@opengeni/react 0.12.0 → 0.13.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 (85) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-5TIXRCSI.js → chunk-NFYVQWIB.js} +150 -64
  3. package/dist/chunk-NFYVQWIB.js.map +1 -0
  4. package/dist/index.d.ts +760 -142
  5. package/dist/index.js +5345 -2146
  6. package/dist/index.js.map +1 -1
  7. package/dist/{machines-BeZ3bD3t.d.ts → machines-CnlMb7E-.d.ts} +5 -5
  8. package/dist/machines.d.ts +1 -1
  9. package/dist/machines.js +1 -1
  10. package/package.json +17 -12
  11. package/src/approvals.ts +16 -4
  12. package/src/client.ts +32 -5
  13. package/src/commands/index.ts +1 -7
  14. package/src/commands/registry.ts +46 -12
  15. package/src/components/chat-composer.tsx +135 -39
  16. package/src/components/code-editor.tsx +28 -36
  17. package/src/components/command-palette.tsx +26 -5
  18. package/src/components/desktop-viewer.tsx +29 -16
  19. package/src/components/diff-view.tsx +27 -189
  20. package/src/components/enrollment-consent.tsx +28 -10
  21. package/src/components/enrollment-device-flow.tsx +8 -5
  22. package/src/components/file-browser.tsx +190 -56
  23. package/src/components/fleet-tile.tsx +13 -4
  24. package/src/components/machine-card.tsx +16 -4
  25. package/src/components/machine-dock-bar.tsx +20 -8
  26. package/src/components/machine-metrics.tsx +31 -8
  27. package/src/components/machine-status-pill.tsx +26 -5
  28. package/src/components/machines-dashboard.tsx +8 -2
  29. package/src/components/markdown.tsx +39 -9
  30. package/src/components/message-timeline.tsx +633 -109
  31. package/src/components/pierre-diff.tsx +83 -15
  32. package/src/components/pierre-file.tsx +10 -9
  33. package/src/components/sandbox-files.tsx +110 -227
  34. package/src/components/sandbox-terminal.tsx +256 -88
  35. package/src/components/sandbox-workspace.tsx +823 -0
  36. package/src/components/session-status.tsx +28 -2
  37. package/src/components/workbench-changes.tsx +541 -0
  38. package/src/components/workspace-dock.tsx +85 -22
  39. package/src/hooks/internal.ts +5 -2
  40. package/src/hooks/use-available-models.ts +7 -2
  41. package/src/hooks/use-billing-usage.ts +4 -1
  42. package/src/hooks/use-codex-accounts.ts +74 -44
  43. package/src/hooks/use-composer.ts +57 -36
  44. package/src/hooks/use-environments.ts +92 -47
  45. package/src/hooks/use-file-attachments.ts +101 -55
  46. package/src/hooks/use-goal.ts +52 -16
  47. package/src/hooks/use-machine-chip.ts +134 -0
  48. package/src/hooks/use-machines.ts +34 -16
  49. package/src/hooks/use-packs.ts +24 -19
  50. package/src/hooks/use-relay-frame-stream.ts +5 -2
  51. package/src/hooks/use-rigs.ts +335 -0
  52. package/src/hooks/use-sandbox-files.ts +213 -39
  53. package/src/hooks/use-sandbox-git.ts +188 -11
  54. package/src/hooks/use-sandbox-terminal.ts +18 -14
  55. package/src/hooks/use-scheduled-tasks.ts +10 -2
  56. package/src/hooks/use-session-capabilities.ts +77 -20
  57. package/src/hooks/use-session-control.ts +49 -21
  58. package/src/hooks/use-session-events.ts +48 -20
  59. package/src/hooks/use-session-lineage.ts +119 -0
  60. package/src/hooks/use-session.ts +43 -28
  61. package/src/hooks/use-slash-commands.ts +6 -4
  62. package/src/hooks/use-turn-queue.ts +74 -147
  63. package/src/hooks/use-windowed-sections.ts +204 -0
  64. package/src/hooks/use-workspace-capture.ts +233 -0
  65. package/src/hooks/use-workspace-edit.ts +231 -0
  66. package/src/hooks/use-workspace-sessions.ts +48 -5
  67. package/src/hooks/use-workspaces.ts +18 -15
  68. package/src/index.ts +127 -23
  69. package/src/lib/format.ts +3 -3
  70. package/src/lib/xterm-renderer.ts +65 -0
  71. package/src/lib/xterm-theme.ts +224 -18
  72. package/src/machines.ts +13 -3
  73. package/src/provider.tsx +3 -1
  74. package/src/timeline/activity-rail.tsx +213 -54
  75. package/src/timeline/disclosure-context.tsx +12 -2
  76. package/src/timeline/index.ts +21 -2
  77. package/src/timeline/parsers.ts +44 -10
  78. package/src/timeline/projection.ts +388 -85
  79. package/src/timeline/shared.tsx +111 -24
  80. package/src/timeline/tool-diff.tsx +24 -20
  81. package/src/timeline/tool-renderers.tsx +98 -21
  82. package/src/timeline/turn-summary.tsx +76 -23
  83. package/src/timeline/types.ts +96 -12
  84. package/styles/tokens.css +2 -2
  85. package/dist/chunk-5TIXRCSI.js.map +0 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/use-session.ts","../src/hooks/use-session-events.ts","../src/timeline/projection.ts","../src/timeline/registry.ts","../src/timeline/tool-renderers.tsx","../src/timeline/parsers.ts","../src/timeline/shared.tsx","../src/timeline/disclosure-context.tsx","../src/timeline/screenshot-lightbox.tsx","../src/timeline/tool-diff.tsx","../src/lib/use-theme-type.ts","../src/components/diff-view.tsx","../src/components/pierre-diff.tsx","../src/lib/git-patch.ts","../src/timeline/activity-rail.tsx","../src/timeline/entrance.tsx","../src/timeline/turn-summary.tsx","../src/hooks/use-composer.ts","../src/hooks/use-file-attachments.ts","../src/hooks/use-turn-queue.ts","../src/hooks/use-goal.ts","../src/hooks/use-session-control.ts","../src/hooks/use-scheduled-tasks.ts","../src/hooks/use-workspace-sessions.ts","../src/hooks/use-environments.ts","../src/hooks/use-packs.ts","../src/hooks/use-workspaces.ts","../src/hooks/use-billing-usage.ts","../src/hooks/use-available-models.ts","../src/hooks/use-session-capabilities.ts","../src/hooks/use-desktop-stream.ts","../src/lib/relay-wire.ts","../src/hooks/use-relay-frame-stream.ts","../src/hooks/use-terminal-stream.ts","../src/hooks/use-sandbox-terminal.ts","../src/hooks/use-sandbox-files.ts","../src/hooks/use-sandbox-git.ts","../src/approvals.ts","../src/commands/registry.ts","../src/hooks/use-slash-commands.ts","../src/components/command-palette.tsx","../src/components/chat-composer.tsx","../src/components/model-picker.tsx","../src/components/message-timeline.tsx","../src/components/markdown.tsx","../src/components/session-status.tsx","../src/components/fleet-tile.tsx","../src/components/sandbox-terminal.tsx","../src/components/file-browser.tsx","../src/components/pierre-file.tsx","../src/components/code-editor.tsx","../src/components/sandbox-files.tsx","../src/components/desktop-viewer.tsx","../src/components/workspace-dock.tsx","../src/hooks/use-codex-accounts.ts","../src/lib/xterm-theme.ts"],"sourcesContent":["import type { Session, SessionEvent } from \"@opengeni/sdk\";\nimport { useCallback, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue, useSessionEventTrigger, type SessionEventFeedOptions } from \"./internal\";\n\nexport type UseSessionOptions = ClientOverride &\n SessionEventFeedOptions & {\n /** Re-fetch on an interval (ms). Off by default — pair with `useSessionEvents` for live status. */\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseSessionResult = {\n session: Session | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Manually rename the session (PATCH, source='user'). Returns the updated session, or null on failure. */\n updateTitle: (title: string) => Promise<Session | null>;\n /** True while a rename is in flight. */\n updating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/** Event types that change the session title (auto + cross-client renames). */\nexport function isTitleEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type === \"session.title_set\";\n}\n\n/** Fetch one session (with optional polling), live-patching its title on `session.title_set`. */\nexport function useSession(sessionId: string | null | undefined, options: UseSessionOptions = {}): UseSessionResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const [override, setOverride] = useState<Session | null>(null);\n const mutation = useMutationRunner();\n const load = useCallback(async () => {\n if (!sessionId) {\n return null;\n }\n const fetched = await client.getSession(workspaceId, sessionId);\n // A fresh server read supersedes any optimistic/event-driven override.\n setOverride(null);\n return fetched;\n }, [client, workspaceId, sessionId]);\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled,\n });\n\n const base = state.data ?? null;\n // The override only ever carries title/titleSource patches; it is reset on\n // every fresh load so it can never go stale against the server snapshot.\n const session = base && override && override.id === base.id ? { ...base, title: override.title, titleSource: override.titleSource } : base;\n\n // Live-patch the title on auto (agent) + cross-client (user/agent) renames so\n // the UI reflects the new title without polling or a full re-fetch.\n const onTitleEvent = useCallback((event: SessionEvent) => {\n const payload = (event.payload ?? {}) as { title?: unknown; source?: unknown };\n const title = payload.title;\n if (typeof title !== \"string\") {\n return;\n }\n const source: \"user\" | \"agent\" | null = payload.source === \"user\" || payload.source === \"agent\" ? payload.source : null;\n setOverride((current): Session | null => {\n const next = current ?? base;\n if (!next) {\n return current;\n }\n return { ...next, title, titleSource: source };\n });\n }, [base]);\n useSessionEventTrigger(client, workspaceId, sessionId, isTitleEvent, onTitleEvent, {\n enabled,\n ...(options.events !== undefined ? { events: options.events } : {}),\n });\n\n const updateTitle = useCallback(\n async (title: string): Promise<Session | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await mutation.run(() => client.updateSession(workspaceId, sessionId, { title }));\n if (result) {\n setOverride(result);\n }\n return result;\n },\n [client, workspaceId, sessionId, mutation.run],\n );\n\n return {\n session,\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n updateTitle,\n updating: mutation.mutating,\n mutationError: mutation.mutationError,\n clearMutationError: mutation.clearMutationError,\n };\n}\n","import type { SessionEvent, SessionStatus, StreamConnectionState } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { buildTimeline, groupTimeline, sessionStatusFromEvents, type TimelineItem } from \"../timeline\";\nimport type { SessionClientLike } from \"../client\";\n\nexport type SessionEventsConnectionState = StreamConnectionState | \"idle\" | \"ended\" | \"error\";\n\nexport type UseSessionEventsOptions = ClientOverride & {\n /** Resume after this sequence (exclusive). Nonzero keeps full replay/resume semantics. */\n after?: number | undefined;\n /** Load a bounded tail by default, or opt back into full replay from `after`. */\n replay?: \"windowed\" | \"full\" | undefined;\n /** Pause the stream without unmounting (e.g. hidden tab). Defaults to true. */\n enabled?: boolean | undefined;\n};\n\nexport type UseSessionEventsResult = {\n /** Replayed + live events, ordered by sequence, no gaps, no duplicates. */\n events: SessionEvent[];\n /** Projected, renderable timeline (memoized over `events`). */\n timeline: TimelineItem[];\n /** Latest session status observed in the event log, if any. */\n sessionStatus: SessionStatus | null;\n connectionState: SessionEventsConnectionState;\n /** Highest sequence seen so far (0 before the first event). */\n lastSequence: number;\n /** True until the initial tail window has been applied (windowed mode). */\n initialLoading: boolean;\n /** Whether older durable events are available before the current window. */\n hasOlder: boolean;\n /** True while an older window is being fetched. */\n loadingOlder: boolean;\n /** Prepend an older density-bounded window; resolves true when more remain. */\n loadOlder: () => Promise<boolean>;\n error: Error | null;\n};\n\nconst TAIL_PAGE_SIZE = 5000;\nconst INITIAL_FETCH_CAP = 1;\nconst OLDER_GROUP_TARGET = 32;\nconst OLDER_FETCH_CAP = 2;\nconst BOUNDARY_PAGE_CAP = 4;\n\n/**\n * Live-stream a session's event log with replay-by-sequence, reconnect, and\n * batched React updates. Fresh loads default to a bounded tail window; pass\n * `replay: \"full\"` or a nonzero `after` for the previous full replay path.\n */\nexport function useSessionEvents(sessionId: string | null | undefined, options: UseSessionEventsOptions = {}): UseSessionEventsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = options.enabled ?? true;\n const after = options.after ?? 0;\n const replay = options.replay ?? \"windowed\";\n const fullReplay = replay === \"full\" || after !== 0;\n\n const [events, setEvents] = useState<SessionEvent[]>([]);\n const [connectionState, setConnectionState] = useState<SessionEventsConnectionState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [hasOlder, setHasOlder] = useState(false);\n const [initialLoading, setInitialLoading] = useState(true);\n const [loadingOlder, setLoadingOlder] = useState(false);\n const lastSequenceRef = useRef(after);\n const oldestSequenceRef = useRef<number | null>(null);\n const hasOlderRef = useRef(false);\n const loadingOlderRef = useRef(false);\n const streamKeyRef = useRef<string | null>(null);\n const generationRef = useRef(0);\n\n useEffect(() => {\n // Reset the accumulated log only when the stream identity changes —\n // pausing via `enabled: false` keeps the timeline visible.\n const streamKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${after}\\u0000${fullReplay ? \"full\" : \"windowed\"}`;\n if (streamKeyRef.current !== streamKey) {\n streamKeyRef.current = streamKey;\n generationRef.current += 1;\n setEvents([]);\n setError(null);\n setHasOlder(false);\n setLoadingOlder(false);\n setInitialLoading(true);\n lastSequenceRef.current = after;\n oldestSequenceRef.current = null;\n hasOlderRef.current = false;\n loadingOlderRef.current = false;\n }\n if (!sessionId || !enabled) {\n setConnectionState(\"idle\");\n return;\n }\n const controller = new AbortController();\n // Batch yielded events into one React update per flush window so a long\n // replay (thousands of events) does not render per event.\n let pending: SessionEvent[] = [];\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const flush = () => {\n flushTimer = null;\n if (pending.length === 0) {\n return;\n }\n const batch = pending;\n pending = [];\n // The resume cursor only advances with delivered batches: events still\n // sitting in `pending` when the stream is torn down are re-fetched on\n // the next connect instead of being skipped.\n const lastInBatch = batch[batch.length - 1];\n if (lastInBatch) {\n lastSequenceRef.current = Math.max(lastSequenceRef.current, ...batch.map(eventResumeSequence));\n }\n setEvents((existing) => [...existing, ...batch]);\n };\n const scheduleFlush = () => {\n flushTimer ??= setTimeout(flush, 16);\n };\n\n void (async () => {\n try {\n if (!fullReplay) {\n setConnectionState(\"connecting\");\n // First paint is ONE compact fetch — the newest window, revealed at\n // the bottom in a few hundred ms. Deeper history loads only when the\n // reader actually scrolls up (the sentinel drives loadOlder).\n const window = await loadEventWindow(client, workspaceId, sessionId, {\n before: Number.MAX_SAFE_INTEGER,\n pageSize: TAIL_PAGE_SIZE,\n targetGroups: Number.POSITIVE_INFINITY,\n maxFetches: INITIAL_FETCH_CAP,\n signal: controller.signal,\n });\n if (controller.signal.aborted) {\n return;\n }\n oldestSequenceRef.current = window.oldestSequence;\n hasOlderRef.current = window.hasOlder;\n lastSequenceRef.current = window.newestSequence;\n setHasOlder(window.hasOlder);\n setEvents(window.events);\n setInitialLoading(false);\n }\n if (fullReplay) {\n setInitialLoading(false);\n }\n const stream = client.streamEvents(workspaceId, sessionId, {\n after: lastSequenceRef.current,\n signal: controller.signal,\n onStateChange: (state) => {\n if (!controller.signal.aborted) {\n setConnectionState(state);\n }\n },\n });\n for await (const event of stream) {\n pending.push(event);\n scheduleFlush();\n }\n if (!controller.signal.aborted) {\n flush();\n setConnectionState(\"ended\");\n }\n } catch (cause) {\n if (!controller.signal.aborted) {\n flush();\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setConnectionState(\"error\");\n }\n }\n })();\n\n return () => {\n controller.abort();\n if (flushTimer !== null) {\n clearTimeout(flushTimer);\n }\n };\n }, [client, workspaceId, sessionId, after, enabled, fullReplay]);\n\n const loadOlder = useCallback(async (): Promise<boolean> => {\n if (!sessionId || fullReplay || loadingOlderRef.current || !hasOlderRef.current) {\n return false;\n }\n const before = oldestSequenceRef.current;\n if (before === null) {\n hasOlderRef.current = false;\n setHasOlder(false);\n return false;\n }\n const generation = generationRef.current;\n loadingOlderRef.current = true;\n setLoadingOlder(true);\n try {\n const window = await loadEventWindow(client, workspaceId, sessionId, {\n before,\n pageSize: TAIL_PAGE_SIZE,\n targetGroups: OLDER_GROUP_TARGET,\n maxFetches: OLDER_FETCH_CAP,\n });\n if (generationRef.current !== generation) {\n return false;\n }\n if (window.events.length === 0) {\n oldestSequenceRef.current = null;\n hasOlderRef.current = false;\n setHasOlder(false);\n return false;\n }\n oldestSequenceRef.current = window.oldestSequence;\n hasOlderRef.current = window.hasOlder;\n setHasOlder(window.hasOlder);\n setEvents((existing) => {\n assertPrependOrder(existing, window.events);\n return [...window.events, ...existing];\n });\n return window.hasOlder;\n } finally {\n if (generationRef.current === generation) {\n loadingOlderRef.current = false;\n setLoadingOlder(false);\n }\n }\n }, [client, workspaceId, sessionId, fullReplay]);\n\n const timeline = useMemo(() => buildTimeline(events), [events]);\n const sessionStatus = useMemo(() => sessionStatusFromEvents(events), [events]);\n\n return {\n events,\n timeline,\n sessionStatus,\n connectionState,\n lastSequence: lastSequenceRef.current,\n initialLoading: fullReplay ? false : initialLoading,\n hasOlder: fullReplay ? false : hasOlder,\n loadingOlder: fullReplay ? false : loadingOlder,\n loadOlder,\n error,\n };\n}\n\ntype LoadedEventWindow = {\n events: SessionEvent[];\n oldestSequence: number | null;\n newestSequence: number;\n hasOlder: boolean;\n};\n\nasync function loadEventWindow(\n client: SessionClientLike,\n workspaceId: string,\n sessionId: string,\n options: {\n before: number;\n pageSize: number;\n targetGroups: number;\n maxFetches: number;\n signal?: AbortSignal;\n },\n): Promise<LoadedEventWindow> {\n let cursor = options.before;\n let buffer: SessionEvent[] = [];\n let reachedStart = false;\n let fetches = 0;\n\n while (fetches < options.maxFetches) {\n if (buffer.length > 0 && groupCount(buffer) >= options.targetGroups) {\n break;\n }\n const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {\n pageSize: options.pageSize,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n fetches += 1;\n if (page.length === 0) {\n reachedStart = true;\n break;\n }\n assertAscending(page);\n buffer = [...page, ...buffer];\n cursor = page[0]!.sequence;\n if (isLogStart(page[0]!)) {\n reachedStart = true;\n break;\n }\n }\n\n // Boundary snap: a window that starts mid-turn TRIMS its head to the oldest\n // turn boundary already in the buffer — the dropped fragment is refetched by\n // the next loadOlder (everything below the new oldest sequence), whose own\n // window snaps the same way, so every seam lands on a turn start. Extra\n // pages are fetched only when the buffer holds no boundary at all (one\n // monster turn); past the cap a mid-turn top is accepted.\n let snapPages = 0;\n while (!reachedStart && findBoundaryIndex(buffer) === -1 && snapPages < BOUNDARY_PAGE_CAP && fetches < options.maxFetches) {\n const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {\n pageSize: options.pageSize,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n fetches += 1;\n snapPages += 1;\n if (page.length === 0) {\n reachedStart = true;\n break;\n }\n assertAscending(page);\n buffer = [...page, ...buffer];\n cursor = page[0]!.sequence;\n if (isLogStart(page[0]!)) {\n reachedStart = true;\n break;\n }\n }\n if (!reachedStart) {\n const boundary = findBoundaryIndex(buffer);\n if (boundary > 0) {\n buffer = buffer.slice(boundary);\n }\n }\n\n const oldest = buffer[0] ?? null;\n const newest = buffer[buffer.length - 1] ?? null;\n return {\n events: buffer,\n oldestSequence: oldest?.sequence ?? null,\n newestSequence: newest ? maxResumeSequence(buffer) : 0,\n hasOlder: buffer.length > 0 && !reachedStart && oldest?.type !== \"session.created\",\n };\n}\n\n/** Index of the oldest clean turn start in the buffer, or -1. */\nfunction findBoundaryIndex(events: SessionEvent[]): number {\n for (let index = 0; index < events.length; index += 1) {\n const type = events[index]!.type;\n if (type === \"session.created\" || type === \"user.message\") {\n return index;\n }\n }\n return -1;\n}\n\ntype PreviousPage = SessionEvent[] & { requested: number };\n\nasync function loadPreviousPage(\n client: SessionClientLike,\n workspaceId: string,\n sessionId: string,\n before: number,\n options: {\n pageSize: number;\n signal?: AbortSignal;\n },\n): Promise<PreviousPage> {\n if (options.signal?.aborted) {\n throw abortError();\n }\n const requested = options.pageSize;\n if (requested === 0) {\n return Object.assign([], { requested });\n }\n const page = await client.listEvents(workspaceId, sessionId, { before, limit: requested, compact: true });\n if (options.signal?.aborted) {\n throw abortError();\n }\n return Object.assign(page, { requested });\n}\n\nfunction groupCount(events: SessionEvent[]): number {\n if (events.length === 0) {\n return 0;\n }\n return groupTimeline(buildTimeline(events)).length;\n}\n\nfunction isLogStart(event: SessionEvent): boolean {\n return event.type === \"session.created\" || event.sequence <= 1;\n}\n\nfunction maxResumeSequence(events: SessionEvent[]): number {\n return events.reduce((max, event) => Math.max(max, eventResumeSequence(event)), 0);\n}\n\nfunction eventResumeSequence(event: SessionEvent): number {\n const payload = asRecord(event.payload);\n const coalescedUntil = Number(payload.coalescedUntil);\n return Math.max(event.sequence, Number.isFinite(coalescedUntil) ? Math.floor(coalescedUntil) : 0);\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" ? value as Record<string, unknown> : {};\n}\n\nfunction assertAscending(events: SessionEvent[]): void {\n for (let index = 1; index < events.length; index += 1) {\n if (events[index - 1]!.sequence >= events[index]!.sequence) {\n throw new Error(\"@opengeni/react: session events must be ordered by ascending sequence\");\n }\n }\n}\n\nfunction assertPrependOrder(existing: SessionEvent[], older: SessionEvent[]): void {\n if (!shouldAssertDevelopment() || existing.length === 0 || older.length === 0) {\n return;\n }\n if (older[older.length - 1]!.sequence >= existing[0]!.sequence) {\n throw new Error(\"@opengeni/react: loadOlder returned overlapping session events\");\n }\n}\n\nfunction shouldAssertDevelopment(): boolean {\n const processEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env;\n return processEnv !== undefined && processEnv.NODE_ENV !== \"production\";\n}\n\nfunction abortError(): Error {\n const error = new Error(\"The operation was aborted.\");\n error.name = \"AbortError\";\n return error;\n}\n","import type { SessionEvent, SessionStatus } from \"@opengeni/sdk\";\nimport { CREDIT_EXHAUSTION_MESSAGE, humanizeFailureReason, isCreditExhaustion, tryParseJson } from \"../lib/format\";\nimport type {\n AgentMessageItem,\n ActivityItem,\n GoalItem,\n SandboxItem,\n SessionStatusItem,\n TimelineGroup,\n TimelineItem,\n TurnEndItem,\n ToolCallItem,\n WorkerItem,\n} from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Timeline projection\n\n `buildTimeline` folds a session's raw event log (replayed + live, ordered by\n sequence) into renderable items: chat messages with accumulated streaming\n deltas, reasoning summaries, tool calls matched to their outputs, sandbox\n operations with command output, spawned-worker status (the manager's\n `session_create` / `session_send_message` orchestration calls), goal\n markers, status changes, and turn failures.\n\n It is a pure function — same events in, same items out — so it can be\n memoized, unit-tested, and re-run incrementally as new events stream in.\n -------------------------------------------------------------------------- */\n\n/** Tool names on the first-party OpenGeni MCP server that operate on sessions. */\nconst WORKER_SPAWN_TOOL = \"session_create\";\nconst WORKER_MESSAGE_TOOL = \"session_send_message\";\nconst WORKER_INTERRUPT_TOOL = \"session_interrupt\";\n\nexport function buildTimeline(events: SessionEvent[]): TimelineItem[] {\n const items: TimelineItem[] = [];\n const prescan = prescanTurnAnchors(events);\n const ordered = orderTimelineEvents(events, prescan);\n\n const last = (): TimelineItem | undefined => items[items.length - 1];\n\n /** A new item of a different kind ends whatever was streaming at the tail. */\n const closeStreamingTail = (): void => {\n const open = last();\n if ((open?.kind === \"agent-message\" || open?.kind === \"reasoning\") && open.streaming) {\n open.streaming = false;\n }\n };\n\n const finalizeOpen = (turnId?: string | null, disposition: \"complete\" | \"failed\" | \"cancelled\" = \"complete\"): void => {\n for (const item of items) {\n if (turnId !== undefined && \"turnId\" in item && item.turnId && turnId && item.turnId !== turnId) {\n continue;\n }\n if ((item.kind === \"agent-message\" || item.kind === \"reasoning\") && item.streaming) {\n item.streaming = false;\n }\n if ((item.kind === \"tool-call\" || item.kind === \"worker\") && item.status === \"running\") {\n item.status = disposition;\n }\n if (item.kind === \"sandbox\" && item.status === \"running\") {\n item.status = disposition;\n }\n }\n };\n\n for (const event of ordered) {\n const payload = asRecord(event.payload);\n const turnId = event.turnId ?? null;\n\n switch (event.type) {\n case \"user.message\": {\n // A steering message must not mark in-flight tools complete; it only\n // ends whatever text was streaming. Turn lifecycle events finalize.\n closeStreamingTail();\n items.push({\n kind: \"user-message\",\n id: event.id,\n text: typeof payload.text === \"string\" ? payload.text : \"\",\n ...(event.pendingUserMessage ? { pending: true } : {}),\n resources: resourceRefs(payload.resources),\n tools: toolRefs(payload.tools),\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.message.delta\": {\n const text = typeof payload.text === \"string\" ? payload.text : \"\";\n if (!text) {\n break;\n }\n const open = last();\n if (open?.kind === \"agent-message\" && open.streaming && open.turnId === turnId) {\n open.text += text;\n break;\n }\n closeStreamingTail();\n items.push({\n kind: \"agent-message\",\n id: event.id,\n turnId,\n text,\n streaming: true,\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.message.completed\": {\n const text = typeof payload.text === \"string\" ? payload.text : \"\";\n // Reconcile the most recent same-turn agent message — even when\n // activity (tool calls, reasoning) landed after its deltas — so the\n // completed text never duplicates the streamed one.\n const open = [...items]\n .reverse()\n .find((item): item is AgentMessageItem => item.kind === \"agent-message\" && item.turnId === turnId);\n if (open && (open.streaming || !open.text || text === open.text || text.startsWith(open.text))) {\n // The completed text is authoritative when it extends what streamed.\n if (!open.text || (text && text.startsWith(open.text))) {\n open.text = text || open.text;\n }\n open.streaming = false;\n break;\n }\n if (text) {\n items.push({\n kind: \"agent-message\",\n id: event.id,\n turnId,\n text,\n streaming: false,\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"agent.reasoning.delta\": {\n const text = reasoningText(event.payload);\n if (!text) {\n break;\n }\n const open = last();\n if (open?.kind === \"reasoning\" && open.streaming && open.turnId === turnId) {\n open.text += text;\n break;\n }\n closeStreamingTail();\n items.push({\n kind: \"reasoning\",\n id: event.id,\n turnId,\n text,\n streaming: true,\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.toolCall.created\": {\n const name = typeof payload.name === \"string\" ? payload.name : \"tool\";\n const callId = typeof payload.id === \"string\" ? payload.id : null;\n const args = payload.arguments ?? null;\n closeStreamingTail();\n if (name === WORKER_INTERRUPT_TOOL) {\n // stop (default) vs steer — the target keeps its goal on steer and\n // picks up its next queued turn (pair with session_send_message).\n items.push({\n kind: \"worker\",\n id: event.id,\n turnId,\n callId,\n action: \"interrupt\",\n prompt: null,\n workerSessionId: extractSessionRef(args),\n mode: workerInterruptMode(args),\n status: \"running\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n if (name === WORKER_SPAWN_TOOL || name === WORKER_MESSAGE_TOOL) {\n items.push({\n kind: \"worker\",\n id: event.id,\n turnId,\n callId,\n action: name === WORKER_SPAWN_TOOL ? \"spawn\" : \"message\",\n prompt: workerPrompt(args),\n workerSessionId: extractSessionRef(args),\n status: \"running\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n items.push({\n kind: \"tool-call\",\n id: event.id,\n turnId,\n callId,\n name,\n arguments: args,\n output: undefined,\n // The provider-native item drives the per-tool renderers (apply_patch\n // operation, computer_call action, web_search providerData, …).\n raw: payload.raw,\n status: \"running\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.toolCall.output\": {\n const callId = typeof payload.id === \"string\" ? payload.id : null;\n const target = findOpenCall(items, callId);\n if (!target) {\n break;\n }\n if (target.kind === \"worker\") {\n // A worker spawn/message that returns an error flag (or an MCP\n // isError result) settles to \"failed\" too, so WorkerRow surfaces it.\n target.status = isErrorOutput(payload) ? \"failed\" : \"complete\";\n target.workerSessionId = target.workerSessionId ?? extractSessionRef(payload.output);\n break;\n }\n // An output carrying an explicit error flag (or an MCP isError result)\n // settles the tool to \"failed\" so the renderer can surface it loudly.\n target.status = isErrorOutput(payload) ? \"failed\" : \"complete\";\n target.output = payload.output;\n break;\n }\n\n case \"sandbox.operation.started\":\n case \"sandbox.operation.completed\":\n case \"sandbox.operation.failed\": {\n const name = typeof payload.name === \"string\" ? payload.name : \"sandbox\";\n const status = event.type.endsWith(\".failed\") ? \"failed\" : event.type.endsWith(\".completed\") ? \"complete\" : \"running\";\n const existing = findOpenSandbox(items, name);\n if (existing && status !== \"running\") {\n existing.status = status;\n const message = failureMessage(payload);\n if (message) {\n existing.output = existing.output ? `${existing.output}\\n${message}` : message;\n }\n break;\n }\n if (!existing) {\n closeStreamingTail();\n items.push({\n kind: \"sandbox\",\n id: event.id,\n turnId,\n name,\n command: typeof payload.command === \"string\" ? payload.command : null,\n output: failureMessage(payload) ?? \"\",\n status,\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"sandbox.command.output.delta\": {\n // `chunk` is the canonical wire field; text/output are legacy shapes.\n const text = typeof payload.chunk === \"string\"\n ? payload.chunk\n : typeof payload.text === \"string\" ? payload.text : typeof payload.output === \"string\" ? payload.output : \"\";\n if (!text) {\n break;\n }\n // Attach to the named operation when the payload carries one;\n // otherwise the latest running operation is the best available owner.\n const open =\n (typeof payload.name === \"string\" ? findOpenSandbox(items, payload.name) : undefined) ??\n [...items].reverse().find((item): item is SandboxItem => item.kind === \"sandbox\" && item.status === \"running\");\n if (open) {\n open.output += text;\n }\n break;\n }\n\n case \"session.status.changed\": {\n const status = payload.status;\n if (!isSessionStatus(status)) {\n break;\n }\n // Only attention-worthy statuses earn a timeline divider. queued /\n // running / idle are machinery telemetry: the header pill carries the\n // live status, the shimmer says \"running\", and the turn chip's duration\n // facet says how long — a stale \"idle · 27s\" row is pure noise,\n // especially in historical traces.\n if (!ATTENTION_STATUSES.has(status)) {\n break;\n }\n const previous = [...items].reverse().find((item): item is SessionStatusItem => item.kind === \"session-status\");\n if (previous?.status === status) {\n break;\n }\n items.push({ kind: \"session-status\", id: event.id, status, occurredAt: event.occurredAt });\n break;\n }\n\n case \"session.requiresAction\": {\n finalizeOpen(turnId);\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"waiting\",\n text: \"Approval needed — the turn is paused until someone decides.\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"tool.auth_needed\": {\n closeStreamingTail();\n const authorizationUrl = typeof payload.authorizationUrl === \"string\" ? payload.authorizationUrl : null;\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"waiting\",\n text: authNeededNoticeText(payload),\n ...(authorizationUrl ? { action: { label: \"Connect\", url: authorizationUrl } } : {}),\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"turn.completed\": {\n // Credit exhaustion arrives as a NOMINALLY completed turn (`detail:\n // \"insufficient OpenGeni credits\"`, `segmentLimit: \"budget_exhausted\"`)\n // — the engine ended the segment early, it did not finish the work.\n // Rendering it as a clean \"complete\" turn is a lie that leaves the\n // session looking healthy while every future turn silently dies, so it\n // projects exactly like a failed turn plus an explicit notice.\n if (isCreditExhaustionPayload(payload)) {\n finalizeOpen(turnId);\n items.push(turnEndItem(event, \"failed\", CREDIT_EXHAUSTION_MESSAGE));\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"failed\",\n text: CREDIT_EXHAUSTION_MESSAGE,\n occurredAt: event.occurredAt,\n });\n break;\n }\n finalizeOpen(turnId);\n items.push(turnEndItem(event, \"complete\", null));\n break;\n }\n\n case \"turn.failed\": {\n const hadActivity = hasTurnActivity(items, turnId);\n // Credit death can hide behind fields `failureMessage` doesn't read\n // (detail/segmentLimit), so classify the whole payload before falling\n // back to the generic error/message extraction.\n const failureText = isCreditExhaustionPayload(payload) ? CREDIT_EXHAUSTION_MESSAGE : failureMessage(payload);\n // The TURN failed — the in-flight items did not. Chip doctrine: red is\n // spent once, on the turn-level outcome. Items caught mid-flight read\n // as calm \"interrupted\" (same as turn.cancelled); an item that itself\n // failed keeps its own failed status from its output event.\n finalizeOpen(turnId, \"cancelled\");\n items.push(turnEndItem(event, \"failed\", failureText));\n if (!hadActivity) {\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"failed\",\n text: failureText ?? \"The turn failed.\",\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"turn.cancelled\": {\n // A retraction of a never-started queued turn is not a turn ending —\n // the message was withdrawn before any work happened; show nothing.\n // A null turnId proves nothing, so it keeps the legacy finalize path.\n if (turnId && !prescan.startedTurnIds.has(turnId)) {\n break;\n }\n const hadActivity = hasTurnActivity(items, turnId);\n finalizeOpen(turnId, \"cancelled\");\n items.push(turnEndItem(event, \"cancelled\", null));\n if (!hadActivity) {\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"cancelled\",\n text: \"Interrupted.\",\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"goal.set\":\n case \"goal.updated\":\n case \"goal.completed\":\n case \"goal.paused\":\n case \"goal.resumed\":\n case \"goal.continuation\": {\n items.push({\n kind: \"goal\",\n id: event.id,\n action: event.type.slice(\"goal.\".length) as GoalItem[\"action\"],\n text: goalText(payload),\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n default:\n break;\n }\n }\n\n return items;\n}\n\n/** The turn-end payload shape, as `isCreditExhaustion` wants it. */\nfunction isCreditExhaustionPayload(payload: Record<string, unknown>): boolean {\n return isCreditExhaustion({\n error: typeof payload.error === \"string\" ? payload.error : null,\n detail: typeof payload.detail === \"string\" ? payload.detail : null,\n segmentLimit: typeof payload.segmentLimit === \"string\" ? payload.segmentLimit : null,\n });\n}\n\n/**\n * Whether the session's most recent turn ended in credit exhaustion — the\n * terminal credit state apps key their \"add credits\" affordances on. Derived\n * from the LAST turn-end event (completed/failed/cancelled): a later turn that\n * settles any other way (someone topped up and kept working) clears it.\n */\nexport function creditExhaustedFromEvents(events: SessionEvent[]): boolean {\n const ordered = [...events].sort((a, b) => a.sequence - b.sequence);\n for (let index = ordered.length - 1; index >= 0; index -= 1) {\n const event = ordered[index];\n if (event?.type !== \"turn.completed\" && event?.type !== \"turn.failed\" && event?.type !== \"turn.cancelled\") {\n continue;\n }\n return isCreditExhaustionPayload(asRecord(event.payload));\n }\n return false;\n}\n\n/** The latest session status carried in the event log, if any. */\nexport function sessionStatusFromEvents(events: SessionEvent[]): SessionStatus | null {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (event?.type !== \"session.status.changed\") {\n continue;\n }\n const status = asRecord(event.payload).status;\n if (isSessionStatus(status)) {\n return status;\n }\n }\n return null;\n}\n\n/* ----------------------------------------------------------------------------\n Visual grouping: consecutive activity items (reasoning / tools / workers /\n sandbox) cluster into collapsible blocks. Once a turn settles, the full\n non-user span folds behind a turn group, with activity blocks nested inside.\n -------------------------------------------------------------------------- */\n\n/**\n * Whether an item clusters into an activity block. A `switch` (not a stringly-\n * typed set) so adding an {@link ActivityItem} kind is a compile-time prompt to\n * decide its grouping — and it narrows `item` to `ActivityItem` with no cast.\n */\nfunction isActivityItem(item: TimelineItem): item is ActivityItem {\n switch (item.kind) {\n case \"reasoning\":\n case \"tool-call\":\n case \"worker\":\n case \"sandbox\":\n return true;\n default:\n return false;\n }\n}\n\nexport function groupTimeline(items: TimelineItem[]): TimelineGroup[] {\n const groups: TimelineGroup[] = [];\n for (const item of items) {\n if (isActivityItem(item)) {\n const open = groups[groups.length - 1];\n if (open?.kind === \"activity\" && open.outcome === undefined) {\n open.items.push(item);\n } else {\n groups.push({ kind: \"activity\", id: `activity-${item.id}`, items: [item] });\n }\n continue;\n }\n if (item.kind === \"turn-end\") {\n stampTurnOutcome(groups, item);\n foldSettledTurn(groups, item);\n continue;\n }\n groups.push({ kind: \"item\", item });\n }\n return groups;\n}\n\n/* --- helpers ---------------------------------------------------------------- */\n\ntype TimelineEvent = SessionEvent & { pendingUserMessage?: true };\n\ntype TurnAnchorPrescan = {\n queuedTurnByTrigger: Map<string, string>;\n startSeqByTrigger: Map<string, number>;\n cancelledBeforeStartTriggers: Set<string>;\n startedTurnIds: Set<string>;\n};\n\nfunction prescanTurnAnchors(events: SessionEvent[]): TurnAnchorPrescan {\n const ordered = [...events].sort((a, b) => a.sequence - b.sequence);\n const queuedTurnByTrigger = new Map<string, string>();\n const startSeqByTrigger = new Map<string, number>();\n const cancelledTurnIds = new Set<string>();\n const fallbackSeqByTurn = new Map<string, number>();\n const startedTurnIds = new Set<string>();\n\n for (const event of ordered) {\n const payload = asRecord(event.payload);\n const turnId = event.turnId ?? null;\n if (event.type === \"turn.queued\") {\n const triggerEventId = typeof payload.triggerEventId === \"string\" ? payload.triggerEventId : null;\n const queuedTurnId = typeof payload.turnId === \"string\" ? payload.turnId : turnId;\n if (triggerEventId && queuedTurnId) {\n queuedTurnByTrigger.set(triggerEventId, queuedTurnId);\n }\n continue;\n }\n if (event.type === \"turn.started\") {\n const triggerEventId = typeof payload.triggerEventId === \"string\" ? payload.triggerEventId : null;\n if (triggerEventId) {\n startSeqByTrigger.set(triggerEventId, event.sequence);\n }\n if (turnId) {\n startedTurnIds.add(turnId);\n }\n } else if (event.type === \"turn.cancelled\" && turnId) {\n cancelledTurnIds.add(turnId);\n }\n\n if (turnId && event.type !== \"turn.queued\" && event.type !== \"turn.cancelled\") {\n const previous = fallbackSeqByTurn.get(turnId);\n if (previous === undefined || event.sequence < previous) {\n fallbackSeqByTurn.set(turnId, event.sequence);\n }\n }\n if (turnId && isAgentActivityEvent(event.type)) {\n startedTurnIds.add(turnId);\n }\n }\n\n for (const [triggerEventId, turnId] of queuedTurnByTrigger) {\n if (!startSeqByTrigger.has(triggerEventId)) {\n const fallbackSeq = fallbackSeqByTurn.get(turnId);\n if (fallbackSeq !== undefined) {\n startSeqByTrigger.set(triggerEventId, fallbackSeq);\n }\n }\n }\n\n const cancelledBeforeStartTriggers = new Set<string>();\n for (const [triggerEventId, turnId] of queuedTurnByTrigger) {\n if (cancelledTurnIds.has(turnId) && !startSeqByTrigger.has(triggerEventId) && !fallbackSeqByTurn.has(turnId)) {\n cancelledBeforeStartTriggers.add(triggerEventId);\n }\n }\n\n return { queuedTurnByTrigger, startSeqByTrigger, cancelledBeforeStartTriggers, startedTurnIds };\n}\n\nfunction orderTimelineEvents(events: SessionEvent[], prescan: TurnAnchorPrescan): TimelineEvent[] {\n const ordered = [...events].sort((a, b) => a.sequence - b.sequence);\n const insertions = new Map<number, TimelineEvent[]>();\n const pending: TimelineEvent[] = [];\n\n for (const event of ordered) {\n if (event.type !== \"user.message\") {\n continue;\n }\n const queuedTurnId = prescan.queuedTurnByTrigger.get(event.id);\n if (!queuedTurnId) {\n pushInsertion(insertions, event.sequence, event);\n continue;\n }\n if (prescan.cancelledBeforeStartTriggers.has(event.id)) {\n continue;\n }\n const startSeq = prescan.startSeqByTrigger.get(event.id);\n if (startSeq !== undefined) {\n pushInsertion(insertions, startSeq, event);\n continue;\n }\n pending.push({ ...event, pendingUserMessage: true });\n }\n\n const projected: TimelineEvent[] = [];\n for (const event of ordered) {\n const before = insertions.get(event.sequence);\n if (before) {\n projected.push(...before);\n }\n if (event.type !== \"user.message\") {\n projected.push(event);\n }\n }\n projected.push(...pending);\n return projected;\n}\n\nfunction pushInsertion(insertions: Map<number, TimelineEvent[]>, sequence: number, event: SessionEvent): void {\n const bucket = insertions.get(sequence);\n if (bucket) {\n bucket.push(event);\n } else {\n insertions.set(sequence, [event]);\n }\n}\n\nfunction isAgentActivityEvent(type: string): boolean {\n return type.startsWith(\"agent.\") || type.startsWith(\"sandbox.\");\n}\n\nfunction turnEndItem(\n event: SessionEvent,\n outcome: TurnEndItem[\"outcome\"],\n failureText: string | null,\n): TurnEndItem {\n return {\n kind: \"turn-end\",\n id: `${event.id}-turn-end`,\n turnId: event.turnId ?? null,\n outcome,\n failureText,\n occurredAt: event.occurredAt,\n };\n}\n\nfunction hasTurnActivity(items: TimelineItem[], turnId: string | null): boolean {\n if (turnId) {\n return items.some((item) => isActivityItem(item) && item.turnId === turnId);\n }\n for (let index = items.length - 1; index >= 0; index -= 1) {\n const item = items[index];\n if (!item || item.kind === \"turn-end\" || item.kind === \"user-message\") {\n return false;\n }\n if (isActivityItem(item)) {\n return true;\n }\n }\n return false;\n}\n\nfunction stampTurnOutcome(groups: TimelineGroup[], turnEnd: TurnEndItem): void {\n if (turnEnd.turnId === null) {\n const trailing = groups[groups.length - 1];\n if (trailing?.kind === \"activity\" && trailing.outcome === undefined) {\n applyTurnOutcome(trailing, turnEnd);\n }\n return;\n }\n for (const group of groups) {\n if (group.kind !== \"activity\" || group.outcome !== undefined) {\n continue;\n }\n if (group.items.some((activity) => activity.turnId === turnEnd.turnId)) {\n applyTurnOutcome(group, turnEnd);\n }\n }\n}\n\nfunction applyTurnOutcome(group: Extract<TimelineGroup, { kind: \"activity\" }>, turnEnd: TurnEndItem): void {\n // A sub-cluster reports ITS OWN outcome, not the turn's. When a turn fails\n // at step 7, clusters 1–6 completed — painting them all red says \"everything\n // broke\" when one thing did. The turn-level fold carries the turn outcome;\n // a cluster goes red only if an item inside it actually failed, and reads\n // \"cancelled\" (interrupted) only when it holds the items cut off mid-flight.\n if (turnEnd.outcome === \"complete\") {\n group.outcome = \"complete\";\n return;\n }\n const hasFailed = group.items.some((item) => \"status\" in item && item.status === \"failed\");\n const hasInterrupted = group.items.some((item) => \"status\" in item && item.status === \"cancelled\");\n group.outcome = hasFailed ? \"failed\" : hasInterrupted ? \"cancelled\" : \"complete\";\n if (turnEnd.failureText && hasFailed) {\n group.failureText = turnEnd.failureText;\n }\n}\n\nfunction foldSettledTurn(groups: TimelineGroup[], turnEnd: TurnEndItem): void {\n let startIndex = groups.length;\n let stoppedAtForeignTurn = false;\n while (startIndex > 0) {\n const previous = groups[startIndex - 1];\n if (isTurnBoundary(previous)) {\n break;\n }\n if (belongsToDifferentTurn(previous, turnEnd.turnId)) {\n stoppedAtForeignTurn = true;\n break;\n }\n startIndex -= 1;\n }\n if (stoppedAtForeignTurn) {\n while (startIndex < groups.length && isBetweenTurnDivider(groups[startIndex])) {\n startIndex += 1;\n }\n }\n\n const collected = groups.slice(startIndex);\n if (collected.length === 0) {\n return;\n }\n\n const finalMessage = extractFinalAgentMessage(collected, turnEnd);\n const body = finalMessage ? collected.slice(0, -1) : collected;\n if (body.length === 0) {\n return;\n }\n\n const firstOccurredAt = groupStartedAt(body[0]) ?? turnEnd.occurredAt;\n const turnGroup: TimelineGroup = {\n kind: \"turn\",\n id: `turn-${turnEnd.turnId ?? turnEnd.id}`,\n outcome: turnEnd.outcome,\n startedAt: firstOccurredAt,\n endedAt: turnEnd.occurredAt,\n groups: body,\n };\n if (turnEnd.failureText) {\n turnGroup.failureText = turnEnd.failureText;\n }\n\n groups.splice(startIndex, collected.length, ...(finalMessage ? [turnGroup, finalMessage] : [turnGroup]));\n}\n\nfunction isTurnBoundary(group: TimelineGroup | undefined): boolean {\n return group?.kind === \"turn\" || (group?.kind === \"item\" && group.item.kind === \"user-message\");\n}\n\nfunction belongsToDifferentTurn(group: TimelineGroup | undefined, turnId: string | null): boolean {\n if (!group || !turnId) {\n return false;\n }\n if (group.kind === \"activity\") {\n return group.items.length > 0 && group.items.every((item) => item.turnId !== null && item.turnId !== turnId);\n }\n return group.kind === \"item\" && group.item.kind === \"agent-message\" && group.item.turnId !== null && group.item.turnId !== turnId;\n}\n\nfunction isBetweenTurnDivider(group: TimelineGroup | undefined): boolean {\n return group?.kind === \"item\" && group.item.kind === \"session-status\" && group.item.status !== \"running\";\n}\n\nfunction extractFinalAgentMessage(groups: TimelineGroup[], turnEnd: TurnEndItem): Extract<TimelineGroup, { kind: \"item\" }> | null {\n const tail = groups[groups.length - 1];\n if (tail?.kind !== \"item\" || tail.item.kind !== \"agent-message\" || tail.item.streaming) {\n return null;\n }\n if (tail.item.turnId && turnEnd.turnId && tail.item.turnId !== turnEnd.turnId) {\n return null;\n }\n return tail;\n}\n\nfunction groupStartedAt(group: TimelineGroup | undefined): string | undefined {\n if (!group) {\n return undefined;\n }\n switch (group.kind) {\n case \"item\":\n return group.item.occurredAt;\n case \"activity\":\n return group.items[0]?.occurredAt;\n case \"turn\":\n return group.startedAt;\n }\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n}\n\nconst SESSION_STATUSES: readonly SessionStatus[] = [\"queued\", \"running\", \"idle\", \"requires_action\", \"failed\", \"cancelled\"];\n\n/** Statuses that demand the reader's attention and so earn a timeline divider. */\nconst ATTENTION_STATUSES: ReadonlySet<SessionStatus> = new Set([\"requires_action\", \"failed\", \"cancelled\"]);\n\n/** Keep only entries that match the wire shapes; user payloads are untyped. */\nfunction resourceRefs(value: unknown): import(\"@opengeni/sdk\").ResourceRef[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter((entry): entry is import(\"@opengeni/sdk\").ResourceRef => {\n const record = asRecord(entry);\n if (record.kind === \"repository\") {\n return typeof record.uri === \"string\" && typeof record.ref === \"string\";\n }\n return record.kind === \"file\" && typeof record.fileId === \"string\";\n });\n}\n\nfunction toolRefs(value: unknown): import(\"@opengeni/sdk\").ToolRef[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter((entry): entry is import(\"@opengeni/sdk\").ToolRef => {\n const record = asRecord(entry);\n return record.kind === \"mcp\" && typeof record.id === \"string\";\n });\n}\n\nfunction isSessionStatus(value: unknown): value is SessionStatus {\n return typeof value === \"string\" && (SESSION_STATUSES as readonly string[]).includes(value);\n}\n\n/** Does this tool output represent an error (explicit flag or MCP `isError`)? */\nfunction isErrorOutput(payload: Record<string, unknown>): boolean {\n if (payload.error === true || payload.failed === true) {\n return true;\n }\n const output = payload.output;\n return !!output && typeof output === \"object\" && (output as { isError?: unknown }).isError === true;\n}\n\nfunction findOpenCall(items: TimelineItem[], callId: string | null): ToolCallItem | WorkerItem | undefined {\n const reversed = [...items].reverse();\n const isCall = (item: TimelineItem): item is ToolCallItem | WorkerItem => item.kind === \"tool-call\" || item.kind === \"worker\";\n if (callId) {\n const byId = reversed.find((item) => isCall(item) && item.callId === callId);\n if (byId) {\n return byId as ToolCallItem | WorkerItem;\n }\n }\n return reversed.find((item): item is ToolCallItem | WorkerItem => isCall(item) && item.status === \"running\");\n}\n\nfunction findOpenSandbox(items: TimelineItem[], name: string): SandboxItem | undefined {\n return [...items].reverse().find((item): item is SandboxItem => item.kind === \"sandbox\" && item.name === name && item.status === \"running\");\n}\n\nfunction failureMessage(payload: Record<string, unknown>): string | null {\n for (const key of [\"error\", \"message\"] as const) {\n const value = payload[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n // Auth/quota provider errors are rewritten for the right audience\n // (raw text remains in the event payload for debug surfaces).\n return humanizeFailureReason(value);\n }\n }\n return null;\n}\n\nfunction goalText(payload: Record<string, unknown>): string | null {\n if (typeof payload.text === \"string\" && payload.text) {\n return payload.text;\n }\n const goal = asRecord(payload.goal);\n if (typeof goal.text === \"string\" && goal.text) {\n return goal.text;\n }\n if (typeof payload.prompt === \"string\" && payload.prompt) {\n return payload.prompt;\n }\n return null;\n}\n\nfunction authNeededNoticeText(payload: Record<string, unknown>): string {\n const provider =\n typeof payload.providerDomain === \"string\" && payload.providerDomain.trim().length > 0 ? payload.providerDomain.trim() : \"This service\";\n const scopes = Array.isArray(payload.scopes)\n ? payload.scopes.filter((scope): scope is string => typeof scope === \"string\" && scope.trim().length > 0)\n : [];\n\n if (payload.reason === \"insufficient_scope\") {\n return scopes.length > 0 ? `${provider} needs additional access (${scopes.join(\", \")}).` : `${provider} needs additional access.`;\n }\n if (payload.reason === \"expired\" || payload.reason === \"refresh_failed\") {\n return `${provider} needs to be reconnected.`;\n }\n return `${provider} needs a connection.`;\n}\n\nfunction reasoningText(payload: unknown): string {\n const record = asRecord(payload);\n if (typeof record.text === \"string\") {\n return record.text;\n }\n const content = asRecord(asRecord(record.item).rawItem).content;\n if (!Array.isArray(content)) {\n return \"\";\n }\n return content\n .map((part) => {\n const text = asRecord(part).text;\n return typeof text === \"string\" ? text : \"\";\n })\n .join(\"\");\n}\n\n/** The worker's initial/sent message from `session_create`/`session_send_message` args. */\nfunction workerPrompt(args: unknown): string | null {\n const record = asRecord(typeof args === \"string\" ? tryParseJson(args) : args);\n for (const key of [\"initialMessage\", \"message\", \"text\", \"prompt\"] as const) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n }\n return null;\n}\n\n/** The interrupt mode from `session_interrupt` args; defaults to \"stop\". */\nfunction workerInterruptMode(args: unknown): \"stop\" | \"steer\" {\n const record = asRecord(typeof args === \"string\" ? tryParseJson(args) : args);\n return record.mode === \"steer\" ? \"steer\" : \"stop\";\n}\n\n/**\n * Find a session id in orchestration tool arguments or output. Handles raw\n * objects, JSON strings, and MCP tool results (`{ content: [{ type: \"text\",\n * text: \"{...}\" }], structuredContent? }`).\n */\nexport function extractSessionRef(value: unknown, depth = 0): string | null {\n if (depth > 6 || value === null || value === undefined) {\n return null;\n }\n if (typeof value === \"string\") {\n return extractSessionRef(tryParseJson(value), depth + 1);\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n const found = extractSessionRef(entry, depth + 1);\n if (found) {\n return found;\n }\n }\n return null;\n }\n if (typeof value !== \"object\") {\n return null;\n }\n const record = value as Record<string, unknown>;\n if (typeof record.sessionId === \"string\" && looksLikeId(record.sessionId)) {\n return record.sessionId;\n }\n if (typeof record.id === \"string\" && looksLikeId(record.id) && (\"status\" in record || \"workspaceId\" in record || \"initialMessage\" in record)) {\n return record.id;\n }\n for (const key of [\"structuredContent\", \"session\", \"result\", \"content\"] as const) {\n if (key in record) {\n const found = extractSessionRef(record[key], depth + 1);\n if (found) {\n return found;\n }\n }\n }\n if (typeof record.text === \"string\") {\n return extractSessionRef(tryParseJson(record.text), depth + 1);\n }\n return null;\n}\n\nfunction looksLikeId(value: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);\n}\n\n/** Readable label for a tool call (\"session_create\" -> \"session create\"). */\nexport function toolDisplayName(name: string): string {\n return name.replace(/[_-]+/g, \" \").trim();\n}\n","import type { ComponentType } from \"react\";\nimport type { ToolCallItem } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Tool renderer registry\n\n The extension point. A `ToolRenderer` is a React component fed one projected\n `ToolCallItem`; the registry resolves which renderer handles a given call,\n keyed on the tool `name` and (secondarily) its provider-native `raw.type`.\n\n Resolution order (most → least specific):\n 1. exact match on `raw.type` (e.g. \"apply_patch_call\", \"computer_call\")\n 2. exact match on the tool `name` (e.g. \"exec_command\", \"web_search_call\")\n 3. the registry's generic fallback\n\n A consumer extends the defaults without forking by passing overrides to\n `createToolRegistry` — e.g. a custom renderer for their own MCP tool, or a\n replacement for a built-in one. The registry is immutable and fully typed.\n -------------------------------------------------------------------------- */\n\nexport type ToolRendererProps = {\n item: ToolCallItem;\n};\n\nexport type ToolRenderer = ComponentType<ToolRendererProps>;\n\n/** A registry entry: which key it matches and the component that renders it. */\nexport type ToolRegistryEntry =\n | { match: \"rawType\"; type: string; render: ToolRenderer }\n | { match: \"name\"; name: string; render: ToolRenderer };\n\nexport type ToolRegistry = {\n /** Resolve the renderer for a call (never null — falls back to generic). */\n resolve: (item: ToolCallItem) => ToolRenderer;\n /** The generic fallback renderer. */\n fallback: ToolRenderer;\n};\n\nexport type CreateToolRegistryOptions = {\n /**\n * Entries that take precedence over the built-ins. Earlier entries win, so a\n * consumer can shadow a default renderer for the same key.\n */\n entries?: ToolRegistryEntry[] | undefined;\n /** Replace the generic fallback used for unmatched tools. */\n fallback?: ToolRenderer | undefined;\n};\n\n/** The `raw.type` of a projected tool call, when the provider item carries one. */\nexport function rawTypeOf(item: ToolCallItem): string | null {\n const raw = item.raw;\n if (raw && typeof raw === \"object\" && typeof (raw as { type?: unknown }).type === \"string\") {\n return (raw as { type: string }).type;\n }\n return null;\n}\n\n/**\n * Build a tool registry from a set of entries and a fallback. The returned\n * registry resolves in priority order: `raw.type` entries first, then `name`\n * entries, then the fallback. Consumer `entries` are consulted before the\n * built-in `baseEntries`, so they shadow defaults cleanly.\n */\nexport function createToolRegistry(\n baseEntries: ToolRegistryEntry[],\n baseFallback: ToolRenderer,\n options: CreateToolRegistryOptions = {},\n): ToolRegistry {\n const entries = [...(options.entries ?? []), ...baseEntries];\n const fallback = options.fallback ?? baseFallback;\n\n const byRawType = new Map<string, ToolRenderer>();\n const byName = new Map<string, ToolRenderer>();\n for (const entry of entries) {\n if (entry.match === \"rawType\") {\n if (!byRawType.has(entry.type)) {\n byRawType.set(entry.type, entry.render);\n }\n } else if (!byName.has(entry.name)) {\n byName.set(entry.name, entry.render);\n }\n }\n\n const resolve = (item: ToolCallItem): ToolRenderer => {\n const rawType = rawTypeOf(item);\n if (rawType) {\n const byType = byRawType.get(rawType);\n if (byType) {\n return byType;\n }\n }\n return byName.get(item.name) ?? fallback;\n };\n\n return { resolve, fallback };\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport {\n CameraIcon,\n CameraOffIcon,\n FileDiffIcon,\n GlobeIcon,\n ImageIcon,\n KeyboardIcon,\n KeyRoundIcon,\n LockIcon,\n MousePointer2Icon,\n PlugIcon,\n SearchIcon,\n TerminalIcon,\n WrenchIcon,\n} from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { stringifyPayload, tryParseJson } from \"../lib/format\";\nimport {\n applyPatchOps,\n controlCaret,\n execTruncated,\n isExecSessionLostBanner,\n looksBinary,\n parseExecBannerSessionId,\n parseToolArgs,\n redactSecrets,\n sandboxCommandExitCode,\n stripExecBanner,\n tailPeek,\n unwrapMcpOutput,\n v4aToGitFileDiff,\n screenshotDataUrl,\n type ApplyPatchOperation,\n} from \"./parsers\";\nimport { createToolRegistry, type ToolRegistry, type ToolRegistryEntry, type ToolRendererProps } from \"./registry\";\nimport {\n BodyNote,\n MediaEmpty,\n MediaSkeleton,\n PayloadBlock,\n ScreenshotFigure,\n TermBlock,\n Thumbnail,\n ActivityDisclosure,\n type DisclosureChip,\n} from \"./shared\";\nimport { RawPatch, ToolDiff } from \"./tool-diff\";\nimport { toolDisplayName } from \"./projection\";\n\n/* ----------------------------------------------------------------------------\n Per-tool renderers\n\n Each renderer takes one projected `ToolCallItem` and returns an `ActivityDisclosure`\n tuned for that tool's real wire shape. The defaults below populate the\n registry; the mapping is registered at the bottom of the file.\n\n Restraint is the rule: compact title + one quiet preview, secondary detail\n only on expand. No loud right-side badges — at most a single settle chip.\n -------------------------------------------------------------------------- */\n\nconst ICON_SIZE = \"size-3.5\";\n\n/**\n * The single in-flight locus for a running row: a pulse dot immediately left of\n * the status word, riding the preview line — NOT a detached gutter badge. The\n * title already shimmers; this keeps the live signal in one place the eye reads\n * left-to-right.\n */\nfunction RunningPreview({ children }: { children: ReactNode }) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"size-1.5 shrink-0 animate-og-pulse rounded-full bg-og-status-running\" />\n <span className=\"min-w-0 truncate\">{children}</span>\n </span>\n );\n}\n\n/* ---- exec_command ---------------------------------------------------------- */\n\nfunction ExecRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const cmd = typeof args.cmd === \"string\" ? args.cmd : \"\";\n const workdir = typeof args.workdir === \"string\" ? args.workdir : null;\n const running = item.status === \"running\";\n const out = item.output;\n const title = `$ ${cmd}`;\n\n // No output event ever arrived (item.output stays undefined from creation):\n // the turn failed before the output insert — most likely a NUL byte in the\n // command output prevented storage. Surface the specific explanation.\n // (Cancelled items bypass this: a cancellation is not a NUL-storage failure.)\n if (item.status === \"failed\" && out === undefined) {\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={title}\n titleMono\n chip={{ tone: \"bad\", text: \"failed\" }}\n preview=\"output lost — NUL byte could not be stored\"\n >\n <BodyNote tone=\"error\">\n output contained a NUL byte and could not be stored; the turn failed on this tool&apos;s output insert — no output\n event ever arrived.\n </BodyNote>\n </ActivityDisclosure>\n );\n }\n\n // An output event arrived but the tool still failed (error:true / MCP isError)\n // and the output is empty — show a generic failure rather than claiming NUL.\n // (Cancelled items bypass this: a cancellation is not a tool-call failure.)\n if (item.status === \"failed\" && (out == null || out === \"\")) {\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={title}\n titleMono\n chip={{ tone: \"bad\", text: \"failed\" }}\n preview=\"tool call failed\"\n >\n <BodyNote tone=\"error\">the tool call failed with no output.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n if (running) {\n const streamed = typeof out === \"string\" ? stripExecBanner(out) : \"\";\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={title}\n titleMono\n running\n preview={<RunningPreview>{streamed ? `${streamed.split(\"\\n\").length} lines` : \"running…\"}</RunningPreview>}\n >\n {/* The row title is already `$ ${cmd}`; the TermBlock header drops the\n command (command={null}) so it never repeats above the output. */}\n <TermBlock command={null} workdir={workdir} output={streamed} live />\n </ActivityDisclosure>\n );\n }\n\n const text = typeof out === \"string\" ? out : stringifyPayload(out);\n const stripped = stripExecBanner(text);\n const bgSession = parseExecBannerSessionId(text);\n const exitCode = sandboxCommandExitCode(text);\n const binary = looksBinary(stripped);\n\n // Color is spent on the exception only: a clean exit (0) earns NO chip — the\n // absence of a red token is the success signal. Background sessions surface a\n // muted id; a non-zero exit is the one red token.\n let chip: DisclosureChip | undefined;\n let iconTone: \"accent\" | \"failed\" | \"muted\" = \"muted\";\n if (bgSession != null) {\n chip = { tone: \"muted\", text: `session ${bgSession}` };\n } else if (exitCode != null && exitCode !== 0) {\n chip = { tone: \"bad\", text: `exit ${exitCode}` };\n iconTone = \"failed\";\n }\n\n const preview = binary ? \"binary output\" : tailPeek(stripped) || \"(no output)\";\n const truncated = execTruncated(text);\n // Hand TermBlock the FULL stripped output; it owns the tail/show-more slicing.\n const body = binary ? \"(binary output suppressed)\" : stripped;\n\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone={iconTone}\n title={title}\n titleMono\n {...(chip ? { chip } : {})}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n preview={truncated ? `⋯ truncated · ${preview}` : preview}\n >\n <TermBlock command={null} workdir={workdir} output={body} />\n {bgSession != null ? (\n <BodyNote>↳ session {bgSession} — a later write_stdin can target this PTY.</BodyNote>\n ) : null}\n </ActivityDisclosure>\n );\n}\n\n/* ---- write_stdin ----------------------------------------------------------- */\n\nfunction WriteStdinRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const sessionId = typeof args.session_id === \"string\" || typeof args.session_id === \"number\" ? args.session_id : undefined;\n const running = item.status === \"running\";\n const text = typeof item.output === \"string\" ? item.output : stringifyPayload(item.output);\n const lost = isExecSessionLostBanner(text);\n const keys = controlCaret(typeof args.chars === \"string\" ? args.chars : \"\");\n const exitCode = sandboxCommandExitCode(text);\n const stripped = stripExecBanner(text);\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={<KeyboardIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={`session ${sessionId} ← ${keys || \"∅\"}`}\n titleMono\n running\n preview={<RunningPreview>sending…</RunningPreview>}\n >\n <BodyNote>sending input to session {sessionId}…</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n // Success (exit 0 or a quiet ack) earns no chip; only a lost PTY / non-zero\n // exit gets the one red token.\n let chip: DisclosureChip | undefined;\n if (lost) {\n chip = { tone: \"bad\", text: \"lost\" };\n } else if (exitCode != null && exitCode !== 0) {\n chip = { tone: \"bad\", text: `exit ${exitCode}` };\n }\n\n return (\n <ActivityDisclosure\n icon={<KeyboardIcon className={ICON_SIZE} />}\n iconTone={lost ? \"failed\" : \"muted\"}\n title={`session ${sessionId} ← ${keys || \"∅\"}`}\n titleMono\n {...(chip ? { chip } : {})}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n preview={lost ? `session ${sessionId} PTY vanished` : tailPeek(stripped) || \"sent\"}\n >\n {lost ? (\n <BodyNote tone=\"error\">{stripped || text}</BodyNote>\n ) : (\n <TermBlock command={`write_stdin → session ${sessionId}`} output={stripped} />\n )}\n </ActivityDisclosure>\n );\n}\n\n/* ---- apply_patch ----------------------------------------------------------- */\n\nfunction verbForOp(op: ApplyPatchOperation | undefined): string {\n if (!op) {\n return \"Edited\";\n }\n return op.type === \"create_file\" ? \"Created\" : op.type === \"delete_file\" ? \"Deleted\" : op.moveTo ? \"Renamed\" : \"Edited\";\n}\n\nfunction basename(path: string): string {\n const parts = path.split(\"/\").filter(Boolean);\n return parts.length ? parts[parts.length - 1]! : path;\n}\n\nfunction dirname(path: string): string {\n const idx = path.lastIndexOf(\"/\");\n return idx >= 0 ? path.slice(0, idx + 1) : \"\";\n}\n\n/**\n * The collapsed-row path preview. Diff magnitude is rendered as a SINGLE muted\n * \"+N −M\" glyph pair — the saturated add/del green/red is reserved exclusively\n * for the expanded DiffView gutter, so the one-line rail stays a calm, single\n * hue (the file path) with no competing colored numerics.\n */\nfunction PathPreview({ path, add, del }: { path: string; add?: number | undefined; del?: number | undefined }) {\n return (\n <span className=\"inline-flex items-center gap-2 truncate font-og-mono\">\n <span className=\"truncate\">\n <span className=\"text-og-fg-subtle\">{dirname(path)}</span>\n <span className=\"text-og-fg-muted\">{basename(path)}</span>\n </span>\n {add != null || del != null ? (\n <span className=\"shrink-0 text-og-fg-subtle\">\n {add != null ? `+${add}` : \"\"}\n {add != null && del != null ? \" \" : \"\"}\n {del != null ? `−${del}` : \"\"}\n </span>\n ) : null}\n </span>\n );\n}\n\nfunction ApplyPatchRenderer({ item }: ToolRendererProps) {\n const ops = applyPatchOps(item.raw);\n const failed = item.status === \"failed\";\n const cancelled = item.status === \"cancelled\";\n const running = item.status === \"running\";\n const firstOp = ops[0];\n\n if (running) {\n // Show the patch structure from the arguments (available immediately on\n // creation), but mark the row clearly as in-progress — not applied yet.\n const fileCount = ops.length;\n const titleVerb = firstOp ? `Applying ${basename(firstOp.path)}` : \"Applying patch\";\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={fileCount > 1 ? `Applying ${fileCount} files` : titleVerb}\n running\n preview={<RunningPreview>{fileCount > 1 ? `${fileCount} files` : firstOp ? firstOp.path : \"applying…\"}</RunningPreview>}\n >\n {ops.map((op) => {\n const file = safeParseOp(op);\n return file ? (\n <ToolDiff key={op.path} files={[file]} />\n ) : (\n <div key={op.path}>\n <p className=\"mb-1 font-og-mono text-og-xs text-og-fg-muted\">{op.path}</p>\n <RawPatch diff={op.diff ?? \"\"} />\n </div>\n );\n })}\n </ActivityDisclosure>\n );\n }\n\n if (failed) {\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={firstOp ? `${verbForOp(firstOp)} ${basename(firstOp.path)}` : \"apply_patch\"}\n chip={{ tone: \"bad\", text: \"failed\" }}\n preview={typeof item.output === \"string\" ? item.output : \"patch failed\"}\n >\n <PayloadBlock label=\"Error\" value={item.output} failed />\n </ActivityDisclosure>\n );\n }\n\n // multi-file edit — magnitude stays a single muted glyph; the per-file\n // green/red lives only inside the expanded DiffView gutter.\n if (ops.length > 1) {\n // Parse every op: successfully parsed ones go into ToolDiff; malformed ops\n // fall back to a RawPatch display (mirroring the single-op fallback path).\n // The count in the title/preview equals ops.length so it is always truthful\n // regardless of how many ops parsed successfully.\n const parsed = ops.map((op) => safeParseOp(op));\n const goodFiles = parsed.filter((f): f is GitFileDiff => f !== null);\n const add = goodFiles.reduce((n, f) => n + f.additions, 0);\n const del = goodFiles.reduce((n, f) => n + f.deletions, 0);\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"accent\"\n title={`Edited ${ops.length} files`}\n cancelled={cancelled}\n preview={\n <span className=\"inline-flex items-center gap-2 font-og-mono\">\n <span className=\"text-og-fg-muted\">{ops.length} files</span>\n <span className=\"text-og-fg-subtle\">\n +{add} −{del}\n </span>\n </span>\n }\n >\n {ops.map((op, index) => {\n const file = parsed[index];\n return file ? (\n <ToolDiff key={op.path} files={[file]} />\n ) : (\n <div key={op.path}>\n <p className=\"mb-1 font-og-mono text-og-xs text-og-fg-muted\">{op.path}</p>\n <RawPatch diff={op.diff ?? \"\"} />\n </div>\n );\n })}\n </ActivityDisclosure>\n );\n }\n\n // single op\n if (!firstOp) {\n return <GenericRenderer item={item} />;\n }\n if (firstOp.type === \"delete_file\") {\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={`Deleted ${basename(firstOp.path)}`}\n cancelled={cancelled}\n preview={<PathPreview path={firstOp.path} />}\n >\n <BodyNote>File deleted — no diff to show.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n const file = safeParseOp(firstOp);\n if (!file) {\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"accent\"\n title={`${verbForOp(firstOp)} ${basename(firstOp.path)}`}\n cancelled={cancelled}\n preview={\n <span className=\"inline-flex items-center gap-2 font-og-mono\">\n <span className=\"text-og-fg-muted\">{basename(firstOp.path)}</span>\n <span className=\"text-og-fg-subtle\">malformed V4A</span>\n </span>\n }\n >\n <RawPatch diff={firstOp.diff ?? \"\"} />\n </ActivityDisclosure>\n );\n }\n\n // The collapsed row shows verb + basename (title) and a muted \"+N −M\"\n // (preview); on expand the preview is hidden and the DiffView header carries\n // the path + churn — so the filename/stat never appears twice at once.\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"accent\"\n title={`${verbForOp(firstOp)} ${basename(file.path)}`}\n cancelled={cancelled}\n preview={<PathPreview path={file.path} add={file.additions} del={file.deletions} />}\n >\n <ToolDiff files={[file]} />\n </ActivityDisclosure>\n );\n}\n\nfunction safeParseOp(op: ApplyPatchOperation): GitFileDiff | null {\n try {\n return v4aToGitFileDiff(op);\n } catch {\n return null;\n }\n}\n\n/* ---- computer_call --------------------------------------------------------- */\n\ntype ComputerAction = {\n type?: string;\n x?: number;\n y?: number;\n text?: string;\n keys?: string[];\n button?: string;\n};\n\nfunction computerVerb(action: ComputerAction | undefined): string {\n if (!action || !action.type) {\n return \"Acted\";\n }\n switch (action.type) {\n case \"screenshot\":\n return \"Screenshot\";\n case \"click\":\n return `Clicked (${action.x}, ${action.y})`;\n case \"double_click\":\n return `Double-clicked (${action.x}, ${action.y})`;\n case \"move\":\n return `Moved (${action.x}, ${action.y})`;\n case \"scroll\":\n return \"Scrolled\";\n case \"type\": {\n const t = action.text ?? \"\";\n return `Typed “${t.slice(0, 28)}${t.length > 28 ? \"…\" : \"\"}”`;\n }\n case \"keypress\":\n return `Pressed ${(action.keys ?? []).join(\"+\")}`;\n case \"drag\":\n return \"Dragged\";\n case \"wait\":\n return \"Waited\";\n default:\n return action.type;\n }\n}\n\n\n/** Coerce a function-tool arguments payload into the ComputerAction fields. */\nfunction asComputerArgs(args: unknown): Partial<ComputerAction> {\n if (!args) {\n return {};\n }\n const parsed = typeof args === \"string\" ? tryParseJson(args) : args;\n if (!parsed || typeof parsed !== \"object\") {\n return {};\n }\n const record = parsed as Record<string, unknown>;\n return {\n ...(typeof record.x === \"number\" ? { x: record.x } : {}),\n ...(typeof record.y === \"number\" ? { y: record.y } : {}),\n ...(typeof record.text === \"string\" ? { text: record.text } : {}),\n ...(Array.isArray(record.keys) ? { keys: record.keys as string[] } : {}),\n ...(typeof record.button === \"string\" ? { button: record.button } : {}),\n };\n}\n\nfunction ComputerCallRenderer({ item }: ToolRendererProps) {\n const raw = (item.raw ?? {}) as {\n action?: ComputerAction;\n actions?: ComputerAction[];\n providerData?: { approvalStatus?: string };\n };\n // Function-mode computer tools (computer_screenshot / computer_click / …,\n // used on codex + chat-wire providers since the explicit tool-transport\n // change) carry the action in the tool NAME + arguments instead of raw.action.\n // Normalize them into the same ComputerAction shape so one renderer serves\n // every transport.\n const functionAction: ComputerAction | undefined =\n !raw.action && item.name.startsWith(\"computer_\") && item.name !== \"computer_call\"\n ? { type: item.name.slice(\"computer_\".length), ...(asComputerArgs(item.arguments)) }\n : undefined;\n const action = raw.action ?? functionAction;\n const actions = raw.actions ?? (action ? [action] : []);\n const verb = computerVerb(action);\n const out = item.output;\n const running = item.status === \"running\";\n const rejected = raw.providerData?.approvalStatus === \"rejected\";\n const readOnly = typeof out === \"string\" && out.includes(\"read-only\");\n const shotUrl = screenshotDataUrl(out);\n const empty = out === \"\" || out == null;\n const batched = actions.length > 1 ? actions.map((a) => computerVerb(a)).join(\" · \") : null;\n // Fold the batched-action count into the title (one media affordance per row),\n // rather than a separate \"+N more\" mono label competing beside the thumbnail.\n const countSuffix = actions.length > 1 ? ` ·${actions.length}` : \"\";\n const isShot = action?.type === \"screenshot\";\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={isShot ? <CameraIcon className={ICON_SIZE} /> : <MousePointer2Icon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={verb}\n running\n media={<MediaSkeleton />}\n >\n <BodyNote>capturing frame…</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n if (readOnly) {\n return (\n <ActivityDisclosure\n icon={<MousePointer2Icon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={verb}\n chip={{ tone: \"bad\", text: \"read-only\" }}\n preview=\"write actions disabled\"\n >\n <BodyNote tone=\"error\">computer-use is read-only — write actions are disabled.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n if (rejected) {\n return (\n <ActivityDisclosure\n icon={<LockIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title={verb}\n preview=\"approval rejected — this action did not run\"\n >\n <BodyNote>approval rejected — this action did not run.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n const isFailed = item.status === \"failed\";\n const isCancelled = item.status === \"cancelled\";\n\n if (shotUrl) {\n const caption = `${verb}${actions.length > 1 ? ` (+${actions.length - 1} more)` : \"\"}`;\n return (\n <ActivityDisclosure\n icon={isShot ? <CameraIcon className={ICON_SIZE} /> : <MousePointer2Icon className={ICON_SIZE} />}\n iconTone={isFailed ? \"failed\" : \"accent\"}\n title={`${verb}${countSuffix}`}\n failed={isFailed}\n cancelled={isCancelled}\n media={<Thumbnail src={shotUrl} caption={caption} />}\n >\n <ScreenshotFigure src={shotUrl} caption={caption} />\n {batched ? <BodyNote>batched: {batched}</BodyNote> : null}\n </ActivityDisclosure>\n );\n }\n\n if (empty) {\n return (\n <ActivityDisclosure\n icon={<CameraOffIcon className={ICON_SIZE} />}\n iconTone={isFailed ? \"failed\" : \"muted\"}\n title={verb}\n failed={isFailed}\n cancelled={isCancelled}\n media={<MediaEmpty />}\n >\n <BodyNote>{isFailed ? \"computer_call failed — no image returned.\" : isCancelled ? \"computer_call interrupted — no image returned.\" : \"(no image) — the session returned an empty screenshot.\"}</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n // a non-screenshot action whose output is not an image (click/keypress)\n return (\n <ActivityDisclosure\n icon={<MousePointer2Icon className={ICON_SIZE} />}\n iconTone={isFailed ? \"failed\" : \"accent\"}\n title={verb}\n failed={isFailed}\n cancelled={isCancelled}\n preview={batched ?? undefined}\n expandable={batched != null}\n >\n {batched ? <BodyNote>{batched}</BodyNote> : null}\n </ActivityDisclosure>\n );\n}\n\n/* ---- web_search ------------------------------------------------------------ */\n\ntype WebSearchResult = { title: string; domain: string; snippet: string };\n\nfunction WebSearchRenderer({ item }: ToolRendererProps) {\n const raw = (item.raw ?? {}) as { providerData?: { action?: { query?: string; queries?: string[] } } };\n const action = raw.providerData?.action ?? {};\n const query = action.query ?? \"(query unavailable)\";\n const queries = action.queries ?? [];\n const variants = queries.length > 1 ? ` +${queries.length - 1} variants` : \"\";\n const running = item.status === \"running\";\n // web_search may surface a results array on the output when the host enriches it.\n // Filter out null/undefined/non-object entries before casting: host-provided\n // data is untrusted and a null element would throw on result.title access.\n const rawResults = (item.output as { results?: unknown } | undefined)?.results;\n const results = Array.isArray(rawResults)\n ? (rawResults as unknown[]).filter((r): r is WebSearchResult => !!r && typeof r === \"object\")\n : undefined;\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={<SearchIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title=\"Searching the web\"\n running\n preview={<RunningPreview>{`${query}${variants}`}</RunningPreview>}\n >\n <BodyNote>searching… results fold into the model context (no output event).</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n return (\n <ActivityDisclosure\n icon={<SearchIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title=\"Searched the web\"\n preview={`${query}${variants}`}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n >\n {results && results.length ? (\n <ul className=\"flex flex-col gap-2\">\n {results.map((result, index) => (\n <li key={index} className=\"flex gap-2.5\">\n <GlobeIcon className=\"mt-0.5 size-3.5 shrink-0 text-og-fg-subtle\" />\n <div className=\"min-w-0\">\n <p className=\"truncate text-og-base text-og-fg\">\n {result.title} <span className=\"text-og-fg-subtle\">{result.domain}</span>\n </p>\n <p className=\"text-og-sm leading-5 text-og-fg-muted\">{result.snippet}</p>\n </div>\n </li>\n ))}\n </ul>\n ) : (\n <BodyNote>results folded into model context — no list available.</BodyNote>\n )}\n </ActivityDisclosure>\n );\n}\n\n/* ---- view_image ------------------------------------------------------------ */\n\nconst VIEW_IMAGE_ERRORS = [\"was not found\", \"is not a file\", \"exceeded the allowed size\", \"is not a supported image\", \"unable to read image\"];\n\nfunction ViewImageRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const path = typeof args.path === \"string\" ? args.path : \"\";\n const out = item.output;\n const text = typeof out === \"string\" ? out : \"\";\n\n if (item.status === \"running\") {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={`View ${basename(path)}`}\n running\n preview={<RunningPreview>reading…</RunningPreview>}\n media={<MediaSkeleton />}\n >\n <BodyNote>reading image…</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n const viewFailed = item.status === \"failed\";\n const viewCancelled = item.status === \"cancelled\";\n\n const errMatch = VIEW_IMAGE_ERRORS.find((p) => text.includes(p));\n if (errMatch) {\n const tooBig = text.includes(\"exceeded the allowed size\");\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={`View ${basename(path)}`}\n chip={{ tone: \"bad\", text: tooBig ? \"too large\" : \"error\" }}\n preview={text}\n >\n <BodyNote tone=\"error\">{text}</BodyNote>\n </ActivityDisclosure>\n );\n }\n if (text.startsWith(\"OpenAI file reference:\")) {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone={viewFailed ? \"failed\" : \"muted\"}\n title={`Viewed ${basename(path)}`}\n failed={viewFailed}\n cancelled={viewCancelled}\n preview={path}\n >\n <BodyNote>{text}</BodyNote>\n </ActivityDisclosure>\n );\n }\n if (text.includes(\"No image data\")) {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone={viewFailed ? \"failed\" : \"muted\"}\n title={`Viewed ${basename(path)}`}\n failed={viewFailed}\n cancelled={viewCancelled}\n preview=\"(no image)\"\n >\n <BodyNote>{viewFailed ? \"view_image failed — no image data returned.\" : viewCancelled ? \"view_image interrupted.\" : \"(no image) — the sandbox session returned no image data.\"}</BodyNote>\n </ActivityDisclosure>\n );\n }\n if (text.startsWith(\"data:\")) {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone={viewFailed ? \"failed\" : \"accent\"}\n title={`Viewed ${basename(path)}`}\n failed={viewFailed}\n cancelled={viewCancelled}\n media={<Thumbnail src={text} caption={path} alt={path} />}\n >\n <ScreenshotFigure src={text} caption={path} alt={path} />\n </ActivityDisclosure>\n );\n }\n return <GenericRenderer item={item} />;\n}\n\n/* ---- environment_set_variable (secret-safe, write-only) -------------------- */\n\nfunction SecretSetRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const name = typeof args.name === \"string\" ? args.name : \"variable\";\n\n if (item.status === \"running\") {\n return (\n <ActivityDisclosure\n icon={<KeyRoundIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={`Set ${name}`}\n running\n preview={<RunningPreview>setting…</RunningPreview>}\n >\n <PayloadBlock label=\"Arguments\" value={redactSecrets(args)} />\n </ActivityDisclosure>\n );\n }\n\n if (item.status === \"failed\") {\n const errorText = typeof item.output === \"string\" ? item.output : null;\n return (\n <ActivityDisclosure\n icon={<KeyRoundIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={`Set ${name}`}\n failed\n preview={errorText ?? \"variable write failed\"}\n >\n <PayloadBlock label=\"Arguments\" value={redactSecrets(args)} />\n {errorText ? <PayloadBlock label=\"Error\" value={errorText} failed /> : <BodyNote tone=\"error\">the tool call failed with no output.</BodyNote>}\n </ActivityDisclosure>\n );\n }\n\n return (\n <ActivityDisclosure\n icon={<KeyRoundIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title={`Set ${name}`}\n cancelled={item.status === \"cancelled\"}\n preview=\"value write-only · never returned\"\n >\n <PayloadBlock label=\"Arguments\" value={redactSecrets(args)} />\n <BodyNote>the value is a secret — redacted in every view; the API never returns it.</BodyNote>\n </ActivityDisclosure>\n );\n}\n\n/* ---- generic fallback (first-party MCP, external MCP, unknown) ------------- */\n\nfunction GenericRenderer({ item }: ToolRendererProps) {\n const running = item.status === \"running\";\n const args = redactSecrets(parseToolArgs(item.arguments));\n const display = toolDisplayName(item.name);\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={<PlugIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={display}\n running\n preview={<RunningPreview>{compactArgs(args) || \"running…\"}</RunningPreview>}\n >\n <PayloadBlock label=\"Arguments\" value={args} />\n </ActivityDisclosure>\n );\n }\n\n const { text: outText, isError } = unwrapMcpOutput(item.output);\n // Cancelled is NOT an error — a user-cancelled tool should not surface the red\n // error chip even if the output payload carries an isError flag (the error may be\n // a consequence of the cancellation, not the tool's own failure).\n if ((isError || item.status === \"failed\") && item.status !== \"cancelled\") {\n return (\n <ActivityDisclosure\n icon={<WrenchIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={display}\n chip={{ tone: \"bad\", text: \"error\" }}\n preview={outText.slice(0, 80)}\n >\n <PayloadBlock label=\"Arguments\" value={args} />\n <PayloadBlock label=\"Error\" value={outText} failed />\n </ActivityDisclosure>\n );\n }\n\n return (\n <ActivityDisclosure\n icon={<WrenchIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title={display}\n cancelled={item.status === \"cancelled\"}\n preview={compactArgs(args)}\n >\n <PayloadBlock label=\"Arguments\" value={args} />\n <PayloadBlock label=\"Result\" value={outText} />\n </ActivityDisclosure>\n );\n}\n\nfunction compactArgs(args: unknown): string {\n const text = stringifyPayload(args).replace(/\\s+/g, \" \").trim();\n return text === \"{}\" ? \"\" : text.length > 90 ? `${text.slice(0, 89)}…` : text;\n}\n\n/* ---- the default registry -------------------------------------------------- */\n\nconst BASE_ENTRIES: ToolRegistryEntry[] = [\n // Provider-native items carry `raw.type` on the wire — this is their source of\n // truth and is consulted first by the registry.\n { match: \"rawType\", type: \"apply_patch_call\", render: ApplyPatchRenderer },\n { match: \"rawType\", type: \"computer_call\", render: ComputerCallRenderer },\n { match: \"rawType\", type: \"hosted_tool_call\", render: WebSearchRenderer },\n // First-party sandbox + MCP tools resolve by name. `apply_patch_call` /\n // `computer_call` are intentionally repeated by name as a fallback only for\n // first-party replays that omit `raw` (the rawType entries above win whenever\n // `raw.type` is present, which is the live-wire case).\n { match: \"name\", name: \"exec_command\", render: ExecRenderer },\n { match: \"name\", name: \"write_stdin\", render: WriteStdinRenderer },\n { match: \"name\", name: \"apply_patch_call\", render: ApplyPatchRenderer },\n { match: \"name\", name: \"computer_call\", render: ComputerCallRenderer },\n // Function-mode computer tools (codex / chat-wire transports).\n { match: \"name\", name: \"computer_screenshot\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_click\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_double_click\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_move\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_scroll\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_type\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_keypress\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_drag\", render: ComputerCallRenderer },\n { match: \"name\", name: \"web_search_call\", render: WebSearchRenderer },\n { match: \"name\", name: \"view_image\", render: ViewImageRenderer },\n { match: \"name\", name: \"environment_set_variable\", render: SecretSetRenderer },\n];\n\n/** The built-in tool renderer registry: every first-party tool plus a fallback. */\nexport const defaultToolRegistry: ToolRegistry = createToolRegistry(BASE_ENTRIES, GenericRenderer);\n\n/** Build a registry that extends the built-ins with consumer entries/fallback. */\nexport function createDefaultToolRegistry(\n options: Parameters<typeof createToolRegistry>[2] = {},\n): ToolRegistry {\n return createToolRegistry(BASE_ENTRIES, GenericRenderer, options);\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { tryParseJson } from \"../lib/format\";\n\n/* ----------------------------------------------------------------------------\n Pure parsers for the provider-native tool shapes that the timeline renders.\n\n These are intentionally browser-safe, dependency-free mirrors of the\n server-side helpers in `@opengeni/runtime` (`sandboxCommandExitCode`,\n `parseExecBannerSessionId`, `stripExecBanner`) plus the V4A diff parser the\n apply-patch renderer needs. The SDK does not depend on `@opengeni/runtime` by\n design (runtime is a heavy server package); these few regexes are cheap to\n own here and keep the React surface free of a server dependency.\n\n Every function is pure -- same input, same output -- so it can be\n unit-tested and memoized.\n -------------------------------------------------------------------------- */\n\n/** Recover the exit code from a sandbox exec banner (`Process exited with code N`). */\nexport function sandboxCommandExitCode(out: unknown): number | null {\n const match = String(out ?? \"\").match(/Process exited with code (-?\\d+)/);\n return match ? Number(match[1]) : null;\n}\n\n/**\n * Recover the numeric exec-session id the sandbox embeds for a STILL-RUNNING\n * (backgrounded) process (`Process running with session ID N`). A finished\n * command emits `Process exited with code N` instead, which yields `null`.\n */\nexport function parseExecBannerSessionId(out: unknown): number | null {\n const text = String(out ?? \"\");\n const outputIdx = text.indexOf(\"\\nOutput:\\n\");\n const banner = outputIdx >= 0 ? text.slice(0, outputIdx) : text.startsWith(\"Output:\\n\") ? \"\" : text;\n const match = banner.match(/Process running with session ID (\\d+)/);\n if (!match) {\n return null;\n }\n const n = Number.parseInt(match[1]!, 10);\n return Number.isFinite(n) ? n : null;\n}\n\n/** Strip the exec banner (`Chunk ID ...\\n...\\nOutput:\\n`) down to the command's stdout. */\nexport function stripExecBanner(out: unknown): string {\n const text = String(out ?? \"\");\n const marker = text.indexOf(\"\\nOutput:\\n\");\n if (marker >= 0) {\n return text.slice(marker + \"\\nOutput:\\n\".length);\n }\n if (text.startsWith(\"Output:\\n\")) {\n return text.slice(\"Output:\\n\".length);\n }\n return text;\n}\n\n/** The sandbox clamped the output (token/line truncation markers in the banner). */\nexport function execTruncated(out: unknown): boolean {\n return /Total output lines:|\\.{3}\\d+ tokens truncated\\.{3}|\\[\\.{3}\\d+ characters truncated/.test(String(out ?? \"\"));\n}\n\n/** A `write_stdin` whose target PTY vanished (`write_stdin failed: session not found: N`). */\nexport function isExecSessionLostBanner(out: unknown): boolean {\n return /write_stdin failed: session not found: \\d+/.test(String(out ?? \"\"));\n}\n\n/** True when the exec stdout looks binary/garbled (a NUL byte or ELF magic). */\nexport function looksBinary(text: string): boolean {\n return text.includes(\"\\u0000\") || text.startsWith(\"\\u007fELF\");\n}\n\n/**\n * Render unprintable control characters as caret notation (0x03 -> `^C`) so a\n * `write_stdin` keystroke payload reads cleanly in the row title.\n */\nexport function controlCaret(printable: string): string {\n return String(printable).replace(/[\\u0000-\\u001f]/g, (c) => `^${String.fromCharCode(c.charCodeAt(0) + 64)}`);\n}\n\n/* --- V4A apply_patch diff -> GitFileDiff ------------------------------------ */\n\n/** One operation inside an `apply_patch_call` (a V4A file edit). */\nexport type ApplyPatchOperation = {\n /**\n * The V4A op kind. The three canonical values are `create_file`,\n * `update_file`, and `delete_file`; the open `string` tail tolerates a\n * forward-compatible/unknown op kind from the provider without a type error\n * (it falls through to the \"Edited\" treatment).\n */\n type: \"create_file\" | \"update_file\" | \"delete_file\" | (string & {});\n path: string;\n /** Rename target -- when present the op is a move/rename. */\n moveTo?: string | null | undefined;\n /** The V4A hunk string (`@@ ...` lines with `+`/`-`/context prefixes). */\n diff?: string | undefined;\n};\n\n/**\n * Parse a single V4A `apply_patch` operation into the SDK's `GitFileDiff` shape\n * so it can flow into the SAME `DiffView` / `PierreDiff` the Files tab uses.\n * Throws on a hunk string it cannot structure (no `@@` anchor on an update); the\n * renderer catches and falls back to a raw-patch view.\n */\nexport function v4aToGitFileDiff(op: ApplyPatchOperation): GitFileDiff {\n const status: GitFileDiff[\"status\"] =\n op.type === \"create_file\" ? \"added\" : op.type === \"delete_file\" ? \"deleted\" : op.moveTo ? \"renamed\" : \"modified\";\n const oldPath = op.moveTo ? op.path : null;\n const path = op.moveTo || op.path;\n\n const hunks: GitFileDiff[\"hunks\"] = [];\n let additions = 0;\n let deletions = 0;\n let sawHunkAnchor = false;\n\n if (op.type !== \"delete_file\") {\n const lines = (op.diff ?? \"\").split(\"\\n\");\n let cur: GitFileDiff[\"hunks\"][number] | null = null;\n let oldNo = 1;\n let newNo = 1;\n for (const raw of lines) {\n if (raw.startsWith(\"@@\")) {\n sawHunkAnchor = true;\n const match = raw.match(/-(\\d+)(?:,\\d+)?\\s+\\+(\\d+)/);\n oldNo = match ? Number(match[1]) : 1;\n newNo = match ? Number(match[2]) : 1;\n cur = {\n oldStart: oldNo,\n oldLines: 0,\n newStart: newNo,\n newLines: 0,\n header: raw,\n lines: [{ type: \"meta\", oldNo: null, newNo: null, text: raw }],\n };\n hunks.push(cur);\n } else if (cur || op.type === \"create_file\") {\n if (!cur) {\n // No `@@` anchor on a create_file body: synthesize an add-only hunk.\n // Leave `header` empty so `gitFileDiffToPatch` regenerates a valid\n // `@@ -0,0 +1,N @@` from the range fields once newLines is counted — a\n // pre-baked partial header (e.g. `@@ +1 @@`) renders zero lines in a\n // generic unified-diff parser.\n cur = { oldStart: 0, oldLines: 0, newStart: 1, newLines: 0, header: \"\", lines: [] };\n hunks.push(cur);\n oldNo = 0;\n newNo = 1;\n }\n if (raw.startsWith(\"+\")) {\n cur.lines.push({ type: \"add\", oldNo: null, newNo: newNo++, text: raw.slice(1) });\n cur.newLines += 1;\n additions += 1;\n } else if (raw.startsWith(\"-\")) {\n cur.lines.push({ type: \"del\", oldNo: oldNo++, newNo: null, text: raw.slice(1) });\n cur.oldLines += 1;\n deletions += 1;\n } else {\n cur.lines.push({ type: \"context\", oldNo: oldNo++, newNo: newNo++, text: raw.replace(/^ /, \"\") });\n cur.oldLines += 1;\n cur.newLines += 1;\n }\n }\n }\n // An update with content but no recognizable hunk anchor is malformed V4A;\n // the caller falls back to the raw-patch view instead of a structured diff.\n if (op.type === \"update_file\" && !sawHunkAnchor && lines.some((l) => l.trim().length > 0)) {\n throw new Error(\"malformed V4A: no @@ hunk anchor\");\n }\n }\n\n return { path, oldPath, status, isBinary: false, isImage: false, additions, deletions, hunks, truncated: false };\n}\n\n/**\n * Extract the `apply_patch` operations from a provider-native tool item's `raw`\n * payload, normalizing the two wire shapes (`raw.operations[]` for a multi-file\n * patch, `raw.operation` for a single op). The single owner of this shape so the\n * renderer and the turn-summary facet counter never drift.\n */\nexport function applyPatchOps(raw: unknown): ApplyPatchOperation[] {\n const r = (raw ?? {}) as { operation?: ApplyPatchOperation; operations?: ApplyPatchOperation[] };\n if (Array.isArray(r.operations)) {\n return r.operations;\n }\n return r.operation ? [r.operation] : [];\n}\n\n/**\n * True when a tool item is an `apply_patch_call` — by its provider-native\n * `raw.type` (the live-wire source of truth) or by tool `name` (first-party\n * replays that omit `raw`). Centralizes the rawType-or-name check.\n */\nexport function isApplyPatch(item: { name: string; raw: unknown }): boolean {\n const type = item.raw && typeof item.raw === \"object\" ? (item.raw as { type?: unknown }).type : undefined;\n return type === \"apply_patch_call\" || item.name === \"apply_patch_call\";\n}\n\n/* --- secret redaction ------------------------------------------------------- */\n\nconst SECRET_KEY = /^(value|secret|token|password|api[_-]?key|signing[_-]?key)$/i;\n\n/** Deep-redact secret-looking values so arguments never leak a key into the UI. */\nexport function redactSecrets(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(redactSecrets);\n }\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = SECRET_KEY.test(k) ? \"••••\" : redactSecrets(v);\n }\n return out;\n }\n return value;\n}\n\n/** Parse tool arguments that may arrive as a JSON string or an object. */\nexport function parseToolArgs(args: unknown): Record<string, unknown> {\n if (args == null) {\n return {};\n }\n if (typeof args === \"string\") {\n const parsed = tryParseJson(args);\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, unknown>) : {};\n }\n return typeof args === \"object\" ? (args as Record<string, unknown>) : {};\n}\n\n/** The last non-empty line of a string -- the compact \"what happened\" peek. */\nexport function tailPeek(text: string): string {\n const trimmed = text.trim();\n if (!trimmed) {\n return \"\";\n }\n const lines = trimmed.split(\"\\n\");\n return lines[lines.length - 1] ?? \"\";\n}\n\n/**\n * Unwrap an MCP tool result (`{ content: [{ type: \"text\", text }], isError? }`)\n * into a flat `{ text, isError }`. Non-MCP outputs pass through as their string\n * form.\n */\nexport function unwrapMcpOutput(output: unknown): { text: string; isError: boolean } {\n if (output && typeof output === \"object\" && \"content\" in output) {\n const record = output as { content?: unknown; isError?: unknown };\n const isError = Boolean(record.isError);\n if (Array.isArray(record.content)) {\n const textPart = record.content.find(\n (part): part is { type: string; text: string } =>\n !!part && typeof part === \"object\" && (part as { type?: unknown }).type === \"text\",\n );\n return { text: textPart ? String(textPart.text) : JSON.stringify(output), isError };\n }\n return { text: JSON.stringify(output), isError };\n }\n return { text: typeof output === \"string\" ? output : output == null ? \"\" : JSON.stringify(output), isError: false };\n}\n\n/* --- computer-use screenshot extraction ------------------------------------- */\n\n/**\n * Extract a renderable `data:` URL from a computer-use screenshot output,\n * whatever transport produced it. The hosted `computer_call` and the\n * function-text mode persist a plain `data:image/...` string; the\n * function-image mode (codex-backed sessions) persists the STRUCTURED image\n * output — `{type:\"image\", image:{data, mediaType}}` with `data` arriving as a\n * number array / index map / Buffer-JSON / base64 string after event\n * serialization — or the agents-core normalized `input_image` content item.\n * Returns null when the output carries no image (so callers fall back to their\n * text/empty presentation).\n */\nexport function screenshotDataUrl(out: unknown): string | null {\n if (typeof out === \"string\") {\n if (out.startsWith(\"data:image\")) {\n return out;\n }\n // A JSON-encoded structured output (some transports stringify tool results).\n if (out.startsWith(\"{\") || out.startsWith(\"[\")) {\n const parsed = tryParseJson(out);\n if (parsed !== undefined && parsed !== out) {\n return screenshotDataUrl(parsed);\n }\n }\n return null;\n }\n if (Array.isArray(out)) {\n for (const entry of out) {\n const url = screenshotDataUrl(entry);\n if (url) {\n return url;\n }\n }\n return null;\n }\n if (out === null || typeof out !== \"object\") {\n return null;\n }\n const record = out as Record<string, unknown>;\n // agents-core normalized content item: {type:\"input_image\", image_url: \"data:…\" | {url}}\n const imageUrl = record.image_url ?? record.imageUrl;\n if (typeof imageUrl === \"string\" && imageUrl.startsWith(\"data:image\")) {\n return imageUrl;\n }\n if (imageUrl && typeof imageUrl === \"object\") {\n const url = (imageUrl as Record<string, unknown>).url;\n if (typeof url === \"string\" && url.startsWith(\"data:image\")) {\n return url;\n }\n }\n // Structured tool output: {type:\"image\", image:{data, mediaType}}\n const image = record.image as Record<string, unknown> | undefined;\n if (image && typeof image === \"object\") {\n const mediaType = typeof image.mediaType === \"string\" ? image.mediaType : \"image/png\";\n const base64 = bytesToBase64(image.data);\n if (base64) {\n return `data:${mediaType};base64,${base64}`;\n }\n if (typeof image.data === \"string\" && image.data.length > 0) {\n // Already base64 text.\n return `data:${mediaType};base64,${image.data}`;\n }\n }\n return null;\n}\n\n/** Serialize whatever a Uint8Array became in JSON (number[], {\"0\":n,…} index\n * map, or Buffer-JSON {type:\"Buffer\",data:[…]}) back into base64. */\nfunction bytesToBase64(data: unknown): string | null {\n const isByte = (n: unknown): n is number => typeof n === \"number\" && Number.isInteger(n) && n >= 0 && n <= 255;\n let bytes: number[] | null = null;\n if (Array.isArray(data) && data.every(isByte)) {\n bytes = data;\n } else if (data && typeof data === \"object\") {\n const record = data as Record<string, unknown>;\n if (record.type === \"Buffer\" && Array.isArray(record.data) && record.data.every(isByte)) {\n bytes = record.data;\n } else {\n const keys = Object.keys(record);\n if (keys.length > 0 && keys.every((key) => /^\\d+$/.test(key))) {\n const values = keys.sort((a, b) => Number(a) - Number(b)).map((key) => record[key]);\n if (values.every(isByte)) {\n bytes = values;\n }\n }\n }\n }\n if (!bytes || bytes.length === 0) {\n return null;\n }\n try {\n let binary = \"\";\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n binary += String.fromCharCode(...bytes.slice(i, i + CHUNK));\n }\n return typeof btoa === \"function\" ? btoa(binary) : Buffer.from(binary, \"binary\").toString(\"base64\");\n } catch {\n // A hostile/absurd payload must degrade to \"no image\", never crash a render.\n return null;\n }\n}\n","import { CameraIcon, CameraOffIcon, ChevronRightIcon } from \"lucide-react\";\nimport { useState, type ReactNode } from \"react\";\nimport { Collapsible } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\nimport { stringifyPayload } from \"../lib/format\";\nimport { useForcedDefaultOpen } from \"./disclosure-context\";\nimport { useLightboxOptional } from \"./screenshot-lightbox\";\n\n/* ----------------------------------------------------------------------------\n Shared timeline primitives\n\n The restraint layer. One disclosure shape every tool renderer reuses, so the\n rail reads as a calm, aligned column: a chevron, a tinted icon, a title, an\n optional muted preview, and — at most — ONE quiet right-aligned signal\n (a settle chip). Compact by default; the body only mounts when expanded.\n\n CHIP DOCTRINE (closed set — do not extend):\n The right gutter carries at most ONE terse status token per row, and COLOR is\n spent only on the exception. Success is the default, so it never earns a hue:\n a settled-ok chip is bare muted text (or nothing). The colored dot is reserved\n for failure alone. In-flight state is NOT a gutter chip — the shimmering title\n carries it, so a running row has a clean right edge (no detached pulse badge).\n There is no bordered/filled pill. Anything narrative (a session id, \"approval\n rejected\", \"malformed V4A\") belongs in the muted preview line, never the gutter.\n\n ok a settled success quiet muted text (\"0\", \"done\") — no dot\n bad a settled failure red dot + red text (\"exit 6\") — the one hue\n muted quiet metadata subtle text (\"session 3\")\n -------------------------------------------------------------------------- */\n\n/**\n * A subtle settle signal — see the CHIP DOCTRINE above. The closed tone set.\n * `\"interrupted\"` is a calm neutral tone for cancelled items — no dot, same\n * quiet weight as `\"muted\"`, but semantically distinct from metadata.\n */\nexport type DisclosureChip = {\n tone: \"ok\" | \"bad\" | \"muted\" | \"interrupted\";\n text: string;\n};\n\nexport type ActivityDisclosureProps = {\n icon: ReactNode;\n /** Icon tint. Defaults to the muted foreground; renderers pass accent/failed. */\n iconTone?: \"accent\" | \"failed\" | \"running\" | \"muted\" | undefined;\n title: ReactNode;\n /** Render the title in the mono face (commands, paths). */\n titleMono?: boolean | undefined;\n /** Shimmer the title while the tool is in-flight. */\n running?: boolean | undefined;\n /**\n * Quiet single-line secondary text (truncated). It is detail-on-demand: hidden\n * when a media preview is set, AND hidden once the row is expanded (the body\n * then owns the detail), so a stat/path never appears twice at once.\n */\n preview?: ReactNode | undefined;\n /** A small inline media preview (a screenshot thumbnail) shown in place of `preview`. */\n media?: ReactNode | undefined;\n /** At most one quiet settle chip, right-aligned to the gutter. */\n chip?: DisclosureChip | undefined;\n /**\n * When true the row carries the standard failure affordance: the icon is tinted\n * red and a \"failed\" bad-chip appears in the right gutter (unless an explicit\n * `chip` is already supplied — the caller's chip wins). Output is still visible\n * on expand; this is a quiet status signal, not a blocking banner.\n *\n * Renderers should pass `failed={item.status === \"failed\"}` on their settled\n * (non-running) paths so any tool with a failed status shows a consistent\n * affordance without each renderer having to duplicate the logic.\n */\n failed?: boolean | undefined;\n /**\n * When true the row carries a calm \"interrupted\" affordance: the icon stays\n * muted (no red) and a quiet \"interrupted\" chip appears in the right gutter\n * (unless an explicit `chip` is already supplied — the caller's chip wins).\n * This is the cancelled-status analogue of `failed`, but deliberately calm\n * and neutral — it is NOT an error; the user chose to stop.\n *\n * Renderers should pass `cancelled={item.status === \"cancelled\"}` so any\n * in-flight item that was interrupted on turn.cancelled reads consistently.\n * `cancelled` is ignored when `failed` is also true (failure takes precedence).\n */\n cancelled?: boolean | undefined;\n /** When false the row is a static line (no expand affordance). */\n expandable?: boolean | undefined;\n children?: ReactNode | undefined;\n};\n\nconst ICON_TONE: Record<NonNullable<ActivityDisclosureProps[\"iconTone\"]>, string> = {\n accent: \"text-og-accent\",\n failed: \"text-og-status-failed\",\n running: \"text-og-status-running\",\n muted: \"text-og-fg-subtle\",\n};\n\n/**\n * The one disclosure row shape every activity row reuses (tool calls, reasoning,\n * sandbox ops): a chevron, a tinted icon, a title, an optional muted preview or\n * inline media, and at most one right-gutter settle chip. Compact by default;\n * the body mounts only when expanded.\n */\nexport function ActivityDisclosure({\n icon,\n iconTone: iconToneProp = \"muted\",\n title,\n titleMono,\n running,\n preview,\n media,\n chip: chipProp,\n failed,\n cancelled,\n expandable = true,\n children,\n}: ActivityDisclosureProps) {\n // `failed` takes precedence over `cancelled` when both are set (shouldn't happen, but be safe).\n // When `failed` is set the icon goes red and a \"failed\" chip appears in the\n // gutter — unless the caller already supplied an explicit chip (their chip wins,\n // e.g. an exit-code chip that is more informative than a bare \"failed\" label).\n // When `cancelled` is set (and not failed) the icon stays muted and a calm\n // \"interrupted\" chip appears — no red, just a quiet neutral signal.\n const iconTone = failed && iconToneProp === \"muted\" ? \"failed\" : iconToneProp;\n const chip =\n chipProp ??\n (failed\n ? ({ tone: \"bad\", text: \"failed\" } satisfies DisclosureChip)\n : cancelled\n ? ({ tone: \"interrupted\", text: \"interrupted\" } satisfies DisclosureChip)\n : undefined);\n // An ancestor may seed the initial open state (screenshot instrumentation);\n // absent in normal app usage, where the row starts collapsed.\n const forcedDefaultOpen = useForcedDefaultOpen();\n const [open, setOpen] = useState(forcedDefaultOpen ?? false);\n const hasBody = expandable && children != null;\n\n // The preview is detail-on-demand: it is suppressed once the row is open so a\n // path/stat shown in the body never also sits in the collapsed row.\n const previewVisible = preview != null && !open;\n\n // ONE full-row layout for EVERY tool — media or not — so the hit target always\n // equals the visible row. The chevron → icon → title lead; a flex spacer (or\n // the preview) fills the middle; the right gutter (ml-auto) carries the chip OR\n // the media thumbnail. There is no media-vs-non-media fork: the screenshot card\n // toggles from anywhere on the row, exactly like every other row.\n //\n // The row is the single Collapsible.Trigger (via `asChild` onto a div), so it\n // is the toggle surface. A div — not a native <button> — so the interactive\n // media thumbnail (itself a <button>) is valid nested DOM; that thumbnail calls\n // stopPropagation so activating it never toggles the row.\n //\n // Radix forwards aria-expanded / aria-controls / data-state and a click handler\n // onto the asChild child, but it does NOT synthesize the button role, tab stop,\n // or Enter/Space activation for a non-button element. We add those ourselves\n // (role/tabIndex/onKeyDown) so the row is a fully keyboard-operable button to\n // AT and the keyboard, matching its native-<button> siblings (TurnSummary).\n const rowClass = cn(\n \"group/disclosure flex w-full min-w-0 items-center gap-2 rounded-og-sm px-1.5 py-1.5 text-left text-og-base\",\n \"text-og-fg-muted transition-colors duration-150\",\n // A tool row is a touch target on coarse pointers: grow its padding so the\n // hit area clears the 40px minimum without loosening the dense desktop rail.\n \"pointer-coarse:py-2.5\",\n );\n // The chevron rotates to point down when open; it tracks `data-state` on this\n // same row (the Trigger), so the affordance never freezes.\n const inner = (\n <>\n {hasBody ? (\n <ChevronRightIcon className=\"size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 ease-og-in-out group-data-[state=open]/disclosure:rotate-90\" />\n ) : (\n <span className=\"size-3.5 shrink-0\" />\n )}\n <span className={cn(\"shrink-0\", ICON_TONE[iconTone])}>{icon}</span>\n <span\n className={cn(\n \"min-w-0 shrink truncate text-og-base font-medium\",\n titleMono && \"font-og-mono text-og-sm font-normal\",\n running && \"og-shimmer-text\",\n )}\n >\n {title}\n </span>\n {previewVisible && !media ? (\n <span className=\"min-w-0 flex-1 truncate text-og-sm text-og-fg-subtle\">{preview}</span>\n ) : (\n <span className=\"flex-1\" />\n )}\n {/* The right gutter carries at most ONE signal: the media thumbnail, else a\n terse settle chip (hidden once expanded — the body owns the detail). */}\n {media ? (\n <span className=\"ml-auto flex shrink-0 items-center gap-2 pl-2\">{media}</span>\n ) : chip && !open ? (\n <span className=\"ml-auto shrink-0 pl-2\">\n <Chip chip={chip} />\n </span>\n ) : null}\n </>\n );\n\n // A `data-status` attribute on the root lets tests (and AT) detect the item's\n // settled state regardless of whether the chip slot is occupied by media.\n const dataStatus = cancelled ? \"cancelled\" : failed ? \"failed\" : undefined;\n\n if (!hasBody) {\n return <div className={cn(rowClass, \"cursor-default\")} data-status={dataStatus}>{inner}</div>;\n }\n\n return (\n <Collapsible.Root open={open} onOpenChange={setOpen}>\n <Collapsible.Trigger asChild>\n <div\n role=\"button\"\n tabIndex={0}\n // Space/Enter activate a native button; Radix doesn't add this for a\n // non-button asChild child, so we toggle here. preventDefault on Space\n // stops the page from scrolling.\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen((prev) => !prev);\n }\n }}\n data-status={dataStatus}\n className={cn(\n rowClass,\n \"cursor-pointer outline-none hover:bg-og-surface-1 hover:text-og-fg\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-0\",\n )}\n >\n {inner}\n </div>\n </Collapsible.Trigger>\n <Collapsible.Content className=\"overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand\">\n <div className=\"mb-2 ml-7 mt-1.5 flex flex-col gap-2\">{children}</div>\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/**\n * The right-gutter settle chip. Color is spent only on the exception: a failure\n * is a red dot + red text (the one colored token in a healthy run); success and\n * metadata are bare muted text with no dot. No box, no fill (see the CHIP\n * DOCTRINE above). A `bad` chip with empty text is a lone dot (no trailing void).\n */\nfunction Chip({ chip }: { chip: DisclosureChip }) {\n const base = \"inline-flex items-center font-og-mono text-og-xs leading-none\";\n const withText = chip.text ? \"gap-1.5\" : \"gap-0\";\n if (chip.tone === \"bad\") {\n return (\n <span className={cn(base, withText, \"text-og-status-failed\")}>\n <span className=\"size-1.5 rounded-full bg-og-status-failed\" />\n {chip.text}\n </span>\n );\n }\n // \"interrupted\" is a calm cancelled signal: same quiet weight as muted, no\n // dot, no red — just a slightly more prominent subtle text so \"interrupted\"\n // reads at a glance without demanding attention the way a failure does.\n if (chip.tone === \"interrupted\") {\n return <span className={cn(base, \"text-og-fg-subtle og-cancelled-chip\")}>{chip.text}</span>;\n }\n // ok and muted are the same quiet weight — success never earns a hue.\n return <span className={cn(base, \"text-og-fg-subtle\")}>{chip.text}</span>;\n}\n\n/* --- terminal output block (exec / write_stdin) ---------------------------- */\n\nexport function TermBlock({\n command,\n workdir,\n output,\n live,\n tailLines = 12,\n}: {\n /**\n * The command shown in the prompt header. Pass `null` when the row title\n * already carries it (e.g. an exec row titled `$ cmd`): the header then drops\n * the command — and the whole prompt line if there is no workdir either — so\n * the command never reads twice, stacked, above the output.\n */\n command: string | null;\n workdir?: string | null | undefined;\n /** The FULL output. TermBlock owns the tail/full slicing internally. */\n output: string;\n live?: boolean | undefined;\n /**\n * When the output exceeds the tail window, only the last `tailLines` are shown\n * with a \"show full output\" toggle. The component holds the full text, so the\n * toggle reveals the rest (never a dead affordance). Defaults to 12.\n */\n tailLines?: number | undefined;\n}) {\n const [full, setFull] = useState(false);\n const empty = output.trim() === \"\";\n const lines = output.split(\"\\n\");\n const big = lines.length > tailLines + 4;\n const shown = full || !big ? output : lines.slice(-tailLines).join(\"\\n\");\n const showMore = big && !full;\n const showHeader = command != null || workdir != null;\n\n return (\n <div className=\"min-w-0 overflow-hidden rounded-og-sm border border-og-border bg-og-bg/70\">\n {showHeader ? (\n <div className=\"flex items-center gap-2 border-b border-og-border/70 px-2.5 py-1.5\">\n <span className=\"select-none text-og-status-idle\">$</span>\n {command != null ? (\n <span className=\"min-w-0 flex-1 truncate font-og-mono text-og-sm text-og-fg-muted\">{command}</span>\n ) : (\n <span className=\"flex-1\" />\n )}\n {workdir ? <span className=\"shrink-0 font-og-mono text-og-xs text-og-fg-subtle\">{workdir}</span> : null}\n </div>\n ) : null}\n {empty ? (\n <p className=\"px-2.5 py-2 font-og-mono text-og-xs italic text-og-fg-subtle\">(no output)</p>\n ) : (\n <pre className=\"max-h-72 overflow-auto whitespace-pre-wrap break-all px-2.5 py-2 font-og-mono text-og-xs leading-5 text-og-fg-muted\">\n {shown}\n {live ? <span className=\"ml-px inline-block h-[1em] w-[2px] translate-y-[2px] animate-og-blink bg-og-accent align-middle\" /> : null}\n </pre>\n )}\n {showMore ? (\n <button\n type=\"button\"\n onClick={() => setFull(true)}\n className=\"w-full border-t border-og-border/70 px-2.5 py-1.5 text-left text-og-xs text-og-fg-subtle transition-colors hover:text-og-fg\"\n >\n show full output ({lines.length} lines)\n </button>\n ) : null}\n </div>\n );\n}\n\n/* --- generic payload block -------------------------------------------------- */\n\nexport function PayloadBlock({ label, value, failed }: { label: string; value: unknown; failed?: boolean | undefined }) {\n const text = typeof value === \"string\" ? value : stringifyPayload(value);\n if (!text || text.trim() === \"\") {\n return null;\n }\n return (\n <div className=\"min-w-0\">\n <p className=\"mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle\">{label}</p>\n <pre\n className={cn(\n \"max-h-64 overflow-auto whitespace-pre-wrap break-all rounded-og-sm border p-2.5 font-og-mono text-og-xs leading-5\",\n failed\n ? \"border-og-status-failed/30 bg-og-status-failed/5 text-og-status-failed\"\n : \"border-og-border bg-og-bg/60 text-og-fg-muted\",\n )}\n >\n {text}\n </pre>\n </div>\n );\n}\n\n/** A quiet inline note inside an expanded body (lost output, empty frame, …). */\nexport function BodyNote({ children, tone }: { children: ReactNode; tone?: \"error\" | \"muted\" | undefined }) {\n if (tone === \"error\") {\n return (\n <div className=\"rounded-og-sm border border-og-status-failed/30 bg-og-status-failed/5 px-2.5 py-2 font-og-mono text-og-xs leading-5 text-og-status-failed\">\n {children}\n </div>\n );\n }\n return <p className=\"px-0.5 text-og-sm italic leading-5 text-og-fg-subtle\">{children}</p>;\n}\n\n/* --- screenshot thumbnail + media states ------------------------------------ */\n\n/**\n * The shared inline-media footprint, so thumb / skeleton / empty align. Sized to\n * the row's line height (~28px) so a media row never out-weighs a text row and\n * the single-column rhythm holds.\n */\nconst MEDIA_BOX = \"h-7 w-[52px] shrink-0 rounded-og-xs border border-og-border\";\n\n/**\n * A loading screenshot placeholder. A faint camera glyph over a shimmering box,\n * so a still frame of the running state reads unambiguously as \"capturing\" — not\n * a broken thumbnail.\n */\nexport function MediaSkeleton() {\n return (\n <span className={cn(MEDIA_BOX, \"relative inline-flex items-center justify-center overflow-hidden bg-og-surface-2\")}>\n <span className=\"absolute inset-0 animate-og-pulse bg-og-surface-3/50\" />\n <CameraIcon className=\"relative size-3.5 text-og-fg-subtle\" />\n </span>\n );\n}\n\n/** A standardized \"tool ran, produced no image\" placeholder in the media slot. */\nexport function MediaEmpty() {\n return (\n <span className={cn(MEDIA_BOX, \"inline-flex items-center justify-center bg-og-bg\")}>\n <CameraOffIcon className=\"size-3.5 text-og-fg-subtle\" />\n </span>\n );\n}\n\n/**\n * A small inline screenshot thumbnail that opens the app lightbox on click.\n *\n * Requires a `LightboxProvider` ancestor for the click-to-expand affordance.\n * Outside one it degrades to a plain, non-interactive image — never a dead\n * \"Expand\" button that announces an action it cannot perform.\n */\nexport function Thumbnail({ src, caption, alt = \"screenshot\" }: { src: string; caption?: string | undefined; alt?: string }) {\n const lightbox = useLightboxOptional();\n const [failed, setFailed] = useState(false);\n if (failed) {\n return <MediaEmpty />;\n }\n // A plain <img> (not a framework Image): this is a framework-agnostic SDK, so\n // the host's image component is unavailable and unwanted here.\n const img = (\n <img\n src={src}\n alt={alt}\n onError={() => setFailed(true)}\n className=\"h-full w-full object-cover transition-opacity group-hover/thumb:opacity-80\"\n />\n );\n if (!lightbox) {\n return <span className={cn(MEDIA_BOX, \"inline-flex overflow-hidden bg-og-bg\")}>{img}</span>;\n }\n // The thumbnail is a real, independently-focusable button nested inside the\n // row's disclosure trigger. It stops both pointer AND keyboard activation from\n // bubbling, so opening the lightbox never also toggles the row.\n return (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n lightbox.open(src, caption);\n }}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.stopPropagation();\n }\n }}\n className={cn(\n MEDIA_BOX,\n \"group/thumb relative inline-flex overflow-hidden bg-og-bg outline-none\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n aria-label=\"Expand screenshot\"\n >\n {img}\n </button>\n );\n}\n\n/**\n * The expanded screenshot inside a tool body: a contained, clickable preview\n * (opens the lightbox) with a quiet caption. Constrained height + object-contain\n * so it never breaks the row layout. Like {@link Thumbnail}, it degrades to a\n * plain image outside a `LightboxProvider`.\n */\nexport function ScreenshotFigure({ src, caption, alt = \"screenshot\" }: { src: string; caption?: string | undefined; alt?: string }) {\n const lightbox = useLightboxOptional();\n const [failed, setFailed] = useState(false);\n const surface = \"block w-full overflow-hidden rounded-og-md border border-og-border bg-og-bg\";\n // A plain <img>, like {@link Thumbnail} — a framework-agnostic SDK has no host\n // Image component to defer to.\n const img = <img src={src} alt={alt} onError={() => setFailed(true)} className=\"max-h-80 w-full object-contain\" />;\n return (\n <figure className=\"m-0 min-w-0\">\n {failed ? (\n <div className=\"rounded-og-md border border-og-border bg-og-bg px-3 py-6 text-center font-og-mono text-og-xs text-og-fg-subtle\">\n image unavailable\n </div>\n ) : lightbox ? (\n <button type=\"button\" onClick={() => lightbox.open(src, caption)} className={surface} aria-label=\"Expand screenshot\">\n {img}\n </button>\n ) : (\n <div className={surface}>{img}</div>\n )}\n {caption ? <figcaption className=\"mt-1.5 font-og-mono text-og-xs text-og-fg-subtle\">{caption}</figcaption> : null}\n </figure>\n );\n}\n","import { createContext, useContext, type ReactNode } from \"react\";\n\n/* ----------------------------------------------------------------------------\n Disclosure defaults context\n\n A tiny, opt-in context that lets an ancestor seed the INITIAL open state of\n every collapsible in the timeline (ActivityDisclosure rows and TurnSummary\n chips). Its sole intended use is deterministic screenshot capture: a tool can\n force every card open so a headless render shows expanded bodies.\n\n It is fully inert in normal app usage. With no provider, the hook returns\n `undefined`, every collapsible keeps its own author-chosen default, and there\n is zero change to how the components look or animate. Mounting the provider\n only changes the SEED of the initial `open` state — Radix still owns the\n open/close transition, so animations are untouched.\n -------------------------------------------------------------------------- */\n\nconst DisclosureDefaultsContext = createContext<boolean | undefined>(undefined);\n\n/**\n * Seed the initial open state of every timeline collapsible below this node.\n * Intended for screenshot/test instrumentation only; absent by default.\n */\nexport function DisclosureDefaultsProvider({ defaultOpen, children }: { defaultOpen: boolean; children: ReactNode }) {\n return <DisclosureDefaultsContext.Provider value={defaultOpen}>{children}</DisclosureDefaultsContext.Provider>;\n}\n\n/**\n * The forced initial-open seed from an ancestor {@link DisclosureDefaultsProvider},\n * or `undefined` when none is mounted (the inert, app-default case).\n */\nexport function useForcedDefaultOpen(): boolean | undefined {\n return useContext(DisclosureDefaultsContext);\n}\n","import { XIcon } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { createContext, useCallback, useContext, useMemo, useState, type ReactNode } from \"react\";\nimport { Dialog } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\n\n/* ----------------------------------------------------------------------------\n Screenshot lightbox\n\n A single, app-level lightbox the computer_call / view_image renderers open by\n `src`. Built on Radix Dialog so it is focus-trapped, ESC-closable, and\n scroll-locked — fixing the v1 mockup's broken expand (an absolutely-positioned\n <img> that overflowed its row). The image is centered, constrained to the\n viewport (`max-w/max-h` + `object-contain`), and sits on a dimmed backdrop.\n\n Consumers render `<LightboxProvider>` once near the timeline; renderers call\n `useLightbox().open(src)`.\n -------------------------------------------------------------------------- */\n\ntype LightboxController = {\n open: (src: string, caption?: string) => void;\n};\n\nconst LightboxContext = createContext<LightboxController | null>(null);\n\n/** Open the app-level screenshot lightbox. No-op outside a `LightboxProvider`. */\nexport function useLightbox(): LightboxController {\n return useContext(LightboxContext) ?? NOOP;\n}\n\n/**\n * The lightbox controller when one is mounted, or `null` outside a\n * `LightboxProvider`. Lets a media primitive degrade to a non-interactive image\n * (rather than a dead \"Expand\" button that announces an action it cannot do).\n */\nexport function useLightboxOptional(): LightboxController | null {\n return useContext(LightboxContext);\n}\n\nconst NOOP: LightboxController = { open: () => {} };\n\n/**\n * The app-level screenshot lightbox. Render once near the timeline; renderers\n * call `useLightbox().open(src)`.\n *\n * Idempotent by design: when an ancestor `LightboxProvider` already exists (e.g.\n * a `MessageTimeline` mounted inside an app that already wraps its shell), this\n * one becomes a pass-through and does NOT mount a second focus-trapping Dialog.\n * That keeps `MessageTimeline` self-sufficient (it owns its own provider) while\n * composing cleanly when nested.\n */\nexport function LightboxProvider({ children }: { children: ReactNode }) {\n const ancestor = useContext(LightboxContext);\n if (ancestor) {\n return <>{children}</>;\n }\n return <LightboxRoot>{children}</LightboxRoot>;\n}\n\nfunction LightboxRoot({ children }: { children: ReactNode }) {\n const [state, setState] = useState<{ src: string; caption?: string } | null>(null);\n\n const open = useCallback((src: string, caption?: string) => {\n setState(caption ? { src, caption } : { src });\n }, []);\n\n const controller = useMemo<LightboxController>(() => ({ open }), [open]);\n\n return (\n <LightboxContext.Provider value={controller}>\n {children}\n <Dialog.Root open={state !== null} onOpenChange={(next) => !next && setState(null)}>\n <AnimatePresence>\n {state !== null ? (\n <Dialog.Portal forceMount>\n <Dialog.Overlay asChild forceMount>\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n className=\"og-root fixed inset-0 z-50 bg-black/90 backdrop-blur-md\"\n />\n </Dialog.Overlay>\n <Dialog.Content\n asChild\n forceMount\n aria-label=\"Screenshot\"\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.98 }}\n transition={{ duration: 0.18, ease: [0.16, 1, 0.3, 1] }}\n // Content is a full-inset centering wrapper layered above the\n // Overlay, so Radix's own click-outside (which fires on the\n // Overlay) can never see a backdrop click — every click lands on\n // Content. We make Content's own backdrop dismiss: a click whose\n // target is the wrapper itself (not the figure) closes it, so the\n // figcaption's \"click outside to close\" affordance is real.\n onClick={(event) => {\n if (event.target === event.currentTarget) {\n setState(null);\n }\n }}\n className=\"og-root fixed inset-0 z-50 flex items-center justify-center p-6 sm:p-12\"\n >\n <Dialog.Title className=\"sr-only\">Screenshot</Dialog.Title>\n {/* The figure is one self-contained object: image, caption, and\n its own close control. The close button anchors to a wrapper\n sized to the IMAGE (w-fit), so it hugs the real top-right\n corner regardless of aspect ratio — never floating into the\n empty space of a wide figure column. */}\n <figure className=\"m-0 flex max-h-full max-w-5xl flex-col items-center gap-3\">\n <div className=\"relative flex min-h-0 w-fit max-w-full\">\n {/* A plain <img>: this SDK is framework-agnostic, with no host Image component. */}\n <img\n src={state.src}\n alt={state.caption ?? \"Screenshot\"}\n className=\"min-h-0 max-h-[82vh] w-auto max-w-full rounded-og-md border border-white/10 object-contain shadow-og-lg\"\n />\n <Dialog.Close\n className={cn(\n \"absolute -right-3 -top-3 inline-flex size-9 items-center justify-center rounded-full\",\n \"border border-white/15 bg-black/60 text-white/70 backdrop-blur\",\n \"transition-colors hover:border-white/30 hover:text-white\",\n )}\n aria-label=\"Close\"\n >\n <XIcon className=\"size-4\" />\n </Dialog.Close>\n </div>\n {state.caption ? (\n <figcaption className=\"max-w-2xl text-center font-og-mono text-og-xs text-white/55\">\n {state.caption}\n </figcaption>\n ) : (\n <figcaption className=\"font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35\">\n Esc or click outside to close\n </figcaption>\n )}\n </figure>\n </motion.div>\n </Dialog.Content>\n </Dialog.Portal>\n ) : null}\n </AnimatePresence>\n </Dialog.Root>\n </LightboxContext.Provider>\n );\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport { DiffView } from \"../components/diff-view\";\nimport { PierreDiff } from \"../components/pierre-diff\";\n\n/* ----------------------------------------------------------------------------\n Tool diff\n\n Renders parsed `GitFileDiff[]` (from the V4A apply_patch parser) through the\n EXACT same diff stack the Files tab uses: `DiffView` with `PierreDiff` wired\n into its `fallback` seam, so a host with `@pierre/diffs` installed gets the\n Shiki-highlighted Pierre renderer and everyone else gets the hand-rolled\n one — a single data contract, zero divergence. A per-block Unified/Split\n toggle sits in the header.\n -------------------------------------------------------------------------- */\n\nexport function ToolDiff({ files }: { files: GitFileDiff[] }) {\n const [layout, setLayout] = useState<\"unified\" | \"split\">(\"unified\");\n // Resolve the host theme (auto-detect via `data-og-theme`) with the SAME hook\n // the Files tab uses, then thread it into Pierre. Without it Pierre falls back\n // to its hard dark default and renders a github-dark slab inside a light page.\n const themeType = useThemeType(undefined);\n // The fallback chain reads top-down: try Pierre's Shiki renderer, and if it's\n // not installed fall back to the built-in DiffView. The plain node is named\n // once and reused, so the same props aren't threaded through three JSX nodes.\n const plain = <DiffView diff={files} layout={layout} />;\n return (\n <div className=\"min-w-0\">\n <div className=\"mb-1.5 flex justify-end\">\n <LayoutToggle layout={layout} onChange={setLayout} />\n </div>\n <DiffView\n diff={files}\n layout={layout}\n fallback={<PierreDiff diff={files} layout={layout} themeType={themeType} fallback={plain} />}\n />\n </div>\n );\n}\n\nfunction LayoutToggle({ layout, onChange }: { layout: \"unified\" | \"split\"; onChange: (next: \"unified\" | \"split\") => void }) {\n return (\n <div className=\"inline-flex items-center gap-px rounded-og-xs border border-og-border p-px\">\n {([\"unified\", \"split\"] as const).map((value) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => onChange(value)}\n className={cn(\n \"rounded-og-xs px-2 py-[3px] text-og-xs font-medium capitalize transition-colors\",\n layout === value ? \"bg-og-surface-2 text-og-fg\" : \"text-og-fg-subtle hover:text-og-fg-muted\",\n )}\n >\n {value}\n </button>\n ))}\n </div>\n );\n}\n\n/** Raw-patch fallback for a V4A hunk string the parser could not structure. */\nexport function RawPatch({ diff }: { diff: string }) {\n return (\n <div className=\"min-w-0\">\n <p className=\"mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle\">\n raw patch (could not parse hunks)\n </p>\n <pre className=\"max-h-72 overflow-auto rounded-og-sm border border-og-border bg-og-bg/60 p-2.5 font-og-mono text-og-xs leading-5\">\n {diff.split(\"\\n\").map((line, index) => (\n <span\n key={index}\n className={cn(\n \"block\",\n line.startsWith(\"@@\")\n ? \"text-og-accent\"\n : line.startsWith(\"+\")\n ? \"text-og-status-idle\"\n : line.startsWith(\"-\")\n ? \"text-og-status-failed\"\n : \"text-og-fg-muted\",\n )}\n >\n {line || \" \"}\n </span>\n ))}\n </pre>\n </div>\n );\n}\n","import { useEffect, useState } from \"react\";\n\n/* ----------------------------------------------------------------------------\n useThemeType\n\n Resolve the effective dark/light theme for surfaces (the Pierre/Shiki diff)\n that render outside the reach of host CSS — they need the theme as a value,\n not a cascade. An explicit prop always wins; otherwise read the host's\n `data-og-theme` attribute (set on `<html>` or any ancestor by the same opt-in\n the tokens use) and default to dark, the first-class theme. A MutationObserver\n keeps it live across runtime theme flips.\n\n One detector, shared by every diff surface (the Files tab and the timeline),\n so the two can never drift onto different themes.\n -------------------------------------------------------------------------- */\n\n/**\n * Resolve the diff theme. An explicit `forced` value wins; otherwise auto-detect\n * from the host `data-og-theme` (defaulting to dark) and track live flips.\n */\nexport function useThemeType(forced: \"dark\" | \"light\" | undefined): \"dark\" | \"light\" {\n const [detected, setDetected] = useState<\"dark\" | \"light\">(\"dark\");\n useEffect(() => {\n if (forced || typeof document === \"undefined\") return;\n const read = () => {\n const el = document.querySelector(\"[data-og-theme]\");\n const value = el?.getAttribute(\"data-og-theme\");\n setDetected(value === \"light\" ? \"light\" : \"dark\");\n };\n read();\n const observer = new MutationObserver(read);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-og-theme\"],\n subtree: true,\n });\n return () => observer.disconnect();\n }, [forced]);\n return forced ?? detected;\n}\n","import type { GitDiffLine, GitFileDiff } from \"@opengeni/sdk\";\nimport { type ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/** Theme tokens for the diff line backgrounds. */\nexport type DiffTheme = {\n addBackground?: string;\n delBackground?: string;\n contextBackground?: string;\n metaForeground?: string;\n};\n\nexport type DiffViewProps = {\n /** From `useSandboxGit().diff` — the structured per-file hunks. */\n diff: GitFileDiff[];\n /** Rendered instead of the built-in diff (the Pierre-swap escape hatch). */\n fallback?: ReactNode | undefined;\n /** unified | split. Default \"unified\". */\n layout?: \"unified\" | \"split\" | undefined;\n theme?: DiffTheme | undefined;\n onSelectFile?: ((path: string) => void) | undefined;\n /** Distinguishes \"no changes\" from \"no repository mounted\". */\n isRepo?: boolean | undefined;\n emptyState?: ReactNode | undefined;\n className?: string | undefined;\n};\n\nconst STATUS_LABEL: Record<GitFileDiff[\"status\"], string> = {\n added: \"added\",\n modified: \"modified\",\n deleted: \"deleted\",\n renamed: \"renamed\",\n copied: \"copied\",\n untracked: \"untracked\",\n ignored: \"ignored\",\n conflicted: \"conflicted\",\n typechange: \"typechange\",\n};\n\n/**\n * The diff view, fed by the Git service via `useSandboxGit().diff`. This is our\n * `PierreDiff` boundary: the built-in renderer delivers the same UX (per-file\n * hunks, unified or side-by-side, old/new line numbers, add/del counts), and a\n * consumer with Pierre's `@pierre/diffs` installed can swap it via `fallback`\n * while keeping the same `GitFileDiff[]` data contract from the hook.\n */\nexport function DiffView({\n diff,\n fallback,\n layout = \"unified\",\n theme,\n onSelectFile,\n isRepo = true,\n emptyState,\n className,\n}: DiffViewProps) {\n if (fallback !== undefined) {\n return <div className={className}>{fallback}</div>;\n }\n\n if (diff.length === 0) {\n return (\n <div className={cn(\"p-3 text-og-sm text-og-fg-subtle\", className)}>\n {emptyState ?? (isRepo ? \"No changes\" : \"No repository mounted\")}\n </div>\n );\n }\n\n return (\n <div className={cn(\"min-w-0 overflow-auto\", className)} data-opengeni-diff>\n {diff.map((file) => (\n <FileDiffBlock\n key={file.path}\n file={file}\n layout={layout}\n theme={theme}\n {...(onSelectFile ? { onSelect: () => onSelectFile(file.path) } : {})}\n />\n ))}\n </div>\n );\n}\n\nfunction FileDiffBlock({\n file,\n layout,\n theme,\n onSelect,\n}: {\n file: GitFileDiff;\n layout: \"unified\" | \"split\";\n theme: DiffTheme | undefined;\n onSelect?: (() => void) | undefined;\n}) {\n return (\n <section className=\"mb-2 overflow-hidden rounded-og-sm border border-og-border\">\n <header\n className={cn(\n \"flex items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm\",\n onSelect && \"cursor-pointer\",\n )}\n onClick={onSelect}\n >\n <span className=\"truncate font-og-mono\">\n {file.oldPath && file.oldPath !== file.path ? `${file.oldPath} → ${file.path}` : file.path}\n </span>\n <span className=\"flex shrink-0 items-center gap-2\">\n <span className=\"rounded-og-xs bg-og-bg px-1 py-0.5 text-og-xs text-og-fg-subtle\">\n {STATUS_LABEL[file.status]}\n </span>\n <span className=\"text-og-status-idle\">+{file.additions}</span>\n <span className=\"text-og-status-failed\">−{file.deletions}</span>\n </span>\n </header>\n {file.isBinary ? (\n <div className=\"px-2 py-3 text-og-sm text-og-fg-subtle\">Binary file not shown</div>\n ) : file.truncated ? (\n <div className=\"px-2 py-3 text-og-sm text-og-fg-subtle\">Diff too large — truncated</div>\n ) : layout === \"split\" ? (\n <SplitHunks file={file} theme={theme} />\n ) : (\n <UnifiedHunks file={file} theme={theme} />\n )}\n </section>\n );\n}\n\nfunction lineBg(type: GitDiffLine[\"type\"], theme: DiffTheme | undefined): string | undefined {\n if (type === \"add\") return theme?.addBackground ?? \"var(--og-color-diff-add-bg)\";\n if (type === \"del\") return theme?.delBackground ?? \"var(--og-color-diff-del-bg)\";\n if (type === \"meta\") return undefined;\n return theme?.contextBackground;\n}\n\nfunction marker(type: GitDiffLine[\"type\"]): string {\n if (type === \"add\") return \"+\";\n if (type === \"del\") return \"−\";\n return \" \";\n}\n\nfunction UnifiedHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | undefined }) {\n return (\n <div className=\"font-og-mono text-og-xs\">\n {file.hunks.map((hunk, hi) => (\n <div key={`${file.path}-h${hi}`}>\n <div\n className=\"px-2 py-0.5 text-og-accent\"\n style={{ color: theme?.metaForeground }}\n >\n {hunk.header}\n </div>\n {hunk.lines.map((line, li) => (\n <div\n key={`${file.path}-h${hi}-l${li}`}\n className=\"flex\"\n style={{ backgroundColor: lineBg(line.type, theme) }}\n >\n <span className=\"w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle\">\n {line.oldNo ?? \"\"}\n </span>\n <span className=\"w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle\">\n {line.newNo ?? \"\"}\n </span>\n <span className=\"w-4 shrink-0 select-none text-center text-og-fg-subtle\">\n {marker(line.type)}\n </span>\n <span className=\"whitespace-pre-wrap break-all px-1\">{line.text}</span>\n </div>\n ))}\n </div>\n ))}\n </div>\n );\n}\n\nfunction SplitHunks({ file, theme }: { file: GitFileDiff; theme: DiffTheme | undefined }) {\n return (\n <div className=\"font-og-mono text-og-xs\">\n {file.hunks.map((hunk, hi) => {\n // Pair del/add lines side-by-side; context spans both columns.\n const left: (GitDiffLine | null)[] = [];\n const right: (GitDiffLine | null)[] = [];\n for (const line of hunk.lines) {\n if (line.type === \"context\" || line.type === \"meta\") {\n left.push(line);\n right.push(line);\n } else if (line.type === \"del\") {\n left.push(line);\n } else {\n right.push(line);\n }\n }\n const rows = Math.max(left.length, right.length);\n return (\n <div key={`${file.path}-h${hi}`}>\n <div className=\"px-2 py-0.5 text-og-accent\" style={{ color: theme?.metaForeground }}>\n {hunk.header}\n </div>\n {Array.from({ length: rows }).map((_, ri) => {\n const l = left[ri] ?? null;\n const r = right[ri] ?? null;\n return (\n <div key={`${file.path}-h${hi}-r${ri}`} className=\"flex\">\n <span\n className=\"flex w-1/2 min-w-0\"\n style={{ backgroundColor: l ? lineBg(l.type, theme) : undefined }}\n >\n <span className=\"w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle\">\n {l?.oldNo ?? \"\"}\n </span>\n <span className=\"whitespace-pre-wrap break-all px-1\">{l?.text ?? \"\"}</span>\n </span>\n <span\n className=\"flex w-1/2 min-w-0 border-l border-og-border\"\n style={{ backgroundColor: r ? lineBg(r.type, theme) : undefined }}\n >\n <span className=\"w-10 shrink-0 select-none px-1 text-right text-og-fg-subtle\">\n {r?.newNo ?? \"\"}\n </span>\n <span className=\"whitespace-pre-wrap break-all px-1\">{r?.text ?? \"\"}</span>\n </span>\n </div>\n );\n })}\n </div>\n );\n })}\n </div>\n );\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport {\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n lazy,\n Suspense,\n useEffect,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { gitFileDiffToPatch } from \"../lib/git-patch\";\n\n/** Pierre `PatchDiff` props subset we drive. */\ntype PatchDiffComponent = ComponentType<{\n patch: string;\n options?: {\n theme?: string | { dark: string; light: string };\n themeType?: \"dark\" | \"light\";\n diffStyle?: \"unified\" | \"split\";\n overflow?: \"scroll\" | \"wrap\";\n stickyHeader?: boolean;\n };\n disableWorkerPool?: boolean;\n className?: string;\n}>;\n\nexport type PierreDiffProps = {\n diff: GitFileDiff[];\n layout?: \"unified\" | \"split\" | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n /** Shiki bundled theme names (dark/light) — derived from the host palette. */\n theme?: { dark: string; light: string } | undefined;\n /** Disable Pierre's worker pool if its worker bundling fights the host bundler. */\n disableWorkerPool?: boolean | undefined;\n /** Rendered while the (lazy) Pierre bundle loads. */\n loading?: ReactNode | undefined;\n /** Rendered if `@pierre/diffs/react` is not installed / fails to import. */\n fallback?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n// Lazy-load `@pierre/diffs/react` so Shiki + the worker pool stay off the\n// critical path (and out of an SSR bundle) until a diff is actually shown. The\n// dynamic specifier is static so the bundler can resolve + chunk it. If the\n// optional peer is absent the import rejects and we render `fallback`.\nconst LazyPatchDiff = lazy(async () => {\n const mod = (await import(\"@pierre/diffs/react\")) as unknown as {\n PatchDiff: PatchDiffComponent;\n };\n return { default: mod.PatchDiff };\n});\n\n/**\n * The Pierre-backed diff: Shiki-highlighted, virtualized, unified/split. Renders\n * one `PatchDiff` per changed file (a reconstructed unified patch from the\n * `GitFileDiff` hunks). This sits behind `DiffView`'s `fallback` seam so a host\n * that lacks `@pierre/diffs` keeps the hand-rolled renderer.\n */\nexport function PierreDiff({\n diff,\n layout = \"unified\",\n themeType,\n theme,\n disableWorkerPool,\n loading,\n fallback,\n className,\n}: PierreDiffProps) {\n const [failed, setFailed] = useState(false);\n\n // Probe the import once so a hard failure (peer missing) shows `fallback`\n // rather than a Suspense boundary that never resolves.\n useEffect(() => {\n let cancelled = false;\n void import(\"@pierre/diffs/react\").catch(() => {\n if (!cancelled) setFailed(true);\n });\n return () => {\n cancelled = true;\n };\n }, []);\n\n if (failed && fallback !== undefined) {\n return <div className={className}>{fallback}</div>;\n }\n\n // Default to the dark theme: the host UI is dark-first, and Pierre's own\n // auto-detection otherwise lands on the light Shiki theme (a white diff pane\n // inside a dark dock). Callers pass `themeType=\"light\"` to opt into light.\n const options = {\n diffStyle: layout,\n overflow: \"scroll\" as const,\n stickyHeader: true,\n ...(theme ? { theme } : { theme: { dark: \"github-dark\", light: \"github-light\" } }),\n themeType: themeType ?? \"dark\",\n };\n\n // Pierre renders inside a shadow DOM, so host CSS can't reach it — but it reads\n // a set of `--diffs-*-override` custom properties through the shadow boundary.\n // Pin the diff's own base background to the dock surface and quiet the hunk\n // separator slab so collapsed context rows do not become heavy bars.\n const pierreVars = {\n \"--diffs-dark-bg\": \"var(--og-color-bg)\",\n \"--diffs-light-bg\": \"var(--og-color-bg)\",\n \"--diffs-bg-buffer-override\": \"var(--og-color-surface-1)\",\n \"--diffs-bg-separator-override\": \"var(--og-color-surface-1)\",\n \"--diffs-font-size\": \"var(--og-code-font-size)\",\n \"--diffs-line-height\": \"var(--og-code-line-height)\",\n } as CSSProperties;\n\n return (\n <div\n className={cn(\"min-w-0\", className)}\n data-opengeni-pierre-diff\n style={pierreVars}\n >\n <Suspense fallback={loading ?? <DiffSkeleton />}>\n {diff.map((file) => (\n <div key={file.path} className=\"mb-2\">\n <LazyPatchDiff\n patch={gitFileDiffToPatch(file)}\n options={options}\n {...(disableWorkerPool !== undefined ? { disableWorkerPool } : {})}\n />\n </div>\n ))}\n </Suspense>\n </div>\n );\n}\n\nfunction DiffSkeleton() {\n return (\n <div className=\"p-3 text-og-sm text-og-fg-subtle\">\n Loading diff…\n </div>\n );\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\n\n/**\n * Reconstruct a unified-diff patch string for a single `GitFileDiff` so it can\n * be fed to a generic patch renderer (e.g. Pierre's `PatchDiff`). The hook\n * already carries per-line old/new numbers and a hunk header, so we emit a\n * conventional `--- / +++ / @@` patch the parser understands.\n */\nexport function gitFileDiffToPatch(file: GitFileDiff): string {\n const oldPath = file.oldPath ?? file.path;\n const newPath = file.path;\n const lines: string[] = [];\n lines.push(`diff --git a/${oldPath} b/${newPath}`);\n if (file.status === \"deleted\") {\n lines.push(`--- a/${oldPath}`);\n lines.push(`+++ /dev/null`);\n } else if (file.status === \"added\" || file.status === \"untracked\") {\n lines.push(`--- /dev/null`);\n lines.push(`+++ b/${newPath}`);\n } else {\n lines.push(`--- a/${oldPath}`);\n lines.push(`+++ b/${newPath}`);\n }\n for (const hunk of file.hunks) {\n // Only trust a pre-parsed header if it carries the full unified range form\n // `@@ -<o>[,<n>] +<o>[,<n>] @@`. A synthesized create_file hunk (parsers.ts)\n // can carry a degenerate `@@ +1 @@` with no `-`/`+` ranges; a generic patch\n // parser (Pierre) renders zero lines from it, so the expanded diff comes up\n // empty while the collapsed chip still shows the (correct) addition count.\n // In that case regenerate a valid header from the hunk's range fields.\n const headerIsValid = /^@@ -\\d+(?:,\\d+)? \\+\\d+(?:,\\d+)? @@/.test(hunk.header ?? \"\");\n const header = headerIsValid\n ? hunk.header\n : `@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`;\n lines.push(header);\n for (const line of hunk.lines) {\n if (line.type === \"meta\") continue;\n const prefix = line.type === \"add\" ? \"+\" : line.type === \"del\" ? \"-\" : \" \";\n lines.push(`${prefix}${line.text}`);\n }\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n","import { BotIcon, BrainIcon, SquareTerminalIcon } from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { truncate } from \"../lib/format\";\nimport { defaultToolRegistry } from \"./tool-renderers\";\nimport { useEntranceAnimation } from \"./entrance\";\nimport type { ToolRegistry } from \"./registry\";\nimport { PayloadBlock, ActivityDisclosure } from \"./shared\";\nimport { toolDisplayName } from \"./projection\";\nimport type { ActivityItem, ReasoningItem, SandboxItem, WorkerItem } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Activity rail\n\n Renders a run of clustered activity items (reasoning, tool calls, workers,\n sandbox ops) as the left-bordered column between chat messages. Tool calls\n resolve through the renderer registry; everything else has a first-class row.\n\n Shared by `MessageTimeline` and the component demo so both draw the exact\n same rail — no divergence.\n -------------------------------------------------------------------------- */\n\nexport type ActivityRailProps = {\n items: ActivityItem[];\n /** Renderer registry for tool calls. Defaults to {@link defaultToolRegistry}. */\n toolRegistry?: ToolRegistry | undefined;\n /** Drill into a spawned worker session. */\n onOpenSession?: ((sessionId: string) => void) | undefined;\n /** Drop the left rule + indent (used inside a folded turn summary). */\n bare?: boolean | undefined;\n className?: string | undefined;\n};\n\n/**\n * The \"family\" a row belongs to, for light intra-rail grouping. Consecutive\n * rows of the same family sit tight; a family change gets a little extra top\n * margin so a long run reads as clusters rather than one undifferentiated wall.\n */\nfunction familyOf(item: ActivityItem): string {\n if (item.kind === \"tool-call\") {\n return item.name === \"exec_command\" || item.name === \"write_stdin\" ? \"terminal\" : item.name;\n }\n return item.kind;\n}\n\nexport function ActivityRail({ items, toolRegistry = defaultToolRegistry, onOpenSession, bare, className }: ActivityRailProps) {\n const enter = useEntranceAnimation();\n return (\n <div\n className={cn(\n // Rows sit TIGHT by default (gap-0.5) so a same-family run reads as one\n // calm cluster; a family change opens real breathing room (mt-3) below,\n // so a long rail reads as a few clusters, not a metronome of rows.\n \"flex flex-col gap-0.5\",\n !bare && \"border-l-2 border-og-border pl-3 sm:pl-4\",\n !bare && enter && \"animate-og-enter\",\n className,\n )}\n >\n {items.map((item, index) => {\n const newFamily = index > 0 && familyOf(item) !== familyOf(items[index - 1]!);\n const row = renderActivity(item, toolRegistry, onOpenSession);\n return (\n <div key={item.id} className={cn(newFamily && \"mt-3\")}>\n {row}\n </div>\n );\n })}\n </div>\n );\n}\n\n/** A never-reachable guard: adding an `ActivityItem` kind is now a compile error. */\nfunction assertNever(item: never): never {\n throw new Error(`ActivityRail: unhandled activity item ${JSON.stringify(item)}`);\n}\n\nfunction renderActivity(\n item: ActivityItem,\n toolRegistry: ToolRegistry,\n onOpenSession: ((sessionId: string) => void) | undefined,\n) {\n switch (item.kind) {\n case \"reasoning\":\n return <ReasoningRow item={item} />;\n case \"tool-call\": {\n const Renderer = toolRegistry.resolve(item);\n return <Renderer item={item} />;\n }\n case \"worker\":\n return <WorkerRow item={item} onOpenSession={onOpenSession} />;\n case \"sandbox\":\n return <SandboxRow item={item} />;\n default:\n return assertNever(item);\n }\n}\n\nfunction ReasoningRow({ item }: { item: ReasoningItem }) {\n // Reasoning recedes: a dimmer, lighter-weight title so action rows lead and\n // thought rows sit a half-step back in the hierarchy.\n return (\n <ActivityDisclosure\n icon={<BrainIcon className=\"size-3.5\" />}\n iconTone=\"muted\"\n title={\n item.streaming ? (\n \"Thinking\"\n ) : (\n <span className=\"font-normal italic text-og-fg-subtle\">Thought</span>\n )\n }\n running={item.streaming}\n preview={truncate(item.text, 110)}\n >\n <p className=\"whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted\">{item.text}</p>\n </ActivityDisclosure>\n );\n}\n\nfunction SandboxRow({ item }: { item: SandboxItem }) {\n return (\n <ActivityDisclosure\n icon={<SquareTerminalIcon className=\"size-3.5\" />}\n iconTone={item.status === \"failed\" ? \"failed\" : item.status === \"running\" ? \"running\" : \"muted\"}\n title={toolDisplayName(item.name)}\n running={item.status === \"running\"}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n preview={item.command ?? undefined}\n >\n {item.command ? <PayloadBlock label=\"Command\" value={item.command} /> : null}\n {item.output ? <PayloadBlock label=\"Output\" value={item.output} /> : null}\n </ActivityDisclosure>\n );\n}\n\n/** Spawned/messaged worker sessions get a first-class card, not a tool row. */\nfunction WorkerRow({ item, onOpenSession }: { item: WorkerItem; onOpenSession?: ((sessionId: string) => void) | undefined }) {\n const running = item.status === \"running\";\n const failed = item.status === \"failed\";\n const cancelled = item.status === \"cancelled\";\n const title =\n item.action === \"spawn\"\n ? running\n ? \"Spawning worker\"\n : failed\n ? \"Worker spawn failed\"\n : cancelled\n ? \"Worker interrupted\"\n : \"Worker spawned\"\n : item.action === \"interrupt\"\n ? (() => {\n const verb = item.mode === \"steer\" ? \"Steering\" : \"Stopping\";\n const done = item.mode === \"steer\" ? \"Worker steered\" : \"Worker stopped\";\n return running ? `${verb} worker` : failed ? \"Worker interrupt failed\" : cancelled ? \"Worker interrupted\" : done;\n })()\n : running\n ? \"Messaging worker\"\n : failed\n ? \"Worker message failed\"\n : cancelled\n ? \"Worker interrupted\"\n : \"Worker messaged\";\n return (\n <div\n className={cn(\n \"my-0.5 flex items-start gap-3 rounded-og-md border bg-og-surface-1 p-3\",\n failed ? \"border-og-status-failed/40\" : \"border-og-border\",\n )}\n >\n <span\n className={cn(\n \"mt-0.5 inline-flex size-7 shrink-0 items-center justify-center\",\n failed ? \"text-og-status-failed\" : \"text-og-accent\",\n )}\n >\n <BotIcon className=\"size-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n {/* In-flight state is carried ONLY by the shimmering title (no detached\n pulse badge), matching every other running row in the rail. */}\n <span className={cn(\"text-og-base font-medium\", running ? \"og-shimmer-text\" : failed ? \"text-og-status-failed\" : \"text-og-fg\")}>\n {title}\n </span>\n {item.prompt ? <p className=\"mt-0.5 truncate text-og-sm text-og-fg-muted\">{truncate(item.prompt, 140)}</p> : null}\n {item.workerSessionId ? (\n <p className=\"mt-1 font-og-mono text-og-xs text-og-fg-subtle\">{item.workerSessionId.slice(0, 8)}</p>\n ) : null}\n </div>\n {/* Right gutter: failed gets a red chip; cancelled gets a calm \"interrupted\"\n chip (no dot, no red); a live complete worker shows an \"Open session\" button. */}\n {failed ? (\n <span className=\"inline-flex shrink-0 self-center items-center gap-1.5 font-og-mono text-og-xs leading-none text-og-status-failed\">\n <span className=\"size-1.5 rounded-full bg-og-status-failed\" />\n failed\n </span>\n ) : cancelled ? (\n <span className=\"og-cancelled-chip shrink-0 self-center font-og-mono text-og-xs leading-none text-og-fg-subtle\">\n interrupted\n </span>\n ) : item.workerSessionId && onOpenSession ? (\n <button\n type=\"button\"\n onClick={() => item.workerSessionId && onOpenSession(item.workerSessionId)}\n className={cn(\n \"shrink-0 self-center rounded-og-sm border border-og-border px-2.5 py-1 text-og-sm font-medium text-og-fg-muted pointer-coarse:py-2\",\n \"outline-none transition-colors duration-150 hover:border-og-border-strong hover:text-og-fg\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n >\n Open session\n </button>\n ) : null}\n </div>\n );\n}\n","import { createContext, useContext, useRef } from \"react\";\n\n/* ----------------------------------------------------------------------------\n Entrance animation gating\n\n Bulk paints (the initial tail window, a prepended older window) must not run\n per-row entrance animations — hundreds of rows fading in at once reads as a\n full-timeline flash. Toggling `animation: none` on and off is NOT an option:\n removing the override restarts every animation, which is itself the flash.\n\n Instead each animated element decides ONCE, at its own mount, whether it was\n born in a bulk paint — and keeps that decision forever. Rows born in a bulk\n paint never animate; rows appended live animate exactly as before. Nothing\n is ever toggled on existing DOM, so nothing can replay.\n -------------------------------------------------------------------------- */\n\nconst EntranceAnimationContext = createContext(true);\n\nexport const EntranceAnimationProvider = EntranceAnimationContext.Provider;\n\n/**\n * Whether this element should wear the entrance animation. Captured at mount\n * from the nearest provider (true outside any provider) and stable for the\n * element's lifetime — see the module doctrine above.\n */\nexport function useEntranceAnimation(): boolean {\n const enabled = useContext(EntranceAnimationContext);\n const captured = useRef(enabled);\n return captured.current;\n}\n","import { CheckIcon, ChevronRightIcon, CircleSlashIcon, TriangleAlertIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { Collapsible } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\nimport { useForcedDefaultOpen } from \"./disclosure-context\";\nimport { useEntranceAnimation } from \"./entrance\";\nimport { applyPatchOps, isApplyPatch, screenshotDataUrl } from \"./parsers\";\nimport { rawTypeOf } from \"./registry\";\nimport type { ActivityItem, TurnOutcome } from \"./types\";\nexport type { TurnOutcome } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Turn summary\n\n A completed (or failed/cancelled) turn folds behind one quiet summary chip:\n \"N steps · M files · K commands · 1 screenshot · 4m\". The chip is the default\n surface; expanding it reveals the full settled turn body. A live turn never\n folds — render its rows directly.\n\n This keeps the timeline calm: a finished turn is a single line until the\n reader chooses to look inside it.\n -------------------------------------------------------------------------- */\n\nexport type TurnSummaryProps = {\n /** The activity items in the turn (used only to compute the facet counts). */\n items: ActivityItem[];\n /**\n * The settled verdict — or absent for a completed CLUSTER of a still-running\n * turn, which folds neutrally: no verdict glyph (the turn has none yet), a\n * quiet pulse dot in its place so alignment and the running feel both hold.\n */\n outcome?: TurnOutcome | undefined;\n /** A short failure reason shown inline on a failed chip (never hidden). */\n failureText?: string | undefined;\n /** Elapsed turn duration; shown as a trailing facet when at least 1s. */\n durationMs?: number | undefined;\n /** Start expanded. */\n defaultOpen?: boolean | undefined;\n /** The rendered activity rail revealed on expand. */\n children: React.ReactNode;\n};\n\nexport function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, children }: TurnSummaryProps) {\n // An explicit `defaultOpen` always wins; otherwise an ancestor may seed it\n // (screenshot instrumentation); otherwise the turn starts folded.\n const forcedDefaultOpen = useForcedDefaultOpen();\n const [open, setOpen] = useState(defaultOpen ?? forcedDefaultOpen ?? false);\n const enter = useEntranceAnimation();\n const facets = summarizeTurn(items, durationMs);\n\n return (\n <Collapsible.Root open={open} onOpenChange={setOpen} className={enter ? \"animate-og-enter\" : undefined}>\n <Collapsible.Trigger\n className={cn(\n \"group flex w-full items-center gap-2.5 rounded-og-md border px-3 py-2 text-left text-og-base transition-colors\",\n // A folded turn is a touch target on coarse pointers: grow the row so\n // it clears the 40px minimum without disturbing the calm desktop rhythm.\n \"pointer-coarse:py-2.5\",\n // Only a failed turn earns the one filled/tinted card in the timeline;\n // complete and cancelled stay flat and calm.\n outcome === \"failed\"\n ? \"border-og-status-failed/30 bg-og-status-failed/[0.06] hover:border-og-status-failed/50\"\n : \"border-og-border bg-og-surface-1/50 hover:border-og-border-strong\",\n )}\n >\n {/* Disclosure grammar matches the rows: chevron leads (far left), then the\n outcome glyph, then the facets — one expand affordance side everywhere. */}\n <ChevronRightIcon className=\"size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 group-data-[state=open]:rotate-90\" />\n {/* Only the exceptional outcomes earn a filled tinted circle. A clean\n (complete) run draws a bare muted check — zero colored fills, so the\n eye is pulled only to a turn that needs attention. */}\n <span\n className={cn(\n \"inline-flex size-5 shrink-0 items-center justify-center rounded-full\",\n outcome === \"failed\"\n ? \"bg-og-status-failed/15 text-og-status-failed\"\n : outcome === \"cancelled\"\n ? \"bg-og-fg-subtle/15 text-og-fg-subtle\"\n : \"text-og-fg-subtle\",\n )}\n >\n {outcome === \"failed\" ? (\n <TriangleAlertIcon className=\"size-3\" />\n ) : outcome === \"cancelled\" ? (\n <CircleSlashIcon className=\"size-3\" />\n ) : outcome === \"complete\" ? (\n <CheckIcon className=\"size-3.5\" />\n ) : (\n <span className=\"size-1.5 animate-og-pulse rounded-full bg-og-fg-subtle\" />\n )}\n </span>\n <span className=\"min-w-0 flex-1 truncate text-og-fg-muted\">\n {facets}\n {outcome === \"failed\" && failureText ? (\n <span className=\"text-og-status-failed\"> · {failureText}</span>\n ) : null}\n {outcome === \"cancelled\" ? <span className=\"text-og-fg-subtle\"> · interrupted</span> : null}\n </span>\n {/* The disclosure hint. Calm at rest on fine pointers (revealed on hover\n and keyboard focus), but always present on coarse pointers where there\n is no hover to lean on — so the fold never reads as a static status\n line. Purely visual: the trigger's aria-expanded already conveys state\n to assistive tech, so the hint is hidden from the accessible name. */}\n <span\n aria-hidden\n className={cn(\n \"ml-auto shrink-0 pl-2 text-og-xs text-og-fg-subtle transition-opacity duration-150\",\n \"opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100\",\n \"pointer-coarse:opacity-100\",\n )}\n >\n {open ? \"hide steps\" : \"show steps\"}\n </span>\n </Collapsible.Trigger>\n <Collapsible.Content className=\"overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand\">\n <div className=\"pt-2\">{children}</div>\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/** Compose the facet summary line (\"14 steps · 3 files · 2 commands · 1 screenshot · 4m\"). */\nfunction summarizeTurn(items: ActivityItem[], durationMs?: number): string {\n let files = 0;\n let commands = 0;\n let screenshots = 0;\n for (const item of items) {\n if (item.kind !== \"tool-call\") {\n continue;\n }\n // `item` is narrowed to ToolCallItem by the guard above — no cast needed.\n if (isApplyPatch(item)) {\n files += applyPatchOps(item.raw).length;\n } else if (item.name === \"exec_command\") {\n commands += 1;\n } else if (rawTypeOf(item) === \"computer_call\" || item.name === \"computer_call\" || item.name === \"computer_screenshot\") {\n if (screenshotDataUrl(item.output) !== null) {\n screenshots += 1;\n }\n }\n }\n const parts = [`${items.length} ${items.length === 1 ? \"step\" : \"steps\"}`];\n if (files) {\n parts.push(`${files} ${files === 1 ? \"file\" : \"files\"} edited`);\n }\n if (commands) {\n parts.push(`${commands} ${commands === 1 ? \"command\" : \"commands\"}`);\n }\n if (screenshots) {\n parts.push(`${screenshots} ${screenshots === 1 ? \"screenshot\" : \"screenshots\"}`);\n }\n const duration = formatDurationFacet(durationMs);\n if (duration) {\n parts.push(duration);\n }\n return parts.join(\" · \");\n}\n\nfunction formatDurationFacet(durationMs: number | undefined): string | null {\n if (durationMs === undefined || !Number.isFinite(durationMs) || durationMs < 1000) {\n return null;\n }\n const totalSeconds = Math.floor(durationMs / 1000);\n if (totalSeconds < 60) {\n return `${totalSeconds}s`;\n }\n const totalMinutes = Math.floor(totalSeconds / 60);\n if (totalMinutes < 60) {\n return `${totalMinutes}m`;\n }\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n return `${hours}h ${String(minutes).padStart(2, \"0\")}m`;\n}\n","import type { SendMessageInput } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type ComposerSendExtras = Omit<SendMessageInput, \"text\" | \"clientEventId\">;\n\n/**\n * Compose-time delivery choice. `queue` (the default) stacks the message\n * behind the running turn — visible, editable, reorderable until claimed.\n * `steer` interrupts the running turn and injects the message now.\n */\nexport type ComposerMode = \"queue\" | \"steer\";\n\nexport type UseComposerOptions = ClientOverride & {\n /** Called with the accepted text after a successful send. */\n onSent?: ((text: string) => void) | undefined;\n /**\n * Extra message fields (resources, tools, model, reasoningEffort) merged\n * into every send. A function is evaluated at send time so it can read the\n * surrounding UI state (attachment pickers, model selectors, ...).\n */\n sendExtras?: ComposerSendExtras | (() => ComposerSendExtras) | undefined;\n /** Initial delivery mode. Defaults to `\"queue\"`. */\n defaultMode?: ComposerMode | undefined;\n};\n\nexport type ComposerState = {\n value: string;\n setValue: (value: string) => void;\n /** Send the draft (or an explicit text) using the current mode. */\n send: (text?: string) => Promise<boolean>;\n sending: boolean;\n canSend: boolean;\n /** Queue (default) vs steer — the compose-time delivery choice. */\n mode: ComposerMode;\n setMode: (mode: ComposerMode) => void;\n /** Ask the agent to stop the current turn. */\n interrupt: (reason?: string) => Promise<void>;\n interrupting: boolean;\n error: Error | null;\n clearError: () => void;\n};\n\n/**\n * Draft + send + interrupt state for the chat composer — the only\n * human-to-agent input surface. The draft survives a failed send (nothing is\n * more hostile than losing a typed message); each send carries a generated\n * `clientEventId` so retries stay idempotent server-side.\n */\nexport function useComposer(sessionId: string | null | undefined, options: UseComposerOptions = {}): ComposerState {\n const { client, workspaceId } = useOpenGeni(options);\n const defaultMode = options.defaultMode ?? \"queue\";\n const [value, setValue] = useState(\"\");\n const [mode, setMode] = useState<ComposerMode>(defaultMode);\n const [sending, setSending] = useState(false);\n const [interrupting, setInterrupting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const pendingClientEventId = useRef<string | null>(null);\n const onSent = options.onSent;\n // Read at send time so an in-flight send uses the mode chosen at submit.\n const modeRef = useRef(mode);\n modeRef.current = mode;\n // Read through a ref so a new extras closure (created every render by\n // callers passing inline functions) does not invalidate `send`.\n const sendExtrasRef = useRef(options.sendExtras);\n sendExtrasRef.current = options.sendExtras;\n\n // A composer is bound to one session: switching targets must not leak the\n // previous session's draft, error, or retry idempotency key.\n const targetKey = `${workspaceId}\\u0000${sessionId ?? \"\"}`;\n const targetKeyRef = useRef(targetKey);\n useEffect(() => {\n if (targetKeyRef.current !== targetKey) {\n targetKeyRef.current = targetKey;\n pendingClientEventId.current = null;\n setValue(\"\");\n setError(null);\n setMode(defaultMode);\n }\n }, [targetKey, defaultMode]);\n\n const send = useCallback(\n async (explicit?: string): Promise<boolean> => {\n const draftAtSend = value;\n const text = (explicit ?? draftAtSend).trim();\n // Resolve the extras once: a file-only message (empty text + ≥1 ready\n // resource) is legitimate, so we must not bail on empty text alone.\n const extras = resolveSendExtras(sendExtrasRef.current);\n const hasResources = (extras.resources?.length ?? 0) > 0;\n if ((!text && !hasResources) || !sessionId || sending) {\n return false;\n }\n // Reuse the clientEventId across retries of the same draft so a\n // timeout + resend cannot double-deliver the message.\n pendingClientEventId.current ??= generateClientEventId();\n setSending(true);\n setError(null);\n try {\n // The wire contract requires non-empty text (z.string().min(1)) and the\n // worker rejects whitespace-only text; a file-only message therefore\n // carries a minimal default so the attachments still get delivered.\n const sendText = text || FILE_ONLY_MESSAGE_TEXT;\n const input = composeSendInput(sendText, pendingClientEventId.current, extras);\n if (modeRef.current === \"steer\") {\n await client.steerMessage(workspaceId, sessionId, input);\n } else {\n await client.sendMessage(workspaceId, sessionId, input);\n }\n pendingClientEventId.current = null;\n if (explicit === undefined) {\n // Clear only the draft that was sent: edits made while the request\n // was in flight were never delivered and must survive.\n setValue((current) => (current === draftAtSend ? \"\" : current));\n }\n onSent?.(sendText);\n return true;\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n return false;\n } finally {\n setSending(false);\n }\n },\n [client, workspaceId, sessionId, value, sending, onSent],\n );\n\n // A send is possible with non-empty text OR with ≥1 attached resource (a\n // file-only message). Resources ride in `sendExtras`, so we resolve them here\n // — keeping useComposer attachment-agnostic while still lighting up the send\n // affordance the moment a file is ready. ChatComposer additionally gates this\n // on its `attachments.uploading` flag so a message never departs mid-upload.\n const hasReadyResources = (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;\n\n const interrupt = useCallback(\n async (reason?: string): Promise<void> => {\n if (!sessionId || interrupting) {\n return;\n }\n setInterrupting(true);\n setError(null);\n try {\n await client.interrupt(workspaceId, sessionId, reason !== undefined ? { reason } : {});\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setInterrupting(false);\n }\n },\n [client, workspaceId, sessionId, interrupting],\n );\n\n const updateValue = useCallback((next: string) => {\n pendingClientEventId.current = null;\n setValue(next);\n }, []);\n\n return {\n value,\n setValue: updateValue,\n send,\n sending,\n canSend: Boolean(sessionId) && !sending && (value.trim().length > 0 || hasReadyResources),\n mode,\n setMode,\n interrupt,\n interrupting,\n error,\n clearError: useCallback(() => setError(null), []),\n };\n}\n\n/**\n * Default text for a file-only message (attachment(s) present, no typed draft).\n * Kept non-empty so the wire contract (`text: z.string().min(1)`) and the\n * worker's non-whitespace guard accept it; the attached files still ride in\n * `resources`. Exported for tests.\n */\nexport const FILE_ONLY_MESSAGE_TEXT = \"(see attached files)\";\n\n/** Resolve possibly-deferred extras to a concrete bag (function evaluated now). */\nexport function resolveSendExtras(\n extras: ComposerSendExtras | (() => ComposerSendExtras) | undefined,\n): ComposerSendExtras {\n return (typeof extras === \"function\" ? extras() : extras) ?? {};\n}\n\n/**\n * Merge the draft text + idempotency key with caller-provided extras. The\n * text and clientEventId always win over extras. Exported for tests.\n */\nexport function composeSendInput(\n text: string,\n clientEventId: string,\n extras: ComposerSendExtras | (() => ComposerSendExtras) | undefined,\n): SendMessageInput {\n return { ...resolveSendExtras(extras), text, clientEventId };\n}\n\n/** Submit on plain Enter; Shift+Enter inserts a newline. Exported for tests. */\nexport function shouldSubmitOnKey(event: { key: string; shiftKey: boolean; nativeEvent?: { isComposing?: boolean } }): boolean {\n if (event.key !== \"Enter\" || event.shiftKey) {\n return false;\n }\n return event.nativeEvent?.isComposing !== true;\n}\n\nfunction generateClientEventId(): string {\n const cryptoApi = globalThis.crypto;\n if (cryptoApi && \"randomUUID\" in cryptoApi) {\n return cryptoApi.randomUUID();\n }\n return `ce-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n","import type { FileAsset, FileResourceRef } from \"@opengeni/sdk\";\nimport { useCallback, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type UseFileAttachmentsOptions = ClientOverride & {\n /**\n * Only files matching this predicate are accepted by {@link\n * UseFileAttachmentsResult.addFromPaste} (the clipboard path). Defaults to\n * `image/*` — the console's historical paste filter. {@link\n * UseFileAttachmentsResult.addFiles} (the explicit picker / drop path)\n * bypasses it.\n */\n pasteFilter?: ((file: File) => boolean) | undefined;\n};\n\nexport type FileAttachment = {\n id: string;\n name: string;\n contentType: string;\n sizeBytes: number;\n status: \"uploading\" | \"ready\" | \"failed\";\n /** The SDK `FileAsset` once the upload finishes. */\n file?: FileAsset | undefined;\n /** Object-URL for an inline preview; minted for `image/*` files only. */\n previewUrl?: string | undefined;\n error?: string | undefined;\n};\n\nexport type UseFileAttachmentsResult = {\n attachments: FileAttachment[];\n /**\n * `FileResourceRef[]` for every attachment that finished uploading — feed\n * straight into `useComposer`'s `sendExtras.resources`.\n */\n readyResources: FileResourceRef[];\n /** True while any attachment is still uploading (drives the send-gate). */\n uploading: boolean;\n /** Explicit picker / drop path — uploads every file, no filter. */\n addFiles: (files: Iterable<File>) => void;\n /** Clipboard path — applies `pasteFilter` (default `image/*`) then uploads. */\n addFromPaste: (event: { clipboardData: DataTransfer | null }) => void;\n /**\n * Re-run the upload for a `failed` attachment, in place (same id, same\n * source file). No-op for an id that isn't a known failed upload.\n */\n retry: (id: string) => void;\n /** Remove one attachment; revokes its object-URL. */\n remove: (id: string) => void;\n /** Remove all; revokes every object-URL. Call from `useComposer`'s `onSent`. */\n clear: () => void;\n};\n\nconst isImage = (file: File): boolean => file.type.startsWith(\"image/\");\n\n/**\n * Upload-and-track state for files attached to the next message. Owns the\n * full client-side upload layer: a per-file `uploading | ready | failed`\n * status machine driven by the SDK's `client.uploadFile`, object-URL image\n * previews with create/revoke lifecycle, the `image/*` clipboard paste filter,\n * and a `FileResourceRef[]` projection that drops straight into a message's\n * `resources`. Workspace-scoped, so it resolves both client and workspace from\n * the {@link OpenGeniProvider} (or a per-call `{ client, workspaceId }`).\n */\nexport function useFileAttachments(options: UseFileAttachmentsOptions = {}): UseFileAttachmentsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const pasteFilter = options.pasteFilter ?? isImage;\n const [attachments, setAttachments] = useState<FileAttachment[]>([]);\n // Keep the source File per attachment id so a failed upload can be retried\n // in place. Cleared on remove/clear so it never outlives its attachment.\n const sources = useRef<Map<string, File>>(new Map());\n\n // Run (or re-run) the upload for one already-tracked attachment id. Sets it\n // back to `uploading`, then resolves to `ready` (with the asset) or `failed`\n // (with the error message).\n const startUpload = useCallback((id: string, file: File) => {\n void client.uploadFile(workspaceId, {\n filename: file.name || \"file\",\n contentType: file.type || \"application/octet-stream\",\n data: file,\n }).then((asset) => {\n setAttachments((current) => current.map((attachment) => attachment.id === id\n ? { ...attachment, status: \"ready\", file: asset, name: asset.filename, contentType: asset.contentType, sizeBytes: asset.sizeBytes, error: undefined }\n : attachment));\n }).catch((error: unknown) => {\n setAttachments((current) => current.map((attachment) => attachment.id === id\n ? { ...attachment, status: \"failed\", error: error instanceof Error ? error.message : String(error) }\n : attachment));\n });\n }, [client, workspaceId]);\n\n const addFiles = useCallback((files: Iterable<File>) => {\n for (const file of files) {\n const id = crypto.randomUUID();\n sources.current.set(id, file);\n const previewUrl = isImage(file) ? URL.createObjectURL(file) : undefined;\n setAttachments((current) => [...current, {\n id,\n name: file.name || \"image\",\n contentType: file.type || \"application/octet-stream\",\n sizeBytes: file.size,\n status: \"uploading\",\n ...(previewUrl ? { previewUrl } : {}),\n }]);\n startUpload(id, file);\n }\n }, [startUpload]);\n\n const retry = useCallback((id: string) => {\n const file = sources.current.get(id);\n if (!file) {\n return;\n }\n setAttachments((current) => current.map((attachment) => attachment.id === id\n ? { ...attachment, status: \"uploading\", error: undefined }\n : attachment));\n startUpload(id, file);\n }, [startUpload]);\n\n const addFromPaste = useCallback((event: { clipboardData: DataTransfer | null }) => {\n const clipboardFiles = event.clipboardData?.files;\n if (!clipboardFiles) {\n return;\n }\n const files = [...clipboardFiles].filter(pasteFilter);\n if (files.length > 0) {\n addFiles(files);\n }\n }, [addFiles, pasteFilter]);\n\n const remove = useCallback((id: string) => {\n sources.current.delete(id);\n setAttachments((current) => {\n const removed = current.find((attachment) => attachment.id === id);\n if (removed?.previewUrl) {\n URL.revokeObjectURL(removed.previewUrl);\n }\n return current.filter((attachment) => attachment.id !== id);\n });\n }, []);\n\n const clear = useCallback(() => {\n sources.current.clear();\n setAttachments((current) => {\n for (const attachment of current) {\n if (attachment.previewUrl) {\n URL.revokeObjectURL(attachment.previewUrl);\n }\n }\n return [];\n });\n }, []);\n\n return {\n attachments,\n readyResources: attachments.flatMap((attachment): FileResourceRef[] => attachment.status === \"ready\" && attachment.file\n ? [{ kind: \"file\", fileId: attachment.file.id }]\n : []),\n uploading: attachments.some((attachment) => attachment.status === \"uploading\"),\n addFiles,\n addFromPaste,\n retry,\n remove,\n clear,\n };\n}\n","import type { SessionEvent, SessionTurn, UpdateSessionTurnRequest } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useDebouncedCallback, useMutationRunner, useSessionEventTrigger, type SessionEventFeedOptions } from \"./internal\";\n\n/** Event types that change the turn queue (queue/edit/reorder/claim/finish). */\nexport function isTurnQueueEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type.startsWith(\"turn.\");\n}\n\n/** Queued turns in execution order (position, then creation time). */\nexport function queueFromTurns(turns: SessionTurn[]): SessionTurn[] {\n return turns\n .filter((turn) => turn.status === \"queued\")\n .sort((a, b) => a.position - b.position || a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id));\n}\n\n/** The turn currently holding the session (running or awaiting approval). */\nexport function activeTurnFromTurns(turns: SessionTurn[]): SessionTurn | null {\n return turns.find((turn) => turn.status === \"running\" || turn.status === \"requires_action\") ?? null;\n}\n\n/** Optimistic projection of a queued-turn edit. */\nexport function applyTurnEdit(turns: SessionTurn[], turnId: string, update: UpdateSessionTurnRequest): SessionTurn[] {\n return turns.map((turn) => {\n if (turn.id !== turnId || turn.status !== \"queued\") {\n return turn;\n }\n return {\n ...turn,\n ...(update.prompt !== undefined ? { prompt: update.prompt } : {}),\n ...(update.resources !== undefined ? { resources: update.resources } : {}),\n ...(update.tools !== undefined ? { tools: update.tools } : {}),\n ...(update.model !== undefined ? { model: update.model } : {}),\n ...(update.reasoningEffort !== undefined ? { reasoningEffort: update.reasoningEffort } : {}),\n ...(update.sandboxBackend !== undefined ? { sandboxBackend: update.sandboxBackend } : {}),\n ...(update.metadata !== undefined ? { metadata: update.metadata } : {}),\n };\n });\n}\n\n/**\n * Optimistic projection of a reorder, mirroring the server: the listed\n * queued turns get positions 1..n in the given order; everything else keeps\n * its position.\n */\nexport function applyTurnReorder(turns: SessionTurn[], turnIds: string[]): SessionTurn[] {\n const positions = new Map(turnIds.map((turnId, index) => [turnId, index + 1] as const));\n return turns.map((turn) => {\n const position = positions.get(turn.id);\n return position !== undefined && turn.status === \"queued\" ? { ...turn, position } : turn;\n });\n}\n\n/** Optimistic projection of a queued-turn delete (server marks it cancelled). */\nexport function applyTurnRemoval(turns: SessionTurn[], turnId: string): SessionTurn[] {\n return turns.map((turn) => (turn.id === turnId && turn.status === \"queued\" ? { ...turn, status: \"cancelled\" as const } : turn));\n}\n\nexport type UseTurnQueueOptions = ClientOverride & SessionEventFeedOptions & {\n /** Optional safety-net polling (ms). Off by default — turn.* events drive updates. */\n pollIntervalMs?: number | undefined;\n};\n\nexport type UseTurnQueueResult = {\n /** All turns the API returned (history + queue), newest server view. */\n turns: SessionTurn[];\n /** Queued turns in execution order — render this as the editable queue. */\n queue: SessionTurn[];\n /** The running / requires_action turn, if any. */\n activeTurn: SessionTurn | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Edit a queued turn (optimistic; rolls back via refetch on failure). */\n editTurn: (turnId: string, update: UpdateSessionTurnRequest) => Promise<SessionTurn | null>;\n /** Reorder the queue to the given queued-turn id order (optimistic). */\n reorderTurns: (turnIds: string[]) => Promise<SessionTurn[] | null>;\n /** Delete (cancel) a queued turn before it is claimed (optimistic). */\n removeTurn: (turnId: string) => Promise<SessionTurn | null>;\n /** True while an edit/reorder/remove is in flight. */\n mutating: boolean;\n /** Last failed mutation, until the next mutation or clear. */\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * The live turn queue — the heart of the queue-by-default interaction model.\n * Messages sent mid-turn stack up here, visible and editable/reorderable/\n * deletable until the worker claims them. Updates arrive over the session\n * event stream (`turn.*`), either shared via `options.events` (pass the log\n * from `useSessionEvents` to reuse its connection) or a dedicated tail\n * stream. All mutations apply optimistically and reconcile with the server.\n */\nexport function useTurnQueue(sessionId: string | null | undefined, options: UseTurnQueueOptions = {}): UseTurnQueueResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const [turns, setTurns] = useState<SessionTurn[]>([]);\n const [loading, setLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const mutation = useMutationRunner();\n const generation = useRef(0);\n const targetKeyRef = useRef<string | null>(null);\n\n const load = useCallback(async (): Promise<void> => {\n if (!sessionId) {\n return;\n }\n const ticket = ++generation.current;\n try {\n const fetched = await client.listTurns(workspaceId, sessionId);\n if (ticket === generation.current) {\n setTurns(fetched);\n setError(null);\n setLoading(false);\n }\n } catch (cause) {\n if (ticket === generation.current) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setLoading(false);\n }\n }\n }, [client, workspaceId, sessionId]);\n\n // Reset when the target session changes; initial load + optional polling.\n useEffect(() => {\n const targetKey = `${workspaceId}\\u0000${sessionId ?? \"\"}`;\n if (targetKeyRef.current !== targetKey) {\n targetKeyRef.current = targetKey;\n setTurns([]);\n setError(null);\n }\n if (!enabled) {\n setLoading(false);\n return;\n }\n setLoading(true);\n void load();\n const pollIntervalMs = options.pollIntervalMs;\n if (pollIntervalMs === undefined || pollIntervalMs <= 0) {\n return () => {\n generation.current += 1;\n };\n }\n const timer = setInterval(() => void load(), pollIntervalMs);\n return () => {\n clearInterval(timer);\n generation.current += 1;\n };\n }, [load, enabled, workspaceId, sessionId, options.pollIntervalMs]);\n\n // Live updates: any turn.* event re-syncs the queue (debounced).\n const scheduleRefresh = useDebouncedCallback(() => void load());\n useSessionEventTrigger(client, workspaceId, sessionId, isTurnQueueEvent, scheduleRefresh, {\n enabled,\n ...(options.events !== undefined ? { events: options.events } : {}),\n });\n\n const editTurn = useCallback(\n async (turnId: string, update: UpdateSessionTurnRequest): Promise<SessionTurn | null> => {\n if (!sessionId) {\n return null;\n }\n setTurns((current) => applyTurnEdit(current, turnId, update));\n const result = await mutation.run(() => client.updateQueuedTurn(workspaceId, sessionId, turnId, update));\n if (result) {\n setTurns((current) => current.map((turn) => (turn.id === result.id ? result : turn)));\n } else {\n void load();\n }\n return result;\n },\n [client, workspaceId, sessionId, mutation.run, load],\n );\n\n const reorderTurns = useCallback(\n async (turnIds: string[]): Promise<SessionTurn[] | null> => {\n if (!sessionId || turnIds.length === 0) {\n return null;\n }\n setTurns((current) => applyTurnReorder(current, turnIds));\n const result = await mutation.run(() => client.reorderQueuedTurns(workspaceId, sessionId, turnIds));\n if (result) {\n // The server returns the queued turns; merge them over local state.\n setTurns((current) => {\n const bySId = new Map(result.map((turn) => [turn.id, turn] as const));\n return current.map((turn) => bySId.get(turn.id) ?? turn);\n });\n } else {\n void load();\n }\n return result;\n },\n [client, workspaceId, sessionId, mutation.run, load],\n );\n\n const removeTurn = useCallback(\n async (turnId: string): Promise<SessionTurn | null> => {\n if (!sessionId) {\n return null;\n }\n setTurns((current) => applyTurnRemoval(current, turnId));\n const result = await mutation.run(() => client.deleteQueuedTurn(workspaceId, sessionId, turnId));\n if (result) {\n setTurns((current) => current.map((turn) => (turn.id === result.id ? result : turn)));\n } else {\n void load();\n }\n return result;\n },\n [client, workspaceId, sessionId, mutation.run, load],\n );\n\n return {\n turns,\n queue: queueFromTurns(turns),\n activeTurn: activeTurnFromTurns(turns),\n loading,\n error,\n refresh: load,\n editTurn,\n reorderTurns,\n removeTurn,\n mutating: mutation.mutating,\n mutationError: mutation.mutationError,\n clearMutationError: mutation.clearMutationError,\n };\n}\n","import { OpenGeniApiError, type SessionEvent, type SessionGoal } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useDebouncedCallback, useMutationRunner, useSessionEventTrigger, type SessionEventFeedOptions } from \"./internal\";\n\n/** Event types that change the session goal (set/updated/completed/paused/...). */\nexport function isGoalEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type.startsWith(\"goal.\");\n}\n\nexport type UseGoalOptions = ClientOverride & SessionEventFeedOptions & {\n /** Optional safety-net polling (ms). Off by default — goal.* events drive updates. */\n pollIntervalMs?: number | undefined;\n};\n\nexport type UseGoalResult = {\n /** The session goal, or null when the session has none. */\n goal: SessionGoal | null;\n /** Convenience flags over `goal.status`. */\n isActive: boolean;\n isPaused: boolean;\n isCompleted: boolean;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Pause the goal loop (PATCH status=paused). */\n pause: (rationale?: string) => Promise<SessionGoal | null>;\n /** Resume a paused goal: resets counters and re-arms continuations. */\n resume: () => Promise<SessionGoal | null>;\n /** True while a pause/resume is in flight. */\n updating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * The session's goal: state, the autonomy counters (`autoContinuations`,\n * `noProgressStreak`), and pause/resume control. A goal-less session yields\n * `goal: null` (the 404 is absorbed). Live-updates on `goal.*` events —\n * pass `options.events` from `useSessionEvents` to reuse its stream.\n */\nexport function useGoal(sessionId: string | null | undefined, options: UseGoalOptions = {}): UseGoalResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const sharedEvents = options.events;\n const sharedFeed = sharedEvents !== undefined;\n const [goal, setGoal] = useState<SessionGoal | null>(null);\n const [loading, setLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const mutation = useMutationRunner();\n const generation = useRef(0);\n const targetKeyRef = useRef<string | null>(null);\n\n const load = useCallback(async (): Promise<void> => {\n if (!sessionId) {\n return;\n }\n const ticket = ++generation.current;\n try {\n const fetched = await client.getGoal(workspaceId, sessionId);\n if (ticket === generation.current) {\n setGoal(fetched);\n setError(null);\n setLoading(false);\n }\n } catch (cause) {\n if (ticket !== generation.current) {\n return;\n }\n if (cause instanceof OpenGeniApiError && cause.status === 404) {\n // No goal is a normal state, not an error.\n setGoal(null);\n setError(null);\n } else {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n setLoading(false);\n }\n }, [client, workspaceId, sessionId]);\n\n useEffect(() => {\n const targetKey = `${workspaceId} ${sessionId ?? \"\"}`;\n if (targetKeyRef.current !== targetKey) {\n targetKeyRef.current = targetKey;\n setGoal(null);\n setError(null);\n }\n if (!enabled) {\n setLoading(false);\n return;\n }\n if (sharedFeed) {\n setLoading(false);\n return () => {\n generation.current += 1;\n };\n }\n setLoading(true);\n void load();\n const pollIntervalMs = options.pollIntervalMs;\n if (pollIntervalMs === undefined || pollIntervalMs <= 0) {\n return () => {\n generation.current += 1;\n };\n }\n const timer = setInterval(() => void load(), pollIntervalMs);\n return () => {\n clearInterval(timer);\n generation.current += 1;\n };\n }, [load, enabled, workspaceId, sessionId, options.pollIntervalMs, sharedFeed]);\n\n const scheduleRefresh = useDebouncedCallback(() => void load());\n useSessionEventTrigger(client, workspaceId, sessionId, isGoalEvent, scheduleRefresh, {\n enabled,\n ...(sharedEvents !== undefined ? { events: sharedEvents } : {}),\n });\n\n const pause = useCallback(\n async (rationale?: string): Promise<SessionGoal | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await mutation.run(() =>\n client.updateGoal(workspaceId, sessionId, {\n status: \"paused\",\n ...(rationale !== undefined ? { rationale } : {}),\n }));\n if (result) {\n setGoal(result);\n }\n return result;\n },\n [client, workspaceId, sessionId, mutation.run],\n );\n\n const resume = useCallback(async (): Promise<SessionGoal | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await mutation.run(() => client.updateGoal(workspaceId, sessionId, { status: \"active\" }));\n if (result) {\n setGoal(result);\n }\n return result;\n }, [client, workspaceId, sessionId, mutation.run]);\n\n return {\n goal,\n isActive: goal?.status === \"active\",\n isPaused: goal?.status === \"paused\",\n isCompleted: goal?.status === \"completed\",\n loading,\n error,\n refresh: load,\n pause,\n resume,\n updating: mutation.mutating,\n mutationError: mutation.mutationError,\n clearMutationError: mutation.clearMutationError,\n };\n}\n","import type { SessionEvent } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner } from \"./internal\";\n\nexport type UseSessionControlOptions = ClientOverride;\n\nexport type UseSessionControlResult = {\n /** Interrupt the running turn (the explicit alternative to queueing). */\n interrupt: (reason?: string) => Promise<SessionEvent | null>;\n interrupting: boolean;\n /** Approve a pending `requires_action` approval. */\n approve: (approvalId: string, message?: string) => Promise<SessionEvent | null>;\n /** Reject a pending `requires_action` approval. */\n reject: (approvalId: string, message?: string) => Promise<SessionEvent | null>;\n /** True while an approval decision is in flight. */\n responding: boolean;\n error: Error | null;\n clearError: () => void;\n};\n\n/**\n * Session control events: interrupt and approval decisions. Pair with\n * `useSessionEvents` (for `session.requiresAction` payloads carrying the\n * `approvalId`) to render an approval bar.\n */\nexport function useSessionControl(\n sessionId: string | null | undefined,\n options: UseSessionControlOptions = {},\n): UseSessionControlResult {\n const { client, workspaceId } = useOpenGeni(options);\n const interruptMutation = useMutationRunner();\n const approvalMutation = useMutationRunner();\n\n const interrupt = useCallback(\n async (reason?: string): Promise<SessionEvent | null> => {\n if (!sessionId) {\n return null;\n }\n return await interruptMutation.run(() =>\n client.interrupt(workspaceId, sessionId, reason !== undefined ? { reason } : {}));\n },\n [client, workspaceId, sessionId, interruptMutation.run],\n );\n\n const decide = useCallback(\n async (approvalId: string, decision: \"approve\" | \"reject\", message?: string): Promise<SessionEvent | null> => {\n if (!sessionId) {\n return null;\n }\n return await approvalMutation.run(() =>\n client.sendApprovalDecision(workspaceId, sessionId, {\n approvalId,\n decision,\n ...(message !== undefined ? { message } : {}),\n }));\n },\n [client, workspaceId, sessionId, approvalMutation.run],\n );\n\n const approve = useCallback(\n async (approvalId: string, message?: string) => await decide(approvalId, \"approve\", message),\n [decide],\n );\n const reject = useCallback(\n async (approvalId: string, message?: string) => await decide(approvalId, \"reject\", message),\n [decide],\n );\n\n const error = approvalMutation.mutationError ?? interruptMutation.mutationError;\n const clearError = useCallback(() => {\n interruptMutation.clearMutationError();\n approvalMutation.clearMutationError();\n }, [interruptMutation.clearMutationError, approvalMutation.clearMutationError]);\n\n return {\n interrupt,\n interrupting: interruptMutation.mutating,\n approve,\n reject,\n responding: approvalMutation.mutating,\n error,\n clearError,\n };\n}\n","import type { ScheduledTask } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseScheduledTasksOptions = ClientOverride & {\n limit?: number | undefined;\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseScheduledTasksResult = {\n tasks: ScheduledTask[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/** List the workspace's scheduled tasks (drift checks, sentinels, reapers, ...). */\nexport function useScheduledTasks(options: UseScheduledTasksOptions = {}): UseScheduledTasksResult {\n const { client, workspaceId } = useOpenGeni(options);\n const limit = options.limit;\n const load = useCallback(\n async () => await client.listScheduledTasks(workspaceId, limit !== undefined ? { limit } : {}),\n [client, workspaceId, limit],\n );\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n return { tasks: state.data ?? [], loading: state.loading, error: state.error, refresh: state.refresh };\n}\n","import type { Session } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseWorkspaceSessionsOptions = ClientOverride & {\n limit?: number | undefined;\n /** Refresh interval (ms) for fleet/manager views. Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseWorkspaceSessionsResult = {\n sessions: Session[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/** List the workspace's sessions — the data behind fleet and manager views. */\nexport function useWorkspaceSessions(options: UseWorkspaceSessionsOptions = {}): UseWorkspaceSessionsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const limit = options.limit;\n const load = useCallback(\n async () => await client.listSessions(workspaceId, limit !== undefined ? { limit } : {}),\n [client, workspaceId, limit],\n );\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n return { sessions: state.data ?? [], loading: state.loading, error: state.error, refresh: state.refresh };\n}\n","import type {\n CreateWorkspaceEnvironmentRequest,\n UpdateWorkspaceEnvironmentRequest,\n WorkspaceEnvironment,\n WorkspaceEnvironmentVariableMetadata,\n} from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UseEnvironmentsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseEnvironmentsResult = {\n environments: WorkspaceEnvironment[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (request: CreateWorkspaceEnvironmentRequest) => Promise<WorkspaceEnvironment | null>;\n update: (environmentId: string, request: UpdateWorkspaceEnvironmentRequest) => Promise<WorkspaceEnvironment | null>;\n remove: (environmentId: string) => Promise<boolean>;\n /** Set/rotate a variable. Values are write-only — reads expose metadata only. */\n setVariable: (environmentId: string, name: string, value: string) => Promise<WorkspaceEnvironmentVariableMetadata | null>;\n deleteVariable: (environmentId: string, name: string) => Promise<boolean>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * Workspace environments (named, encrypted variable sets attached to sessions\n * and scheduled tasks). Variable values are write-only end to end: this hook\n * never sees a value after it is sent.\n */\nexport function useEnvironments(options: UseEnvironmentsOptions = {}): UseEnvironmentsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(async () => await client.listEnvironments(workspaceId), [client, workspaceId]);\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n const mutation = useMutationRunner();\n\n const create = useCallback(\n async (request: CreateWorkspaceEnvironmentRequest): Promise<WorkspaceEnvironment | null> => {\n const result = await mutation.run(() => client.createEnvironment(workspaceId, request));\n if (result) {\n await state.refresh();\n }\n return result;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n const update = useCallback(\n async (environmentId: string, request: UpdateWorkspaceEnvironmentRequest): Promise<WorkspaceEnvironment | null> => {\n const result = await mutation.run(() => client.updateEnvironment(workspaceId, environmentId, request));\n if (result) {\n await state.refresh();\n }\n return result;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n const remove = useCallback(\n async (environmentId: string): Promise<boolean> => {\n const result = await mutation.run(async () => {\n await client.deleteEnvironment(workspaceId, environmentId);\n return true;\n });\n if (result) {\n await state.refresh();\n }\n return result === true;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n const setVariable = useCallback(\n async (environmentId: string, name: string, value: string): Promise<WorkspaceEnvironmentVariableMetadata | null> => {\n const result = await mutation.run(() => client.setEnvironmentVariable(workspaceId, environmentId, name, value));\n if (result) {\n await state.refresh();\n }\n return result;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n const deleteVariable = useCallback(\n async (environmentId: string, name: string): Promise<boolean> => {\n const result = await mutation.run(async () => {\n await client.deleteEnvironmentVariable(workspaceId, environmentId, name);\n return true;\n });\n if (result) {\n await state.refresh();\n }\n return result === true;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n return {\n environments: state.data ?? [],\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n create,\n update,\n remove,\n setVariable,\n deleteVariable,\n mutating: mutation.mutating,\n mutationError: mutation.mutationError,\n clearMutationError: mutation.clearMutationError,\n };\n}\n","import type {\n CapabilityPack,\n EnablePackRequest,\n PackInstallation,\n RegisterCapabilityPackRequest,\n WorkspaceRegisteredPack,\n} from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UsePacksOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UsePacksResult = {\n /** Built-in + registered packs available to the workspace. */\n packs: CapabilityPack[];\n /** Enable/disable state per pack. */\n installations: PackInstallation[];\n /** The installation for a pack id, if any. */\n installationFor: (packId: string) => PackInstallation | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Register (or replace) a workspace-scoped pack manifest. */\n register: (manifest: RegisterCapabilityPackRequest) => Promise<WorkspaceRegisteredPack | null>;\n enable: (packId: string, request?: EnablePackRequest) => Promise<PackInstallation | null>;\n /** Unregister a workspace-scoped pack (built-ins cannot be removed). */\n remove: (packId: string) => Promise<boolean>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/** Capability packs: catalog + installations + register/enable/unregister. */\nexport function usePacks(options: UsePacksOptions = {}): UsePacksResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(async () => await client.listPacks(workspaceId), [client, workspaceId]);\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n const mutation = useMutationRunner();\n\n const register = useCallback(\n async (manifest: RegisterCapabilityPackRequest): Promise<WorkspaceRegisteredPack | null> => {\n const result = await mutation.run(() => client.registerPack(workspaceId, manifest));\n if (result) {\n await state.refresh();\n }\n return result;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n const enable = useCallback(\n async (packId: string, request: EnablePackRequest = {}): Promise<PackInstallation | null> => {\n const result = await mutation.run(() => client.enablePack(workspaceId, packId, request));\n if (result) {\n await state.refresh();\n }\n return result;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n const remove = useCallback(\n async (packId: string): Promise<boolean> => {\n const result = await mutation.run(async () => {\n await client.deletePack(workspaceId, packId);\n return true;\n });\n if (result) {\n await state.refresh();\n }\n return result === true;\n },\n [client, workspaceId, mutation.run, state.refresh],\n );\n\n const installations = state.data?.installations ?? [];\n const installationFor = useCallback(\n (packId: string): PackInstallation | null =>\n installations.find((installation) => installation.packId === packId) ?? null,\n [installations],\n );\n\n return {\n packs: state.data?.packs ?? [],\n installations,\n installationFor,\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n register,\n enable,\n remove,\n mutating: mutation.mutating,\n mutationError: mutation.mutationError,\n clearMutationError: mutation.clearMutationError,\n };\n}\n","import type { CreateWorkspaceRequest, UpdateWorkspaceRequest, Workspace } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeniClient, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UseWorkspacesOptions = Pick<ClientOverride, \"client\"> & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseWorkspacesResult = {\n workspaces: Workspace[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (request: CreateWorkspaceRequest) => Promise<Workspace | null>;\n update: (workspaceId: string, request: UpdateWorkspaceRequest) => Promise<Workspace | null>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * The caller's workspaces (workspace switchers, onboarding). Not scoped to\n * the provider's workspace, so it only needs the client.\n */\nexport function useWorkspaces(options: UseWorkspacesOptions = {}): UseWorkspacesResult {\n const client = useOpenGeniClient(options);\n const load = useCallback(async () => await client.listWorkspaces(), [client]);\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n const mutation = useMutationRunner();\n\n const create = useCallback(\n async (request: CreateWorkspaceRequest): Promise<Workspace | null> => {\n const result = await mutation.run(() => client.createWorkspace(request));\n if (result) {\n await state.refresh();\n }\n return result;\n },\n [client, mutation.run, state.refresh],\n );\n\n const update = useCallback(\n async (workspaceId: string, request: UpdateWorkspaceRequest): Promise<Workspace | null> => {\n const result = await mutation.run(() => client.updateWorkspace(workspaceId, request));\n if (result) {\n await state.refresh();\n }\n return result;\n },\n [client, mutation.run, state.refresh],\n );\n\n return {\n workspaces: state.data ?? [],\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n create,\n update,\n mutating: mutation.mutating,\n mutationError: mutation.mutationError,\n clearMutationError: mutation.clearMutationError,\n };\n}\n","import type { BillingBalance, UsageEvent } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeniClient, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseBillingUsageOptions = Pick<ClientOverride, \"client\"> & {\n /** Account to read. Defaults to the caller's default account server-side. */\n accountId?: string | undefined;\n /** Filter usage to one workspace. */\n workspaceId?: string | undefined;\n /** Refresh interval (ms) for live billing meters. Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseBillingUsageResult = {\n /** Prepaid credit balance (micro-USD), null until loaded. */\n balance: BillingBalance | null;\n /** Recent usage events (runs, tokens, cost, uploads, ...). */\n usage: UsageEvent[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/**\n * Account billing usage: credit balance + recent usage events — the data\n * behind per-call billing meters. Account-scoped, so it only needs the\n * client; pass `workspaceId` to narrow usage to one workspace.\n */\nexport function useBillingUsage(options: UseBillingUsageOptions = {}): UseBillingUsageResult {\n const client = useOpenGeniClient(options);\n const accountId = options.accountId;\n const workspaceId = options.workspaceId;\n const load = useCallback(\n async () =>\n await client.getBillingUsage({\n ...(accountId !== undefined ? { accountId } : {}),\n ...(workspaceId !== undefined ? { workspaceId } : {}),\n }),\n [client, accountId, workspaceId],\n );\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n return {\n balance: state.data?.balance ?? null,\n usage: state.data?.usage ?? [],\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import type { ClientModel } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeniClient, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseAvailableModelsOptions = Pick<ClientOverride, \"client\"> & {\n /** Refresh interval (ms). Off by default — the host model list rarely moves. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseAvailableModelsResult = {\n /** The provider-grouped models the host exposes (empty until loaded). */\n models: ClientModel[];\n /** The deployment's default model id, null until loaded. */\n defaultModel: string | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/**\n * The host-exposed model list for a <ModelPicker>: fetches the deployment's\n * public client config (`GET /v1/config/client`) and surfaces the richer\n * provider-grouped `models` plus the `defaultModel` the picker should preselect.\n * Deployment-scoped, so it only needs the client (no workspace).\n */\nexport function useAvailableModels(options: UseAvailableModelsOptions = {}): UseAvailableModelsResult {\n const client = useOpenGeniClient(options);\n const load = useCallback(async () => await client.getClientConfig(), [client]);\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n return {\n models: state.data?.models ?? [],\n defaultModel: state.data?.defaultModel ?? null,\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import {\n OpenGeniApiError,\n applyUrlRotation,\n type SessionCapabilities,\n type SessionEvent,\n type StreamUrlRotatedPayload,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type SessionCapabilitiesState = \"idle\" | \"negotiating\" | \"ready\" | \"cold\" | \"error\";\n\nexport type UseSessionCapabilitiesOptions = ClientOverride & {\n /**\n * Live event log to fold `stream.url.rotated` from (usually\n * `useSessionEvents().events`). When present the desktop socket stays fresh on\n * a box rollover without a round-trip; stale-epoch rotations are dropped.\n */\n events?: SessionEvent[] | undefined;\n /**\n * Whether to acquire a viewer holder for the desktop pixel plane. Requires the\n * un-redacted acknowledgment to have been recorded (else the attach 409s and\n * the hook surfaces the consent requirement). Default false: read-only\n * negotiation (no holder, no warm) — terminal/files/git work without it.\n */\n attachDesktop?: boolean | undefined;\n /**\n * Whether to acquire a viewer holder to warm the box for the REAL interactive\n * terminal (the ttyd pty-ws plane). Symmetric with `attachDesktop` and shares\n * the SAME viewer attach (one warm box serves both planes), but needs NO\n * un-redacted acknowledgment — a shell is interactive by nature, and the gate\n * is the scoped tunnel URL + stream token. Default false: the terminal stays on\n * the read-only Channel-A firehose until the user opens/focuses it. The attach\n * folds the minted `pty-ws` url+token into the `Terminal` cell.\n */\n attachTerminal?: boolean | undefined;\n /**\n * Whether to acquire a viewer holder purely to KEEP THE BOX WARM while the\n * structured Files surface is open. Shares the SAME viewer attach as the\n * desktop/terminal (one warm box, one holder) and — like the terminal — needs\n * NO un-redacted acknowledgment: listing/reading/writing files is the ordinary\n * Channel-A control plane, not the pixel plane. Default false: the Files tab\n * negotiates read-only and each op pays the cold-box resume (~5s). When true,\n * the holder warms the box once and heartbeats it, so subsequent fs ops are\n * ~100ms instead of re-resuming the box on every list/write. It folds NO live\n * URL (files ride the stateless HTTP plane) — it only refcounts liveness.\n */\n attachFiles?: boolean | undefined;\n /** Hold off negotiating (e.g. the workbench panel is collapsed). Default true. */\n enabled?: boolean | undefined;\n /** Poll cadence (ms) while the lease is cold/warming. Default 1500. */\n warmingPollMs?: number | undefined;\n /**\n * Give up waiting for `warm` after this long while polling (ms) and surface a\n * stalled error with a manual `renegotiate`. Default 30000. This is a UI\n * patience deadline, independent from the worker's sandbox warming timeout.\n * 0 disables the deadline.\n */\n warmingDeadlineMs?: number | undefined;\n};\n\nexport type UseSessionCapabilitiesResult = {\n /** The negotiated capability doc — the single source of UI truth. */\n capabilities: SessionCapabilities | null;\n state: SessionCapabilitiesState;\n error: Error | null;\n /**\n * 409 from the desktop attach: the un-redacted (or shared) plane needs explicit\n * acknowledgment before a viewer holder is granted. Drives the consent prompt.\n */\n acknowledgmentRequired: \"unredacted\" | \"shared\" | null;\n /** 429 from the desktop attach: the per-session viewer cap is reached. */\n viewerCapReached: boolean;\n /** The viewer holder id minted on a desktop attach (for detach/heartbeat). */\n viewerId: string | null;\n /** Force a re-negotiation (after acknowledging, a resolution change, etc.). */\n renegotiate: () => void;\n};\n\n/**\n * Whether a desktop attach (POST /viewers) is worth attempting for this cell.\n * The desktop is FEASIBLE — and thus worth warming — when it already has a live\n * transport, OR when the only thing missing is a warm box (a cold/un-provisioned\n * lease). The handshake never warms a box, so a feasible-but-cold cell reports\n * transport:null with a transient reason; the viewer attach is exactly what warms\n * it. A genuinely-unsupported desktop (backend/os/policy/headless) is never\n * attachable — attaching would 409/403/no-op without ever producing a stream.\n */\nfunction desktopAttachable(cell: SessionCapabilities[\"DesktopStream\"]): boolean {\n if (cell.transport !== null) return true;\n // transport === null: attach only when the reason is a transient cold state.\n return cell.reason === \"lease_cold\" || cell.reason === \"not_provisioned\" || cell.reason === null;\n}\n\n/**\n * Whether warming the box for the interactive terminal (pty-ws) is worth it.\n * The Terminal cell is ALWAYS feasible when the backend advertises a transport at\n * all (`sse-events` on a cold box, `pty-ws` once warm) — only a genuinely\n * terminal-less backend reports transport:null with a hard reason. The attach is\n * what flips `sse-events` → `pty-ws` by warming the box and minting the ttyd\n * tunnel URL, so we attach whenever the terminal is not hard-unavailable.\n */\nfunction terminalAttachable(cell: SessionCapabilities[\"Terminal\"]): boolean {\n if (cell.transport === null) {\n // No terminal at all unless the only blocker is a transient cold state.\n return cell.reason === \"lease_cold\" || cell.reason === \"not_provisioned\" || cell.reason === null;\n }\n // Already pty-ws (warm) is fine to (re)attach; sse-events is the cold state the\n // attach upgrades. Either way it's attachable.\n return true;\n}\n\n/** Read `stream.url.rotated` payloads off the live event log, newest last. */\nfunction rotationsFrom(events: SessionEvent[]): StreamUrlRotatedPayload[] {\n const out: StreamUrlRotatedPayload[] = [];\n for (const event of events) {\n if (event.type === \"stream.url.rotated\" && event.payload && typeof event.payload === \"object\") {\n out.push(event.payload as StreamUrlRotatedPayload);\n }\n }\n return out;\n}\n\n/**\n * The capability-negotiation hook. Discovers what THIS session+backend+OS\n * supports (FileSystem/Terminal/Git always-ish; DesktopStream/Recording\n * sometimes), drives capability-gated rendering, and — when `attachDesktop` —\n * holds a viewer lease + heartbeats it so the box stays warm while watched.\n *\n * Degradation is a value, never a crash: an unsupported surface comes back\n * `available:false`/`transport:null` + a `reason`; the components render the\n * reason-aware empty state. 409 (consent) and 429 (viewer cap) are surfaced as\n * typed signals, not thrown.\n */\nexport function useSessionCapabilities(\n sessionId: string | null | undefined,\n options: UseSessionCapabilitiesOptions = {},\n): UseSessionCapabilitiesResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const attachDesktop = options.attachDesktop ?? false;\n const attachTerminal = options.attachTerminal ?? false;\n const attachFiles = options.attachFiles ?? false;\n const warmingPollMs = options.warmingPollMs ?? 1500;\n const warmingDeadlineMs = options.warmingDeadlineMs ?? 30_000;\n\n const [capabilities, setCapabilities] = useState<SessionCapabilities | null>(null);\n const [state, setState] = useState<SessionCapabilitiesState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [acknowledgmentRequired, setAcknowledgmentRequired] = useState<\"unredacted\" | \"shared\" | null>(null);\n const [viewerCapReached, setViewerCapReached] = useState(false);\n const [viewerId, setViewerId] = useState<string | null>(null);\n // Bumped to force a fresh negotiation cycle.\n const [nonce, setNonce] = useState(0);\n\n // The epoch the client has settled on — used to fence stale rotations folded\n // from the event log, and echoed on heartbeats.\n const epochRef = useRef(0);\n const viewerIdRef = useRef<string | null>(null);\n\n const renegotiate = useCallback(() => {\n setNonce((n) => n + 1);\n }, []);\n\n // ── Negotiation + viewer lifecycle ──────────────────────────────────────────\n useEffect(() => {\n if (!enabled || !sessionId) {\n setState(\"idle\");\n setCapabilities(null);\n return;\n }\n let cancelled = false;\n let pollTimer: ReturnType<typeof setTimeout> | null = null;\n let heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n let localViewerId: string | null = null;\n const startedAt = Date.now();\n\n const clearTimers = () => {\n if (pollTimer !== null) clearTimeout(pollTimer);\n if (heartbeatTimer !== null) clearInterval(heartbeatTimer);\n pollTimer = null;\n heartbeatTimer = null;\n };\n\n const settle = (caps: SessionCapabilities) => {\n if (cancelled) return;\n epochRef.current = caps.leaseEpoch;\n setCapabilities(caps);\n setError(null);\n };\n\n const startHeartbeat = (caps: SessionCapabilities) => {\n if (!localViewerId || heartbeatTimer !== null) return;\n const intervalMs = caps.viewerHeartbeatIntervalMs > 0 ? caps.viewerHeartbeatIntervalMs : 30_000;\n heartbeatTimer = setInterval(() => {\n if (cancelled || !localViewerId) return;\n void client\n .heartbeatViewer(workspaceId, sessionId, localViewerId, { leaseEpoch: epochRef.current })\n .then((res) => {\n // alive:false ⇒ the holder was reaped or the epoch moved under us;\n // re-negotiate to re-acquire against the new owner.\n if (!res.alive && !cancelled) {\n renegotiate();\n }\n })\n .catch((cause) => {\n if (cancelled) return;\n if (cause instanceof OpenGeniApiError && (cause.status === 409 || cause.status === 410)) {\n renegotiate();\n }\n });\n }, intervalMs);\n };\n\n const pollUntilWarm = () => {\n pollTimer = setTimeout(() => {\n if (cancelled) return;\n void client\n .getStreamCapabilities(workspaceId, sessionId)\n .then((caps) => {\n if (cancelled) return;\n settle(caps);\n if (caps.liveness === \"warm\" || caps.liveness === \"draining\") {\n setState(\"ready\");\n return;\n }\n if (warmingDeadlineMs > 0 && Date.now() - startedAt > warmingDeadlineMs) {\n setState(\"error\");\n setError(new Error(\"sandbox did not warm in time — retry to re-negotiate\"));\n return;\n }\n pollUntilWarm();\n })\n .catch((cause) => {\n if (!cancelled) {\n setState(\"error\");\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n });\n }, warmingPollMs);\n };\n\n void (async () => {\n setState(\"negotiating\");\n setAcknowledgmentRequired(null);\n setViewerCapReached(false);\n try {\n const caps = await client.getStreamCapabilities(workspaceId, sessionId);\n if (cancelled) return;\n settle(caps);\n\n // Optional viewer attach: acquire a viewer holder (warms a cold box). ONE\n // attach serves BOTH live planes — the desktop pixel stream AND the\n // interactive terminal (ttyd pty-ws) ride the same warm box and the same\n // holder; the response folds the minted address for each requested plane.\n // The consent gate (409) and the viewer cap (429) surface as typed signals\n // rather than throwing — the tabs degrade gracefully.\n //\n // KEY: the handshake (getStreamCapabilities) NEVER spins up a cold box, so\n // on a cold/warming lease the desktop cell comes back transport:null and\n // the terminal cell comes back `sse-events` (read-only firehose) with a\n // transient reason (`lease_cold`/`not_provisioned`). Gating the attach on\n // `transport` therefore dead-ends both surfaces (forever \"Starting…\"): they\n // never warm because they never attach, and never attach because they\n // aren't warm. We attach whenever a REQUESTED plane is FEASIBLE — transport\n // already live OR cold-but-feasible — and let POST /viewers warm the box and\n // mint the URLs. Only a genuinely-unsupported reason suppresses the attach.\n const wantDesktopAttach = attachDesktop && desktopAttachable(caps.DesktopStream);\n const wantTerminalAttach = attachTerminal && terminalAttachable(caps.Terminal);\n // The Files surface warms the box for fast Channel-A ops. It folds no live\n // URL (files are stateless HTTP) — the attach is purely a liveness refcount,\n // so it's wanted whenever the FileSystem capability is advertised at all.\n const wantFilesAttach = attachFiles && caps.FileSystem.available;\n if (wantDesktopAttach || wantTerminalAttach || wantFilesAttach) {\n try {\n // Declare WHICH plane we're attaching for. `desktop:true` opts into the\n // un-redacted pixel plane (which carries the consent gate); a\n // terminal-only attach (`desktop:false`) warms the box + mints the\n // pty-ws terminal cell WITHOUT tripping the desktop consent 409.\n const holder = await client.attachViewer(workspaceId, sessionId, { desktop: wantDesktopAttach });\n if (cancelled) return;\n localViewerId = holder.viewerId;\n viewerIdRef.current = holder.viewerId;\n setViewerId(holder.viewerId);\n epochRef.current = holder.leaseEpoch;\n // Fold the freshly-minted live address(es) into the doc the components\n // read. Desktop fields fold only when a desktop attach was wanted;\n // terminal fields fold the minted ttyd pty-ws url+token when present.\n setCapabilities((prev) =>\n prev\n ? {\n ...prev,\n liveness: holder.liveness,\n leaseEpoch: holder.leaseEpoch,\n viewerHeartbeatIntervalMs: holder.viewerHeartbeatIntervalMs,\n DesktopStream: wantDesktopAttach\n ? {\n ...prev.DesktopStream,\n transport: holder.transport ?? prev.DesktopStream.transport,\n client: holder.client ?? prev.DesktopStream.client,\n url: holder.dataPlaneUrl ?? prev.DesktopStream.url,\n token: holder.streamToken ?? prev.DesktopStream.token,\n expiresAt: holder.streamExpiresAt ?? prev.DesktopStream.expiresAt,\n resolution: holder.resolution ?? prev.DesktopStream.resolution,\n }\n : prev.DesktopStream,\n Terminal:\n holder.terminalUrl && holder.terminalTransport\n ? {\n ...prev.Terminal,\n transport: holder.terminalTransport,\n url: holder.terminalUrl,\n token: holder.terminalToken ?? prev.Terminal.token,\n // A live pty-ws means the box is pty-capable for real.\n ptyCapable: true,\n reason: null,\n }\n : prev.Terminal,\n }\n : prev,\n );\n } catch (cause) {\n if (cancelled) return;\n if (cause instanceof OpenGeniApiError) {\n if (cause.status === 409) {\n // The un-redacted/shared consent gate is a DESKTOP requirement. A\n // terminal-only warm attach needs no consent, so a 409 there is not\n // a consent prompt — the terminal just stays on the read-only\n // firehose. Only raise the consent requirement when the desktop was\n // the (or a) reason we attached.\n if (wantDesktopAttach) {\n setAcknowledgmentRequired(\n cause.message.includes(\"shared_acknowledgment\") ? \"shared\" : \"unredacted\",\n );\n }\n } else if (cause.status === 429) {\n setViewerCapReached(true);\n } else if (cause.status === 403) {\n setState(\"error\");\n setError(cause);\n return;\n }\n // 409/429 are recoverable: structured surfaces still negotiated;\n // keep going to set ready/cold below.\n } else {\n throw cause;\n }\n }\n }\n\n if (caps.liveness === \"warm\" || caps.liveness === \"draining\" || localViewerId) {\n setState(\"ready\");\n startHeartbeat(caps);\n } else {\n setState(\"cold\");\n pollUntilWarm();\n }\n } catch (cause) {\n if (cancelled) return;\n if (cause instanceof OpenGeniApiError && cause.status === 403) {\n setState(\"error\");\n setError(new Error(\"not permitted to view this session's sandbox\"));\n return;\n }\n setState(\"error\");\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n })();\n\n return () => {\n cancelled = true;\n clearTimers();\n // Fire-and-forget detach (idempotent delete-my-row). Capture the id so a\n // re-render/unmount race still releases the right holder.\n const releaseId = localViewerId ?? viewerIdRef.current;\n if (releaseId) {\n void client.detachViewer(workspaceId, sessionId, releaseId).catch(() => {});\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, workspaceId, sessionId, enabled, attachDesktop, attachTerminal, attachFiles, warmingPollMs, warmingDeadlineMs, nonce]);\n\n // ── Fold stream.url.rotated from the live event log (no round trip) ──────────\n const events = options.events;\n useEffect(() => {\n if (!events || events.length === 0) return;\n setCapabilities((prev) => {\n if (!prev || !prev.DesktopStream.url) return prev;\n let next = prev.DesktopStream;\n let changed = false;\n for (const rotation of rotationsFrom(events)) {\n // Only this viewer's rotations (others' are filtered by viewerId when set).\n if (rotation.viewerId && viewerIdRef.current && rotation.viewerId !== viewerIdRef.current) {\n continue;\n }\n const applied = applyUrlRotation(next, rotation, epochRef.current);\n if (applied) {\n next = { ...next, url: applied.url, token: applied.token, expiresAt: applied.expiresAt };\n epochRef.current = Math.max(epochRef.current, rotation.leaseEpoch);\n changed = true;\n }\n }\n return changed ? { ...prev, DesktopStream: next, leaseEpoch: epochRef.current } : prev;\n });\n }, [events]);\n\n return {\n capabilities,\n state,\n error,\n acknowledgmentRequired,\n viewerCapReached,\n viewerId,\n renegotiate,\n };\n}\n","import {\n desktopSocketUrl,\n nextDesktopState,\n type DesktopConnectionState,\n type DesktopRfbFactory,\n type DesktopRfbLike,\n type DesktopStreamCapability,\n} from \"@opengeni/sdk\";\nimport { type RefObject, useEffect, useRef, useState } from \"react\";\nimport { type DesktopWebSocketFactory, useRelayFrameStream } from \"./use-relay-frame-stream\";\n\nexport type UseDesktopStreamOptions = {\n /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */\n capability: DesktopStreamCapability | null;\n /** The mount target. RFB (or the frame canvas) attaches here on connect. */\n containerRef: RefObject<HTMLDivElement | null>;\n /** Read-only by default (v1 ruling H). interactive only when cap.mode allows. */\n interactive?: boolean | undefined;\n scaleViewport?: boolean | undefined;\n /** Custom RFB factory (tests / a WebRTC swap). Defaults to a lazy @novnc/novnc. */\n rfbFactory?: DesktopRfbFactory | undefined;\n /** Custom socket factory for the `relay-frames` transport (tests). Defaults to\n * `new WebSocket(url)`. Mirrors `rfbFactory` for the frame renderer. */\n webSocketFactory?: DesktopWebSocketFactory | undefined;\n};\n\nexport type UseDesktopStreamResult = {\n state: DesktopConnectionState;\n error: Error | null;\n /** Manual reconnect (e.g. after a securityfailure once a fresh URL arrives). */\n reconnect: () => void;\n};\n\n/** Lazy-load @novnc/novnc's RFB as the default factory. Imported inside the\n * connect effect so SSR / non-desktop bundles never pull the DOM-only lib.\n * @novnc/novnc ships no types and a single `export default class RFB`. The\n * specifier is STATIC (`import(\"@novnc/novnc\")`) so Vite can pre-bundle and\n * resolve it — a runtime-string indirection with `@vite-ignore` (the previous\n * approach) hands the browser a bare specifier and throws\n * \"Failed to resolve module specifier '@novnc/novnc'\". The dynamic form keeps\n * it out of the SSR / non-desktop critical path while staying resolvable. */\nasync function defaultRfbFactory(): Promise<DesktopRfbFactory> {\n const mod = (await import(\"@novnc/novnc\")) as unknown as {\n default: new (\n t: HTMLElement,\n u: string,\n o: { credentials?: { password?: string | undefined } | undefined },\n ) => DesktopRfbLike;\n };\n const RFB = mod.default;\n return (target, url, opts) => new RFB(target, url, opts);\n}\n\n/**\n * Drive the noVNC RFB lifecycle from a `DesktopStreamCapability`, using the\n * SDK's `desktop.ts` reducer + `desktopSocketUrl`. SSR-safe: the RFB import and\n * the DOM attach happen inside `useEffect`, so a server render is a no-op and\n * the component shows its placeholder until hydration.\n *\n * Read-only is enforced at three layers: `capability.mode` (server) →\n * `interactive` prop → `RFB.viewOnly`. v1 always resolves to read-only. On a\n * capability `url` change (a rotation), the old RFB disconnects and a fresh one\n * connects to the new URL — a brief \"desktop blink\", acceptable on rollover.\n *\n * Transport dispatch: a Modal box negotiates `transport: \"vnc-ws\"` and drives the\n * noVNC RFB below. A SELF-HOSTED machine negotiates `transport: \"relay-frames\"`\n * (PNG-per-frame over the relay, view-only) — that path is delegated to\n * `useRelayFrameStream`, which paints a `<canvas>`. Both hooks are ALWAYS called\n * (rules of hooks); each is dormant for the other's transport, and we return the\n * result of whichever owns the surface. The public interface is identical either\n * way, so `DesktopViewer` is transport-agnostic.\n */\nexport function useDesktopStream(options: UseDesktopStreamOptions): UseDesktopStreamResult {\n const { capability, containerRef, interactive, scaleViewport, rfbFactory, webSocketFactory } =\n options;\n\n // The self-hosted PNG-frame path. Always invoked (rules of hooks); dormant\n // unless `transport === \"relay-frames\"`, in which case it owns the surface.\n const frameStream = useRelayFrameStream({\n capability,\n containerRef,\n ...(webSocketFactory ? { webSocketFactory } : {}),\n });\n const [state, setState] = useState<DesktopConnectionState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [nonce, setNonce] = useState(0);\n const stateRef = useRef<DesktopConnectionState>(\"idle\");\n const setBoth = (next: DesktopConnectionState) => {\n stateRef.current = next;\n setState(next);\n };\n\n const reconnect = () => setNonce((n) => n + 1);\n\n const url = capability?.url ?? null;\n // The credential is keyed into the connect effect so a token rotation (new\n // password) reconnects, but NOT folded into the whole-`capability` identity —\n // a benign re-negotiation that re-mints the same cell must not churn the socket.\n const token = capability?.token ?? null;\n const transport = capability?.transport ?? null;\n const mode = capability?.mode ?? \"read-only\";\n\n // The live RFB handle. Holding it in a ref lets us flip view-only (take\n // control / return control) and re-scale on the OPEN connection instead of\n // tearing the socket down — the old behaviour reconnected on every\n // `interactive` change, which read as a constant \"refresh\" and (combined with\n // the canvas churn) bounced control back to watch.\n const rfbRef = useRef<DesktopRfbLike | null>(null);\n // Latest input/scale/factory the connect effect reads via refs so they are NOT\n // connect-effect dependencies: changing them must update the live RFB in place,\n // never reconnect it.\n const interactiveRef = useRef(interactive);\n const scaleViewportRef = useRef(scaleViewport);\n const modeRef = useRef(mode);\n const rfbFactoryRef = useRef(rfbFactory);\n interactiveRef.current = interactive;\n scaleViewportRef.current = scaleViewport;\n modeRef.current = mode;\n rfbFactoryRef.current = rfbFactory;\n\n // read-only is forced when the server says so OR the caller didn't opt in.\n const viewOnlyFor = (m: string, want: boolean | undefined) => m === \"read-only\" || !want;\n\n useEffect(() => {\n // SSR / no DOM / no usable transport: stay idle and show the placeholder.\n if (typeof window === \"undefined\") return;\n if (transport !== \"vnc-ws\" || !url) {\n setBoth(\"idle\");\n return;\n }\n const container = containerRef.current;\n if (!container) {\n // The mount target isn't in the DOM yet (e.g. the tab is still hidden).\n // Stay idle (not a stale negotiating/connecting) so a re-attach nudge —\n // fired by the viewer on becoming visible / on mount — can re-run this\n // effect once the container exists. Without this the surface can stick\n // forever on the idle scrim and never open a socket.\n setBoth(\"idle\");\n return;\n }\n\n let rfb: DesktopRfbLike | null = null;\n let disposed = false;\n setError(null);\n setBoth(\"negotiating\");\n\n const onConnect = () => {\n if (!disposed) setBoth(nextDesktopState(stateRef.current, { type: \"connected\" }));\n };\n const onDisconnect = () => {\n if (!disposed) setBoth(nextDesktopState(stateRef.current, { type: \"disconnected\" }));\n };\n const onSecurityFailure = () => {\n if (disposed) return;\n setError(new Error(\"desktop authentication failed (token expired or revoked)\"));\n setBoth(nextDesktopState(stateRef.current, { type: \"fail\" }));\n };\n\n void (async () => {\n try {\n const factory = rfbFactoryRef.current ?? (await defaultRfbFactory());\n if (disposed) return;\n const socketUrl = desktopSocketUrl({ url });\n setBoth(nextDesktopState(stateRef.current, { type: \"negotiated\" }));\n rfb = factory(container, socketUrl, {\n credentials: token ? { password: token } : undefined,\n });\n rfb.viewOnly = viewOnlyFor(modeRef.current, interactiveRef.current);\n // Fit-to-panel: SCALE the 1280x800 framebuffer down to the container\n // (aspect-preserved) and never 1:1-clip. `clipViewport=false` is pinned\n // explicitly — noVNC forces it off while scaling, but a fresh RFB on a\n // url rotation could otherwise start from a stale clip and read as\n // \"zoomed in\". Order matters: clip off, then scale on.\n rfb.clipViewport = false;\n rfb.scaleViewport = scaleViewportRef.current ?? true;\n rfb.addEventListener(\"connect\", onConnect);\n rfb.addEventListener(\"disconnect\", onDisconnect);\n rfb.addEventListener(\"securityfailure\", onSecurityFailure);\n rfbRef.current = rfb;\n } catch (cause) {\n if (!disposed) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setBoth(\"error\");\n }\n }\n })();\n\n return () => {\n disposed = true;\n if (rfbRef.current === rfb) rfbRef.current = null;\n if (rfb) {\n rfb.removeEventListener?.(\"connect\", onConnect);\n rfb.removeEventListener?.(\"disconnect\", onDisconnect);\n rfb.removeEventListener?.(\"securityfailure\", onSecurityFailure);\n try {\n rfb.disconnect();\n } catch {\n // ignore teardown errors\n }\n }\n };\n // ONLY a real transport change reconnects: a fresh url (rotation), a new\n // credential, the transport flipping, or an explicit manual reconnect\n // (`nonce`). `interactive`/`scaleViewport`/`mode`/`rfbFactory` are read via\n // refs and applied live below — they must never re-open the socket.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, token, transport, nonce]);\n\n // Apply take-control / return-control to the OPEN connection in place. noVNC\n // honours `viewOnly` live, so flipping it neither blinks the surface nor drops\n // the framebuffer — the cure for the take-control \"refresh + auto-release\" loop.\n useEffect(() => {\n const rfb = rfbRef.current;\n if (rfb) rfb.viewOnly = viewOnlyFor(mode, interactive);\n // viewOnlyFor is pure; re-run only when the inputs change.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [interactive, mode, state]);\n\n // Re-scale the live RFB in place (no reconnect) when the scale preference flips\n // OR the connection state advances (e.g. the first framebuffer paints after a\n // take-control flip / a re-attach). Re-asserting clip-off + scale-on here is the\n // belt-and-suspenders against a \"zoomed\" surface: it re-fits the canvas to the\n // panel on every meaningful transition, so a transient mis-measure at connect\n // time can never stick.\n useEffect(() => {\n const rfb = rfbRef.current;\n if (rfb) {\n rfb.clipViewport = false;\n rfb.scaleViewport = scaleViewport ?? true;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scaleViewport, state]);\n\n // Delegate to whichever transport owns the surface. For `relay-frames` the\n // noVNC effect above is dormant (it bailed to idle) and the frame renderer\n // drives; for `vnc-ws` (and everything else) the noVNC path drives while the\n // frame renderer stays idle. Same public shape either way.\n if (transport === \"relay-frames\") return frameStream;\n return { state, error, reconnect };\n}\n","// Minimal HAND-MIRROR of the relay stream wire messages the desktop frame client\n// needs (`StreamOpen` encode; `StreamOpenAck` + `StreamFrame` decode). It exists\n// because the publish-closure guard (scripts/publish-closure-guard.ts) forbids\n// `@opengeni/react` from depending on `@opengeni/agent-proto` — the published SDK\n// closure may only reach `@opengeni/sdk` among `@opengeni/*` packages. So, exactly\n// as the guard prescribes (\"hand-mirror it\"), we re-encode just these three\n// messages against the third-party `@bufbuild/protobuf/wire` runtime (the same\n// runtime `@opengeni/agent-proto` generates against), byte-compatible with the\n// generated code. Field numbers copied verbatim from\n// `packages/agent-proto/src/gen/opengeni_agent.ts`:\n// StreamChannel: channelId=1, workspaceId=2, agentId=3, kind=4(int32), port=5(uint32)\n// StreamOpen: channel=1(msg), token=2, role=3(int32), resumeFromSeq=4(uint64, omitted when \"0\")\n// StreamOpenAck: accepted=1(bool), error=2(AgentError msg), resumeFromSeq=3\n// AgentError: code=1, message=2, retryable=3, detail=4 (we read only message)\n// StreamFrame: channelId=1, seq=2, data=3(bytes), producedAtMs=4 (we read only data)\nimport { BinaryReader, BinaryWriter } from \"@bufbuild/protobuf/wire\";\n\n/** `StreamKind.STREAM_KIND_DESKTOP` (agent-proto enum value). */\nexport const STREAM_KIND_DESKTOP = 2;\n/** `StreamRole.STREAM_ROLE_CLIENT` (agent-proto enum value). */\nexport const STREAM_ROLE_CLIENT = 2;\n\nexport interface RelayChannel {\n channelId: string;\n workspaceId: string;\n agentId: string;\n kind: number;\n port: number;\n}\n\nexport interface RelayStreamOpen {\n channel: RelayChannel;\n token: string;\n role: number;\n resumeFromSeq: string;\n}\n\nfunction encodeChannel(message: RelayChannel, writer: BinaryWriter): BinaryWriter {\n if (message.channelId !== \"\") writer.uint32(10).string(message.channelId);\n if (message.workspaceId !== \"\") writer.uint32(18).string(message.workspaceId);\n if (message.agentId !== \"\") writer.uint32(26).string(message.agentId);\n if (message.kind !== 0) writer.uint32(32).int32(message.kind);\n if (message.port !== 0) writer.uint32(40).uint32(message.port);\n return writer;\n}\n\n/** Encode a `StreamOpen`, byte-compatible with `StreamOpen.encode(...).finish()`. */\nexport function encodeStreamOpen(message: RelayStreamOpen): Uint8Array {\n const writer = new BinaryWriter();\n encodeChannel(message.channel, writer.uint32(10).fork()).join();\n if (message.token !== \"\") writer.uint32(18).string(message.token);\n if (message.role !== 0) writer.uint32(24).int32(message.role);\n if (message.resumeFromSeq !== \"0\") writer.uint32(32).uint64(message.resumeFromSeq);\n return writer.finish();\n}\n\n/** The only `AgentError` field we surface from a rejected ack. */\nfunction decodeAgentErrorMessage(reader: BinaryReader, length: number): { message?: string } {\n const end = reader.pos + length;\n let message: string | undefined;\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 2 && tag === 18) {\n message = reader.string();\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return message !== undefined ? { message } : {};\n}\n\n/** Decode a `StreamOpenAck` (we need `accepted` + the error message). */\nexport function decodeStreamOpenAck(bytes: Uint8Array): {\n accepted: boolean;\n error?: { message?: string };\n} {\n const reader = new BinaryReader(bytes);\n const end = reader.len;\n let accepted = false;\n let error: { message?: string } | undefined;\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 1 && tag === 8) {\n accepted = reader.bool();\n continue;\n }\n if (tag >>> 3 === 2 && tag === 18) {\n error = decodeAgentErrorMessage(reader, reader.uint32());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return error !== undefined ? { accepted, error } : { accepted };\n}\n\n/** Decode a `StreamFrame`, extracting only the `data` (framebuffer PNG) bytes. */\nexport function decodeStreamFrame(bytes: Uint8Array): { data: Uint8Array } {\n const reader = new BinaryReader(bytes);\n const end = reader.len;\n let data = new Uint8Array(0);\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 3 && tag === 26) {\n // Copy into a fresh ArrayBuffer-backed view: BinaryReader.bytes() returns\n // `Uint8Array<ArrayBufferLike>` (a view into the message buffer), which both\n // narrows the type to `Uint8Array<ArrayBuffer>` and isolates just this frame.\n data = new Uint8Array(reader.bytes());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return { data };\n}\n","import {\n decodeStreamFrame,\n decodeStreamOpenAck,\n encodeStreamOpen,\n STREAM_KIND_DESKTOP,\n STREAM_ROLE_CLIENT,\n} from \"../lib/relay-wire\";\nimport type { DesktopConnectionState, DesktopStreamCapability } from \"@opengeni/sdk\";\nimport { type RefObject, useEffect, useRef, useState } from \"react\";\n\n/**\n * The minimal WebSocket surface the frame renderer drives. Lets tests (and a\n * future transport swap) inject a fake without a live socket — the exact\n * analogue of `DesktopRfbFactory` for the noVNC path. Structurally a subset of\n * the browser `WebSocket`.\n */\nexport interface DesktopWebSocketLike {\n binaryType: string;\n send(data: ArrayBuffer): void;\n close(): void;\n addEventListener(\n type: \"open\" | \"message\" | \"error\" | \"close\",\n listener: (ev: { data?: unknown } & Record<string, unknown>) => void,\n ): void;\n removeEventListener(\n type: \"open\" | \"message\" | \"error\" | \"close\",\n listener: (ev: { data?: unknown } & Record<string, unknown>) => void,\n ): void;\n}\n\nexport type DesktopWebSocketFactory = (url: string) => DesktopWebSocketLike;\n\nexport type UseRelayFrameStreamOptions = {\n /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */\n capability: DesktopStreamCapability | null;\n /** The mount target. A `<canvas>` is appended here on connect. */\n containerRef: RefObject<HTMLDivElement | null>;\n /** Custom socket factory (tests / a transport swap). Defaults to `new WebSocket(url)`. */\n webSocketFactory?: DesktopWebSocketFactory | undefined;\n};\n\nexport type UseRelayFrameStreamResult = {\n state: DesktopConnectionState;\n error: Error | null;\n /** Tear down + reopen the socket (e.g. after a drop, once a fresh url arrives). */\n reconnect: () => void;\n};\n\n// Relay datagram tags: byte[0] of every binary message. Mirrors the proven wire\n// protocol in `apps/api/scripts/diagnose-mac-desktop-stream.ts`.\nconst TAG_OPEN = 1;\nconst TAG_OPENACK = 2;\nconst TAG_FRAME = 3;\n\n/** Build a relay datagram: a fresh Uint8Array of `body.length + 1` with the tag\n * at [0] and the protobuf body copied at offset 1 (so `.buffer` is exact). */\nfunction datagram(tag: number, body: Uint8Array): Uint8Array {\n const out = new Uint8Array(body.length + 1);\n out[0] = tag;\n out.set(body, 1);\n return out;\n}\n\nfunction defaultWebSocketFactory(url: string): DesktopWebSocketLike {\n // The browser `WebSocket` is structurally a superset of `DesktopWebSocketLike`\n // (its event maps are stricter); cast so the seam stays loosely typed for fakes.\n return new WebSocket(url) as unknown as DesktopWebSocketLike;\n}\n\n/**\n * VIEW-ONLY PNG-frame renderer for a SELF-HOSTED desktop stream — the relay\n * transport (`transport: \"relay-frames\"`, `client: \"frames\"`). The self-hosted\n * agent produces one PNG per frame as a protobuf datagram over the relay; there\n * is no RFB/noVNC here. This hook opens the relay DESKTOP channel as a CLIENT\n * (mirroring the proven diagnostic wire protocol), decodes each PNG onto a\n * `<canvas>` mounted into `containerRef`, and drives the connection state\n * machine: idle → connecting (ws opening) → connected (first painted frame) →\n * error (ws error/close/ack rejection).\n *\n * It is DORMANT for any other transport (or no url): it stays idle and touches\n * nothing, so the noVNC path owns the surface. SSR-safe: the socket + DOM attach\n * live inside `useEffect`.\n *\n * Backpressure (critical — frames are ~1.8MB at ~10fps): at most one frame is\n * decoded at a time; a frame arriving mid-decode replaces the pending one\n * (latest-wins), so a slow decode can never build an unbounded queue.\n */\nexport function useRelayFrameStream(options: UseRelayFrameStreamOptions): UseRelayFrameStreamResult {\n const { capability, containerRef, webSocketFactory } = options;\n const [state, setState] = useState<DesktopConnectionState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [nonce, setNonce] = useState(0);\n const stateRef = useRef<DesktopConnectionState>(\"idle\");\n const setBoth = (next: DesktopConnectionState) => {\n stateRef.current = next;\n setState(next);\n };\n\n const reconnect = () => setNonce((n) => n + 1);\n\n const transport = capability?.transport ?? null;\n const url = capability?.url ?? null;\n const token = capability?.token ?? null;\n\n // The factory is read via a ref so swapping it never re-opens the socket (it is\n // not a connect-effect dependency), symmetric with the noVNC `rfbFactory`.\n const factoryRef = useRef(webSocketFactory);\n factoryRef.current = webSocketFactory;\n\n useEffect(() => {\n // SSR / no DOM: stay idle and show the placeholder.\n if (typeof window === \"undefined\") return;\n // This hook OWNS the surface ONLY for the frame transport; anything else (or\n // no live url) → dormant idle so the noVNC path can drive.\n if (transport !== \"relay-frames\" || !url) {\n setBoth(\"idle\");\n return;\n }\n const container = containerRef.current;\n if (!container) {\n // Mount target not in the DOM yet (tab hidden) — stay idle so a re-attach\n // nudge can re-run this effect once the container exists.\n setBoth(\"idle\");\n return;\n }\n\n // Parse the 4 relay query params the channel is keyed on.\n let channel: {\n channelId: string;\n workspaceId: string;\n agentId: string;\n kind: number;\n port: number;\n };\n try {\n const u = new URL(url);\n channel = {\n channelId: u.searchParams.get(\"channel\") ?? \"\",\n workspaceId: u.searchParams.get(\"ws\") ?? \"\",\n agentId: u.searchParams.get(\"agent\") ?? \"\",\n kind: STREAM_KIND_DESKTOP,\n port: Number(u.searchParams.get(\"port\") ?? \"0\"),\n };\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setBoth(\"error\");\n return;\n }\n\n setError(null);\n setBoth(\"connecting\");\n\n // Canvas mount — mirror the noVNC surface conventions: absolute-fill the\n // panel and CONTAIN the framebuffer (aspect-preserved, centered, letterboxed)\n // — never distorted, never overflowing. `max-*: 100%` + `margin: auto` +\n // intrinsic size gives fit-to-panel without a resize observer.\n const canvas = document.createElement(\"canvas\");\n canvas.setAttribute(\"data-opengeni-desktop-frames\", \"\");\n const style = canvas.style;\n style.position = \"absolute\";\n style.top = \"0\";\n style.left = \"0\";\n style.right = \"0\";\n style.bottom = \"0\";\n style.margin = \"auto\";\n style.maxWidth = \"100%\";\n style.maxHeight = \"100%\";\n style.width = \"auto\";\n style.height = \"auto\";\n style.display = \"block\";\n style.imageRendering = \"auto\";\n container.appendChild(canvas);\n const ctx = canvas.getContext(\"2d\");\n\n let disposed = false;\n let acked = false;\n // Backpressure: decode at most ONE frame at a time; a frame arriving mid-\n // decode replaces `pending` (keep only the LATEST) — never a queue.\n let decoding = false;\n let pending: Uint8Array | null = null;\n\n const drainLatest = async () => {\n if (decoding) return;\n decoding = true;\n try {\n while (!disposed && pending) {\n const data = pending;\n pending = null;\n let bmp: ImageBitmap;\n try {\n // Copy the exact frame bytes into a fresh ArrayBuffer-backed view:\n // ts-proto's `bytes()` hands back a subarray VIEW into the larger\n // message buffer, so slicing isolates just this PNG (and satisfies the\n // `BlobPart` typing, which rejects the generic `ArrayBufferLike`).\n bmp = await createImageBitmap(new Blob([new Uint8Array(data)], { type: \"image/png\" }));\n } catch {\n // A corrupt/partial frame is skipped; latest-wins keeps us live.\n continue;\n }\n if (disposed) {\n bmp.close();\n break;\n }\n // Size the backing store to the frame's natural WxH on the first frame\n // (or when the resolution changes); CSS then scales the element to fit.\n if (canvas.width !== bmp.width || canvas.height !== bmp.height) {\n canvas.width = bmp.width;\n canvas.height = bmp.height;\n }\n ctx?.drawImage(bmp, 0, 0, canvas.width, canvas.height);\n bmp.close();\n // First painted frame → connected.\n if (!disposed && stateRef.current !== \"connected\") setBoth(\"connected\");\n }\n } finally {\n decoding = false;\n }\n };\n\n let ws: DesktopWebSocketLike;\n try {\n ws = (factoryRef.current ?? defaultWebSocketFactory)(url);\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setBoth(\"error\");\n canvas.remove();\n return;\n }\n ws.binaryType = \"arraybuffer\";\n\n const onOpen = () => {\n if (disposed) return;\n const body = encodeStreamOpen({\n channel,\n token: token ?? \"\",\n role: STREAM_ROLE_CLIENT,\n resumeFromSeq: \"0\",\n });\n try {\n ws.send(datagram(TAG_OPEN, body).buffer as ArrayBuffer);\n } catch {\n // Socket already closing; the close/error handler surfaces it.\n }\n };\n\n const onMessage = (ev: { data?: unknown }) => {\n if (disposed) return;\n const data = ev.data;\n if (!(data instanceof ArrayBuffer)) return;\n const buf = new Uint8Array(data);\n if (buf.length === 0) return;\n const tag = buf[0];\n const rest = buf.subarray(1);\n if (tag === TAG_OPENACK) {\n let ack: ReturnType<typeof decodeStreamOpenAck>;\n try {\n ack = decodeStreamOpenAck(rest);\n } catch {\n return;\n }\n if (!ack.accepted) {\n setError(\n new Error(\n ack.error?.message\n ? `desktop stream rejected: ${ack.error.message}`\n : \"desktop stream rejected by the relay\",\n ),\n );\n setBoth(\"error\");\n try {\n ws.close();\n } catch {\n // already closed\n }\n return;\n }\n // Accepted — stay \"connecting\" until the first frame paints.\n acked = true;\n } else if (tag === TAG_FRAME) {\n let fr: ReturnType<typeof decodeStreamFrame>;\n try {\n fr = decodeStreamFrame(rest);\n } catch {\n return;\n }\n if (fr.data && fr.data.length > 0) {\n pending = fr.data; // latest-wins backpressure\n void drainLatest();\n }\n }\n };\n\n const onError = () => {\n if (disposed) return;\n setError((prev) => prev ?? new Error(\"desktop stream connection error\"));\n setBoth(\"error\");\n };\n\n const onClose = () => {\n if (disposed) return;\n setError(\n (prev) =>\n prev ??\n new Error(acked ? \"desktop stream closed\" : \"desktop stream closed before it opened\"),\n );\n setBoth(\"error\");\n };\n\n ws.addEventListener(\"open\", onOpen);\n ws.addEventListener(\"message\", onMessage);\n ws.addEventListener(\"error\", onError);\n ws.addEventListener(\"close\", onClose);\n\n return () => {\n disposed = true;\n pending = null;\n ws.removeEventListener(\"open\", onOpen);\n ws.removeEventListener(\"message\", onMessage);\n ws.removeEventListener(\"error\", onError);\n ws.removeEventListener(\"close\", onClose);\n try {\n ws.close();\n } catch {\n // ignore teardown errors\n }\n canvas.remove();\n };\n // ONLY a real transport change reopens: a fresh url (rotation), a new token,\n // the transport flipping, or a manual reconnect (`nonce`). The factory is read\n // via a ref and must never re-open the socket.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, token, transport, nonce]);\n\n return { state, error, reconnect };\n}\n","import {\n TTYD_SUBPROTOCOL,\n TerminalCapability,\n terminalSocketUrl,\n ttydAuthFrame,\n ttydInputFrame,\n ttydResizeFrame,\n TtydServerCommand,\n} from \"@opengeni/sdk\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\n/** The ttyd connection lifecycle as surfaced to the component. */\nexport type TerminalStreamStatus = \"connecting\" | \"open\" | \"closed\" | \"error\";\n\nexport type UseTerminalStreamOptions = {\n /** The Terminal cell of the negotiated capabilities (`capabilities.Terminal`).\n * The stream connects ONLY when `transport === \"pty-ws\"` and `url` is set; on a\n * cold box (`transport === \"sse-events\"` / no url) it stays idle and the caller\n * falls back to the Channel-A read-only firehose. */\n capability: Pick<TerminalCapability, \"transport\" | \"url\" | \"token\"> | null;\n /** Called for each OUTPUT payload from ttyd (write verbatim into xterm). */\n onOutput?: ((data: string) => void) | undefined;\n /** Called when ttyd sends a SET_WINDOW_TITLE frame. */\n onTitle?: ((title: string) => void) | undefined;\n /** Initial PTY size to seed the ttyd auth frame + first resize. */\n initialCols?: number | undefined;\n initialRows?: number | undefined;\n};\n\nexport type UseTerminalStreamResult = {\n /** True once the ttyd socket is open (and the auth frame has been sent). */\n connected: boolean;\n status: TerminalStreamStatus;\n /** Pipe a keystroke/paste to the PTY stdin. No-op until the socket is open. */\n write: (data: string) => void;\n /** Tell ttyd the PTY window changed size (on xterm fit/resize). */\n resize: (cols: number, rows: number) => void;\n /** Tear the socket down (the effect also tears down on unmount / url change). */\n disconnect: () => void;\n};\n\n/** Decode an inbound ttyd frame's payload (everything after the 1-char command).\n * ttyd may send either a text frame (string) or a binary frame (ArrayBuffer);\n * for binary we slice off the first byte (the command) and utf-8 decode the rest. */\nfunction decodeFrame(data: string | ArrayBuffer): { command: string; payload: string } {\n if (typeof data === \"string\") {\n return { command: data.charAt(0), payload: data.slice(1) };\n }\n const bytes = new Uint8Array(data);\n const command = bytes.length > 0 ? String.fromCharCode(bytes[0]!) : \"\";\n const payload = bytes.length > 1 ? new TextDecoder().decode(bytes.subarray(1)) : \"\";\n return { command, payload };\n}\n\n/**\n * Drive a ttyd PTY-over-websocket connection from a `pty-ws` Terminal capability,\n * symmetric with `use-desktop-stream` (the noVNC-over-tunnel hook). The scoped\n * stream token is already embedded in the minted tunnel `url`; the WebSocket is\n * opened with the REQUIRED ttyd subprotocol \"tty\".\n *\n * ttyd wire protocol (see `@opengeni/sdk/terminal`):\n * - first frame: `JSON.stringify({ AuthToken: \"\" })` (+ optional columns/rows).\n * - client→server: INPUT = \"0\"+data ; RESIZE = \"1\"+JSON({columns,rows}).\n * - server→client: \"0\" = OUTPUT (→ xterm) ; \"1\" = SET_WINDOW_TITLE ;\n * \"2\" = SET_PREFERENCES (ignored). Binary frames are decoded the same way.\n *\n * On a `url`/`token` rotation (a box rollover folds a fresh address into the cell)\n * the effect re-runs: the old socket closes and a fresh one connects — a brief\n * terminal blink, acceptable on rollover (mirrors the desktop's RFB hot-swap).\n * SSR-safe: the socket open lives in `useEffect`, so a server render is a no-op.\n */\nexport function useTerminalStream(options: UseTerminalStreamOptions): UseTerminalStreamResult {\n const { capability, onOutput, onTitle, initialCols, initialRows } = options;\n const [status, setStatus] = useState<TerminalStreamStatus>(\"closed\");\n const wsRef = useRef<WebSocket | null>(null);\n // Latest size, so a resize() before the socket opens is replayed on open, and a\n // reconnect seeds the right geometry.\n const sizeRef = useRef<{ cols: number; rows: number }>({\n cols: initialCols ?? 80,\n rows: initialRows ?? 24,\n });\n // Keep the callbacks current without re-running the connect effect on every\n // render (the parent passes fresh closures each time).\n const onOutputRef = useRef(onOutput);\n const onTitleRef = useRef(onTitle);\n onOutputRef.current = onOutput;\n onTitleRef.current = onTitle;\n\n const transport = capability?.transport ?? null;\n const url = capability?.url ?? null;\n const token = capability?.token ?? null;\n\n useEffect(() => {\n // SSR / no WebSocket / not a live pty-ws cell: stay closed; the caller falls\n // back to the Channel-A read-only firehose.\n if (typeof window === \"undefined\" || typeof WebSocket === \"undefined\") return;\n if (transport !== \"pty-ws\" || !url) {\n setStatus(\"closed\");\n return;\n }\n\n let disposed = false;\n let socket: WebSocket;\n setStatus(\"connecting\");\n try {\n // The ttyd \"tty\" subprotocol is REQUIRED — ttyd rejects a handshake without\n // it. The scoped token is already in the tunnel `url`.\n socket = new WebSocket(terminalSocketUrl({ url }), TTYD_SUBPROTOCOL);\n } catch {\n setStatus(\"error\");\n return;\n }\n socket.binaryType = \"arraybuffer\";\n wsRef.current = socket;\n\n socket.onopen = () => {\n if (disposed) return;\n // ttyd's required first frame: the auth message (empty token — the gate is\n // the tunnel url + scoped stream token, not a ttyd -c credential), seeded\n // with the current PTY geometry. Then an explicit resize to be safe.\n try {\n socket.send(ttydAuthFrame({ columns: sizeRef.current.cols, rows: sizeRef.current.rows }));\n socket.send(ttydResizeFrame(sizeRef.current.cols, sizeRef.current.rows));\n } catch {\n // a closed socket between open and send — onclose handles state.\n }\n setStatus(\"open\");\n };\n\n socket.onmessage = (ev: MessageEvent) => {\n if (disposed) return;\n const { command, payload } = decodeFrame(ev.data as string | ArrayBuffer);\n switch (command) {\n case TtydServerCommand.OUTPUT:\n onOutputRef.current?.(payload);\n break;\n case TtydServerCommand.SET_WINDOW_TITLE:\n onTitleRef.current?.(payload);\n break;\n // SET_PREFERENCES (\"2\") and anything else: ignored.\n default:\n break;\n }\n };\n\n socket.onerror = () => {\n if (!disposed) setStatus(\"error\");\n };\n socket.onclose = () => {\n if (!disposed) setStatus(\"closed\");\n };\n\n return () => {\n disposed = true;\n wsRef.current = null;\n // Drop handlers so an in-flight close/error doesn't mutate state post-unmount.\n socket.onopen = null;\n socket.onmessage = null;\n socket.onerror = null;\n socket.onclose = null;\n try {\n socket.close();\n } catch {\n // ignore teardown errors\n }\n };\n // A url/token change (rotation) re-runs this effect → close old, open new.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [transport, url, token]);\n\n return useMemo<UseTerminalStreamResult>(() => {\n const write = (data: string) => {\n const ws = wsRef.current;\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(ttydInputFrame(data));\n } catch {\n // socket raced closed — the reconnect effect will re-establish.\n }\n }\n };\n const resize = (cols: number, rows: number) => {\n if (cols <= 0 || rows <= 0) return;\n sizeRef.current = { cols, rows };\n const ws = wsRef.current;\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(ttydResizeFrame(cols, rows));\n } catch {\n // socket raced closed — geometry is replayed on the next open.\n }\n }\n };\n const disconnect = () => {\n const ws = wsRef.current;\n wsRef.current = null;\n if (ws) {\n try {\n ws.close();\n } catch {\n // ignore\n }\n }\n };\n return { connected: status === \"open\", status, write, resize, disconnect };\n }, [status]);\n}\n","import type {\n SandboxCommandOutputDeltaPayload,\n SessionEvent,\n TerminalPtyExitedPayload,\n TerminalPtyOutputDeltaPayload,\n} from \"@opengeni/sdk\";\nimport { OpenGeniApiError } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type TerminalChunk = {\n /** Stable key (the source event id) so the xterm writer tracks a written-cursor. */\n id: string;\n /** Raw output bytes (utf-8 lossy) — written verbatim into xterm. */\n text: string;\n /** stdout vs stderr (drives optional tinting). */\n stream: \"stdout\" | \"stderr\";\n /** Global ordering: the source event sequence. */\n seq: number;\n};\n\nexport type UseSandboxTerminalOptions = ClientOverride & {\n /** The live session event log (usually `useSessionEvents().events`). */\n events: SessionEvent[];\n /** Restrict to one PTY (by ptyId). Omit to interleave the agent firehose +\n * every PTY. */\n ptyId?: string | undefined;\n /** Include the agent's command-output firehose (sandbox.command.output.delta).\n * Default true — the read-only \"terminal-as-events\" the data path settled on. */\n includeAgentFirehose?: boolean | undefined;\n /**\n * OPEN an interactive PTY against the box so the user can type, not just watch.\n * When true (and the session is live) the hook calls `terminalPtyOpen` once,\n * tracks the returned ptyId, exposes `write` immediately (bound to that ptyId),\n * and closes the PTY on unmount. The PTY's banner + every output delta ride the\n * SSE spine (`terminal.pty.*`) back into `events`, so xterm fills in. Default\n * false — a caller that only wants the read-only firehose stays projection-only.\n */\n interactive?: boolean | undefined;\n /** Lease liveness (\"cold\" | \"warm\" | \"draining\"). The interactive PTY is only\n * opened once the box is warm — opening on a cold box (ptyCapable is advertised\n * cold too) races the box and leaves a dead read-only terminal. */\n liveness?: string | undefined;\n};\n\nexport type UseSandboxTerminalResult = {\n /** Ordered, deduped output chunks to write() into xterm.js. */\n chunks: TerminalChunk[];\n /** Whether a PTY is currently open (drives the prompt/cursor affordance). */\n running: boolean;\n /**\n * Interactive write fn when a PTY is open and the backend supports stdin\n * (`terminal.transport === \"pty-ws\"` / `PtyOpenResponse.supportsInput`). Null\n * in the read-only event-projection case (v1 default).\n */\n write: ((data: string) => void) | null;\n /** The active PTY id, if one is open. */\n activePtyId: string | null;\n /** Close the active PTY (no-op when none is open). */\n close: () => void;\n /** A PTY-open failure (interactive mode), if any. */\n error: Error | null;\n};\n\n/**\n * Project the Channel-A event log into an xterm-writable byte stream. The\n * terminal is \"terminal-as-events\": there is NO new socket in v1 — the agent's\n * command output (`sandbox.command.output.delta`) and any interactive PTY\n * (`terminal.pty.output.delta`) ride the existing SSE spine. When a PTY is open\n * and the backend accepts stdin, `write` pipes keystrokes via the SDK\n * `terminalPtyWrite` (the synchronous Channel-A control path).\n */\nexport function useSandboxTerminal(\n sessionId: string | null | undefined,\n options: UseSandboxTerminalOptions,\n): UseSandboxTerminalResult {\n const { client, workspaceId } = useOpenGeni(options);\n const includeAgentFirehose = options.includeAgentFirehose ?? true;\n const interactive = options.interactive ?? false;\n // When the caller controls a fixed ptyId we project that one; otherwise (the\n // interactive default) the hook opens its OWN PTY and tracks it here so `write`\n // is live before the `terminal.pty.started` event round-trips through SSE.\n const ptyFilter = options.ptyId;\n const liveness = options.liveness;\n const [openedPtyId, setOpenedPtyId] = useState<string | null>(null);\n const [openError, setOpenError] = useState<Error | null>(null);\n // Bumped to force a fresh PTY open after a write reveals the old PTY was lost\n // (a 409 \"pty session lost\" — the box rolled over since the open). This makes\n // the interactive terminal self-heal instead of dead-ending on a stale session.\n const [reopenNonce, setReopenNonce] = useState(0);\n\n // Open ONE interactive PTY against the box, close it on unmount/identity\n // change. The open's banner + subsequent output deltas ride A1, so xterm fills\n // from `events` — we don't thread the open's body output here (the SSE\n // projection is the single source of truth for what's written). The open is\n // gated on a WARM box: opening on a cold/warming lease races the box (the PTY\n // exec-session is created on a box that the next op may not resume), which is\n // exactly the \"session not found\" terminal failure; we wait for warm/draining.\n const openInFlight = useRef(false);\n const boxWarm = liveness === undefined || liveness === \"warm\" || liveness === \"draining\";\n useEffect(() => {\n if (!interactive || !sessionId || ptyFilter || !boxWarm) return;\n let cancelled = false;\n openInFlight.current = true;\n let openedId: string | null = null;\n void client\n .terminalPtyOpen(workspaceId, sessionId, {})\n .then((res) => {\n if (cancelled) {\n // Raced past unmount — close the orphan we just opened.\n void client.terminalPtyClose(workspaceId, sessionId, { ptyId: res.ptyId }).catch(() => {});\n return;\n }\n openedId = res.ptyId;\n setOpenedPtyId(res.ptyId);\n })\n .catch((cause) => {\n if (!cancelled) setOpenError(cause instanceof Error ? cause : new Error(String(cause)));\n })\n .finally(() => {\n openInFlight.current = false;\n });\n return () => {\n cancelled = true;\n setOpenedPtyId(null);\n const id = openedId;\n if (id) void client.terminalPtyClose(workspaceId, sessionId, { ptyId: id }).catch(() => {});\n };\n }, [interactive, client, workspaceId, sessionId, ptyFilter, boxWarm, reopenNonce]);\n\n const { chunks, openPty, supportsInput } = useMemo(() => {\n const out: TerminalChunk[] = [];\n // Track PTY lifecycle so `running`/`write` reflect the latest state.\n const open = new Map<string, { supportsInput: boolean }>();\n let lastOpened: string | null = null;\n let lastSupportsInput = false;\n\n for (const event of options.events) {\n if (event.type === \"terminal.pty.started\") {\n const payload = event.payload as { ptyId?: string } | null;\n if (payload?.ptyId) {\n open.set(payload.ptyId, { supportsInput: true });\n lastOpened = payload.ptyId;\n }\n continue;\n }\n if (event.type === \"terminal.pty.exited\") {\n const payload = event.payload as TerminalPtyExitedPayload | null;\n if (payload?.ptyId) {\n open.delete(payload.ptyId);\n if (lastOpened === payload.ptyId) lastOpened = null;\n }\n continue;\n }\n if (event.type === \"terminal.pty.output.delta\") {\n const payload = event.payload as TerminalPtyOutputDeltaPayload | null;\n if (!payload || (ptyFilter && payload.ptyId !== ptyFilter)) continue;\n out.push({\n id: event.id,\n text: payload.chunk,\n stream: payload.stream === \"stderr\" ? \"stderr\" : \"stdout\",\n seq: event.sequence,\n });\n continue;\n }\n if (includeAgentFirehose && !ptyFilter && event.type === \"sandbox.command.output.delta\") {\n const payload = event.payload as SandboxCommandOutputDeltaPayload | null;\n if (!payload?.chunk) continue;\n out.push({\n id: event.id,\n text: payload.chunk,\n stream: payload.stream === \"stderr\" ? \"stderr\" : \"stdout\",\n seq: event.sequence,\n });\n }\n }\n\n // Stable order: by sequence (the SSE spine guarantees per-session ordering).\n out.sort((a, b) => a.seq - b.seq);\n const activePty = ptyFilter && open.has(ptyFilter) ? ptyFilter : lastOpened;\n lastSupportsInput = activePty ? (open.get(activePty)?.supportsInput ?? false) : false;\n return { chunks: out, openPty: activePty, supportsInput: lastSupportsInput };\n }, [options.events, ptyFilter, includeAgentFirehose]);\n\n // The PTY this hook actively drives: the one it opened (interactive) wins so\n // `write` is live the instant the open resolves — even before the\n // `terminal.pty.started` event arrives through SSE. Fall back to whatever the\n // event projection found (a PTY opened elsewhere, or a caller-pinned ptyId).\n const activePtyId = openedPtyId ?? openPty;\n // An interactively-opened PTY accepts stdin by construction (we only open it on\n // a pty-capable backend); a projected PTY uses its advertised supportsInput.\n const canWrite = openedPtyId !== null || supportsInput;\n\n const write = useMemo(() => {\n if (!activePtyId || !canWrite || !sessionId) return null;\n return (data: string) => {\n void client.terminalPtyWrite(workspaceId, sessionId, { ptyId: activePtyId, data }).catch((cause) => {\n // The PTY exec-session was lost on the live box (409/404 — the box rolled\n // over since the open). Self-heal: drop the stale id and re-open a fresh\n // PTY against the current box rather than silently swallowing keystrokes.\n if (\n cause instanceof OpenGeniApiError &&\n (cause.status === 409 || cause.status === 404) &&\n activePtyId === openedPtyId\n ) {\n setOpenedPtyId(null);\n setReopenNonce((n) => n + 1);\n }\n });\n };\n }, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId]);\n\n const close = useCallback(() => {\n if (!activePtyId || !sessionId) return;\n void client.terminalPtyClose(workspaceId, sessionId, { ptyId: activePtyId }).catch(() => {});\n }, [client, workspaceId, sessionId, activePtyId]);\n\n return {\n chunks,\n running: activePtyId !== null,\n write,\n activePtyId,\n close,\n error: openError,\n };\n}\n","import type {\n FsChangedPayload,\n FsReadResponse,\n FsTreeNode,\n FsWriteResponse,\n GitChangedPayload,\n GitFileStatusCode,\n SessionEvent,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\n/** The git-status overlay a file row may carry (tints modified files in the tree). */\nexport type FileTreeStatus = \"added\" | \"modified\" | \"deleted\" | \"renamed\" | \"untracked\";\n\n/** A node in the Pierre file tree. `children === undefined` ⇒ an unexpanded dir\n * (lazy treeMode); `children: []` ⇒ an expanded-but-empty dir. */\nexport type FileTreeNode = {\n path: string; // workspace-relative POSIX\n name: string;\n kind: \"file\" | \"dir\";\n children?: FileTreeNode[] | undefined;\n size?: number | null | undefined;\n status?: FileTreeStatus | undefined;\n};\n\nexport type UseSandboxFilesOptions = ClientOverride & {\n /** Live event log (usually `useSessionEvents().events`) — drives auto-refresh\n * on `fs.changed` / `git.changed`. */\n events?: SessionEvent[] | undefined;\n /** Initial path to list (workspace root by default). */\n rootPath?: string | undefined;\n /** Hold off the initial list (e.g. panel collapsed). Default true. */\n enabled?: boolean | undefined;\n /** The lease liveness (\"cold\" | \"warm\" | \"draining\"). The structured FileSystem\n * capability is advertised even on a COLD box, so the mount-time list can race\n * the box: it lists before the box is warm, gets an empty/errored result, and\n * (with no `fs.changed` event) never re-lists. Passing liveness re-lists when\n * the box first becomes warm, so the tree populates as soon as the box is up. */\n liveness?: string | undefined;\n /** Called when an OPTIMISTIC mutation is reverted because its background\n * Channel-A op failed (e.g. a 409 rename collision). The host wires this to a\n * toast — the tree silently rolls the node back, the user sees why. */\n onMutationError?: ((error: Error, op: string) => void) | undefined;\n};\n\nexport type UseSandboxFilesResult = {\n /** The tree roots (the listed root's children). */\n tree: FileTreeNode[];\n /** Lazy-expand a directory node in place (lists its immediate children). */\n expand: (path: string) => Promise<void>;\n /** Paths whose lazy `fs.list` is currently in flight — the FileBrowser shows a\n * spinner on these nodes so a 2-3s Channel-A list never looks frozen. */\n expandingPaths: Set<string>;\n /** Read a file for the preview pane (text or base64-for-binary, size-capped). */\n readFile: (path: string) => Promise<FsReadResponse>;\n /** Write a file (overwrite, last-writer-wins) — the editor save path.\n * Optimistic: a brand-new file is spliced into the tree immediately and the\n * Channel-A write runs in the background; on failure the splice is reverted. */\n writeFile: (path: string, content: string) => Promise<FsWriteResponse>;\n /** Create a new empty file (refuses to clobber an existing path: overwrite=false). */\n createFile: (path: string) => Promise<void>;\n /** Create a directory (recursive by default). */\n createDir: (path: string) => Promise<void>;\n /** Delete a path (pass recursive=true for a non-empty directory). */\n deleteEntry: (path: string, recursive?: boolean) => Promise<void>;\n /** Move / rename a path (rename == move). Refuses to clobber unless overwrite=true. */\n moveEntry: (path: string, newPath: string, opts?: { overwrite?: boolean }) => Promise<void>;\n /** Re-list the whole tree from the root. */\n refresh: () => Promise<void>;\n loading: boolean;\n error: Error | null;\n};\n\n/** The workspace-relative parent directory of a POSIX path (\"\" for a root entry). */\nfunction parentOf(path: string): string {\n const i = path.lastIndexOf(\"/\");\n return i <= 0 ? \"\" : path.slice(0, i);\n}\n\n/** The leaf name of a POSIX path. */\nfunction leafOf(path: string): string {\n const i = path.lastIndexOf(\"/\");\n return i < 0 ? path : path.slice(i + 1);\n}\n\n/** Join a parent dir with a leaf name (handles the root \"\" parent). */\nfunction joinPath(parent: string, name: string): string {\n return parent ? `${parent}/${name}` : name;\n}\n\n/** Stable sibling ordering: dirs before files, then case-insensitive by name —\n * matches a typical depth-1 list so an optimistic insert lands where a real\n * re-list would put it (no jump when the server reconciles). */\nfunction sortNodes(nodes: FileTreeNode[]): FileTreeNode[] {\n return [...nodes].sort((a, b) => {\n if (a.kind !== b.kind) return a.kind === \"dir\" ? -1 : 1;\n return a.name.localeCompare(b.name, undefined, { sensitivity: \"base\" });\n });\n}\n\nfunction fsNodeToTree(node: FsTreeNode): FileTreeNode {\n const kind = node.type === \"dir\" ? \"dir\" : \"file\";\n // Lazy-tree contract: a depth-bounded `fsList` returns each directory at the\n // depth boundary with `children: []` (the dir is listed, but its grandchildren\n // are NOT). An empty array therefore means \"not yet expanded\", NOT \"empty\n // directory\" — so we must map it to `undefined` (the unexpanded marker the\n // FileBrowser keys lazy-expand on). If we kept `[]`, `toggle()`'s\n // `node.children === undefined` guard would never fire and clicking a folder\n // would do nothing (the reported bug). A directory we actually expand has its\n // children spliced in by `replaceChildren` (bypassing this mapper), so a\n // genuinely-empty dir correctly ends up as `[]` AFTER expansion.\n const mappedChildren =\n node.children && node.children.length > 0 ? node.children.map(fsNodeToTree) : undefined;\n return {\n path: node.path,\n name: node.name,\n kind,\n size: node.sizeBytes,\n ...(kind === \"dir\" ? { children: mappedChildren } : {}),\n };\n}\n\nconst GIT_STATUS_TO_TREE: Partial<Record<GitFileStatusCode, FileTreeStatus>> = {\n added: \"added\",\n modified: \"modified\",\n deleted: \"deleted\",\n renamed: \"renamed\",\n copied: \"added\",\n untracked: \"untracked\",\n typechange: \"modified\",\n};\n\n/** Replace the children of `targetPath` within the tree (immutably). */\nfunction replaceChildren(nodes: FileTreeNode[], targetPath: string, children: FileTreeNode[]): FileTreeNode[] {\n return nodes.map((node) => {\n if (node.path === targetPath) {\n return { ...node, children };\n }\n if (node.kind === \"dir\" && node.children && targetPath.startsWith(`${node.path}/`)) {\n return { ...node, children: replaceChildren(node.children, targetPath, children) };\n }\n return node;\n });\n}\n\n/** Find a node by exact path (depth-first). */\nfunction findNodeByPath(nodes: FileTreeNode[], path: string): FileTreeNode | undefined {\n for (const node of nodes) {\n if (node.path === path) return node;\n if (node.kind === \"dir\" && node.children && path.startsWith(`${node.path}/`)) {\n const hit = findNodeByPath(node.children, path);\n if (hit) return hit;\n }\n }\n return undefined;\n}\n\n// ── In-place (optimistic) tree mutations ────────────────────────────────────\n// The Pierre mutation-handle analogue. These splice a single node in/out/across\n// the immutable tree, PRESERVING every other node's `children` (and therefore the\n// FileBrowser's expansion + selection). The old data flow re-listed the whole\n// root and `setTree(rootChildren)` — that dropped every expanded dir back to the\n// unexpanded marker, which is exactly the \"everything refreshes / collapses to\n// .config\" the user saw. Mutating in place is the fix.\n//\n// `parent === \"\"` targets the root list directly. A parent that isn't present in\n// the (lazily-loaded) tree means it's collapsed/unloaded — the helpers return the\n// tree UNCHANGED in that case (caller treats it as \"nothing visible to update\",\n// which is correct: a collapsed dir re-lists fresh when the user expands it).\n\n/** True when `parent` is the root (\"\") or a dir node that is actually present in\n * the loaded tree (so an insert/remove there would be visible). */\nfunction parentIsLoaded(nodes: FileTreeNode[], parent: string): boolean {\n if (parent === \"\") return true;\n const node = findNodeByPath(nodes, parent);\n return Boolean(node && node.kind === \"dir\" && node.children !== undefined);\n}\n\n/** Insert `child` under `parent` (immutably), keeping siblings sorted. A no-op\n * (returns the same array) when the parent isn't a loaded dir or the child\n * already exists. */\nfunction insertNode(nodes: FileTreeNode[], parent: string, child: FileTreeNode): FileTreeNode[] {\n if (parent === \"\") {\n if (nodes.some((n) => n.path === child.path)) return nodes;\n return sortNodes([...nodes, child]);\n }\n return nodes.map((node) => {\n if (node.path === parent) {\n if (node.kind !== \"dir\" || node.children === undefined) return node;\n if (node.children.some((n) => n.path === child.path)) return node;\n return { ...node, children: sortNodes([...node.children, child]) };\n }\n if (node.kind === \"dir\" && node.children && parent.startsWith(`${node.path}/`)) {\n return { ...node, children: insertNode(node.children, parent, child) };\n }\n return node;\n });\n}\n\n/** Remove the node at `path` (immutably). No-op when it isn't in the tree. */\nfunction removeNode(nodes: FileTreeNode[], path: string): FileTreeNode[] {\n const parent = parentOf(path);\n if (parent === \"\") {\n if (!nodes.some((n) => n.path === path)) return nodes;\n return nodes.filter((n) => n.path !== path);\n }\n return nodes.map((node) => {\n if (node.path === parent) {\n if (node.kind !== \"dir\" || node.children === undefined) return node;\n return { ...node, children: node.children.filter((n) => n.path !== path) };\n }\n if (node.kind === \"dir\" && node.children && parent.startsWith(`${node.path}/`)) {\n return { ...node, children: removeNode(node.children, path) };\n }\n return node;\n });\n}\n\n/** Reconcile a freshly-listed depth-1 set of children against the CURRENT nodes\n * at the same level, PRESERVING expansion: an existing dir keeps its already-\n * loaded `children` (so its expanded subtree survives), new entries are added,\n * and entries the server no longer returns are dropped. This is the in-place\n * merge a root (\"\") reconcile needs — a blind replace would collapse every\n * expanded top-level dir back to the unexpanded marker (the reported bug). */\nfunction mergeChildren(current: FileTreeNode[], listed: FileTreeNode[]): FileTreeNode[] {\n const byPath = new Map(current.map((n) => [n.path, n] as const));\n const merged = listed.map((next) => {\n const existing = byPath.get(next.path);\n // Keep an already-expanded dir's loaded children; otherwise take the listing's\n // marker (undefined = unexpanded). Carry forward size/status from the listing.\n if (existing && existing.kind === \"dir\" && next.kind === \"dir\" && existing.children !== undefined) {\n return { ...next, children: existing.children };\n }\n return next;\n });\n return sortNodes(merged);\n}\n\n/** Root-level (\"\") reconcile: merge a fresh depth-1 listing into the root list\n * without collapsing expanded top-level dirs. */\nfunction mergeRootChildren(nodes: FileTreeNode[], listed: FileTreeNode[]): FileTreeNode[] {\n return mergeChildren(nodes, listed);\n}\n\n/** Re-path a subtree rooted at `node` from `fromPrefix` to `toPrefix` (so a moved\n * dir's descendants keep correct paths without a re-list). */\nfunction repathNode(node: FileTreeNode, fromPrefix: string, toPrefix: string): FileTreeNode {\n const newPath = toPrefix + node.path.slice(fromPrefix.length);\n const next: FileTreeNode = { ...node, path: newPath, name: leafOf(newPath) };\n if (node.children) next.children = node.children.map((c) => repathNode(c, fromPrefix, toPrefix));\n return next;\n}\n\n/**\n * Project the FileSystem service into a lazy-loaded Pierre tree. The initial\n * list pulls one level (depth 1); `expand(path)` lists a directory's immediate\n * children on demand (the fast lazy-tree UX). A git-status overlay tints\n * modified files. Auto-refreshes when an `fs.changed` / `git.changed` event\n * arrives on the live log.\n */\nexport function useSandboxFiles(\n sessionId: string | null | undefined,\n options: UseSandboxFilesOptions = {},\n): UseSandboxFilesResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const rootPath = options.rootPath ?? \"\";\n\n const [tree, setTree] = useState<FileTreeNode[]>([]);\n // A ref mirror of the current tree — lets the optimistic path snapshot the\n // pre-op tree WITHOUT relying on a `setTree` updater (which StrictMode invokes\n // twice, corrupting an in-closure snapshot). Kept in sync on every set below\n // and in a layout effect for any path that sets `tree` directly.\n const treeRef = useRef<FileTreeNode[]>([]);\n const [loading, setLoading] = useState(false);\n const [expandingPaths, setExpandingPaths] = useState<Set<string>>(new Set());\n const [error, setError] = useState<Error | null>(null);\n const statusRef = useRef<Map<string, FileTreeStatus>>(new Map());\n\n // ── Self-emitted fs.changed de-dupe ───────────────────────────────────────\n // Every one of OUR mutations emits an `fs.changed` event back on the live log\n // (source:\"write\"). The old flow auto-refreshed on EVERY fs.changed, so each\n // edit self-triggered a full root collapse-reload (~5s, lost expansion). We now\n // (a) ignore fs.changed whose `source === \"write\"` (our own control-plane ops),\n // and (b) belt-and-braces, track the revisions WE caused so even a watch-sourced\n // echo of our own write is suppressed. Only EXTERNAL changes (the agent writing,\n // source:\"agent\"/\"watch\" we didn't cause) drive a targeted reconcile.\n const ownRevisionsRef = useRef<Set<number>>(new Set());\n const onMutationError = options.onMutationError;\n\n // Keep the ref mirror current for the optimistic snapshot path.\n treeRef.current = tree;\n\n const applyStatus = useCallback((nodes: FileTreeNode[]): FileTreeNode[] => {\n const overlay = statusRef.current;\n if (overlay.size === 0) return nodes;\n const walk = (list: FileTreeNode[]): FileTreeNode[] =>\n list.map((node) => {\n const status = overlay.get(node.path);\n const next = node.children ? { ...node, children: walk(node.children) } : { ...node };\n if (status && node.kind === \"file\") next.status = status;\n else delete next.status;\n return next;\n });\n return walk(nodes);\n }, []);\n\n const refresh = useCallback(async () => {\n if (!sessionId) return;\n setLoading(true);\n setError(null);\n try {\n // Pull the git-status overlay first (best-effort — a non-repo box just\n // returns isRepo:false), then the tree, so the first paint is tinted.\n try {\n const status = await client.gitStatus(workspaceId, sessionId, { path: rootPath });\n const overlay = new Map<string, FileTreeStatus>();\n for (const file of status.files) {\n const code = file.worktree ?? file.index;\n const mapped = code ? GIT_STATUS_TO_TREE[code] : undefined;\n if (mapped) overlay.set(file.path, mapped);\n }\n statusRef.current = overlay;\n } catch {\n statusRef.current = new Map();\n }\n const listed = await client.fsList(workspaceId, sessionId, { path: rootPath, depth: 1 });\n const children = (listed.root.children ?? []).map(fsNodeToTree);\n // Merge rather than replace so an explicit refresh / cold→warm re-list folds\n // in new entries WITHOUT collapsing the dirs the user already expanded. On a\n // first (empty) load this is a plain set.\n setTree((prev) => applyStatus(prev.length === 0 ? children : mergeRootChildren(prev, children)));\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setLoading(false);\n }\n }, [client, workspaceId, sessionId, rootPath, applyStatus]);\n\n const expand = useCallback(\n async (path: string) => {\n if (!sessionId) return;\n // Mark this node as expanding so the FileBrowser can render a spinner while\n // the (often 2-3s) Channel-A fs/list is in flight — the tree never looks\n // frozen on a click.\n setExpandingPaths((prev) => {\n const next = new Set(prev);\n next.add(path);\n return next;\n });\n try {\n const listed = await client.fsList(workspaceId, sessionId, { path, depth: 1 });\n const children = (listed.root.children ?? []).map(fsNodeToTree);\n setTree((prev) => applyStatus(replaceChildren(prev, path, children)));\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setExpandingPaths((prev) => {\n if (!prev.has(path)) return prev;\n const next = new Set(prev);\n next.delete(path);\n return next;\n });\n }\n },\n [client, workspaceId, sessionId, applyStatus],\n );\n\n const readFile = useCallback(\n async (path: string) => {\n if (!sessionId) throw new Error(\"no session\");\n return await client.fsRead(workspaceId, sessionId, { path });\n },\n [client, workspaceId, sessionId],\n );\n\n // TARGETED reconcile of a single directory — re-list ONE parent at depth 1 and\n // splice its children in place via `replaceChildren`, preserving the rest of the\n // tree's expansion. NEVER falls back to a root refresh (that's the collapse).\n // Used to (a) reconcile an optimistic insert against the server's real\n // size/mtime, and (b) fold an EXTERNAL (agent) change into the tree. A reconcile\n // of a parent that isn't loaded (collapsed/unmounted) is a no-op — there's\n // nothing visible to update, and it re-lists fresh when the user expands it.\n const reconcilePath = useCallback(\n async (path: string) => {\n if (!sessionId) return;\n // Skip parents that aren't currently loaded/expanded in the tree (nothing\n // visible to update; they re-list fresh on the next expand).\n if (!parentIsLoaded(treeRef.current, path)) return;\n try {\n const listed = await client.fsList(workspaceId, sessionId, { path, depth: 1 });\n const children = (listed.root.children ?? []).map(fsNodeToTree);\n if (path === \"\") setTree((prev) => applyStatus(mergeRootChildren(prev, children)));\n else\n setTree((prev) => {\n const existing = findNodeByPath(prev, path);\n const merged = existing?.children ? mergeChildren(existing.children, children) : children;\n return applyStatus(replaceChildren(prev, path, merged));\n });\n } catch {\n // A failed reconcile is non-fatal: the optimistic state stands. We never\n // root-refresh here (that would collapse the tree the user is working in).\n }\n },\n [client, workspaceId, sessionId, applyStatus],\n );\n\n // Run a Channel-A op behind an OPTIMISTIC tree edit. `apply` splices the change\n // in immediately (preserving expansion/selection); the op runs in the\n // background; on failure we revert to the pre-op snapshot and surface a toast.\n // On success we keep the optimistic state and (optionally) reconcile the\n // affected parent(s) to pick up the server's real size/revision — NEVER a full\n // refresh. The returned promise resolves/rejects with the op so callers (the\n // editor save, inline rename) can still await it.\n const runOptimistic = useCallback(\n async <T,>(\n opName: string,\n apply: (nodes: FileTreeNode[]) => FileTreeNode[],\n op: () => Promise<T>,\n reconcileParents: string[],\n ): Promise<T> => {\n // Snapshot the pre-op tree from the ref (StrictMode-safe — see treeRef).\n const snapshot = treeRef.current;\n setTree(applyStatus(apply(snapshot)));\n try {\n const res = await op();\n // Remember the revision WE caused so the matching fs.changed echo is\n // ignored by the event effect (no self-triggered refresh).\n if (res && typeof res === \"object\" && \"revision\" in res) {\n const rev = (res as { revision?: unknown }).revision;\n if (typeof rev === \"number\") ownRevisionsRef.current.add(rev);\n }\n // Reconcile loaded parents to fold the server's real metadata. Sequential\n // and best-effort — purely cosmetic over the already-correct optimistic UI.\n for (const parent of reconcileParents) await reconcilePath(parent);\n return res;\n } catch (cause) {\n const err = cause instanceof Error ? cause : new Error(String(cause));\n // Revert the optimistic edit to the exact pre-op tree.\n setTree(applyStatus(snapshot));\n setError(err);\n onMutationError?.(err, opName);\n throw err;\n }\n },\n [applyStatus, reconcilePath, onMutationError],\n );\n\n const writeFile = useCallback(\n async (path: string, content: string): Promise<FsWriteResponse> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentOf(path);\n // Splice a new file node in immediately ONLY when the path doesn't already\n // exist in a loaded parent (an editor SAVE to an existing file mutates no\n // tree shape — just content — so it needs no optimistic node, no reconcile).\n const exists = Boolean(findNodeByPath(tree, path));\n const node: FileTreeNode = { path, name: leafOf(path), kind: \"file\", size: content.length };\n return await runOptimistic(\n \"write\",\n (nodes) => (exists ? nodes : insertNode(nodes, parent, node)),\n () => client.fsWrite(workspaceId, sessionId, { path, content, overwrite: true }),\n exists ? [] : [parent],\n );\n },\n [client, workspaceId, sessionId, tree, runOptimistic],\n );\n\n const createFile = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentOf(path);\n const node: FileTreeNode = { path, name: leafOf(path), kind: \"file\", size: 0 };\n await runOptimistic(\n \"create file\",\n (nodes) => insertNode(nodes, parent, node),\n () => client.fsWrite(workspaceId, sessionId, { path, content: \"\", overwrite: false }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n const createDir = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentOf(path);\n // A freshly-created dir is empty + expanded: children:[] (not undefined, so\n // it doesn't show the lazy-expand marker over a dir we KNOW is empty).\n const node: FileTreeNode = { path, name: leafOf(path), kind: \"dir\", children: [] };\n await runOptimistic(\n \"create folder\",\n (nodes) => insertNode(nodes, parent, node),\n () => client.fsMkdir(workspaceId, sessionId, { path, recursive: true }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n const deleteEntry = useCallback(\n async (path: string, recursive = false): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n await runOptimistic(\n \"delete\",\n (nodes) => removeNode(nodes, path),\n () => client.fsDelete(workspaceId, sessionId, { path, recursive }),\n [parentOf(path)],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n const moveEntry = useCallback(\n async (path: string, newPath: string, opts?: { overwrite?: boolean }): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const from = parentOf(path);\n const to = parentOf(newPath);\n await runOptimistic(\n \"move\",\n (nodes) => {\n const moving = findNodeByPath(nodes, path);\n if (!moving) return nodes; // not loaded — let the reconcile pick it up\n // Re-path the moved subtree, drop it from its old parent, splice into new.\n const moved = repathNode(moving, path, newPath);\n return insertNode(removeNode(nodes, path), to, moved);\n },\n () =>\n client.fsMove(workspaceId, sessionId, {\n path,\n newPath,\n overwrite: opts?.overwrite ?? false,\n }),\n to === from ? [from] : [from, to],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n // Initial load + reset on identity change.\n useEffect(() => {\n if (!enabled) {\n setTree([]);\n return;\n }\n void refresh();\n }, [enabled, refresh]);\n\n // Re-pull JUST the git-status overlay and re-tint the existing tree in place —\n // no fs re-list, no collapse. This is all a `git.changed` (commit/stage/checkout)\n // needs: the tree SHAPE is unchanged, only the tints move.\n const refreshGitOverlay = useCallback(async () => {\n if (!sessionId) return;\n try {\n const status = await client.gitStatus(workspaceId, sessionId, { path: rootPath });\n const overlay = new Map<string, FileTreeStatus>();\n for (const file of status.files) {\n const code = file.worktree ?? file.index;\n const mapped = code ? GIT_STATUS_TO_TREE[code] : undefined;\n if (mapped) overlay.set(file.path, mapped);\n }\n statusRef.current = overlay;\n setTree((prev) => applyStatus(prev));\n } catch {\n /* a non-repo box has no overlay — leave the tree untinted */\n }\n }, [client, workspaceId, sessionId, rootPath, applyStatus]);\n\n // Auto-reconcile on fs/git change notifications — TARGETED, never a root\n // collapse-reload, and de-duped against our OWN mutations.\n //\n // • Our own ops (`source:\"write\"`, or a revision WE caused) are IGNORED —\n // the optimistic edit already reflects them, so a refresh here would be the\n // pointless 5s collapse the user reported.\n // • An EXTERNAL fs.changed (the agent writing files: `source:\"agent\"`/`watch`)\n // reconciles ONLY the affected parent directories (in place, expansion\n // preserved). Bursts are debounced into a single reconcile pass.\n // • A git.changed just re-tints (refreshes the status overlay) — no fs re-list.\n const events = options.events;\n const lastSeqRef = useRef(0);\n const pendingParentsRef = useRef<Set<string>>(new Set());\n const pendingGitRef = useRef(false);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (!enabled || !events) return;\n let sawNew = false;\n for (const event of events) {\n if (event.sequence <= lastSeqRef.current) continue;\n if (event.type === \"fs.changed\") {\n sawNew = true;\n const payload = event.payload as FsChangedPayload | null;\n if (!payload || typeof payload !== \"object\") continue;\n // Suppress our own writes: the optimistic tree already shows them.\n if (payload.source === \"write\") continue;\n if (typeof payload.revision === \"number\" && ownRevisionsRef.current.has(payload.revision)) continue;\n for (const change of payload.changes ?? []) {\n pendingParentsRef.current.add(parentOf(change.path));\n if (change.oldPath) pendingParentsRef.current.add(parentOf(change.oldPath));\n }\n } else if (event.type === \"git.changed\") {\n sawNew = true;\n const payload = event.payload as GitChangedPayload | null;\n // A git.changed our own write triggered (commit/stage from the agent is\n // external; a checkout we caused isn't — but we don't cause git ops here,\n // so any git.changed is external) → re-tint.\n if (payload && typeof payload === \"object\" && typeof payload.revision === \"number\"\n && ownRevisionsRef.current.has(payload.revision)) continue;\n pendingGitRef.current = true;\n }\n }\n // Advance the high-water mark past everything we've folded.\n for (const event of events) if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;\n if (!sawNew) return;\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n debounceRef.current = setTimeout(() => {\n debounceRef.current = null;\n const parents = pendingParentsRef.current;\n pendingParentsRef.current = new Set();\n const wantGit = pendingGitRef.current;\n pendingGitRef.current = false;\n // Reconcile the changed directories (in place). A git change re-tints first\n // so the freshly-listed nodes get the correct overlay.\n void (async () => {\n if (wantGit) await refreshGitOverlay();\n for (const parent of parents) await reconcilePath(parent);\n })();\n }, 150);\n }, [enabled, events, reconcilePath, refreshGitOverlay]);\n\n useEffect(\n () => () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n },\n [],\n );\n\n // Re-list when the box first becomes warm. The FileSystem capability is\n // advertised on a cold box too, so the mount-time `refresh()` can run before\n // the box is up (empty/errored result); without an `fs.changed` event the tree\n // would stay empty forever. A cold->warm transition re-lists once the box is\n // actually serving — the real fix for the \"No files\" the deployed app showed.\n const wasLiveRef = useRef(false);\n const liveness = options.liveness;\n useEffect(() => {\n const live = liveness === \"warm\" || liveness === \"draining\";\n if (enabled && live && !wasLiveRef.current) {\n wasLiveRef.current = true;\n void refresh();\n } else if (!live) {\n wasLiveRef.current = false;\n }\n }, [enabled, liveness, refresh]);\n\n return {\n tree,\n expand,\n expandingPaths,\n readFile,\n writeFile,\n createFile,\n createDir,\n deleteEntry,\n moveEntry,\n refresh,\n loading,\n error,\n };\n}\n","import type { GitFileDiff, SessionEvent } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type UseSandboxGitOptions = ClientOverride & {\n /** Live event log (usually `useSessionEvents().events`) — drives auto-refresh\n * on `git.changed`. */\n events?: SessionEvent[] | undefined;\n /** Repo root within the workspace (multi-repo). Default: workspace root. */\n repoPath?: string | undefined;\n /** Diff the staged index vs HEAD (`--cached`) instead of the working tree. */\n staged?: boolean | undefined;\n /** Hold off the initial fetch. Default true. */\n enabled?: boolean | undefined;\n};\n\nexport type UseSandboxGitResult = {\n /** Working-tree (or staged) diff vs HEAD — the structured hunks the Pierre\n * diff view renders. */\n diff: GitFileDiff[];\n branch: string | null;\n /** Whether a repo is actually mounted (drives \"no repository\" vs \"no changes\"). */\n isRepo: boolean;\n ahead: number;\n behind: number;\n refresh: () => Promise<void>;\n loading: boolean;\n error: Error | null;\n};\n\n/**\n * Project the Git service into the Pierre diff data contract: structured\n * `GitFileDiff[]` (per-file hunks with per-line old/new numbers, rename\n * detection, binary flag, add/del counts) plus branch + ahead/behind. The\n * `git diff` runs in-box (API-direct) and the hunks come back inline. Refreshes\n * on `git.changed`.\n */\nexport function useSandboxGit(\n sessionId: string | null | undefined,\n options: UseSandboxGitOptions = {},\n): UseSandboxGitResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const repoPath = options.repoPath ?? \"\";\n const staged = options.staged ?? false;\n\n const [diff, setDiff] = useState<GitFileDiff[]>([]);\n const [branch, setBranch] = useState<string | null>(null);\n const [isRepo, setIsRepo] = useState(false);\n const [ahead, setAhead] = useState(0);\n const [behind, setBehind] = useState(0);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const refresh = useCallback(async () => {\n if (!sessionId) return;\n setLoading(true);\n setError(null);\n try {\n const status = await client.gitStatus(workspaceId, sessionId, { path: repoPath });\n setIsRepo(status.isRepo);\n setBranch(status.head);\n setAhead(status.ahead);\n setBehind(status.behind);\n if (!status.isRepo) {\n setDiff([]);\n return;\n }\n const result = await client.gitDiff(workspaceId, sessionId, { path: repoPath, staged });\n setDiff(result.files);\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setLoading(false);\n }\n }, [client, workspaceId, sessionId, repoPath, staged]);\n\n useEffect(() => {\n if (!enabled) {\n setDiff([]);\n setIsRepo(false);\n setBranch(null);\n return;\n }\n void refresh();\n }, [enabled, refresh]);\n\n const events = options.events;\n const lastChangeRef = useRef(0);\n useEffect(() => {\n if (!enabled || !events) return;\n let latest = lastChangeRef.current;\n for (const event of events) {\n if (event.type === \"git.changed\" && event.sequence > latest) {\n latest = event.sequence;\n }\n }\n if (latest > lastChangeRef.current) {\n lastChangeRef.current = latest;\n void refresh();\n }\n }, [enabled, events, refresh]);\n\n return { diff, branch, isRepo, ahead, behind, refresh, loading, error };\n}\n","import type { SessionEvent } from \"@opengeni/sdk\";\n\n/* ----------------------------------------------------------------------------\n Pending-approvals projection\n\n `session.requiresAction` events live forever in the durable log, so a\n console that replays the log from sequence 0 must not render every\n historical approval as actionable. `projectPendingApprovals` folds the\n ordered event log into the approvals that are still undecided *now*:\n\n - `session.requiresAction` replaces the pending set with the payload's\n approvals (the producer always emits the full currently-pending set, so\n re-emission after a worker re-dispatch cannot duplicate cards);\n - `user.approvalDecision` subtracts the decided approval;\n - the owning turn finishing (`turn.completed`/`turn.failed`/\n `turn.cancelled`) clears the set — whatever was pending died with the\n turn. A `turn.cancelled` for a *different* turn (deleting a queued turn\n while the session waits on an approval) leaves the set alone.\n\n Pure function — same events in, same approvals out — so approve-then-reload\n projects to an empty set instead of a zombie Approve button.\n -------------------------------------------------------------------------- */\n\nexport type PendingApproval = {\n /** The id to send back via `user.approvalDecision` (`approvalId`). */\n id: string;\n /** Tool/function name awaiting the decision. */\n name: string;\n arguments?: unknown;\n /** The raw approval entry from the `session.requiresAction` payload. */\n raw?: unknown;\n};\n\n/** The approvals carried by one `session.requiresAction` payload. */\nexport function approvalsFromRequiresAction(payload: unknown): PendingApproval[] {\n const approvals = payload && typeof payload === \"object\" ? (payload as { approvals?: unknown }).approvals : undefined;\n if (!Array.isArray(approvals)) {\n return [];\n }\n return approvals.map((approval, index) => {\n const raw = (approval && typeof approval === \"object\" ? approval : {}) as Record<string, unknown>;\n const rawItem = raw.rawItem && typeof raw.rawItem === \"object\" ? raw.rawItem as Record<string, unknown> : {};\n return {\n id: String(raw.id ?? raw.callId ?? rawItem.callId ?? index),\n name: String(raw.name ?? \"approval\"),\n arguments: raw.arguments,\n raw: approval,\n };\n });\n}\n\n/** The approvals still awaiting a decision after replaying `events` in order. */\nexport function projectPendingApprovals(events: SessionEvent[]): PendingApproval[] {\n let pending: PendingApproval[] = [];\n let owningTurnId: string | null = null;\n for (const event of events) {\n switch (event.type) {\n case \"session.requiresAction\": {\n pending = approvalsFromRequiresAction(event.payload);\n owningTurnId = event.turnId ?? null;\n break;\n }\n case \"user.approvalDecision\": {\n const payload = event.payload && typeof event.payload === \"object\" ? event.payload as { approvalId?: unknown } : {};\n if (typeof payload.approvalId === \"string\") {\n pending = pending.filter((approval) => approval.id !== payload.approvalId);\n }\n break;\n }\n case \"turn.completed\":\n case \"turn.failed\":\n case \"turn.cancelled\": {\n // Scope clearing to the turn that raised the approvals when both\n // sides carry a turn id; clear conservatively when either is unknown.\n if (owningTurnId === null || event.turnId == null || event.turnId === owningTurnId) {\n pending = [];\n owningTurnId = null;\n }\n break;\n }\n default:\n break;\n }\n }\n return pending;\n}\n","import type { Permission } from \"@opengeni/sdk\";\nimport type { CommandContext, SlashArg, SlashCommand } from \"./types\";\n\n/**\n * Parse a composer value into a command name + the rest. A command is\n * recognized ONLY when the value's first character is \"/\" (the start token);\n * anything else is plain chat and returns null.\n *\n * \"/cl\" -> { name: \"cl\", rest: \"\", hasTrailingSpace: false }\n * \"/goal \" -> { name: \"goal\", rest: \"\", hasTrailingSpace: true }\n * \"/goal pause\"-> { name: \"goal\", rest: \"pause\", hasTrailingSpace: false }\n */\nexport type ParsedCommandLine = {\n name: string;\n rest: string;\n /** True when the name token is closed by a space — arg-hint mode. */\n hasTrailingSpace: boolean;\n args: string[];\n};\n\nexport function parseCommandLine(value: string): ParsedCommandLine | null {\n if (value[0] !== \"/\") {\n return null;\n }\n const body = value.slice(1);\n const firstSpace = body.indexOf(\" \");\n if (firstSpace === -1) {\n return { name: body, rest: \"\", hasTrailingSpace: false, args: [] };\n }\n const name = body.slice(0, firstSpace);\n const rest = body.slice(firstSpace + 1);\n return {\n name,\n rest,\n hasTrailingSpace: true,\n args: rest.split(/\\s+/).filter((token) => token.length > 0),\n };\n}\n\nconst PERMISSION_SUPERUSER: Permission = \"workspace:admin\";\n\n/** Whether the operator's permission set satisfies a command's gate. */\nexport function hasPermission(required: Permission | undefined, permissions: Permission[]): boolean {\n if (!required) {\n return true;\n }\n return permissions.includes(required) || permissions.includes(PERMISSION_SUPERUSER);\n}\n\n/** Match a command (by name or alias) against the value. */\nexport function matchCommand(commands: readonly SlashCommand[], value: string): SlashCommand | null {\n const parsed = parseCommandLine(value);\n if (!parsed) {\n return null;\n }\n const token = parsed.name.toLowerCase();\n return commands.find((command) => command.name === token || command.aliases?.includes(token)) ?? null;\n}\n\ntype FilterCtx = Pick<CommandContext, \"sessionId\" | \"status\" | \"permissions\">;\n\n/**\n * The commands visible for the current token + context. Permission-absent and\n * `available()===false` commands are dropped entirely (a gated command is never\n * shown, not shown-disabled). Filtering is a prefix match on name/alias.\n */\nexport function filterCommands(commands: readonly SlashCommand[], token: string, ctx: FilterCtx): SlashCommand[] {\n const needle = token.toLowerCase();\n return commands.filter((command) => {\n if (!hasPermission(command.permission, ctx.permissions)) {\n return false;\n }\n if (command.available && !command.available(ctx)) {\n return false;\n }\n if (needle.length === 0) {\n return true;\n }\n return command.name.startsWith(needle) || (command.aliases?.some((alias) => alias.startsWith(needle)) ?? false);\n });\n}\n\n/** Render a command's arg hint for the palette footer / help, e.g. \"<pause|resume>\". */\nexport function argHint(args: readonly SlashArg[] | undefined): string {\n if (!args || args.length === 0) {\n return \"\";\n }\n return args\n .map((arg) => {\n const label = arg.oneOf ? arg.oneOf.join(\"|\") : arg.name;\n return arg.required ? `<${label}>` : `[${label}]`;\n })\n .join(\" \");\n}\n\n/** The first required arg that has not yet been supplied, if any. */\nexport function firstMissingRequiredArg(command: SlashCommand, args: string[]): SlashArg | null {\n const required = (command.args ?? []).filter((arg) => arg.required);\n for (let i = 0; i < required.length; i += 1) {\n const value = args[i];\n if (value === undefined || value.length === 0) {\n return required[i] ?? null;\n }\n }\n return null;\n}\n\nfunction requireSession(ctx: CommandContext): string {\n if (!ctx.sessionId) {\n throw new Error(\"No active session yet — start a session first.\");\n }\n return ctx.sessionId;\n}\n\nconst hasSession = (ctx: FilterCtx): boolean => ctx.sessionId !== null;\n\n/**\n * The default command set. Adding a command is one object literal here; the\n * palette list, filter, arg-hint footer, and /help all render from this array.\n * Apps concat their own commands via the ChatComposer `commands` prop.\n */\nexport const defaultCommands: readonly SlashCommand[] = [\n {\n name: \"help\",\n aliases: [\"?\"],\n description: \"Show available commands.\",\n run: (_args, ctx) => {\n ctx.openHelp();\n return { status: \"ok\" };\n },\n },\n {\n name: \"clear-view\",\n description: \"Clear the local timeline view (this device only; no server change).\",\n run: (_args, ctx) => {\n // clearView() reports whether the host actually wired a view-reset. If it\n // didn't (the console surface has no resettable local timeline), reporting\n // \"Local view cleared.\" would be a false success — return an honest error\n // instead so the operator isn't told something happened when nothing did.\n const cleared = ctx.clearView();\n if (!cleared) {\n return { status: \"error\", message: \"This view can't be cleared here (no local timeline to reset).\" };\n }\n return { status: \"ok\", message: \"Local view cleared.\" };\n },\n },\n {\n name: \"goal\",\n description: \"Pause or resume the session's goal loop.\",\n permission: \"sessions:control\",\n available: hasSession,\n args: [{ name: \"action\", required: true, oneOf: [\"pause\", \"resume\"], description: \"pause | resume\" }],\n run: async (args, ctx) => {\n const sessionId = requireSession(ctx);\n const action = args[0];\n if (action !== \"pause\" && action !== \"resume\") {\n return { status: \"error\", message: \"Usage: /goal pause | /goal resume\" };\n }\n try {\n await ctx.client.updateGoal(ctx.workspaceId, sessionId, { status: action === \"pause\" ? \"paused\" : \"active\" });\n return { status: \"ok\", message: action === \"pause\" ? \"Goal paused.\" : \"Goal resumed.\" };\n } catch (cause) {\n return { status: \"error\", message: goalErrorMessage(cause, action) };\n }\n },\n },\n {\n name: \"compact\",\n description: \"Compact the conversation context now.\",\n permission: \"sessions:control\",\n available: hasSession,\n run: async (_args, ctx) => {\n const sessionId = requireSession(ctx);\n try {\n const result = await ctx.client.compactSessionContext(ctx.workspaceId, sessionId);\n return { status: \"ok\", message: result.message };\n } catch (cause) {\n return { status: \"error\", message: errorMessage(cause) ?? \"Could not compact context.\" };\n }\n },\n },\n {\n name: \"clear\",\n description: \"Clear the conversation context (destructive; audit-preserved).\",\n permission: \"sessions:control\",\n danger: true,\n available: hasSession,\n run: async (_args, ctx) => {\n const sessionId = requireSession(ctx);\n const confirmed = await ctx.confirm();\n if (!confirmed) {\n // Canceled: no error, but keep the \"/clear\" draft so the operator who\n // backed out doesn't silently lose what they typed.\n return { status: \"ok\", keepDraft: true };\n }\n try {\n await ctx.client.clearSessionContext(ctx.workspaceId, sessionId);\n return { status: \"ok\", message: \"Context cleared.\" };\n } catch (cause) {\n return { status: \"error\", message: clearErrorMessage(cause) };\n }\n },\n },\n];\n\nfunction errorMessage(cause: unknown): string | undefined {\n if (cause && typeof cause === \"object\" && \"message\" in cause && typeof (cause as { message?: unknown }).message === \"string\") {\n return (cause as { message: string }).message;\n }\n return undefined;\n}\n\nfunction statusCode(cause: unknown): number | undefined {\n if (cause && typeof cause === \"object\" && \"status\" in cause && typeof (cause as { status?: unknown }).status === \"number\") {\n return (cause as { status: number }).status;\n }\n return undefined;\n}\n\nfunction goalErrorMessage(cause: unknown, action: \"pause\" | \"resume\"): string {\n const code = statusCode(cause);\n if (code === 404) {\n return \"This session has no goal to control.\";\n }\n if (code === 409) {\n return action === \"resume\" ? \"Only a paused goal can be resumed.\" : \"Goal is already in a terminal state.\";\n }\n return errorMessage(cause) ?? `Could not ${action} the goal.`;\n}\n\nfunction clearErrorMessage(cause: unknown): string {\n if (statusCode(cause) === 409) {\n return \"Can't clear context mid-turn — stop the current turn first.\";\n }\n return errorMessage(cause) ?? \"Could not clear context.\";\n}\n","import type { KeyboardEvent } from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n argHint,\n filterCommands,\n firstMissingRequiredArg,\n matchCommand,\n parseCommandLine,\n} from \"../commands/registry\";\nimport type { CommandContext, Notice, SlashCommand } from \"../commands/types\";\n\n/**\n * Context the composer supplies for command execution and visibility. The\n * composer owns the UI affordances (notice/openHelp/clearView/confirm), so they\n * are NOT part of this slice — the hook closes over them via `handlers`.\n */\nexport type SlashCommandContext = Pick<\n CommandContext,\n \"client\" | \"workspaceId\" | \"sessionId\" | \"status\" | \"permissions\"\n>;\n\n/**\n * UI affordances the composer supplies. `confirm` differs from the registry-\n * facing {@link CommandContext.confirm} (which takes no args): the composer's\n * confirm receives the command being run so the confirm bar renders from that\n * exact command's identity. The hook bridges the two in {@link buildContext}.\n */\nexport type SlashCommandHandlers = Pick<CommandContext, \"notice\" | \"openHelp\" | \"clearView\"> & {\n confirm: (command: SlashCommand) => Promise<boolean>;\n};\n\nexport type ConfirmState = {\n command: SlashCommand;\n /** Resolve the pending confirm() promise. */\n resolve: (confirmed: boolean) => void;\n} | null;\n\nexport type UseSlashCommandsOptions = {\n commands: readonly SlashCommand[];\n context: SlashCommandContext | undefined;\n handlers: SlashCommandHandlers;\n /** The current composer draft. */\n value: string;\n /** Replace the composer draft (autocomplete writes through this). */\n setValue: (value: string) => void;\n};\n\nexport type UseSlashCommandsResult = {\n /** Whether the palette is open (a command token is being typed). */\n open: boolean;\n /**\n * Whether the draft is a slash-command attempt (matches a registered command)\n * — true even after Escape dismisses the popover. The composer blocks its send\n * path while this holds so a command can't be delivered to the agent as chat.\n */\n isCommandDraft: boolean;\n /** Commands shown for the current token + context, in display order. */\n items: SlashCommand[];\n /** Index into `items` of the highlighted row. */\n highlight: number;\n setHighlight: (index: number) => void;\n /** The matched command once the name is closed by a space (arg-hint mode). */\n activeCommand: SlashCommand | null;\n /** The arg hint string for the active command (footer), or \"\". */\n activeArgHint: string;\n /**\n * Key handler for the textarea. Returns true when it consumed the event\n * (the composer must then NOT run its send path). Only consumes while open.\n */\n onKeyDown: (event: KeyboardEvent<HTMLTextAreaElement>) => boolean;\n /** Run the highlighted command (or the active command in arg-hint mode). */\n runHighlighted: () => Promise<void>;\n /**\n * Run the command at an explicitly chosen index (a pointer click on a row).\n * Bypasses the exact-match token heuristic that runHighlighted uses for\n * keyboard Enter, so an explicit click always runs the clicked command.\n */\n runAt: (index: number) => Promise<void>;\n /** Autocomplete the highlighted command name + a trailing space. */\n autocompleteHighlighted: () => void;\n};\n\nexport function useSlashCommands(options: UseSlashCommandsOptions): UseSlashCommandsResult {\n const { commands, context, handlers, value, setValue } = options;\n const [highlight, setHighlight] = useState(0);\n // Escape closes the palette but keeps the draft. We remember the dismissed\n // value; any further edit (value !== dismissed) re-opens the palette.\n const [dismissedValue, setDismissedValue] = useState<string | null>(null);\n const dismissed = dismissedValue !== null && dismissedValue === value;\n\n // Whether the operator has explicitly arrow-navigated the highlight for the\n // CURRENT draft. When they have, Enter is an explicit choice of the\n // highlighted row — the exact-match token override must NOT hijack it (else\n // ArrowDown to /clear-view + Enter would still fire the destructive /clear,\n // since \"clear\" exact-matches the token). Reset whenever the draft changes.\n const navigatedRef = useRef(false);\n const navTokenRef = useRef(value);\n if (navTokenRef.current !== value) {\n navTokenRef.current = value;\n navigatedRef.current = false;\n }\n\n const parsed = useMemo(() => parseCommandLine(value), [value]);\n const filterCtx = useMemo(\n () => ({\n sessionId: context?.sessionId ?? null,\n status: context?.status ?? null,\n permissions: context?.permissions ?? [],\n }),\n [context?.sessionId, context?.status, context?.permissions],\n );\n\n // In arg-hint mode (\"/name \"), the list collapses to the matched command so\n // the palette shows just its arg hint; while typing the name it filters.\n const activeCommand = useMemo(() => {\n if (!parsed || !parsed.hasTrailingSpace) {\n return null;\n }\n return matchCommand(commands, value);\n }, [commands, value, parsed]);\n\n const items = useMemo(() => {\n if (!parsed) {\n return [];\n }\n if (activeCommand) {\n return [activeCommand];\n }\n return filterCommands(commands, parsed.name, filterCtx);\n }, [commands, parsed, activeCommand, filterCtx]);\n\n const open = parsed !== null && items.length > 0 && !dismissed;\n\n // Whether the current draft is a slash-command ATTEMPT that should be run via\n // the palette, never delivered to the agent as plain chat. True even when the\n // palette is dismissed (Escape) — the draft still starts with \"/\" and matches\n // a command, so the composer must block its send path (button + Enter) to keep\n // commands from leaking into the conversation as messages the model reads.\n const isCommandDraft = parsed !== null && items.length > 0;\n\n // Keep highlight in range as items change.\n const clampedHighlight = items.length === 0 ? 0 : Math.min(highlight, items.length - 1);\n\n const activeArgHint = activeCommand ? argHint(activeCommand.args) : \"\";\n\n // Build the context for a SPECIFIC command. The danger confirm() is bound to\n // that command so the confirm bar names the command actually about to run —\n // not whatever near-match happens to sit highlighted in the palette (e.g.\n // typing \"/clear\"+Enter runs the destructive `clear`, but `clear-view` sorts\n // first and would otherwise mislabel the bar as a harmless local-view reset).\n const buildContext = useCallback(\n (command: SlashCommand): CommandContext | null => {\n if (!context) {\n return null;\n }\n return { ...context, ...handlers, confirm: () => handlers.confirm(command) };\n },\n [context, handlers],\n );\n\n const execute = useCallback(\n async (command: SlashCommand, args: string[]): Promise<void> => {\n const ctx = buildContext(command);\n if (!ctx) {\n return;\n }\n try {\n const result = await command.run(args, ctx);\n if (result.message) {\n ctx.notice({ tone: result.status === \"ok\" ? \"ok\" : \"error\", message: result.message });\n }\n if (result.status === \"ok\" && !result.keepDraft) {\n setValue(\"\");\n }\n } catch (cause) {\n ctx.notice({ tone: \"error\", message: errorMessage(cause) });\n }\n },\n [buildContext, setValue],\n );\n\n const autocomplete = useCallback(\n (command: SlashCommand) => {\n setValue(`/${command.name} `);\n setHighlight(0);\n },\n [setValue],\n );\n\n const autocompleteHighlighted = useCallback(() => {\n const command = items[clampedHighlight];\n if (command) {\n autocomplete(command);\n }\n }, [items, clampedHighlight, autocomplete]);\n\n // Resolve a SPECIFIC, already-chosen command against the current draft, then\n // either autocomplete (name-only / required arg missing) or execute. This is\n // the shared core for both Enter (which first resolves WHICH command via the\n // exact-match heuristic) and a pointer click (which has ALREADY chosen the\n // command — the clicked row — and must not re-resolve to a near-match).\n const runResolved = useCallback(\n async (command: SlashCommand, options?: { explicit?: boolean }): Promise<void> => {\n if (!parsed) {\n return;\n }\n const explicit = options?.explicit ?? false;\n // Token-vs-command equality is case-insensitive (matching the registry's\n // matchCommand/filterCommands), so a fully-typed \"/Clear\" counts as having\n // named `clear` and runs rather than autocompleting.\n const nameMatchesToken =\n command.name === parsed.name.toLowerCase() ||\n (command.aliases?.includes(parsed.name.toLowerCase()) ?? false);\n // A name-only token whose name doesn't yet equal the resolved command (e.g.\n // \"/cl\" -> clear) first autocompletes so the operator sees the full name.\n // An EXPLICIT pointer click skips this: the operator already chose the row,\n // so clicking \"/clear-view\" (while the token is \"clear\") runs it outright\n // rather than merely filling the name and waiting for a second Enter.\n if (!explicit && !activeCommand && !nameMatchesToken && !parsed.hasTrailingSpace) {\n autocomplete(command);\n return;\n }\n // When the click resolves a different command than the typed token, the\n // typed token's tail isn't this command's args — run with no positional\n // args and let the required-arg guard below prompt for them via autocomplete.\n const args = nameMatchesToken || parsed.hasTrailingSpace ? parsed.args : [];\n const missing = firstMissingRequiredArg(command, args);\n if (missing) {\n // A required arg is absent: keep the palette open at the arg hint rather\n // than firing a half-formed command.\n if (!parsed.hasTrailingSpace) {\n autocomplete(command);\n }\n return;\n }\n await execute(command, args);\n },\n [parsed, activeCommand, autocomplete, execute],\n );\n\n const runHighlighted = useCallback(async (): Promise<void> => {\n if (!parsed) {\n return;\n }\n // If the operator has arrow-navigated, Enter is an explicit choice of the\n // highlighted row — run it directly, exactly like a click. This makes\n // /clear-view reachable via ArrowDown+Enter even when \"/clear\" is fully\n // typed (otherwise the exact-match override below would hijack it).\n if (navigatedRef.current && !activeCommand) {\n const highlighted = items[clampedHighlight];\n if (highlighted) {\n await runResolved(highlighted, { explicit: true });\n }\n return;\n }\n // Otherwise (no explicit navigation): when the typed token is an exact\n // command name (e.g. \"/clear\" while the longer \"/clear-view\" sits first in\n // the filtered list), Enter should run THAT command, not autocomplete the\n // highlighted near-match. Exact match wins over the highlight; otherwise use\n // the highlighted row. A pointer click goes through runAt, never here.\n // Compare case-insensitively, matching filterCommands/matchCommand, so a\n // fully-typed \"/Clear\" still resolves to the exact (destructive) clear\n // rather than the highlighted prefix near-match.\n const token = parsed.name.toLowerCase();\n const exact = items.find((item) => item.name === token || item.aliases?.includes(token));\n const command = activeCommand ?? exact ?? items[clampedHighlight];\n if (!command) {\n return;\n }\n await runResolved(command);\n }, [parsed, activeCommand, items, clampedHighlight, runResolved]);\n\n // Run the command at an EXPLICITLY chosen index (a pointer click on a palette\n // row). Unlike runHighlighted this does NOT apply the exact-match override:\n // clicking the harmless `/clear-view` row while the draft is \"/clear\" must run\n // clear-view, never the destructive `/clear` that exact-matches the token. The\n // operator's pointer is the selection; token-resolution heuristics don't apply.\n const runAt = useCallback(\n async (index: number): Promise<void> => {\n const command = items[index];\n if (!command) {\n return;\n }\n await runResolved(command, { explicit: true });\n },\n [items, runResolved],\n );\n\n // Track an in-flight run so Enter can't double-fire.\n const runningRef = useRef(false);\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLTextAreaElement>): boolean => {\n if (!open) {\n return false;\n }\n switch (event.key) {\n case \"ArrowDown\": {\n event.preventDefault();\n navigatedRef.current = true;\n setHighlight((current) => (items.length === 0 ? 0 : (Math.min(current, items.length - 1) + 1) % items.length));\n return true;\n }\n case \"ArrowUp\": {\n event.preventDefault();\n navigatedRef.current = true;\n setHighlight((current) => {\n const base = Math.min(current, items.length - 1);\n return items.length === 0 ? 0 : (base - 1 + items.length) % items.length;\n });\n return true;\n }\n case \"Tab\": {\n event.preventDefault();\n autocompleteHighlighted();\n return true;\n }\n case \"Enter\": {\n if (event.shiftKey || event.nativeEvent?.isComposing) {\n return false;\n }\n event.preventDefault();\n if (runningRef.current) {\n return true;\n }\n runningRef.current = true;\n void runHighlighted().finally(() => {\n runningRef.current = false;\n });\n return true;\n }\n case \"Escape\": {\n event.preventDefault();\n // Close the palette but keep the draft intact. Remember the dismissed\n // value; the next edit re-opens (value !== dismissedValue).\n setDismissedValue(value);\n return true;\n }\n default:\n return false;\n }\n },\n [open, items, autocompleteHighlighted, runHighlighted, value],\n );\n\n return {\n open,\n isCommandDraft,\n items,\n highlight: clampedHighlight,\n setHighlight,\n activeCommand,\n activeArgHint,\n onKeyDown,\n runHighlighted,\n runAt,\n autocompleteHighlighted,\n };\n}\n\nfunction errorMessage(cause: unknown): string {\n if (cause instanceof Error) {\n return cause.message;\n }\n return String(cause);\n}\n","import { AnimatePresence, motion } from \"motion/react\";\nimport { argHint } from \"../commands/registry\";\nimport type { SlashCommand } from \"../commands/types\";\nimport { cn } from \"../lib/cn\";\n\nexport type CommandPaletteProps = {\n open: boolean;\n items: SlashCommand[];\n highlight: number;\n /** Hover/click selects a row. */\n onHighlight: (index: number) => void;\n /** Click runs the row (same path as Enter). */\n onRun: (index: number) => void;\n /** Footer arg hint shown in arg-hint mode (e.g. \"<pause|resume>\"). */\n argHintText: string;\n /** id used for aria-activedescendant wiring from the textarea. */\n listboxId: string;\n};\n\n/**\n * The slash-command palette: a popover anchored above the textarea, rendered\n * entirely from the filtered registry. Dark-first, Linear/Vercel-calm, using\n * the opengeni#46 design tokens. Full keyboard nav lives in useSlashCommands;\n * this component is presentational + aria.\n */\nexport function CommandPalette({ open, items, highlight, onHighlight, onRun, argHintText, listboxId }: CommandPaletteProps) {\n return (\n <AnimatePresence>\n {open ? (\n <motion.div\n initial={{ opacity: 0, y: 6, scale: 0.99 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={{ opacity: 0, y: 6, scale: 0.99 }}\n transition={{ duration: 0.13, ease: \"easeOut\" }}\n className={cn(\n \"absolute bottom-full left-0 right-0 z-20 mb-2 overflow-hidden\",\n \"rounded-og-lg border border-og-border bg-og-surface-2 shadow-og-sm\",\n )}\n >\n <ul\n id={listboxId}\n role=\"listbox\"\n aria-label=\"Slash commands\"\n className=\"max-h-72 overflow-y-auto py-1\"\n >\n {items.map((command, index) => {\n const selected = index === highlight;\n const hint = argHint(command.args);\n return (\n <li\n key={command.name}\n id={`${listboxId}-option-${index}`}\n role=\"option\"\n aria-selected={selected}\n onMouseEnter={() => onHighlight(index)}\n onMouseDown={(event) => {\n // Keep textarea focus; run on click.\n event.preventDefault();\n onRun(index);\n }}\n className={cn(\n \"mx-1 flex cursor-pointer items-center gap-2 rounded-og-md px-2.5 py-1.5\",\n \"transition-colors duration-100\",\n selected ? \"bg-og-accent/15 text-og-fg\" : \"text-og-fg-muted hover:bg-og-surface-3\",\n )}\n >\n <span className=\"flex min-w-0 items-baseline gap-1.5\">\n <span className={cn(\"font-mono text-[13px]\", selected ? \"text-og-accent\" : \"text-og-fg\")}>\n /{command.name}\n </span>\n {hint ? <span className=\"truncate font-mono text-[11px] text-og-fg-subtle\">{hint}</span> : null}\n </span>\n <span className=\"ml-auto flex items-center gap-1.5\">\n {command.danger ? (\n <span className=\"rounded-og-xs bg-og-status-failed/15 px-1 text-[10px] uppercase tracking-wide text-og-status-failed\">\n danger\n </span>\n ) : null}\n <span className=\"truncate text-[12px] text-og-fg-subtle max-sm:hidden\">{command.description}</span>\n </span>\n </li>\n );\n })}\n </ul>\n {argHintText ? (\n <div className=\"border-t border-og-border px-3 py-1.5 font-mono text-[11px] text-og-fg-subtle\">\n {argHintText}\n </div>\n ) : null}\n </motion.div>\n ) : null}\n </AnimatePresence>\n );\n}\n","import type { ClientModel, SessionStatus } from \"@opengeni/sdk\";\nimport { ArrowUpIcon, FileIcon, ImageIcon, LoaderCircleIcon, PaperclipIcon, RotateCwIcon, SquareIcon, XIcon } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { useCallback, useEffect, useId, useMemo, useRef, useState, type ChangeEvent, type ClipboardEvent, type DragEvent, type KeyboardEvent, type ReactNode, type RefObject } from \"react\";\nimport { argHint } from \"../commands/registry\";\nimport type { Notice, SlashCommand } from \"../commands/types\";\nimport type { ComposerState } from \"../hooks/use-composer\";\nimport { shouldSubmitOnKey } from \"../hooks/use-composer\";\nimport type { UseFileAttachmentsResult } from \"../hooks/use-file-attachments\";\nimport { defaultCommands } from \"../commands/registry\";\nimport { useSlashCommands, type ConfirmState, type SlashCommandContext } from \"../hooks/use-slash-commands\";\nimport { cn } from \"../lib/cn\";\nimport { formatBytes } from \"../lib/format\";\nimport { CommandPalette } from \"./command-palette\";\nimport { ModelPicker } from \"./model-picker\";\n\nexport type ChatComposerProps = {\n composer: ComposerState;\n /** Current session status; shows the stop control while a turn runs. */\n status?: SessionStatus | null | undefined;\n placeholder?: string | undefined;\n disabled?: boolean | undefined;\n autoFocus?: boolean | undefined;\n /** Replaces the default keyboard hint under the field. */\n hint?: string | undefined;\n /** App controls (model picker, attach button, ...) in the footer row, replacing the hint. */\n controlsStart?: ReactNode | undefined;\n /** Content rendered above the textarea, inside the field chrome (e.g. attachment chips). */\n header?: ReactNode | undefined;\n /** Paste hook on the textarea (e.g. paste-image-to-attach). */\n onPaste?: ((event: ClipboardEvent<HTMLTextAreaElement>) => void) | undefined;\n /**\n * Opt-in file attachments. When supplied (e.g. from {@link useFileAttachments}),\n * the composer renders a built-in attach button (prepended to `controlsStart`),\n * an attachment-chips strip (above the textarea, before any host `header`),\n * routes paste through `addFromPaste` (image/* filter lives in the hook), and\n * gates send while `uploading` so a message never departs without its files.\n * Absent → no attachment UI renders and the composer behaves exactly as before.\n */\n attachments?: UseFileAttachmentsResult | undefined;\n /**\n * Opt-in model picker. When supplied (e.g. from {@link useAvailableModels}),\n * the composer renders a {@link ModelPicker} at the start of `controlsStart`\n * so the operator can choose which host-exposed model serves the next message.\n * The host owns the selection (`selectedModel`/`onSelectModel`) and is\n * responsible for threading it into the composer's `sendExtras` (typically\n * `useComposer({ sendExtras: () => ({ model }) })`) so `composeSendInput`\n * carries it. Absent → no picker renders and the composer behaves as before.\n */\n models?: ClientModel[] | undefined;\n /** The currently selected model id (the picker's controlled value). */\n selectedModel?: string | undefined;\n /** Called with the chosen model id when the operator picks one. */\n onSelectModel?: ((modelId: string) => void) | undefined;\n className?: string | undefined;\n /**\n * Slash-command palette. Defaults to the built-in {@link defaultCommands};\n * apps concat their own. Backward-compatible: when `commandContext` is absent\n * the palette is inert and behavior is identical to before.\n */\n commands?: readonly SlashCommand[] | undefined;\n /**\n * Wiring the palette needs to run server commands and gate visibility. The\n * composer supplies notice/openHelp/clearView/confirm internally.\n */\n commandContext?: SlashCommandContext | undefined;\n /** Reset the local timeline view (the /clear-view command target). */\n onClearView?: (() => void) | undefined;\n};\n\nconst ACTIVE_STATUSES: ReadonlySet<SessionStatus> = new Set([\"queued\", \"running\"]);\n\n/**\n * The chat composer — the only human-to-agent input surface. Plain chat in,\n * everything else is the agent's job. Enter sends, Shift+Enter breaks the\n * line, and the stop control appears while a turn is running (sending while\n * running is legitimate steering, so send stays available too).\n *\n * Typing a leading \"/\" opens the slash-command palette — SESSION/OPERATOR\n * controls (clear, compact, pause goal, help), never a structured channel to\n * the agent. The palette is purely additive: with no `commandContext` it is\n * inert and the composer behaves exactly as before.\n */\nexport function ChatComposer({\n composer,\n status,\n placeholder,\n disabled,\n autoFocus,\n hint,\n controlsStart,\n header,\n onPaste,\n attachments,\n models,\n selectedModel,\n onSelectModel,\n className,\n commands = defaultCommands,\n commandContext,\n onClearView,\n}: ChatComposerProps) {\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n const active = status != null && ACTIVE_STATUSES.has(status);\n\n // Block sends while attachments are still uploading so a message never\n // departs without the files the user attached to it. This gates BOTH the\n // Enter-to-send path (which calls composer.send directly, bypassing canSend)\n // and the send button — dropping either path could ship a fileless message.\n const blockedByUpload = attachments?.uploading === true;\n\n // A ready attachment makes a file-only message (empty draft) sendable. The\n // composer (when wired with `sendExtras.resources`) already reflects this in\n // `canSend`; we OR it in here too so send-enablement is correct even for a\n // composer whose canSend doesn't know about attachments — and so this stays\n // the single home of the attachment send-gate.\n const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;\n // The send affordance: text OR a ready attachment, never mid-upload or mid-send.\n const canSend = (composer.canSend || hasReadyAttachment) && !blockedByUpload && !composer.sending;\n\n // Drag-and-drop file attach: only a drop target when `attachments` is wired,\n // and only reacts to drags that actually carry files (so it never hijacks\n // normal text drag/drop). `dragging` drives the drop overlay.\n const [dragging, setDragging] = useState(false);\n const dragCarriesFiles = (event: { dataTransfer: DataTransfer | null }): boolean =>\n event.dataTransfer != null && [...event.dataTransfer.types].includes(\"Files\");\n const handleDragOver = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (!attachments || !dragCarriesFiles(event)) {\n return;\n }\n // preventDefault marks this a valid drop target so the browser fires drop.\n event.preventDefault();\n setDragging(true);\n },\n [attachments],\n );\n const handleDragLeave = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (!attachments) {\n return;\n }\n // Ignore leaves bubbling from children: only clear when the pointer left\n // the composer bounds entirely (the related target is outside it).\n if (event.currentTarget.contains(event.relatedTarget as Node | null)) {\n return;\n }\n setDragging(false);\n },\n [attachments],\n );\n const handleDrop = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (!attachments || !dragCarriesFiles(event)) {\n return;\n }\n event.preventDefault();\n setDragging(false);\n // Same path the picker uses: addFiles accepts ALL files (no image filter).\n if (event.dataTransfer.files.length > 0) {\n attachments.addFiles(event.dataTransfer.files);\n }\n },\n [attachments],\n );\n\n const [notice, setNotice] = useState<Notice | null>(null);\n const [helpOpen, setHelpOpen] = useState(false);\n const [confirmState, setConfirmState] = useState<ConfirmState>(null);\n const listboxId = useId();\n\n const resize = useCallback(() => {\n const textarea = textareaRef.current;\n if (!textarea) {\n return;\n }\n textarea.style.height = \"0px\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, 220)}px`;\n }, []);\n\n useEffect(() => {\n resize();\n }, [composer.value, resize]);\n\n // The UI affordances commands reach: surface a notice, open the help panel,\n // reset the local view, and the danger confirm flow (resolves when the\n // operator confirms/cancels in the confirm bar).\n const handlers = useMemo(\n () => ({\n notice: (next: Notice) => {\n setNotice(next);\n composer.clearError();\n },\n openHelp: () => setHelpOpen(true),\n // Report whether a view-reset was actually wired by the host: with no\n // onClearView the command is a no-op and must say so (not a false success).\n clearView: () => {\n if (!onClearView) {\n return false;\n }\n onClearView();\n return true;\n },\n // The hook binds the command actually being run into confirm() (see\n // use-slash-commands buildContext), so the confirm bar renders from THAT\n // command — never a near-match highlighted in the palette. This is what\n // keeps the destructive /clear from being mislabeled as /clear-view.\n confirm: (command: SlashCommand) =>\n new Promise<boolean>((resolve) => {\n setConfirmState({\n command,\n resolve: (confirmed) => {\n setConfirmState(null);\n resolve(confirmed);\n },\n });\n }),\n }),\n [composer, onClearView],\n );\n\n const palette = useSlashCommands({\n commands,\n context: commandContext,\n handlers,\n value: composer.value,\n setValue: composer.setValue,\n });\n\n // The confirm bar renders from the command the hook is actually running —\n // carried into confirmState by handlers.confirm — NOT a near-match that\n // happens to be highlighted/active in the palette. (Re-deriving it from\n // palette.items[palette.highlight] mislabeled the destructive /clear as the\n // harmless /clear-view, since clear-view prefix-matches \"clear\" and sorts\n // first.)\n const pendingDangerCommand = confirmState ? confirmState.command : null;\n\n const paletteEnabled = commandContext !== undefined;\n\n // A slash-command draft must never be delivered to the agent as chat — it is\n // an operator control, not a message. The palette consumes Enter while open,\n // but after Escape the popover is closed yet the draft still matches a command;\n // block the send path (here and on the send button) so \"/clear\" can't be sent.\n const commandDraftBlocked = paletteEnabled && palette.isCommandDraft;\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n // Palette key handling runs FIRST and only when the palette is open; when\n // closed it returns false and the existing send path is untouched.\n if (paletteEnabled && palette.onKeyDown(event)) {\n return;\n }\n if (shouldSubmitOnKey(event)) {\n event.preventDefault();\n if (commandDraftBlocked) {\n // Dismissed palette + a \"/command\" draft: don't send it as chat. Nudge\n // the operator to re-open the palette (any edit re-opens it) or clear it.\n setNotice({ tone: \"error\", message: \"That's a slash command — press Enter in the command list to run it, or edit the line to send a message.\" });\n return;\n }\n if (blockedByUpload) {\n // Files are still uploading: swallow the Enter so the message can't\n // depart without them. The send button is disabled in the same state.\n return;\n }\n void composer.send();\n }\n };\n\n // The host's onPaste still fires (model/tool/whatever paste handling); when\n // attachments are wired, also feed the clipboard through addFromPaste so the\n // image/* filter (owned by the hook) attaches pasted images.\n const handlePaste = useCallback(\n (event: ClipboardEvent<HTMLTextAreaElement>) => {\n onPaste?.(event);\n attachments?.addFromPaste(event);\n },\n [onPaste, attachments],\n );\n\n const handleFileChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n if (event.target.files) {\n attachments?.addFiles(event.target.files);\n }\n event.target.value = \"\";\n },\n [attachments],\n );\n\n const helpCommands = useMemo(\n () =>\n commands.filter((command) => {\n if (command.permission && commandContext) {\n const perms = commandContext.permissions;\n return perms.includes(command.permission) || perms.includes(\"workspace:admin\");\n }\n return true;\n }),\n [commands, commandContext],\n );\n\n const activeNotice = notice ?? (composer.error ? { tone: \"error\" as const, message: composer.error.message || \"Sending failed — your draft is still here. Try again.\" } : null);\n\n return (\n // Respect the iOS home-indicator inset so the sticky composer never sits\n // under it (0 on non-notch devices and desktop, so it's inert there).\n <div className={cn(\"og-root\", className)} style={{ paddingBottom: \"env(safe-area-inset-bottom)\" }}>\n <div className=\"relative\">\n {paletteEnabled ? (\n <CommandPalette\n open={palette.open && confirmState === null}\n items={palette.items}\n highlight={palette.highlight}\n onHighlight={palette.setHighlight}\n onRun={(index) => {\n // Run the CLICKED row directly. We must not route a pointer click\n // through runHighlighted: its exact-match override would re-resolve\n // \"/clear\" to the destructive clear even when the operator clicked\n // the harmless clear-view row. runAt honors the explicit selection.\n palette.setHighlight(index);\n void palette.runAt(index);\n }}\n argHintText={palette.activeArgHint}\n listboxId={listboxId}\n />\n ) : null}\n <div\n // Drag-and-drop file attach lives on the field wrapper, but only when\n // `attachments` is wired — without it the composer is not a drop target\n // and behaves exactly as before.\n onDragOver={attachments ? handleDragOver : undefined}\n onDragLeave={attachments ? handleDragLeave : undefined}\n onDrop={attachments ? handleDrop : undefined}\n className={cn(\n \"relative rounded-og-lg border border-og-border bg-og-surface-1 shadow-og-sm\",\n \"transition-[border-color,box-shadow] duration-200\",\n \"focus-within:border-og-accent/60 focus-within:shadow-og-glow\",\n // While files are dragged over, swap to a dashed accent border to\n // signal a live drop target (the overlay carries the label).\n dragging && \"border-dashed border-og-accent\",\n )}\n >\n {dragging ? (\n <div\n aria-hidden\n className={cn(\n \"pointer-events-none absolute inset-0 z-10 flex items-center justify-center\",\n \"rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]\",\n )}\n >\n <span className=\"inline-flex items-center gap-2\">\n <PaperclipIcon className=\"size-4\" />\n Drop files to attach\n </span>\n </div>\n ) : null}\n {attachments && attachments.attachments.length > 0 ? (\n <AttachmentChips\n attachments={attachments.attachments}\n onRemove={attachments.remove}\n onRetry={attachments.retry}\n />\n ) : null}\n {header}\n <textarea\n ref={textareaRef}\n rows={1}\n value={composer.value}\n onChange={(event) => composer.setValue(event.target.value)}\n onKeyDown={onKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder ?? \"Message the agent…\"}\n disabled={disabled}\n autoFocus={autoFocus}\n aria-label=\"Message the agent\"\n role={paletteEnabled && palette.open ? \"combobox\" : undefined}\n aria-expanded={paletteEnabled ? palette.open : undefined}\n aria-controls={paletteEnabled && palette.open ? listboxId : undefined}\n aria-activedescendant={paletteEnabled && palette.open ? `${listboxId}-option-${palette.highlight}` : undefined}\n className={cn(\n // Font size steps up to 16px below `md` so iOS never zooms the\n // viewport on focus; desktop keeps the 15px og-md rhythm.\n \"block w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-base leading-6 md:text-og-md\",\n // The wrapper owns the whole-composer focus affordance (focus-within\n // border + soft glow). Suppress any self-scoped focus outline on the\n // textarea itself: `focus:outline-none` alone only sets outline-style\n // on `:focus`, which a host app's zero-specificity\n // `:where(...):focus-visible { outline: ... }` base rule re-applies as\n // the full shorthand. `focus-visible:outline-none` matches the same\n // state at class specificity and wins, so no second highlight (the\n // top-half rectangle bounded to the textarea box) ever paints.\n \"text-og-fg placeholder:text-og-fg-subtle focus:outline-none focus-visible:outline-none\",\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n )}\n />\n {confirmState && pendingDangerCommand ? (\n <ConfirmBar\n command={pendingDangerCommand}\n onCancel={() => confirmState.resolve(false)}\n onConfirm={() => confirmState.resolve(true)}\n returnFocusRef={textareaRef}\n />\n ) : (\n <div className=\"flex items-end gap-2 px-2.5 pb-2.5 pt-1\">\n {attachments || models || controlsStart ? (\n // The control group wraps onto extra rows when it can't fit\n // (narrow viewports) instead of clipping under the rounded\n // corner; send/stop stays anchored bottom-right (shrink-0).\n <span className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n {attachments ? (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n onChange={handleFileChange}\n />\n <button\n type=\"button\"\n disabled={disabled === true}\n onClick={() => fileInputRef.current?.click()}\n aria-label=\"Attach files\"\n title=\"Attach files\"\n className={cn(\n \"inline-flex size-8 items-center justify-center rounded-og-md\",\n \"text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n )}\n >\n <PaperclipIcon className=\"size-4\" />\n </button>\n </>\n ) : null}\n {models ? (\n <ModelPicker\n models={models}\n value={selectedModel}\n onChange={(modelId) => onSelectModel?.(modelId)}\n disabled={disabled === true}\n />\n ) : null}\n {controlsStart}\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 px-1.5 text-og-xs text-og-fg-subtle max-sm:hidden\">\n {hint ?? \"Enter to send · Shift+Enter for a new line · / for commands\"}\n </span>\n )}\n <span className=\"ml-auto flex shrink-0 items-center gap-1.5\">\n <AnimatePresence initial={false}>\n {active ? (\n <motion.button\n key=\"stop\"\n type=\"button\"\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() => void composer.interrupt()}\n disabled={composer.interrupting}\n aria-label=\"Stop the current turn\"\n title=\"Stop the current turn\"\n className={cn(\n \"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border pointer-coarse:size-11\",\n \"bg-og-surface-2 text-og-fg-muted transition-colors duration-150\",\n \"hover:border-og-status-failed/50 hover:text-og-status-failed\",\n \"disabled:opacity-50\",\n )}\n >\n {composer.interrupting ? (\n <LoaderCircleIcon className=\"size-3.5 animate-og-spin\" />\n ) : (\n <SquareIcon className=\"size-3 fill-current\" />\n )}\n </motion.button>\n ) : null}\n </AnimatePresence>\n <button\n type=\"button\"\n onClick={() => {\n if (blockedByUpload) {\n return;\n }\n void composer.send();\n }}\n disabled={!canSend || disabled === true || commandDraftBlocked}\n aria-label=\"Send message\"\n className={cn(\n \"inline-flex size-8 items-center justify-center rounded-og-md pointer-coarse:size-11\",\n \"bg-og-accent text-og-accent-fg shadow-og-sm\",\n \"transition-[background-color,transform,opacity] duration-150 ease-og-spring\",\n \"hover:bg-og-accent-strong active:scale-95\",\n \"disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none\",\n )}\n >\n {composer.sending ? <LoaderCircleIcon className=\"size-4 animate-og-spin\" /> : <ArrowUpIcon className=\"size-4\" />}\n </button>\n </span>\n </div>\n )}\n </div>\n </div>\n <AnimatePresence>\n {helpOpen ? (\n <HelpPanel commands={helpCommands} onClose={() => setHelpOpen(false)} />\n ) : null}\n </AnimatePresence>\n <AnimatePresence>\n {activeNotice ? (\n <motion.p\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: \"auto\" }}\n exit={{ opacity: 0, height: 0 }}\n className={cn(\n \"overflow-hidden px-1 pt-1.5 text-xs\",\n activeNotice.tone === \"ok\" ? \"text-og-fg-muted\" : \"text-og-status-failed\",\n )}\n role={activeNotice.tone === \"error\" ? \"alert\" : \"status\"}\n onAnimationComplete={() => {\n if (activeNotice.tone === \"ok\") {\n // Auto-dismiss success notices after a beat.\n window.setTimeout(() => setNotice((current) => (current === activeNotice ? null : current)), 2400);\n }\n }}\n >\n {activeNotice.message}\n </motion.p>\n ) : null}\n </AnimatePresence>\n </div>\n );\n}\n\n/**\n * The danger confirm bar — reuses og-status-failed tokens (like the stop\n * control). Inline (not a modal) but keyboard-complete: Escape cancels, focus\n * moves to the primary action when it appears and returns to the composer on\n * dismiss, and the primary button names the action rather than a bare \"Confirm\".\n */\nfunction ConfirmBar({\n command,\n onCancel,\n onConfirm,\n returnFocusRef,\n}: {\n command: SlashCommand;\n onCancel: () => void;\n onConfirm: () => void;\n /** Focus returns here when the bar dismisses (the composer textarea). */\n returnFocusRef?: RefObject<HTMLTextAreaElement | null> | undefined;\n}) {\n const confirmRef = useRef<HTMLButtonElement | null>(null);\n const descriptionId = useId();\n useEffect(() => {\n const returnTo = returnFocusRef?.current ?? null;\n confirmRef.current?.focus();\n return () => {\n returnTo?.focus();\n };\n }, [returnFocusRef]);\n return (\n <div\n role=\"alertdialog\"\n aria-label={`Confirm /${command.name}`}\n aria-describedby={descriptionId}\n data-testid=\"danger-confirm\"\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n onCancel();\n }\n }}\n className=\"flex items-end justify-between gap-2 px-2.5 pb-2.5 pt-1\"\n >\n <span id={descriptionId} className=\"min-w-0 flex-1 px-1.5 text-og-sm text-og-status-failed\">\n Run <span className=\"font-mono\">/{command.name}</span>? {command.description}\n </span>\n <span className=\"flex shrink-0 items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-og-md border border-og-border bg-og-surface-2 px-2.5 py-1 text-og-sm text-og-fg-muted hover:bg-og-surface-3 pointer-coarse:min-h-10\"\n >\n Cancel\n </button>\n <button\n ref={confirmRef}\n type=\"button\"\n onClick={onConfirm}\n className=\"rounded-og-md border border-og-status-failed/50 bg-og-status-failed/15 px-2.5 py-1 text-og-sm text-og-status-failed hover:bg-og-status-failed/25 pointer-coarse:min-h-10\"\n >\n Run /{command.name}\n </button>\n </span>\n </div>\n );\n}\n\n/**\n * The attachment-chips strip rendered above the textarea while files are\n * attached. Each chip shows an image preview (or a type icon), the filename,\n * an upload/size/failed status line, and a remove control. A failed upload\n * surfaces its actual error (inline, full text on hover via `title`) and offers\n * a retry alongside remove — a failed attachment never blocks send (only an\n * in-progress upload does), and removing it clears the way. Styled with the\n * package's og-* tokens so it themes in any consumer.\n */\nfunction AttachmentChips({ attachments, onRemove, onRetry }: {\n attachments: UseFileAttachmentsResult[\"attachments\"];\n onRemove: (id: string) => void;\n onRetry?: ((id: string) => void) | undefined;\n}) {\n return (\n <div className=\"flex flex-wrap gap-2 border-b border-og-border px-3 py-2\">\n {attachments.map((attachment) => {\n const failed = attachment.status === \"failed\";\n const statusText = attachment.status === \"uploading\"\n ? \"Uploading\"\n : failed\n ? attachment.error || \"Upload failed\"\n : formatBytes(attachment.sizeBytes);\n return (\n <div\n key={attachment.id}\n className={cn(\n \"flex min-w-0 max-w-[240px] items-center gap-2 rounded-og-md border px-2 py-1.5 text-og-sm\",\n failed ? \"border-og-status-failed/40 bg-og-status-failed/10\" : \"border-og-border bg-og-surface-2\",\n )}\n >\n {attachment.previewUrl ? (\n <img src={attachment.previewUrl} alt=\"\" className=\"size-8 shrink-0 rounded object-cover\" />\n ) : attachment.contentType.startsWith(\"image/\") ? (\n <ImageIcon className=\"size-4 shrink-0 text-og-fg-muted\" />\n ) : (\n <FileIcon className=\"size-4 shrink-0 text-og-fg-muted\" />\n )}\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate font-medium text-og-fg\">{attachment.name}</div>\n <div\n className={cn(\"truncate text-og-xs\", failed ? \"text-og-status-failed\" : \"text-og-fg-subtle\")}\n title={failed ? statusText : undefined}\n >\n {statusText}\n </div>\n </div>\n {attachment.status === \"uploading\" ? <LoaderCircleIcon className=\"size-3.5 shrink-0 animate-og-spin\" /> : null}\n {failed && onRetry ? (\n <button\n type=\"button\"\n onClick={() => onRetry(attachment.id)}\n className=\"shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-8\"\n aria-label={`Retry ${attachment.name}`}\n title=\"Retry upload\"\n >\n <RotateCwIcon className=\"size-3.5\" />\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={() => onRemove(attachment.id)}\n className=\"shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-8\"\n aria-label={`Remove ${attachment.name}`}\n >\n <XIcon className=\"size-3.5\" />\n </button>\n </div>\n );\n })}\n </div>\n );\n}\n\n/** The in-composer /help panel, rendered entirely from the registry. */\nfunction HelpPanel({ commands, onClose }: { commands: readonly SlashCommand[]; onClose: () => void }) {\n return (\n <motion.div\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: \"auto\" }}\n exit={{ opacity: 0, height: 0 }}\n className=\"mt-2 overflow-hidden rounded-og-lg border border-og-border bg-og-surface-2\"\n >\n <div className=\"flex items-center justify-between border-b border-og-border px-3 py-1.5\">\n <span className=\"text-og-sm font-medium text-og-fg\">Commands</span>\n <button type=\"button\" onClick={onClose} className=\"text-og-xs text-og-fg-subtle hover:text-og-fg\">\n Close\n </button>\n </div>\n <ul className=\"py-1\">\n {commands.map((command) => {\n const hint = argHint(command.args);\n return (\n <li key={command.name} className=\"flex items-baseline gap-2 px-3 py-1\">\n <span className=\"font-mono text-og-sm text-og-accent\">\n /{command.name}\n {hint ? <span className=\"ml-1 text-og-fg-subtle\">{hint}</span> : null}\n </span>\n <span className=\"text-og-sm text-og-fg-muted\">{command.description}</span>\n {command.danger ? (\n <span className=\"ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-og-xs uppercase tracking-wide text-og-status-failed\">\n danger\n </span>\n ) : null}\n </li>\n );\n })}\n </ul>\n </motion.div>\n );\n}\n","import type { ClientModel } from \"@opengeni/sdk\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport { useId, useMemo } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type ModelPickerProps = {\n /** The host-exposed models to choose from (typically {@link useAvailableModels}). */\n models: ClientModel[];\n /** Controlled selection — the model id, or undefined for \"nothing chosen yet\". */\n value?: string | undefined;\n /** Called with the chosen model id when the operator picks a row. */\n onChange: (modelId: string) => void;\n disabled?: boolean | undefined;\n className?: string | undefined;\n};\n\n/**\n * The model picker — a compact dropdown for the composer footer, grouping the\n * host-exposed models by `providerLabel` (so \"OpenAI\" and \"Fireworks AI\" head\n * their own sections) and showing each model's display `label`. A native\n * `<select>` keeps it keyboard- and screen-reader-accessible for free and\n * themes via the package's og-* tokens; the chevron is a decorative overlay.\n *\n * Controlled: the host owns `value`/`onChange` and threads the selection into\n * the send path. Renders nothing when no models are exposed, so a single-model\n * deployment shows no chrome.\n */\nexport function ModelPicker({ models, value, onChange, disabled, className }: ModelPickerProps) {\n const selectId = useId();\n // Group by provider, preserving first-seen order for both the providers and\n // the models within each — the server already orders the list (default model\n // and built-in provider first), so we must not re-sort it.\n const groups = useMemo(() => {\n const byProvider = new Map<string, { label: string; models: ClientModel[] }>();\n for (const model of models) {\n let group = byProvider.get(model.provider);\n if (!group) {\n group = { label: model.providerLabel, models: [] };\n byProvider.set(model.provider, group);\n }\n group.models.push(model);\n }\n return [...byProvider.values()];\n }, [models]);\n\n if (models.length === 0) {\n return null;\n }\n\n return (\n <span className={cn(\"relative inline-flex items-center\", className)}>\n <label htmlFor={selectId} className=\"sr-only\">\n Model\n </label>\n <select\n id={selectId}\n value={value ?? \"\"}\n onChange={(event) => onChange(event.target.value)}\n disabled={disabled === true}\n aria-label=\"Model\"\n className={cn(\n // Sized like the other footer controls; the chevron overlay needs the\n // right padding so the value never collides with it.\n \"h-8 max-w-[180px] cursor-pointer appearance-none truncate rounded-og-md bg-transparent\",\n \"py-0 pl-2 pr-6 text-[13px] text-og-fg-muted\",\n \"transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg\",\n \"focus:outline-none focus-visible:outline-none\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n )}\n >\n {groups.map((group) => (\n <optgroup key={group.label} label={group.label}>\n {group.models.map((model) => (\n <option key={model.id} value={model.id}>\n {model.label}\n </option>\n ))}\n </optgroup>\n ))}\n </select>\n <ChevronDownIcon\n aria-hidden\n className=\"pointer-events-none absolute right-1.5 size-3.5 text-og-fg-subtle\"\n />\n </span>\n );\n}\n","import type { SessionEvent, SessionStatus } from \"@opengeni/sdk\";\nimport {\n ArrowDownIcon,\n ArrowRightIcon,\n CheckIcon,\n PauseIcon,\n PencilLineIcon,\n PlayIcon,\n TargetIcon,\n TriangleAlertIcon,\n} from \"lucide-react\";\nimport type { ComponentType } from \"react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { formatRelativeTime, truncate } from \"../lib/format\";\nimport { Markdown } from \"./markdown\";\nimport {\n ActivityRail,\n buildTimeline,\n defaultToolRegistry,\n groupTimeline,\n LightboxProvider,\n type ActivityItem,\n type AgentMessageItem,\n type GoalItem,\n type NoticeItem,\n type TimelineGroup,\n type TimelineItem,\n type ToolRegistry,\n type UserMessageItem,\n TurnSummary,\n} from \"../timeline\";\nimport { SESSION_STATUS_META, StatusDot } from \"./session-status\";\nimport { EntranceAnimationProvider, useEntranceAnimation } from \"../timeline/entrance\";\n\nexport type MessageTimelineProps = {\n /** Raw session events (projected internally) … */\n events?: SessionEvent[] | undefined;\n /** … or pre-projected items (e.g. from `useSessionEvents().timeline`). */\n items?: TimelineItem[] | undefined;\n /** Current session status; drives the live \"working\" indicator. */\n status?: SessionStatus | null | undefined;\n /** Plug a markdown renderer for message bodies (e.g. streamdown). */\n renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined;\n /** Drill into a spawned worker session. */\n onOpenSession?: ((sessionId: string) => void) | undefined;\n /**\n * The tool-renderer registry that resolves how each tool call is drawn.\n * Defaults to {@link defaultToolRegistry}; pass a registry from\n * `createDefaultToolRegistry({ entries })` to add custom tool renderers.\n */\n toolRegistry?: ToolRegistry | undefined;\n /** Follow new events when pinned to the bottom. Defaults to true. */\n autoFollow?: boolean | undefined;\n /** Older durable history exists above the current window (see useSessionEvents). */\n hasOlder?: boolean | undefined;\n /** An older window is being fetched; shows the quiet top shimmer. */\n loadingOlder?: boolean | undefined;\n /** Called when the reader nears the top and older history should backfill. */\n onLoadOlder?: (() => void) | undefined;\n emptyState?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n/**\n * The session timeline: chat messages with streaming deltas, collapsed\n * activity clusters (reasoning, tool calls, sandbox work), spawned-worker\n * cards, goal markers, and status transitions. Owns stick-to-bottom scrolling\n * with a \"jump to latest\" affordance when the reader scrolls back.\n */\nexport function MessageTimeline({\n events,\n items,\n status,\n renderMessageText,\n onOpenSession,\n toolRegistry = defaultToolRegistry,\n autoFollow = true,\n hasOlder = false,\n loadingOlder = false,\n onLoadOlder,\n emptyState,\n className,\n}: MessageTimelineProps) {\n const resolvedItems = useMemo(() => items ?? buildTimeline(events ?? []), [items, events]);\n const groups = useMemo(() => groupTimeline(resolvedItems), [resolvedItems]);\n const firstGroupKey = groups[0] ? timelineGroupKey(groups[0]) : null;\n\n const scrollRef = useRef<HTMLDivElement | null>(null);\n const topSentinelRef = useRef<HTMLDivElement | null>(null);\n const previousBulkFirstKeyRef = useRef<string | null | undefined>(undefined);\n const [pinned, setPinned] = useState(true);\n const [bulkActive, setBulkActive] = useState(true);\n // Content stays invisible until its first bottom-anchored frame, so a flash\n // of the window's TOP while a large timeline lays out across commits is\n // structurally impossible — the reader only ever sees it already at the\n // bottom. An empty timeline reveals immediately (there is nothing to anchor).\n const [revealed, setRevealed] = useState(false);\n // Our own scrollTop assignments echo back as scroll events; those must never\n // UNPIN the reader (they are not reader intent). Marked around every\n // programmatic assignment and consumed by onScroll. When an assignment is a\n // NO-OP (already at the target) no scroll event will fire, so the mark must\n // self-clear — a stale mark would eat the reader's next real scroll-up.\n const programmaticScrollRef = useRef(false);\n const assignScrollTop = useCallback((node: HTMLElement, value: number) => {\n const previous = node.scrollTop;\n programmaticScrollRef.current = true;\n node.scrollTop = value;\n if (node.scrollTop === previous) {\n programmaticScrollRef.current = false;\n }\n }, []);\n // Mirror `pinned` into a ref so the ResizeObserver callback (a stable closure)\n // always reads the live value without re-subscribing on every scroll.\n const pinnedRef = useRef(true);\n // The reader's visual anchor: the topmost still-visible timeline element and\n // its offset from the viewport top. Recaptured on scroll and after every\n // height change, it lets us hold the reader's position when content above the\n // viewport expands or collapses (e.g. a turn folds when it settles).\n const anchorRef = useRef<{ el: Element; top: number } | null>(null);\n const lastItem = resolvedItems[resolvedItems.length - 1];\n const streaming = lastItem !== undefined && (lastItem.kind === \"agent-message\" || lastItem.kind === \"reasoning\") && lastItem.streaming;\n const working = status === \"running\" && !streaming;\n // Bulk paints (the initial tail window, a prepended older window — detected\n // by the first group key changing) must not run per-row entrance animations.\n const firstKeyChangedForBulk = previousBulkFirstKeyRef.current !== undefined && previousBulkFirstKeyRef.current !== firstGroupKey;\n const bulkRender = groups.length > 0 && (bulkActive || firstKeyChangedForBulk);\n\n // Snapshot the topmost visible element and where it sits in the viewport, so a\n // later reflow can restore it to the same spot. Transient chrome (the backfill\n // sentinel and shimmer) is skipped — anchoring to a row that unmounts when the\n // older window lands would drop the correction mid-prepend.\n const captureAnchor = useCallback(() => {\n const node = scrollRef.current;\n const inner = node?.firstElementChild;\n if (!node || !inner) {\n anchorRef.current = null;\n return;\n }\n const containerTop = node.getBoundingClientRect().top;\n for (const child of Array.from(inner.children)) {\n if (child instanceof HTMLElement && child.dataset.ogTimelineChrome !== undefined) {\n continue;\n }\n const rect = child.getBoundingClientRect();\n if (rect.bottom > containerTop + 1) {\n anchorRef.current = { el: child, top: rect.top - containerTop };\n return;\n }\n }\n anchorRef.current = null;\n }, []);\n\n // Follow the stream while pinned to the bottom; never fight the reader.\n // A LAYOUT effect so the very first paint of a freshly loaded session is\n // already anchored at the bottom — no visible traversal down the history.\n useLayoutEffect(() => {\n const node = scrollRef.current;\n if (node && autoFollow && pinned) {\n assignScrollTop(node, node.scrollHeight);\n }\n if (!revealed && groups.length > 0) {\n setRevealed(true);\n }\n }, [resolvedItems, working, autoFollow, pinned, revealed, groups.length, assignScrollTop]);\n\n // A cleared timeline (stream identity change) re-arms the reveal so the next\n // session also first paints at its bottom.\n useLayoutEffect(() => {\n if (groups.length === 0 && revealed) {\n setRevealed(false);\n }\n }, [groups.length, revealed]);\n\n // Clear the bulk-paint marker a frame after it renders, so rows appended\n // live (streams, new turns) animate exactly as before.\n useLayoutEffect(() => {\n previousBulkFirstKeyRef.current = firstGroupKey;\n if (!bulkRender) {\n return;\n }\n setBulkActive(true);\n const frame = requestFrame(() => setBulkActive(false));\n return () => cancelFrame(frame);\n }, [bulkRender, firstGroupKey]);\n\n // Prefetch older history well before the reader reaches the top: the\n // sentinel sits above the first group and trips 1600px early, so backfill\n // is usually rendered (and anchored by the ResizeObserver below) before the\n // top of the window ever becomes visible.\n useEffect(() => {\n const root = scrollRef.current;\n const target = topSentinelRef.current;\n if (!root || !target || !hasOlder || loadingOlder || !onLoadOlder || typeof IntersectionObserver === \"undefined\") {\n return;\n }\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n onLoadOlder();\n }\n }, { root, rootMargin: \"1600px 0px 0px 0px\" });\n observer.observe(target);\n return () => observer.disconnect();\n }, [hasOlder, loadingOlder, onLoadOlder, firstGroupKey]);\n\n // Scroll anchoring: when the content reflows (a fold expands/collapses, a\n // stream appends), keep following the bottom if pinned; otherwise pin the\n // reader's anchor in place. A change ABOVE the anchor shifts its viewport\n // offset — we correct scrollTop by that shift so the reader never gets yanked.\n // A change BELOW the anchor (a bottom append while scrolled up) leaves the\n // anchor put, so `diff` is 0 and we leave scrollTop alone.\n useEffect(() => {\n const node = scrollRef.current;\n const inner = node?.firstElementChild;\n if (!node || !inner || typeof ResizeObserver === \"undefined\") {\n return;\n }\n const observer = new ResizeObserver(() => {\n const current = scrollRef.current;\n if (!current) {\n return;\n }\n if (autoFollow && pinnedRef.current) {\n assignScrollTop(current, current.scrollHeight);\n } else {\n const anchor = anchorRef.current;\n if (anchor && anchor.el.isConnected) {\n const containerTop = current.getBoundingClientRect().top;\n const now = anchor.el.getBoundingClientRect().top - containerTop;\n const diff = now - anchor.top;\n if (diff !== 0) {\n assignScrollTop(current, current.scrollTop + diff);\n }\n }\n }\n captureAnchor();\n });\n observer.observe(inner);\n return () => observer.disconnect();\n }, [autoFollow, captureAnchor, assignScrollTop]);\n\n const onScroll = () => {\n const node = scrollRef.current;\n if (!node) {\n return;\n }\n const programmatic = programmaticScrollRef.current;\n programmaticScrollRef.current = false;\n const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;\n // Echoes of our own assignments may PIN but never UNPIN — only the reader\n // scrolling away releases the bottom-follow.\n if (nextPinned || !programmatic) {\n pinnedRef.current = nextPinned;\n setPinned(nextPinned);\n }\n captureAnchor();\n };\n\n return (\n <LightboxProvider>\n <EntranceAnimationProvider value={!bulkRender}>\n <div className={cn(\"og-root relative flex min-h-0 flex-col\", className)}>\n {/* overflow-anchor off: the browser's native scroll anchoring would fight\n the ResizeObserver corrections above — one authority only. */}\n <div\n ref={scrollRef}\n onScroll={onScroll}\n style={groups.length > 0 && !revealed ? { visibility: \"hidden\" } : undefined}\n className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 [overflow-anchor:none] sm:px-6\"\n >\n <div className=\"mx-auto flex w-full max-w-3xl flex-col gap-5\">\n {groups.length === 0 && !working\n ? (emptyState ?? <p className=\"py-10 text-center text-sm text-og-fg-subtle\">No activity yet.</p>)\n : null}\n {hasOlder ? <div ref={topSentinelRef} data-og-top-sentinel=\"\" data-og-timeline-chrome=\"\" aria-hidden=\"true\" className=\"h-px w-full shrink-0\" /> : null}\n {loadingOlder ? (\n <div data-og-timeline-chrome=\"\" className=\"flex items-center gap-2 text-sm\">\n <span className=\"og-shimmer-text font-medium\">Loading earlier activity…</span>\n </div>\n ) : null}\n {groups.map((group, index) => (\n <TimelineGroupView\n key={timelineGroupKey(group)}\n group={group}\n renderMessageText={renderMessageText}\n onOpenSession={onOpenSession}\n toolRegistry={toolRegistry}\n foldLiveCluster={isAgentProgress(groups[index + 1])}\n />\n ))}\n {working ? (\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"og-shimmer-text font-medium\">Working…</span>\n </div>\n ) : null}\n </div>\n </div>\n <AnimatePresence>\n {!pinned && autoFollow ? (\n <motion.button\n type=\"button\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: 8 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() => {\n const node = scrollRef.current;\n if (node) {\n node.scrollTo({ top: node.scrollHeight, behavior: \"smooth\" });\n }\n pinnedRef.current = true;\n setPinned(true);\n }}\n className={cn(\n \"absolute bottom-4 left-1/2 -translate-x-1/2\",\n \"inline-flex items-center gap-1.5 rounded-full border border-og-border bg-og-surface-3/90 px-3 py-1.5\",\n \"text-xs font-medium text-og-fg shadow-og-md backdrop-blur\",\n \"hover:border-og-border-strong\",\n )}\n >\n <ArrowDownIcon className=\"size-3.5\" />\n Jump to latest\n </motion.button>\n ) : null}\n </AnimatePresence>\n </div>\n </EntranceAnimationProvider>\n </LightboxProvider>\n );\n}\n\nfunction requestFrame(callback: FrameRequestCallback): number {\n if (typeof requestAnimationFrame === \"function\") {\n return requestAnimationFrame(callback);\n }\n return window.setTimeout(() => callback(performance.now()), 16);\n}\n\nfunction cancelFrame(id: number): void {\n if (typeof cancelAnimationFrame === \"function\") {\n cancelAnimationFrame(id);\n return;\n }\n window.clearTimeout(id);\n}\n\nfunction TimelineGroupView({\n group,\n renderMessageText,\n onOpenSession,\n toolRegistry,\n insideTurn = false,\n foldLiveCluster = false,\n}: {\n group: TimelineGroup;\n renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined;\n onOpenSession?: ((sessionId: string) => void) | undefined;\n toolRegistry: ToolRegistry;\n /** A completed cluster of a still-RUNNING turn (not the live tail) folds\n behind a neutral chip — the one place activity without an outcome still\n folds, bounding the DOM of days-long autonomous turns. */\n foldLiveCluster?: boolean;\n /** Rendering inside an expanded turn group: the outer chip already owns the\n failure surface, so nested chips stay tinted but quiet (no repeated\n failure text, no auto-open) — one loud error, N calm sub-expands. */\n insideTurn?: boolean;\n}) {\n switch (group.kind) {\n case \"activity\":\n return group.outcome || (foldLiveCluster && clusterIsSettled(group)) ? (\n <TurnSummary\n items={group.items}\n outcome={group.outcome}\n failureText={insideTurn ? undefined : group.failureText}\n defaultOpen={!insideTurn && group.outcome === \"failed\" ? true : undefined}\n >\n <ActivityRail items={group.items} onOpenSession={onOpenSession} toolRegistry={toolRegistry} />\n </TurnSummary>\n ) : (\n <ActivityRail items={group.items} onOpenSession={onOpenSession} toolRegistry={toolRegistry} />\n );\n case \"turn\": {\n const activityItems = flattenActivityItems(group.groups);\n return (\n <TurnSummary\n items={activityItems}\n outcome={group.outcome}\n failureText={group.failureText}\n durationMs={durationBetween(group.startedAt, group.endedAt)}\n defaultOpen={group.outcome === \"failed\" ? true : undefined}\n >\n {/* The body wears the timeline's rail language (matching ActivityRail)\n so nested chips read as contained by the turn, not as siblings. */}\n <div className=\"flex flex-col gap-4 border-l-2 border-og-border pl-3 sm:pl-4\">\n {group.groups.map((child) => (\n <TimelineGroupView\n key={timelineGroupKey(child)}\n group={child}\n renderMessageText={renderMessageText}\n onOpenSession={onOpenSession}\n toolRegistry={toolRegistry}\n insideTurn\n />\n ))}\n </div>\n </TurnSummary>\n );\n }\n case \"item\":\n return <TimelineRow item={group.item} renderMessageText={renderMessageText} />;\n }\n}\n\nfunction timelineGroupKey(group: TimelineGroup): string {\n switch (group.kind) {\n case \"item\":\n return group.item.id;\n case \"activity\":\n return group.id;\n case \"turn\":\n return group.id;\n }\n}\n\n/** The agent has moved PAST a cluster only when what follows is more agent\n progress — new activity, a settled turn, or narration. A waiting notice\n (approval pause), a pending queued message, a goal pill, or nothing at all\n do NOT advance the story, and folding on them would hide exactly the work\n the reader needs in view. */\nfunction isAgentProgress(next: TimelineGroup | undefined): boolean {\n if (!next) {\n return false;\n }\n return next.kind === \"activity\" || next.kind === \"turn\" || (next.kind === \"item\" && next.item.kind === \"agent-message\");\n}\n\n/** No item still running or streaming — the only state safe to fold live.\n Position alone is a broken proxy: a pending queued message (or any trailing\n item) can sit after the ACTIVE cluster, which must never fold mid-work. */\nfunction clusterIsSettled(group: Extract<TimelineGroup, { kind: \"activity\" }>): boolean {\n return group.items.every((item) => {\n if (item.kind === \"reasoning\") {\n return !item.streaming;\n }\n return item.status !== \"running\";\n });\n}\n\nfunction flattenActivityItems(groups: TimelineGroup[]): ActivityItem[] {\n const items: ActivityItem[] = [];\n for (const group of groups) {\n if (group.kind === \"activity\") {\n items.push(...group.items);\n } else if (group.kind === \"turn\") {\n items.push(...flattenActivityItems(group.groups));\n }\n }\n return items;\n}\n\nfunction durationBetween(startedAt: string, endedAt: string): number | undefined {\n const started = Date.parse(startedAt);\n const ended = Date.parse(endedAt);\n if (!Number.isFinite(started) || !Number.isFinite(ended) || ended < started) {\n return undefined;\n }\n return ended - started;\n}\n\n/* --- single rows ------------------------------------------------------------ */\n\n/**\n * Render one non-activity timeline item (chat message, status divider, goal\n * landmark, notice). Exported so the component demo draws the EXACT same rows as\n * the live app — no forked bubble/goal markup.\n */\nexport function TimelineRow({\n item,\n renderMessageText,\n}: {\n item: TimelineItem;\n renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined;\n}) {\n switch (item.kind) {\n case \"user-message\":\n return <UserMessageRow item={item} renderMessageText={renderMessageText} />;\n case \"agent-message\":\n return <AgentMessageRow item={item} renderMessageText={renderMessageText} />;\n case \"session-status\":\n return <SessionStatusRow item={item} />;\n case \"goal\":\n return <GoalRow item={item} />;\n case \"notice\":\n return <NoticeRow item={item} />;\n default:\n return null;\n }\n}\n\nfunction UserMessageRow({\n item,\n renderMessageText,\n}: {\n item: UserMessageItem;\n renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined;\n}) {\n const enter = useEntranceAnimation();\n return (\n <div className={cn(enter && \"animate-og-enter\", \"flex justify-end\")}>\n <div className=\"flex max-w-[85%] min-w-0 flex-col items-end gap-1\">\n {item.pending ? <span className=\"px-1 text-og-xs text-og-fg-subtle\">queued</span> : null}\n <div className=\"w-fit max-w-full min-w-0 rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-og-md leading-6 text-og-fg\">\n {renderMessageText ? renderMessageText(item.text, item) : <Markdown>{item.text}</Markdown>}\n </div>\n </div>\n </div>\n );\n}\n\nfunction AgentMessageRow({\n item,\n renderMessageText,\n}: {\n item: AgentMessageItem;\n renderMessageText?: ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode) | undefined;\n}) {\n const enter = useEntranceAnimation();\n const caret = item.streaming ? (\n <span className=\"ml-0.5 inline-block h-[1.1em] w-[2px] translate-y-[3px] animate-og-blink rounded-full bg-og-accent\" aria-hidden />\n ) : null;\n return (\n <div className={cn(enter && \"animate-og-enter\", \"min-w-0 text-og-md leading-7 text-og-fg\")}>\n {renderMessageText ? (\n <>\n {renderMessageText(item.text, item)}\n {caret}\n </>\n ) : (\n // While streaming, let the caret ride the end of the last rendered line:\n // the trailing block (usually a <p>) flows inline so the caret sits on\n // its baseline instead of dropping to a new line.\n <div className={item.streaming ? \"[&_>div>:last-child]:inline\" : undefined}>\n <Markdown>{item.text}</Markdown>\n {caret}\n </div>\n )}\n </div>\n );\n}\n\nfunction SessionStatusRow({ item }: { item: { status: SessionStatus; occurredAt: string } }) {\n const enter = useEntranceAnimation();\n const meta = SESSION_STATUS_META[item.status];\n return (\n <div className={cn(enter && \"animate-og-enter\", \"flex items-center gap-3 text-og-xs text-og-fg-subtle\")} role=\"status\">\n <span className=\"h-px flex-1 bg-og-border\" />\n <span className=\"inline-flex items-center gap-1.5\">\n <StatusDot status={item.status} className=\"size-1\" />\n {meta.label.toLowerCase()} · {formatRelativeTime(item.occurredAt)}\n </span>\n <span className=\"h-px flex-1 bg-og-border\" />\n </div>\n );\n}\n\n/**\n * The per-action presentation of a goal landmark pill. Each of the six goal\n * actions reads distinctly, but the palette stays quiet — color is spent only on\n * the two states that genuinely earn it, the rest are neutral pills set apart by\n * their glyph alone:\n *\n * completed success green (status-idle) check — the only \"done\" hue\n * paused attention waiting-tinted pause — a held goal asks to resume\n * set a landmark a quiet accent target — opening a fresh goal\n * resumed forward neutral play — motion picking back up\n * updated a revision neutral pencil — the goal text changed\n * continuation steady on neutral arrow — still tracking the same goal\n *\n * The pill class is the established badge convention (`text-X border-X/30\n * bg-X/10`); neutral actions reuse the surface/border tokens so a clean run of\n * landmarks stays calm rather than a row of colored chips.\n */\ntype GoalMeta = { label: string; pill: string; icon: ComponentType<{ className?: string }> };\n\nconst NEUTRAL_PILL = \"border-og-border bg-og-surface-1 text-og-fg-muted\";\n\nconst GOAL_META: Record<GoalItem[\"action\"], GoalMeta> = {\n set: { label: \"Goal set\", pill: \"border-og-accent/30 bg-og-accent/10 text-og-accent\", icon: TargetIcon },\n updated: { label: \"Goal updated\", pill: NEUTRAL_PILL, icon: PencilLineIcon },\n completed: { label: \"Goal completed\", pill: \"border-og-status-idle/30 bg-og-status-idle/10 text-og-status-idle\", icon: CheckIcon },\n paused: { label: \"Goal paused\", pill: \"border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting\", icon: PauseIcon },\n resumed: { label: \"Goal resumed\", pill: NEUTRAL_PILL, icon: PlayIcon },\n continuation: { label: \"Continuing toward the goal\", pill: NEUTRAL_PILL, icon: ArrowRightIcon },\n};\n\n/**\n * A goal landmark pill. Resolves its label, accent/tone, and glyph from\n * {@link GOAL_META} so all six actions are visually distinguishable while the\n * palette stays restrained — see that table for the per-action rationale.\n */\nfunction GoalRow({ item }: { item: GoalItem }) {\n const enter = useEntranceAnimation();\n const { label, pill, icon: Icon } = GOAL_META[item.action];\n return (\n <div className={cn(enter && \"animate-og-enter\", \"flex justify-center\")}>\n <span className={cn(\"inline-flex max-w-full items-center gap-1.5 rounded-full border px-3 py-1 text-og-sm\", pill)}>\n <Icon className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">\n {label}\n {item.text ? `: ${truncate(item.text, 90)}` : \"\"}\n </span>\n </span>\n </div>\n );\n}\n\nfunction NoticeRow({ item }: { item: NoticeItem }) {\n const enter = useEntranceAnimation();\n const tone =\n item.tone === \"failed\"\n ? \"border-og-status-failed/35 bg-og-status-failed/10 text-og-status-failed\"\n : item.tone === \"waiting\"\n ? \"border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting\"\n : \"border-og-border bg-og-surface-1 text-og-fg-muted\";\n return (\n <div className={cn(enter && \"animate-og-enter\", \"flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm\", tone)} role=\"status\">\n <TriangleAlertIcon className={cn(\"mt-0.5 size-4 shrink-0\", item.tone === \"cancelled\" && \"opacity-60\")} />\n <span className=\"min-w-0 flex-1 whitespace-pre-wrap break-words\">{item.text}</span>\n {item.action ? (\n <a\n className=\"shrink-0 rounded-og-sm border border-current/25 px-2 py-1 text-xs font-medium hover:bg-current/10\"\n href={item.action.url}\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n {item.action.label}\n </a>\n ) : null}\n </div>\n );\n}\n","import { memo } from \"react\";\nimport ReactMarkdown, { type Components } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"../lib/cn\";\n\n/**\n * The default renderer for chat message bodies in {@link MessageTimeline}.\n *\n * Agent (and user) messages arrive as GitHub-flavored markdown. This turns the\n * raw text into styled HTML using `react-markdown` + `remark-gfm`, themed to the\n * package's `og-*` design tokens so it reads as one cohesive dark surface — no\n * stock Tailwind colors leak in.\n *\n * It re-parses on every render, which is exactly right for streaming: a body\n * that is still arriving (an unterminated `**`, a half-open code fence, a table\n * mid-row) renders as best-effort markdown and resolves cleanly as the rest of\n * the tokens land. Consumers who want a different renderer can still pass\n * `renderMessageText` to `MessageTimeline` to override this entirely.\n */\nexport type MarkdownProps = {\n children: string;\n className?: string | undefined;\n};\n\n/* --- element renderers (themed to og-* tokens) ------------------------------ */\n\nconst components: Components = {\n h1: ({ children, ...props }) => (\n <h1 className=\"mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0\" {...props}>\n {children}\n </h1>\n ),\n h2: ({ children, ...props }) => (\n <h2 className=\"mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0\" {...props}>\n {children}\n </h2>\n ),\n h3: ({ children, ...props }) => (\n <h3 className=\"mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0\" {...props}>\n {children}\n </h3>\n ),\n h4: ({ children, ...props }) => (\n <h4 className=\"mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0\" {...props}>\n {children}\n </h4>\n ),\n p: ({ children, ...props }) => (\n <p className=\"my-2.5 leading-7 first:mt-0 last:mb-0\" {...props}>\n {children}\n </p>\n ),\n strong: ({ children, ...props }) => (\n <strong className=\"font-semibold text-og-fg\" {...props}>\n {children}\n </strong>\n ),\n em: ({ children, ...props }) => (\n <em className=\"italic\" {...props}>\n {children}\n </em>\n ),\n a: ({ children, ...props }) => (\n <a\n className=\"break-words font-medium text-og-accent underline-offset-2 hover:underline\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n {...props}\n >\n {children}\n </a>\n ),\n ul: ({ children, ...props }) => (\n <ul className=\"my-2.5 ml-5 flex list-disc flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\" {...props}>\n {children}\n </ul>\n ),\n ol: ({ children, ...props }) => (\n <ol className=\"my-2.5 ml-5 flex list-decimal flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\" {...props}>\n {children}\n </ol>\n ),\n // GFM task-list items carry a leading checkbox <input>; `list-none` + a\n // negative margin pull the checkbox back to the bullet column so it aligns\n // with the text.\n li: ({ children, ...props }) => (\n <li className=\"leading-7 marker:text-og-fg-subtle [&>ul]:my-1 [&>ol]:my-1 [&:has(>input)]:list-none [&:has(>input)]:-ml-5\" {...props}>\n {children}\n </li>\n ),\n input: ({ type, ...props }) =>\n type === \"checkbox\" ? (\n <input\n {...props}\n type=\"checkbox\"\n disabled\n className=\"mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline\"\n />\n ) : (\n <input type={type} {...props} />\n ),\n blockquote: ({ children, ...props }) => (\n <blockquote\n className=\"my-3 border-l-2 border-og-border-strong pl-3.5 text-og-fg-muted [&>p]:my-1.5 first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </blockquote>\n ),\n hr: (props) => <hr className=\"my-4 border-0 border-t border-og-border\" {...props} />,\n // Inline `code` vs fenced code blocks. react-markdown v10 no longer passes an\n // `inline` flag; a fenced block is a <code> whose parent is <pre> (styled by\n // the `pre` renderer), so a `code` reaching here is treated as inline.\n code: ({ children, className: _className, ...props }) => (\n <code\n className=\"rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg\"\n {...props}\n >\n {children}\n </code>\n ),\n // Fenced code blocks — mirror the timeline's PayloadBlock <pre> styling for\n // visual consistency (bordered, scrollable, mono, surface background).\n pre: ({ children, ...props }) => (\n <pre\n className=\"my-3 max-h-96 overflow-auto rounded-og-md border border-og-border bg-og-bg/60 p-3 font-og-mono text-og-sm text-og-fg-muted [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:text-inherit first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </pre>\n ),\n table: ({ children, ...props }) => (\n <div className=\"my-3 max-w-full overflow-x-auto rounded-og-md border border-og-border first:mt-0 last:mb-0\">\n <table className=\"w-full border-collapse text-og-base\" {...props}>\n {children}\n </table>\n </div>\n ),\n thead: ({ children, ...props }) => (\n <thead className=\"bg-og-surface-1\" {...props}>\n {children}\n </thead>\n ),\n th: ({ children, ...props }) => (\n <th className=\"border-b border-og-border px-3 py-1.5 text-left font-medium text-og-fg\" {...props}>\n {children}\n </th>\n ),\n td: ({ children, ...props }) => (\n <td className=\"border-b border-og-border px-3 py-1.5 align-top text-og-fg-muted [tr:last-child>&]:border-b-0\" {...props}>\n {children}\n </td>\n ),\n img: ({ alt, ...props }) => <img alt={alt ?? \"\"} className=\"my-3 max-w-full rounded-og-md border border-og-border\" {...props} />,\n};\n\nfunction MarkdownImpl({ children, className }: MarkdownProps) {\n return (\n // `min-w-0` lets the prose shrink inside flex parents (message bubbles) so\n // long links and code blocks wrap/scroll instead of forcing overflow.\n <div className={cn(\"min-w-0 break-words\", className)}>\n <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>\n {children}\n </ReactMarkdown>\n </div>\n );\n}\n\n/** Memoized so streaming re-renders of the parent don't re-parse settled bodies. */\nexport const Markdown = memo(MarkdownImpl);\n","import type { SessionStatus as SessionStatusValue } from \"@opengeni/sdk\";\nimport { cn } from \"../lib/cn\";\n\nexport type SessionStatusMeta = {\n label: string;\n /** Token-backed color classes for the dot and tinted badge. */\n dotClassName: string;\n badgeClassName: string;\n /** Live states breathe; terminal states hold still. */\n pulse: boolean;\n};\n\nexport const SESSION_STATUS_META: Record<SessionStatusValue, SessionStatusMeta> = {\n queued: {\n label: \"Queued\",\n dotClassName: \"bg-og-status-queued\",\n badgeClassName: \"text-og-fg-muted border-og-border bg-og-status-queued/10\",\n pulse: true,\n },\n running: {\n label: \"Running\",\n dotClassName: \"bg-og-status-running\",\n badgeClassName: \"text-og-status-running border-og-status-running/30 bg-og-status-running/10\",\n pulse: true,\n },\n idle: {\n label: \"Idle\",\n dotClassName: \"bg-og-status-idle\",\n badgeClassName: \"text-og-status-idle border-og-status-idle/30 bg-og-status-idle/10\",\n pulse: false,\n },\n requires_action: {\n label: \"Waiting on you\",\n dotClassName: \"bg-og-status-waiting\",\n badgeClassName: \"text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10\",\n pulse: true,\n },\n failed: {\n label: \"Failed\",\n dotClassName: \"bg-og-status-failed\",\n badgeClassName: \"text-og-status-failed border-og-status-failed/35 bg-og-status-failed/10\",\n pulse: false,\n },\n cancelled: {\n label: \"Cancelled\",\n dotClassName: \"bg-og-status-cancelled\",\n badgeClassName: \"text-og-fg-subtle border-og-border bg-og-status-cancelled/10\",\n pulse: false,\n },\n};\n\nexport type SessionStatusProps = {\n status: SessionStatusValue;\n /** Override the label (\"Running\" -> \"Deploying\", ...). */\n label?: string | undefined;\n size?: \"sm\" | \"md\" | undefined;\n className?: string | undefined;\n};\n\n/** Status badge with a breathing dot for live states. */\nexport function SessionStatus({ status, label, size = \"md\", className }: SessionStatusProps) {\n const meta = SESSION_STATUS_META[status];\n return (\n <span\n data-status={status}\n className={cn(\n \"og-root inline-flex shrink-0 items-center rounded-full border font-medium\",\n size === \"sm\" ? \"gap-1 px-1.5 py-px text-og-xs\" : \"gap-1.5 px-2 py-0.5 text-xs\",\n meta.badgeClassName,\n className,\n )}\n >\n <StatusDot status={status} className={size === \"sm\" ? \"size-1\" : \"size-1.5\"} />\n {label ?? meta.label}\n </span>\n );\n}\n\nexport type StatusDotProps = {\n status: SessionStatusValue;\n className?: string | undefined;\n};\n\n/** Just the dot — for dense rows and tiles. */\nexport function StatusDot({ status, className }: StatusDotProps) {\n const meta = SESSION_STATUS_META[status];\n return (\n <span className={cn(\"relative inline-flex size-1.5 shrink-0 rounded-full\", meta.dotClassName, className)}>\n {meta.pulse ? <span className={cn(\"absolute inset-0 animate-og-pulse rounded-full\", meta.dotClassName)} /> : null}\n </span>\n );\n}\n","import type { Session } from \"@opengeni/sdk\";\nimport { cn } from \"../lib/cn\";\nimport { formatRelativeTime, truncate } from \"../lib/format\";\nimport { SessionStatus } from \"./session-status\";\n\nexport type FleetTileProps = {\n session: Session;\n /** Overrides the derived title (metadata.title/name, else the initial message). */\n title?: string | undefined;\n /** Extra line under the title — e.g. \"drift check\" or the worker's task. */\n subtitle?: string | undefined;\n onOpen?: ((session: Session) => void) | undefined;\n className?: string | undefined;\n};\n\n/** Best-effort display title for a session. */\nexport function sessionDisplayTitle(session: Session): string {\n // A set title (agent-generated or user-renamed) wins over metadata + the\n // initial-message fallback.\n if (typeof session.title === \"string\" && session.title.trim().length > 0) {\n return session.title;\n }\n for (const key of [\"title\", \"name\"] as const) {\n const value = session.metadata[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n }\n return truncate(session.initialMessage, 100) || session.id.slice(0, 8);\n}\n\n/**\n * One session in the fleet/manager view: title, live status, model, and\n * recency — dense but calm. Running sessions carry a breathing status dot\n * and a faint accent edge so the live ones read at a glance.\n */\nexport function FleetTile({ session, title, subtitle, onOpen, className }: FleetTileProps) {\n const running = session.status === \"running\" || session.status === \"queued\";\n const needsYou = session.status === \"requires_action\";\n return (\n <button\n type=\"button\"\n data-status={session.status}\n onClick={onOpen ? () => onOpen(session) : undefined}\n disabled={!onOpen}\n className={cn(\n \"og-root group relative flex w-full flex-col gap-2.5 overflow-hidden rounded-og-lg border border-og-border\",\n \"bg-og-surface-1 p-4 text-left shadow-og-sm\",\n \"transition-[border-color,background-color,box-shadow,transform] duration-200 ease-og-out\",\n onOpen && \"hover:-translate-y-px hover:border-og-border-strong hover:bg-og-surface-2 hover:shadow-og-md\",\n \"disabled:cursor-default\",\n className,\n )}\n >\n <span\n aria-hidden\n className={cn(\n \"absolute inset-y-0 left-0 w-0.5 transition-opacity duration-300\",\n running ? \"bg-og-accent opacity-100\" : needsYou ? \"bg-og-status-waiting opacity-100\" : \"opacity-0\",\n )}\n />\n <span className=\"flex w-full items-start justify-between gap-3\">\n <span className=\"line-clamp-2 min-w-0 text-og-base font-medium leading-snug text-og-fg\">{title ?? sessionDisplayTitle(session)}</span>\n <SessionStatus status={session.status} size=\"sm\" className=\"mt-px\" />\n </span>\n {subtitle ? <span className=\"line-clamp-1 text-og-sm text-og-fg-muted\">{subtitle}</span> : null}\n <span className=\"mt-auto flex w-full items-center gap-2 text-og-xs text-og-fg-subtle\">\n <span className=\"font-og-mono\">{session.id.slice(0, 8)}</span>\n <span aria-hidden>·</span>\n <span className=\"truncate\">{session.model}</span>\n <span className=\"ml-auto shrink-0\" title={session.updatedAt}>\n {formatRelativeTime(session.updatedAt)}\n </span>\n </span>\n </button>\n );\n}\n","import type { TerminalCapability } from \"@opengeni/sdk\";\nimport { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useTerminalStream } from \"../hooks/use-terminal-stream\";\nimport type { UseSandboxTerminalResult } from \"../hooks/use-sandbox-terminal\";\n\n/** A subset of xterm.js's ITheme — the tokens worth themeing from a host app. */\nexport type XtermTheme = {\n background?: string;\n foreground?: string;\n cursor?: string;\n cursorAccent?: string;\n selectionBackground?: string;\n};\n\nexport type SandboxTerminalProps = {\n /** From `useSandboxTerminal(...)`. */\n result: UseSandboxTerminalResult;\n /**\n * The negotiated Terminal capability cell. When it advertises `transport:\n * \"pty-ws\"` + a live `url` (a warm box with a viewer attached), the terminal is\n * driven by a REAL bidirectional PTY over the Modal tunnel (ttyd-over-websocket)\n * INSTEAD of the broken ptyWrite-over-HTTP path: xterm input → the socket, the\n * socket's output → xterm, xterm resize → the socket. On a cold box / no url\n * (`transport: \"sse-events\"`) it stays on the read-only Channel-A firehose\n * (`result.chunks`). Omit to force the legacy firehose-only behavior.\n */\n terminalCapability?: TerminalCapability | null | undefined;\n theme?: XtermTheme | undefined;\n fontFamily?: string | undefined;\n fontSize?: number | undefined;\n /**\n * Force read-only even when the PTY accepts stdin. Default: interactive\n * whenever a live pty-ws stream is connected OR `result.write !== null` (the box\n * advertises an interactive PTY); otherwise the read-only agent firehose.\n */\n readOnly?: boolean | undefined;\n /** Shown on the server / before xterm hydrates (SSR-safe placeholder). */\n placeholder?: ReactNode | undefined;\n /** Render the small status header (pty/shell + running dot + read-only pill). */\n showHeader?: boolean | undefined;\n /** Shell label for the header (e.g. `/bin/bash`). */\n shell?: string | undefined;\n /**\n * Fired the first time the user engages the terminal surface (focus or click).\n * The host wires this to warm the box for the REAL pty-ws terminal (the viewer\n * attach), so a cold box upgrades from the read-only firehose to a live PTY ON\n * INTERACT — never on mere mount (which would force a box spin-up and regress\n * the firehose-only default).\n */\n onActivate?: (() => void) | undefined;\n className?: string | undefined;\n};\n\n// The xterm.js handle the effect owns. `any`-free structural shape so we can\n// drive it without a hard type dep on the lazily-imported lib.\ntype XtermLike = {\n open: (el: HTMLElement) => void;\n write: (data: string) => void;\n clear: () => void;\n onData: (cb: (data: string) => void) => { dispose: () => void };\n onResize: (cb: (size: { cols: number; rows: number }) => void) => { dispose: () => void };\n loadAddon: (addon: unknown) => void;\n dispose: () => void;\n cols: number;\n rows: number;\n options: { theme?: XtermTheme; disableStdin?: boolean };\n};\ntype FitAddonLike = { fit: () => void };\n\n/**\n * An xterm.js terminal fed by the Channel-A event projection\n * (`useSandboxTerminal`). xterm + the fit + web-links addons are lazy-imported\n * inside an effect, so SSR renders the placeholder and the terminal mounts on\n * hydration. Output chunks are written incrementally (tracking a written-cursor\n * by chunk id so a re-render never re-writes). When `result.write` is non-null\n * and not forced read-only, keystrokes pipe back through the PTY.\n *\n * Resizes are tracked with a `ResizeObserver` on the container (not just\n * `window.resize`) so dragging the dock handle refits the grid instead of\n * leaving the terminal mis-sized.\n */\nexport function SandboxTerminal({\n result,\n terminalCapability,\n theme,\n fontFamily,\n fontSize,\n readOnly,\n placeholder,\n showHeader,\n shell,\n onActivate,\n className,\n}: SandboxTerminalProps) {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const termRef = useRef<XtermLike | null>(null);\n const fitRef = useRef<FitAddonLike | null>(null);\n const writtenRef = useRef<Set<string>>(new Set());\n const [ready, setReady] = useState(false);\n\n // ── Interactive transport switch ─────────────────────────────────────────────\n // The interactive terminal is a REAL bidirectional PTY (ttyd over the Modal\n // tunnel) WHENEVER the Terminal cell advertises `transport: \"pty-ws\"` + a live\n // `url`; the ttyd socket then OWNS the screen (input + output both ride it). On\n // a cold box / sse-events cell, `useTerminalStream` stays idle and we fall back\n // to the read-only Channel-A command-output firehose (`result.chunks`) — with\n // the legacy `result.write` (ptyWrite-over-HTTP) as the only stdin path there.\n const ptyWs = terminalCapability?.transport === \"pty-ws\" && Boolean(terminalCapability?.url);\n // Output frames buffer here until xterm has mounted; the write effect drains it.\n const ptyOutputQueueRef = useRef<string[]>([]);\n const ptyStream = useTerminalStream({\n capability: ptyWs\n ? {\n transport: terminalCapability!.transport,\n url: terminalCapability!.url,\n token: terminalCapability!.token,\n }\n : null,\n onOutput: (data) => {\n const term = termRef.current;\n if (term) term.write(data);\n else ptyOutputQueueRef.current.push(data);\n },\n });\n\n // PTY mode = a live ttyd socket drives the screen. In PTY mode the screen is\n // owned by the websocket (we must NOT replay the SSE firehose into it — that\n // double-writes the agent's command output on top of the live PTY). Firehose\n // mode = the read-only projection (or the legacy HTTP-write fallback).\n const ptyMode = ptyWs && ptyStream.status !== \"closed\";\n // Interactive (stdin enabled) when a live PTY socket is connected, OR (legacy\n // fallback) the projection exposed an HTTP write fn. `readOnly` forces off.\n const interactive = !readOnly && (ptyMode || result.write !== null);\n\n // Mount xterm once (client-only). Re-mounts only when the interactive flag\n // flips (stdin enable/disable is a construction param on xterm).\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const el = containerRef.current;\n if (!el) return;\n let disposed = false;\n\n // Wait for the container to have a real measured size before opening xterm.\n // If `term.open()` runs while the panel is 0-wide (tab still mounting, dock\n // mid-resize), xterm renders at its 80×24 fallback and the first frame's\n // grid is rasterized into the canvas; a later fit reflows the text but the\n // stale first paint lingers as a `]]]bbb` smear on the top row. Gating the\n // open on a non-zero size removes that first wrong-width render entirely.\n const waitForSize = (el: HTMLElement) =>\n new Promise<void>((resolve) => {\n if (el.clientWidth > 0 && el.clientHeight > 0) return resolve();\n const ro = new ResizeObserver(() => {\n if (el.clientWidth > 0 && el.clientHeight > 0) {\n ro.disconnect();\n resolve();\n }\n });\n ro.observe(el);\n // Safety: never hang if the observer somehow never fires.\n setTimeout(() => {\n ro.disconnect();\n resolve();\n }, 1000);\n });\n\n // Inject xterm's structural CSS before the first open so the helper-textarea\n // ghost is clipped from frame one (no top-left input box flash).\n ensureXtermBaseCss();\n\n void (async () => {\n const [{ Terminal }, { FitAddon }, { WebLinksAddon }] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ]);\n if (disposed) return;\n await waitForSize(el);\n if (disposed) return;\n const term = new Terminal({\n convertEol: true,\n disableStdin: !interactive,\n cursorBlink: interactive,\n fontFamily: fontFamily ?? \"var(--og-font-mono)\",\n fontSize: fontSize ?? 13,\n lineHeight: 1.25,\n // A little breathing room from the panel edge so output isn't flush to\n // the border (matches a real terminal app's inner gutter).\n ...({ padding: 8 } as Record<string, unknown>),\n ...(theme ? { theme } : {}),\n }) as unknown as XtermLike;\n const fit = new FitAddon() as unknown as FitAddonLike;\n term.loadAddon(fit);\n // Clickable URLs in agent output (open in a new tab).\n term.loadAddon(\n new WebLinksAddon((_e: MouseEvent, uri: string) => window.open(uri, \"_blank\", \"noopener,noreferrer\")) as unknown,\n );\n term.open(el);\n termRef.current = term;\n fitRef.current = fit;\n // Critical: the column count must be settled BEFORE any output is written,\n // or seeded transcript lines reflow/garble against the default 80×24 grid\n // (the trailing prompt's escape codes smear into `]]]bbb` artifacts). Fit\n // once now, then again on the next frame after layout has measured the\n // real container width, and only then unblock the write effect.\n const settle = () => {\n try {\n fit.fit();\n } catch {\n // ignore fit before layout\n }\n };\n settle();\n requestAnimationFrame(() => {\n if (disposed) return;\n settle();\n // Drain any ttyd OUTPUT that arrived before xterm finished mounting.\n if (ptyOutputQueueRef.current.length > 0) {\n for (const data of ptyOutputQueueRef.current) term.write(data);\n ptyOutputQueueRef.current = [];\n }\n setReady(true);\n });\n })();\n\n return () => {\n disposed = true;\n termRef.current?.dispose();\n termRef.current = null;\n fitRef.current = null;\n writtenRef.current = new Set();\n setReady(false);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [interactive]);\n\n // Re-theme live (e.g. dark↔light flip) without re-mounting / losing scrollback.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term || !theme) return;\n term.options.theme = theme;\n }, [ready, theme]);\n\n // On the firehose → PTY transition (the box warmed and the ttyd socket came\n // up), clear the stale read-only transcript so the live shell starts on a clean\n // screen instead of below the agent's projected command output.\n const enteredPtyRef = useRef(false);\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term) return;\n if (ptyMode && !enteredPtyRef.current) {\n enteredPtyRef.current = true;\n term.clear();\n } else if (!ptyMode) {\n enteredPtyRef.current = false;\n }\n }, [ready, ptyMode]);\n\n // Write new firehose chunks incrementally — but ONLY in firehose mode. In PTY\n // mode the ttyd socket owns the screen; replaying the SSE command-output\n // projection on top of it would double-render the agent's output.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term || ptyMode) return;\n for (const chunk of result.chunks) {\n if (writtenRef.current.has(chunk.id)) continue;\n writtenRef.current.add(chunk.id);\n term.write(chunk.text);\n }\n }, [ready, result.chunks, ptyMode]);\n\n // Wire interactive input when allowed. PTY mode pipes keystrokes to the ttyd\n // socket (the real PTY); firehose mode uses the legacy ptyWrite-over-HTTP fn.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term || !interactive) return;\n const sink = ptyMode ? ptyStream.write : result.write;\n if (!sink) return;\n const sub = term.onData((data) => sink(data));\n return () => sub.dispose();\n }, [ready, interactive, ptyMode, ptyStream.write, result.write]);\n\n // In PTY mode, tell ttyd the window size on the xterm resize event (the fit\n // addon reflows the grid; ttyd resizes the remote PTY to match), and push the\n // initial geometry once the socket is open.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term || !ptyMode) return;\n ptyStream.resize(term.cols, term.rows);\n const sub = term.onResize(({ cols, rows }) => ptyStream.resize(cols, rows));\n return () => sub.dispose();\n }, [ready, ptyMode, ptyStream.connected, ptyStream.resize]);\n\n // Refit on container resize (dock drag) AND window resize. The fit addon\n // mutates xterm's cols/rows → the onResize handler above forwards to ttyd.\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const refit = () => {\n try {\n fitRef.current?.fit();\n } catch {\n // ignore\n }\n };\n window.addEventListener(\"resize\", refit);\n let observer: ResizeObserver | null = null;\n const el = containerRef.current;\n if (el && typeof ResizeObserver !== \"undefined\") {\n observer = new ResizeObserver(() => refit());\n observer.observe(el);\n }\n return () => {\n window.removeEventListener(\"resize\", refit);\n observer?.disconnect();\n };\n }, [ready]);\n\n return (\n <div className={cn(\"relative flex h-full w-full flex-col overflow-hidden\", className)}>\n {showHeader && (\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-og-border px-2 py-1 text-og-xs text-og-fg-subtle\">\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <span\n className={cn(\n \"size-1.5 shrink-0 rounded-full\",\n result.running ? \"bg-og-status-running\" : \"bg-og-fg-subtle\",\n )}\n />\n <span className=\"truncate font-og-mono\">\n pty: {shell ?? \"shell\"}\n </span>\n </span>\n <span className=\"flex shrink-0 items-center gap-2\">\n {!interactive && (\n <span className=\"rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-xs uppercase tracking-wide\">\n read-only\n </span>\n )}\n <button\n type=\"button\"\n onClick={() => {\n termRef.current?.clear();\n writtenRef.current = new Set();\n }}\n className=\"rounded-og-sm px-1.5 py-0.5 text-og-xs hover:text-og-fg pointer-coarse:min-h-10\"\n >\n Clear\n </button>\n </span>\n </div>\n )}\n {/* `onPointerDownCapture`/`onFocusCapture` fire on the FIRST user engagement\n with the terminal surface (capture so they win even though xterm's own\n listeners stop propagation). The host warms the box for pty-ws here. */}\n <div\n className=\"relative min-h-0 flex-1 bg-og-bg px-2 py-1.5\"\n onPointerDownCapture={onActivate}\n onFocusCapture={onActivate}\n >\n {!ready && (placeholder ?? <TerminalPlaceholder />)}\n <div ref={containerRef} className=\"h-full w-full\" data-opengeni-terminal />\n </div>\n </div>\n );\n}\n\n// xterm.js ships a stylesheet (`@xterm/xterm/css/xterm.css`) that is REQUIRED for\n// correct layout — without it the `.xterm-helper-textarea` (an off-screen input\n// xterm uses for IME/keystrokes) is NOT clipped and renders as a visible 1-line\n// box in the top-left (the \"weird input box\" bug), and the viewport/screen aren't\n// positioned. The host app never imports that CSS (no global stylesheet here), so\n// we inject the structural rules once, idempotently (keyed by id), the first time\n// any terminal mounts. Scoped under `.xterm` so it can't leak into host styles.\nconst XTERM_STYLE_ID = \"opengeni-xterm-base-css\";\nconst XTERM_BASE_CSS = `\n.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}\n.xterm.focus,.xterm:focus{outline:none}\n.xterm .xterm-helpers{position:absolute;top:0;z-index:5}\n.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}\n.xterm .composition-view{background:var(--og-color-bg);color:var(--og-color-fg);display:none;position:absolute;white-space:nowrap;z-index:1}\n.xterm .composition-view.active{display:block}\n.xterm .xterm-viewport{background-color:transparent;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}\n.xterm .xterm-screen{position:relative}\n.xterm .xterm-screen canvas{position:absolute;left:0;top:0}\n.xterm .xterm-scroll-area{visibility:hidden}\n.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}\n.xterm.enable-mouse-events{cursor:default}\n.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}\n.xterm.column-select.focus{cursor:crosshair}\n.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}\n.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}\n.xterm .xterm-accessibility-tree{user-select:text;white-space:pre}\n.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}\n.xterm-dim{opacity:1!important}\n.xterm-underline-1{text-decoration:underline}\n.xterm-underline-2{text-decoration:double underline}\n.xterm-underline-3{text-decoration:wavy underline}\n.xterm-underline-4{text-decoration:dotted underline}\n.xterm-underline-5{text-decoration:dashed underline}\n.xterm-overline{text-decoration:overline}\n.xterm-strikethrough{text-decoration:line-through}\n.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}\n.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}\n.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}\n.xterm-decoration-top{z-index:2;position:relative}\n`;\n\nfunction ensureXtermBaseCss(): void {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(XTERM_STYLE_ID)) return;\n const style = document.createElement(\"style\");\n style.id = XTERM_STYLE_ID;\n style.textContent = XTERM_BASE_CSS;\n document.head.appendChild(style);\n}\n\nfunction TerminalPlaceholder() {\n return (\n <div className=\"absolute inset-0 flex items-center justify-center text-og-sm text-og-fg-subtle\">\n Loading terminal…\n </div>\n );\n}\n","import {\n ChevronRightIcon,\n FileIcon,\n FilePlusIcon,\n FolderIcon,\n FolderPlusIcon,\n Loader2Icon,\n PencilIcon,\n RefreshCwIcon,\n Trash2Icon,\n} from \"lucide-react\";\nimport {\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport type { FileTreeNode, UseSandboxFilesResult } from \"../hooks/use-sandbox-files\";\n\nexport type FileBrowserProps = {\n /** From `useSandboxFiles(...)`. */\n result: UseSandboxFilesResult;\n /**\n * Rendered instead of the built-in tree when the file surface is unavailable\n * (e.g. a `FileSystem.available === false` capability). Default: a quiet notice.\n */\n fallback?: ReactNode | undefined;\n /** Selection callback for the preview pane. */\n onSelectFile?: ((path: string) => void) | undefined;\n selectedPath?: string | undefined;\n /** Render-prop to theme/replace a row entirely (the Pierre-swap escape hatch). */\n renderNode?: ((node: FileTreeNode, depth: number, expanded: boolean) => ReactNode) | undefined;\n /** Shown when the tree is empty (no files / not loaded yet). */\n emptyState?: ReactNode | undefined;\n /**\n * Enable the file-manager affordances (toolbar, context menu, drag-drop move,\n * inline rename, delete, new file/folder). Defaults to `true` when the hook\n * exposes the mutation methods; pass `false` for a strictly read-only tree.\n */\n editable?: boolean | undefined;\n /**\n * Confirm a (recursive) delete before it runs. Return `false` to cancel.\n * Defaults to `window.confirm`. Pass a no-op returning `true` to skip.\n */\n confirmDelete?: ((node: FileTreeNode) => boolean | Promise<boolean>) | undefined;\n className?: string | undefined;\n};\n\nconst STATUS_TINT: Record<NonNullable<FileTreeNode[\"status\"]>, string> = {\n added: \"text-og-status-idle\",\n modified: \"text-og-status-running\",\n deleted: \"text-og-status-failed line-through\",\n renamed: \"text-og-accent\",\n untracked: \"text-og-fg-subtle\",\n};\n\n/** Parent dir of a workspace-relative POSIX path (\"\" for a root entry). */\nfunction parentOf(path: string): string {\n const i = path.lastIndexOf(\"/\");\n return i <= 0 ? \"\" : path.slice(0, i);\n}\n\n/** Join a parent dir with a leaf name (handles the root \"\" parent). */\nfunction joinPath(parent: string, name: string): string {\n return parent ? `${parent}/${name}` : name;\n}\n\n/** Walk the tree to find a node by path. */\nfunction findNode(nodes: FileTreeNode[], path: string): FileTreeNode | undefined {\n for (const node of nodes) {\n if (node.path === path) return node;\n if (node.kind === \"dir\" && node.children && path.startsWith(`${node.path}/`)) {\n const hit = findNode(node.children, path);\n if (hit) return hit;\n }\n }\n return undefined;\n}\n\n/** A pending inline-create: a phantom input row under `parent`. */\ntype DraftCreate = { parent: string; kind: \"file\" | \"dir\" };\n/** A pending inline-rename of an existing node. */\ntype DraftRename = { path: string };\ntype ContextMenuState = { node: FileTreeNode | null; x: number; y: number };\n\n/**\n * The file MANAGER, fed by the FileSystem service via `useSandboxFiles`. This is\n * a first-class editable tree (not a render-only view): lazy-expand with a\n * spinner on the in-flight node, git-status tinting, full keyboard navigation,\n * selection, and the mutating affordances wired straight to the hook —\n *\n * • drag-and-drop MOVE → `moveEntry(from, to)`\n * • inline RENAME → `moveEntry(path, newPath)` (F2 / double-click / menu)\n * • DELETE → `deleteEntry(path, recursive)` (Del / menu, confirmed)\n * • NEW FILE / FOLDER → `createFile` / `createDir` (toolbar + menu), then open\n * • right-click CONTEXT MENU\n *\n * `renderNode` is still honoured as the Pierre-swap escape hatch for the row\n * chrome; the manager scaffolding (toolbar, dnd, menu, inline inputs) wraps it.\n */\nexport function FileBrowser({\n result,\n fallback,\n onSelectFile,\n selectedPath,\n renderNode,\n emptyState,\n editable = true,\n confirmDelete,\n className,\n}: FileBrowserProps) {\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n const [loadingPaths, setLoadingPaths] = useState<Set<string>>(new Set());\n const [active, setActive] = useState<string | null>(null);\n const [draftCreate, setDraftCreate] = useState<DraftCreate | null>(null);\n const [draftRename, setDraftRename] = useState<DraftRename | null>(null);\n const [dragOver, setDragOver] = useState<string | null>(null);\n const [menu, setMenu] = useState<ContextMenuState | null>(null);\n const [busy, setBusy] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n\n // The keyboard cursor: an explicitly-navigated node falls back to the\n // externally-selected file so arrow keys pick up where the preview pane is.\n const cursor = active ?? selectedPath ?? null;\n\n const expand = useCallback(\n async (path: string) => {\n const node = findNode(result.tree, path);\n if (node && node.kind === \"dir\" && node.children === undefined) {\n setLoadingPaths((prev) => new Set(prev).add(path));\n try {\n await result.expand(path);\n } finally {\n setLoadingPaths((prev) => {\n const next = new Set(prev);\n next.delete(path);\n return next;\n });\n }\n }\n },\n [result],\n );\n\n const open = useCallback(\n (path: string) => {\n setExpanded((prev) => new Set(prev).add(path));\n void expand(path);\n },\n [expand],\n );\n\n const toggle = useCallback(\n async (node: FileTreeNode) => {\n if (node.kind !== \"dir\") return;\n const isOpen = expanded.has(node.path);\n setExpanded((prev) => {\n const next = new Set(prev);\n if (isOpen) next.delete(node.path);\n else next.add(node.path);\n return next;\n });\n if (!isOpen) await expand(node.path);\n },\n [expanded, expand],\n );\n\n // The visible rows in DOM order — drives keyboard up/down navigation.\n const flatRows = useMemo(() => {\n const rows: { node: FileTreeNode; depth: number }[] = [];\n const walk = (nodes: FileTreeNode[], depth: number) => {\n for (const node of nodes) {\n rows.push({ node, depth });\n if (node.kind === \"dir\" && expanded.has(node.path) && node.children?.length) {\n walk(node.children, depth + 1);\n }\n }\n };\n walk(result.tree, 0);\n return rows;\n }, [result.tree, expanded]);\n\n const supportsMutation = editable;\n\n const runDelete = useCallback(\n async (node: FileTreeNode) => {\n if (!supportsMutation) return;\n const recursive = node.kind === \"dir\";\n const confirmFn =\n confirmDelete ??\n ((n: FileTreeNode) =>\n typeof window !== \"undefined\" && typeof window.confirm === \"function\"\n ? window.confirm(\n `Delete ${n.kind === \"dir\" ? \"folder\" : \"file\"} \"${n.name}\"${recursive ? \" and its contents\" : \"\"}?`,\n )\n : true);\n const ok = await confirmFn(node);\n if (!ok) return;\n setBusy(true);\n try {\n await result.deleteEntry(node.path, recursive);\n } catch {\n // The hook surfaces the error on `result.error`; the panel renders it.\n } finally {\n setBusy(false);\n }\n },\n [supportsMutation, confirmDelete, result],\n );\n\n const commitCreate = useCallback(\n async (name: string) => {\n const draft = draftCreate;\n setDraftCreate(null);\n if (!draft || !supportsMutation) return;\n const trimmed = name.trim().replace(/\\/+$/, \"\");\n if (!trimmed) return;\n const path = joinPath(draft.parent, trimmed);\n setBusy(true);\n try {\n if (draft.kind === \"dir\") {\n await result.createDir(path);\n open(path);\n } else {\n await result.createFile(path);\n // Open the freshly-created file in the preview/editor pane.\n setActive(path);\n onSelectFile?.(path);\n }\n } catch {\n /* error surfaced via result.error */\n } finally {\n setBusy(false);\n }\n },\n [draftCreate, supportsMutation, result, open, onSelectFile],\n );\n\n const commitRename = useCallback(\n async (name: string) => {\n const draft = draftRename;\n setDraftRename(null);\n if (!draft || !supportsMutation) return;\n const node = findNode(result.tree, draft.path);\n const trimmed = name.trim().replace(/\\/+$/, \"\");\n if (!node || !trimmed || trimmed === node.name) return;\n const newPath = joinPath(parentOf(draft.path), trimmed);\n setBusy(true);\n try {\n await result.moveEntry(draft.path, newPath);\n if (node.kind === \"file\" && (selectedPath === draft.path || active === draft.path)) {\n setActive(newPath);\n onSelectFile?.(newPath);\n }\n } catch {\n /* error surfaced via result.error */\n } finally {\n setBusy(false);\n }\n },\n [draftRename, supportsMutation, result, selectedPath, active, onSelectFile],\n );\n\n // Begin a new file/folder under the active node's directory (or root).\n const startCreate = useCallback(\n (kind: \"file\" | \"dir\") => {\n if (!supportsMutation) return;\n const anchor = cursor ? findNode(result.tree, cursor) : undefined;\n const parent = anchor ? (anchor.kind === \"dir\" ? anchor.path : parentOf(anchor.path)) : \"\";\n if (parent) open(parent);\n setDraftRename(null);\n setMenu(null);\n setDraftCreate({ parent, kind });\n },\n [supportsMutation, cursor, result.tree, open],\n );\n\n const startRename = useCallback(\n (node: FileTreeNode) => {\n if (!supportsMutation) return;\n setDraftCreate(null);\n setMenu(null);\n setDraftRename({ path: node.path });\n },\n [supportsMutation],\n );\n\n // Drag-drop move: drop a node onto a directory (or the root) → moveEntry.\n const onDropOnto = useCallback(\n async (targetDir: string, sourcePath: string) => {\n setDragOver(null);\n if (!supportsMutation || !sourcePath) return;\n const src = findNode(result.tree, sourcePath);\n if (!src) return;\n // No-op drops: onto its own current parent, onto itself, or into its own subtree.\n if (parentOf(sourcePath) === targetDir) return;\n if (targetDir === sourcePath || targetDir.startsWith(`${sourcePath}/`)) return;\n const newPath = joinPath(targetDir, src.name);\n if (newPath === sourcePath) return;\n setBusy(true);\n try {\n await result.moveEntry(sourcePath, newPath);\n if (src.kind === \"file\" && (selectedPath === sourcePath || active === sourcePath)) {\n setActive(newPath);\n onSelectFile?.(newPath);\n }\n } catch {\n /* 409/collision etc. surfaced via result.error */\n } finally {\n setBusy(false);\n }\n },\n [supportsMutation, result, selectedPath, active, onSelectFile],\n );\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLDivElement>) => {\n if (draftCreate || draftRename) return; // inline input owns the keyboard\n if (flatRows.length === 0) return;\n const idx = flatRows.findIndex((r) => r.node.path === cursor);\n const move = (next: number) => {\n const clamped = Math.max(0, Math.min(flatRows.length - 1, next));\n const row = flatRows[clamped];\n if (row) setActive(row.node.path);\n e.preventDefault();\n };\n const cur = idx >= 0 ? flatRows[idx] : undefined;\n switch (e.key) {\n case \"ArrowDown\":\n move(idx < 0 ? 0 : idx + 1);\n break;\n case \"ArrowUp\":\n move(idx < 0 ? 0 : idx - 1);\n break;\n case \"ArrowRight\":\n if (cur?.node.kind === \"dir\") {\n if (!expanded.has(cur.node.path)) open(cur.node.path);\n else move(idx + 1);\n e.preventDefault();\n }\n break;\n case \"ArrowLeft\":\n if (cur) {\n if (cur.node.kind === \"dir\" && expanded.has(cur.node.path)) {\n setExpanded((prev) => {\n const n = new Set(prev);\n n.delete(cur.node.path);\n return n;\n });\n } else {\n const parent = parentOf(cur.node.path);\n if (parent) setActive(parent);\n }\n e.preventDefault();\n }\n break;\n case \"Enter\":\n if (cur) {\n if (cur.node.kind === \"dir\") void toggle(cur.node);\n else onSelectFile?.(cur.node.path);\n e.preventDefault();\n }\n break;\n case \"F2\":\n if (cur) {\n startRename(cur.node);\n e.preventDefault();\n }\n break;\n case \"Delete\":\n case \"Backspace\":\n if (cur && supportsMutation) {\n void runDelete(cur.node);\n e.preventDefault();\n }\n break;\n }\n },\n [draftCreate, draftRename, flatRows, cursor, expanded, open, toggle, onSelectFile, startRename, runDelete, supportsMutation],\n );\n\n // Close the context menu on any outside interaction.\n useEffect(() => {\n if (!menu) return;\n const close = () => setMenu(null);\n window.addEventListener(\"click\", close);\n window.addEventListener(\"scroll\", close, true);\n window.addEventListener(\"resize\", close);\n return () => {\n window.removeEventListener(\"click\", close);\n window.removeEventListener(\"scroll\", close, true);\n window.removeEventListener(\"resize\", close);\n };\n }, [menu]);\n\n const showErrorEmpty = result.error && result.tree.length === 0 && !draftCreate;\n const showEmpty = !result.loading && result.tree.length === 0 && !draftCreate;\n const showToolbar = supportsMutation || Boolean(result.error) || result.loading;\n\n const renderRow = (node: FileTreeNode, depth: number): ReactNode => {\n const isOpen = expanded.has(node.path);\n if (renderNode) {\n return <div key={node.path}>{renderNode(node, depth, isOpen)}</div>;\n }\n const isDir = node.kind === \"dir\";\n const isSelected = node.path === selectedPath || node.path === active;\n const isCursor = node.path === cursor;\n const isLoading = loadingPaths.has(node.path) || result.expandingPaths.has(node.path);\n const isRenaming = draftRename?.path === node.path;\n const isDropTarget = dragOver === (isDir ? node.path : parentOf(node.path));\n const showSkeleton = isDir && isOpen && isLoading && (node.children === undefined || node.children.length === 0);\n const dropDir = isDir ? node.path : parentOf(node.path);\n\n return (\n <div\n key={node.path}\n role=\"treeitem\"\n aria-expanded={isDir ? isOpen : undefined}\n aria-selected={isCursor || undefined}\n aria-busy={isLoading || undefined}\n onDragOver={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n setDragOver(dropDir);\n }\n : undefined\n }\n onDragLeave={\n supportsMutation\n ? (e) => {\n e.stopPropagation();\n setDragOver((cur) => (cur === dropDir ? null : cur));\n }\n : undefined\n }\n onDrop={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n e.stopPropagation();\n const src = e.dataTransfer.getData(\"text/og-path\");\n void onDropOnto(dropDir, src);\n }\n : undefined\n }\n >\n {isRenaming ? (\n <InlineInput\n depth={depth}\n kind={node.kind}\n initialValue={node.name}\n onCommit={(name) => void commitRename(name)}\n onCancel={() => setDraftRename(null)}\n />\n ) : (\n <button\n type=\"button\"\n draggable={supportsMutation || undefined}\n onDragStart={\n supportsMutation\n ? (e) => {\n e.dataTransfer.setData(\"text/og-path\", node.path);\n e.dataTransfer.effectAllowed = \"move\";\n }\n : undefined\n }\n onClick={() => {\n setActive(node.path);\n if (isDir) void toggle(node);\n else onSelectFile?.(node.path);\n }}\n onDoubleClick={() => supportsMutation && startRename(node)}\n onContextMenu={(e) => {\n if (!supportsMutation) return;\n e.preventDefault();\n setActive(node.path);\n setMenu({ node, x: e.clientX, y: e.clientY });\n }}\n className={cn(\n \"group flex w-full items-center gap-1 truncate rounded-og-sm px-1 py-0.5 text-left text-og-sm pointer-coarse:min-h-10\",\n \"hover:bg-og-surface-2\",\n isSelected && \"bg-og-surface-2\",\n isCursor && \"outline outline-1 -outline-offset-1 outline-og-accent\",\n isDropTarget && \"bg-og-accent-soft ring-1 ring-inset ring-og-accent\",\n node.status ? STATUS_TINT[node.status] : undefined,\n )}\n style={{ paddingLeft: `${depth * 12 + 4}px` }}\n >\n {isDir ? (\n isLoading ? (\n <Loader2Icon\n className=\"size-3 shrink-0 animate-spin text-og-fg-subtle\"\n aria-label=\"Loading\"\n />\n ) : (\n <ChevronRightIcon className={cn(\"size-3 shrink-0 transition-transform\", isOpen && \"rotate-90\")} />\n )\n ) : (\n <span className=\"inline-block w-3 shrink-0\" />\n )}\n {isDir ? <FolderIcon className=\"size-3.5 shrink-0\" /> : <FileIcon className=\"size-3.5 shrink-0\" />}\n <span className=\"truncate\">{node.name}</span>\n {supportsMutation && (\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label=\"More actions\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n setActive(node.path);\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n setMenu({ node, x: rect.right, y: rect.bottom });\n }}\n className=\"ml-auto hidden shrink-0 px-1 text-og-fg-subtle hover:text-og-fg group-hover:inline\"\n >\n ⋯\n </span>\n )}\n </button>\n )}\n\n {/* Inline create input nested directly under an expanded directory. */}\n {draftCreate?.parent === node.path && isDir && isOpen && (\n <InlineInput\n depth={depth + 1}\n kind={draftCreate.kind}\n initialValue=\"\"\n onCommit={(name) => void commitCreate(name)}\n onCancel={() => setDraftCreate(null)}\n />\n )}\n\n {showSkeleton && (\n <div\n role=\"group\"\n aria-hidden\n style={{ paddingLeft: `${(depth + 1) * 12 + 4}px` }}\n className=\"space-y-1 py-1\"\n >\n {[0, 1, 2].map((i) => (\n <div\n key={i}\n className=\"h-2.5 animate-pulse rounded-og-sm bg-og-surface-2\"\n style={{ width: `${70 - i * 12}%` }}\n />\n ))}\n </div>\n )}\n {isDir && isOpen && node.children && node.children.length > 0 && (\n <div role=\"group\">{node.children.map((child) => renderRow(child, depth + 1))}</div>\n )}\n </div>\n );\n };\n\n return (\n <div className={cn(\"flex min-w-0 flex-col\", className)}>\n {showToolbar && (\n <div className=\"flex shrink-0 flex-wrap items-center gap-0.5 border-b border-og-border px-1 py-1\">\n {supportsMutation ? (\n <>\n <ToolbarButton label=\"New file\" onClick={() => startCreate(\"file\")} disabled={busy}>\n <FilePlusIcon className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton label=\"New folder\" onClick={() => startCreate(\"dir\")} disabled={busy}>\n <FolderPlusIcon className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n label=\"Rename\"\n onClick={() => {\n const node = cursor ? findNode(result.tree, cursor) : undefined;\n if (node) startRename(node);\n }}\n disabled={busy || !cursor}\n >\n <PencilIcon className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n label=\"Delete\"\n onClick={() => {\n const node = cursor ? findNode(result.tree, cursor) : undefined;\n if (node) void runDelete(node);\n }}\n disabled={busy || !cursor}\n >\n <Trash2Icon className=\"size-3.5\" />\n </ToolbarButton>\n </>\n ) : null}\n <span className=\"ml-auto\" />\n <ToolbarButton label=\"Refresh\" onClick={() => void result.refresh()} disabled={busy || result.loading}>\n <RefreshCwIcon className={cn(\"size-3.5\", result.loading && \"animate-spin\")} />\n </ToolbarButton>\n </div>\n )}\n\n {/* The tree itself. The root is a drop target so a node can be moved to \"\". */}\n {/* biome-ignore lint/a11y/noNoninteractiveTabindex: the tree owns keyboard nav */}\n <div\n ref={containerRef}\n role=\"tree\"\n tabIndex={0}\n aria-multiselectable={false}\n onKeyDown={onKeyDown}\n onDragOver={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n setDragOver(\"\");\n }\n : undefined\n }\n onDrop={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n const src = e.dataTransfer.getData(\"text/og-path\");\n void onDropOnto(\"\", src);\n }\n : undefined\n }\n className={cn(\n \"min-w-0 flex-1 overflow-auto p-1 outline-none\",\n dragOver === \"\" && \"ring-1 ring-inset ring-og-accent\",\n )}\n data-opengeni-file-tree\n >\n {/* A root-level create input sits above the rows. */}\n {draftCreate?.parent === \"\" && (\n <InlineInput\n depth={0}\n kind={draftCreate.kind}\n initialValue=\"\"\n onCommit={(name) => void commitCreate(name)}\n onCancel={() => setDraftCreate(null)}\n />\n )}\n {showErrorEmpty ? (\n <div className=\"flex flex-col items-start gap-2 p-2 text-og-sm text-og-fg-subtle\">\n <div>{fallback ?? `Could not load files: ${result.error?.message ?? \"refresh the file list to try again\"}`}</div>\n <button\n type=\"button\"\n onClick={() => void result.refresh()}\n disabled={result.loading}\n className=\"inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-10\"\n >\n <RefreshCwIcon className={cn(\"size-3.5\", result.loading && \"animate-spin\")} aria-hidden />\n Retry\n </button>\n </div>\n ) : showEmpty ? (\n <div className=\"p-2 text-og-sm text-og-fg-subtle\">\n {emptyState ?? \"This directory is empty\"}\n </div>\n ) : (\n result.tree.map((node) => renderRow(node, 0))\n )}\n </div>\n\n {menu && menu.node && (\n <ContextMenu\n node={menu.node}\n x={menu.x}\n y={menu.y}\n onRename={() => menu.node && startRename(menu.node)}\n onDelete={() => menu.node && void runDelete(menu.node)}\n onNewFile={() => startCreate(\"file\")}\n onNewFolder={() => startCreate(\"dir\")}\n />\n )}\n </div>\n );\n}\n\nfunction ToolbarButton({\n label,\n onClick,\n disabled,\n children,\n}: {\n label: string;\n onClick: () => void;\n disabled?: boolean;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n title={label}\n aria-label={label}\n onClick={onClick}\n disabled={disabled}\n className={cn(\n \"inline-flex items-center justify-center rounded-og-sm p-1 text-og-fg-muted pointer-coarse:min-h-10 pointer-coarse:min-w-10\",\n \"hover:bg-og-surface-2 hover:text-og-fg\",\n \"disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n >\n {children}\n </button>\n );\n}\n\n/** An inline text input for create / rename, indented to match its row depth. */\nfunction InlineInput({\n depth,\n kind,\n initialValue,\n onCommit,\n onCancel,\n}: {\n depth: number;\n kind: \"file\" | \"dir\";\n initialValue: string;\n onCommit: (value: string) => void;\n onCancel: () => void;\n}) {\n const [value, setValue] = useState(initialValue);\n const ref = useRef<HTMLInputElement | null>(null);\n // Track whether we've already resolved so a blur after Enter/Escape is a no-op.\n const doneRef = useRef(false);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n el.focus();\n // Select the basename (excluding any extension) for a rename, like an IDE.\n const dot = initialValue.lastIndexOf(\".\");\n if (initialValue && dot > 0) el.setSelectionRange(0, dot);\n else el.select();\n }, [initialValue]);\n\n const finish = (commit: boolean) => {\n if (doneRef.current) return;\n doneRef.current = true;\n if (commit) onCommit(value);\n else onCancel();\n };\n\n return (\n <div className=\"flex items-center gap-1 px-1 py-0.5\" style={{ paddingLeft: `${depth * 12 + 4}px` }}>\n <span className=\"inline-block w-3 shrink-0\" />\n {kind === \"dir\" ? <FolderIcon className=\"size-3.5 shrink-0\" /> : <FileIcon className=\"size-3.5 shrink-0\" />}\n <input\n ref={ref}\n value={value}\n spellCheck={false}\n autoComplete=\"off\"\n aria-label={kind === \"dir\" ? \"Folder name\" : \"File name\"}\n onChange={(e) => setValue(e.target.value)}\n onBlur={() => finish(true)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n finish(true);\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n finish(false);\n }\n e.stopPropagation();\n }}\n className={cn(\n \"min-w-0 flex-1 rounded-og-sm border bg-og-bg px-1 py-0 text-og-sm\",\n \"border-og-accent text-og-fg\",\n \"outline-none\",\n )}\n />\n </div>\n );\n}\n\n/** The right-click / kebab context menu, positioned at the click point. */\nfunction ContextMenu({\n node,\n x,\n y,\n onRename,\n onDelete,\n onNewFile,\n onNewFolder,\n}: {\n node: FileTreeNode;\n x: number;\n y: number;\n onRename: () => void;\n onDelete: () => void;\n onNewFile: () => void;\n onNewFolder: () => void;\n}) {\n const isDir = node.kind === \"dir\";\n // Keep the menu on-screen when opened near the viewport edge.\n const vw = typeof window !== \"undefined\" ? window.innerWidth : 9999;\n const vh = typeof window !== \"undefined\" ? window.innerHeight : 9999;\n const left = Math.min(x, vw - 180);\n const top = Math.min(y, vh - 160);\n\n const item = (label: string, icon: ReactNode, onClick: () => void, danger?: boolean) => (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n className={cn(\n \"flex w-full items-center gap-2 px-2.5 py-1 text-left text-og-sm pointer-coarse:min-h-10\",\n \"hover:bg-og-surface-2\",\n danger ? \"text-og-status-failed\" : \"text-og-fg\",\n )}\n >\n {icon}\n {label}\n </button>\n );\n\n return (\n <div\n role=\"menu\"\n onClick={(e) => e.stopPropagation()}\n style={{ left, top }}\n className={cn(\n \"fixed z-50 min-w-[160px] overflow-hidden rounded-md border py-1 shadow-lg\",\n \"border-og-border\",\n \"bg-og-surface-1\",\n )}\n >\n {isDir && (\n <>\n {item(\"New file\", <FilePlusIcon className=\"size-3.5\" />, onNewFile)}\n {item(\"New folder\", <FolderPlusIcon className=\"size-3.5\" />, onNewFolder)}\n <div className=\"my-1 h-px bg-og-border\" />\n </>\n )}\n {item(\"Rename\", <PencilIcon className=\"size-3.5\" />, onRename)}\n {item(\"Delete\", <Trash2Icon className=\"size-3.5\" />, onDelete, true)}\n </div>\n );\n}\n","import {\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n lazy,\n Suspense,\n useEffect,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/** Pierre `File` props subset we drive — the single-file, syntax-highlighted view\n * (Shiki), the read counterpart of `PatchDiff`. */\ntype FileComponent = ComponentType<{\n file: { name: string; contents: string; lang?: string };\n options?: {\n theme?: string | { dark: string; light: string };\n themeType?: \"dark\" | \"light\";\n overflow?: \"scroll\" | \"wrap\";\n stickyHeader?: boolean;\n showLineNumbers?: boolean;\n };\n disableWorkerPool?: boolean;\n className?: string;\n}>;\n\nexport type PierreFileProps = {\n /** Workspace-relative path (used for the header + language inference). */\n path: string;\n /** The decoded text contents. */\n contents: string;\n themeType?: \"dark\" | \"light\" | undefined;\n /** Shiki bundled theme names (dark/light) — derived from the host palette. */\n theme?: { dark: string; light: string } | undefined;\n /** Disable Pierre's worker pool if its worker bundling fights the host bundler. */\n disableWorkerPool?: boolean | undefined;\n /** Rendered while the (lazy) Pierre bundle loads. */\n loading?: ReactNode | undefined;\n /** Rendered if `@pierre/diffs/react` is not installed / fails to import. */\n fallback?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n// Lazy-load `@pierre/diffs/react`'s `File` so Shiki + the worker pool stay off the\n// critical path (and out of an SSR bundle) until a file is actually viewed.\nconst LazyFile = lazy(async () => {\n const mod = (await import(\"@pierre/diffs/react\")) as unknown as { File: FileComponent };\n return { default: mod.File };\n});\n\n/**\n * The Pierre-backed single-file VIEWER: Shiki-highlighted, language inferred from\n * the filename — the read complement of `PierreDiff`. Wired to `fs.read` so\n * clicking any file in the tree shows its contents (NOT a diff; no repo needed).\n * Falls back to a plain `<pre>` when `@pierre/diffs` is absent / fails to import.\n */\nexport function PierreFile({\n path,\n contents,\n themeType,\n theme,\n disableWorkerPool,\n loading,\n fallback,\n className,\n}: PierreFileProps) {\n const [failed, setFailed] = useState(false);\n\n // Probe the import once so a hard failure (peer missing) shows `fallback`\n // rather than a Suspense boundary that never resolves.\n useEffect(() => {\n let cancelled = false;\n void import(\"@pierre/diffs/react\").catch(() => {\n if (!cancelled) setFailed(true);\n });\n return () => {\n cancelled = true;\n };\n }, []);\n\n const name = path.split(\"/\").filter(Boolean).pop() ?? path;\n\n if (failed) {\n return (\n <div className={className}>\n {fallback ?? <PlainFile name={name} contents={contents} />}\n </div>\n );\n }\n\n const options = {\n overflow: \"scroll\" as const,\n stickyHeader: true,\n showLineNumbers: true,\n ...(theme ? { theme } : { theme: { dark: \"github-dark\", light: \"github-light\" } }),\n themeType: themeType ?? \"dark\",\n };\n\n // Same shadow-DOM override vars as PierreDiff: pin the base background to the\n // dock surface so the viewer reads as part of the panel, not a black seam.\n const pierreVars = {\n \"--diffs-dark-bg\": \"var(--og-color-bg)\",\n \"--diffs-light-bg\": \"var(--og-color-bg)\",\n \"--diffs-bg-buffer-override\": \"var(--og-color-surface-1)\",\n \"--diffs-bg-separator-override\": \"var(--og-color-surface-1)\",\n \"--diffs-font-size\": \"var(--og-code-font-size)\",\n \"--diffs-line-height\": \"var(--og-code-line-height)\",\n } as CSSProperties;\n\n return (\n <div className={cn(\"min-w-0\", className)} data-opengeni-pierre-file style={pierreVars}>\n <Suspense fallback={loading ?? <FileSkeleton />}>\n {/* `cacheKey` keys Pierre's worker-pool highlight cache on path+size so a\n re-select of the same file is instant but an edited file re-highlights. */}\n <LazyFile\n file={{ name, contents }}\n options={options}\n {...(disableWorkerPool !== undefined ? { disableWorkerPool } : {})}\n />\n </Suspense>\n </div>\n );\n}\n\nfunction PlainFile({ name, contents }: { name: string; contents: string }) {\n return (\n <pre\n className=\"overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg\"\n data-file={name}\n >\n {contents}\n </pre>\n );\n}\n\nfunction FileSkeleton() {\n return (\n <div className=\"p-3 text-og-sm text-og-fg-subtle\">\n Loading file…\n </div>\n );\n}\n","import { Loader2Icon, SaveIcon } from \"lucide-react\";\nimport {\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n lazy,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\n\n// --- Lazy CodeMirror surface ----------------------------------------------\n//\n// CodeMirror 6 (via @uiw/react-codemirror) plus the per-language grammars are a\n// heavy bundle (lezer parsers, the view layer). We keep them OFF the critical\n// path and out of any SSR bundle by lazy-importing only when a file is actually\n// EDITED. The read-only viewer stays Pierre's Shiki `File`; this is the\n// editable complement, mounted on demand.\n\n/** The subset of `@uiw/react-codemirror`'s props we drive. */\ntype ReactCodeMirrorComponent = ComponentType<{\n value?: string;\n height?: string;\n theme?: \"light\" | \"dark\" | \"none\" | unknown;\n editable?: boolean;\n readOnly?: boolean;\n basicSetup?: boolean | Record<string, boolean>;\n extensions?: unknown[];\n onChange?: ((value: string) => void) | undefined;\n className?: string;\n style?: CSSProperties;\n}>;\n\n// Resolved lazily on first edit: the editor component + the keymap/Prec helpers\n// (both re-exported from @uiw/react-codemirror, which re-exports @codemirror/view\n// and @codemirror/state) + the chosen language extension.\ntype EditorBundle = {\n Editor: ReactCodeMirrorComponent;\n saveKeymapExtension: (onSave: () => void) => unknown;\n languageExtension: unknown | null;\n};\n\n/** Language grammar loaders, keyed by the extension class we infer from the path. */\nconst LANGUAGE_LOADERS: Record<string, () => Promise<unknown>> = {\n javascript: async () =>\n (await import(\"@codemirror/lang-javascript\")).javascript({ jsx: true, typescript: true }),\n json: async () => (await import(\"@codemirror/lang-json\")).json(),\n python: async () => (await import(\"@codemirror/lang-python\")).python(),\n markdown: async () => (await import(\"@codemirror/lang-markdown\")).markdown(),\n css: async () => (await import(\"@codemirror/lang-css\")).css(),\n html: async () => (await import(\"@codemirror/lang-html\")).html(),\n};\n\n/** Map a filename to a grammar key (or null for plain text — still fully editable). */\nexport function languageForPath(path: string): keyof typeof LANGUAGE_LOADERS | null {\n const name = path.split(\"/\").pop() ?? path;\n const ext = name.includes(\".\") ? (name.split(\".\").pop() ?? \"\").toLowerCase() : \"\";\n switch (ext) {\n case \"js\":\n case \"jsx\":\n case \"ts\":\n case \"tsx\":\n case \"mjs\":\n case \"cjs\":\n return \"javascript\";\n case \"json\":\n case \"jsonc\":\n return \"json\";\n case \"py\":\n case \"pyi\":\n return \"python\";\n case \"md\":\n case \"markdown\":\n case \"mdx\":\n return \"markdown\";\n case \"css\":\n case \"scss\":\n case \"less\":\n return \"css\";\n case \"html\":\n case \"htm\":\n case \"xml\":\n case \"svg\":\n case \"vue\":\n return \"html\";\n default:\n return null;\n }\n}\n\nconst LazyCodeMirror = lazy(async () => {\n const mod = (await import(\"@uiw/react-codemirror\")) as unknown as {\n default: ReactCodeMirrorComponent;\n };\n return { default: mod.default };\n});\n\nexport type CodeEditorProps = {\n /** Workspace-relative path — drives language inference (and the save target upstream). */\n path: string;\n /** The decoded text contents to seed the editor with. */\n initialContents: string;\n /** Persist the current buffer. Resolves when the write lands; rejects to surface an error. */\n onSave: (contents: string) => Promise<unknown>;\n /** Read-only mode (e.g. a truncated/too-large file shown for reference only). */\n readOnly?: boolean | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n /** Rendered while the (lazy) CodeMirror bundle loads. */\n loading?: ReactNode | undefined;\n /** Rendered if `@uiw/react-codemirror` is not installed / fails to import. */\n fallback?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n/**\n * The EDITABLE single-file pane: CodeMirror 6 with a per-language grammar chosen\n * from the filename, og-* themed, with dirty tracking and a save path wired to\n * `Cmd/Ctrl+S` *and* an explicit Save button. The viewer (Pierre `File`) stays\n * the read-only complement — this is only mounted when the user opts to edit.\n *\n * Save semantics: the buffer is \"dirty\" the moment it diverges from the last\n * saved baseline; a successful `onSave` clears dirty and re-baselines. A failed\n * save keeps the buffer dirty (nothing is lost) and surfaces the error inline.\n * `readOnly` suppresses every mutation path so a truncated/binary file can never\n * be saved back (which would corrupt it by writing the truncated prefix).\n */\nexport function CodeEditor({\n path,\n initialContents,\n onSave,\n readOnly = false,\n themeType = \"dark\",\n loading,\n fallback,\n className,\n}: CodeEditorProps) {\n const [failed, setFailed] = useState(false);\n const [bundle, setBundle] = useState<EditorBundle | null>(null);\n\n // The live buffer + the baseline it's compared against for dirtiness. The\n // baseline resets whenever a *new* file is loaded (path/initialContents change)\n // or after a successful save.\n const [value, setValue] = useState(initialContents);\n const [baseline, setBaseline] = useState(initialContents);\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<Error | null>(null);\n const [savedTick, setSavedTick] = useState(false);\n\n const dirty = value !== baseline;\n\n // Reload the buffer when the file identity changes. Guard on initialContents\n // too so an external refresh of the SAME path (e.g. fs.changed re-read) reseeds\n // a clean buffer — but only when the user hasn't got unsaved edits in flight.\n const lastSeed = useRef<{ path: string; contents: string }>({ path, contents: initialContents });\n useEffect(() => {\n const seedChanged =\n lastSeed.current.path !== path || lastSeed.current.contents !== initialContents;\n if (!seedChanged) return;\n lastSeed.current = { path, contents: initialContents };\n setValue(initialContents);\n setBaseline(initialContents);\n setSaveError(null);\n setSavedTick(false);\n }, [path, initialContents]);\n\n // Resolve the lazy bundle (editor + keymap/Prec helpers + language grammar)\n // once, re-resolving the grammar when the file's language class changes.\n const langKey = useMemo(() => languageForPath(path), [path]);\n useEffect(() => {\n let cancelled = false;\n void (async () => {\n try {\n const cmMod = (await import(\"@uiw/react-codemirror\")) as unknown as {\n default: ReactCodeMirrorComponent;\n keymap: { of: (binds: unknown[]) => unknown };\n Prec: { highest: (ext: unknown) => unknown };\n };\n const languageExtension = langKey ? await LANGUAGE_LOADERS[langKey]?.() : null;\n if (cancelled) return;\n // A high-precedence Cmd/Ctrl-S keymap that calls back into the latest\n // save handler (kept fresh via a ref) and swallows the browser's\n // \"save page\" default.\n const saveKeymapExtension = (run: () => void) =>\n cmMod.Prec.highest(\n cmMod.keymap.of([\n {\n key: \"Mod-s\",\n preventDefault: true,\n run: () => {\n run();\n return true;\n },\n },\n ]),\n );\n setBundle({\n Editor: cmMod.default,\n saveKeymapExtension,\n languageExtension: languageExtension ?? null,\n });\n } catch {\n if (!cancelled) setFailed(true);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [langKey]);\n\n // Keep the freshest save closure reachable from the (stable) keymap binding.\n const saveRef = useRef<() => void>(() => {});\n\n const save = useCallback(async () => {\n if (readOnly) return;\n // Snapshot the buffer at call time so an in-flight edit can't race the write.\n const snapshot = value;\n if (snapshot === baseline) return; // nothing to persist\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onSave(snapshot);\n setBaseline(snapshot);\n lastSeed.current = { path, contents: snapshot };\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setSaving(false);\n }\n }, [readOnly, value, baseline, onSave, path]);\n\n saveRef.current = () => {\n void save();\n };\n\n // A brief \"Saved\" affordance after a successful write, cleared on the next edit.\n useEffect(() => {\n if (!savedTick) return;\n const t = setTimeout(() => setSavedTick(false), 1800);\n return () => clearTimeout(t);\n }, [savedTick]);\n\n const fileName = path.split(\"/\").filter(Boolean).pop() ?? path;\n\n const cmExtensions = useMemo(() => {\n if (!bundle) return [] as unknown[];\n const exts: unknown[] = [bundle.saveKeymapExtension(() => saveRef.current())];\n if (bundle.languageExtension) exts.push(bundle.languageExtension);\n return exts;\n }, [bundle]);\n\n if (failed) {\n return (\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n {fallback ?? (\n <PlainTextarea\n value={value}\n readOnly={readOnly}\n onChange={(next) => {\n setValue(next);\n setSavedTick(false);\n }}\n />\n )}\n </div>\n );\n }\n\n return (\n <div\n className={cn(\"flex h-full min-h-0 flex-col\", className)}\n data-opengeni-code-editor\n style={editorVars}\n >\n {/* Save bar: dirty indicator + status + the explicit Save button. */}\n <div className=\"flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1\">\n <span\n className={cn(\n \"size-1.5 shrink-0 rounded-full transition-colors\",\n readOnly\n ? \"bg-transparent\"\n : dirty\n ? \"bg-og-status-running\"\n : \"bg-og-status-idle\",\n )}\n title={readOnly ? \"read-only\" : dirty ? \"unsaved changes\" : \"saved\"}\n />\n <span className=\"truncate font-og-mono text-og-xs text-og-fg-muted\">\n {fileName}\n {dirty && !readOnly ? \" •\" : \"\"}\n </span>\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {saveError && (\n <span\n className=\"max-w-[220px] truncate text-og-xs text-og-status-failed\"\n title={saveError.message}\n >\n {saveError.message}\n </span>\n )}\n {!saveError && savedTick && (\n <span className=\"text-og-xs text-og-status-idle\">\n Saved\n </span>\n )}\n {readOnly ? (\n <span className=\"text-og-xs uppercase tracking-wide text-og-fg-subtle\">\n Read-only\n </span>\n ) : (\n <button\n type=\"button\"\n onClick={() => void save()}\n disabled={saving || !dirty}\n className={cn(\n \"flex items-center gap-1 rounded-og-sm border border-og-border px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10\",\n saving || !dirty\n ? \"cursor-default text-og-fg-subtle opacity-60\"\n : \"text-og-fg hover:bg-og-accent-soft\",\n )}\n title=\"Save (⌘/Ctrl+S)\"\n >\n {saving ? (\n <Loader2Icon className=\"size-3 animate-spin\" />\n ) : (\n <SaveIcon className=\"size-3\" />\n )}\n Save\n </button>\n )}\n </div>\n </div>\n\n {/* The editor surface. */}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <Suspense fallback={loading ?? <EditorSkeleton />}>\n <LazyCodeMirror\n value={value}\n theme={themeType === \"light\" ? \"light\" : \"dark\"}\n editable={!readOnly}\n readOnly={readOnly}\n basicSetup={true}\n extensions={cmExtensions}\n height=\"100%\"\n className=\"og-cm-editor min-h-full text-og-sm\"\n onChange={\n readOnly\n ? undefined\n : (next: string) => {\n setValue(next);\n setSavedTick(false);\n }\n }\n />\n </Suspense>\n </div>\n </div>\n );\n}\n\n/** og-* themed CSS-var overrides handed to CodeMirror's container. */\nconst editorVars = {\n \"--og-cm-bg\": \"var(--og-color-bg)\",\n fontFamily: \"var(--og-font-mono)\",\n} as CSSProperties;\n\nfunction PlainTextarea({\n value,\n readOnly,\n onChange,\n}: {\n value: string;\n readOnly: boolean;\n onChange: (value: string) => void;\n}) {\n return (\n <textarea\n value={value}\n readOnly={readOnly}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n className=\"h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-none\"\n />\n );\n}\n\nfunction EditorSkeleton() {\n return (\n <div className=\"p-3 text-og-sm text-og-fg-subtle\">\n Loading editor…\n </div>\n );\n}\n","import type { FsReadResponse, GitFileDiff } from \"@opengeni/sdk\";\nimport { FileIcon } from \"lucide-react\";\nimport { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport type { UseSandboxFilesResult } from \"../hooks/use-sandbox-files\";\nimport type { UseSandboxGitResult } from \"../hooks/use-sandbox-git\";\nimport { CodeEditor } from \"./code-editor\";\nimport { FileBrowser } from \"./file-browser\";\nimport { DiffView } from \"./diff-view\";\nimport { PierreDiff } from \"./pierre-diff\";\nimport { PierreFile } from \"./pierre-file\";\n\nexport type SandboxFilesProps = {\n /** From `useSandboxFiles(...)`. */\n files: UseSandboxFilesResult;\n /** From `useSandboxGit(...)` — the working-tree diff. */\n git: UseSandboxGitResult;\n /** From a second `useSandboxGit(..., { staged: true })` — the staged diff. */\n stagedGit?: UseSandboxGitResult | undefined;\n /** Whether a FileSystem surface is advertised (drives the unavailable notice). */\n fileSystemAvailable?: boolean | undefined;\n /** Use Pierre's Shiki-highlighted diff (default true; falls back to built-in). */\n usePierre?: boolean | undefined;\n /** Allow in-place editing of tree files (CodeMirror). Default true. When false\n * the surface is review-only: every text file opens in the read-only viewer. */\n editable?: boolean | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n className?: string | undefined;\n};\n\nconst STATUS_TINT: Record<GitFileDiff[\"status\"], string> = {\n added: \"text-og-status-idle\",\n modified: \"text-og-status-running\",\n deleted: \"text-og-status-failed\",\n renamed: \"text-og-accent\",\n copied: \"text-og-accent\",\n untracked: \"text-og-fg-subtle\",\n ignored: \"text-og-fg-subtle\",\n conflicted: \"text-og-status-failed\",\n typechange: \"text-og-status-running\",\n};\n\nconst STATUS_LETTER: Record<GitFileDiff[\"status\"], string> = {\n added: \"A\",\n modified: \"M\",\n deleted: \"D\",\n renamed: \"R\",\n copied: \"C\",\n untracked: \"U\",\n ignored: \"I\",\n conflicted: \"!\",\n typechange: \"T\",\n};\n\n/**\n * The review-first Files surface: a sticky branch/dirty header, a \"Changes\"\n * group (changed files vs HEAD, badged), the full lazy file tree for context,\n * and an inline diff pane below for the selected changed file. The agent\n * commits; the human reviews — there is no stage/commit/push UI here (power-git\n * lives in the terminal).\n */\nexport function SandboxFiles({\n files,\n git,\n stagedGit,\n fileSystemAvailable = true,\n usePierre = true,\n editable = true,\n themeType,\n className,\n}: SandboxFilesProps) {\n const [selected, setSelected] = useState<string | null>(null);\n const [staged, setStaged] = useState(false);\n const [layout, setLayout] = useState<\"unified\" | \"split\">(\"unified\");\n // View vs Edit for the read-only-viewer branch (a tree file that is NOT a\n // diff). Resets to View on every new selection so opening a file never lands\n // you in a stale dirty editor for a different path.\n const [editMode, setEditMode] = useState(false);\n\n // Side-by-side (tree left, diff right) once the surface is wide enough;\n // stacked (tree over diff) on a narrow dock. Tracked off the container so it\n // reacts to the dock resize, not just the viewport.\n const rootRef = useRef<HTMLDivElement | null>(null);\n const [wide, setWide] = useState(false);\n useEffect(() => {\n const el = rootRef.current;\n if (!el || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver((entries) => {\n const w = entries[0]?.contentRect.width ?? 0;\n setWide(w >= 720);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n // Resolve the effective diff theme from the host palette (the `data-og-theme`\n // attribute the demo/app sets), defaulting to dark, unless the caller forced\n // one. Keeps the Pierre diff dark-on-dark instead of a white slab.\n const resolvedTheme = useThemeType(themeType);\n\n const activeGit = staged && stagedGit ? stagedGit : git;\n const changed = activeGit.diff;\n const changedPaths = useMemo(() => new Set(changed.map((f) => f.path)), [changed]);\n\n // The selection is EITHER a changed file (-> diff pane) or any tree file\n // (-> read-only viewer pane). An explicit pick wins; otherwise default to the\n // first changed file so a review-first dock opens on a diff. Crucially this is\n // NOT gated on a repo: with no changes (or no repo) the pane simply waits for a\n // tree click, and a clicked tree file always resolves to the viewer.\n const effectiveSelected = selected ?? changed[0]?.path ?? null;\n const selectedDiff = changed.find((f) => f.path === effectiveSelected) ?? null;\n // A selected path that is not a changed file is viewed (fs.read), not diffed.\n const viewPath = effectiveSelected && !selectedDiff ? effectiveSelected : null;\n\n // Read the selected file's contents for the viewer pane (text/base64). The\n // hook caps size + flags binary; we surface a notice for binary rather than\n // dumping base64 into the highlighter.\n const fileView = useFileView(viewPath, files.readFile);\n\n // Selecting a (different) file always returns to View — never drop the user\n // into an editor whose buffer belongs to the previously-selected path.\n const selectFile = useCallback((path: string) => {\n setSelected(path);\n setEditMode(false);\n }, []);\n\n // A tree file is editable only when it is a real, fully-loaded text file: not\n // binary (would corrupt on save) and not truncated (we only hold a PREFIX, so\n // a save would write the prefix back and lose the tail). The editor is then\n // additionally gated on the `editable` prop. Anything failing this opens\n // read-only in the viewer.\n const canEdit =\n editable &&\n viewPath !== null &&\n !fileView.loading &&\n fileView.error === null &&\n !fileView.isBinary &&\n !fileView.truncated &&\n fileView.content !== null;\n const showEditor = canEdit && editMode;\n\n if (!fileSystemAvailable) {\n return (\n <Notice className={className}>This sandbox does not expose a file system.</Notice>\n );\n }\n\n return (\n <div ref={rootRef} className={cn(\"flex h-full min-h-0 min-w-0 flex-col\", className)}>\n {/* Branch + dirty header */}\n <GitHeader git={git} dirtyCount={changedPaths.size} />\n\n <div className={cn(\"flex min-h-0 flex-1\", wide ? \"flex-row\" : \"flex-col\")}>\n {/* Tree pane: Changes group + full tree. A fixed left column when wide,\n a top band when narrow. */}\n <div\n className={cn(\n \"min-h-0 overflow-auto\",\n wide\n ? \"w-[280px] shrink-0 border-r border-og-border\"\n : \"flex-1\",\n )}\n >\n {changed.length > 0 && (\n <div className=\"border-b border-og-border\">\n <div className=\"px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle\">\n Changes · {changed.length}\n </div>\n <ul className=\"pb-1\">\n {changed.map((file) => (\n <li key={file.path}>\n <button\n type=\"button\"\n onClick={() => selectFile(file.path)}\n className={cn(\n \"flex w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-og-sm hover:bg-og-surface-2 pointer-coarse:min-h-10\",\n file.path === effectiveSelected && \"bg-og-surface-2\",\n )}\n >\n <span\n className={cn(\n \"w-3 shrink-0 text-center font-og-mono text-og-xs\",\n STATUS_TINT[file.status],\n )}\n >\n {STATUS_LETTER[file.status]}\n </span>\n <FileIcon className=\"size-3.5 shrink-0 opacity-70\" />\n <span className=\"truncate\">{file.path}</span>\n <span className=\"ml-auto flex shrink-0 items-center gap-1.5 pl-2 text-og-xs\">\n <span className=\"text-og-status-idle\">\n +{file.additions}\n </span>\n <span className=\"text-og-status-failed\">\n −{file.deletions}\n </span>\n </span>\n </button>\n </li>\n ))}\n </ul>\n </div>\n )}\n\n <div className=\"px-2 py-1 text-og-xs font-medium uppercase tracking-wide text-og-fg-subtle\">\n Files\n </div>\n <FileBrowser\n result={files}\n selectedPath={effectiveSelected ?? undefined}\n onSelectFile={selectFile}\n emptyState=\"This directory is empty\"\n className=\"min-w-0\"\n />\n </div>\n\n {/* Diff pane: the selected file's diff. Fills the remaining width when\n side-by-side, sits below the tree when stacked. */}\n <div\n className={cn(\n \"flex min-h-0 min-w-0 flex-col\",\n wide\n ? \"flex-1\"\n : \"flex-[1.4] border-t border-og-border\",\n )}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1\">\n <span className=\"min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted\">\n {effectiveSelected ?? \"No file selected\"}\n </span>\n <div className=\"flex min-w-0 shrink-0 flex-wrap items-center justify-end gap-1\">\n {/* The Working/Staged + Unified/Split toggles only apply to a diff.\n Hide them in the read-only viewer (a non-changed tree file). */}\n {selectedDiff && stagedGit && (\n <Segmented\n options={[\n { value: \"working\", label: \"Working tree\" },\n { value: \"staged\", label: \"Staged\" },\n ]}\n value={staged ? \"staged\" : \"working\"}\n onChange={(v) => setStaged(v === \"staged\")}\n />\n )}\n {selectedDiff && (\n <Segmented\n options={[\n { value: \"unified\", label: \"Unified\" },\n { value: \"split\", label: \"Split\" },\n ]}\n value={layout}\n onChange={(v) => setLayout(v as \"unified\" | \"split\")}\n />\n )}\n {/* View/Edit toggle — only for a real, fully-loaded text file the\n editor can safely round-trip. Binary/truncated files never get\n an Edit affordance (they'd corrupt on save). */}\n {!selectedDiff && canEdit && (\n <Segmented\n options={[\n { value: \"view\", label: \"View\" },\n { value: \"edit\", label: \"Edit\" },\n ]}\n value={editMode ? \"edit\" : \"view\"}\n onChange={(v) => setEditMode(v === \"edit\")}\n />\n )}\n </div>\n </div>\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {selectedDiff ? (\n // A changed file -> diff pane (HEAD vs working/staged).\n usePierre ? (\n <PierreDiff\n diff={[selectedDiff]}\n layout={layout}\n themeType={resolvedTheme}\n fallback={\n <DiffView diff={[selectedDiff]} layout={layout} isRepo={git.isRepo} className=\"p-1\" />\n }\n className=\"p-1\"\n />\n ) : (\n <DiffView diff={[selectedDiff]} layout={layout} isRepo={git.isRepo} className=\"p-1\" />\n )\n ) : viewPath ? (\n // Any other tree file -> editable editor (Edit mode) or read-only\n // single-file viewer (fs.read). This works with NO repo — viewing\n // and editing files never requires git.\n showEditor && fileView.content !== null ? (\n <CodeEditor\n key={viewPath}\n path={viewPath}\n initialContents={fileView.content}\n themeType={resolvedTheme}\n onSave={(contents) => files.writeFile(viewPath, contents)}\n className=\"h-full\"\n />\n ) : fileView.error ? (\n <Notice>Could not open {viewPath}: {fileView.error.message}</Notice>\n ) : fileView.loading ? (\n <Notice>Loading {viewPath}…</Notice>\n ) : fileView.isBinary ? (\n <Notice>{viewPath} is a binary file ({fileView.sizeBytes ?? 0} bytes).</Notice>\n ) : fileView.content !== null ? (\n <>\n {fileView.truncated && (\n <div className=\"border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-status-running\">\n Large file — showing a truncated preview ({fileView.sizeBytes ?? 0} bytes loaded). Editing is disabled to avoid corrupting the file.\n </div>\n )}\n {usePierre ? (\n <PierreFile\n path={viewPath}\n contents={fileView.content}\n themeType={resolvedTheme}\n fallback={\n <pre className=\"overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg\">\n {fileView.content}\n </pre>\n }\n className=\"p-1\"\n />\n ) : (\n <pre className=\"overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg\">\n {fileView.content}\n </pre>\n )}\n </>\n ) : (\n <Notice>Loading {viewPath}…</Notice>\n )\n ) : (\n // Nothing selected — never claim a repo is required; the tree shows\n // the whole workspace regardless of git.\n <Notice>\n {changed.length > 0\n ? \"Select a changed file to review its diff, or a file in the tree to view it.\"\n : \"Select a file in the tree to view it.\"}\n </Notice>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction GitHeader({ git, dirtyCount }: { git: UseSandboxGitResult; dirtyCount: number }) {\n const dirty = dirtyCount > 0;\n return (\n <div className=\"flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm\">\n <span\n className={cn(\n \"size-2 shrink-0 rounded-full\",\n dirty ? \"bg-og-status-running\" : \"bg-og-status-idle\",\n )}\n title={dirty ? `${dirtyCount} changed` : \"clean\"}\n />\n <span className=\"truncate font-og-mono text-og-fg\">\n {git.branch ?? (git.isRepo ? \"(detached)\" : \"no repo\")}\n </span>\n {(git.ahead > 0 || git.behind > 0) && (\n <span className=\"flex shrink-0 items-center gap-1.5 text-og-xs text-og-fg-subtle\">\n {git.ahead > 0 && <span>↑{git.ahead}</span>}\n {git.behind > 0 && <span>↓{git.behind}</span>}\n </span>\n )}\n {dirty && (\n <span className=\"ml-auto shrink-0 text-og-xs text-og-fg-subtle\">\n {dirtyCount} changed\n </span>\n )}\n </div>\n );\n}\n\nfunction Segmented({\n options,\n value,\n onChange,\n}: {\n options: { value: string; label: string }[];\n value: string;\n onChange: (value: string) => void;\n}) {\n return (\n <div className=\"flex flex-wrap items-center rounded-og-sm border border-og-border p-0.5\">\n {options.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => onChange(opt.value)}\n className={cn(\n \"rounded-og-xs px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10\",\n opt.value === value\n ? \"bg-og-accent-soft text-og-fg\"\n : \"text-og-fg-subtle hover:text-og-fg\",\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n );\n}\n\ntype FileViewState = {\n content: string | null;\n isBinary: boolean;\n /** The backend truncated the read (size cap hit) — content is a PREFIX only.\n * Editing+saving such a file would write the prefix back and corrupt it, so\n * the editor must stay read-only for a truncated read. */\n truncated: boolean;\n sizeBytes: number | null;\n loading: boolean;\n error: Error | null;\n};\n\n/**\n * Read a file's contents for the viewer pane. Calls `fs.read` (text by default;\n * the backend flags binary), decodes a base64 payload if one comes back, and\n * exposes loading/error/binary state. Re-fetches when the path changes; ignores\n * a stale resolve after the selection moves on.\n */\nfunction useFileView(\n path: string | null,\n readFile: (path: string) => Promise<FsReadResponse>,\n): FileViewState {\n const [state, setState] = useState<FileViewState>({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: false,\n error: null,\n });\n useEffect(() => {\n if (!path) {\n setState({ content: null, isBinary: false, truncated: false, sizeBytes: null, loading: false, error: null });\n return;\n }\n let cancelled = false;\n setState({ content: null, isBinary: false, truncated: false, sizeBytes: null, loading: true, error: null });\n void readFile(path)\n .then((res) => {\n if (cancelled) return;\n const content = res.isBinary\n ? null\n : res.encoding === \"base64\"\n ? decodeBase64Utf8(res.content)\n : res.content;\n setState({\n content,\n isBinary: res.isBinary,\n truncated: res.truncated,\n sizeBytes: res.sizeBytes,\n loading: false,\n error: null,\n });\n })\n .catch((cause) => {\n if (cancelled) return;\n setState({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: false,\n error: cause instanceof Error ? cause : new Error(String(cause)),\n });\n });\n return () => {\n cancelled = true;\n };\n }, [path, readFile]);\n return state;\n}\n\n/** Decode a base64 payload to a UTF-8 string (browser `atob` + TextDecoder). */\nfunction decodeBase64Utf8(b64: string): string {\n try {\n if (typeof atob === \"function\") {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n } catch {\n /* fall through to returning the raw payload */\n }\n return b64;\n}\n\nfunction Notice({ children, className }: { children: ReactNode; className?: string | undefined }) {\n return (\n <div\n className={cn(\n \"flex h-full items-center justify-center p-4 text-center text-og-sm text-og-fg-subtle\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n","import type { CapabilityUnavailableReason, DesktopRfbFactory, DesktopStreamCapability } from \"@opengeni/sdk\";\nimport { LoaderCircleIcon, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from \"lucide-react\";\nimport { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useDesktopStream } from \"../hooks/use-desktop-stream\";\nimport type { DesktopWebSocketFactory } from \"../hooks/use-relay-frame-stream\";\n\nexport type DesktopViewerProps = {\n /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */\n capability: DesktopStreamCapability | null;\n /**\n * Initial control mode. Default false (watch). When the user flips\n * \"Take control\" the viewer drives input — but only if `capability.mode`\n * permits it (server-gated; a read-only deployment disables the toggle).\n * Pass a value to control it externally; omit to let the viewer own the state.\n */\n interactive?: boolean | undefined;\n /** Render the built-in Watching ⇄ Take control toggle (default true). */\n showControlToggle?: boolean | undefined;\n scaleViewport?: boolean | undefined;\n /** Custom RFB factory (tests / a WebRTC swap). Defaults to lazy @novnc/novnc. */\n rfbFactory?: DesktopRfbFactory | undefined;\n /** Custom socket factory for the self-hosted `relay-frames` transport (tests).\n * Defaults to `new WebSocket(url)`. Mirrors `rfbFactory`. */\n webSocketFactory?: DesktopWebSocketFactory | undefined;\n /**\n * Consent gate for the un-redacted (and possibly shared) pixel plane. Rendered\n * BEFORE connecting whenever the desktop requires acknowledgment that hasn't\n * been given. Call `onAccept` to record consent (the host wires it to\n * `client.acknowledgeStream` + a re-negotiate). When omitted, a default\n * banner is shown.\n */\n renderConsentGate?: ((onAccept: () => void, shared: boolean) => ReactNode) | undefined;\n /** Called when the default consent gate's accept button is pressed. */\n onAcknowledge?: (() => void) | undefined;\n /**\n * Whether the host has the viewer attach engaged (i.e. the user has opted into\n * watching — the parent's `watchDesktop`/`attachDesktop`). Drives the\n * cold-state behaviour: when watching, a cold-but-warmable lease AUTO-WARMS\n * (and re-warms when the box drains) instead of dead-ending. When omitted we\n * infer it from a recorded consent (the default gate's accept), so the\n * component still self-heals after the first acknowledgment.\n */\n watching?: boolean | undefined;\n /**\n * Request a (re)warm of the sandbox WITHOUT re-acknowledging (the consent has\n * already been recorded — only the box drained). The host wires this to\n * \"engage the viewer attach + re-negotiate\". Called automatically when a\n * watched desktop is found cold-but-warmable, and behind the manual retry on\n * the warming notice. Distinct from `onAcknowledge`, which is the FIRST,\n * consent-bearing warm.\n */\n onWarm?: (() => void) | undefined;\n /** Shown when transport is null (headless backend / degraded / disabled). */\n renderUnavailable?: ((reason: CapabilityUnavailableReason | null) => ReactNode) | undefined;\n /** Shown while the box is cold/warming (no live address yet). */\n renderWarming?: (() => ReactNode) | undefined;\n /** Shown when the per-session viewer cap (429) was hit. */\n renderViewerCap?: (() => ReactNode) | undefined;\n /** Surface the 429 cap state from `useSessionCapabilities().viewerCapReached`. */\n viewerCapReached?: boolean | undefined;\n /**\n * Connect watchdog (ms): if a live url is present but the RFB hasn't connected\n * within this window, surface a \"Couldn't connect\" + Reconnect instead of an\n * eternal idle scrim. Default 13000. 0 disables the watchdog.\n */\n connectTimeoutMs?: number | undefined;\n className?: string | undefined;\n};\n\n/**\n * The derived desktop surface state. A single source of truth so the overlay,\n * the scrim, the auto-warm effect, and the watchdog all agree. Priority order\n * (highest first): viewer-cap → unavailable → consent → warming → connect-failed\n * → error → connecting → connected.\n */\ntype DesktopUiState =\n | \"viewer_cap\" // 429 — the per-session live-viewer limit is reached.\n | \"unavailable\" // genuinely unsupported (headless/policy/os/backend/not-provisioned).\n | \"consent\" // un-redacted/shared plane needs acknowledgment first.\n | \"warming\" // cold-but-warmable: box not running yet (we auto-warm + spin).\n | \"connecting\" // url is live, RFB negotiating/handshaking (we spin, with a watchdog).\n | \"connect_failed\" // watchdog fired: url present but never connected.\n | \"error\" // RFB error / securityfailure after a connect.\n | \"connected\"; // live framebuffer painting.\n\n// Media-inspection exception: the framebuffer sits on true black so screenshots\n// and desktop pixels are not tinted by the product chrome palette.\nconst DESKTOP_MEDIA_BACKGROUND = \"#000\";\n\n/** Reasons that are genuinely-unavailable (never warmable from the viewer). A\n * `lease_cold` is deliberately EXCLUDED — that's the warmable cold state. */\nfunction isHardUnavailable(reason: CapabilityUnavailableReason | null): boolean {\n switch (reason) {\n case \"backend_unsupported\":\n case \"os_unsupported\":\n case \"not_provisioned\":\n case \"disabled_by_policy\":\n case \"tier_headless\":\n return true;\n default:\n // null or \"lease_cold\" → not a hard reason (cold-but-warmable / live).\n return false;\n }\n}\n\n/**\n * The desktop surface: a noVNC client connecting to the Channel-B scoped tunnel\n * URL from the capability doc. Owns the mount `<div ref>`, drives\n * `useDesktopStream` (SSR-safe lazy RFB), and renders a real\n * cold → warming → connecting → connected → error state machine with live\n * feedback (spinners, transitions) — never a dead black box with stale text.\n *\n * The read-only vs interactive decision is enforced server-first\n * (`capability.mode`): when the deployment advertises mode \"interactive\" the\n * viewer can TAKE CONTROL and drive the mouse & keyboard into the box's :0; a\n * \"read-only\" deployment disables the take-control affordance (graceful, with a\n * reason).\n *\n * Warming: a cold-but-warmable lease (`reason: \"lease_cold\"`) is NOT a dead end.\n * When the user is watching (consented), the viewer asks the host to (re)warm\n * the box (`onWarm`) and shows a \"Warming…\" spinner; if the box later drains to\n * cold it re-warms. Genuinely-unavailable surfaces (headless/policy/os/backend)\n * keep a clear, static unavailable notice.\n */\nexport function DesktopViewer({\n capability,\n interactive,\n showControlToggle = true,\n scaleViewport,\n rfbFactory,\n webSocketFactory,\n renderConsentGate,\n onAcknowledge,\n watching,\n onWarm,\n renderUnavailable,\n renderWarming,\n renderViewerCap,\n viewerCapReached,\n connectTimeoutMs = 13_000,\n className,\n}: DesktopViewerProps) {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [consented, setConsented] = useState(false);\n // Local control state when not externally controlled. The server gate\n // (`capability.mode`) is the hard ceiling — a read-only deployment can never\n // be flipped to interactive regardless of this toggle.\n const [takeControl, setTakeControl] = useState(interactive ?? false);\n const externallyControlled = interactive !== undefined;\n const serverAllowsControl = capability?.mode !== \"read-only\";\n const wantControl = externallyControlled ? interactive : takeControl;\n const inControl = Boolean(wantControl) && serverAllowsControl;\n\n // Whether the host has the viewer attach engaged. Prefer the explicit prop;\n // fall back to a locally-recorded consent so the component still self-heals\n // (auto-warms / re-warms) once the user has accepted the gate at least once.\n const isWatching = watching ?? consented;\n\n // ── Decide the rendered state (before touching the stream hook) ─────────────\n const transportNull = !capability || capability.transport === null;\n const reason = capability?.reason ?? null;\n const needsAck =\n capability?.requiresAcknowledgment === true && capability.acknowledged !== true && !consented;\n // No live address yet on an otherwise-live transport (post-ack, mid-warm).\n const noLiveAddress = Boolean(capability) && !transportNull && !capability!.url;\n\n // Cold-but-warmable: the lease is cold (`lease_cold`) OR the transport is up\n // but no url has been minted yet — either way warming, not unavailable.\n const coldWarmable =\n (transportNull && reason === \"lease_cold\") || (!transportNull && noLiveAddress);\n // Genuinely-unavailable: transport null for a HARD reason (not lease_cold).\n const hardUnavailable = transportNull && isHardUnavailable(reason);\n\n const accept = () => {\n setConsented(true);\n onAcknowledge?.();\n };\n\n // Release control WITHOUT ever swallowing a key the desktop needs. Esc, and\n // every other key, pass straight through to noVNC/:0 — vital for vim, menus,\n // and dialogs inside the box. Exactly ONE non-trapping keyboard exit:\n // • A single non-conflicting chord — Ctrl+Alt+Shift pressed on its own (no\n // other key) — which no app binds, so it never eats a real keystroke.\n // (Plus the always-visible \"Return control\" button in the in-control bar.)\n //\n // We deliberately DO NOT release on pointer-leave (or window blur): those fire\n // as a SIDE EFFECT of connecting — the noVNC canvas re-laying-out, the surface\n // grabbing focus, the connecting scrim swapping in — which bounced control\n // straight back to \"watch\" the instant the user took it. Control is given up\n // only on an explicit, intentional gesture (the button or the chord).\n useEffect(() => {\n if (!inControl || externallyControlled) return;\n const onKey = (event: KeyboardEvent) => {\n // Only the bare modifier chord releases; if any non-modifier key is also\n // down (event.key is a real key like \"a\"/\"Escape\"), let it pass through.\n if (\n event.ctrlKey &&\n event.altKey &&\n event.shiftKey &&\n (event.key === \"Control\" || event.key === \"Alt\" || event.key === \"Shift\")\n ) {\n event.preventDefault();\n setTakeControl(false);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n };\n }, [inControl, externallyControlled]);\n\n // The hook is always called (rules of hooks); it stays idle until `url` is set.\n // Do NOT open a socket while the viewer-cap (429) notice is showing — the slot\n // is already exhausted, so connecting would only burn a doomed attempt (and in\n // tests leak an unhandled ws error from the never-resolving tunnel URL).\n const connectCapability =\n !transportNull && !needsAck && !viewerCapReached ? capability : null;\n const stream = useDesktopStream({\n capability: connectCapability,\n containerRef,\n interactive: inControl,\n ...(scaleViewport !== undefined ? { scaleViewport } : {}),\n ...(rfbFactory ? { rfbFactory } : {}),\n ...(webSocketFactory ? { webSocketFactory } : {}),\n });\n\n const connected = stream.state === \"connected\";\n const hasLiveUrl = Boolean(connectCapability?.url);\n // The latest stream state, read without making it an effect dependency — so the\n // re-attach below can consult it on a visibility change WITHOUT re-subscribing\n // (and re-firing) every time the state walks idle→negotiating→connected.\n const streamStateRef = useRef(stream.state);\n streamStateRef.current = stream.state;\n\n // ── AUTO-WARM ───────────────────────────────────────────────────────────────\n // When the user is watching and the desktop is cold-but-warmable, ask the host\n // to (re)warm the box. This covers BOTH (a) the user just accepted consent and\n // (b) a previously-warm box that drained back to cold under a live viewer. We\n // fire once per distinct cold episode (keyed on the lease epoch + url) so we\n // don't spam the attach while a single warm is in flight. `onWarm` is the\n // no-re-ack path; if the host only wired `onAcknowledge` (no `onWarm`), the\n // first warm still rides consent and subsequent drains fall back to it.\n const warmKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (!isWatching || !coldWarmable || needsAck || viewerCapReached) {\n // Reset the de-dupe once we leave the cold episode so a future drain warms.\n if (!coldWarmable) warmKeyRef.current = null;\n return;\n }\n const warm = onWarm ?? onAcknowledge;\n if (!warm) return;\n // Key the de-dupe on the cell fields available to the viewer: while cold,\n // `reason`/`url`/`expiresAt` are stable, so we warm exactly once; once the box\n // warms the cell changes (url+expiresAt minted) and `coldWarmable` flips false,\n // resetting the ref so a later drain re-warms.\n const key = `${capability?.reason ?? \"\"}:${capability?.url ?? \"\"}:${capability?.expiresAt ?? \"\"}`;\n if (warmKeyRef.current === key) return; // already kicked this episode.\n warmKeyRef.current = key;\n warm();\n // capability identity is the trigger; leaseEpoch/expiresAt key the episode.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isWatching, coldWarmable, needsAck, viewerCapReached, capability, onWarm, onAcknowledge]);\n\n // ── TAB RE-ATTACH ───────────────────────────────────────────────────────────\n // The \"stuck Watching, never connects\" bug: the RFB socket never (re)fires when\n // the Desktop tab is shown without a refresh. When a live url exists but we are\n // not connected/connecting, nudge the stream hook to (re)attach — on mount, on\n // the document becoming visible, and on a fresh capability. Re-attach is cheap\n // (disconnect-old/connect-new) and idempotent: the hook ignores it once live.\n useEffect(() => {\n if (!hasLiveUrl || typeof document === \"undefined\") return;\n const maybeReattach = () => {\n if (document.visibilityState !== \"visible\") return;\n // Only kick a socket that never OPENED (idle — e.g. the tab was hidden when\n // the url arrived, so the connect effect bailed on a missing container).\n // Deliberately NOT on \"error\": that surfaces an overlay with an explicit\n // Reconnect, and auto-retrying here would hammer (reconnect → error →\n // reconnect…). We read the live state via a ref so this effect does NOT\n // depend on `stream.state` — depending on it re-ran the effect on every\n // transition and re-fired the kick, which is the reconnect loop.\n if (streamStateRef.current === \"idle\") stream.reconnect();\n };\n // The connect effect already opens the socket on mount / a fresh url. The\n // ONLY gap it can't self-heal is a tab that was hidden when the url arrived\n // (container not in the DOM → connect effect bailed to idle): the socket then\n // never (re)fires on its own. So we revive it on the tab becoming visible —\n // NOT on mount (that double-opens the socket the connect effect just opened).\n document.addEventListener(\"visibilitychange\", maybeReattach);\n return () => document.removeEventListener(\"visibilitychange\", maybeReattach);\n // Re-run ONLY on a fresh live url, never on a state transition.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hasLiveUrl, connectCapability?.url]);\n\n // ── CONNECT WATCHDOG ─────────────────────────────────────────────────────────\n // If a live url is present but the RFB hasn't reached \"connected\" within the\n // window, stop spinning forever and surface \"Couldn't connect\" + Reconnect.\n // Cleared whenever we connect, the url rotates, or the user reconnects.\n const [connectTimedOut, setConnectTimedOut] = useState(false);\n // Bumped on every manual reconnect so the watchdog re-arms its window (the\n // stream hook's url/error don't change on a reconnect, so we need our own key).\n const [reconnectNonce, setReconnectNonce] = useState(0);\n useEffect(() => {\n // Re-arm on a fresh url / a reconnect and clear the moment we connect or hit a\n // real RFB error. We deliberately do NOT key on `stream.state`, so the benign\n // idle→connecting walk doesn't keep resetting the window — the full timeout\n // runs from the url becoming live.\n setConnectTimedOut(false);\n if (!hasLiveUrl || connected || stream.error || connectTimeoutMs <= 0) return;\n const timer = setTimeout(() => setConnectTimedOut(true), connectTimeoutMs);\n return () => clearTimeout(timer);\n }, [hasLiveUrl, connected, connectTimeoutMs, connectCapability?.url, stream.error, reconnectNonce]);\n\n const reconnect = () => {\n setConnectTimedOut(false);\n setReconnectNonce((n) => n + 1);\n stream.reconnect();\n };\n\n // ── Resolve the single UI state (priority order) ────────────────────────────\n let uiState: DesktopUiState;\n if (viewerCapReached) uiState = \"viewer_cap\";\n else if (hardUnavailable) uiState = \"unavailable\";\n else if (needsAck && !isWatching) uiState = \"consent\";\n else if (coldWarmable) uiState = \"warming\";\n else if (connected) uiState = \"connected\";\n else if (stream.error) uiState = \"error\";\n else if (connectTimedOut) uiState = \"connect_failed\";\n else uiState = \"connecting\"; // hasLiveUrl && not yet connected (idle/negotiating/connecting).\n\n // An overlay blocks the surface for every state except connected; the toggle\n // and the live scrim are suppressed under an overlay.\n const overlayShown = uiState !== \"connected\" && uiState !== \"connecting\";\n const showToggle = showControlToggle && !overlayShown;\n\n let overlay: ReactNode = null;\n switch (uiState) {\n case \"viewer_cap\":\n overlay =\n renderViewerCap?.() ??\n defaultNotice(\"Too many viewers\", \"This session has reached its live-viewer limit. Try again shortly.\");\n break;\n case \"unavailable\":\n overlay =\n renderUnavailable?.(reason) ?? defaultNotice(\"Desktop unavailable\", unavailableCopy(reason));\n break;\n case \"consent\":\n overlay = renderConsentGate ? (\n renderConsentGate(accept, capability?.shared ?? false)\n ) : (\n <DefaultConsentGate shared={capability?.shared ?? false} onAccept={accept} />\n );\n break;\n case \"warming\":\n overlay = renderWarming?.() ?? <WarmingNotice />;\n break;\n case \"connect_failed\":\n overlay = defaultNotice(\n \"Couldn’t connect\",\n \"The desktop is warm but the live stream didn’t come up. This usually clears on a retry.\",\n reconnect,\n );\n break;\n case \"error\":\n overlay = defaultNotice(\"Desktop disconnected\", stream.error?.message ?? \"The stream dropped.\", reconnect);\n break;\n case \"connecting\":\n case \"connected\":\n overlay = null;\n break;\n }\n\n return (\n <div\n className={cn(\n \"relative h-full w-full overflow-hidden\",\n inControl && \"ring-2 ring-inset ring-og-accent\",\n className,\n )}\n style={{ backgroundColor: DESKTOP_MEDIA_BACKGROUND }}\n data-opengeni-desktop\n data-state={stream.state}\n data-ui-state={uiState}\n data-in-control={inControl ? \"true\" : undefined}\n >\n {/* noVNC mount target. It appends a `width:100%;height:100%` `_screen` div\n and AUTOSCALES the 1280x800 framebuffer to fit THIS box. We pin it to\n the bounded `relative` wrapper with `absolute inset-0` (not just\n `h-full w-full`) so its measured size is ALWAYS the panel — never the\n canvas content. A content-sized mount is exactly what makes noVNC\n measure a huge screen and paint the desktop \"zoomed in\". `overflow-hidden`\n keeps the centered (margin:auto) canvas from ever spilling the panel. */}\n <div\n ref={containerRef}\n className=\"absolute inset-0 overflow-hidden\"\n data-opengeni-desktop-canvas\n data-state={stream.state}\n />\n\n {/* Idle / connecting scrim: a quiet, ALIVE \"connecting to the desktop\"\n state behind the canvas so the surface never reads as a dead black\n rectangle before the first framebuffer paints. Only shown in the\n `connecting` UI-state (every other non-connected state has an explicit\n overlay). A spinner + transitional copy makes it feel live. */}\n {uiState === \"connecting\" && (\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-og-fg-subtle\">\n <span className=\"relative flex items-center justify-center\">\n <MonitorIcon className=\"size-8 opacity-30\" strokeWidth={1.5} />\n <LoaderCircleIcon\n className=\"absolute size-12 animate-og-spin text-og-accent opacity-70\"\n strokeWidth={1.25}\n />\n </span>\n <span className=\"text-og-sm\">Connecting to the desktop…</span>\n </div>\n )}\n\n {/* Take-control affordance. Two distinct states:\n - WATCHING → a prominent, centered call-to-action button overlaid on\n the desktop (the primary CTA; tasteful so the screen stays visible).\n - IN CONTROL → a small top bar (\"You're in control · click Return\n control (or Ctrl+Alt+Shift)\") with a clearly-visible Return-control\n button; the desktop stays fully usable and EVERY key — Esc included —\n passes through to the box. Server-gated: when the deployment is\n read-only the CTA renders disabled with a reason so it degrades\n gracefully. */}\n {showToggle && !externallyControlled && inControl && (\n <InControlBar\n shared={capability?.shared ?? false}\n onRelease={() => setTakeControl(false)}\n />\n )}\n {/* The big CTA only appears once the framebuffer is live + the viewer is\n watching: before connect the scrim already communicates state, so we\n don't double up. A read-only deployment (serverAllowsControl=false) still\n surfaces the CTA disabled-with-reason once connected, so it degrades\n gracefully and stays discoverable. */}\n {showToggle && !externallyControlled && !inControl && connected && (\n <TakeControlCallToAction\n disabled={!serverAllowsControl}\n disabledReason={\n !serverAllowsControl\n ? capability?.client === \"frames\"\n ? \"View-only — live control isn't available for this machine yet.\"\n : \"This deployment streams the desktop read-only.\"\n : undefined\n }\n onTakeControl={() => setTakeControl(true)}\n />\n )}\n\n {overlay && (\n <div className=\"absolute inset-0 flex items-center justify-center p-4\">{overlay}</div>\n )}\n </div>\n );\n}\n\n/**\n * The primary WATCHING-state call-to-action: a large, centered pill button\n * overlaid on the desktop inviting the viewer to drive the mouse & keyboard.\n * Tasteful by default — it sits in the LOWER-center with a soft scrim only behind\n * the button (not the whole screen) and lifts on hover, so a watcher can still see\n * the agent work. Server-gated: when the deployment is read-only (or the desktop\n * hasn't connected yet) it renders disabled with a reason. Accessible: a real\n * <button> with a title, focus ring, and Enter/Space activation.\n */\nfunction TakeControlCallToAction({\n disabled,\n disabledReason,\n onTakeControl,\n}: {\n disabled: boolean;\n disabledReason?: string | undefined;\n onTakeControl: () => void;\n}) {\n return (\n // The wrapper spans the surface but is click-through (pointer-events-none); only\n // the button itself is interactive, so watchers can still see the desktop.\n <div className=\"pointer-events-none absolute inset-0 flex items-end justify-center pb-[8%]\">\n <button\n type=\"button\"\n disabled={disabled}\n aria-label=\"Take control of the desktop\"\n title={disabled ? disabledReason : \"Take control of the desktop\"}\n onClick={onTakeControl}\n className={cn(\n \"group pointer-events-auto flex items-center gap-3 rounded-og-lg border px-5 py-3\",\n \"border-og-border\",\n \"bg-og-bg/85 backdrop-blur-md\",\n \"shadow-og-lg\",\n \"outline-none transition-all duration-150 ease-out\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg\",\n disabled\n ? \"cursor-not-allowed opacity-60\"\n : cn(\n \"cursor-pointer opacity-90 hover:-translate-y-0.5 hover:opacity-100\",\n \"hover:border-og-accent\",\n \"hover:bg-og-accent/10\",\n ),\n )}\n >\n <span\n className={cn(\n \"flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\",\n \"bg-og-accent\",\n \"text-og-accent-fg\",\n disabled ? \"\" : \"group-hover:scale-105\",\n )}\n >\n <MousePointerClickIcon className=\"size-5\" strokeWidth={2} />\n </span>\n <span className=\"flex flex-col items-start leading-tight\">\n <span className=\"text-og-base font-semibold text-og-fg\">\n Take control\n </span>\n <span className=\"text-og-xs text-og-fg-subtle\">\n {disabled && disabledReason ? disabledReason : \"Drive the mouse & keyboard\"}\n </span>\n </span>\n </button>\n </div>\n );\n}\n\n/**\n * The IN-CONTROL state: a small top bar so the desktop stays fully usable while\n * driving (the accent ring around the viewport carries the primary \"you're\n * driving\" signal). Every keystroke — including Esc — passes through to the box,\n * so release lives only on explicit, non-trapping affordances: a clearly-visible\n * \"Return control\" button and the Ctrl+Alt+Shift chord. The button is solid\n * (not a faint ghost) so it's always discoverable as the way out.\n */\nfunction InControlBar({ shared, onRelease }: { shared: boolean; onRelease: () => void }) {\n return (\n <div className=\"pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between gap-2 p-2\">\n <span className=\"pointer-events-auto inline-flex items-center gap-2 rounded-og-sm bg-og-accent px-2.5 py-1 text-og-xs font-medium text-og-accent-fg shadow-og-md\">\n <span className=\"size-1.5 animate-pulse rounded-full bg-current\" aria-hidden />\n You&apos;re in control\n <span className=\"opacity-75\">· click Return control (or Ctrl+Alt+Shift)</span>\n </span>\n <div className=\"pointer-events-auto flex items-center gap-1.5\">\n {shared && (\n <span className=\"rounded-og-sm bg-og-status-failed/85 px-2 py-0.5 text-og-xs text-og-accent-fg\">\n Shared sandbox — others are watching\n </span>\n )}\n <button\n type=\"button\"\n onClick={onRelease}\n title=\"Return control (or press Ctrl+Alt+Shift)\"\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-og-sm border px-2.5 py-1 text-og-xs font-semibold shadow-og-md transition-colors\",\n \"border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm\",\n \"outline-none hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n >\n <MonitorIcon className=\"size-3.5\" strokeWidth={2} aria-hidden />\n Return control\n </button>\n </div>\n </div>\n );\n}\n\nfunction unavailableCopy(reason: CapabilityUnavailableReason | null): string {\n switch (reason) {\n case \"backend_unsupported\":\n return \"This sandbox backend cannot stream a desktop.\";\n case \"tier_headless\":\n return \"This deployment is headless — terminal, files, and diff only.\";\n case \"os_unsupported\":\n return \"The sandbox OS does not support a desktop stream.\";\n case \"not_provisioned\":\n return \"This sandbox doesn't have a desktop yet.\";\n case \"disabled_by_policy\":\n return \"Desktop streaming is disabled on this deployment.\";\n case \"lease_cold\":\n // Should not reach the unavailable notice (lease_cold warms), but keep\n // friendly copy as a fallback rather than the old dead-end wording.\n return \"Waiting for the sandbox to start…\";\n default:\n return \"The desktop isn’t available for this sandbox.\";\n }\n}\n\n/**\n * The WARMING state: a cold-but-warmable box that is being spun up. A spinner +\n * clear, accurate copy — and (when the host wired a manual warm) an explicit\n * retry so a slow warm never feels stuck. This is the cure for the old\n * \"Desktop unavailable — Start a turn or attach to warm it\" dead-end: the box IS\n * being warmed automatically; we just tell the user it's happening.\n */\nfunction WarmingNotice({ onRetry }: { onRetry?: (() => void) | undefined }) {\n return (\n <div className=\"flex max-w-sm flex-col items-center gap-3 rounded-og-lg border border-og-border bg-og-bg/90 p-5 text-center text-og-base text-og-fg backdrop-blur-sm\">\n <LoaderCircleIcon\n className=\"size-7 animate-og-spin text-og-accent\"\n strokeWidth={1.5}\n />\n <div className=\"space-y-1\">\n <div className=\"font-medium\">Warming the sandbox…</div>\n <p className=\"text-og-sm text-og-fg-subtle\">\n Spinning up the desktop — this takes a few seconds.\n </p>\n </div>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm text-og-fg-muted transition-colors hover:text-og-fg pointer-coarse:min-h-10\"\n >\n Taking too long? Retry\n </button>\n )}\n </div>\n );\n}\n\nfunction DefaultConsentGate({ shared, onAccept }: { shared: boolean; onAccept: () => void }) {\n return (\n <div className=\"max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg\">\n <div className=\"mb-1 font-medium\">Watch the live desktop?</div>\n <p className=\"mb-3 text-og-sm text-og-fg-subtle\">\n The desktop pixel stream is <strong>un-redacted</strong> — it can show secrets the agent prints\n on screen.\n {shared\n ? \" This sandbox is shared: you'll also see other sessions' agents on the same screen.\"\n : \"\"}\n </p>\n <button\n type=\"button\"\n onClick={onAccept}\n className=\"rounded-og-sm bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg pointer-coarse:min-h-10\"\n >\n I understand — show the desktop\n </button>\n </div>\n );\n}\n\nfunction defaultNotice(title: string, body: string, onRetry?: () => void): ReactNode {\n return (\n <div className=\"max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg\">\n <div className=\"mb-1 flex items-center justify-center gap-1.5 font-medium\">\n {onRetry && <WifiOffIcon className=\"size-4 opacity-70\" strokeWidth={1.75} />}\n {title}\n </div>\n <p className=\"text-og-sm text-og-fg-subtle\">{body}</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-3 rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm transition-colors hover:border-og-accent pointer-coarse:min-h-10\"\n >\n Reconnect\n </button>\n )}\n </div>\n );\n}\n","import { type ReactNode, useCallback, useEffect, useLayoutEffect, useState } from \"react\";\nimport {\n ChevronsLeftRightIcon,\n Maximize2Icon,\n Minimize2Icon,\n PanelRightCloseIcon,\n XIcon,\n} from \"lucide-react\";\nimport {\n Group,\n Panel,\n Separator,\n useDefaultLayout,\n usePanelRef,\n} from \"react-resizable-panels\";\nimport { cn } from \"../lib/cn\";\n\nexport type WorkspaceTab = {\n id: string;\n label: ReactNode;\n /** Rendered as the active surface. */\n content: ReactNode;\n /** A small badge after the label (e.g. dirty count, live pill). */\n badge?: ReactNode | undefined;\n};\n\nexport type WorkspaceDockProps = {\n /** The chat / primary pane shown beside the dock. */\n primary: ReactNode;\n tabs: WorkspaceTab[];\n /** Controlled active tab. Falls back to the first tab. */\n activeTab?: string | undefined;\n onActiveTabChange?: ((id: string) => void) | undefined;\n /** Controlled collapsed state for hosts that expose their own dock toggle. */\n collapsed?: boolean | undefined;\n onCollapsedChange?: ((collapsed: boolean) => void) | undefined;\n /** Persisted layout id (localStorage key) for react-resizable-panels. */\n autoSaveId?: string | undefined;\n /** Default dock width as a percent of the session area. */\n defaultSize?: number | undefined;\n minSize?: number | undefined;\n maxSize?: number | undefined;\n className?: string | undefined;\n};\n\n/**\n * The resizable / collapsible / maximizable right-hand Workspace dock. Replaces\n * a fixed grid column: drag the separator to set width, collapse to a thin rail\n * that re-opens on click, and maximize to a full-workspace overlay (Esc /\n * restore button returns). Layout persists via `useDefaultLayout` keyed on\n * `autoSaveId`. Maximize is a mode ABOVE the Group (a `fixed inset-0` overlay) —\n * pushing a Panel to ~100% still fights min sizes and leaves a chat sliver.\n *\n * Below {@link DOCK_OVERLAY_BREAKPOINT} the side-by-side split can't work on a\n * phone-width viewport, so the resizable panels are dropped entirely: the\n * primary pane goes full-width and the dock becomes a full-screen overlay driven\n * by the same `collapsed` / `onCollapsedChange` contract (collapsed → hidden).\n * No drag splitter renders below the breakpoint.\n */\nconst useDockLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\n/**\n * The dock stops being a side column at this width and becomes a full-screen\n * overlay — matches the app's rail-drawer breakpoint (the single `isMobile`\n * source). The package can't read app context, so it detects the width itself.\n */\nconst DOCK_OVERLAY_BREAKPOINT = 1024;\n\n/** SSR-safe `(max-width: …)` match; false until mounted, then live. */\nfunction useIsNarrow(maxWidth: number): boolean {\n const [narrow, setNarrow] = useState(false);\n useDockLayoutEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return;\n }\n const mql = window.matchMedia(`(max-width: ${maxWidth - 1}px)`);\n const update = () => setNarrow(mql.matches);\n update();\n if (typeof mql.addEventListener === \"function\") {\n mql.addEventListener(\"change\", update);\n return () => mql.removeEventListener(\"change\", update);\n }\n // Legacy Safari.\n mql.addListener(update);\n return () => mql.removeListener(update);\n }, [maxWidth]);\n return narrow;\n}\n\nexport function WorkspaceDock({\n primary,\n tabs,\n activeTab,\n onActiveTabChange,\n collapsed: collapsedProp,\n onCollapsedChange,\n autoSaveId = \"og.session.dock\",\n defaultSize = 34,\n minSize = 22,\n maxSize = 70,\n className,\n}: WorkspaceDockProps) {\n const narrow = useIsNarrow(DOCK_OVERLAY_BREAKPOINT);\n const dockPanelRef = usePanelRef();\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const [maximized, setMaximized] = useState(false);\n const [internalTab, setInternalTab] = useState(tabs[0]?.id ?? \"\");\n const collapsed = collapsedProp ?? internalCollapsed;\n // When the host supplies `collapsed` it owns the open/close affordance (e.g.\n // the app header's panel toggle) — the dock must not offer a SECOND\n // open/close control (duplicate buttons with near-identical icons read as a\n // bug). Standalone (uncontrolled) usage keeps the built-in collapse button\n // and the thin re-open rail as its only affordances.\n const hostControlled = collapsedProp !== undefined;\n\n // Persisted layout (width split) keyed by autoSaveId.\n const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n panelIds: [\"primary\", \"dock\"],\n storage: typeof window !== \"undefined\" ? window.localStorage : undefined,\n id: autoSaveId,\n } as Parameters<typeof useDefaultLayout>[0]);\n\n const current = activeTab ?? internalTab;\n const tabIds = tabs.map((tab) => tab.id).join(\"\\u0000\");\n const firstTabId = tabs[0]?.id ?? \"\";\n const setTab = useCallback(\n (id: string) => {\n setInternalTab(id);\n onActiveTabChange?.(id);\n },\n [onActiveTabChange],\n );\n const setCollapsed = useCallback(\n (next: boolean) => {\n setInternalCollapsed((previous) => (previous === next ? previous : next));\n onCollapsedChange?.(next);\n },\n [onCollapsedChange],\n );\n\n useDockLayoutEffect(() => {\n if (collapsedProp === undefined) {\n return;\n }\n if (collapsedProp) {\n dockPanelRef.current?.collapse();\n setMaximized(false);\n } else {\n dockPanelRef.current?.expand();\n }\n }, [collapsedProp, dockPanelRef]);\n\n // Keep the active tab valid if the available tabs change.\n useEffect(() => {\n if (firstTabId && !tabs.some((t) => t.id === current)) {\n setTab(firstTabId);\n }\n // Depend on tab identity, not the tab content objects. Session live events\n // rebuild tab JSX frequently; only id changes can invalidate the active tab.\n }, [tabIds, firstTabId, current, setTab]);\n\n const collapse = useCallback(() => {\n dockPanelRef.current?.collapse();\n setCollapsed(true);\n }, [dockPanelRef, setCollapsed]);\n const expand = useCallback(() => {\n dockPanelRef.current?.expand();\n setCollapsed(false);\n }, [dockPanelRef, setCollapsed]);\n\n // Esc restores from maximize (desktop) and closes the mobile overlay.\n useEffect(() => {\n const overlayOpen = maximized || (narrow && !collapsed);\n if (!overlayOpen) return;\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return;\n if (maximized) setMaximized(false);\n else collapse();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [maximized, narrow, collapsed, collapse]);\n\n // Below the breakpoint the dock is a full-screen overlay, not a resizable\n // column: primary goes full-width and no splitter ever mounts. The overlay is\n // driven by the same `collapsed` contract (collapsed → hidden).\n if (narrow) {\n return (\n <div className={cn(\"relative flex h-full min-h-0 w-full min-w-0\", className)}>\n <div className=\"min-h-0 min-w-0 flex-1\">{primary}</div>\n {!collapsed && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Workspace\"\n className=\"fixed inset-0 z-40 flex flex-col bg-og-bg\"\n style={{\n paddingTop: \"env(safe-area-inset-top)\",\n paddingBottom: \"env(safe-area-inset-bottom)\",\n }}\n >\n <DockChrome\n tabs={tabs}\n current={current}\n onTab={setTab}\n controls={\n <ChromeButton onClick={collapse} title=\"Close workspace\" label=\"Close workspace\">\n <XIcon className=\"size-4\" />\n </ChromeButton>\n }\n />\n </div>\n )}\n </div>\n );\n }\n\n const dockChrome = (\n <DockChrome\n tabs={tabs}\n current={current}\n onTab={setTab}\n controls={\n <>\n <ChromeButton\n onClick={() => setMaximized((m) => !m)}\n title={maximized ? \"Restore (Esc)\" : \"Maximize\"}\n label={maximized ? \"Restore dock\" : \"Maximize dock\"}\n >\n {maximized ? <Minimize2Icon className=\"size-3.5\" /> : <Maximize2Icon className=\"size-3.5\" />}\n </ChromeButton>\n {hostControlled ? null : (\n <ChromeButton onClick={collapse} title=\"Collapse\" label=\"Collapse dock\">\n <PanelRightCloseIcon className=\"size-3.5\" />\n </ChromeButton>\n )}\n </>\n }\n />\n );\n\n return (\n <div className={cn(\"relative flex h-full min-h-0 w-full min-w-0\", className)}>\n <Group\n orientation=\"horizontal\"\n className=\"min-h-0 flex-1\"\n {...(defaultLayout ? { defaultLayout } : {})}\n onLayoutChanged={onLayoutChanged}\n >\n <Panel id=\"primary\" minSize=\"30%\" className=\"min-h-0 min-w-0\">\n {primary}\n </Panel>\n\n {!collapsed && (\n <Separator className=\"group relative w-1.5 shrink-0 outline-none\">\n <span className=\"absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-og-border transition-colors group-hover:bg-og-accent group-data-[separator-state=dragging]:bg-og-accent\" />\n </Separator>\n )}\n\n <Panel\n id=\"dock\"\n panelRef={dockPanelRef}\n collapsible\n collapsedSize=\"0%\"\n defaultSize={`${defaultSize}%`}\n minSize={`${minSize}%`}\n maxSize={`${maxSize}%`}\n onResize={(size, _id, previousSize) => {\n // `asPercentage` is 0..100; treat a near-zero panel as collapsed.\n const isCollapsed = size.asPercentage <= 1;\n const canInferCollapse = collapsedProp === undefined || previousSize !== undefined;\n if (canInferCollapse && isCollapsed !== collapsed) {\n setCollapsed(isCollapsed);\n }\n }}\n className=\"min-h-0 min-w-0\"\n >\n {/* Hidden behind the overlay while maximized (avoids double-mounting\n the surfaces). */}\n {!collapsed && !maximized && (\n <div className=\"flex h-full min-h-0 min-w-0 flex-col border-l border-og-border bg-og-bg\">\n {dockChrome}\n </div>\n )}\n </Panel>\n </Group>\n\n {/* Collapsed rail: the standalone fallback re-open affordance. Hidden\n when the host controls collapse — its own toggle is the one way in. */}\n {collapsed && !maximized && !hostControlled && (\n <button\n type=\"button\"\n onClick={expand}\n title=\"Open workspace\"\n className=\"absolute inset-y-0 right-0 flex w-6 shrink-0 items-center justify-center border-l border-og-border bg-og-surface-1 text-og-fg-subtle hover:text-og-fg\"\n >\n <ChevronsLeftRightIcon className=\"size-3.5\" />\n </button>\n )}\n\n {/* Maximize overlay: full-workspace surface above everything. */}\n {maximized && (\n <div className=\"fixed inset-0 z-40 flex flex-col bg-og-bg\">\n {dockChrome}\n </div>\n )}\n </div>\n );\n}\n\n/** A dock-chrome control button — compact on fine pointers, ≥40px on coarse. */\nfunction ChromeButton({\n onClick,\n title,\n label,\n children,\n}: {\n onClick: () => void;\n title: string;\n label: string;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={title}\n aria-label={label}\n className=\"inline-flex items-center justify-center rounded-og-sm p-1 transition-colors hover:bg-og-surface-2 hover:text-og-fg pointer-coarse:size-10\"\n >\n {children}\n </button>\n );\n}\n\nfunction DockChrome({\n tabs,\n current,\n onTab,\n controls,\n}: {\n tabs: WorkspaceTab[];\n current: string;\n onTab: (id: string) => void;\n /** Right-aligned chrome controls (maximize / collapse, or the overlay close). */\n controls: ReactNode;\n}) {\n const active = tabs.find((t) => t.id === current) ?? tabs[0];\n return (\n <>\n <div className=\"flex shrink-0 items-center gap-2 border-b border-og-border px-1.5 py-1\">\n {/* The tab list scrolls horizontally when it can't fit — it must never\n grow into or overlap the chrome controls (they stay shrink-0). The\n scrollbar is hidden to keep the strip calm. */}\n <div\n className=\"flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n role=\"tablist\"\n >\n {tabs.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={tab.id === current}\n onClick={() => onTab(tab.id)}\n className={cn(\n \"flex shrink-0 items-center gap-1 rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors pointer-coarse:min-h-10\",\n tab.id === current\n ? \"bg-og-accent-soft text-og-fg\"\n : \"text-og-fg-subtle hover:text-og-fg\",\n )}\n >\n <span>{tab.label}</span>\n {tab.badge}\n </button>\n ))}\n </div>\n <div className=\"flex shrink-0 items-center gap-0.5 text-og-fg-subtle\">{controls}</div>\n </div>\n <div className=\"min-h-0 min-w-0 flex-1 overflow-hidden\" role=\"tabpanel\">\n {active?.content}\n </div>\n </>\n );\n}\n","import { useCallback, useState } from \"react\";\nimport type { CodexAccount, CodexAccountsResponse, CodexRotationSettings, SessionEvent } from \"@opengeni/sdk\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue, useSessionEventTrigger, type SessionEventFeedOptions } from \"./internal\";\n\n/** Events that change which Codex account a session runs on (or just ran). */\nexport function isCodexAccountEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type === \"codex.account.switched\" || event.type === \"turn.started\";\n}\n\n/**\n * The structural slice of the SDK client the Codex-accounts surface needs. Method\n * NAMES + SIGNATURES match `OpenGeniClient` so the real client satisfies it\n * directly; declared structurally (not a hard Pick) so a test/Geni client can\n * stand in. `getSession` reads the session's pin/last; `pinSessionCodexAccount`\n * is the optional mutation (absent ⇒ the indicator hides the switch affordance).\n */\nexport type CodexAccountsClientLike = {\n listCodexAccounts: (workspaceId: string) => Promise<CodexAccountsResponse>;\n getSession?: (workspaceId: string, sessionId: string) => Promise<{ codexPinnedCredentialId?: string | null; codexLastCredentialId?: string | null }>;\n pinSessionCodexAccount?: (workspaceId: string, sessionId: string, target: string) => Promise<{ pinned: string }>;\n /** Optional (absent ⇒ the card hides live refresh): batched live /wham/usage refresh. */\n refreshCodexUsage?: (workspaceId: string) => Promise<{ usage: Record<string, unknown> }>;\n};\n\nexport type UseCodexAccountsOptions = ClientOverride & SessionEventFeedOptions & {\n pollIntervalMs?: number | undefined;\n /** Scope to a session so the hook resolves the pin + the effective account. */\n sessionId?: string | undefined;\n /** Override the client with one implementing `CodexAccountsClientLike`. */\n codexClient?: CodexAccountsClientLike | undefined;\n};\n\nexport type UseCodexAccountsResult = {\n accounts: CodexAccount[];\n /** The workspace ACTIVE account (used when a session is unpinned). */\n activeAccountId: string | null;\n /** The session's PINNED account (null ⇒ following workspace active). */\n pinnedAccountId: string | null;\n /** The account the next turn will run on: pin > workspace active. */\n effectiveAccountId: string | null;\n /** The account the session's last turn ACTUALLY ran on (the \"Running on:\" source). */\n lastAccountId: string | null;\n settings: CodexRotationSettings;\n loading: boolean;\n refresh: () => Promise<void>;\n /**\n * Trigger a LIVE batched /wham/usage refresh across all accounts, then re-read\n * the cached metadata so the new windows land on `accounts`. Modeled on `pin`.\n * No-op (resolves false) when the client can't refresh usage.\n */\n refreshUsage: () => Promise<boolean>;\n /** True while a live usage refresh is in flight (drives the bar skeleton). */\n refreshingUsage: boolean;\n /** Pin (or unpin via \"auto\") the session's account; returns true on success. */\n pin: (target: string) => Promise<boolean>;\n pinning: boolean;\n /** The target of the in-flight pin (for per-row spinner gating). */\n pinningTarget: string | null;\n mutationError: Error | null;\n};\n\nconst EMPTY_SETTINGS: CodexRotationSettings = { rotationEnabled: false, rotationStrategy: \"most_remaining\", activeCredentialId: null };\n\ntype CodexAccountsState = {\n accounts: CodexAccount[];\n activeAccountId: string | null;\n settings: CodexRotationSettings;\n pinnedAccountId: string | null;\n lastAccountId: string | null;\n};\n\nconst EMPTY_STATE: CodexAccountsState = {\n accounts: [],\n activeAccountId: null,\n settings: EMPTY_SETTINGS,\n pinnedAccountId: null,\n lastAccountId: null,\n};\n\n/**\n * The workspace's Codex accounts + the per-workspace active pointer + (when\n * session-scoped) the session pin and last-ran-on account. Composed like\n * `useMachines`: slow polling (the realtime work is done by the\n * `codex.account.switched` / `turn.started` event trigger) + a `pin` mutation.\n * Dual-consumer safe via the structural `CodexAccountsClientLike` surface.\n */\nexport function useCodexAccounts(options: UseCodexAccountsOptions = {}): UseCodexAccountsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const codexClient = (options.codexClient ?? (client as unknown as CodexAccountsClientLike));\n const sessionId = options.sessionId;\n const sharedEvents = options.events;\n\n const load = useCallback(async (): Promise<CodexAccountsState> => {\n const accountsP = codexClient.listCodexAccounts(workspaceId);\n const sessionP = sessionId && codexClient.getSession\n ? codexClient.getSession(workspaceId, sessionId).catch(() => null)\n : Promise.resolve(null);\n const [acc, session] = await Promise.all([accountsP, sessionP]);\n return {\n accounts: acc.accounts,\n activeAccountId: acc.activeAccountId,\n settings: acc.settings,\n pinnedAccountId: session?.codexPinnedCredentialId ?? null,\n lastAccountId: session?.codexLastCredentialId ?? null,\n };\n }, [codexClient, workspaceId, sessionId]);\n\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });\n const mutation = useMutationRunner();\n const usageMutation = useMutationRunner();\n const [pinningTarget, setPinningTarget] = useState<string | null>(null);\n\n // Live flip: a manual switch (P1) or a failover (P3) emits codex.account.switched;\n // turn.started covers the case where the worker recorded the actual account.\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isCodexAccountEvent,\n () => void state.refresh(),\n { enabled: options.enabled ?? true, ...(sharedEvents !== undefined ? { events: sharedEvents } : {}) },\n );\n\n const pin = useCallback(\n async (target: string): Promise<boolean> => {\n if (!sessionId || !codexClient.pinSessionCodexAccount) {\n return false;\n }\n setPinningTarget(target);\n const result = await mutation.run(async () => {\n await codexClient.pinSessionCodexAccount!(workspaceId, sessionId, target);\n return true;\n });\n setPinningTarget(null);\n if (result) await state.refresh();\n return result === true;\n },\n [codexClient, workspaceId, sessionId, mutation.run, state.refresh],\n );\n\n // Live usage refresh: hit the batched provider read, then re-read cached\n // metadata so the fresh windows land on `accounts`. The provider read writes the\n // cache columns server-side; state.refresh() pulls them back.\n const refreshUsage = useCallback(\n async (): Promise<boolean> => {\n if (!codexClient.refreshCodexUsage) {\n return false;\n }\n const result = await usageMutation.run(async () => {\n await codexClient.refreshCodexUsage!(workspaceId);\n return true;\n });\n if (result) await state.refresh();\n return result === true;\n },\n [codexClient, workspaceId, usageMutation.run, state.refresh],\n );\n\n const data = state.data ?? EMPTY_STATE;\n const effectiveAccountId = data.pinnedAccountId ?? data.activeAccountId;\n\n return {\n accounts: data.accounts,\n activeAccountId: data.activeAccountId,\n pinnedAccountId: data.pinnedAccountId,\n effectiveAccountId,\n lastAccountId: data.lastAccountId,\n settings: data.settings,\n loading: state.loading,\n refresh: state.refresh,\n refreshUsage,\n refreshingUsage: usageMutation.mutating,\n pin,\n pinning: mutation.mutating,\n pinningTarget,\n mutationError: mutation.mutationError,\n };\n}\n","import type { XtermTheme } from \"../components/sandbox-terminal\";\n\n/**\n * Derive an xterm `ITheme` subset from the live OKLCH `--og-*` token system.\n * Reads the COMPUTED values so xterm — which\n * paints into a canvas and can't consume CSS vars — gets concrete colors. Call\n * on mount and re-derive on a `data-og-theme` flip.\n *\n * SSR-safe: returns undefined off the DOM (the caller keeps xterm's defaults).\n */\nexport function xtermThemeFromTokens(root?: HTMLElement | null): XtermTheme | undefined {\n if (typeof window === \"undefined\" || typeof getComputedStyle === \"undefined\") return undefined;\n const el = root ?? document.documentElement;\n const style = getComputedStyle(el);\n const read = (name: string): string | undefined => {\n const value = style.getPropertyValue(name).trim();\n return value || undefined;\n };\n const bg = read(\"--og-color-bg\");\n const fg = read(\"--og-color-fg\");\n const accent = read(\"--og-color-accent\");\n const theme: XtermTheme = {};\n if (bg) theme.background = bg;\n if (fg) theme.foreground = fg;\n if (accent) {\n theme.cursor = accent;\n theme.selectionBackground = accent;\n }\n if (bg) theme.cursorAccent = bg;\n return Object.keys(theme).length > 0 ? theme : undefined;\n}\n"],"mappings":"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","names":["useCallback","useEffect","useMemo","useRef","useState","CameraIcon","CameraOffIcon","marker","useState","createContext","useCallback","useContext","useState","jsx","createContext","useContext","useState","useCallback","Fragment","jsx","jsxs","useState","useState","useState","jsx","jsxs","useEffect","useState","jsx","useState","useEffect","jsx","jsxs","useState","jsx","jsxs","file","CameraIcon","CameraOffIcon","createContext","useContext","jsx","jsxs","ChevronRightIcon","useState","Collapsible","jsx","jsxs","useState","Collapsible","ChevronRightIcon","useState","useRef","useEffect","window","useCallback","useMemo","asRecord","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useCallback","useRef","useState","useState","useRef","useCallback","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","OpenGeniApiError","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","OpenGeniApiError","useEffect","useRef","useState","useEffect","useRef","useState","useState","useRef","useEffect","useEffect","useMemo","useRef","useState","OpenGeniApiError","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useEffect","useMemo","OpenGeniApiError","useCallback","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useEffect","useRef","useState","useState","useCallback","useEffect","useRef","useCallback","useMemo","useRef","useState","useState","useRef","useMemo","useCallback","errorMessage","options","AnimatePresence","motion","jsx","jsxs","AnimatePresence","motion","ImageIcon","XIcon","AnimatePresence","motion","useCallback","useEffect","useId","useMemo","useRef","useState","useMemo","jsx","jsxs","useMemo","Fragment","jsx","jsxs","useRef","useState","useCallback","useId","useEffect","useMemo","AnimatePresence","motion","ImageIcon","XIcon","CheckIcon","TriangleAlertIcon","AnimatePresence","motion","useCallback","useEffect","useMemo","useRef","useState","jsx","jsx","jsxs","Fragment","jsx","jsxs","useMemo","useRef","useState","useCallback","useEffect","AnimatePresence","motion","CheckIcon","TriangleAlertIcon","jsx","jsxs","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","el","ChevronRightIcon","FileIcon","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","parentOf","useState","useRef","useCallback","useMemo","useEffect","ChevronRightIcon","FileIcon","lazy","Suspense","useEffect","useState","jsx","lazy","useState","useEffect","Suspense","Loader2Icon","lazy","Suspense","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","lazy","useState","useRef","useEffect","useMemo","useCallback","Loader2Icon","Suspense","FileIcon","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","STATUS_TINT","useState","useRef","useEffect","useMemo","useCallback","FileIcon","LoaderCircleIcon","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","LoaderCircleIcon","useCallback","useEffect","useLayoutEffect","useState","XIcon","Fragment","jsx","jsxs","useEffect","useLayoutEffect","useState","useCallback","XIcon","useCallback","useState","useCallback","useState"]}
1
+ {"version":3,"sources":["../src/hooks/use-session.ts","../src/hooks/use-session-events.ts","../src/timeline/projection.ts","../src/timeline/registry.ts","../src/timeline/tool-renderers.tsx","../src/timeline/parsers.ts","../src/timeline/shared.tsx","../src/timeline/disclosure-context.tsx","../src/timeline/screenshot-lightbox.tsx","../src/timeline/tool-diff.tsx","../src/lib/use-theme-type.ts","../src/components/pierre-diff.tsx","../src/lib/git-patch.ts","../src/timeline/activity-rail.tsx","../src/timeline/entrance.tsx","../src/timeline/turn-summary.tsx","../src/hooks/use-composer.ts","../src/hooks/use-file-attachments.ts","../src/hooks/use-turn-queue.ts","../src/hooks/use-goal.ts","../src/hooks/use-session-control.ts","../src/hooks/use-scheduled-tasks.ts","../src/hooks/use-workspace-sessions.ts","../src/hooks/use-session-lineage.ts","../src/hooks/use-environments.ts","../src/hooks/use-rigs.ts","../src/hooks/use-packs.ts","../src/hooks/use-workspaces.ts","../src/hooks/use-billing-usage.ts","../src/hooks/use-available-models.ts","../src/hooks/use-session-capabilities.ts","../src/hooks/use-desktop-stream.ts","../src/lib/relay-wire.ts","../src/hooks/use-relay-frame-stream.ts","../src/hooks/use-terminal-stream.ts","../src/hooks/use-sandbox-terminal.ts","../src/hooks/use-sandbox-files.ts","../src/hooks/use-sandbox-git.ts","../src/hooks/use-workspace-capture.ts","../src/hooks/use-workspace-edit.ts","../src/hooks/use-machine-chip.ts","../src/approvals.ts","../src/commands/registry.ts","../src/hooks/use-slash-commands.ts","../src/components/command-palette.tsx","../src/components/chat-composer.tsx","../src/components/model-picker.tsx","../src/components/message-timeline.tsx","../src/components/markdown.tsx","../src/components/session-status.tsx","../src/components/fleet-tile.tsx","../src/components/sandbox-terminal.tsx","../src/lib/xterm-theme.ts","../src/lib/xterm-renderer.ts","../src/components/file-browser.tsx","../src/components/diff-view.tsx","../src/components/pierre-file.tsx","../src/components/code-editor.tsx","../src/components/sandbox-files.tsx","../src/components/desktop-viewer.tsx","../src/components/workspace-dock.tsx","../src/components/sandbox-workspace.tsx","../src/components/workbench-changes.tsx","../src/hooks/use-windowed-sections.ts","../src/hooks/use-codex-accounts.ts"],"sourcesContent":["import type { Session, SessionEvent } from \"@opengeni/sdk\";\nimport { useCallback, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport {\n useMutationRunner,\n usePolledValue,\n useSessionEventTrigger,\n type SessionEventFeedOptions,\n} from \"./internal\";\n\nexport type UseSessionOptions = ClientOverride &\n SessionEventFeedOptions & {\n /** Re-fetch on an interval (ms). Off by default — pair with `useSessionEvents` for live status. */\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseSessionResult = {\n session: Session | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Manually rename the session (PATCH, source='user'). Returns the updated session, or null on failure. */\n updateTitle: (title: string) => Promise<Session | null>;\n /** True while a rename is in flight. */\n updating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/** Event types that change the session title (auto + cross-client renames). */\nexport function isTitleEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type === \"session.title_set\";\n}\n\n/** Fetch one session (with optional polling), live-patching its title on `session.title_set`. */\nexport function useSession(\n sessionId: string | null | undefined,\n options: UseSessionOptions = {},\n): UseSessionResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const [override, setOverride] = useState<Session | null>(null);\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n const load = useCallback(async () => {\n if (!sessionId) {\n return null;\n }\n const fetched = await client.getSession(workspaceId, sessionId);\n // A fresh server read supersedes any optimistic/event-driven override.\n setOverride(null);\n return fetched;\n }, [client, workspaceId, sessionId]);\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled,\n });\n\n const base = data ?? null;\n // The override only ever carries title/titleSource patches; it is reset on\n // every fresh load so it can never go stale against the server snapshot.\n const session =\n base && override && override.id === base.id\n ? { ...base, title: override.title, titleSource: override.titleSource }\n : base;\n\n // Live-patch the title on auto (agent) + cross-client (user/agent) renames so\n // the UI reflects the new title without polling or a full re-fetch.\n const onTitleEvent = useCallback(\n (event: SessionEvent) => {\n const payload = (event.payload ?? {}) as { title?: unknown; source?: unknown };\n const title = payload.title;\n if (typeof title !== \"string\") {\n return;\n }\n const source: \"user\" | \"agent\" | null =\n payload.source === \"user\" || payload.source === \"agent\" ? payload.source : null;\n setOverride((current): Session | null => {\n const next = current ?? base;\n if (!next) {\n return current;\n }\n return { ...next, title, titleSource: source };\n });\n },\n [base],\n );\n useSessionEventTrigger(client, workspaceId, sessionId, isTitleEvent, onTitleEvent, {\n enabled,\n ...(options.events !== undefined ? { events: options.events } : {}),\n });\n\n const updateTitle = useCallback(\n async (title: string): Promise<Session | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await run(() => client.updateSession(workspaceId, sessionId, { title }));\n if (result) {\n setOverride(result);\n }\n return result;\n },\n [client, workspaceId, sessionId, run],\n );\n\n return {\n session,\n loading,\n error,\n refresh,\n updateTitle,\n updating: mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import type { SessionEvent, SessionStatus, StreamConnectionState } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport {\n buildTimeline,\n groupTimeline,\n sessionStatusFromEvents,\n type TimelineItem,\n} from \"../timeline\";\nimport type { SessionClientLike } from \"../client\";\n\nexport type SessionEventsConnectionState = StreamConnectionState | \"idle\" | \"ended\" | \"error\";\n\nexport type UseSessionEventsOptions = ClientOverride & {\n /** Resume after this sequence (exclusive). Nonzero keeps full replay/resume semantics. */\n after?: number | undefined;\n /** Load a bounded tail by default, or opt back into full replay from `after`. */\n replay?: \"windowed\" | \"full\" | undefined;\n /** Pause the stream without unmounting (e.g. hidden tab). Defaults to true. */\n enabled?: boolean | undefined;\n};\n\nexport type UseSessionEventsResult = {\n /** Replayed + live events, ordered by sequence, no gaps, no duplicates. */\n events: SessionEvent[];\n /** Projected, renderable timeline (memoized over `events`). */\n timeline: TimelineItem[];\n /** Latest session status observed in the event log, if any. */\n sessionStatus: SessionStatus | null;\n connectionState: SessionEventsConnectionState;\n /** Highest sequence seen so far (0 before the first event). */\n lastSequence: number;\n /** True until the initial tail window has been applied (windowed mode). */\n initialLoading: boolean;\n /** Whether older durable events are available before the current window. */\n hasOlder: boolean;\n /** True while an older window is being fetched. */\n loadingOlder: boolean;\n /** Prepend an older density-bounded window; resolves true when more remain. */\n loadOlder: () => Promise<boolean>;\n error: Error | null;\n};\n\nconst INITIAL_TAIL_PAGE_SIZE = 1000;\nconst OLDER_PAGE_SIZE = 5000;\nconst INITIAL_FETCH_CAP = 1;\nconst OLDER_GROUP_TARGET = 32;\nconst OLDER_FETCH_CAP = 2;\nconst BOUNDARY_PAGE_CAP = 4;\nconst EMPTY_EVENTS: SessionEvent[] = [];\n\n/**\n * Live-stream a session's event log with replay-by-sequence, reconnect, and\n * batched React updates. Fresh loads default to a bounded tail window; pass\n * `replay: \"full\"` or a nonzero `after` for the previous full replay path.\n */\nexport function useSessionEvents(\n sessionId: string | null | undefined,\n options: UseSessionEventsOptions = {},\n): UseSessionEventsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = options.enabled ?? true;\n const after = options.after ?? 0;\n const replay = options.replay ?? \"windowed\";\n const fullReplay = replay === \"full\" || after !== 0;\n const streamKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${after}\\u0000${fullReplay ? \"full\" : \"windowed\"}`;\n\n const [events, setEvents] = useState<SessionEvent[]>([]);\n const [connectionState, setConnectionState] = useState<SessionEventsConnectionState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [hasOlder, setHasOlder] = useState(false);\n const [initialLoading, setInitialLoading] = useState(true);\n const [loadingOlder, setLoadingOlder] = useState(false);\n const lastSequenceRef = useRef(after);\n const oldestSequenceRef = useRef<number | null>(null);\n const hasOlderRef = useRef(false);\n const loadingOlderRef = useRef(false);\n const streamKeyRef = useRef<string | null>(null);\n const generationRef = useRef(0);\n // Effects reset state after commit. Tag the state so the first render for a\n // new stream identity cannot expose the previous session's event log.\n const [stateStreamKey, setStateStreamKey] = useState(streamKey);\n\n useEffect(() => {\n // Reset the accumulated log only when the stream identity changes —\n // pausing via `enabled: false` keeps the timeline visible.\n if (streamKeyRef.current !== streamKey) {\n streamKeyRef.current = streamKey;\n generationRef.current += 1;\n setStateStreamKey(streamKey);\n setEvents([]);\n setError(null);\n setHasOlder(false);\n setLoadingOlder(false);\n setInitialLoading(true);\n lastSequenceRef.current = after;\n oldestSequenceRef.current = null;\n hasOlderRef.current = false;\n loadingOlderRef.current = false;\n }\n if (!sessionId || !enabled) {\n setConnectionState(\"idle\");\n return;\n }\n const controller = new AbortController();\n // Batch yielded events into one React update per flush window so a long\n // replay (thousands of events) does not render per event.\n let pending: SessionEvent[] = [];\n let flushTimer: ReturnType<typeof setTimeout> | null = null;\n const flush = () => {\n flushTimer = null;\n if (pending.length === 0) {\n return;\n }\n const batch = pending;\n pending = [];\n // The resume cursor only advances with delivered batches: events still\n // sitting in `pending` when the stream is torn down are re-fetched on\n // the next connect instead of being skipped.\n const lastInBatch = batch[batch.length - 1];\n if (lastInBatch) {\n lastSequenceRef.current = Math.max(\n lastSequenceRef.current,\n ...batch.map(eventResumeSequence),\n );\n }\n setEvents((existing) => [...existing, ...batch]);\n };\n const scheduleFlush = () => {\n flushTimer ??= setTimeout(flush, 16);\n };\n\n void (async () => {\n try {\n if (!fullReplay) {\n setConnectionState(\"connecting\");\n // First paint is ONE compact fetch — the newest window, revealed at\n // the bottom in a few hundred ms. Deeper history loads only when the\n // reader actually scrolls up (the sentinel drives loadOlder).\n const window = await loadEventWindow(client, workspaceId, sessionId, {\n before: Number.MAX_SAFE_INTEGER,\n pageSize: INITIAL_TAIL_PAGE_SIZE,\n targetGroups: Number.POSITIVE_INFINITY,\n maxFetches: INITIAL_FETCH_CAP,\n signal: controller.signal,\n });\n if (controller.signal.aborted) {\n return;\n }\n oldestSequenceRef.current = window.oldestSequence;\n hasOlderRef.current = window.hasOlder;\n lastSequenceRef.current = window.newestSequence;\n setHasOlder(window.hasOlder);\n setEvents(window.events);\n setInitialLoading(false);\n }\n if (fullReplay) {\n setInitialLoading(false);\n }\n const stream = client.streamEvents(workspaceId, sessionId, {\n after: lastSequenceRef.current,\n signal: controller.signal,\n onStateChange: (state) => {\n if (!controller.signal.aborted) {\n setConnectionState(state);\n }\n },\n });\n for await (const event of stream) {\n pending.push(event);\n scheduleFlush();\n }\n if (!controller.signal.aborted) {\n flush();\n setConnectionState(\"ended\");\n }\n } catch (cause) {\n if (!controller.signal.aborted) {\n flush();\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setConnectionState(\"error\");\n }\n }\n })();\n\n return () => {\n controller.abort();\n if (flushTimer !== null) {\n clearTimeout(flushTimer);\n }\n };\n }, [client, workspaceId, sessionId, after, enabled, fullReplay, streamKey]);\n\n const loadOlder = useCallback(async (): Promise<boolean> => {\n if (!sessionId || fullReplay || loadingOlderRef.current || !hasOlderRef.current) {\n return false;\n }\n const before = oldestSequenceRef.current;\n if (before === null) {\n hasOlderRef.current = false;\n setHasOlder(false);\n return false;\n }\n const generation = generationRef.current;\n loadingOlderRef.current = true;\n setLoadingOlder(true);\n try {\n const window = await loadEventWindow(client, workspaceId, sessionId, {\n before,\n pageSize: OLDER_PAGE_SIZE,\n targetGroups: OLDER_GROUP_TARGET,\n maxFetches: OLDER_FETCH_CAP,\n });\n if (generationRef.current !== generation) {\n return false;\n }\n if (window.events.length === 0) {\n oldestSequenceRef.current = null;\n hasOlderRef.current = false;\n setHasOlder(false);\n return false;\n }\n oldestSequenceRef.current = window.oldestSequence;\n hasOlderRef.current = window.hasOlder;\n setHasOlder(window.hasOlder);\n setEvents((existing) => {\n assertPrependOrder(existing, window.events);\n return [...window.events, ...existing];\n });\n return window.hasOlder;\n } finally {\n if (generationRef.current === generation) {\n loadingOlderRef.current = false;\n setLoadingOlder(false);\n }\n }\n }, [client, workspaceId, sessionId, fullReplay]);\n\n const identityMatches = stateStreamKey === streamKey;\n const visibleEvents = identityMatches ? events : EMPTY_EVENTS;\n const timeline = useMemo(() => buildTimeline(visibleEvents), [visibleEvents]);\n const sessionStatus = useMemo(() => sessionStatusFromEvents(visibleEvents), [visibleEvents]);\n\n return {\n events: visibleEvents,\n timeline,\n sessionStatus,\n connectionState: identityMatches ? connectionState : \"idle\",\n lastSequence: identityMatches ? lastSequenceRef.current : after,\n initialLoading: fullReplay ? false : identityMatches ? initialLoading : true,\n hasOlder: fullReplay || !identityMatches ? false : hasOlder,\n loadingOlder: fullReplay || !identityMatches ? false : loadingOlder,\n loadOlder,\n error: identityMatches ? error : null,\n };\n}\n\ntype LoadedEventWindow = {\n events: SessionEvent[];\n oldestSequence: number | null;\n newestSequence: number;\n hasOlder: boolean;\n};\n\nasync function loadEventWindow(\n client: SessionClientLike,\n workspaceId: string,\n sessionId: string,\n options: {\n before: number;\n pageSize: number;\n targetGroups: number;\n maxFetches: number;\n signal?: AbortSignal;\n },\n): Promise<LoadedEventWindow> {\n let cursor = options.before;\n let buffer: SessionEvent[] = [];\n let reachedStart = false;\n let fetches = 0;\n\n while (fetches < options.maxFetches) {\n if (buffer.length > 0 && groupCount(buffer) >= options.targetGroups) {\n break;\n }\n const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {\n pageSize: options.pageSize,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n fetches += 1;\n if (page.length === 0) {\n reachedStart = true;\n break;\n }\n assertAscending(page);\n buffer = [...page, ...buffer];\n cursor = page[0]!.sequence;\n if (isLogStart(page[0]!)) {\n reachedStart = true;\n break;\n }\n }\n\n // Boundary snap: a window that starts mid-turn TRIMS its head to the oldest\n // turn boundary already in the buffer — the dropped fragment is refetched by\n // the next loadOlder (everything below the new oldest sequence), whose own\n // window snaps the same way, so every seam lands on a turn start. Extra\n // pages are fetched only when the buffer holds no boundary at all (one\n // monster turn); past the cap a mid-turn top is accepted.\n let snapPages = 0;\n while (\n !reachedStart &&\n findBoundaryIndex(buffer) === -1 &&\n snapPages < BOUNDARY_PAGE_CAP &&\n fetches < options.maxFetches\n ) {\n const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {\n pageSize: options.pageSize,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n fetches += 1;\n snapPages += 1;\n if (page.length === 0) {\n reachedStart = true;\n break;\n }\n assertAscending(page);\n buffer = [...page, ...buffer];\n cursor = page[0]!.sequence;\n if (isLogStart(page[0]!)) {\n reachedStart = true;\n break;\n }\n }\n if (!reachedStart) {\n const boundary = findBoundaryIndex(buffer);\n if (boundary > 0) {\n buffer = buffer.slice(boundary);\n }\n }\n\n const oldest = buffer[0] ?? null;\n const newest = buffer[buffer.length - 1] ?? null;\n return {\n events: buffer,\n oldestSequence: oldest?.sequence ?? null,\n newestSequence: newest ? maxResumeSequence(buffer) : 0,\n hasOlder: buffer.length > 0 && !reachedStart && oldest?.type !== \"session.created\",\n };\n}\n\n/** Index of the oldest clean turn start in the buffer, or -1. */\nfunction findBoundaryIndex(events: SessionEvent[]): number {\n for (let index = 0; index < events.length; index += 1) {\n const type = events[index]!.type;\n if (type === \"session.created\" || type === \"user.message\") {\n return index;\n }\n }\n return -1;\n}\n\ntype PreviousPage = SessionEvent[] & { requested: number };\n\nasync function loadPreviousPage(\n client: SessionClientLike,\n workspaceId: string,\n sessionId: string,\n before: number,\n options: {\n pageSize: number;\n signal?: AbortSignal;\n },\n): Promise<PreviousPage> {\n if (options.signal?.aborted) {\n throw abortError();\n }\n const requested = options.pageSize;\n if (requested === 0) {\n return Object.assign([], { requested });\n }\n const page = await client.listEvents(workspaceId, sessionId, {\n before,\n limit: requested,\n compact: true,\n });\n if (options.signal?.aborted) {\n throw abortError();\n }\n return Object.assign(page, { requested });\n}\n\nfunction groupCount(events: SessionEvent[]): number {\n if (events.length === 0) {\n return 0;\n }\n return groupTimeline(buildTimeline(events)).length;\n}\n\nfunction isLogStart(event: SessionEvent): boolean {\n return event.type === \"session.created\" || event.sequence <= 1;\n}\n\nfunction maxResumeSequence(events: SessionEvent[]): number {\n return events.reduce((max, event) => Math.max(max, eventResumeSequence(event)), 0);\n}\n\nfunction eventResumeSequence(event: SessionEvent): number {\n const payload = asRecord(event.payload);\n const coalescedUntil = Number(payload.coalescedUntil);\n return Math.max(event.sequence, Number.isFinite(coalescedUntil) ? Math.floor(coalescedUntil) : 0);\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n}\n\nfunction assertAscending(events: SessionEvent[]): void {\n for (let index = 1; index < events.length; index += 1) {\n if (events[index - 1]!.sequence >= events[index]!.sequence) {\n throw new Error(\"@opengeni/react: session events must be ordered by ascending sequence\");\n }\n }\n}\n\nfunction assertPrependOrder(existing: SessionEvent[], older: SessionEvent[]): void {\n if (!shouldAssertDevelopment() || existing.length === 0 || older.length === 0) {\n return;\n }\n if (older[older.length - 1]!.sequence >= existing[0]!.sequence) {\n throw new Error(\"@opengeni/react: loadOlder returned overlapping session events\");\n }\n}\n\nfunction shouldAssertDevelopment(): boolean {\n const processEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env;\n return processEnv !== undefined && processEnv.NODE_ENV !== \"production\";\n}\n\nfunction abortError(): Error {\n const error = new Error(\"The operation was aborted.\");\n error.name = \"AbortError\";\n return error;\n}\n","import type { SessionEvent, SessionStatus } from \"@opengeni/sdk\";\nimport {\n CREDIT_EXHAUSTION_MESSAGE,\n humanizeFailureReason,\n isCreditExhaustion,\n tryParseJson,\n} from \"../lib/format\";\nimport type {\n AgentMessageItem,\n ActivityItem,\n AuthNeededItem,\n GoalItem,\n MemoryItem,\n SandboxItem,\n SessionStatusItem,\n TimelineGroup,\n TimelineItem,\n TurnEndItem,\n ToolCallItem,\n WorkerItem,\n} from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Timeline projection\n\n `buildTimeline` folds a session's raw event log (replayed + live, ordered by\n sequence) into renderable items: chat messages with accumulated streaming\n deltas, reasoning summaries, tool calls matched to their outputs, sandbox\n operations with command output, spawned-worker status (the manager's\n `session_create` / `session_send_message` orchestration calls), goal\n markers, status changes, and turn failures.\n\n It is a pure function — same events in, same items out — so it can be\n memoized, unit-tested, and re-run incrementally as new events stream in.\n -------------------------------------------------------------------------- */\n\n/** Tool names on the first-party OpenGeni MCP server that operate on sessions. */\nconst WORKER_SPAWN_TOOL = \"session_create\";\nconst WORKER_MESSAGE_TOOL = \"session_send_message\";\n\nexport function buildTimeline(events: SessionEvent[]): TimelineItem[] {\n const items: TimelineItem[] = [];\n const prescan = prescanTurnAnchors(events);\n const ordered = orderTimelineEvents(events, prescan);\n\n const last = (): TimelineItem | undefined => items[items.length - 1];\n\n /** A new item of a different kind ends whatever was streaming at the tail. */\n const closeStreamingTail = (): void => {\n const open = last();\n if ((open?.kind === \"agent-message\" || open?.kind === \"reasoning\") && open.streaming) {\n open.streaming = false;\n }\n };\n\n const finalizeOpen = (\n turnId?: string | null,\n disposition: \"complete\" | \"failed\" | \"cancelled\" = \"complete\",\n ): void => {\n for (const item of items) {\n if (\n turnId !== undefined &&\n \"turnId\" in item &&\n item.turnId &&\n turnId &&\n item.turnId !== turnId\n ) {\n continue;\n }\n if ((item.kind === \"agent-message\" || item.kind === \"reasoning\") && item.streaming) {\n item.streaming = false;\n }\n if ((item.kind === \"tool-call\" || item.kind === \"worker\") && item.status === \"running\") {\n item.status = disposition;\n }\n if (item.kind === \"sandbox\" && item.status === \"running\") {\n item.status = disposition;\n }\n }\n };\n\n for (const event of ordered) {\n const payload = asRecord(event.payload);\n const turnId = event.turnId ?? null;\n\n switch (event.type) {\n case \"user.message\": {\n // A steering message must not mark in-flight tools complete; it only\n // ends whatever text was streaming. Turn lifecycle events finalize.\n closeStreamingTail();\n const childCompletion = workerCompletionPayload(payload.childCompletion);\n if (childCompletion) {\n items.push({\n kind: \"worker-completion\",\n id: event.id,\n turnId,\n occurredAt: event.occurredAt,\n childSessionId: childCompletion.childSessionId,\n childStatus: childCompletion.childStatus,\n goalStatus: childCompletion.goalStatus,\n goalText: childCompletion.goalText,\n evidence: childCompletion.evidence,\n pausedReason: childCompletion.pausedReason,\n text: typeof payload.text === \"string\" ? payload.text : \"\",\n });\n break;\n }\n items.push({\n kind: \"user-message\",\n id: event.id,\n text: typeof payload.text === \"string\" ? payload.text : \"\",\n resources: resourceRefs(payload.resources),\n tools: toolRefs(payload.tools),\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.message.delta\": {\n const text = typeof payload.text === \"string\" ? payload.text : \"\";\n if (!text) {\n break;\n }\n const open = last();\n if (open?.kind === \"agent-message\" && open.streaming && open.turnId === turnId) {\n open.text += text;\n break;\n }\n closeStreamingTail();\n items.push({\n kind: \"agent-message\",\n id: event.id,\n turnId,\n text,\n streaming: true,\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.message.completed\": {\n const text = typeof payload.text === \"string\" ? payload.text : \"\";\n // Reconcile the most recent same-turn agent message — even when\n // activity (tool calls, reasoning) landed after its deltas — so the\n // completed text never duplicates the streamed one.\n const open = [...items]\n .reverse()\n .find(\n (item): item is AgentMessageItem =>\n item.kind === \"agent-message\" && item.turnId === turnId,\n );\n if (\n open &&\n (open.streaming || !open.text || text === open.text || text.startsWith(open.text))\n ) {\n // The completed text is authoritative when it extends what streamed.\n if (!open.text || (text && text.startsWith(open.text))) {\n open.text = text || open.text;\n }\n open.streaming = false;\n break;\n }\n if (text) {\n items.push({\n kind: \"agent-message\",\n id: event.id,\n turnId,\n text,\n streaming: false,\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"agent.reasoning.delta\": {\n const text = reasoningText(event.payload);\n if (!text) {\n break;\n }\n const open = last();\n if (open?.kind === \"reasoning\" && open.streaming && open.turnId === turnId) {\n open.text += text;\n break;\n }\n closeStreamingTail();\n items.push({\n kind: \"reasoning\",\n id: event.id,\n turnId,\n text,\n streaming: true,\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.toolCall.created\": {\n const name = typeof payload.name === \"string\" ? payload.name : \"tool\";\n const callId = typeof payload.id === \"string\" ? payload.id : null;\n const args = payload.arguments ?? null;\n closeStreamingTail();\n if (name === WORKER_SPAWN_TOOL || name === WORKER_MESSAGE_TOOL) {\n items.push({\n kind: \"worker\",\n id: event.id,\n turnId,\n callId,\n action: name === WORKER_SPAWN_TOOL ? \"spawn\" : \"message\",\n prompt: workerPrompt(args),\n workerSessionId: extractSessionRef(args),\n status: \"running\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n items.push({\n kind: \"tool-call\",\n id: event.id,\n turnId,\n callId,\n name,\n arguments: args,\n output: undefined,\n // The provider-native item drives the per-tool renderers (apply_patch\n // operation, computer_call action, web_search providerData, …).\n raw: payload.raw,\n status: \"running\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"agent.toolCall.output\": {\n const callId = typeof payload.id === \"string\" ? payload.id : null;\n const target = findOpenCall(items, callId);\n if (!target) {\n break;\n }\n if (target.kind === \"worker\") {\n // A worker spawn/message that returns an error flag (or an MCP\n // isError result) settles to \"failed\" too, so WorkerRow surfaces it.\n target.status = isErrorOutput(payload) ? \"failed\" : \"complete\";\n target.workerSessionId = target.workerSessionId ?? extractSessionRef(payload.output);\n break;\n }\n // An output carrying an explicit error flag (or an MCP isError result)\n // settles the tool to \"failed\" so the renderer can surface it loudly.\n target.status = isErrorOutput(payload) ? \"failed\" : \"complete\";\n target.output = payload.output;\n break;\n }\n\n case \"sandbox.operation.started\":\n case \"sandbox.operation.completed\":\n case \"sandbox.operation.failed\": {\n const name = typeof payload.name === \"string\" ? payload.name : \"sandbox\";\n const status = event.type.endsWith(\".failed\")\n ? \"failed\"\n : event.type.endsWith(\".completed\")\n ? \"complete\"\n : \"running\";\n // Routine per-turn platform plumbing that runs before EVERY turn to\n // guarantee box contents survive a re-warm — NOT the agent redoing work:\n // - repository-clone: idempotent clone check + off-manifest token re-seed;\n // - file-resource-download: idempotent `if [ ! -f ] then curl` (skips\n // when the attached file is already on the box — see\n // sandboxFileDownloadCommand), so an uploaded image is not re-fetched;\n // the operation still emits every turn even when it does nothing.\n // Rendering either every turn reads as churn. Only FAILURES surface, and\n // they surface loudly — the failed event below creates its own item even\n // without a started row.\n if (\n (name === \"repository-clone\" || name === \"file-resource-download\") &&\n status !== \"failed\"\n ) {\n break;\n }\n const existing = findOpenSandbox(items, name);\n if (existing && status !== \"running\") {\n existing.status = status;\n if (\n payload.origin === \"created\" ||\n payload.origin === \"restored\" ||\n payload.origin === \"resumed\"\n ) {\n existing.origin = payload.origin;\n }\n const message = failureMessage(payload);\n if (message) {\n existing.output = existing.output ? `${existing.output}\\n${message}` : message;\n }\n break;\n }\n if (!existing) {\n closeStreamingTail();\n items.push({\n kind: \"sandbox\",\n id: event.id,\n turnId,\n name,\n command: typeof payload.command === \"string\" ? payload.command : null,\n output: failureMessage(payload) ?? \"\",\n origin:\n payload.origin === \"created\" ||\n payload.origin === \"restored\" ||\n payload.origin === \"resumed\"\n ? payload.origin\n : null,\n status,\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"sandbox.command.output.delta\": {\n // `chunk` is the canonical wire field; text/output are legacy shapes.\n const text =\n typeof payload.chunk === \"string\"\n ? payload.chunk\n : typeof payload.text === \"string\"\n ? payload.text\n : typeof payload.output === \"string\"\n ? payload.output\n : \"\";\n if (!text) {\n break;\n }\n // Attach to the named operation when the payload carries one;\n // otherwise the latest running operation is the best available owner.\n const open =\n (typeof payload.name === \"string\" ? findOpenSandbox(items, payload.name) : undefined) ??\n [...items]\n .reverse()\n .find(\n (item): item is SandboxItem => item.kind === \"sandbox\" && item.status === \"running\",\n );\n if (open) {\n open.output += text;\n }\n break;\n }\n\n case \"session.status.changed\": {\n const status = payload.status;\n if (!isSessionStatus(status)) {\n break;\n }\n // Only attention-worthy statuses earn a timeline divider. queued /\n // running / idle are machinery telemetry: the header pill carries the\n // live status, the shimmer says \"running\", and the turn chip's duration\n // facet says how long — a stale \"idle · 27s\" row is pure noise,\n // especially in historical traces.\n if (!ATTENTION_STATUSES.has(status)) {\n break;\n }\n const previous = [...items]\n .reverse()\n .find((item): item is SessionStatusItem => item.kind === \"session-status\");\n if (previous?.status === status) {\n break;\n }\n items.push({ kind: \"session-status\", id: event.id, status, occurredAt: event.occurredAt });\n break;\n }\n\n case \"session.requiresAction\": {\n finalizeOpen(turnId);\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"waiting\",\n text: \"Approval needed — the turn is paused until someone decides.\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"session.context.compacted\": {\n closeStreamingTail();\n const before =\n typeof payload.estimatedTokensBefore === \"number\"\n ? Math.round(payload.estimatedTokensBefore).toLocaleString(\"en-US\")\n : null;\n const after =\n typeof payload.estimatedTokensAfter === \"number\"\n ? Math.round(payload.estimatedTokensAfter).toLocaleString(\"en-US\")\n : null;\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"waiting\",\n text:\n before && after\n ? `Context compacted from approximately ${before} to ${after} tokens.`\n : \"Context compacted so the turn could continue.\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"session.context.compaction.skipped\": {\n closeStreamingTail();\n const reason = typeof payload.reason === \"string\" ? payload.reason : null;\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"waiting\",\n text:\n reason === \"no_history\"\n ? \"Context compaction skipped because there is no active history to compact.\"\n : reason === \"replacement_not_smaller\"\n ? \"Context compaction skipped because the generated checkpoint would not reduce the context.\"\n : \"Context compaction was not needed.\",\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"turn.recovery.requested\": {\n // Recovery requests are durable control-plane evidence, not a user\n // message or proof that recovery succeeded. Live state already exposes\n // a genuinely recovering session; keep the raw event in Debug/audit.\n break;\n }\n\n case \"turn.event.rejected_late\": {\n // Attempt-fence rejections prove stale callbacks did not alter current\n // truth. They are useful diagnostics but never actionable chat content,\n // regardless of the rejected event type. Debug/audit retains the event.\n break;\n }\n\n case \"tool.auth_needed\": {\n // Keep the whole structured payload — the renderer turns it into a clean\n // inline reconnect card, and the app starts the recovery flow off the\n // connectionId/resource. Losing it to a plain-text notice was the ugly\n // \"linear.app needs to be reconnected.\" line users complained about.\n closeStreamingTail();\n items.push({\n kind: \"auth-needed\",\n id: event.id,\n turnId,\n providerDomain: typeof payload.providerDomain === \"string\" ? payload.providerDomain : \"\",\n connectionId: typeof payload.connectionId === \"string\" ? payload.connectionId : null,\n reason: authNeededReason(payload.reason),\n scopes: stringList(payload.scopes),\n resource: typeof payload.resource === \"string\" ? payload.resource : null,\n toolName: typeof payload.toolName === \"string\" ? payload.toolName : null,\n authorizationUrl:\n typeof payload.authorizationUrl === \"string\" ? payload.authorizationUrl : null,\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n case \"turn.completed\": {\n // A standalone manual compaction uses the turn ledger for fencing and\n // recovery, but it is maintenance rather than a conversational turn.\n // The dedicated session.context.compacted notice is the complete UI\n // truth; adding a generic turn chip would falsely make it look like an\n // extra agent response.\n if (payload.maintenance === \"context_compaction\") {\n finalizeOpen(turnId);\n break;\n }\n // Credit exhaustion arrives as a NOMINALLY completed turn (`detail:\n // \"insufficient OpenGeni credits\"`, `segmentLimit: \"budget_exhausted\"`)\n // — the engine ended the segment early, it did not finish the work.\n // Rendering it as a clean \"complete\" turn is a lie that leaves the\n // session looking healthy while every future turn silently dies, so it\n // projects exactly like a failed turn plus an explicit notice.\n if (isCreditExhaustionPayload(payload)) {\n finalizeOpen(turnId);\n items.push(turnEndItem(event, \"failed\", CREDIT_EXHAUSTION_MESSAGE));\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"failed\",\n text: CREDIT_EXHAUSTION_MESSAGE,\n occurredAt: event.occurredAt,\n });\n break;\n }\n finalizeOpen(turnId);\n items.push(turnEndItem(event, \"complete\", null));\n break;\n }\n\n case \"turn.failed\": {\n const hadActivity = hasTurnActivity(items, turnId);\n // Credit death can hide behind fields `failureMessage` doesn't read\n // (detail/segmentLimit), so classify the whole payload before falling\n // back to the generic error/message extraction.\n const failureText = isCreditExhaustionPayload(payload)\n ? CREDIT_EXHAUSTION_MESSAGE\n : failureMessage(payload);\n // The TURN failed — the in-flight items did not. Chip doctrine: red is\n // spent once, on the turn-level outcome. Items caught mid-flight read\n // as calm \"interrupted\" (same as turn.cancelled); an item that itself\n // failed keeps its own failed status from its output event.\n finalizeOpen(turnId, \"cancelled\");\n items.push(turnEndItem(event, \"failed\", failureText));\n if (!hadActivity) {\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"failed\",\n text: failureText ?? \"The turn failed.\",\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"turn.cancelled\": {\n // A retraction of a never-started queued turn is not a turn ending —\n // the message was withdrawn before any work happened; show nothing.\n // A null turnId proves nothing, so it keeps the legacy finalize path.\n if (turnId && !prescan.startedTurnIds.has(turnId)) {\n break;\n }\n const hadActivity = hasTurnActivity(items, turnId);\n finalizeOpen(turnId, \"cancelled\");\n items.push(turnEndItem(event, \"cancelled\", null));\n if (!hadActivity) {\n items.push({\n kind: \"notice\",\n id: event.id,\n tone: \"cancelled\",\n text: \"Interrupted.\",\n occurredAt: event.occurredAt,\n });\n }\n break;\n }\n\n case \"memory.saved\":\n case \"memory.corrected\": {\n // A first-party memory write is a discrete step, not streamed text, so it\n // ends whatever was streaming (mirrors tool/sandbox pushes). A payload\n // missing the memory id is malformed and dropped rather than shown blank.\n const memory = memoryItem(event.id, event.type, turnId, payload, event.occurredAt);\n if (memory) {\n closeStreamingTail();\n items.push(memory);\n }\n break;\n }\n\n case \"goal.set\":\n case \"goal.updated\":\n case \"goal.completed\":\n case \"goal.paused\":\n case \"goal.resumed\":\n case \"goal.cleared\":\n case \"goal.continuation\": {\n items.push({\n kind: \"goal\",\n id: event.id,\n action: event.type.slice(\"goal.\".length) as GoalItem[\"action\"],\n text: goalText(payload),\n occurredAt: event.occurredAt,\n });\n break;\n }\n\n default:\n break;\n }\n }\n\n return items;\n}\n\n/** The turn-end payload shape, as `isCreditExhaustion` wants it. */\nfunction isCreditExhaustionPayload(payload: Record<string, unknown>): boolean {\n return isCreditExhaustion({\n error: typeof payload.error === \"string\" ? payload.error : null,\n detail: typeof payload.detail === \"string\" ? payload.detail : null,\n segmentLimit: typeof payload.segmentLimit === \"string\" ? payload.segmentLimit : null,\n });\n}\n\n/**\n * Whether the session's most recent turn ended in credit exhaustion — the\n * terminal credit state apps key their \"add credits\" affordances on. Derived\n * from the LAST turn-end event (completed/failed/cancelled): a later turn that\n * settles any other way (someone topped up and kept working) clears it.\n */\nexport function creditExhaustedFromEvents(events: SessionEvent[]): boolean {\n const ordered = [...events].sort((a, b) => a.sequence - b.sequence);\n for (let index = ordered.length - 1; index >= 0; index -= 1) {\n const event = ordered[index];\n if (\n event?.type !== \"turn.completed\" &&\n event?.type !== \"turn.failed\" &&\n event?.type !== \"turn.cancelled\"\n ) {\n continue;\n }\n return isCreditExhaustionPayload(asRecord(event.payload));\n }\n return false;\n}\n\n/** The latest session status carried in the event log, if any. */\nexport function sessionStatusFromEvents(events: SessionEvent[]): SessionStatus | null {\n for (let index = events.length - 1; index >= 0; index -= 1) {\n const event = events[index];\n if (event?.type !== \"session.status.changed\") {\n continue;\n }\n const status = asRecord(event.payload).status;\n if (isSessionStatus(status)) {\n return status;\n }\n }\n return null;\n}\n\n/* ----------------------------------------------------------------------------\n Visual grouping: consecutive activity items (reasoning / tools / workers /\n sandbox) cluster into collapsible blocks. Once a turn settles, the full\n non-user span folds behind a turn group, with activity blocks nested inside.\n -------------------------------------------------------------------------- */\n\n/**\n * Whether an item clusters into an activity block. A `switch` (not a stringly-\n * typed set) so adding an {@link ActivityItem} kind is a compile-time prompt to\n * decide its grouping — and it narrows `item` to `ActivityItem` with no cast.\n */\nfunction isActivityItem(item: TimelineItem): item is ActivityItem {\n switch (item.kind) {\n case \"reasoning\":\n case \"tool-call\":\n case \"worker\":\n case \"sandbox\":\n case \"memory\":\n return true;\n default:\n return false;\n }\n}\n\nexport function groupTimeline(items: TimelineItem[]): TimelineGroup[] {\n const groups: TimelineGroup[] = [];\n for (const item of items) {\n if (isActivityItem(item)) {\n const open = groups[groups.length - 1];\n if (open?.kind === \"activity\" && open.outcome === undefined) {\n open.items.push(item);\n } else {\n groups.push({ kind: \"activity\", id: `activity-${item.id}`, items: [item] });\n }\n continue;\n }\n if (item.kind === \"turn-end\") {\n stampTurnOutcome(groups, item);\n foldSettledTurn(groups, item);\n continue;\n }\n groups.push({ kind: \"item\", item });\n }\n return groups;\n}\n\n/* --- helpers ---------------------------------------------------------------- */\n\ntype TurnAnchorPrescan = {\n queuedTurnByTrigger: Map<string, string>;\n startSeqByTrigger: Map<string, number>;\n cancelledBeforeStartTriggers: Set<string>;\n startedTurnIds: Set<string>;\n};\n\nfunction prescanTurnAnchors(events: SessionEvent[]): TurnAnchorPrescan {\n const ordered = [...events].sort((a, b) => a.sequence - b.sequence);\n const queuedTurnByTrigger = new Map<string, string>();\n const startSeqByTrigger = new Map<string, number>();\n const cancelledTurnIds = new Set<string>();\n const fallbackSeqByTurn = new Map<string, number>();\n const startedTurnIds = new Set<string>();\n\n for (const event of ordered) {\n const payload = asRecord(event.payload);\n const turnId = event.turnId ?? null;\n if (event.type === \"turn.queued\") {\n const triggerEventId =\n typeof payload.triggerEventId === \"string\" ? payload.triggerEventId : null;\n const queuedTurnId = typeof payload.turnId === \"string\" ? payload.turnId : turnId;\n if (triggerEventId && queuedTurnId) {\n queuedTurnByTrigger.set(triggerEventId, queuedTurnId);\n }\n continue;\n }\n if (event.type === \"turn.started\") {\n const triggerEventId =\n typeof payload.triggerEventId === \"string\" ? payload.triggerEventId : null;\n if (triggerEventId && !startSeqByTrigger.has(triggerEventId)) {\n startSeqByTrigger.set(triggerEventId, event.sequence);\n }\n if (turnId) {\n startedTurnIds.add(turnId);\n }\n } else if (event.type === \"turn.cancelled\" && turnId) {\n cancelledTurnIds.add(turnId);\n }\n\n if (turnId && event.type !== \"turn.queued\" && event.type !== \"turn.cancelled\") {\n const previous = fallbackSeqByTurn.get(turnId);\n if (previous === undefined || event.sequence < previous) {\n fallbackSeqByTurn.set(turnId, event.sequence);\n }\n }\n if (turnId && isAgentActivityEvent(event.type)) {\n startedTurnIds.add(turnId);\n }\n }\n\n for (const [triggerEventId, turnId] of queuedTurnByTrigger) {\n if (!startSeqByTrigger.has(triggerEventId)) {\n const fallbackSeq = fallbackSeqByTurn.get(turnId);\n if (fallbackSeq !== undefined) {\n startSeqByTrigger.set(triggerEventId, fallbackSeq);\n }\n }\n }\n\n const cancelledBeforeStartTriggers = new Set<string>();\n for (const [triggerEventId, turnId] of queuedTurnByTrigger) {\n if (\n cancelledTurnIds.has(turnId) &&\n !startSeqByTrigger.has(triggerEventId) &&\n !fallbackSeqByTurn.has(turnId)\n ) {\n cancelledBeforeStartTriggers.add(triggerEventId);\n }\n }\n\n return { queuedTurnByTrigger, startSeqByTrigger, cancelledBeforeStartTriggers, startedTurnIds };\n}\n\nfunction orderTimelineEvents(events: SessionEvent[], prescan: TurnAnchorPrescan): SessionEvent[] {\n const ordered = [...events].sort((a, b) => a.sequence - b.sequence);\n const insertions = new Map<number, SessionEvent[]>();\n\n for (const event of ordered) {\n if (event.type !== \"user.message\") {\n continue;\n }\n const queuedTurnId = prescan.queuedTurnByTrigger.get(event.id);\n if (!queuedTurnId) {\n pushInsertion(insertions, event.sequence, event);\n continue;\n }\n if (prescan.cancelledBeforeStartTriggers.has(event.id)) {\n continue;\n }\n const startSeq = prescan.startSeqByTrigger.get(event.id);\n if (startSeq !== undefined) {\n pushInsertion(insertions, startSeq, event);\n continue;\n }\n // A waiting prompt belongs only in the prompt queue. It enters the\n // timeline at turn.started (or the first same-turn activity fallback),\n // never as a second queued representation.\n }\n\n const projected: SessionEvent[] = [];\n for (const event of ordered) {\n const before = insertions.get(event.sequence);\n if (before) {\n projected.push(...before);\n }\n if (event.type !== \"user.message\") {\n projected.push(event);\n }\n }\n return projected;\n}\n\nfunction pushInsertion(\n insertions: Map<number, SessionEvent[]>,\n sequence: number,\n event: SessionEvent,\n): void {\n const bucket = insertions.get(sequence);\n if (bucket) {\n bucket.push(event);\n } else {\n insertions.set(sequence, [event]);\n }\n}\n\nfunction isAgentActivityEvent(type: string): boolean {\n return type.startsWith(\"agent.\") || type.startsWith(\"sandbox.\");\n}\n\nfunction turnEndItem(\n event: SessionEvent,\n outcome: TurnEndItem[\"outcome\"],\n failureText: string | null,\n): TurnEndItem {\n return {\n kind: \"turn-end\",\n id: `${event.id}-turn-end`,\n turnId: event.turnId ?? null,\n outcome,\n failureText,\n occurredAt: event.occurredAt,\n };\n}\n\nfunction hasTurnActivity(items: TimelineItem[], turnId: string | null): boolean {\n if (turnId) {\n return items.some((item) => isActivityItem(item) && item.turnId === turnId);\n }\n for (let index = items.length - 1; index >= 0; index -= 1) {\n const item = items[index];\n if (!item || item.kind === \"turn-end\" || item.kind === \"user-message\") {\n return false;\n }\n if (isActivityItem(item)) {\n return true;\n }\n }\n return false;\n}\n\nfunction stampTurnOutcome(groups: TimelineGroup[], turnEnd: TurnEndItem): void {\n if (turnEnd.turnId === null) {\n const trailing = groups[groups.length - 1];\n if (trailing?.kind === \"activity\" && trailing.outcome === undefined) {\n applyTurnOutcome(trailing, turnEnd);\n }\n return;\n }\n for (const group of groups) {\n if (group.kind !== \"activity\" || group.outcome !== undefined) {\n continue;\n }\n if (group.items.some((activity) => activity.turnId === turnEnd.turnId)) {\n applyTurnOutcome(group, turnEnd);\n }\n }\n}\n\nfunction applyTurnOutcome(\n group: Extract<TimelineGroup, { kind: \"activity\" }>,\n turnEnd: TurnEndItem,\n): void {\n // A sub-cluster reports ITS OWN outcome, not the turn's. When a turn fails\n // at step 7, clusters 1–6 completed — painting them all red says \"everything\n // broke\" when one thing did. The turn-level fold carries the turn outcome;\n // a cluster goes red only if an item inside it actually failed, and reads\n // \"cancelled\" (interrupted) only when it holds the items cut off mid-flight.\n if (turnEnd.outcome === \"complete\") {\n group.outcome = \"complete\";\n return;\n }\n const hasFailed = group.items.some((item) => \"status\" in item && item.status === \"failed\");\n const hasInterrupted = group.items.some(\n (item) => \"status\" in item && item.status === \"cancelled\",\n );\n group.outcome = hasFailed ? \"failed\" : hasInterrupted ? \"cancelled\" : \"complete\";\n if (turnEnd.failureText && hasFailed) {\n group.failureText = turnEnd.failureText;\n }\n}\n\nfunction foldSettledTurn(groups: TimelineGroup[], turnEnd: TurnEndItem): void {\n let startIndex = groups.length;\n let stoppedAtForeignTurn = false;\n while (startIndex > 0) {\n const previous = groups[startIndex - 1];\n if (isTurnBoundary(previous)) {\n break;\n }\n if (belongsToDifferentTurn(previous, turnEnd.turnId)) {\n stoppedAtForeignTurn = true;\n break;\n }\n startIndex -= 1;\n }\n if (stoppedAtForeignTurn) {\n while (startIndex < groups.length && isBetweenTurnDivider(groups[startIndex])) {\n startIndex += 1;\n }\n }\n\n const collected = groups.slice(startIndex);\n if (collected.length === 0) {\n return;\n }\n\n const finalMessage = extractFinalAgentMessage(collected, turnEnd);\n const body = finalMessage ? collected.slice(0, -1) : collected;\n if (body.length === 0) {\n return;\n }\n\n const firstOccurredAt = groupStartedAt(body[0]) ?? turnEnd.occurredAt;\n const turnGroup: TimelineGroup = {\n kind: \"turn\",\n id: `turn-${turnEnd.turnId ?? turnEnd.id}`,\n outcome: turnEnd.outcome,\n startedAt: firstOccurredAt,\n endedAt: turnEnd.occurredAt,\n groups: body,\n };\n if (turnEnd.failureText) {\n turnGroup.failureText = turnEnd.failureText;\n }\n\n groups.splice(\n startIndex,\n collected.length,\n ...(finalMessage ? [turnGroup, finalMessage] : [turnGroup]),\n );\n}\n\nfunction isTurnBoundary(group: TimelineGroup | undefined): boolean {\n return group?.kind === \"turn\" || (group?.kind === \"item\" && group.item.kind === \"user-message\");\n}\n\nfunction belongsToDifferentTurn(group: TimelineGroup | undefined, turnId: string | null): boolean {\n if (!group || !turnId) {\n return false;\n }\n if (group.kind === \"activity\") {\n return (\n group.items.length > 0 &&\n group.items.every((item) => item.turnId !== null && item.turnId !== turnId)\n );\n }\n return (\n group.kind === \"item\" &&\n group.item.kind === \"agent-message\" &&\n group.item.turnId !== null &&\n group.item.turnId !== turnId\n );\n}\n\nfunction isBetweenTurnDivider(group: TimelineGroup | undefined): boolean {\n return (\n group?.kind === \"item\" &&\n group.item.kind === \"session-status\" &&\n group.item.status !== \"running\"\n );\n}\n\nfunction extractFinalAgentMessage(\n groups: TimelineGroup[],\n turnEnd: TurnEndItem,\n): Extract<TimelineGroup, { kind: \"item\" }> | null {\n const tail = groups[groups.length - 1];\n if (tail?.kind !== \"item\" || tail.item.kind !== \"agent-message\" || tail.item.streaming) {\n return null;\n }\n if (tail.item.turnId && turnEnd.turnId && tail.item.turnId !== turnEnd.turnId) {\n return null;\n }\n return tail;\n}\n\nfunction groupStartedAt(group: TimelineGroup | undefined): string | undefined {\n if (!group) {\n return undefined;\n }\n switch (group.kind) {\n case \"item\":\n return group.item.occurredAt;\n case \"activity\":\n return group.items[0]?.occurredAt;\n case \"turn\":\n return group.startedAt;\n }\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n}\n\nconst SESSION_STATUSES: readonly SessionStatus[] = [\n \"queued\",\n \"running\",\n \"idle\",\n \"requires_action\",\n \"failed\",\n \"cancelled\",\n];\n\n/** Statuses that demand the reader's attention and so earn a timeline divider. */\nconst ATTENTION_STATUSES: ReadonlySet<SessionStatus> = new Set([\n \"requires_action\",\n \"failed\",\n \"cancelled\",\n]);\n\n/** Keep only entries that match the wire shapes; user payloads are untyped. */\nfunction resourceRefs(value: unknown): import(\"@opengeni/sdk\").ResourceRef[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter((entry): entry is import(\"@opengeni/sdk\").ResourceRef => {\n const record = asRecord(entry);\n if (record.kind === \"repository\") {\n return typeof record.uri === \"string\" && typeof record.ref === \"string\";\n }\n return record.kind === \"file\" && typeof record.fileId === \"string\";\n });\n}\n\nfunction toolRefs(value: unknown): import(\"@opengeni/sdk\").ToolRef[] {\n if (!Array.isArray(value)) {\n return [];\n }\n return value.filter((entry): entry is import(\"@opengeni/sdk\").ToolRef => {\n const record = asRecord(entry);\n return record.kind === \"mcp\" && typeof record.id === \"string\";\n });\n}\n\nfunction workerCompletionPayload(value: unknown): {\n childSessionId: string;\n childStatus: string;\n goalStatus: string | null;\n goalText: string | null;\n evidence: string | null;\n pausedReason: string | null;\n} | null {\n const payload = asRecord(value);\n const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n if (\n typeof payload.childSessionId !== \"string\" ||\n !uuidPattern.test(payload.childSessionId) ||\n typeof payload.status !== \"string\" ||\n payload.status.trim() === \"\"\n ) {\n return null;\n }\n const goal = asRecord(payload.goal);\n return {\n childSessionId: payload.childSessionId,\n childStatus: payload.status,\n goalStatus: typeof goal.status === \"string\" ? goal.status : null,\n goalText: typeof goal.text === \"string\" ? goal.text : null,\n evidence: typeof goal.evidence === \"string\" ? goal.evidence : null,\n // Console pauses and several server paths put the human explanation on\n // `rationale`, not `pausedReason` — same fallback the goal pill uses, so a\n // paused worker card never shows \"Worker paused\" with the reason missing.\n pausedReason:\n typeof goal.pausedReason === \"string\"\n ? goal.pausedReason\n : typeof goal.rationale === \"string\"\n ? goal.rationale\n : null,\n };\n}\n\nfunction isSessionStatus(value: unknown): value is SessionStatus {\n return typeof value === \"string\" && (SESSION_STATUSES as readonly string[]).includes(value);\n}\n\n/** Does this tool output represent an error (explicit flag or MCP `isError`)? */\nfunction isErrorOutput(payload: Record<string, unknown>): boolean {\n if (payload.error === true || payload.failed === true) {\n return true;\n }\n const output = payload.output;\n return (\n !!output && typeof output === \"object\" && (output as { isError?: unknown }).isError === true\n );\n}\n\nfunction findOpenCall(\n items: TimelineItem[],\n callId: string | null,\n): ToolCallItem | WorkerItem | undefined {\n const reversed = [...items].reverse();\n const isCall = (item: TimelineItem): item is ToolCallItem | WorkerItem =>\n item.kind === \"tool-call\" || item.kind === \"worker\";\n if (callId) {\n const byId = reversed.find((item) => isCall(item) && item.callId === callId);\n if (byId) {\n return byId as ToolCallItem | WorkerItem;\n }\n }\n return reversed.find(\n (item): item is ToolCallItem | WorkerItem => isCall(item) && item.status === \"running\",\n );\n}\n\nfunction findOpenSandbox(items: TimelineItem[], name: string): SandboxItem | undefined {\n return [...items]\n .reverse()\n .find(\n (item): item is SandboxItem =>\n item.kind === \"sandbox\" && item.name === name && item.status === \"running\",\n );\n}\n\nfunction failureMessage(payload: Record<string, unknown>): string | null {\n for (const key of [\"error\", \"message\"] as const) {\n const value = payload[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n // Auth/quota provider errors are rewritten for the right audience\n // (raw text remains in the event payload for debug surfaces).\n return humanizeFailureReason(value);\n }\n }\n return null;\n}\n\nfunction goalText(payload: Record<string, unknown>): string | null {\n if (typeof payload.text === \"string\" && payload.text) {\n return payload.text;\n }\n const goal = asRecord(payload.goal);\n if (typeof goal.text === \"string\" && goal.text) {\n return goal.text;\n }\n if (typeof payload.prompt === \"string\" && payload.prompt) {\n return payload.prompt;\n }\n return null;\n}\n\n/**\n * Fold a `memory.saved` / `memory.corrected` event into a {@link MemoryItem}.\n * Reads DEFENSIVELY (the payload is untyped `unknown`, no Zod schema): a missing\n * memory id means a malformed event, so we return null and the case drops it.\n */\nfunction memoryItem(\n id: string,\n type: string,\n turnId: string | null,\n payload: Record<string, unknown>,\n occurredAt: string,\n): MemoryItem | null {\n const memoryId =\n typeof payload.memoryId === \"string\" && payload.memoryId ? payload.memoryId : null;\n if (!memoryId) {\n return null;\n }\n const replacementPreview =\n typeof payload.replacementPreview === \"string\" ? payload.replacementPreview : undefined;\n const replacementMemoryId =\n typeof payload.replacementMemoryId === \"string\" ? payload.replacementMemoryId : undefined;\n const action = typeof payload.action === \"string\" ? payload.action : undefined;\n return {\n kind: \"memory\",\n id,\n turnId,\n variant: type === \"memory.corrected\" ? \"corrected\" : \"saved\",\n memoryKind: typeof payload.kind === \"string\" ? payload.kind : \"\",\n preview: typeof payload.preview === \"string\" ? payload.preview : \"\",\n ...(payload.deduped === true ? { deduped: true } : {}),\n ...(replacementPreview ? { replacementPreview } : {}),\n ...(action ? { action } : {}),\n memoryId,\n ...(replacementMemoryId ? { replacementMemoryId } : {}),\n occurredAt,\n };\n}\n\nconst AUTH_NEEDED_REASONS: ReadonlySet<string> = new Set([\n \"missing_connection\",\n \"expired\",\n \"insufficient_scope\",\n \"refresh_failed\",\n]);\n\nfunction authNeededReason(value: unknown): AuthNeededItem[\"reason\"] {\n return typeof value === \"string\" && AUTH_NEEDED_REASONS.has(value)\n ? (value as AuthNeededItem[\"reason\"])\n : null;\n}\n\nfunction stringList(value: unknown): string[] {\n return Array.isArray(value)\n ? value.filter((entry): entry is string => typeof entry === \"string\" && entry.trim().length > 0)\n : [];\n}\n\nfunction reasoningText(payload: unknown): string {\n const record = asRecord(payload);\n if (typeof record.text === \"string\") {\n return record.text;\n }\n const content = asRecord(asRecord(record.item).rawItem).content;\n if (!Array.isArray(content)) {\n return \"\";\n }\n return content\n .map((part) => {\n const text = asRecord(part).text;\n return typeof text === \"string\" ? text : \"\";\n })\n .join(\"\");\n}\n\n/** The worker's initial/sent message from `session_create`/`session_send_message` args. */\nfunction workerPrompt(args: unknown): string | null {\n const record = asRecord(typeof args === \"string\" ? tryParseJson(args) : args);\n for (const key of [\"initialMessage\", \"message\", \"text\", \"prompt\"] as const) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n }\n return null;\n}\n\n/**\n * Find a session id in orchestration tool arguments or output. Handles raw\n * objects, JSON strings, and MCP tool results (`{ content: [{ type: \"text\",\n * text: \"{...}\" }], structuredContent? }`).\n */\nexport function extractSessionRef(value: unknown, depth = 0): string | null {\n if (depth > 6 || value === null || value === undefined) {\n return null;\n }\n if (typeof value === \"string\") {\n return extractSessionRef(tryParseJson(value), depth + 1);\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n const found = extractSessionRef(entry, depth + 1);\n if (found) {\n return found;\n }\n }\n return null;\n }\n if (typeof value !== \"object\") {\n return null;\n }\n const record = value as Record<string, unknown>;\n if (typeof record.sessionId === \"string\" && looksLikeId(record.sessionId)) {\n return record.sessionId;\n }\n if (\n typeof record.id === \"string\" &&\n looksLikeId(record.id) &&\n (\"status\" in record || \"workspaceId\" in record || \"initialMessage\" in record)\n ) {\n return record.id;\n }\n for (const key of [\"structuredContent\", \"session\", \"result\", \"content\"] as const) {\n if (key in record) {\n const found = extractSessionRef(record[key], depth + 1);\n if (found) {\n return found;\n }\n }\n }\n if (typeof record.text === \"string\") {\n return extractSessionRef(tryParseJson(record.text), depth + 1);\n }\n return null;\n}\n\nfunction looksLikeId(value: string): boolean {\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);\n}\n\n/**\n * Readable label for a tool call (\"session_create\" -> \"session create\").\n *\n * MCP tools are namespaced `<serverId>__<toolName>` (see prefixedMcpToolName),\n * and for catalog-imported servers that serverId is an opaque slug+hash\n * (\"mcp-integrations-sh-supabase-com-34ed9dcf1390-0i6tcf8\"). De-slugging the\n * whole thing leaked that id into the timeline; strip the server prefix and show\n * just the tool (\"list organizations\"). Names without the `__` boundary (plain\n * built-ins like \"session_create\") are unaffected.\n */\nexport function toolDisplayName(name: string): string {\n // The prefix is a single LEFT boundary (`registryId__toolName`), so split on\n // the FIRST `__` — the tool name itself may contain `__` and must survive whole.\n const boundary = name.indexOf(\"__\");\n const toolPart = boundary >= 0 ? name.slice(boundary + 2) : name;\n return toolPart.replace(/[_-]+/g, \" \").trim();\n}\n","import type { ComponentType } from \"react\";\nimport type { ToolCallItem } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Tool renderer registry\n\n The extension point. A `ToolRenderer` is a React component fed one projected\n `ToolCallItem`; the registry resolves which renderer handles a given call,\n keyed on the tool `name` and (secondarily) its provider-native `raw.type`.\n\n Resolution order (most → least specific):\n 1. exact match on `raw.type` (e.g. \"apply_patch_call\", \"computer_call\")\n 2. exact match on the tool `name` (e.g. \"exec_command\", \"web_search_call\")\n 3. the registry's generic fallback\n\n A consumer extends the defaults without forking by passing overrides to\n `createToolRegistry` — e.g. a custom renderer for their own MCP tool, or a\n replacement for a built-in one. The registry is immutable and fully typed.\n -------------------------------------------------------------------------- */\n\nexport type ToolRendererProps = {\n item: ToolCallItem;\n};\n\nexport type ToolRenderer = ComponentType<ToolRendererProps>;\n\n/** A registry entry: which key it matches and the component that renders it. */\nexport type ToolRegistryEntry =\n | { match: \"rawType\"; type: string; render: ToolRenderer }\n | { match: \"name\"; name: string; render: ToolRenderer };\n\nexport type ToolRegistry = {\n /** Resolve the renderer for a call (never null — falls back to generic). */\n resolve: (item: ToolCallItem) => ToolRenderer;\n /** The generic fallback renderer. */\n fallback: ToolRenderer;\n};\n\nexport type CreateToolRegistryOptions = {\n /**\n * Entries that take precedence over the built-ins. Earlier entries win, so a\n * consumer can shadow a default renderer for the same key.\n */\n entries?: ToolRegistryEntry[] | undefined;\n /** Replace the generic fallback used for unmatched tools. */\n fallback?: ToolRenderer | undefined;\n};\n\n/** The `raw.type` of a projected tool call, when the provider item carries one. */\nexport function rawTypeOf(item: ToolCallItem): string | null {\n const raw = item.raw;\n if (raw && typeof raw === \"object\" && typeof (raw as { type?: unknown }).type === \"string\") {\n return (raw as { type: string }).type;\n }\n return null;\n}\n\n/**\n * Build a tool registry from a set of entries and a fallback. The returned\n * registry resolves in priority order: `raw.type` entries first, then `name`\n * entries, then the fallback. Consumer `entries` are consulted before the\n * built-in `baseEntries`, so they shadow defaults cleanly.\n */\nexport function createToolRegistry(\n baseEntries: ToolRegistryEntry[],\n baseFallback: ToolRenderer,\n options: CreateToolRegistryOptions = {},\n): ToolRegistry {\n const entries = [...(options.entries ?? []), ...baseEntries];\n const fallback = options.fallback ?? baseFallback;\n\n const byRawType = new Map<string, ToolRenderer>();\n const byName = new Map<string, ToolRenderer>();\n for (const entry of entries) {\n if (entry.match === \"rawType\") {\n if (!byRawType.has(entry.type)) {\n byRawType.set(entry.type, entry.render);\n }\n } else if (!byName.has(entry.name)) {\n byName.set(entry.name, entry.render);\n }\n }\n\n const resolve = (item: ToolCallItem): ToolRenderer => {\n const rawType = rawTypeOf(item);\n if (rawType) {\n const byType = byRawType.get(rawType);\n if (byType) {\n return byType;\n }\n }\n return byName.get(item.name) ?? fallback;\n };\n\n return { resolve, fallback };\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport {\n CameraIcon,\n CameraOffIcon,\n FileDiffIcon,\n GlobeIcon,\n ImageIcon,\n KeyboardIcon,\n KeyRoundIcon,\n LockIcon,\n MousePointer2Icon,\n PlugIcon,\n SearchIcon,\n TerminalIcon,\n WrenchIcon,\n} from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { stringifyPayload, tryParseJson } from \"../lib/format\";\nimport {\n applyPatchOps,\n controlCaret,\n execTruncated,\n isExecSessionLostBanner,\n looksBinary,\n parseExecBannerSessionId,\n parseToolArgs,\n redactSecrets,\n sandboxCommandExitCode,\n stripExecBanner,\n tailPeek,\n unwrapMcpOutput,\n v4aToGitFileDiff,\n screenshotDataUrl,\n type ApplyPatchOperation,\n} from \"./parsers\";\nimport {\n createToolRegistry,\n type ToolRegistry,\n type ToolRegistryEntry,\n type ToolRendererProps,\n} from \"./registry\";\nimport {\n BodyNote,\n MediaEmpty,\n MediaSkeleton,\n PayloadBlock,\n ScreenshotFigure,\n TermBlock,\n Thumbnail,\n ActivityDisclosure,\n type DisclosureChip,\n} from \"./shared\";\nimport { RawPatch, ToolDiff } from \"./tool-diff\";\nimport { toolDisplayName } from \"./projection\";\n\n/* ----------------------------------------------------------------------------\n Per-tool renderers\n\n Each renderer takes one projected `ToolCallItem` and returns an `ActivityDisclosure`\n tuned for that tool's real wire shape. The defaults below populate the\n registry; the mapping is registered at the bottom of the file.\n\n Restraint is the rule: compact title + one quiet preview, secondary detail\n only on expand. No loud right-side badges — at most a single settle chip.\n -------------------------------------------------------------------------- */\n\nconst ICON_SIZE = \"size-3.5\";\n\n/**\n * The single in-flight locus for a running row: a pulse dot immediately left of\n * the status word, riding the preview line — NOT a detached gutter badge. The\n * title already shimmers; this keeps the live signal in one place the eye reads\n * left-to-right.\n */\nfunction RunningPreview({ children }: { children: ReactNode }) {\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"size-1.5 shrink-0 animate-og-pulse rounded-full bg-og-status-running\" />\n <span className=\"min-w-0 truncate\">{children}</span>\n </span>\n );\n}\n\n/* ---- exec_command ---------------------------------------------------------- */\n\nfunction ExecRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const cmd = typeof args.cmd === \"string\" ? args.cmd : \"\";\n const workdir = typeof args.workdir === \"string\" ? args.workdir : null;\n const running = item.status === \"running\";\n const out = item.output;\n const title = `$ ${cmd}`;\n\n // No output event ever arrived (item.output stays undefined from creation):\n // the turn failed before the output insert — most likely a NUL byte in the\n // command output prevented storage. Surface the specific explanation.\n // (Cancelled items bypass this: a cancellation is not a NUL-storage failure.)\n if (item.status === \"failed\" && out === undefined) {\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={title}\n titleMono\n chip={{ tone: \"bad\", text: \"failed\" }}\n preview=\"output lost — NUL byte could not be stored\"\n >\n <BodyNote tone=\"error\">\n output contained a NUL byte and could not be stored; the turn failed on this tool&apos;s\n output insert — no output event ever arrived.\n </BodyNote>\n </ActivityDisclosure>\n );\n }\n\n // An output event arrived but the tool still failed (error:true / MCP isError)\n // and the output is empty — show a generic failure rather than claiming NUL.\n // (Cancelled items bypass this: a cancellation is not a tool-call failure.)\n if (item.status === \"failed\" && (out == null || out === \"\")) {\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={title}\n titleMono\n chip={{ tone: \"bad\", text: \"failed\" }}\n preview=\"tool call failed\"\n >\n <BodyNote tone=\"error\">the tool call failed with no output.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n if (running) {\n const streamed = typeof out === \"string\" ? stripExecBanner(out) : \"\";\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={title}\n titleMono\n running\n preview={\n <RunningPreview>\n {streamed ? `${streamed.split(\"\\n\").length} lines` : \"running…\"}\n </RunningPreview>\n }\n >\n {/* The row title is already `$ ${cmd}`; the TermBlock header drops the\n command (command={null}) so it never repeats above the output. */}\n <TermBlock command={null} workdir={workdir} output={streamed} live />\n </ActivityDisclosure>\n );\n }\n\n const text = typeof out === \"string\" ? out : stringifyPayload(out);\n const stripped = stripExecBanner(text);\n const bgSession = parseExecBannerSessionId(text);\n const exitCode = sandboxCommandExitCode(text);\n const binary = looksBinary(stripped);\n\n // Color is spent on the exception only: a clean exit (0) earns NO chip — the\n // absence of a red token is the success signal. Background sessions surface a\n // muted id; a non-zero exit is the one red token.\n let chip: DisclosureChip | undefined;\n let iconTone: \"accent\" | \"failed\" | \"muted\" = \"muted\";\n if (bgSession != null) {\n chip = { tone: \"muted\", text: `session ${bgSession}` };\n } else if (exitCode != null && exitCode !== 0) {\n chip = { tone: \"bad\", text: `exit ${exitCode}` };\n iconTone = \"failed\";\n }\n\n const preview = binary ? \"binary output\" : tailPeek(stripped) || \"(no output)\";\n const truncated = execTruncated(text);\n // Hand TermBlock the FULL stripped output; it owns the tail/show-more slicing.\n const body = binary ? \"(binary output suppressed)\" : stripped;\n\n return (\n <ActivityDisclosure\n icon={<TerminalIcon className={ICON_SIZE} />}\n iconTone={iconTone}\n title={title}\n titleMono\n {...(chip ? { chip } : {})}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n preview={truncated ? `⋯ truncated · ${preview}` : preview}\n >\n <TermBlock\n command={null}\n workdir={workdir}\n output={body}\n failed={item.status === \"failed\" || (exitCode != null && exitCode !== 0)}\n />\n {bgSession != null ? (\n <BodyNote>↳ session {bgSession} — a later write_stdin can target this PTY.</BodyNote>\n ) : null}\n </ActivityDisclosure>\n );\n}\n\n/* ---- write_stdin ----------------------------------------------------------- */\n\nfunction WriteStdinRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const sessionId =\n typeof args.session_id === \"string\" || typeof args.session_id === \"number\"\n ? args.session_id\n : undefined;\n const running = item.status === \"running\";\n const text = typeof item.output === \"string\" ? item.output : stringifyPayload(item.output);\n const lost = isExecSessionLostBanner(text);\n const keys = controlCaret(typeof args.chars === \"string\" ? args.chars : \"\");\n const exitCode = sandboxCommandExitCode(text);\n const stripped = stripExecBanner(text);\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={<KeyboardIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={`session ${sessionId} ← ${keys || \"∅\"}`}\n titleMono\n running\n preview={<RunningPreview>sending…</RunningPreview>}\n >\n <BodyNote>sending input to session {sessionId}…</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n // Success (exit 0 or a quiet ack) earns no chip; only a lost PTY / non-zero\n // exit gets the one red token.\n let chip: DisclosureChip | undefined;\n if (lost) {\n chip = { tone: \"bad\", text: \"lost\" };\n } else if (exitCode != null && exitCode !== 0) {\n chip = { tone: \"bad\", text: `exit ${exitCode}` };\n }\n\n return (\n <ActivityDisclosure\n icon={<KeyboardIcon className={ICON_SIZE} />}\n iconTone={lost ? \"failed\" : \"muted\"}\n title={`session ${sessionId} ← ${keys || \"∅\"}`}\n titleMono\n {...(chip ? { chip } : {})}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n preview={lost ? `session ${sessionId} PTY vanished` : tailPeek(stripped) || \"sent\"}\n >\n {lost ? (\n <BodyNote tone=\"error\">{stripped || text}</BodyNote>\n ) : (\n <TermBlock command={`write_stdin → session ${sessionId}`} output={stripped} />\n )}\n </ActivityDisclosure>\n );\n}\n\n/* ---- apply_patch ----------------------------------------------------------- */\n\nfunction verbForOp(op: ApplyPatchOperation | undefined): string {\n if (!op) {\n return \"Edited\";\n }\n return op.type === \"create_file\"\n ? \"Created\"\n : op.type === \"delete_file\"\n ? \"Deleted\"\n : op.moveTo\n ? \"Renamed\"\n : \"Edited\";\n}\n\nfunction basename(path: string): string {\n const parts = path.split(\"/\").filter(Boolean);\n return parts.length ? parts[parts.length - 1]! : path;\n}\n\nfunction dirname(path: string): string {\n const idx = path.lastIndexOf(\"/\");\n return idx >= 0 ? path.slice(0, idx + 1) : \"\";\n}\n\n/**\n * The collapsed-row path preview. Diff magnitude is rendered as a SINGLE muted\n * \"+N −M\" glyph pair — the saturated add/del green/red is reserved exclusively\n * for the expanded DiffView gutter, so the one-line rail stays a calm, single\n * hue (the file path) with no competing colored numerics.\n */\nfunction PathPreview({\n path,\n add,\n del,\n}: {\n path: string;\n add?: number | undefined;\n del?: number | undefined;\n}) {\n return (\n <span className=\"inline-flex items-center gap-2 truncate font-og-mono\">\n <span className=\"truncate\">\n <span className=\"text-og-fg-subtle\">{dirname(path)}</span>\n <span className=\"text-og-fg-muted\">{basename(path)}</span>\n </span>\n {add != null || del != null ? (\n <span className=\"shrink-0 text-og-fg-subtle\">\n {add != null ? `+${add}` : \"\"}\n {add != null && del != null ? \" \" : \"\"}\n {del != null ? `−${del}` : \"\"}\n </span>\n ) : null}\n </span>\n );\n}\n\nfunction ApplyPatchRenderer({ item }: ToolRendererProps) {\n const ops = applyPatchOps(item.raw);\n const failed = item.status === \"failed\";\n const cancelled = item.status === \"cancelled\";\n const running = item.status === \"running\";\n const firstOp = ops[0];\n\n if (running) {\n // Show the patch structure from the arguments (available immediately on\n // creation), but mark the row clearly as in-progress — not applied yet.\n const fileCount = ops.length;\n const titleVerb = firstOp ? `Applying ${basename(firstOp.path)}` : \"Applying patch\";\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={fileCount > 1 ? `Applying ${fileCount} files` : titleVerb}\n running\n preview={\n <RunningPreview>\n {fileCount > 1 ? `${fileCount} files` : firstOp ? firstOp.path : \"applying…\"}\n </RunningPreview>\n }\n >\n {ops.map((op) => {\n const file = safeParseOp(op);\n return file ? (\n <ToolDiff key={op.path} files={[file]} />\n ) : (\n <div key={op.path}>\n <p className=\"mb-1 font-og-mono text-og-xs text-og-fg-muted\">{op.path}</p>\n <RawPatch diff={op.diff ?? \"\"} />\n </div>\n );\n })}\n </ActivityDisclosure>\n );\n }\n\n if (failed) {\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={firstOp ? `${verbForOp(firstOp)} ${basename(firstOp.path)}` : \"apply_patch\"}\n chip={{ tone: \"bad\", text: \"failed\" }}\n preview={typeof item.output === \"string\" ? item.output : \"patch failed\"}\n >\n <PayloadBlock label=\"Error\" value={item.output} failed />\n </ActivityDisclosure>\n );\n }\n\n // multi-file edit — magnitude stays a single muted glyph; the per-file\n // green/red lives only inside the expanded DiffView gutter.\n if (ops.length > 1) {\n // Parse every op: successfully parsed ones go into ToolDiff; malformed ops\n // fall back to a RawPatch display (mirroring the single-op fallback path).\n // The count in the title/preview equals ops.length so it is always truthful\n // regardless of how many ops parsed successfully.\n const parsed = ops.map((op) => safeParseOp(op));\n const goodFiles = parsed.filter((f): f is GitFileDiff => f !== null);\n const add = goodFiles.reduce((n, f) => n + f.additions, 0);\n const del = goodFiles.reduce((n, f) => n + f.deletions, 0);\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"accent\"\n title={`Edited ${ops.length} files`}\n cancelled={cancelled}\n preview={\n <span className=\"inline-flex items-center gap-2 font-og-mono\">\n <span className=\"text-og-fg-muted\">{ops.length} files</span>\n <span className=\"text-og-fg-subtle\">\n +{add} −{del}\n </span>\n </span>\n }\n >\n {ops.map((op, index) => {\n const file = parsed[index];\n return file ? (\n <ToolDiff key={op.path} files={[file]} />\n ) : (\n <div key={op.path}>\n <p className=\"mb-1 font-og-mono text-og-xs text-og-fg-muted\">{op.path}</p>\n <RawPatch diff={op.diff ?? \"\"} />\n </div>\n );\n })}\n </ActivityDisclosure>\n );\n }\n\n // single op\n if (!firstOp) {\n return <GenericRenderer item={item} />;\n }\n if (firstOp.type === \"delete_file\") {\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={`Deleted ${basename(firstOp.path)}`}\n cancelled={cancelled}\n preview={<PathPreview path={firstOp.path} />}\n >\n <BodyNote>File deleted — no diff to show.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n const file = safeParseOp(firstOp);\n if (!file) {\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"accent\"\n title={`${verbForOp(firstOp)} ${basename(firstOp.path)}`}\n cancelled={cancelled}\n preview={\n <span className=\"inline-flex items-center gap-2 font-og-mono\">\n <span className=\"text-og-fg-muted\">{basename(firstOp.path)}</span>\n <span className=\"text-og-fg-subtle\">malformed V4A</span>\n </span>\n }\n >\n <RawPatch diff={firstOp.diff ?? \"\"} />\n </ActivityDisclosure>\n );\n }\n\n // The collapsed row shows verb + basename (title) and a muted \"+N −M\"\n // (preview); on expand the preview is hidden and the DiffView header carries\n // the path + churn — so the filename/stat never appears twice at once.\n return (\n <ActivityDisclosure\n icon={<FileDiffIcon className={ICON_SIZE} />}\n iconTone=\"accent\"\n title={`${verbForOp(firstOp)} ${basename(file.path)}`}\n cancelled={cancelled}\n preview={<PathPreview path={file.path} add={file.additions} del={file.deletions} />}\n >\n <ToolDiff files={[file]} />\n </ActivityDisclosure>\n );\n}\n\nfunction safeParseOp(op: ApplyPatchOperation): GitFileDiff | null {\n try {\n return v4aToGitFileDiff(op);\n } catch {\n return null;\n }\n}\n\n/* ---- computer_call --------------------------------------------------------- */\n\ntype ComputerAction = {\n type?: string;\n x?: number;\n y?: number;\n text?: string;\n keys?: string[];\n button?: string;\n};\n\nfunction computerVerb(action: ComputerAction | undefined): string {\n if (!action || !action.type) {\n return \"Acted\";\n }\n switch (action.type) {\n case \"screenshot\":\n return \"Screenshot\";\n case \"click\":\n return `Clicked (${action.x}, ${action.y})`;\n case \"double_click\":\n return `Double-clicked (${action.x}, ${action.y})`;\n case \"move\":\n return `Moved (${action.x}, ${action.y})`;\n case \"scroll\":\n return \"Scrolled\";\n case \"type\": {\n const t = action.text ?? \"\";\n return `Typed “${t.slice(0, 28)}${t.length > 28 ? \"…\" : \"\"}”`;\n }\n case \"keypress\":\n return `Pressed ${(action.keys ?? []).join(\"+\")}`;\n case \"drag\":\n return \"Dragged\";\n case \"wait\":\n return \"Waited\";\n default:\n return action.type;\n }\n}\n\n/** Coerce a function-tool arguments payload into the ComputerAction fields. */\nfunction asComputerArgs(args: unknown): Partial<ComputerAction> {\n if (!args) {\n return {};\n }\n const parsed = typeof args === \"string\" ? tryParseJson(args) : args;\n if (!parsed || typeof parsed !== \"object\") {\n return {};\n }\n const record = parsed as Record<string, unknown>;\n return {\n ...(typeof record.x === \"number\" ? { x: record.x } : {}),\n ...(typeof record.y === \"number\" ? { y: record.y } : {}),\n ...(typeof record.text === \"string\" ? { text: record.text } : {}),\n ...(Array.isArray(record.keys) ? { keys: record.keys as string[] } : {}),\n ...(typeof record.button === \"string\" ? { button: record.button } : {}),\n };\n}\n\nfunction ComputerCallRenderer({ item }: ToolRendererProps) {\n const raw = (item.raw ?? {}) as {\n action?: ComputerAction;\n actions?: ComputerAction[];\n providerData?: { approvalStatus?: string };\n };\n // Function-mode computer tools (computer_screenshot / computer_click / …,\n // used on codex + chat-wire providers since the explicit tool-transport\n // change) carry the action in the tool NAME + arguments instead of raw.action.\n // Normalize them into the same ComputerAction shape so one renderer serves\n // every transport.\n const functionAction: ComputerAction | undefined =\n !raw.action && item.name.startsWith(\"computer_\") && item.name !== \"computer_call\"\n ? { type: item.name.slice(\"computer_\".length), ...asComputerArgs(item.arguments) }\n : undefined;\n const action = raw.action ?? functionAction;\n const actions = raw.actions ?? (action ? [action] : []);\n const verb = computerVerb(action);\n const out = item.output;\n const running = item.status === \"running\";\n const rejected = raw.providerData?.approvalStatus === \"rejected\";\n const readOnly = typeof out === \"string\" && out.includes(\"read-only\");\n const shotUrl = screenshotDataUrl(out);\n const empty = out === \"\" || out == null;\n const batched = actions.length > 1 ? actions.map((a) => computerVerb(a)).join(\" · \") : null;\n // Fold the batched-action count into the title (one media affordance per row),\n // rather than a separate \"+N more\" mono label competing beside the thumbnail.\n const countSuffix = actions.length > 1 ? ` ·${actions.length}` : \"\";\n const isShot = action?.type === \"screenshot\";\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={\n isShot ? (\n <CameraIcon className={ICON_SIZE} />\n ) : (\n <MousePointer2Icon className={ICON_SIZE} />\n )\n }\n iconTone=\"running\"\n title={verb}\n running\n media={<MediaSkeleton />}\n >\n <BodyNote>capturing frame…</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n if (readOnly) {\n return (\n <ActivityDisclosure\n icon={<MousePointer2Icon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={verb}\n chip={{ tone: \"bad\", text: \"read-only\" }}\n preview=\"write actions disabled\"\n >\n <BodyNote tone=\"error\">computer-use is read-only — write actions are disabled.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n if (rejected) {\n return (\n <ActivityDisclosure\n icon={<LockIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title={verb}\n preview=\"approval rejected — this action did not run\"\n >\n <BodyNote>approval rejected — this action did not run.</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n const isFailed = item.status === \"failed\";\n const isCancelled = item.status === \"cancelled\";\n\n if (shotUrl) {\n const caption = `${verb}${actions.length > 1 ? ` (+${actions.length - 1} more)` : \"\"}`;\n return (\n <ActivityDisclosure\n icon={\n isShot ? (\n <CameraIcon className={ICON_SIZE} />\n ) : (\n <MousePointer2Icon className={ICON_SIZE} />\n )\n }\n iconTone={isFailed ? \"failed\" : \"accent\"}\n title={`${verb}${countSuffix}`}\n failed={isFailed}\n cancelled={isCancelled}\n media={<Thumbnail src={shotUrl} caption={caption} />}\n >\n <ScreenshotFigure src={shotUrl} caption={caption} />\n {batched ? <BodyNote>batched: {batched}</BodyNote> : null}\n </ActivityDisclosure>\n );\n }\n\n if (empty) {\n return (\n <ActivityDisclosure\n icon={<CameraOffIcon className={ICON_SIZE} />}\n iconTone={isFailed ? \"failed\" : \"muted\"}\n title={verb}\n failed={isFailed}\n cancelled={isCancelled}\n media={<MediaEmpty />}\n >\n <BodyNote>\n {isFailed\n ? \"computer_call failed — no image returned.\"\n : isCancelled\n ? \"computer_call interrupted — no image returned.\"\n : \"(no image) — the session returned an empty screenshot.\"}\n </BodyNote>\n </ActivityDisclosure>\n );\n }\n\n // a non-screenshot action whose output is not an image (click/keypress)\n return (\n <ActivityDisclosure\n icon={<MousePointer2Icon className={ICON_SIZE} />}\n iconTone={isFailed ? \"failed\" : \"accent\"}\n title={verb}\n failed={isFailed}\n cancelled={isCancelled}\n preview={batched ?? undefined}\n expandable={batched != null}\n >\n {batched ? <BodyNote>{batched}</BodyNote> : null}\n </ActivityDisclosure>\n );\n}\n\n/* ---- web_search ------------------------------------------------------------ */\n\ntype WebSearchResult = { title: string; domain: string; snippet: string };\n\nfunction WebSearchRenderer({ item }: ToolRendererProps) {\n const raw = (item.raw ?? {}) as {\n providerData?: { action?: { query?: string; queries?: string[] } };\n };\n const action = raw.providerData?.action ?? {};\n const query = action.query ?? \"(query unavailable)\";\n const queries = action.queries ?? [];\n const variants = queries.length > 1 ? ` +${queries.length - 1} variants` : \"\";\n const running = item.status === \"running\";\n // web_search may surface a results array on the output when the host enriches it.\n // Filter out null/undefined/non-object entries before casting: host-provided\n // data is untrusted and a null element would throw on result.title access.\n const rawResults = (item.output as { results?: unknown } | undefined)?.results;\n const results = Array.isArray(rawResults)\n ? (rawResults as unknown[]).filter((r): r is WebSearchResult => !!r && typeof r === \"object\")\n : undefined;\n const resultOccurrences = new Map<string, number>();\n const keyedResults = results?.map((result) => {\n const contentKey = `${result.domain}\\u0000${result.title}\\u0000${result.snippet}`;\n const occurrence = (resultOccurrences.get(contentKey) ?? 0) + 1;\n resultOccurrences.set(contentKey, occurrence);\n return { key: `${contentKey}\\u0000${occurrence}`, result };\n });\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={<SearchIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title=\"Searching the web\"\n running\n preview={<RunningPreview>{`${query}${variants}`}</RunningPreview>}\n >\n <BodyNote>searching… results fold into the model context (no output event).</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n return (\n <ActivityDisclosure\n icon={<SearchIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title=\"Searched the web\"\n preview={`${query}${variants}`}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n >\n {keyedResults && keyedResults.length ? (\n <ul className=\"flex flex-col gap-2\">\n {keyedResults.map(({ key, result }) => (\n <li key={key} className=\"flex gap-2.5\">\n <GlobeIcon className=\"mt-0.5 size-3.5 shrink-0 text-og-fg-subtle\" />\n <div className=\"min-w-0\">\n <p className=\"truncate text-og-base text-og-fg\">\n {result.title} <span className=\"text-og-fg-subtle\">{result.domain}</span>\n </p>\n <p className=\"text-og-sm leading-5 text-og-fg-muted\">{result.snippet}</p>\n </div>\n </li>\n ))}\n </ul>\n ) : (\n <BodyNote>results folded into model context — no list available.</BodyNote>\n )}\n </ActivityDisclosure>\n );\n}\n\n/* ---- view_image ------------------------------------------------------------ */\n\nconst VIEW_IMAGE_ERRORS = [\n \"was not found\",\n \"is not a file\",\n \"exceeded the allowed size\",\n \"is not a supported image\",\n \"unable to read image\",\n];\n\nfunction ViewImageRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const path = typeof args.path === \"string\" ? args.path : \"\";\n const out = item.output;\n const text = typeof out === \"string\" ? out : \"\";\n\n if (item.status === \"running\") {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={`View ${basename(path)}`}\n running\n preview={<RunningPreview>reading…</RunningPreview>}\n media={<MediaSkeleton />}\n >\n <BodyNote>reading image…</BodyNote>\n </ActivityDisclosure>\n );\n }\n\n const viewFailed = item.status === \"failed\";\n const viewCancelled = item.status === \"cancelled\";\n\n const errMatch = VIEW_IMAGE_ERRORS.find((p) => text.includes(p));\n if (errMatch) {\n const tooBig = text.includes(\"exceeded the allowed size\");\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={`View ${basename(path)}`}\n chip={{ tone: \"bad\", text: tooBig ? \"too large\" : \"error\" }}\n preview={text}\n >\n <BodyNote tone=\"error\">{text}</BodyNote>\n </ActivityDisclosure>\n );\n }\n if (text.startsWith(\"OpenAI file reference:\")) {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone={viewFailed ? \"failed\" : \"muted\"}\n title={`Viewed ${basename(path)}`}\n failed={viewFailed}\n cancelled={viewCancelled}\n preview={path}\n >\n <BodyNote>{text}</BodyNote>\n </ActivityDisclosure>\n );\n }\n if (text.includes(\"No image data\")) {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone={viewFailed ? \"failed\" : \"muted\"}\n title={`Viewed ${basename(path)}`}\n failed={viewFailed}\n cancelled={viewCancelled}\n preview=\"(no image)\"\n >\n <BodyNote>\n {viewFailed\n ? \"view_image failed — no image data returned.\"\n : viewCancelled\n ? \"view_image interrupted.\"\n : \"(no image) — the sandbox session returned no image data.\"}\n </BodyNote>\n </ActivityDisclosure>\n );\n }\n if (text.startsWith(\"data:\")) {\n return (\n <ActivityDisclosure\n icon={<ImageIcon className={ICON_SIZE} />}\n iconTone={viewFailed ? \"failed\" : \"accent\"}\n title={`Viewed ${basename(path)}`}\n failed={viewFailed}\n cancelled={viewCancelled}\n media={<Thumbnail src={text} caption={path} alt={path} />}\n >\n <ScreenshotFigure src={text} caption={path} alt={path} />\n </ActivityDisclosure>\n );\n }\n return <GenericRenderer item={item} />;\n}\n\n/* ---- environment_set_variable (secret-safe, write-only) -------------------- */\n\nfunction SecretSetRenderer({ item }: ToolRendererProps) {\n const args = parseToolArgs(item.arguments);\n const name = typeof args.name === \"string\" ? args.name : \"variable\";\n\n if (item.status === \"running\") {\n return (\n <ActivityDisclosure\n icon={<KeyRoundIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={`Set ${name}`}\n running\n preview={<RunningPreview>setting…</RunningPreview>}\n >\n <PayloadBlock label=\"Arguments\" value={redactSecrets(args)} />\n </ActivityDisclosure>\n );\n }\n\n if (item.status === \"failed\") {\n const errorText = typeof item.output === \"string\" ? item.output : null;\n return (\n <ActivityDisclosure\n icon={<KeyRoundIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={`Set ${name}`}\n failed\n preview={errorText ?? \"variable write failed\"}\n >\n <PayloadBlock label=\"Arguments\" value={redactSecrets(args)} />\n {errorText ? (\n <PayloadBlock label=\"Error\" value={errorText} failed />\n ) : (\n <BodyNote tone=\"error\">the tool call failed with no output.</BodyNote>\n )}\n </ActivityDisclosure>\n );\n }\n\n return (\n <ActivityDisclosure\n icon={<KeyRoundIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title={`Set ${name}`}\n cancelled={item.status === \"cancelled\"}\n preview=\"value write-only · never returned\"\n >\n <PayloadBlock label=\"Arguments\" value={redactSecrets(args)} />\n <BodyNote>the value is a secret — redacted in every view; the API never returns it.</BodyNote>\n </ActivityDisclosure>\n );\n}\n\n/* ---- generic fallback (first-party MCP, external MCP, unknown) ------------- */\n\nfunction GenericRenderer({ item }: ToolRendererProps) {\n const running = item.status === \"running\";\n const args = redactSecrets(parseToolArgs(item.arguments));\n const display = toolDisplayName(item.name);\n\n if (running) {\n return (\n <ActivityDisclosure\n icon={<PlugIcon className={ICON_SIZE} />}\n iconTone=\"running\"\n title={display}\n running\n preview={<RunningPreview>{compactArgs(args) || \"running…\"}</RunningPreview>}\n >\n <PayloadBlock label=\"Arguments\" value={args} />\n </ActivityDisclosure>\n );\n }\n\n const { text: outText, isError } = unwrapMcpOutput(item.output);\n // Cancelled is NOT an error — a user-cancelled tool should not surface the red\n // error chip even if the output payload carries an isError flag (the error may be\n // a consequence of the cancellation, not the tool's own failure).\n if ((isError || item.status === \"failed\") && item.status !== \"cancelled\") {\n return (\n <ActivityDisclosure\n icon={<WrenchIcon className={ICON_SIZE} />}\n iconTone=\"failed\"\n title={display}\n chip={{ tone: \"bad\", text: \"error\" }}\n preview={outText.slice(0, 80)}\n >\n <PayloadBlock label=\"Arguments\" value={args} />\n <PayloadBlock label=\"Error\" value={outText} failed />\n </ActivityDisclosure>\n );\n }\n\n return (\n <ActivityDisclosure\n icon={<WrenchIcon className={ICON_SIZE} />}\n iconTone=\"muted\"\n title={display}\n cancelled={item.status === \"cancelled\"}\n preview={compactArgs(args)}\n >\n <PayloadBlock label=\"Arguments\" value={args} />\n <PayloadBlock label=\"Result\" value={outText} />\n </ActivityDisclosure>\n );\n}\n\nfunction compactArgs(args: unknown): string {\n const text = stringifyPayload(args).replace(/\\s+/g, \" \").trim();\n return text === \"{}\" ? \"\" : text.length > 90 ? `${text.slice(0, 89)}…` : text;\n}\n\n/* ---- the default registry -------------------------------------------------- */\n\nconst BASE_ENTRIES: ToolRegistryEntry[] = [\n // Provider-native items carry `raw.type` on the wire — this is their source of\n // truth and is consulted first by the registry.\n { match: \"rawType\", type: \"apply_patch_call\", render: ApplyPatchRenderer },\n { match: \"rawType\", type: \"computer_call\", render: ComputerCallRenderer },\n { match: \"rawType\", type: \"hosted_tool_call\", render: WebSearchRenderer },\n // First-party sandbox + MCP tools resolve by name. `apply_patch_call` /\n // `computer_call` are intentionally repeated by name as a fallback only for\n // first-party replays that omit `raw` (the rawType entries above win whenever\n // `raw.type` is present, which is the live-wire case).\n { match: \"name\", name: \"exec_command\", render: ExecRenderer },\n { match: \"name\", name: \"write_stdin\", render: WriteStdinRenderer },\n { match: \"name\", name: \"apply_patch_call\", render: ApplyPatchRenderer },\n { match: \"name\", name: \"computer_call\", render: ComputerCallRenderer },\n // Function-mode computer tools (codex / chat-wire transports).\n { match: \"name\", name: \"computer_screenshot\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_click\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_double_click\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_move\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_scroll\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_type\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_keypress\", render: ComputerCallRenderer },\n { match: \"name\", name: \"computer_drag\", render: ComputerCallRenderer },\n { match: \"name\", name: \"web_search_call\", render: WebSearchRenderer },\n { match: \"name\", name: \"view_image\", render: ViewImageRenderer },\n { match: \"name\", name: \"environment_set_variable\", render: SecretSetRenderer },\n];\n\n/** The built-in tool renderer registry: every first-party tool plus a fallback. */\nexport const defaultToolRegistry: ToolRegistry = createToolRegistry(BASE_ENTRIES, GenericRenderer);\n\n/** Build a registry that extends the built-ins with consumer entries/fallback. */\nexport function createDefaultToolRegistry(\n options: Parameters<typeof createToolRegistry>[2] = {},\n): ToolRegistry {\n return createToolRegistry(BASE_ENTRIES, GenericRenderer, options);\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { tryParseJson } from \"../lib/format\";\n\n/* ----------------------------------------------------------------------------\n Pure parsers for the provider-native tool shapes that the timeline renders.\n\n These are intentionally browser-safe, dependency-free mirrors of the\n server-side helpers in `@opengeni/runtime` (`sandboxCommandExitCode`,\n `parseExecBannerSessionId`, `stripExecBanner`) plus the V4A diff parser the\n apply-patch renderer needs. The SDK does not depend on `@opengeni/runtime` by\n design (runtime is a heavy server package); these few regexes are cheap to\n own here and keep the React surface free of a server dependency.\n\n Every function is pure -- same input, same output -- so it can be\n unit-tested and memoized.\n -------------------------------------------------------------------------- */\n\n/** Recover the exit code from a sandbox exec banner (`Process exited with code N`). */\nexport function sandboxCommandExitCode(out: unknown): number | null {\n const match = String(out ?? \"\").match(/Process exited with code (-?\\d+)/);\n return match ? Number(match[1]) : null;\n}\n\n/**\n * Recover the numeric exec-session id the sandbox embeds for a STILL-RUNNING\n * (backgrounded) process (`Process running with session ID N`). A finished\n * command emits `Process exited with code N` instead, which yields `null`.\n */\nexport function parseExecBannerSessionId(out: unknown): number | null {\n const text = String(out ?? \"\");\n const outputIdx = text.indexOf(\"\\nOutput:\\n\");\n const banner =\n outputIdx >= 0 ? text.slice(0, outputIdx) : text.startsWith(\"Output:\\n\") ? \"\" : text;\n const match = banner.match(/Process running with session ID (\\d+)/);\n if (!match) {\n return null;\n }\n const n = Number.parseInt(match[1]!, 10);\n return Number.isFinite(n) ? n : null;\n}\n\n/** Strip the exec banner (`Chunk ID ...\\n...\\nOutput:\\n`) down to the command's stdout. */\nexport function stripExecBanner(out: unknown): string {\n const text = String(out ?? \"\");\n const marker = text.indexOf(\"\\nOutput:\\n\");\n if (marker >= 0) {\n return text.slice(marker + \"\\nOutput:\\n\".length);\n }\n if (text.startsWith(\"Output:\\n\")) {\n return text.slice(\"Output:\\n\".length);\n }\n return text;\n}\n\n/** The sandbox clamped the output (token/line truncation markers in the banner). */\nexport function execTruncated(out: unknown): boolean {\n return /Total output lines:|\\.{3}\\d+ tokens truncated\\.{3}|\\[\\.{3}\\d+ characters truncated/.test(\n String(out ?? \"\"),\n );\n}\n\n/** A `write_stdin` whose target PTY vanished (`write_stdin failed: session not found: N`). */\nexport function isExecSessionLostBanner(out: unknown): boolean {\n return /write_stdin failed: session not found: \\d+/.test(String(out ?? \"\"));\n}\n\n/** True when the exec stdout looks binary/garbled (a NUL byte or ELF magic). */\nexport function looksBinary(text: string): boolean {\n return text.includes(\"\\u0000\") || text.startsWith(\"\\u007fELF\");\n}\n\n/**\n * Render unprintable control characters as caret notation (0x03 -> `^C`) so a\n * `write_stdin` keystroke payload reads cleanly in the row title.\n */\nexport function controlCaret(printable: string): string {\n return String(printable).replace(\n /[\\u0000-\\u001f]/g,\n (c) => `^${String.fromCharCode(c.charCodeAt(0) + 64)}`,\n );\n}\n\n/* --- V4A apply_patch diff -> GitFileDiff ------------------------------------ */\n\n/** One operation inside an `apply_patch_call` (a V4A file edit). */\nexport type ApplyPatchOperation = {\n /**\n * The V4A op kind. The three canonical values are `create_file`,\n * `update_file`, and `delete_file`; the open `string` tail tolerates a\n * forward-compatible/unknown op kind from the provider without a type error\n * (it falls through to the \"Edited\" treatment).\n */\n type: \"create_file\" | \"update_file\" | \"delete_file\" | (string & {});\n path: string;\n /** Rename target -- when present the op is a move/rename. */\n moveTo?: string | null | undefined;\n /** The V4A hunk string (`@@ ...` lines with `+`/`-`/context prefixes). */\n diff?: string | undefined;\n};\n\n/**\n * Parse a single V4A `apply_patch` operation into the SDK's `GitFileDiff` shape\n * so it can flow into the SAME `DiffView` / `PierreDiff` the Files tab uses.\n * Throws on a hunk string it cannot structure (no `@@` anchor on an update); the\n * renderer catches and falls back to a raw-patch view.\n */\nexport function v4aToGitFileDiff(op: ApplyPatchOperation): GitFileDiff {\n const status: GitFileDiff[\"status\"] =\n op.type === \"create_file\"\n ? \"added\"\n : op.type === \"delete_file\"\n ? \"deleted\"\n : op.moveTo\n ? \"renamed\"\n : \"modified\";\n const oldPath = op.moveTo ? op.path : null;\n const path = op.moveTo || op.path;\n\n const hunks: GitFileDiff[\"hunks\"] = [];\n let additions = 0;\n let deletions = 0;\n let sawHunkAnchor = false;\n\n if (op.type !== \"delete_file\") {\n const lines = (op.diff ?? \"\").split(\"\\n\");\n let cur: GitFileDiff[\"hunks\"][number] | null = null;\n let oldNo = 1;\n let newNo = 1;\n for (const raw of lines) {\n if (raw.startsWith(\"@@\")) {\n sawHunkAnchor = true;\n const match = raw.match(/-(\\d+)(?:,\\d+)?\\s+\\+(\\d+)/);\n oldNo = match ? Number(match[1]) : 1;\n newNo = match ? Number(match[2]) : 1;\n cur = {\n oldStart: oldNo,\n oldLines: 0,\n newStart: newNo,\n newLines: 0,\n header: raw,\n lines: [{ type: \"meta\", oldNo: null, newNo: null, text: raw }],\n };\n hunks.push(cur);\n } else if (cur || op.type === \"create_file\") {\n if (!cur) {\n // No `@@` anchor on a create_file body: synthesize an add-only hunk.\n // Leave `header` empty so `gitFileDiffToPatch` regenerates a valid\n // `@@ -0,0 +1,N @@` from the range fields once newLines is counted — a\n // pre-baked partial header (e.g. `@@ +1 @@`) renders zero lines in a\n // generic unified-diff parser.\n cur = { oldStart: 0, oldLines: 0, newStart: 1, newLines: 0, header: \"\", lines: [] };\n hunks.push(cur);\n oldNo = 0;\n newNo = 1;\n }\n if (raw.startsWith(\"+\")) {\n cur.lines.push({ type: \"add\", oldNo: null, newNo: newNo++, text: raw.slice(1) });\n cur.newLines += 1;\n additions += 1;\n } else if (raw.startsWith(\"-\")) {\n cur.lines.push({ type: \"del\", oldNo: oldNo++, newNo: null, text: raw.slice(1) });\n cur.oldLines += 1;\n deletions += 1;\n } else {\n cur.lines.push({\n type: \"context\",\n oldNo: oldNo++,\n newNo: newNo++,\n text: raw.replace(/^ /, \"\"),\n });\n cur.oldLines += 1;\n cur.newLines += 1;\n }\n }\n }\n // An update with content but no recognizable hunk anchor is malformed V4A;\n // the caller falls back to the raw-patch view instead of a structured diff.\n if (op.type === \"update_file\" && !sawHunkAnchor && lines.some((l) => l.trim().length > 0)) {\n throw new Error(\"malformed V4A: no @@ hunk anchor\");\n }\n }\n\n return {\n path,\n oldPath,\n status,\n isBinary: false,\n isImage: false,\n additions,\n deletions,\n hunks,\n truncated: false,\n };\n}\n\n/**\n * Extract the `apply_patch` operations from a provider-native tool item's `raw`\n * payload, normalizing the two wire shapes (`raw.operations[]` for a multi-file\n * patch, `raw.operation` for a single op). The single owner of this shape so the\n * renderer and the turn-summary facet counter never drift.\n */\nexport function applyPatchOps(raw: unknown): ApplyPatchOperation[] {\n const r = (raw ?? {}) as { operation?: ApplyPatchOperation; operations?: ApplyPatchOperation[] };\n if (Array.isArray(r.operations)) {\n return r.operations;\n }\n return r.operation ? [r.operation] : [];\n}\n\n/**\n * True when a tool item is an `apply_patch_call` — by its provider-native\n * `raw.type` (the live-wire source of truth) or by tool `name` (first-party\n * replays that omit `raw`). Centralizes the rawType-or-name check.\n */\nexport function isApplyPatch(item: { name: string; raw: unknown }): boolean {\n const type =\n item.raw && typeof item.raw === \"object\" ? (item.raw as { type?: unknown }).type : undefined;\n return type === \"apply_patch_call\" || item.name === \"apply_patch_call\";\n}\n\n/* --- secret redaction ------------------------------------------------------- */\n\nconst SECRET_KEY = /^(value|secret|token|password|api[_-]?key|signing[_-]?key)$/i;\n\n/** Deep-redact secret-looking values so arguments never leak a key into the UI. */\nexport function redactSecrets(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(redactSecrets);\n }\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = SECRET_KEY.test(k) ? \"••••\" : redactSecrets(v);\n }\n return out;\n }\n return value;\n}\n\n/** Parse tool arguments that may arrive as a JSON string or an object. */\nexport function parseToolArgs(args: unknown): Record<string, unknown> {\n if (args == null) {\n return {};\n }\n if (typeof args === \"string\") {\n const parsed = tryParseJson(args);\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, unknown>) : {};\n }\n return typeof args === \"object\" ? (args as Record<string, unknown>) : {};\n}\n\n/** The last non-empty line of a string -- the compact \"what happened\" peek. */\nexport function tailPeek(text: string): string {\n const trimmed = text.trim();\n if (!trimmed) {\n return \"\";\n }\n const lines = trimmed.split(\"\\n\");\n return lines[lines.length - 1] ?? \"\";\n}\n\n/**\n * Unwrap an MCP tool result (`{ content: [{ type: \"text\", text }], isError? }`)\n * into a flat `{ text, isError }`. Non-MCP outputs pass through as their string\n * form.\n */\nexport function unwrapMcpOutput(output: unknown): { text: string; isError: boolean } {\n if (output && typeof output === \"object\" && \"content\" in output) {\n const record = output as { content?: unknown; isError?: unknown };\n const isError = Boolean(record.isError);\n if (Array.isArray(record.content)) {\n const textPart = record.content.find(\n (part): part is { type: string; text: string } =>\n !!part && typeof part === \"object\" && (part as { type?: unknown }).type === \"text\",\n );\n return { text: textPart ? String(textPart.text) : JSON.stringify(output), isError };\n }\n return { text: JSON.stringify(output), isError };\n }\n return {\n text: typeof output === \"string\" ? output : output == null ? \"\" : JSON.stringify(output),\n isError: false,\n };\n}\n\n/* --- computer-use screenshot extraction ------------------------------------- */\n\n/**\n * Extract a renderable `data:` URL from a computer-use screenshot output,\n * whatever transport produced it. The hosted `computer_call` and the\n * function-text mode persist a plain `data:image/...` string; the\n * function-image mode (codex-backed sessions) persists the STRUCTURED image\n * output — `{type:\"image\", image:{data, mediaType}}` with `data` arriving as a\n * number array / index map / Buffer-JSON / base64 string after event\n * serialization — or the agents-core normalized `input_image` content item.\n * Returns null when the output carries no image (so callers fall back to their\n * text/empty presentation).\n */\nexport function screenshotDataUrl(out: unknown): string | null {\n if (typeof out === \"string\") {\n if (out.startsWith(\"data:image\")) {\n return out;\n }\n // A JSON-encoded structured output (some transports stringify tool results).\n if (out.startsWith(\"{\") || out.startsWith(\"[\")) {\n const parsed = tryParseJson(out);\n if (parsed !== undefined && parsed !== out) {\n return screenshotDataUrl(parsed);\n }\n }\n return null;\n }\n if (Array.isArray(out)) {\n for (const entry of out) {\n const url = screenshotDataUrl(entry);\n if (url) {\n return url;\n }\n }\n return null;\n }\n if (out === null || typeof out !== \"object\") {\n return null;\n }\n const record = out as Record<string, unknown>;\n // agents-core normalized content item: {type:\"input_image\", image_url: \"data:…\" | {url}}\n const imageUrl = record.image_url ?? record.imageUrl;\n if (typeof imageUrl === \"string\" && imageUrl.startsWith(\"data:image\")) {\n return imageUrl;\n }\n if (imageUrl && typeof imageUrl === \"object\") {\n const url = (imageUrl as Record<string, unknown>).url;\n if (typeof url === \"string\" && url.startsWith(\"data:image\")) {\n return url;\n }\n }\n // Structured tool output: {type:\"image\", image:{data, mediaType}}\n const image = record.image as Record<string, unknown> | undefined;\n if (image && typeof image === \"object\") {\n const mediaType = typeof image.mediaType === \"string\" ? image.mediaType : \"image/png\";\n const base64 = bytesToBase64(image.data);\n if (base64) {\n return `data:${mediaType};base64,${base64}`;\n }\n if (typeof image.data === \"string\" && image.data.length > 0) {\n // Already base64 text.\n return `data:${mediaType};base64,${image.data}`;\n }\n }\n return null;\n}\n\n/** Serialize whatever a Uint8Array became in JSON (number[], {\"0\":n,…} index\n * map, or Buffer-JSON {type:\"Buffer\",data:[…]}) back into base64. */\nfunction bytesToBase64(data: unknown): string | null {\n const isByte = (n: unknown): n is number =>\n typeof n === \"number\" && Number.isInteger(n) && n >= 0 && n <= 255;\n let bytes: number[] | null = null;\n if (Array.isArray(data) && data.every(isByte)) {\n bytes = data;\n } else if (data && typeof data === \"object\") {\n const record = data as Record<string, unknown>;\n if (record.type === \"Buffer\" && Array.isArray(record.data) && record.data.every(isByte)) {\n bytes = record.data;\n } else {\n const keys = Object.keys(record);\n if (keys.length > 0 && keys.every((key) => /^\\d+$/.test(key))) {\n const values = keys.sort((a, b) => Number(a) - Number(b)).map((key) => record[key]);\n if (values.every(isByte)) {\n bytes = values;\n }\n }\n }\n }\n if (!bytes || bytes.length === 0) {\n return null;\n }\n try {\n let binary = \"\";\n const CHUNK = 0x8000;\n for (let i = 0; i < bytes.length; i += CHUNK) {\n binary += String.fromCharCode(...bytes.slice(i, i + CHUNK));\n }\n return typeof btoa === \"function\"\n ? btoa(binary)\n : Buffer.from(binary, \"binary\").toString(\"base64\");\n } catch {\n // A hostile/absurd payload must degrade to \"no image\", never crash a render.\n return null;\n }\n}\n","import { CameraIcon, CameraOffIcon, ChevronRightIcon } from \"lucide-react\";\nimport { useState, type ReactNode } from \"react\";\nimport { Collapsible } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\nimport { stringifyPayload } from \"../lib/format\";\nimport { useForcedDefaultOpen } from \"./disclosure-context\";\nimport { useLightboxOptional } from \"./screenshot-lightbox\";\n\n/* ----------------------------------------------------------------------------\n Shared timeline primitives\n\n The restraint layer. One disclosure shape every tool renderer reuses, so the\n rail reads as a calm, aligned column: a chevron, a tinted icon, a title, an\n optional muted preview, and — at most — ONE quiet right-aligned signal\n (a settle chip). Compact by default; the body only mounts when expanded.\n\n CHIP DOCTRINE (closed set — do not extend):\n The right gutter carries at most ONE terse status token per row, and COLOR is\n spent only on the exception. Success is the default, so it never earns a hue:\n a settled-ok chip is bare muted text (or nothing). The colored dot is reserved\n for failure alone. In-flight state is NOT a gutter chip — the shimmering title\n carries it, so a running row has a clean right edge (no detached pulse badge).\n There is no bordered/filled pill. Anything narrative (a session id, \"approval\n rejected\", \"malformed V4A\") belongs in the muted preview line, never the gutter.\n\n ok a settled success quiet muted text (\"0\", \"done\") — no dot\n bad a settled failure red dot + red text (\"exit 6\") — the one hue\n muted quiet metadata subtle text (\"session 3\")\n -------------------------------------------------------------------------- */\n\n/**\n * A subtle settle signal — see the CHIP DOCTRINE above. The closed tone set.\n * `\"interrupted\"` is a calm neutral tone for cancelled items — no dot, same\n * quiet weight as `\"muted\"`, but semantically distinct from metadata.\n */\nexport type DisclosureChip = {\n tone: \"ok\" | \"bad\" | \"muted\" | \"interrupted\";\n text: string;\n};\n\nexport type ActivityDisclosureProps = {\n icon: ReactNode;\n /** Icon tint. Defaults to the muted foreground; renderers pass accent/failed. */\n iconTone?: \"accent\" | \"failed\" | \"running\" | \"muted\" | undefined;\n title: ReactNode;\n /** Render the title in the mono face (commands, paths). */\n titleMono?: boolean | undefined;\n /** Shimmer the title while the tool is in-flight. */\n running?: boolean | undefined;\n /**\n * Quiet single-line secondary text (truncated). It is detail-on-demand: hidden\n * when a media preview is set, AND hidden once the row is expanded (the body\n * then owns the detail), so a stat/path never appears twice at once.\n */\n preview?: ReactNode | undefined;\n /** A small inline media preview (a screenshot thumbnail) shown in place of `preview`. */\n media?: ReactNode | undefined;\n /** At most one quiet settle chip, right-aligned to the gutter. */\n chip?: DisclosureChip | undefined;\n /**\n * When true the row carries the standard failure affordance: the icon is tinted\n * red and a \"failed\" bad-chip appears in the right gutter (unless an explicit\n * `chip` is already supplied — the caller's chip wins). Output is still visible\n * on expand; this is a quiet status signal, not a blocking banner.\n *\n * Renderers should pass `failed={item.status === \"failed\"}` on their settled\n * (non-running) paths so any tool with a failed status shows a consistent\n * affordance without each renderer having to duplicate the logic.\n */\n failed?: boolean | undefined;\n /**\n * When true the row carries a calm \"interrupted\" affordance: the icon stays\n * muted (no red) and a quiet \"interrupted\" chip appears in the right gutter\n * (unless an explicit `chip` is already supplied — the caller's chip wins).\n * This is the cancelled-status analogue of `failed`, but deliberately calm\n * and neutral — it is NOT an error; the user chose to stop.\n *\n * Renderers should pass `cancelled={item.status === \"cancelled\"}` so any\n * in-flight item that was interrupted on turn.cancelled reads consistently.\n * `cancelled` is ignored when `failed` is also true (failure takes precedence).\n */\n cancelled?: boolean | undefined;\n /** When false the row is a static line (no expand affordance). */\n expandable?: boolean | undefined;\n children?: ReactNode | undefined;\n};\n\nconst ICON_TONE: Record<NonNullable<ActivityDisclosureProps[\"iconTone\"]>, string> = {\n accent: \"text-og-accent\",\n failed: \"text-og-status-failed\",\n running: \"text-og-status-running\",\n muted: \"text-og-fg-subtle\",\n};\n\n/**\n * The one disclosure row shape every activity row reuses (tool calls, reasoning,\n * sandbox ops): a chevron, a tinted icon, a title, an optional muted preview or\n * inline media, and at most one right-gutter settle chip. Compact by default;\n * the body mounts only when expanded.\n */\nexport function ActivityDisclosure({\n icon,\n iconTone: iconToneProp = \"muted\",\n title,\n titleMono,\n running,\n preview,\n media,\n chip: chipProp,\n failed,\n cancelled,\n expandable = true,\n children,\n}: ActivityDisclosureProps) {\n // `failed` takes precedence over `cancelled` when both are set (shouldn't happen, but be safe).\n // When `failed` is set the icon goes red and a \"failed\" chip appears in the\n // gutter — unless the caller already supplied an explicit chip (their chip wins,\n // e.g. an exit-code chip that is more informative than a bare \"failed\" label).\n // When `cancelled` is set (and not failed) the icon stays muted and a calm\n // \"interrupted\" chip appears — no red, just a quiet neutral signal.\n const iconTone = failed && iconToneProp === \"muted\" ? \"failed\" : iconToneProp;\n const chip =\n chipProp ??\n (failed\n ? ({ tone: \"bad\", text: \"failed\" } satisfies DisclosureChip)\n : cancelled\n ? ({ tone: \"interrupted\", text: \"interrupted\" } satisfies DisclosureChip)\n : undefined);\n // An ancestor may seed the initial open state (screenshot instrumentation);\n // absent in normal app usage, where the row starts collapsed.\n const forcedDefaultOpen = useForcedDefaultOpen();\n const [open, setOpen] = useState(forcedDefaultOpen ?? false);\n const hasBody = expandable && children != null;\n\n // The preview is detail-on-demand: it is suppressed once the row is open so a\n // path/stat shown in the body never also sits in the collapsed row.\n const previewVisible = preview != null && !open;\n\n // ONE full-row layout for EVERY tool — media or not — so the hit target always\n // equals the visible row. The chevron → icon → title lead; a flex spacer (or\n // the preview) fills the middle; the right gutter (ml-auto) carries the chip OR\n // the media thumbnail. There is no media-vs-non-media fork: the screenshot card\n // toggles from anywhere on the row, exactly like every other row.\n //\n // The row is the single Collapsible.Trigger (via `asChild` onto a div), so it\n // is the toggle surface. A div — not a native <button> — so the interactive\n // media thumbnail (itself a <button>) is valid nested DOM; that thumbnail calls\n // stopPropagation so activating it never toggles the row.\n //\n // Radix forwards aria-expanded / aria-controls / data-state and a click handler\n // onto the asChild child, but it does NOT synthesize the button role, tab stop,\n // or Enter/Space activation for a non-button element. We add those ourselves\n // (role/tabIndex/onKeyDown) so the row is a fully keyboard-operable button to\n // AT and the keyboard, matching its native-<button> siblings (TurnSummary).\n const rowClass = cn(\n \"group/disclosure flex w-full min-w-0 items-center gap-2 rounded-og-sm px-1.5 py-1.5 text-left text-og-base\",\n \"text-og-fg-muted transition-colors duration-150\",\n // A tool row is a touch target on coarse pointers: grow its padding so the\n // hit area clears the 40px minimum without loosening the dense desktop rail.\n \"pointer-coarse:py-2.5\",\n );\n // The chevron rotates to point down when open; it tracks `data-state` on this\n // same row (the Trigger), so the affordance never freezes.\n const inner = (\n <>\n {hasBody ? (\n <ChevronRightIcon className=\"size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 ease-og-in-out group-data-[state=open]/disclosure:rotate-90\" />\n ) : (\n <span className=\"size-3.5 shrink-0\" />\n )}\n <span className={cn(\"shrink-0\", ICON_TONE[iconTone])}>{icon}</span>\n <span\n className={cn(\n \"min-w-0 shrink truncate text-og-base font-medium\",\n titleMono && \"font-og-mono text-og-sm font-normal\",\n running && \"og-shimmer-text\",\n )}\n >\n {title}\n </span>\n {previewVisible && !media ? (\n <span className=\"min-w-0 flex-1 truncate text-og-sm text-og-fg-subtle\">{preview}</span>\n ) : (\n <span className=\"flex-1\" />\n )}\n {/* The right gutter carries at most ONE signal: the media thumbnail, else a\n terse settle chip (hidden once expanded — the body owns the detail). */}\n {media ? (\n <span className=\"ml-auto flex shrink-0 items-center gap-2 pl-2\">{media}</span>\n ) : chip && !open ? (\n <span className=\"ml-auto shrink-0 pl-2\">\n <Chip chip={chip} />\n </span>\n ) : null}\n </>\n );\n\n // A `data-status` attribute on the root lets tests (and AT) detect the item's\n // settled state regardless of whether the chip slot is occupied by media.\n const dataStatus = cancelled ? \"cancelled\" : failed ? \"failed\" : undefined;\n\n if (!hasBody) {\n return (\n <div className={cn(rowClass, \"cursor-default\")} data-status={dataStatus}>\n {inner}\n </div>\n );\n }\n\n return (\n <Collapsible.Root open={open} onOpenChange={setOpen}>\n <Collapsible.Trigger asChild>\n <div\n role=\"button\"\n tabIndex={0}\n // Space/Enter activate a native button; Radix doesn't add this for a\n // non-button asChild child, so we toggle here. preventDefault on Space\n // stops the page from scrolling.\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n setOpen((prev) => !prev);\n }\n }}\n data-status={dataStatus}\n className={cn(\n rowClass,\n \"cursor-pointer outline-none hover:bg-og-surface-1 hover:text-og-fg\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-0\",\n )}\n >\n {inner}\n </div>\n </Collapsible.Trigger>\n <Collapsible.Content className=\"overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand\">\n <div className=\"mb-2 ml-7 mt-1.5 flex flex-col gap-2\">{children}</div>\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/**\n * The right-gutter settle chip. Color is spent only on the exception: a failure\n * is a red dot + red text (the one colored token in a healthy run); success and\n * metadata are bare muted text with no dot. No box, no fill (see the CHIP\n * DOCTRINE above). A `bad` chip with empty text is a lone dot (no trailing void).\n */\nfunction Chip({ chip }: { chip: DisclosureChip }) {\n const base = \"inline-flex items-center font-og-mono text-og-xs leading-none\";\n const withText = chip.text ? \"gap-1.5\" : \"gap-0\";\n if (chip.tone === \"bad\") {\n return (\n <span className={cn(base, withText, \"text-og-status-failed\")}>\n <span className=\"size-1.5 rounded-full bg-og-status-failed\" />\n {chip.text}\n </span>\n );\n }\n // \"interrupted\" is a calm cancelled signal: same quiet weight as muted, no\n // dot, no red — just a slightly more prominent subtle text so \"interrupted\"\n // reads at a glance without demanding attention the way a failure does.\n if (chip.tone === \"interrupted\") {\n return <span className={cn(base, \"text-og-fg-subtle og-cancelled-chip\")}>{chip.text}</span>;\n }\n // ok and muted are the same quiet weight — success never earns a hue.\n return <span className={cn(base, \"text-og-fg-subtle\")}>{chip.text}</span>;\n}\n\n/* --- terminal output block (exec / write_stdin) ---------------------------- */\n\nexport function TermBlock({\n command,\n workdir,\n output,\n live,\n tailLines = 12,\n failed,\n}: {\n /**\n * The command shown in the prompt header. Pass `null` when the row title\n * already carries it (e.g. an exec row titled `$ cmd`): the header then drops\n * the command — and the whole prompt line if there is no workdir either — so\n * the command never reads twice, stacked, above the output.\n */\n command: string | null;\n workdir?: string | null | undefined;\n /** The FULL output. TermBlock owns the tail/full slicing internally. */\n output: string;\n live?: boolean | undefined;\n /** A non-zero exit / failed call — tints the left accent red (the one hue). */\n failed?: boolean | undefined;\n /**\n * When the output exceeds the tail window, only the last `tailLines` are shown\n * with a \"show full output\" toggle. The component holds the full text, so the\n * toggle reveals the rest (never a dead affordance). Defaults to 12.\n */\n tailLines?: number | undefined;\n}) {\n const [full, setFull] = useState(false);\n const empty = output.trim() === \"\";\n const lines = output.split(\"\\n\");\n const big = lines.length > tailLines + 4;\n const shown = full || !big ? output : lines.slice(-tailLines).join(\"\\n\");\n const showMore = big && !full;\n const showHeader = command != null || workdir != null;\n\n // No frame, no fill: a quiet monospace run flush on the page, marked only by a\n // 2px left accent so it reads as terminal output at a glance without becoming\n // yet another nested box. Color is spent only on the exception — a settled run\n // gets a calm neutral rule, a live one the running hue, a failed one the red.\n return (\n <div\n className={cn(\n \"min-w-0 border-l-2 pl-3\",\n failed\n ? \"border-og-status-failed/50\"\n : live\n ? \"border-og-status-running/50\"\n : \"border-og-border\",\n )}\n >\n {showHeader ? (\n <div className=\"flex items-center gap-2 pb-1\">\n <span className=\"select-none text-og-status-idle\">$</span>\n {command != null ? (\n <span className=\"min-w-0 flex-1 truncate font-og-mono text-og-sm text-og-fg-muted\">\n {command}\n </span>\n ) : (\n <span className=\"flex-1\" />\n )}\n {workdir ? (\n <span className=\"shrink-0 font-og-mono text-og-xs text-og-fg-subtle\">{workdir}</span>\n ) : null}\n </div>\n ) : null}\n {empty ? (\n <p className=\"font-og-mono text-og-xs italic text-og-fg-subtle\">(no output)</p>\n ) : (\n <pre className=\"max-h-72 overflow-auto whitespace-pre-wrap break-all font-og-mono text-og-xs leading-5 text-og-fg-muted\">\n {shown}\n {live ? (\n <span className=\"ml-px inline-block h-[1em] w-[2px] translate-y-[2px] animate-og-blink bg-og-accent align-middle\" />\n ) : null}\n </pre>\n )}\n {showMore ? (\n <button\n type=\"button\"\n onClick={() => setFull(true)}\n className=\"mt-1 text-left text-og-xs text-og-fg-subtle transition-colors hover:text-og-fg\"\n >\n show full output ({lines.length} lines)\n </button>\n ) : null}\n </div>\n );\n}\n\n/* --- generic payload block -------------------------------------------------- */\n\nexport function PayloadBlock({\n label,\n value,\n failed,\n}: {\n label: string;\n value: unknown;\n failed?: boolean | undefined;\n}) {\n const text = typeof value === \"string\" ? value : stringifyPayload(value);\n if (!text || text.trim() === \"\") {\n return null;\n }\n // Flush on the page, no frame — a labelled monospace run marked only by a 2px\n // left accent (red when the call failed, otherwise a calm neutral rule), so a\n // payload reads as detail hanging off the row, never a nested card.\n return (\n <div\n className={cn(\n \"min-w-0 border-l-2 pl-3\",\n failed ? \"border-og-status-failed/50\" : \"border-og-border\",\n )}\n >\n <p className=\"mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle\">\n {label}\n </p>\n <pre\n className={cn(\n \"max-h-64 overflow-auto whitespace-pre-wrap break-all font-og-mono text-og-xs leading-5\",\n failed ? \"text-og-status-failed\" : \"text-og-fg-muted\",\n )}\n >\n {text}\n </pre>\n </div>\n );\n}\n\n/** A quiet inline note inside an expanded body (lost output, empty frame, …). */\nexport function BodyNote({\n children,\n tone,\n}: {\n children: ReactNode;\n tone?: \"error\" | \"muted\" | undefined;\n}) {\n if (tone === \"error\") {\n // A quiet error run marked by a 2px red accent — the same flush, frameless\n // language as the payload/output blocks, not a filled callout box.\n return (\n <div className=\"border-l-2 border-og-status-failed/50 pl-3 font-og-mono text-og-xs leading-5 text-og-status-failed\">\n {children}\n </div>\n );\n }\n return <p className=\"px-0.5 text-og-sm italic leading-5 text-og-fg-subtle\">{children}</p>;\n}\n\n/* --- screenshot thumbnail + media states ------------------------------------ */\n\n/**\n * The shared inline-media footprint, so thumb / skeleton / empty align. Sized to\n * the row's line height (~28px) so a media row never out-weighs a text row and\n * the single-column rhythm holds.\n */\nconst MEDIA_BOX = \"h-7 w-[52px] shrink-0 rounded-og-xs border border-og-border\";\n\n/**\n * A loading screenshot placeholder. A faint camera glyph over a shimmering box,\n * so a still frame of the running state reads unambiguously as \"capturing\" — not\n * a broken thumbnail.\n */\nexport function MediaSkeleton() {\n return (\n <span\n className={cn(\n MEDIA_BOX,\n \"relative inline-flex items-center justify-center overflow-hidden bg-og-surface-2\",\n )}\n >\n <span className=\"absolute inset-0 animate-og-pulse bg-og-surface-3/50\" />\n <CameraIcon className=\"relative size-3.5 text-og-fg-subtle\" />\n </span>\n );\n}\n\n/** A standardized \"tool ran, produced no image\" placeholder in the media slot. */\nexport function MediaEmpty() {\n return (\n <span className={cn(MEDIA_BOX, \"inline-flex items-center justify-center bg-og-bg\")}>\n <CameraOffIcon className=\"size-3.5 text-og-fg-subtle\" />\n </span>\n );\n}\n\n/**\n * A small inline screenshot thumbnail that opens the app lightbox on click.\n *\n * Requires a `LightboxProvider` ancestor for the click-to-expand affordance.\n * Outside one it degrades to a plain, non-interactive image — never a dead\n * \"Expand\" button that announces an action it cannot perform.\n */\nexport function Thumbnail({\n src,\n caption,\n alt = \"screenshot\",\n}: {\n src: string;\n caption?: string | undefined;\n alt?: string;\n}) {\n const lightbox = useLightboxOptional();\n const [failed, setFailed] = useState(false);\n if (failed) {\n return <MediaEmpty />;\n }\n // A plain <img> (not a framework Image): this is a framework-agnostic SDK, so\n // the host's image component is unavailable and unwanted here.\n const img = (\n <img\n src={src}\n alt={alt}\n onError={() => setFailed(true)}\n className=\"h-full w-full object-cover transition-opacity group-hover/thumb:opacity-80\"\n />\n );\n if (!lightbox) {\n return <span className={cn(MEDIA_BOX, \"inline-flex overflow-hidden bg-og-bg\")}>{img}</span>;\n }\n // The thumbnail is a real, independently-focusable button nested inside the\n // row's disclosure trigger. It stops both pointer AND keyboard activation from\n // bubbling, so opening the lightbox never also toggles the row.\n return (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n lightbox.open(src, caption);\n }}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.stopPropagation();\n }\n }}\n className={cn(\n MEDIA_BOX,\n \"group/thumb relative inline-flex overflow-hidden bg-og-bg outline-none\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n aria-label=\"Expand screenshot\"\n >\n {img}\n </button>\n );\n}\n\n/**\n * The expanded screenshot inside a tool body: a contained, clickable preview\n * (opens the lightbox) with a quiet caption. Constrained height + object-contain\n * so it never breaks the row layout. Like {@link Thumbnail}, it degrades to a\n * plain image outside a `LightboxProvider`.\n */\nexport function ScreenshotFigure({\n src,\n caption,\n alt = \"screenshot\",\n}: {\n src: string;\n caption?: string | undefined;\n alt?: string;\n}) {\n const lightbox = useLightboxOptional();\n const [failed, setFailed] = useState(false);\n const surface = \"block w-full overflow-hidden rounded-og-md border border-og-border bg-og-bg\";\n // A plain <img>, like {@link Thumbnail} — a framework-agnostic SDK has no host\n // Image component to defer to.\n const img = (\n <img\n src={src}\n alt={alt}\n onError={() => setFailed(true)}\n className=\"max-h-80 w-full object-contain\"\n />\n );\n return (\n <figure className=\"m-0 min-w-0\">\n {failed ? (\n <div className=\"rounded-og-md border border-og-border bg-og-bg px-3 py-6 text-center font-og-mono text-og-xs text-og-fg-subtle\">\n image unavailable\n </div>\n ) : lightbox ? (\n <button\n type=\"button\"\n onClick={() => lightbox.open(src, caption)}\n className={surface}\n aria-label=\"Expand screenshot\"\n >\n {img}\n </button>\n ) : (\n <div className={surface}>{img}</div>\n )}\n {caption ? (\n <figcaption className=\"mt-1.5 font-og-mono text-og-xs text-og-fg-subtle\">\n {caption}\n </figcaption>\n ) : null}\n </figure>\n );\n}\n","import { createContext, useContext, type ReactNode } from \"react\";\n\n/* ----------------------------------------------------------------------------\n Disclosure defaults context\n\n A tiny, opt-in context that lets an ancestor seed the INITIAL open state of\n every collapsible in the timeline (ActivityDisclosure rows and TurnSummary\n chips). Its sole intended use is deterministic screenshot capture: a tool can\n force every card open so a headless render shows expanded bodies.\n\n It is fully inert in normal app usage. With no provider, the hook returns\n `undefined`, every collapsible keeps its own author-chosen default, and there\n is zero change to how the components look or animate. Mounting the provider\n only changes the SEED of the initial `open` state — Radix still owns the\n open/close transition, so animations are untouched.\n -------------------------------------------------------------------------- */\n\nconst DisclosureDefaultsContext = createContext<boolean | undefined>(undefined);\n\n/**\n * Seed the initial open state of every timeline collapsible below this node.\n * Intended for screenshot/test instrumentation only; absent by default.\n */\nexport function DisclosureDefaultsProvider({\n defaultOpen,\n children,\n}: {\n defaultOpen: boolean;\n children: ReactNode;\n}) {\n return (\n <DisclosureDefaultsContext.Provider value={defaultOpen}>\n {children}\n </DisclosureDefaultsContext.Provider>\n );\n}\n\n/**\n * The forced initial-open seed from an ancestor {@link DisclosureDefaultsProvider},\n * or `undefined` when none is mounted (the inert, app-default case).\n */\nexport function useForcedDefaultOpen(): boolean | undefined {\n return useContext(DisclosureDefaultsContext);\n}\n","import { XIcon } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { createContext, useCallback, useContext, useMemo, useState, type ReactNode } from \"react\";\nimport { Dialog } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\n\n/* ----------------------------------------------------------------------------\n Screenshot lightbox\n\n A single, app-level lightbox the computer_call / view_image renderers open by\n `src`. Built on Radix Dialog so it is focus-trapped, ESC-closable, and\n scroll-locked — fixing the v1 mockup's broken expand (an absolutely-positioned\n <img> that overflowed its row). The image is centered, constrained to the\n viewport (`max-w/max-h` + `object-contain`), and sits on a dimmed backdrop.\n\n Consumers render `<LightboxProvider>` once near the timeline; renderers call\n `useLightbox().open(src)`.\n -------------------------------------------------------------------------- */\n\ntype LightboxController = {\n open: (src: string, caption?: string) => void;\n};\n\nconst LightboxContext = createContext<LightboxController | null>(null);\n\n/** Open the app-level screenshot lightbox. No-op outside a `LightboxProvider`. */\nexport function useLightbox(): LightboxController {\n return useContext(LightboxContext) ?? NOOP;\n}\n\n/**\n * The lightbox controller when one is mounted, or `null` outside a\n * `LightboxProvider`. Lets a media primitive degrade to a non-interactive image\n * (rather than a dead \"Expand\" button that announces an action it cannot do).\n */\nexport function useLightboxOptional(): LightboxController | null {\n return useContext(LightboxContext);\n}\n\nconst NOOP: LightboxController = { open: () => {} };\n\n/**\n * The app-level screenshot lightbox. Render once near the timeline; renderers\n * call `useLightbox().open(src)`.\n *\n * Idempotent by design: when an ancestor `LightboxProvider` already exists (e.g.\n * a `MessageTimeline` mounted inside an app that already wraps its shell), this\n * one becomes a pass-through and does NOT mount a second focus-trapping Dialog.\n * That keeps `MessageTimeline` self-sufficient (it owns its own provider) while\n * composing cleanly when nested.\n */\nexport function LightboxProvider({ children }: { children: ReactNode }) {\n const ancestor = useContext(LightboxContext);\n if (ancestor) {\n return <>{children}</>;\n }\n return <LightboxRoot>{children}</LightboxRoot>;\n}\n\nfunction LightboxRoot({ children }: { children: ReactNode }) {\n const [state, setState] = useState<{ src: string; caption?: string } | null>(null);\n\n const open = useCallback((src: string, caption?: string) => {\n setState(caption ? { src, caption } : { src });\n }, []);\n\n const controller = useMemo<LightboxController>(() => ({ open }), [open]);\n\n return (\n <LightboxContext.Provider value={controller}>\n {children}\n <Dialog.Root open={state !== null} onOpenChange={(next) => !next && setState(null)}>\n <AnimatePresence>\n {state !== null ? (\n <Dialog.Portal forceMount>\n <Dialog.Overlay asChild forceMount>\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n className=\"og-root fixed inset-0 z-50 bg-black/90 backdrop-blur-md\"\n />\n </Dialog.Overlay>\n <Dialog.Content\n asChild\n forceMount\n aria-label=\"Screenshot\"\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.98 }}\n transition={{ duration: 0.18, ease: [0.16, 1, 0.3, 1] }}\n // Content is a full-inset centering wrapper layered above the\n // Overlay, so Radix's own click-outside (which fires on the\n // Overlay) can never see a backdrop click — every click lands on\n // Content. We make Content's own backdrop dismiss: a click whose\n // target is the wrapper itself (not the figure) closes it, so the\n // figcaption's \"click outside to close\" affordance is real.\n onClick={(event) => {\n if (event.target === event.currentTarget) {\n setState(null);\n }\n }}\n className=\"og-root fixed inset-0 z-50 flex items-center justify-center p-6 sm:p-12\"\n >\n <Dialog.Title className=\"sr-only\">Screenshot</Dialog.Title>\n {/* The figure is one self-contained object: image, caption, and\n its own close control. The close button anchors to a wrapper\n sized to the IMAGE (w-fit), so it hugs the real top-right\n corner regardless of aspect ratio — never floating into the\n empty space of a wide figure column. */}\n <figure className=\"m-0 flex max-h-full max-w-5xl flex-col items-center gap-3\">\n <div className=\"relative flex min-h-0 w-fit max-w-full\">\n {/* A plain <img>: this SDK is framework-agnostic, with no host Image component. */}\n <img\n src={state.src}\n alt={state.caption ?? \"Screenshot\"}\n className=\"min-h-0 max-h-[82vh] w-auto max-w-full rounded-og-md border border-white/10 object-contain shadow-og-lg\"\n />\n <Dialog.Close\n className={cn(\n \"absolute -right-3 -top-3 inline-flex size-9 items-center justify-center rounded-full\",\n \"border border-white/15 bg-black/60 text-white/70 backdrop-blur\",\n \"transition-colors hover:border-white/30 hover:text-white\",\n )}\n aria-label=\"Close\"\n >\n <XIcon className=\"size-4\" />\n </Dialog.Close>\n </div>\n {state.caption ? (\n <figcaption className=\"max-w-2xl text-center font-og-mono text-og-xs text-white/55\">\n {state.caption}\n </figcaption>\n ) : (\n <figcaption className=\"font-og-mono text-og-xs uppercase tracking-[0.1em] text-white/35\">\n Esc or click outside to close\n </figcaption>\n )}\n </figure>\n </motion.div>\n </Dialog.Content>\n </Dialog.Portal>\n ) : null}\n </AnimatePresence>\n </Dialog.Root>\n </LightboxContext.Provider>\n );\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport { PierreDiff } from \"../components/pierre-diff\";\n\n/* ----------------------------------------------------------------------------\n Tool diff\n\n Renders parsed `GitFileDiff[]` (from the V4A apply_patch parser) through the\n EXACT same diff stack the Files/Changes tabs use: `PierreDiff` (Shiki-\n highlighted), with a built-in plain-text degrade for a host without\n `@pierre/diffs` — one renderer, a single data contract. A per-block\n Unified/Split toggle sits in the header.\n -------------------------------------------------------------------------- */\n\nexport function ToolDiff({ files }: { files: GitFileDiff[] }) {\n const [layout, setLayout] = useState<\"unified\" | \"split\">(\"unified\");\n // Resolve the host theme (auto-detect via `data-og-theme`) with the SAME hook\n // the Files tab uses, then thread it into Pierre. Without it Pierre falls back\n // to its hard dark default and renders a github-dark slab inside a light page.\n const themeType = useThemeType(undefined);\n return (\n <div className=\"min-w-0\">\n <div className=\"mb-1.5 flex justify-end\">\n <LayoutToggle layout={layout} onChange={setLayout} />\n </div>\n <PierreDiff diff={files} layout={layout} themeType={themeType} />\n </div>\n );\n}\n\nfunction LayoutToggle({\n layout,\n onChange,\n}: {\n layout: \"unified\" | \"split\";\n onChange: (next: \"unified\" | \"split\") => void;\n}) {\n return (\n <div className=\"inline-flex items-center gap-px rounded-og-xs border border-og-border p-px\">\n {([\"unified\", \"split\"] as const).map((value) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => onChange(value)}\n className={cn(\n \"rounded-og-xs px-2 py-[3px] text-og-xs font-medium capitalize transition-colors\",\n layout === value\n ? \"bg-og-surface-2 text-og-fg\"\n : \"text-og-fg-subtle hover:text-og-fg-muted\",\n )}\n >\n {value}\n </button>\n ))}\n </div>\n );\n}\n\n/** Raw-patch fallback for a V4A hunk string the parser could not structure. */\nexport function RawPatch({ diff }: { diff: string }) {\n const occurrences = new Map<string, number>();\n const lines = diff.split(\"\\n\").map((line) => {\n const occurrence = (occurrences.get(line) ?? 0) + 1;\n occurrences.set(line, occurrence);\n return { key: `${line}\\u0000${occurrence}`, line };\n });\n return (\n <div className=\"min-w-0\">\n <p className=\"mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle\">\n raw patch (could not parse hunks)\n </p>\n <pre className=\"max-h-72 overflow-auto border-l-2 border-og-border pl-3 font-og-mono text-og-xs leading-5\">\n {lines.map(({ key, line }) => (\n <span\n key={key}\n className={cn(\n \"block\",\n line.startsWith(\"@@\")\n ? \"text-og-accent\"\n : line.startsWith(\"+\")\n ? \"text-og-status-idle\"\n : line.startsWith(\"-\")\n ? \"text-og-status-failed\"\n : \"text-og-fg-muted\",\n )}\n >\n {line || \" \"}\n </span>\n ))}\n </pre>\n </div>\n );\n}\n","import { useEffect, useState } from \"react\";\n\n/* ----------------------------------------------------------------------------\n useThemeType\n\n Resolve the effective dark/light theme for surfaces (the Pierre/Shiki diff)\n that render outside the reach of host CSS — they need the theme as a value,\n not a cascade. An explicit prop always wins; otherwise read the host's\n `data-og-theme` attribute (set on `<html>` or any ancestor by the same opt-in\n the tokens use) and default to dark, the first-class theme. A MutationObserver\n keeps it live across runtime theme flips.\n\n One detector, shared by every diff surface (the Files tab and the timeline),\n so the two can never drift onto different themes.\n -------------------------------------------------------------------------- */\n\n/**\n * Resolve the diff theme. An explicit `forced` value wins; otherwise auto-detect\n * from the host `data-og-theme` (defaulting to dark) and track live flips.\n */\nexport function useThemeType(forced: \"dark\" | \"light\" | undefined): \"dark\" | \"light\" {\n const [detected, setDetected] = useState<\"dark\" | \"light\">(\"dark\");\n useEffect(() => {\n if (forced || typeof document === \"undefined\") return;\n const read = () => {\n const el = document.querySelector(\"[data-og-theme]\");\n const value = el?.getAttribute(\"data-og-theme\");\n setDetected(value === \"light\" ? \"light\" : \"dark\");\n };\n read();\n const observer = new MutationObserver(read);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-og-theme\"],\n subtree: true,\n });\n return () => observer.disconnect();\n }, [forced]);\n return forced ?? detected;\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport {\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n lazy,\n Suspense,\n useEffect,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { gitFileDiffToPatch } from \"../lib/git-patch\";\n\n/** Pierre `PatchDiff` props subset we drive. */\ntype PatchDiffComponent = ComponentType<{\n patch: string;\n options?: {\n theme?: string | { dark: string; light: string };\n themeType?: \"dark\" | \"light\";\n diffStyle?: \"unified\" | \"split\";\n overflow?: \"scroll\" | \"wrap\";\n stickyHeader?: boolean;\n };\n disableWorkerPool?: boolean;\n className?: string;\n}>;\n\nexport type PierreDiffProps = {\n diff: GitFileDiff[];\n layout?: \"unified\" | \"split\" | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n /** Shiki bundled theme names (dark/light) — derived from the host palette. */\n theme?: { dark: string; light: string } | undefined;\n /** Disable Pierre's worker pool if its worker bundling fights the host bundler. */\n disableWorkerPool?: boolean | undefined;\n /** Rendered while the (lazy) Pierre bundle loads. */\n loading?: ReactNode | undefined;\n /** Rendered if `@pierre/diffs/react` is not installed / fails to import. */\n fallback?: ReactNode | undefined;\n /** Skip the Shiki renderer entirely and show the plain-text degrade (the old\n * `usePierre={false}` path — one renderer, opted out of highlighting). */\n plain?: boolean | undefined;\n /** Long-line handling: `\"wrap\"` soft-wraps (the default — a diff in a narrow\n * dock pane should be readable without a horizontal-scroll tax), `\"scroll\"`\n * keeps lines on one row behind a horizontal scrollbar (better for a wide\n * viewport or pathological minified lines). */\n overflow?: \"wrap\" | \"scroll\" | undefined;\n className?: string | undefined;\n};\n\n// Lazy-load `@pierre/diffs/react` so Shiki + the worker pool stay off the\n// critical path (and out of an SSR bundle) until a diff is actually shown. The\n// dynamic specifier is static so the bundler can resolve + chunk it. If the\n// optional peer is absent the import rejects and we render `fallback`.\nconst LazyPatchDiff = lazy(async () => {\n const mod = (await import(\"@pierre/diffs/react\")) as unknown as {\n PatchDiff: PatchDiffComponent;\n };\n return { default: mod.PatchDiff };\n});\n\n/**\n * The Pierre-backed diff: Shiki-highlighted, virtualized, unified/split. Renders\n * one `PatchDiff` per changed file (a reconstructed unified patch from the\n * `GitFileDiff` hunks). The ONE workbench diff renderer; a host without\n * `@pierre/diffs` gets the built-in plain-text degrade (`PlainPatch`).\n */\nexport function PierreDiff({\n diff,\n layout = \"unified\",\n themeType,\n theme,\n disableWorkerPool,\n loading,\n fallback,\n plain,\n overflow = \"wrap\",\n className,\n}: PierreDiffProps) {\n const [failed, setFailed] = useState(false);\n\n // Probe the import once so a hard failure (peer missing) shows `fallback`\n // rather than a Suspense boundary that never resolves. Skipped when `plain`.\n useEffect(() => {\n if (plain) return;\n let cancelled = false;\n void import(\"@pierre/diffs/react\").catch(() => {\n if (!cancelled) setFailed(true);\n });\n return () => {\n cancelled = true;\n };\n }, [plain]);\n\n if (plain || failed) {\n // `plain` opts out of highlighting; `failed` = `@pierre/diffs` not installed.\n // Render the caller's fallback, or a plain (unhighlighted) patch dump — NOT a\n // second hunk renderer. One highlighted renderer (Pierre) + a text degrade.\n return <div className={className}>{fallback ?? <PlainPatch diff={diff} />}</div>;\n }\n\n // Default to the dark theme: the host UI is dark-first, and Pierre's own\n // auto-detection otherwise lands on the light Shiki theme (a white diff pane\n // inside a dark dock). Callers pass `themeType=\"light\"` to opt into light.\n const options = {\n diffStyle: layout,\n overflow,\n stickyHeader: true,\n ...(theme\n ? { theme }\n : {\n theme: {\n dark: \"github-dark-high-contrast\",\n light: \"github-light-high-contrast\",\n },\n }),\n themeType: themeType ?? \"dark\",\n };\n\n // Pierre renders inside a shadow DOM, so host CSS can't reach it — but it reads\n // a set of `--diffs-*-override` custom properties through the shadow boundary.\n // Pin the diff's own base background to the dock surface and quiet the hunk\n // separator slab so collapsed context rows do not become heavy bars.\n const pierreVars = {\n \"--diffs-dark-bg\": \"var(--og-color-bg)\",\n \"--diffs-light-bg\": \"var(--og-color-bg)\",\n \"--diffs-bg-buffer-override\": \"var(--og-color-surface-1)\",\n \"--diffs-bg-separator-override\": \"var(--og-color-surface-1)\",\n \"--diffs-addition-color-override\": \"var(--og-color-status-idle)\",\n \"--diffs-deletion-color-override\": \"var(--og-color-status-failed)\",\n \"--diffs-fg-number-addition-override\": \"var(--og-color-status-idle)\",\n \"--diffs-fg-number-deletion-override\": \"var(--og-color-status-failed)\",\n \"--diffs-bg-addition-override\":\n \"color-mix(in oklch, var(--og-color-status-idle) 12%, var(--og-color-bg))\",\n \"--diffs-bg-deletion-override\":\n \"color-mix(in oklch, var(--og-color-status-failed) 12%, var(--og-color-bg))\",\n \"--diffs-bg-addition-emphasis-override\":\n \"color-mix(in oklch, var(--og-color-status-idle) 22%, var(--og-color-bg))\",\n \"--diffs-bg-deletion-emphasis-override\":\n \"color-mix(in oklch, var(--og-color-status-failed) 22%, var(--og-color-bg))\",\n \"--diffs-font-size\": \"var(--og-code-font-size)\",\n \"--diffs-line-height\": \"var(--og-code-line-height)\",\n } as CSSProperties;\n\n return (\n <div className={cn(\"min-w-0\", className)} data-opengeni-pierre-diff style={pierreVars}>\n <Suspense fallback={loading ?? <DiffSkeleton />}>\n {diff.map((file) => (\n <div key={file.path} className=\"mb-2\">\n <LazyPatchDiff\n patch={gitFileDiffToPatch(file)}\n options={options}\n {...(disableWorkerPool !== undefined ? { disableWorkerPool } : {})}\n />\n </div>\n ))}\n </Suspense>\n </div>\n );\n}\n\nfunction DiffSkeleton() {\n return <div className=\"p-3 text-og-sm text-og-fg-subtle\">Loading diff…</div>;\n}\n\n/**\n * The unhighlighted degrade for a host without `@pierre/diffs`: the reconstructed\n * unified patch as monospace text with +/−/@@ tinting. Deliberately NOT a\n * structured hunk renderer — the workbench keeps exactly one of those (Pierre).\n */\nfunction PlainPatch({ diff }: { diff: GitFileDiff[] }) {\n if (diff.length === 0) {\n return <div className=\"p-3 text-og-sm text-og-fg-subtle\">No changes</div>;\n }\n return (\n <div className=\"min-w-0\">\n {diff.map((file) => (\n <pre\n key={file.path}\n className=\"mb-2 overflow-auto whitespace-pre rounded-og-sm border border-og-border bg-og-bg/60 p-2.5 font-og-mono text-og-xs leading-5\"\n >\n {gitFileDiffToPatch(file)\n .split(\"\\n\")\n .map((line, index) => (\n <span\n // Patch line position is the stable identity in this immutable plain-text fallback.\n // oxlint-disable-next-line react/no-array-index-key\n key={index}\n className={cn(\n \"block\",\n line.startsWith(\"@@\")\n ? \"text-og-accent\"\n : line.startsWith(\"+\")\n ? \"text-og-status-idle\"\n : line.startsWith(\"-\")\n ? \"text-og-status-failed\"\n : \"text-og-fg-muted\",\n )}\n >\n {line || \" \"}\n </span>\n ))}\n </pre>\n ))}\n </div>\n );\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\n\n/**\n * Reconstruct a unified-diff patch string for a single `GitFileDiff` so it can\n * be fed to a generic patch renderer (e.g. Pierre's `PatchDiff`). The hook\n * already carries per-line old/new numbers and a hunk header, so we emit a\n * conventional `--- / +++ / @@` patch the parser understands.\n */\nexport function gitFileDiffToPatch(file: GitFileDiff): string {\n const oldPath = file.oldPath ?? file.path;\n const newPath = file.path;\n const lines: string[] = [];\n lines.push(`diff --git a/${oldPath} b/${newPath}`);\n if (file.status === \"deleted\") {\n lines.push(`--- a/${oldPath}`);\n lines.push(`+++ /dev/null`);\n } else if (file.status === \"added\" || file.status === \"untracked\") {\n lines.push(`--- /dev/null`);\n lines.push(`+++ b/${newPath}`);\n } else {\n lines.push(`--- a/${oldPath}`);\n lines.push(`+++ b/${newPath}`);\n }\n for (const hunk of file.hunks) {\n // Only trust a pre-parsed header if it carries the full unified range form\n // `@@ -<o>[,<n>] +<o>[,<n>] @@`. A synthesized create_file hunk (parsers.ts)\n // can carry a degenerate `@@ +1 @@` with no `-`/`+` ranges; a generic patch\n // parser (Pierre) renders zero lines from it, so the expanded diff comes up\n // empty while the collapsed chip still shows the (correct) addition count.\n // In that case regenerate a valid header from the hunk's range fields.\n const headerIsValid = /^@@ -\\d+(?:,\\d+)? \\+\\d+(?:,\\d+)? @@/.test(hunk.header ?? \"\");\n const header = headerIsValid\n ? hunk.header\n : `@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`;\n lines.push(header);\n for (const line of hunk.lines) {\n if (line.type === \"meta\") continue;\n const prefix = line.type === \"add\" ? \"+\" : line.type === \"del\" ? \"-\" : \" \";\n lines.push(`${prefix}${line.text}`);\n }\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n","import {\n ArrowRightIcon,\n BotIcon,\n BrainCircuitIcon,\n BrainIcon,\n SquareTerminalIcon,\n} from \"lucide-react\";\nimport { cn } from \"../lib/cn\";\nimport { truncate } from \"../lib/format\";\nimport { defaultToolRegistry } from \"./tool-renderers\";\nimport { useEntranceAnimation } from \"./entrance\";\nimport type { ToolRegistry } from \"./registry\";\nimport { BodyNote, PayloadBlock, ActivityDisclosure } from \"./shared\";\nimport { toolDisplayName } from \"./projection\";\nimport type { ActivityItem, MemoryItem, ReasoningItem, SandboxItem, WorkerItem } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Activity rail\n\n Renders a run of clustered activity items (reasoning, tool calls, workers,\n sandbox ops) as the left-bordered column between chat messages. Tool calls\n resolve through the renderer registry; everything else has a first-class row.\n\n Shared by `MessageTimeline` and the component demo so both draw the exact\n same rail — no divergence.\n -------------------------------------------------------------------------- */\n\nexport type ActivityRailProps = {\n items: ActivityItem[];\n /** Renderer registry for tool calls. Defaults to {@link defaultToolRegistry}. */\n toolRegistry?: ToolRegistry | undefined;\n /** Drill into a spawned worker session. */\n onOpenSession?: ((sessionId: string) => void) | undefined;\n /**\n * Deep-link a memory row to its record in the host's memory pane. Opt-in: the\n * library draws no \"View in memory\" affordance without a handler (the memory\n * row is then non-interactive rich content). See {@link MessageTimelineProps}.\n */\n onMemoryClick?: ((memoryId: string) => void) | undefined;\n /** Drop the left rule + indent (used inside a folded turn summary). */\n bare?: boolean | undefined;\n className?: string | undefined;\n};\n\n/**\n * The \"family\" a row belongs to, for light intra-rail grouping. Consecutive\n * rows of the same family sit tight; a family change gets a little extra top\n * margin so a long run reads as clusters rather than one undifferentiated wall.\n */\nfunction familyOf(item: ActivityItem): string {\n if (item.kind === \"tool-call\") {\n return item.name === \"exec_command\" || item.name === \"write_stdin\" ? \"terminal\" : item.name;\n }\n return item.kind;\n}\n\nexport function ActivityRail({\n items,\n toolRegistry = defaultToolRegistry,\n onOpenSession,\n onMemoryClick,\n bare,\n className,\n}: ActivityRailProps) {\n const enter = useEntranceAnimation();\n return (\n <div\n className={cn(\n // Rows sit TIGHT by default (gap-0.5) so a same-family run reads as one\n // calm cluster; a family change opens real breathing room (mt-3) below,\n // so a long rail reads as a few clusters, not a metronome of rows.\n \"flex flex-col gap-0.5\",\n !bare && \"border-l-2 border-og-border pl-3 sm:pl-4\",\n !bare && enter && \"animate-og-enter\",\n className,\n )}\n >\n {items.map((item, index) => {\n const newFamily = index > 0 && familyOf(item) !== familyOf(items[index - 1]!);\n const row = renderActivity(item, toolRegistry, onOpenSession, onMemoryClick);\n return (\n <div key={item.id} className={cn(newFamily && \"mt-3\")}>\n {row}\n </div>\n );\n })}\n </div>\n );\n}\n\n/** A never-reachable guard: adding an `ActivityItem` kind is now a compile error. */\nfunction assertNever(item: never): never {\n throw new Error(`ActivityRail: unhandled activity item ${JSON.stringify(item)}`);\n}\n\nfunction renderActivity(\n item: ActivityItem,\n toolRegistry: ToolRegistry,\n onOpenSession: ((sessionId: string) => void) | undefined,\n onMemoryClick: ((memoryId: string) => void) | undefined,\n) {\n switch (item.kind) {\n case \"reasoning\":\n return <ReasoningRow item={item} />;\n case \"tool-call\": {\n const Renderer = toolRegistry.resolve(item);\n return <Renderer item={item} />;\n }\n case \"worker\":\n return <WorkerRow item={item} onOpenSession={onOpenSession} />;\n case \"sandbox\":\n return <SandboxRow item={item} />;\n case \"memory\":\n return <MemoryRow item={item} onMemoryClick={onMemoryClick} />;\n default:\n return assertNever(item);\n }\n}\n\nfunction ReasoningRow({ item }: { item: ReasoningItem }) {\n // Reasoning recedes: a dimmer, lighter-weight title so action rows lead and\n // thought rows sit a half-step back in the hierarchy.\n return (\n <ActivityDisclosure\n icon={<BrainIcon className=\"size-3.5\" />}\n iconTone=\"muted\"\n title={\n item.streaming ? (\n \"Thinking\"\n ) : (\n <span className=\"font-normal italic text-og-fg-subtle\">Thought</span>\n )\n }\n running={item.streaming}\n preview={truncate(item.text, 110)}\n >\n <p className=\"whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted\">{item.text}</p>\n </ActivityDisclosure>\n );\n}\n\n/**\n * Human labels for the memory kinds, translated at the SDK boundary so a raw\n * enum slug never renders as UI. Kept local to the library (the app has its own\n * `KIND_LABEL`); an unknown kind simply omits the chip rather than showing a slug.\n */\nconst MEMORY_KIND_LABEL: Record<string, string> = {\n preference: \"Preference\",\n semantic: \"Fact\",\n procedural: \"Procedure\",\n decision: \"Decision\",\n episodic: \"History\",\n};\n\n/**\n * A memory write the agent made mid-turn. A calm, NEUTRAL step (a successful save\n * is ordinary progress, never an exceptional state, so no accent/color): a brain-\n * circuit glyph, \"Saved to memory\" / \"Updated memory\", a human kind chip, and the\n * memory text. Expanding reveals the full text; a supersede shows the old text\n * struck through above the new one. When the host opts in with `onMemoryClick`,\n * a quiet \"View in memory\" affordance deep-links to the LIVE record.\n */\nfunction MemoryRow({\n item,\n onMemoryClick,\n}: {\n item: MemoryItem;\n onMemoryClick?: ((memoryId: string) => void) | undefined;\n}) {\n const corrected = item.variant === \"corrected\";\n const kindLabel = MEMORY_KIND_LABEL[item.memoryKind];\n // A supersede carries both the old text (`preview`) and the new (`replacementPreview`);\n // an in-place update / archive carries only `preview`.\n const superseded = corrected && Boolean(item.replacementPreview);\n // Link to the LIVE record: a supersede's replacement when present, else the memory itself.\n const targetId = corrected ? (item.replacementMemoryId ?? item.memoryId) : item.memoryId;\n const deepLink = Boolean(onMemoryClick);\n return (\n <ActivityDisclosure\n icon={<BrainCircuitIcon className=\"size-3.5\" />}\n iconTone=\"muted\"\n title={\n <span className=\"inline-flex min-w-0 items-center gap-2\">\n <span className=\"shrink-0\">{corrected ? \"Updated memory\" : \"Saved to memory\"}</span>\n {kindLabel ? (\n <span className=\"shrink-0 rounded-og-xs bg-og-surface-2 px-1.5 py-px text-og-xs font-normal leading-tight text-og-fg-subtle\">\n {kindLabel}\n </span>\n ) : null}\n </span>\n }\n preview={superseded ? item.replacementPreview : item.preview}\n >\n {superseded ? (\n // The correction as a before → after: the old memory struck through and\n // dimmed, the new text in the ordinary body weight below it.\n <div className=\"flex flex-col gap-1.5\">\n <p className=\"whitespace-pre-wrap text-og-sm leading-6 text-og-fg-subtle line-through\">\n {item.preview}\n </p>\n <p className=\"whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted\">\n {item.replacementPreview}\n </p>\n </div>\n ) : corrected && item.action === \"updated\" ? (\n // Edited in place, no replacement record: the memory is still live, so\n // show its current text — NOT the archived treatment.\n <>\n <p className=\"whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted\">\n {item.preview}\n </p>\n <BodyNote tone=\"muted\">Updated in place.</BodyNote>\n </>\n ) : corrected ? (\n // A correction with no replacement (and not an in-place update) archived the record.\n <BodyNote tone=\"muted\">Archived.</BodyNote>\n ) : (\n <p className=\"whitespace-pre-wrap text-og-base leading-6 text-og-fg-muted\">\n {item.preview}\n </p>\n )}\n {item.deduped ? <BodyNote tone=\"muted\">Merged into an existing memory.</BodyNote> : null}\n {deepLink ? (\n <button\n type=\"button\"\n onClick={() => onMemoryClick?.(targetId)}\n className={cn(\n \"group/memlink -mx-1 inline-flex w-fit items-center gap-1 rounded-og-sm px-1 py-0.5 text-left text-og-sm text-og-fg-subtle\",\n \"outline-none transition-colors duration-150 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n >\n View in memory\n <ArrowRightIcon className=\"size-3.5 transition-transform duration-150 group-hover/memlink:translate-x-0.5\" />\n </button>\n ) : null}\n </ActivityDisclosure>\n );\n}\n\n/**\n * A human title for a sandbox operation row. Named platform operations (the lazy\n * `sandbox.provision` first-establish that now runs mid-turn) read as calm,\n * status-aware English instead of a raw op id — the box coming up should look\n * like \"Starting sandbox\", never an unexplained long-running command. Unnamed /\n * unknown ops fall back to the generic id-to-words {@link toolDisplayName}.\n */\nfunction sandboxRowTitle(item: SandboxItem): string {\n if (item.name === \"sandbox.provision\") {\n if (item.status === \"failed\") return \"Sandbox didn’t start\";\n if (item.status === \"running\") return \"Starting sandbox\";\n if (item.origin === \"resumed\") return \"Sandbox reattached\";\n if (item.origin === \"restored\") return \"Sandbox restored\";\n if (item.origin === \"created\") return \"Sandbox created\";\n return \"Sandbox ready\";\n }\n return toolDisplayName(item.name);\n}\n\nfunction SandboxRow({ item }: { item: SandboxItem }) {\n return (\n <ActivityDisclosure\n icon={<SquareTerminalIcon className=\"size-3.5\" />}\n iconTone={\n item.status === \"failed\" ? \"failed\" : item.status === \"running\" ? \"running\" : \"muted\"\n }\n title={sandboxRowTitle(item)}\n running={item.status === \"running\"}\n failed={item.status === \"failed\"}\n cancelled={item.status === \"cancelled\"}\n preview={item.command ?? undefined}\n >\n {item.command ? <PayloadBlock label=\"Command\" value={item.command} /> : null}\n {item.output ? <PayloadBlock label=\"Output\" value={item.output} /> : null}\n </ActivityDisclosure>\n );\n}\n\n/** Spawned/messaged worker sessions get a first-class card, not a tool row. */\nfunction WorkerRow({\n item,\n onOpenSession,\n}: {\n item: WorkerItem;\n onOpenSession?: ((sessionId: string) => void) | undefined;\n}) {\n const running = item.status === \"running\";\n const failed = item.status === \"failed\";\n const cancelled = item.status === \"cancelled\";\n const title =\n item.action === \"spawn\"\n ? running\n ? \"Spawning worker\"\n : failed\n ? \"Worker spawn failed\"\n : cancelled\n ? \"Worker interrupted\"\n : \"Worker spawned\"\n : running\n ? \"Messaging worker\"\n : failed\n ? \"Worker message failed\"\n : cancelled\n ? \"Worker interrupted\"\n : \"Worker messaged\";\n // A worker is a first-class actor but still a STEP on the rail — a borderless\n // row (no card), aligned to its sibling tool rows: the chevron column is an\n // empty spacer (a worker doesn't expand), then the bot glyph, then the title\n // with a quiet prompt beneath, and one right-gutter affordance.\n //\n // Once the worker's session id is known, the WHOLE row is a clean, clickable\n // deep-link into that child session (a trailing arrow brightens on hover) —\n // the spawn moment itself is the affordance, not a small side button. A\n // still-in-flight spawn (no id yet) or a failed/cancelled worker is inert, so\n // there is never a dead click target. The gutter mirrors the worker-completion\n // card's calm language: red chip on failure, \"interrupted\" on cancel.\n const sessionId = item.workerSessionId;\n const deepLink = Boolean(sessionId) && Boolean(onOpenSession) && !failed && !cancelled;\n const inner = (\n <>\n <span className=\"size-3.5 shrink-0\" aria-hidden />\n <span className={cn(\"mt-px shrink-0\", failed ? \"text-og-status-failed\" : \"text-og-accent\")}>\n <BotIcon className=\"size-3.5\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n {/* In-flight state is carried ONLY by the shimmering title (no detached\n pulse badge), matching every other running row in the rail. */}\n <span\n className={cn(\n \"text-og-base font-medium\",\n running ? \"og-shimmer-text\" : failed ? \"text-og-status-failed\" : \"text-og-fg\",\n )}\n >\n {title}\n </span>\n {item.prompt ? (\n <p className=\"mt-0.5 truncate text-og-sm text-og-fg-muted\">\n {truncate(item.prompt, 140)}\n </p>\n ) : null}\n </div>\n {failed ? (\n <span className=\"inline-flex shrink-0 self-center items-center gap-1.5 font-og-mono text-og-xs leading-none text-og-status-failed\">\n <span className=\"size-1.5 rounded-full bg-og-status-failed\" />\n failed\n </span>\n ) : cancelled ? (\n <span className=\"og-cancelled-chip shrink-0 self-center font-og-mono text-og-xs leading-none text-og-fg-subtle\">\n interrupted\n </span>\n ) : deepLink ? (\n <ArrowRightIcon\n aria-hidden\n className=\"mt-0.5 size-3.5 shrink-0 text-og-fg-subtle transition-[transform,color] duration-150 group-hover/worker:translate-x-0.5 group-hover/worker:text-og-fg\"\n />\n ) : null}\n </>\n );\n\n if (deepLink && sessionId && onOpenSession) {\n return (\n <button\n type=\"button\"\n onClick={() => onOpenSession(sessionId)}\n className={cn(\n \"group/worker -mx-1.5 flex w-full items-start gap-2 rounded-og-sm px-1.5 py-1.5 text-left\",\n \"outline-none transition-colors duration-150 hover:bg-og-surface-1 focus-visible:ring-2 focus-visible:ring-og-accent\",\n \"pointer-coarse:py-2.5\",\n )}\n >\n {inner}\n </button>\n );\n }\n return <div className=\"flex items-start gap-2 px-1.5 py-1.5\">{inner}</div>;\n}\n","import { createContext, useContext, useRef } from \"react\";\n\n/* ----------------------------------------------------------------------------\n Entrance animation gating\n\n Bulk paints (the initial tail window, a prepended older window) must not run\n per-row entrance animations — hundreds of rows fading in at once reads as a\n full-timeline flash. Toggling `animation: none` on and off is NOT an option:\n removing the override restarts every animation, which is itself the flash.\n\n Instead each animated element decides ONCE, at its own mount, whether it was\n born in a bulk paint — and keeps that decision forever. Rows born in a bulk\n paint never animate; rows appended live animate exactly as before. Nothing\n is ever toggled on existing DOM, so nothing can replay.\n -------------------------------------------------------------------------- */\n\nconst EntranceAnimationContext = createContext(true);\n\nexport const EntranceAnimationProvider = EntranceAnimationContext.Provider;\n\n/**\n * Whether this element should wear the entrance animation. Captured at mount\n * from the nearest provider (true outside any provider) and stable for the\n * element's lifetime — see the module doctrine above.\n */\nexport function useEntranceAnimation(): boolean {\n const enabled = useContext(EntranceAnimationContext);\n const captured = useRef(enabled);\n return captured.current;\n}\n","import { CheckIcon, ChevronRightIcon, CircleSlashIcon, TriangleAlertIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { Collapsible } from \"radix-ui\";\nimport { cn } from \"../lib/cn\";\nimport { useForcedDefaultOpen } from \"./disclosure-context\";\nimport { useEntranceAnimation } from \"./entrance\";\nimport { applyPatchOps, isApplyPatch, screenshotDataUrl } from \"./parsers\";\nimport { rawTypeOf } from \"./registry\";\nimport type { ActivityItem, TurnOutcome } from \"./types\";\nexport type { TurnOutcome } from \"./types\";\n\n/* ----------------------------------------------------------------------------\n Turn summary\n\n A completed (or failed/cancelled) turn folds behind one quiet summary chip:\n \"N steps · M files · K commands · 1 screenshot · 4m\". The chip is the default\n surface; expanding it reveals the full settled turn body. A live turn never\n folds — render its rows directly.\n\n This keeps the timeline calm: a finished turn is a single line until the\n reader chooses to look inside it.\n -------------------------------------------------------------------------- */\n\nexport type TurnSummaryProps = {\n /** The activity items in the turn (used only to compute the facet counts). */\n items: ActivityItem[];\n /**\n * The settled verdict — or absent for a completed CLUSTER of a still-running\n * turn, which folds neutrally: no verdict glyph (the turn has none yet), a\n * quiet pulse dot in its place so alignment and the running feel both hold.\n */\n outcome?: TurnOutcome | undefined;\n /** A short failure reason shown inline on a failed chip (never hidden). */\n failureText?: string | undefined;\n /** Elapsed turn duration; shown as a trailing facet when at least 1s. */\n durationMs?: number | undefined;\n /** Start expanded. */\n defaultOpen?: boolean | undefined;\n /**\n * A nested fold — a cluster or sub-turn INSIDE an already-expanded turn. It\n * drops the bordered/filled chip and renders as a plain disclosure node on the\n * parent's rail (chevron + glyph + facets), so expanding a turn reveals a thread\n * of nodes, never a stack of boxes-in-boxes. The top-level fold stays a chip.\n */\n bare?: boolean | undefined;\n /** The rendered activity rail revealed on expand. */\n children: React.ReactNode;\n};\n\nexport function TurnSummary({\n items,\n outcome,\n failureText,\n durationMs,\n defaultOpen,\n bare,\n children,\n}: TurnSummaryProps) {\n // An explicit `defaultOpen` always wins; otherwise an ancestor may seed it\n // (screenshot instrumentation); otherwise the turn starts folded.\n const forcedDefaultOpen = useForcedDefaultOpen();\n const [open, setOpen] = useState(defaultOpen ?? forcedDefaultOpen ?? false);\n const enter = useEntranceAnimation();\n const facets = summarizeTurn(items, durationMs);\n\n return (\n <Collapsible.Root\n open={open}\n onOpenChange={setOpen}\n className={enter && !bare ? \"animate-og-enter\" : undefined}\n >\n <Collapsible.Trigger\n className={cn(\n // Both the top-level turn fold and a nested cluster fold render as a\n // FLAT rail row — chevron + glyph + facets on the page background, no\n // border, no fill. Only a hover tint hints the row is expandable, so a\n // collapsed turn never reads as a boxed card. The top-level row is a\n // touch larger (base text, size-5 glyph, wider gap) so it still reads\n // as a turn landmark above the nested cluster rows it groups.\n \"group flex w-full items-center rounded-og-sm text-left transition-colors\",\n // A folded turn is a touch target on coarse pointers: grow the row so it\n // clears the 40px minimum without disturbing the calm desktop rhythm.\n \"pointer-coarse:py-2.5\",\n bare\n ? \"gap-2 px-1.5 py-1.5 text-og-sm text-og-fg-muted\"\n : \"-mx-2 gap-2.5 px-2 py-1.5 text-og-base text-og-fg-muted\",\n // A failed fold keeps its red accent (glyph + inline reason below) and a\n // faint red hover wash so attention still lands there; every other\n // outcome gets the neutral surface hover.\n outcome === \"failed\"\n ? \"hover:bg-og-status-failed/[0.06] hover:text-og-fg\"\n : \"hover:bg-og-surface-1 hover:text-og-fg\",\n )}\n >\n {/* Disclosure grammar matches the rows: chevron leads (far left), then the\n outcome glyph, then the facets — one expand affordance side everywhere. */}\n <ChevronRightIcon className=\"size-3.5 shrink-0 text-og-fg-subtle transition-transform duration-150 group-data-[state=open]:rotate-90\" />\n {/* The outcome glyph carries the state by hue alone — no filled circle, no\n card. A clean (complete) run draws a bare muted check; a failed one a\n red triangle; a cancelled one a muted slash; a still-running cluster a\n quiet pulse dot in the glyph's place so alignment holds. */}\n <span\n className={cn(\n \"inline-flex shrink-0 items-center justify-center\",\n bare ? \"size-3.5\" : \"size-5\",\n outcome === \"failed\" ? \"text-og-status-failed\" : \"text-og-fg-subtle\",\n )}\n >\n {outcome === \"failed\" ? (\n <TriangleAlertIcon className=\"size-3\" />\n ) : outcome === \"cancelled\" ? (\n <CircleSlashIcon className=\"size-3\" />\n ) : outcome === \"complete\" ? (\n <CheckIcon className={bare ? \"size-3\" : \"size-3.5\"} />\n ) : (\n <span className=\"size-1.5 animate-og-pulse rounded-full bg-og-fg-subtle\" />\n )}\n </span>\n <span className={cn(\"min-w-0 flex-1 truncate\", bare ? \"text-og-sm\" : \"text-og-fg-muted\")}>\n {facets}\n {outcome === \"failed\" && failureText ? (\n <span className=\"text-og-status-failed\"> · {failureText}</span>\n ) : null}\n {outcome === \"cancelled\" ? (\n <span className=\"text-og-fg-subtle\"> · interrupted</span>\n ) : null}\n </span>\n {/* The disclosure hint. Calm at rest on fine pointers (revealed on hover\n and keyboard focus), but always present on coarse pointers where there\n is no hover to lean on — so the fold never reads as a static status\n line. Purely visual: the trigger's aria-expanded already conveys state\n to assistive tech, so the hint is hidden from the accessible name. */}\n <span\n aria-hidden\n className={cn(\n \"ml-auto shrink-0 pl-2 text-og-xs text-og-fg-subtle transition-opacity duration-150\",\n \"opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100\",\n \"pointer-coarse:opacity-100\",\n )}\n >\n {open ? \"hide steps\" : \"show steps\"}\n </span>\n </Collapsible.Trigger>\n <Collapsible.Content className=\"overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand\">\n {/* A nested node indents its revealed rows under the glyph (thread nesting\n off the parent rail); the top-level turn body owns its own rail. */}\n <div className={bare ? \"pt-1 pl-5\" : \"pt-2\"}>{children}</div>\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/** Compose the facet summary line (\"14 steps · 3 files · 2 commands · 1 screenshot · 4m\"). */\nfunction summarizeTurn(items: ActivityItem[], durationMs?: number): string {\n let files = 0;\n let commands = 0;\n let screenshots = 0;\n let memoriesSaved = 0;\n let memoriesUpdated = 0;\n for (const item of items) {\n if (item.kind === \"memory\") {\n // A memory write is a first-class facet — the \"wrote 1 memory\" signal the\n // fold should make prominent — counted saved vs updated separately.\n if (item.variant === \"corrected\") {\n memoriesUpdated += 1;\n } else {\n memoriesSaved += 1;\n }\n continue;\n }\n if (item.kind !== \"tool-call\") {\n continue;\n }\n // `item` is narrowed to ToolCallItem by the guard above — no cast needed.\n if (isApplyPatch(item)) {\n files += applyPatchOps(item.raw).length;\n } else if (item.name === \"exec_command\") {\n commands += 1;\n } else if (\n rawTypeOf(item) === \"computer_call\" ||\n item.name === \"computer_call\" ||\n item.name === \"computer_screenshot\"\n ) {\n if (screenshotDataUrl(item.output) !== null) {\n screenshots += 1;\n }\n }\n }\n const parts = [`${items.length} ${items.length === 1 ? \"step\" : \"steps\"}`];\n if (files) {\n parts.push(`${files} ${files === 1 ? \"file\" : \"files\"} edited`);\n }\n if (commands) {\n parts.push(`${commands} ${commands === 1 ? \"command\" : \"commands\"}`);\n }\n if (screenshots) {\n parts.push(`${screenshots} ${screenshots === 1 ? \"screenshot\" : \"screenshots\"}`);\n }\n if (memoriesSaved) {\n parts.push(`${memoriesSaved} ${memoriesSaved === 1 ? \"memory\" : \"memories\"} saved`);\n }\n if (memoriesUpdated) {\n parts.push(`${memoriesUpdated} ${memoriesUpdated === 1 ? \"memory\" : \"memories\"} updated`);\n }\n const duration = formatDurationFacet(durationMs);\n if (duration) {\n parts.push(duration);\n }\n return parts.join(\" · \");\n}\n\nfunction formatDurationFacet(durationMs: number | undefined): string | null {\n if (durationMs === undefined || !Number.isFinite(durationMs) || durationMs < 1000) {\n return null;\n }\n const totalSeconds = Math.floor(durationMs / 1000);\n if (totalSeconds < 60) {\n return `${totalSeconds}s`;\n }\n const totalMinutes = Math.floor(totalSeconds / 60);\n if (totalMinutes < 60) {\n return `${totalMinutes}m`;\n }\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n return `${hours}h ${String(minutes).padStart(2, \"0\")}m`;\n}\n","import type { SendMessageInput } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type ComposerSendExtras = Omit<SendMessageInput, \"text\" | \"clientEventId\">;\n\n/**\n * Enter appends a prompt; Cmd/Ctrl+Enter steers it to the head and supersedes\n * the current inference.\n */\nexport type ComposerMode = \"queue\" | \"steer\";\n\nexport type UseComposerOptions = ClientOverride & {\n /** Called with the accepted text after a successful send. */\n onSent?: ((text: string) => void) | undefined;\n /**\n * Extra message fields (resources, tools, model, reasoningEffort) merged\n * into every send. A function is evaluated at send time so it can read the\n * surrounding UI state (attachment pickers, model selectors, ...).\n */\n sendExtras?: ComposerSendExtras | (() => ComposerSendExtras) | undefined;\n};\n\nexport type ComposerState = {\n value: string;\n setValue: (value: string) => void;\n /** Send the draft (or explicit text). Queue is the default; steer is explicit. */\n send: (text?: string, mode?: ComposerMode) => Promise<boolean>;\n sending: boolean;\n canSend: boolean;\n /** Pause the session without deleting its prompt queue. */\n pause: (reason?: string) => Promise<void>;\n pausing: boolean;\n resume: (reason?: string) => Promise<void>;\n resuming: boolean;\n error: Error | null;\n clearError: () => void;\n};\n\n/**\n * Draft + send + Pause/Resume state for the chat composer — the only\n * human-to-agent input surface. The draft survives a failed send (nothing is\n * more hostile than losing a typed message); each send carries a generated\n * `clientEventId` so retries stay idempotent server-side.\n */\nexport function useComposer(\n sessionId: string | null | undefined,\n options: UseComposerOptions = {},\n): ComposerState {\n const { client, workspaceId } = useOpenGeni(options);\n const [value, setValue] = useState(\"\");\n const [sending, setSending] = useState(false);\n const [pausing, setPausing] = useState(false);\n const [resuming, setResuming] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const pendingClientEventId = useRef<string | null>(null);\n const onSent = options.onSent;\n // Read through a ref so a new extras closure (created every render by\n // callers passing inline functions) does not invalidate `send`.\n const sendExtrasRef = useRef(options.sendExtras);\n sendExtrasRef.current = options.sendExtras;\n\n // A composer is bound to one session: switching targets must not leak the\n // previous session's draft, error, or retry idempotency key.\n const targetKey = `${workspaceId}\\u0000${sessionId ?? \"\"}`;\n const targetKeyRef = useRef(targetKey);\n useEffect(() => {\n if (targetKeyRef.current !== targetKey) {\n targetKeyRef.current = targetKey;\n pendingClientEventId.current = null;\n setValue(\"\");\n setError(null);\n }\n }, [targetKey]);\n\n const send = useCallback(\n async (explicit?: string, delivery: ComposerMode = \"queue\"): Promise<boolean> => {\n const draftAtSend = value;\n const text = (explicit ?? draftAtSend).trim();\n // Resolve the extras once: a file-only message (empty text + ≥1 ready\n // resource) is legitimate, so we must not bail on empty text alone.\n const extras = resolveSendExtras(sendExtrasRef.current);\n const hasResources = (extras.resources?.length ?? 0) > 0;\n if ((!text && !hasResources) || !sessionId || sending) {\n return false;\n }\n // Reuse the clientEventId across retries of the same draft so a\n // timeout + resend cannot double-deliver the message.\n pendingClientEventId.current ??= generateClientEventId();\n setSending(true);\n setError(null);\n try {\n // The wire contract requires non-empty text (z.string().min(1)) and the\n // worker rejects whitespace-only text; a file-only message therefore\n // carries a minimal default so the attachments still get delivered.\n const sendText = text || FILE_ONLY_MESSAGE_TEXT;\n const input = composeSendInput(sendText, pendingClientEventId.current, extras);\n if (delivery === \"steer\") {\n await client.steerMessage(workspaceId, sessionId, input);\n } else {\n await client.sendMessage(workspaceId, sessionId, input);\n }\n pendingClientEventId.current = null;\n if (explicit === undefined) {\n // Clear only the draft that was sent: edits made while the request\n // was in flight were never delivered and must survive.\n setValue((current) => (current === draftAtSend ? \"\" : current));\n }\n onSent?.(sendText);\n return true;\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n return false;\n } finally {\n setSending(false);\n }\n },\n [client, workspaceId, sessionId, value, sending, onSent],\n );\n\n // A send is possible with non-empty text OR with ≥1 attached resource (a\n // file-only message). Resources ride in `sendExtras`, so we resolve them here\n // — keeping useComposer attachment-agnostic while still lighting up the send\n // affordance the moment a file is ready. ChatComposer additionally gates this\n // on its `attachments.uploading` flag so a message never departs mid-upload.\n const hasReadyResources = (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;\n\n const pause = useCallback(\n async (reason?: string): Promise<void> => {\n if (!sessionId || pausing) {\n return;\n }\n setPausing(true);\n setError(null);\n try {\n await client.pauseSession(workspaceId, sessionId, reason !== undefined ? { reason } : {});\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setPausing(false);\n }\n },\n [client, workspaceId, sessionId, pausing],\n );\n\n const resume = useCallback(\n async (reason?: string): Promise<void> => {\n if (!sessionId || resuming) return;\n setResuming(true);\n setError(null);\n try {\n await client.resumeSession(workspaceId, sessionId, reason !== undefined ? { reason } : {});\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setResuming(false);\n }\n },\n [client, workspaceId, sessionId, resuming],\n );\n\n const updateValue = useCallback((next: string) => {\n pendingClientEventId.current = null;\n setValue(next);\n }, []);\n\n return {\n value,\n setValue: updateValue,\n send,\n sending,\n canSend: Boolean(sessionId) && !sending && (value.trim().length > 0 || hasReadyResources),\n pause,\n pausing,\n resume,\n resuming,\n error,\n clearError: useCallback(() => setError(null), []),\n };\n}\n\n/**\n * Default text for a file-only message (attachment(s) present, no typed draft).\n * Kept non-empty so the wire contract (`text: z.string().min(1)`) and the\n * worker's non-whitespace guard accept it; the attached files still ride in\n * `resources`. Exported for tests.\n */\nexport const FILE_ONLY_MESSAGE_TEXT = \"(see attached files)\";\n\n/** Resolve possibly-deferred extras to a concrete bag (function evaluated now). */\nexport function resolveSendExtras(\n extras: ComposerSendExtras | (() => ComposerSendExtras) | undefined,\n): ComposerSendExtras {\n return (typeof extras === \"function\" ? extras() : extras) ?? {};\n}\n\n/**\n * Merge the draft text + idempotency key with caller-provided extras. The\n * text and clientEventId always win over extras. Exported for tests.\n */\nexport function composeSendInput(\n text: string,\n clientEventId: string,\n extras: ComposerSendExtras | (() => ComposerSendExtras) | undefined,\n): SendMessageInput {\n return { ...resolveSendExtras(extras), text, clientEventId };\n}\n\n/** Submit on plain Enter; Shift+Enter inserts a newline. Exported for tests. */\nexport function shouldSubmitOnKey(event: {\n key: string;\n shiftKey: boolean;\n metaKey?: boolean;\n ctrlKey?: boolean;\n nativeEvent?: { isComposing?: boolean };\n}): boolean {\n if (event.key !== \"Enter\" || event.shiftKey) {\n return false;\n }\n return event.nativeEvent?.isComposing !== true;\n}\n\n/** Cmd/Ctrl+Enter steers; ordinary Enter appends to the queue. */\nexport function composerModeForKey(event: { metaKey?: boolean; ctrlKey?: boolean }): ComposerMode {\n return event.metaKey || event.ctrlKey ? \"steer\" : \"queue\";\n}\n\nfunction generateClientEventId(): string {\n const cryptoApi = globalThis.crypto;\n if (cryptoApi && \"randomUUID\" in cryptoApi) {\n return cryptoApi.randomUUID();\n }\n return `ce-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n","import type { FileAsset, FileResourceRef } from \"@opengeni/sdk\";\nimport { useCallback, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type UseFileAttachmentsOptions = ClientOverride & {\n /**\n * Only files matching this predicate are accepted by {@link\n * UseFileAttachmentsResult.addFromPaste} (the clipboard path). Defaults to\n * `image/*` — the console's historical paste filter. {@link\n * UseFileAttachmentsResult.addFiles} (the explicit picker / drop path)\n * bypasses it.\n */\n pasteFilter?: ((file: File) => boolean) | undefined;\n};\n\nexport type FileAttachment = {\n id: string;\n name: string;\n contentType: string;\n sizeBytes: number;\n status: \"uploading\" | \"ready\" | \"failed\";\n /** The SDK `FileAsset` once the upload finishes. */\n file?: FileAsset | undefined;\n /** Object-URL for an inline preview; minted for `image/*` files only. */\n previewUrl?: string | undefined;\n error?: string | undefined;\n};\n\nexport type UseFileAttachmentsResult = {\n attachments: FileAttachment[];\n /**\n * `FileResourceRef[]` for every attachment that finished uploading — feed\n * straight into `useComposer`'s `sendExtras.resources`.\n */\n readyResources: FileResourceRef[];\n /** True while any attachment is still uploading (drives the send-gate). */\n uploading: boolean;\n /** Explicit picker / drop path — uploads every file, no filter. */\n addFiles: (files: Iterable<File>) => void;\n /** Clipboard path — applies `pasteFilter` (default `image/*`) then uploads. */\n addFromPaste: (event: { clipboardData: DataTransfer | null }) => void;\n /**\n * Re-run the upload for a `failed` attachment, in place (same id, same\n * source file). No-op for an id that isn't a known failed upload.\n */\n retry: (id: string) => void;\n /** Remove one attachment; revokes its object-URL. */\n remove: (id: string) => void;\n /** Remove all; revokes every object-URL. Call from `useComposer`'s `onSent`. */\n clear: () => void;\n};\n\nconst isImage = (file: File): boolean => file.type.startsWith(\"image/\");\n\n/**\n * Upload-and-track state for files attached to the next message. Owns the\n * full client-side upload layer: a per-file `uploading | ready | failed`\n * status machine driven by the SDK's `client.uploadFile`, object-URL image\n * previews with create/revoke lifecycle, the `image/*` clipboard paste filter,\n * and a `FileResourceRef[]` projection that drops straight into a message's\n * `resources`. Workspace-scoped, so it resolves both client and workspace from\n * the {@link OpenGeniProvider} (or a per-call `{ client, workspaceId }`).\n */\nexport function useFileAttachments(\n options: UseFileAttachmentsOptions = {},\n): UseFileAttachmentsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const pasteFilter = options.pasteFilter ?? isImage;\n const [attachments, setAttachments] = useState<FileAttachment[]>([]);\n // Keep the source File per attachment id so a failed upload can be retried\n // in place. Cleared on remove/clear so it never outlives its attachment.\n const sources = useRef<Map<string, File>>(new Map());\n\n // Run (or re-run) the upload for one already-tracked attachment id. Sets it\n // back to `uploading`, then resolves to `ready` (with the asset) or `failed`\n // (with the error message).\n const startUpload = useCallback(\n (id: string, file: File) => {\n void client\n .uploadFile(workspaceId, {\n filename: file.name || \"file\",\n contentType: file.type || \"application/octet-stream\",\n data: file,\n })\n .then((asset) => {\n setAttachments((current) =>\n current.map((attachment) =>\n attachment.id === id\n ? {\n ...attachment,\n status: \"ready\",\n file: asset,\n name: asset.filename,\n contentType: asset.contentType,\n sizeBytes: asset.sizeBytes,\n error: undefined,\n }\n : attachment,\n ),\n );\n })\n .catch((error: unknown) => {\n setAttachments((current) =>\n current.map((attachment) =>\n attachment.id === id\n ? {\n ...attachment,\n status: \"failed\",\n error: error instanceof Error ? error.message : String(error),\n }\n : attachment,\n ),\n );\n });\n },\n [client, workspaceId],\n );\n\n const addFiles = useCallback(\n (files: Iterable<File>) => {\n for (const file of files) {\n const id = crypto.randomUUID();\n sources.current.set(id, file);\n const previewUrl = isImage(file) ? URL.createObjectURL(file) : undefined;\n setAttachments((current) => [\n ...current,\n {\n id,\n name: file.name || \"image\",\n contentType: file.type || \"application/octet-stream\",\n sizeBytes: file.size,\n status: \"uploading\",\n ...(previewUrl ? { previewUrl } : {}),\n },\n ]);\n startUpload(id, file);\n }\n },\n [startUpload],\n );\n\n const retry = useCallback(\n (id: string) => {\n const file = sources.current.get(id);\n if (!file) {\n return;\n }\n setAttachments((current) =>\n current.map((attachment) =>\n attachment.id === id\n ? { ...attachment, status: \"uploading\", error: undefined }\n : attachment,\n ),\n );\n startUpload(id, file);\n },\n [startUpload],\n );\n\n const addFromPaste = useCallback(\n (event: { clipboardData: DataTransfer | null }) => {\n const clipboardFiles = event.clipboardData?.files;\n if (!clipboardFiles) {\n return;\n }\n const files = [...clipboardFiles].filter(pasteFilter);\n if (files.length > 0) {\n addFiles(files);\n }\n },\n [addFiles, pasteFilter],\n );\n\n const remove = useCallback((id: string) => {\n sources.current.delete(id);\n setAttachments((current) => {\n const removed = current.find((attachment) => attachment.id === id);\n if (removed?.previewUrl) {\n URL.revokeObjectURL(removed.previewUrl);\n }\n return current.filter((attachment) => attachment.id !== id);\n });\n }, []);\n\n const clear = useCallback(() => {\n sources.current.clear();\n setAttachments((current) => {\n for (const attachment of current) {\n if (attachment.previewUrl) {\n URL.revokeObjectURL(attachment.previewUrl);\n }\n }\n return [];\n });\n }, []);\n\n return {\n attachments,\n readyResources: attachments.flatMap((attachment): FileResourceRef[] =>\n attachment.status === \"ready\" && attachment.file\n ? [{ kind: \"file\", fileId: attachment.file.id }]\n : [],\n ),\n uploading: attachments.some((attachment) => attachment.status === \"uploading\"),\n addFiles,\n addFromPaste,\n retry,\n remove,\n clear,\n };\n}\n","import type { SessionEvent, SessionQueueSnapshot, SessionTurn } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport {\n useDebouncedCallback,\n useMutationRunner,\n useSessionEventTrigger,\n type SessionEventFeedOptions,\n} from \"./internal\";\n\n/** Events that can change the authoritative prompt queue or its pause gates. */\nexport function isTurnQueueEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return (\n event.type.startsWith(\"turn.\") ||\n event.type.startsWith(\"session.queue.\") ||\n event.type.startsWith(\"session.control.\") ||\n event.type.startsWith(\"workspace.inference.\")\n );\n}\n\nexport type UseTurnQueueOptions = ClientOverride &\n SessionEventFeedOptions & {\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseTurnQueueResult = {\n snapshot: SessionQueueSnapshot | null;\n /** Human/API prompts exactly in server execution order. Never client-sorted. */\n queue: SessionTurn[];\n controlState: SessionQueueSnapshot[\"controlState\"] | null;\n controlGeneration: number | null;\n workspaceInferenceState: SessionQueueSnapshot[\"workspaceInferenceState\"] | null;\n workspaceInferenceGeneration: number | null;\n workspaceRunExceptionGeneration: number | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Delete a waiting prompt before the worker claims it. */\n removeTurn: (turnId: string) => Promise<boolean>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * The single authoritative waiting-prompt queue. The server owns ordering; the\n * client renders the returned array verbatim and supports deletion only.\n */\nexport function useTurnQueue(\n sessionId: string | null | undefined,\n options: UseTurnQueueOptions = {},\n): UseTurnQueueResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const [snapshot, setSnapshot] = useState<SessionQueueSnapshot | null>(null);\n const [loading, setLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n const generation = useRef(0);\n const targetKeyRef = useRef<string | null>(null);\n const snapshotRef = useRef<SessionQueueSnapshot | null>(null);\n\n const replaceSnapshot = useCallback((next: SessionQueueSnapshot | null): void => {\n snapshotRef.current = next;\n setSnapshot(next);\n }, []);\n\n const load = useCallback(async (): Promise<void> => {\n if (!sessionId) return;\n const ticket = ++generation.current;\n try {\n const fetched = await client.getQueue(workspaceId, sessionId);\n if (ticket === generation.current) {\n replaceSnapshot(fetched);\n setError(null);\n setLoading(false);\n }\n } catch (cause) {\n if (ticket === generation.current) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setLoading(false);\n }\n }\n }, [client, workspaceId, sessionId, replaceSnapshot]);\n\n useEffect(() => {\n const targetKey = `${workspaceId}\\u0000${sessionId ?? \"\"}`;\n if (targetKeyRef.current !== targetKey) {\n targetKeyRef.current = targetKey;\n replaceSnapshot(null);\n setError(null);\n }\n if (!enabled) {\n setLoading(false);\n return;\n }\n setLoading(true);\n void load();\n const pollIntervalMs = options.pollIntervalMs;\n if (pollIntervalMs === undefined || pollIntervalMs <= 0) {\n return () => {\n generation.current += 1;\n };\n }\n const timer = setInterval(() => void load(), pollIntervalMs);\n return () => {\n clearInterval(timer);\n generation.current += 1;\n };\n }, [load, enabled, workspaceId, sessionId, options.pollIntervalMs, replaceSnapshot]);\n\n const scheduleRefresh = useDebouncedCallback(() => void load());\n useSessionEventTrigger(client, workspaceId, sessionId, isTurnQueueEvent, scheduleRefresh, {\n enabled,\n ...(options.events !== undefined ? { events: options.events } : {}),\n });\n\n const removeTurn = useCallback(\n async (turnId: string): Promise<boolean> => {\n if (!sessionId) return false;\n const current = snapshotRef.current;\n const item = current?.items.find((turn) => turn.id === turnId);\n if (!current || !item) return false;\n const result = await run(() =>\n client.cancelQueueItem(workspaceId, sessionId, turnId, {\n expectedQueueVersion: current.version,\n expectedItemVersion: item.version,\n }),\n );\n if (!result) {\n void load();\n return false;\n }\n replaceSnapshot(result.snapshot);\n return true;\n },\n [client, workspaceId, sessionId, run, load, replaceSnapshot],\n );\n\n return {\n snapshot,\n queue: snapshot?.items ?? [],\n controlState: snapshot?.controlState ?? null,\n controlGeneration: snapshot?.controlGeneration ?? null,\n workspaceInferenceState: snapshot?.workspaceInferenceState ?? null,\n workspaceInferenceGeneration: snapshot?.workspaceInferenceGeneration ?? null,\n workspaceRunExceptionGeneration: snapshot?.workspaceRunExceptionGeneration ?? null,\n loading,\n error,\n refresh: load,\n removeTurn,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import { OpenGeniApiError, type SessionEvent, type SessionGoal } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport {\n useDebouncedCallback,\n useMutationRunner,\n useSessionEventTrigger,\n type SessionEventFeedOptions,\n} from \"./internal\";\n\n/** Event types that change the session goal (set/updated/completed/paused/...). */\nexport function isGoalEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type.startsWith(\"goal.\");\n}\n\nexport type UseGoalOptions = ClientOverride &\n SessionEventFeedOptions & {\n /** Optional safety-net polling (ms). Off by default — goal.* events drive updates. */\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseGoalResult = {\n /** The session goal, or null when the session has none. */\n goal: SessionGoal | null;\n /** Convenience flags over `goal.status`. */\n isActive: boolean;\n isPaused: boolean;\n isCompleted: boolean;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Pause the goal loop (PATCH status=paused). */\n pause: (rationale?: string) => Promise<SessionGoal | null>;\n /** Resume a paused goal: resets counters and re-arms continuations. */\n resume: () => Promise<SessionGoal | null>;\n /** Clear the session goal; goal-less sessions remain a successful no-op. */\n clearGoal: () => Promise<void>;\n /** Alias for `clearGoal`. */\n deleteGoal: () => Promise<void>;\n /** True while a pause/resume/clear is in flight. */\n updating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * The session's goal: state, the autonomy counters (`autoContinuations`,\n * `noProgressStreak`), and pause/resume control. A goal-less session yields\n * `goal: null` (the 404 is absorbed). Live-updates on `goal.*` events —\n * pass `options.events` from `useSessionEvents` to reuse its stream.\n */\nexport function useGoal(\n sessionId: string | null | undefined,\n options: UseGoalOptions = {},\n): UseGoalResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const sharedEvents = options.events;\n const sharedFeed = sharedEvents !== undefined;\n const [goal, setGoal] = useState<SessionGoal | null>(null);\n const [loading, setLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n const generation = useRef(0);\n const targetKeyRef = useRef<string | null>(null);\n\n const load = useCallback(async (): Promise<void> => {\n if (!sessionId) {\n return;\n }\n const ticket = ++generation.current;\n try {\n const fetched = await client.getGoal(workspaceId, sessionId);\n if (ticket === generation.current) {\n setGoal(fetched);\n setError(null);\n setLoading(false);\n }\n } catch (cause) {\n if (ticket !== generation.current) {\n return;\n }\n if (cause instanceof OpenGeniApiError && cause.status === 404) {\n // No goal is a normal state, not an error.\n setGoal(null);\n setError(null);\n } else {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n setLoading(false);\n }\n }, [client, workspaceId, sessionId]);\n\n useEffect(() => {\n const targetKey = `${workspaceId} ${sessionId ?? \"\"}`;\n if (targetKeyRef.current !== targetKey) {\n targetKeyRef.current = targetKey;\n setGoal(null);\n setError(null);\n }\n if (!enabled) {\n setLoading(false);\n return;\n }\n if (sharedFeed) {\n setLoading(false);\n return () => {\n generation.current += 1;\n };\n }\n setLoading(true);\n void load();\n const pollIntervalMs = options.pollIntervalMs;\n if (pollIntervalMs === undefined || pollIntervalMs <= 0) {\n return () => {\n generation.current += 1;\n };\n }\n const timer = setInterval(() => void load(), pollIntervalMs);\n return () => {\n clearInterval(timer);\n generation.current += 1;\n };\n }, [load, enabled, workspaceId, sessionId, options.pollIntervalMs, sharedFeed]);\n\n const scheduleRefresh = useDebouncedCallback(() => void load());\n useSessionEventTrigger(client, workspaceId, sessionId, isGoalEvent, scheduleRefresh, {\n enabled,\n ...(sharedEvents !== undefined ? { events: sharedEvents } : {}),\n });\n\n const pause = useCallback(\n async (rationale?: string): Promise<SessionGoal | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await run(() =>\n client.updateGoal(workspaceId, sessionId, {\n status: \"paused\",\n ...(rationale !== undefined ? { rationale } : {}),\n }),\n );\n if (result) {\n setGoal(result);\n }\n return result;\n },\n [client, workspaceId, sessionId, run],\n );\n\n const resume = useCallback(async (): Promise<SessionGoal | null> => {\n if (!sessionId) {\n return null;\n }\n const result = await run(() => client.updateGoal(workspaceId, sessionId, { status: \"active\" }));\n if (result) {\n setGoal(result);\n }\n return result;\n }, [client, workspaceId, sessionId, run]);\n\n const clearGoal = useCallback(async (): Promise<void> => {\n if (!sessionId) {\n return;\n }\n // deleteGoal resolves void, so distinguish success (a truthy sentinel) from\n // mutation.run's null-on-failure. Only a SUCCESSFUL delete hides the goal:\n // a failed one leaves the pill up so its mutationError renders. And invalidate\n // any in-flight load first so a slower getGoal started before the delete can't\n // commit and repopulate the just-cleared goal.\n const ok = await run(async () => {\n await client.deleteGoal(workspaceId, sessionId);\n return true as const;\n });\n if (ok) {\n generation.current += 1;\n setGoal(null);\n setError(null);\n }\n }, [client, workspaceId, sessionId, run]);\n\n return {\n goal,\n isActive: goal?.status === \"active\",\n isPaused: goal?.status === \"paused\",\n isCompleted: goal?.status === \"completed\",\n loading,\n error,\n refresh: load,\n pause,\n resume,\n clearGoal,\n deleteGoal: clearGoal,\n updating: mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import type { SessionEvent } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner } from \"./internal\";\n\nexport type UseSessionControlOptions = ClientOverride;\n\nexport type UseSessionControlResult = {\n pause: (reason?: string) => Promise<SessionEvent | null>;\n resume: (reason?: string) => Promise<SessionEvent | null>;\n controlling: boolean;\n /** Approve a pending `requires_action` approval. */\n approve: (approvalId: string, message?: string) => Promise<SessionEvent | null>;\n /** Reject a pending `requires_action` approval. */\n reject: (approvalId: string, message?: string) => Promise<SessionEvent | null>;\n /** True while an approval decision is in flight. */\n responding: boolean;\n error: Error | null;\n clearError: () => void;\n};\n\n/**\n * Session pause/resume and approval decisions. Pair with\n * `useSessionEvents` (for `session.requiresAction` payloads carrying the\n * `approvalId`) to render an approval bar.\n */\nexport function useSessionControl(\n sessionId: string | null | undefined,\n options: UseSessionControlOptions = {},\n): UseSessionControlResult {\n const { client, workspaceId } = useOpenGeni(options);\n const {\n run: runControl,\n mutating: controlling,\n mutationError: controlError,\n clearMutationError: clearControlError,\n } = useMutationRunner();\n const {\n run: runApproval,\n mutating: responding,\n mutationError: approvalError,\n clearMutationError: clearApprovalError,\n } = useMutationRunner();\n\n const pause = useCallback(\n async (reason?: string): Promise<SessionEvent | null> => {\n if (!sessionId) {\n return null;\n }\n return await runControl(() =>\n client.pauseSession(workspaceId, sessionId, reason !== undefined ? { reason } : {}),\n );\n },\n [client, workspaceId, sessionId, runControl],\n );\n\n const resume = useCallback(\n async (reason?: string): Promise<SessionEvent | null> => {\n if (!sessionId) return null;\n const result = await runControl(() =>\n client.resumeSession(workspaceId, sessionId, reason !== undefined ? { reason } : {}),\n );\n return result?.event ?? null;\n },\n [client, workspaceId, sessionId, runControl],\n );\n\n const decide = useCallback(\n async (\n approvalId: string,\n decision: \"approve\" | \"reject\",\n message?: string,\n ): Promise<SessionEvent | null> => {\n if (!sessionId) {\n return null;\n }\n return await runApproval(() =>\n client.sendApprovalDecision(workspaceId, sessionId, {\n approvalId,\n decision,\n ...(message !== undefined ? { message } : {}),\n }),\n );\n },\n [client, workspaceId, sessionId, runApproval],\n );\n\n const approve = useCallback(\n async (approvalId: string, message?: string) => await decide(approvalId, \"approve\", message),\n [decide],\n );\n const reject = useCallback(\n async (approvalId: string, message?: string) => await decide(approvalId, \"reject\", message),\n [decide],\n );\n\n const error = approvalError ?? controlError;\n const clearError = useCallback(() => {\n clearControlError();\n clearApprovalError();\n }, [clearControlError, clearApprovalError]);\n\n return {\n pause,\n resume,\n controlling,\n approve,\n reject,\n responding,\n error,\n clearError,\n };\n}\n","import type { ScheduledTask } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseScheduledTasksOptions = ClientOverride & {\n limit?: number | undefined;\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseScheduledTasksResult = {\n tasks: ScheduledTask[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/** List the workspace's scheduled tasks (drift checks, sentinels, reapers, ...). */\nexport function useScheduledTasks(options: UseScheduledTasksOptions = {}): UseScheduledTasksResult {\n const { client, workspaceId } = useOpenGeni(options);\n const limit = options.limit;\n const load = useCallback(\n async () => await client.listScheduledTasks(workspaceId, limit !== undefined ? { limit } : {}),\n [client, workspaceId, limit],\n );\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n return {\n tasks: state.data ?? [],\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import type { Session } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseWorkspaceSessionsOptions = ClientOverride & {\n limit?: number | undefined;\n parentSessionId?: string | null | undefined;\n cursor?: string | undefined;\n search?: string | undefined;\n /** Refresh interval (ms) for fleet/manager views. Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseWorkspaceSessionsResult = {\n /**\n * All visible rows, with pins first. This preserves the pre-pinning hook\n * contract for consumers that only read `sessions`.\n */\n sessions: Session[];\n /** The complete personal pinned section, also present in `sessions`. */\n pinned: Session[];\n nextCursor: string | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/** List the workspace's sessions — the data behind fleet and manager views. */\nexport function useWorkspaceSessions(\n options: UseWorkspaceSessionsOptions = {},\n): UseWorkspaceSessionsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const limit = options.limit;\n const parentSessionId = options.parentSessionId;\n const cursor = options.cursor;\n const search = options.search;\n const queryKey = JSON.stringify({ workspaceId, limit, parentSessionId, cursor, search });\n const load = useCallback(\n async () => ({\n queryKey,\n page: await client.listSessionPage(workspaceId, {\n ...(limit !== undefined ? { limit } : {}),\n ...(parentSessionId !== undefined ? { parentSessionId } : {}),\n ...(cursor !== undefined ? { cursor } : {}),\n ...(search !== undefined ? { search } : {}),\n }),\n }),\n [client, workspaceId, limit, parentSessionId, cursor, search, queryKey],\n );\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n // usePolledValue drops stale async completions, while the explicit query key\n // also prevents the previous query's cached value from painting for the one\n // render before its loader-change effect clears state.\n const page = state.data?.queryKey === queryKey ? state.data.page : null;\n const pinned = page?.pinned ?? [];\n const ordinary = page?.sessions ?? [];\n return {\n // The old hook returned every visible session. Keep that public behavior\n // while exposing `pinned` separately for the compact section. The API page\n // itself continues to paginate only `ordinary` rows via nextCursor.\n sessions: [...pinned, ...ordinary],\n pinned,\n nextCursor: page?.nextCursor ?? null,\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import type { SessionEvent, SessionLineageResponse } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useDebouncedCallback, usePolledValue, useSessionEventTrigger } from \"./internal\";\n\nexport type UseSessionLineageOptions = ClientOverride & {\n events?: SessionEvent[] | undefined;\n /** Refresh interval (ms). Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseSessionLineageResult = {\n lineage: SessionLineageResponse | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\nexport function isLineageRefreshEvent(event: SessionEvent): boolean {\n if (event.type === \"session.status.changed\" || event.type === \"session.created\") {\n return true;\n }\n // A child's creation never appears on the PARENT's stream as session.created —\n // the parent sees its own spawn as an agent.toolCall.* for session_create.\n // Created events are handled separately so they can refresh immediately and\n // once after the child row has had time to commit.\n if (event.type === \"agent.toolCall.output\") {\n const payload = event.payload as { name?: unknown; toolName?: unknown } | null | undefined;\n const name =\n typeof payload?.name === \"string\"\n ? payload.name\n : typeof payload?.toolName === \"string\"\n ? payload.toolName\n : \"\";\n return name === \"session_create\" || name.endsWith(\"__session_create\");\n }\n return false;\n}\n\nfunction isSessionCreateToolCallCreated(event: SessionEvent): boolean {\n if (event.type !== \"agent.toolCall.created\") {\n return false;\n }\n const payload = event.payload as { name?: unknown; toolName?: unknown } | null | undefined;\n const name =\n typeof payload?.name === \"string\"\n ? payload.name\n : typeof payload?.toolName === \"string\"\n ? payload.toolName\n : \"\";\n return name === \"session_create\" || name.endsWith(\"__session_create\");\n}\n\n/** Read the ancestors + descendant tree for one session. Data-only; no UI state. */\nexport function useSessionLineage(\n sessionId: string | null | undefined,\n options: UseSessionLineageOptions = {},\n): UseSessionLineageResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const load = useCallback(\n async () =>\n sessionId\n ? await client.getSessionLineage(workspaceId, sessionId)\n : { ancestors: [], children: [], truncated: false },\n [client, workspaceId, sessionId],\n );\n const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled });\n const refreshSoon = useDebouncedCallback(() => void state.refresh(), 150);\n const delayedChildRefreshRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n // Clear a pending delayed refresh on session/workspace SWITCH (not just\n // unmount): otherwise a timer scheduled for the previous session can fire\n // ~2.5s later and commit that session's lineage onto the new one.\n useEffect(() => {\n return () => {\n if (delayedChildRefreshRef.current !== null) {\n clearTimeout(delayedChildRefreshRef.current);\n delayedChildRefreshRef.current = null;\n }\n };\n }, [sessionId, workspaceId]);\n const refreshAfterChildCreate = useCallback(() => {\n void state.refresh();\n if (delayedChildRefreshRef.current !== null) {\n clearTimeout(delayedChildRefreshRef.current);\n }\n delayedChildRefreshRef.current = setTimeout(() => {\n delayedChildRefreshRef.current = null;\n void state.refresh();\n }, 2500);\n }, [state]);\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isLineageRefreshEvent,\n refreshSoon,\n // SHARED-FEED ONLY: without a caller-provided events log the trigger would\n // open its OWN streamEvents tail — a second live SSE connection next to the\n // session route's useSessionEvents. A caller with no feed opts into polling\n // (pollIntervalMs), never a duplicate stream.\n { events: options.events, enabled: enabled && options.events !== undefined },\n );\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isSessionCreateToolCallCreated,\n refreshAfterChildCreate,\n { events: options.events, enabled: enabled && options.events !== undefined },\n );\n return {\n lineage: state.data,\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import type {\n CreateVariableSetRequest,\n UpdateVariableSetRequest,\n VariableSet,\n VariableSetVariableMetadata,\n} from \"@opengeni/sdk\";\nimport { useCallback, useMemo } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UseVariableSetsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseVariableSetsResult = {\n variableSets: VariableSet[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (request: CreateVariableSetRequest) => Promise<VariableSet | null>;\n update: (variableSetId: string, request: UpdateVariableSetRequest) => Promise<VariableSet | null>;\n remove: (variableSetId: string) => Promise<boolean>;\n /** Set/rotate a variable. Values are write-only — reads expose metadata only. */\n setVariable: (\n variableSetId: string,\n name: string,\n value: string,\n ) => Promise<VariableSetVariableMetadata | null>;\n deleteVariable: (variableSetId: string, name: string) => Promise<boolean>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * Variable sets (named, encrypted variable sets attached to sessions\n * and scheduled tasks). Variable values are write-only end to end: this hook\n * never sees a value after it is sent.\n */\nexport function useVariableSets(options: UseVariableSetsOptions = {}): UseVariableSetsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(\n async () => await client.listVariableSets(workspaceId),\n [client, workspaceId],\n );\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n\n const create = useCallback(\n async (request: CreateVariableSetRequest): Promise<VariableSet | null> => {\n const result = await run(() => client.createVariableSet(workspaceId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const update = useCallback(\n async (\n variableSetId: string,\n request: UpdateVariableSetRequest,\n ): Promise<VariableSet | null> => {\n const result = await run(() => client.updateVariableSet(workspaceId, variableSetId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const remove = useCallback(\n async (variableSetId: string): Promise<boolean> => {\n const result = await run(async () => {\n await client.deleteVariableSet(workspaceId, variableSetId);\n return true;\n });\n if (result) {\n await refresh();\n }\n return result === true;\n },\n [client, workspaceId, run, refresh],\n );\n\n const setVariable = useCallback(\n async (\n variableSetId: string,\n name: string,\n value: string,\n ): Promise<VariableSetVariableMetadata | null> => {\n const result = await run(() =>\n client.setVariableSetVariable(workspaceId, variableSetId, name, value),\n );\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const deleteVariable = useCallback(\n async (variableSetId: string, name: string): Promise<boolean> => {\n const result = await run(async () => {\n await client.deleteVariableSetVariable(workspaceId, variableSetId, name);\n return true;\n });\n if (result) {\n await refresh();\n }\n return result === true;\n },\n [client, workspaceId, run, refresh],\n );\n\n return {\n variableSets: data ?? [],\n loading,\n error,\n refresh,\n create,\n update,\n remove,\n setVariable,\n deleteVariable,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n\n/** @deprecated use UseVariableSetsOptions */\nexport type UseEnvironmentsOptions = UseVariableSetsOptions;\n/** @deprecated use UseVariableSetsResult */\nexport type UseEnvironmentsResult = UseVariableSetsResult & { environments: VariableSet[] };\n/** @deprecated use useVariableSets */\nexport function useEnvironments(options: UseEnvironmentsOptions = {}): UseEnvironmentsResult {\n const legacyClient = useMemo(() => {\n if (!options.client) {\n return undefined;\n }\n return {\n ...options.client,\n listVariableSets: options.client.listEnvironments ?? options.client.listVariableSets,\n createVariableSet: options.client.createEnvironment ?? options.client.createVariableSet,\n updateVariableSet: options.client.updateEnvironment ?? options.client.updateVariableSet,\n deleteVariableSet: options.client.deleteEnvironment ?? options.client.deleteVariableSet,\n setVariableSetVariable:\n options.client.setEnvironmentVariable ?? options.client.setVariableSetVariable,\n deleteVariableSetVariable:\n options.client.deleteEnvironmentVariable ?? options.client.deleteVariableSetVariable,\n };\n }, [options.client]);\n const result = useVariableSets({ ...options, ...(legacyClient ? { client: legacyClient } : {}) });\n return { ...result, environments: result.variableSets };\n}\n","import type {\n CreateRigRequest,\n ProposeRigChangeRequest,\n Rig,\n RigChange,\n RigVersion,\n UpdateRigRequest,\n} from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UseRigsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseRigsResult = {\n rigs: Rig[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (request: CreateRigRequest) => Promise<Rig | null>;\n update: (rigId: string, request: UpdateRigRequest) => Promise<Rig | null>;\n remove: (rigId: string) => Promise<boolean>;\n listVersions: (rigId: string) => Promise<RigVersion[] | null>;\n activateVersion: (rigId: string, versionId: string) => Promise<RigVersion | null>;\n listChanges: (rigId: string) => Promise<RigChange[] | null>;\n proposeChange: (rigId: string, request: ProposeRigChangeRequest) => Promise<RigChange | null>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * Rigs (workspace-scoped, versioned sandbox machine definitions). The list\n * polls; version/change reads are on-demand (they are per-rig detail, not part\n * of the list surface).\n */\nexport function useRigs(options: UseRigsOptions = {}): UseRigsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(async () => await client.listRigs(workspaceId), [client, workspaceId]);\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n\n const create = useCallback(\n async (request: CreateRigRequest): Promise<Rig | null> => {\n const result = await run(() => client.createRig(workspaceId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const update = useCallback(\n async (rigId: string, request: UpdateRigRequest): Promise<Rig | null> => {\n const result = await run(() => client.updateRig(workspaceId, rigId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const remove = useCallback(\n async (rigId: string): Promise<boolean> => {\n const result = await run(async () => {\n await client.deleteRig(workspaceId, rigId);\n return true;\n });\n if (result) {\n await refresh();\n }\n return result === true;\n },\n [client, workspaceId, run, refresh],\n );\n\n const listVersions = useCallback(\n async (rigId: string): Promise<RigVersion[] | null> => {\n return await run(() => client.listRigVersions(workspaceId, rigId));\n },\n [client, workspaceId, run],\n );\n\n const activateVersion = useCallback(\n async (rigId: string, versionId: string): Promise<RigVersion | null> => {\n const result = await run(() => client.activateRigVersion(workspaceId, rigId, versionId));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const listChanges = useCallback(\n async (rigId: string): Promise<RigChange[] | null> => {\n return await run(() => client.listRigChanges(workspaceId, rigId));\n },\n [client, workspaceId, run],\n );\n\n const proposeChange = useCallback(\n async (rigId: string, request: ProposeRigChangeRequest): Promise<RigChange | null> => {\n const result = await run(() => client.proposeRigChange(workspaceId, rigId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n return {\n rigs: data ?? [],\n loading,\n error,\n refresh,\n create,\n update,\n remove,\n listVersions,\n activateVersion,\n listChanges,\n proposeChange,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n\nexport type UseRigOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseRigResult = {\n rig: Rig | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n update: (request: UpdateRigRequest) => Promise<Rig | null>;\n remove: () => Promise<boolean>;\n activateVersion: (versionId: string) => Promise<RigVersion | null>;\n proposeChange: (request: ProposeRigChangeRequest) => Promise<RigChange | null>;\n /** Re-run verification for a change (asynchronous — poll for the outcome). */\n verifyChange: (changeId: string) => Promise<RigChange | null>;\n /** Promote a verified definition_edit into a new active version (rigs:manage). */\n promoteChange: (changeId: string) => Promise<RigVersion | null>;\n /** Re-verify the active version's checks in a clean throwaway sandbox. */\n verify: () => Promise<{ ok: boolean; versionId: string } | null>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * A single rig (its active version + counts), polled so verification and\n * promotion state stay live. Owns the rig's write actions; the versions and\n * changes lists are separate polled reads (`useRigVersions`/`useRigChanges`).\n */\nexport function useRig(rigId: string, options: UseRigOptions = {}): UseRigResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(\n async () => await client.getRig(workspaceId, rigId),\n [client, workspaceId, rigId],\n );\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n\n const update = useCallback(\n async (request: UpdateRigRequest): Promise<Rig | null> => {\n const result = await run(() => client.updateRig(workspaceId, rigId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, rigId, run, refresh],\n );\n\n const remove = useCallback(async (): Promise<boolean> => {\n const result = await run(async () => {\n await client.deleteRig(workspaceId, rigId);\n return true;\n });\n return result === true;\n }, [client, workspaceId, rigId, run]);\n\n const activateVersion = useCallback(\n async (versionId: string): Promise<RigVersion | null> => {\n const result = await run(() => client.activateRigVersion(workspaceId, rigId, versionId));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, rigId, run, refresh],\n );\n\n const proposeChange = useCallback(\n async (request: ProposeRigChangeRequest): Promise<RigChange | null> => {\n const result = await run(() => client.proposeRigChange(workspaceId, rigId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, rigId, run, refresh],\n );\n\n const verifyChange = useCallback(\n async (changeId: string): Promise<RigChange | null> => {\n const result = await run(() => client.verifyRigChange(workspaceId, rigId, changeId));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, rigId, run, refresh],\n );\n\n const promoteChange = useCallback(\n async (changeId: string): Promise<RigVersion | null> => {\n const result = await run(() => client.promoteRigChange(workspaceId, rigId, changeId));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, rigId, run, refresh],\n );\n\n const verify = useCallback(async (): Promise<{ ok: boolean; versionId: string } | null> => {\n return await run(() => client.verifyRig(workspaceId, rigId));\n }, [client, workspaceId, rigId, run]);\n\n return {\n rig: data,\n loading,\n error,\n refresh,\n update,\n remove,\n activateVersion,\n proposeChange,\n verifyChange,\n promoteChange,\n verify,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n\nexport type UseRigVersionsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseRigVersionsResult = {\n versions: RigVersion[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/** A rig's append-only version history, newest-first (polled). */\nexport function useRigVersions(\n rigId: string,\n options: UseRigVersionsOptions = {},\n): UseRigVersionsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(\n async () => await client.listRigVersions(workspaceId, rigId),\n [client, workspaceId, rigId],\n );\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n return {\n versions: state.data ?? [],\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n\nexport type UseRigChangesOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseRigChangesResult = {\n changes: RigChange[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/**\n * A rig's change queue (polled). The default poll cadence lets a change move\n * through verifying → merged/rejected without a manual refresh.\n */\nexport function useRigChanges(\n rigId: string,\n options: UseRigChangesOptions = {},\n): UseRigChangesResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(\n async () => await client.listRigChanges(workspaceId, rigId),\n [client, workspaceId, rigId],\n );\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n return {\n changes: state.data ?? [],\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import type {\n CapabilityPack,\n EnablePackRequest,\n PackInstallation,\n RegisterCapabilityPackRequest,\n WorkspaceRegisteredPack,\n} from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nconst EMPTY_INSTALLATIONS: PackInstallation[] = [];\n\nexport type UsePacksOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UsePacksResult = {\n /** Built-in + registered packs available to the workspace. */\n packs: CapabilityPack[];\n /** Enable/disable state per pack. */\n installations: PackInstallation[];\n /** The installation for a pack id, if any. */\n installationFor: (packId: string) => PackInstallation | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n /** Register (or replace) a workspace-scoped pack manifest. */\n register: (manifest: RegisterCapabilityPackRequest) => Promise<WorkspaceRegisteredPack | null>;\n enable: (packId: string, request?: EnablePackRequest) => Promise<PackInstallation | null>;\n /** Unregister a workspace-scoped pack (built-ins cannot be removed). */\n remove: (packId: string) => Promise<boolean>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/** Capability packs: catalog + installations + register/enable/unregister. */\nexport function usePacks(options: UsePacksOptions = {}): UsePacksResult {\n const { client, workspaceId } = useOpenGeni(options);\n const load = useCallback(async () => await client.listPacks(workspaceId), [client, workspaceId]);\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n\n const register = useCallback(\n async (manifest: RegisterCapabilityPackRequest): Promise<WorkspaceRegisteredPack | null> => {\n const result = await run(() => client.registerPack(workspaceId, manifest));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const enable = useCallback(\n async (packId: string, request: EnablePackRequest = {}): Promise<PackInstallation | null> => {\n const result = await run(() => client.enablePack(workspaceId, packId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const remove = useCallback(\n async (packId: string): Promise<boolean> => {\n const result = await run(async () => {\n await client.deletePack(workspaceId, packId);\n return true;\n });\n if (result) {\n await refresh();\n }\n return result === true;\n },\n [client, workspaceId, run, refresh],\n );\n\n const installations = data?.installations ?? EMPTY_INSTALLATIONS;\n const installationFor = useCallback(\n (packId: string): PackInstallation | null =>\n installations.find((installation) => installation.packId === packId) ?? null,\n [installations],\n );\n\n return {\n packs: data?.packs ?? [],\n installations,\n installationFor,\n loading,\n error,\n refresh,\n register,\n enable,\n remove,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import type { CreateWorkspaceRequest, UpdateWorkspaceRequest, Workspace } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeniClient, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UseWorkspacesOptions = Pick<ClientOverride, \"client\"> & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseWorkspacesResult = {\n workspaces: Workspace[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (request: CreateWorkspaceRequest) => Promise<Workspace | null>;\n update: (workspaceId: string, request: UpdateWorkspaceRequest) => Promise<Workspace | null>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * The caller's workspaces (workspace switchers, onboarding). Not scoped to\n * the provider's workspace, so it only needs the client.\n */\nexport function useWorkspaces(options: UseWorkspacesOptions = {}): UseWorkspacesResult {\n const client = useOpenGeniClient(options);\n const load = useCallback(async () => await client.listWorkspaces(), [client]);\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner();\n\n const create = useCallback(\n async (request: CreateWorkspaceRequest): Promise<Workspace | null> => {\n const result = await run(() => client.createWorkspace(request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, run, refresh],\n );\n\n const update = useCallback(\n async (workspaceId: string, request: UpdateWorkspaceRequest): Promise<Workspace | null> => {\n const result = await run(() => client.updateWorkspace(workspaceId, request));\n if (result) {\n await refresh();\n }\n return result;\n },\n [client, run, refresh],\n );\n\n return {\n workspaces: data ?? [],\n loading,\n error,\n refresh,\n create,\n update,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import type { BillingBalance, UsageEvent } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeniClient, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseBillingUsageOptions = Pick<ClientOverride, \"client\"> & {\n /** Account to read. Defaults to the caller's default account server-side. */\n accountId?: string | undefined;\n /** Filter usage to one workspace. */\n workspaceId?: string | undefined;\n /** Refresh interval (ms) for live billing meters. Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseBillingUsageResult = {\n /** Prepaid credit balance (micro-USD), null until loaded. */\n balance: BillingBalance | null;\n /** Recent usage events (runs, tokens, cost, uploads, ...). */\n usage: UsageEvent[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/**\n * Account billing usage: credit balance + recent usage events — the data\n * behind per-call billing meters. Account-scoped, so it only needs the\n * client; pass `workspaceId` to narrow usage to one workspace.\n */\nexport function useBillingUsage(options: UseBillingUsageOptions = {}): UseBillingUsageResult {\n const client = useOpenGeniClient(options);\n const accountId = options.accountId;\n const workspaceId = options.workspaceId;\n const load = useCallback(\n async () =>\n await client.getBillingUsage({\n ...(accountId !== undefined ? { accountId } : {}),\n ...(workspaceId !== undefined ? { workspaceId } : {}),\n }),\n [client, accountId, workspaceId],\n );\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n return {\n balance: state.data?.balance ?? null,\n usage: state.data?.usage ?? [],\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import type { ClientModel } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\nimport { useOpenGeniClient, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseAvailableModelsOptions = Pick<ClientOverride, \"client\"> & {\n /** Refresh interval (ms). Off by default — the host model list rarely moves. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseAvailableModelsResult = {\n /** The provider-grouped models the host exposes (empty until loaded). */\n models: ClientModel[];\n /** The deployment's default model id, null until loaded. */\n defaultModel: string | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\n/**\n * The host-exposed model list for a <ModelPicker>: fetches the deployment's\n * public client config (`GET /v1/config/client`) and surfaces the richer\n * provider-grouped `models` plus the `defaultModel` the picker should preselect.\n * Deployment-scoped, so it only needs the client (no workspace).\n */\nexport function useAvailableModels(\n options: UseAvailableModelsOptions = {},\n): UseAvailableModelsResult {\n const client = useOpenGeniClient(options);\n const load = useCallback(async () => await client.getClientConfig(), [client]);\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n return {\n models: state.data?.models ?? [],\n defaultModel: state.data?.defaultModel ?? null,\n loading: state.loading,\n error: state.error,\n refresh: state.refresh,\n };\n}\n","import {\n OpenGeniApiError,\n applyUrlRotation,\n type SessionCapabilities,\n type SessionEvent,\n type StreamUrlRotatedPayload,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\n// \"on-demand\" is the boxless-benign resting state: the lease is cold and NOTHING\n// asked to warm a box (no viewer/consent action, no files-tab warm). Under lazy\n// provisioning a chat-only turn never creates a box, so this is the correct calm\n// terminal state — NOT an error. It is distinct from \"cold\", which now means \"a\n// warm-up is genuinely in flight\" (a viewer attach was requested) and therefore\n// still polls with a patience deadline. A box appears on demand when the agent\n// first runs a sandbox tool; the workbench observes `sandbox.provision` and\n// renegotiates to pick up the freshly-warm box.\nexport type SessionCapabilitiesState =\n | \"idle\"\n | \"negotiating\"\n | \"ready\"\n | \"cold\"\n | \"on-demand\"\n | \"error\";\n\nexport type UseSessionCapabilitiesOptions = ClientOverride & {\n /**\n * Live event log to fold `stream.url.rotated` from (usually\n * `useSessionEvents().events`). When present the desktop socket stays fresh on\n * a box rollover without a round-trip; stale-epoch rotations are dropped.\n */\n events?: SessionEvent[] | undefined;\n /**\n * Whether to acquire a viewer holder for the desktop pixel plane. Requires the\n * un-redacted acknowledgment to have been recorded (else the attach 409s and\n * the hook surfaces the consent requirement). Default false: read-only\n * negotiation (no holder, no warm) — terminal/files/git work without it.\n */\n attachDesktop?: boolean | undefined;\n /**\n * Whether to acquire a viewer holder to warm the box for the REAL interactive\n * terminal (the ttyd pty-ws plane). Symmetric with `attachDesktop` and shares\n * the SAME viewer attach (one warm box serves both planes), but needs NO\n * un-redacted acknowledgment — a shell is interactive by nature, and the gate\n * is the scoped tunnel URL + stream token. Default false: the terminal stays on\n * the read-only Channel-A firehose until the user opens/focuses it. The attach\n * folds the minted `pty-ws` url+token into the `Terminal` cell.\n */\n attachTerminal?: boolean | undefined;\n /**\n * Whether to acquire a viewer holder to warm the box for a FILE WRITE — the\n * wake-on-edit INTENT (a first keystroke in the editor), NOT passive browsing.\n * Shares the SAME viewer attach as the desktop/terminal (one warm box, one\n * holder) and — like the terminal — needs NO un-redacted acknowledgment:\n * reading/writing files is the ordinary Channel-A control plane, not the pixel\n * plane. It folds NO live URL (files ride the stateless HTTP plane) — it only\n * refcounts liveness. Unlike desktop/terminal it warms even a COLD box: an edit\n * legitimately cold-creates (that IS the wake), so the write lands ~100ms warm\n * instead of paying the ~5s cold resume. Default false. IMPORTANT: merely\n * opening/reading the Files tab must NOT set this — browsing capture-served\n * trees/diffs needs no box, and warming one on a cold glance burns box-hours to\n * serve reads the capture already answers for free.\n */\n attachFiles?: boolean | undefined;\n /** Hold off negotiating (e.g. the workbench panel is collapsed). Default true. */\n enabled?: boolean | undefined;\n /** Poll cadence (ms) while the lease is cold/warming. Default 1500. */\n warmingPollMs?: number | undefined;\n /**\n * Give up waiting for `warm` after this long while polling (ms) and surface a\n * stalled error with a manual `renegotiate`. Default 30000. This is a UI\n * patience deadline, independent from the worker's sandbox warming timeout.\n * 0 disables the deadline.\n */\n warmingDeadlineMs?: number | undefined;\n};\n\nexport type UseSessionCapabilitiesResult = {\n /** The negotiated capability doc — the single source of UI truth. */\n capabilities: SessionCapabilities | null;\n state: SessionCapabilitiesState;\n error: Error | null;\n /**\n * 409 from the desktop attach: the un-redacted (or shared) plane needs explicit\n * acknowledgment before a viewer holder is granted. Drives the consent prompt.\n */\n acknowledgmentRequired: \"unredacted\" | \"shared\" | null;\n /** 429 from the desktop attach: the per-session viewer cap is reached. */\n viewerCapReached: boolean;\n /** The viewer holder id minted on a desktop attach (for detach/heartbeat). */\n viewerId: string | null;\n /** Force a re-negotiation (after acknowledging, a resolution change, etc.). */\n renegotiate: () => void;\n};\n\n/**\n * Whether a desktop attach (POST /viewers) is worth attempting for this cell.\n * The desktop is FEASIBLE — and thus worth warming — when it already has a live\n * transport, OR when the only thing missing is a warm box (a cold/un-provisioned\n * lease). The handshake never warms a box, so a feasible-but-cold cell reports\n * transport:null with a transient reason; the viewer attach is exactly what warms\n * it. A genuinely-unsupported desktop (backend/os/policy/headless) is never\n * attachable — attaching would 409/403/no-op without ever producing a stream.\n */\nfunction desktopAttachable(cell: SessionCapabilities[\"DesktopStream\"]): boolean {\n if (cell.transport !== null) return true;\n // transport === null: attach only when the reason is a transient cold state.\n return cell.reason === \"lease_cold\" || cell.reason === \"not_provisioned\" || cell.reason === null;\n}\n\n/**\n * Whether warming the box for the interactive terminal (pty-ws) is worth it.\n * The Terminal cell is ALWAYS feasible when the backend advertises a transport at\n * all (`sse-events` on a cold box, `pty-ws` once warm) — only a genuinely\n * terminal-less backend reports transport:null with a hard reason. The attach is\n * what flips `sse-events` → `pty-ws` by warming the box and minting the ttyd\n * tunnel URL, so we attach whenever the terminal is not hard-unavailable.\n */\nfunction terminalAttachable(cell: SessionCapabilities[\"Terminal\"]): boolean {\n if (cell.transport === null) {\n // No terminal at all unless the only blocker is a transient cold state.\n return (\n cell.reason === \"lease_cold\" || cell.reason === \"not_provisioned\" || cell.reason === null\n );\n }\n // Already pty-ws (warm) is fine to (re)attach; sse-events is the cold state the\n // attach upgrades. Either way it's attachable.\n return true;\n}\n\n/** Read `stream.url.rotated` payloads off the live event log, newest last. */\nfunction rotationsFrom(events: SessionEvent[]): StreamUrlRotatedPayload[] {\n const out: StreamUrlRotatedPayload[] = [];\n for (const event of events) {\n if (event.type === \"stream.url.rotated\" && event.payload && typeof event.payload === \"object\") {\n out.push(event.payload as StreamUrlRotatedPayload);\n }\n }\n return out;\n}\n\n/**\n * The capability-negotiation hook. Discovers what THIS session+backend+OS\n * supports (FileSystem/Terminal/Git always-ish; DesktopStream/Recording\n * sometimes), drives capability-gated rendering, and — when `attachDesktop` —\n * holds a viewer lease + heartbeats it so the box stays warm while watched.\n *\n * Degradation is a value, never a crash: an unsupported surface comes back\n * `available:false`/`transport:null` + a `reason`; the components render the\n * reason-aware empty state. 409 (consent) and 429 (viewer cap) are surfaced as\n * typed signals, not thrown.\n */\nexport function useSessionCapabilities(\n sessionId: string | null | undefined,\n options: UseSessionCapabilitiesOptions = {},\n): UseSessionCapabilitiesResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const attachDesktop = options.attachDesktop ?? false;\n const attachTerminal = options.attachTerminal ?? false;\n const attachFiles = options.attachFiles ?? false;\n const warmingPollMs = options.warmingPollMs ?? 1500;\n const warmingDeadlineMs = options.warmingDeadlineMs ?? 30_000;\n\n const [capabilities, setCapabilities] = useState<SessionCapabilities | null>(null);\n const [state, setState] = useState<SessionCapabilitiesState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [acknowledgmentRequired, setAcknowledgmentRequired] = useState<\n \"unredacted\" | \"shared\" | null\n >(null);\n const [viewerCapReached, setViewerCapReached] = useState(false);\n const [viewerId, setViewerId] = useState<string | null>(null);\n // Bumped to force a fresh negotiation cycle.\n const [nonce, setNonce] = useState(0);\n\n // The epoch the client has settled on — used to fence stale rotations folded\n // from the event log, and echoed on heartbeats.\n const epochRef = useRef(0);\n const viewerIdRef = useRef<string | null>(null);\n\n const renegotiate = useCallback(() => {\n setNonce((n) => n + 1);\n }, []);\n\n // ── Negotiation + viewer lifecycle ──────────────────────────────────────────\n useEffect(() => {\n if (!enabled || !sessionId) {\n setState(\"idle\");\n setCapabilities(null);\n return;\n }\n let cancelled = false;\n let pollTimer: ReturnType<typeof setTimeout> | null = null;\n let heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n let localViewerId: string | null = null;\n const startedAt = Date.now();\n\n const clearTimers = () => {\n if (pollTimer !== null) clearTimeout(pollTimer);\n if (heartbeatTimer !== null) clearInterval(heartbeatTimer);\n pollTimer = null;\n heartbeatTimer = null;\n };\n\n const settle = (caps: SessionCapabilities) => {\n if (cancelled) return;\n epochRef.current = caps.leaseEpoch;\n setCapabilities(caps);\n setError(null);\n };\n\n const startHeartbeat = (caps: SessionCapabilities) => {\n if (!localViewerId || heartbeatTimer !== null) return;\n const intervalMs =\n caps.viewerHeartbeatIntervalMs > 0 ? caps.viewerHeartbeatIntervalMs : 30_000;\n heartbeatTimer = setInterval(() => {\n if (cancelled || !localViewerId) return;\n void client\n .heartbeatViewer(workspaceId, sessionId, localViewerId, { leaseEpoch: epochRef.current })\n .then((res) => {\n // alive:false ⇒ the holder was reaped or the epoch moved under us;\n // re-negotiate to re-acquire against the new owner.\n if (!res.alive && !cancelled) {\n renegotiate();\n }\n })\n .catch((cause) => {\n if (cancelled) return;\n if (\n cause instanceof OpenGeniApiError &&\n (cause.status === 409 || cause.status === 410)\n ) {\n renegotiate();\n }\n });\n }, intervalMs);\n };\n\n const pollUntilWarm = () => {\n pollTimer = setTimeout(() => {\n if (cancelled) return;\n void client\n .getStreamCapabilities(workspaceId, sessionId)\n .then((caps) => {\n if (cancelled) return;\n settle(caps);\n if (caps.liveness === \"warm\" || caps.liveness === \"draining\") {\n setState(\"ready\");\n return;\n }\n if (warmingDeadlineMs > 0 && Date.now() - startedAt > warmingDeadlineMs) {\n setState(\"error\");\n setError(new Error(\"sandbox did not warm in time — retry to re-negotiate\"));\n return;\n }\n pollUntilWarm();\n })\n .catch((cause) => {\n if (!cancelled) {\n setState(\"error\");\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n });\n }, warmingPollMs);\n };\n\n void (async () => {\n setState(\"negotiating\");\n setAcknowledgmentRequired(null);\n setViewerCapReached(false);\n try {\n const caps = await client.getStreamCapabilities(workspaceId, sessionId);\n if (cancelled) return;\n settle(caps);\n\n // Optional viewer attach: acquire a viewer holder (warms a cold box). ONE\n // attach serves BOTH live planes — the desktop pixel stream AND the\n // interactive terminal (ttyd pty-ws) ride the same warm box and the same\n // holder; the response folds the minted address for each requested plane.\n // The consent gate (409) and the viewer cap (429) surface as typed signals\n // rather than throwing — the tabs degrade gracefully.\n //\n // KEY: the handshake (getStreamCapabilities) NEVER spins up a cold box, so\n // on a cold/warming lease the desktop cell comes back transport:null and\n // the terminal cell comes back `sse-events` (read-only firehose) with a\n // transient reason (`lease_cold`/`not_provisioned`). Gating the attach on\n // `transport` therefore dead-ends both surfaces (forever \"Starting…\"): they\n // never warm because they never attach, and never attach because they\n // aren't warm. We attach whenever a REQUESTED plane is FEASIBLE — transport\n // already live OR cold-but-feasible — and let POST /viewers warm the box and\n // mint the URLs. Only a genuinely-unsupported reason suppresses the attach.\n const wantDesktopAttach = attachDesktop && desktopAttachable(caps.DesktopStream);\n const wantTerminalAttach = attachTerminal && terminalAttachable(caps.Terminal);\n // The Files attach warms the box for a file WRITE (wake-on-edit intent). It\n // folds no live URL (files are stateless HTTP) — the attach is purely a\n // liveness refcount. Unlike the previous \"keep the box warm while the Files\n // tab is on screen\" wiring, this fires on genuine EDIT intent only, so it\n // legitimately cold-CREATES: an edit is the wake, and the caller (the dock)\n // never sets it for passive browsing. Gate solely on the FileSystem cap\n // being advertised; liveness (cold included) does not suppress it — POST\n // /viewers warms a cold box exactly as it does for a desktop/terminal engage.\n const wantFilesAttach = attachFiles && caps.FileSystem.available;\n if (wantDesktopAttach || wantTerminalAttach || wantFilesAttach) {\n try {\n // Declare WHICH plane we're attaching for. `desktop:true` opts into the\n // un-redacted pixel plane (which carries the consent gate); a\n // terminal-only attach (`desktop:false`) warms the box + mints the\n // pty-ws terminal cell WITHOUT tripping the desktop consent 409.\n const holder = await client.attachViewer(workspaceId, sessionId, {\n desktop: wantDesktopAttach,\n });\n if (cancelled) return;\n localViewerId = holder.viewerId;\n viewerIdRef.current = holder.viewerId;\n setViewerId(holder.viewerId);\n epochRef.current = holder.leaseEpoch;\n // Fold the freshly-minted live address(es) into the doc the components\n // read. Desktop fields fold only when a desktop attach was wanted;\n // terminal fields fold the minted ttyd pty-ws url+token when present.\n setCapabilities((prev) =>\n prev\n ? {\n ...prev,\n liveness: holder.liveness,\n leaseEpoch: holder.leaseEpoch,\n viewerHeartbeatIntervalMs: holder.viewerHeartbeatIntervalMs,\n DesktopStream: wantDesktopAttach\n ? {\n ...prev.DesktopStream,\n transport: holder.transport ?? prev.DesktopStream.transport,\n client: holder.client ?? prev.DesktopStream.client,\n url: holder.dataPlaneUrl ?? prev.DesktopStream.url,\n token: holder.streamToken ?? prev.DesktopStream.token,\n expiresAt: holder.streamExpiresAt ?? prev.DesktopStream.expiresAt,\n resolution: holder.resolution ?? prev.DesktopStream.resolution,\n }\n : prev.DesktopStream,\n Terminal:\n holder.terminalUrl && holder.terminalTransport\n ? {\n ...prev.Terminal,\n transport: holder.terminalTransport,\n url: holder.terminalUrl,\n token: holder.terminalToken ?? prev.Terminal.token,\n // A live pty-ws means the box is pty-capable for real.\n ptyCapable: true,\n reason: null,\n }\n : prev.Terminal,\n }\n : prev,\n );\n } catch (cause) {\n if (cancelled) return;\n if (cause instanceof OpenGeniApiError) {\n if (cause.status === 409) {\n // The un-redacted/shared consent gate is a DESKTOP requirement. A\n // terminal-only warm attach needs no consent, so a 409 there is not\n // a consent prompt — the terminal just stays on the read-only\n // firehose. Only raise the consent requirement when the desktop was\n // the (or a) reason we attached.\n if (wantDesktopAttach) {\n setAcknowledgmentRequired(\n cause.message.includes(\"shared_acknowledgment\") ? \"shared\" : \"unredacted\",\n );\n }\n } else if (cause.status === 429) {\n setViewerCapReached(true);\n } else if (cause.status === 403) {\n setState(\"error\");\n setError(cause);\n return;\n }\n // 409/429 are recoverable: structured surfaces still negotiated;\n // keep going to set ready/cold below.\n } else {\n throw cause;\n }\n }\n }\n\n // Whether ANYTHING asked to warm a box this negotiation. Only then is a\n // cold lease \"warming in flight\" — worth polling, and worth surfacing a\n // stall as an error. With no warm-up requested a cold lease is the benign\n // boxless resting state (below), never an error.\n const warmUpRequested = wantDesktopAttach || wantTerminalAttach || wantFilesAttach;\n if (caps.liveness === \"warm\" || caps.liveness === \"draining\" || localViewerId) {\n setState(\"ready\");\n startHeartbeat(caps);\n } else if (warmUpRequested) {\n // A warm-up is genuinely in flight (a viewer attach was requested) but the\n // box isn't warm yet — poll until it warms, with the patience deadline so a\n // real stall surfaces as an error.\n setState(\"cold\");\n pollUntilWarm();\n } else {\n // Boxless and nobody asked for a box: rest in the benign on-demand state.\n // NO poll, NO deadline, NO false \"sandbox offline\". The box is created on\n // demand when the agent first runs a sandbox tool; the workbench watches\n // for `sandbox.provision` and renegotiates to pick the warm box back up.\n setState(\"on-demand\");\n }\n } catch (cause) {\n if (cancelled) return;\n if (cause instanceof OpenGeniApiError && cause.status === 403) {\n setState(\"error\");\n setError(new Error(\"not permitted to view this session's sandbox\"));\n return;\n }\n setState(\"error\");\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n })();\n\n return () => {\n cancelled = true;\n clearTimers();\n // Fire-and-forget detach (idempotent delete-my-row). Capture the id so a\n // re-render/unmount race still releases the right holder.\n const releaseId = localViewerId ?? viewerIdRef.current;\n if (releaseId) {\n void client.detachViewer(workspaceId, sessionId, releaseId).catch(() => {});\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n client,\n workspaceId,\n sessionId,\n enabled,\n attachDesktop,\n attachTerminal,\n attachFiles,\n warmingPollMs,\n warmingDeadlineMs,\n nonce,\n ]);\n\n // ── Fold stream.url.rotated from the live event log (no round trip) ──────────\n const events = options.events;\n useEffect(() => {\n if (!events || events.length === 0) return;\n setCapabilities((prev) => {\n if (!prev || !prev.DesktopStream.url) return prev;\n let next = prev.DesktopStream;\n let changed = false;\n for (const rotation of rotationsFrom(events)) {\n // Only this viewer's rotations (others' are filtered by viewerId when set).\n if (rotation.viewerId && viewerIdRef.current && rotation.viewerId !== viewerIdRef.current) {\n continue;\n }\n const applied = applyUrlRotation(next, rotation, epochRef.current);\n if (applied) {\n next = { ...next, url: applied.url, token: applied.token, expiresAt: applied.expiresAt };\n epochRef.current = Math.max(epochRef.current, rotation.leaseEpoch);\n changed = true;\n }\n }\n return changed ? { ...prev, DesktopStream: next, leaseEpoch: epochRef.current } : prev;\n });\n }, [events]);\n\n return {\n capabilities,\n state,\n error,\n acknowledgmentRequired,\n viewerCapReached,\n viewerId,\n renegotiate,\n };\n}\n","import {\n desktopSocketUrl,\n nextDesktopState,\n type DesktopConnectionState,\n type DesktopRfbFactory,\n type DesktopRfbLike,\n type DesktopStreamCapability,\n} from \"@opengeni/sdk\";\nimport { type RefObject, useEffect, useRef, useState } from \"react\";\nimport { type DesktopWebSocketFactory, useRelayFrameStream } from \"./use-relay-frame-stream\";\n\nexport type UseDesktopStreamOptions = {\n /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */\n capability: DesktopStreamCapability | null;\n /** The mount target. RFB (or the frame canvas) attaches here on connect. */\n containerRef: RefObject<HTMLDivElement | null>;\n /** Read-only by default (v1 ruling H). interactive only when cap.mode allows. */\n interactive?: boolean | undefined;\n scaleViewport?: boolean | undefined;\n /** Custom RFB factory (tests / a WebRTC swap). Defaults to a lazy @novnc/novnc. */\n rfbFactory?: DesktopRfbFactory | undefined;\n /** Custom socket factory for the `relay-frames` transport (tests). Defaults to\n * `new WebSocket(url)`. Mirrors `rfbFactory` for the frame renderer. */\n webSocketFactory?: DesktopWebSocketFactory | undefined;\n};\n\nexport type UseDesktopStreamResult = {\n state: DesktopConnectionState;\n error: Error | null;\n /** Manual reconnect (e.g. after a securityfailure once a fresh URL arrives). */\n reconnect: () => void;\n};\n\n/** Lazy-load @novnc/novnc's RFB as the default factory. Imported inside the\n * connect effect so SSR / non-desktop bundles never pull the DOM-only lib.\n * @novnc/novnc ships no types and a single `export default class RFB`. The\n * specifier is STATIC (`import(\"@novnc/novnc\")`) so Vite can pre-bundle and\n * resolve it — a runtime-string indirection with `@vite-ignore` (the previous\n * approach) hands the browser a bare specifier and throws\n * \"Failed to resolve module specifier '@novnc/novnc'\". The dynamic form keeps\n * it out of the SSR / non-desktop critical path while staying resolvable. */\nasync function defaultRfbFactory(): Promise<DesktopRfbFactory> {\n const mod = (await import(\"@novnc/novnc\")) as unknown as {\n default: new (\n t: HTMLElement,\n u: string,\n o: { credentials?: { password?: string | undefined } | undefined },\n ) => DesktopRfbLike;\n };\n const RFB = mod.default;\n return (target, url, opts) => new RFB(target, url, opts);\n}\n\n/**\n * Drive the noVNC RFB lifecycle from a `DesktopStreamCapability`, using the\n * SDK's `desktop.ts` reducer + `desktopSocketUrl`. SSR-safe: the RFB import and\n * the DOM attach happen inside `useEffect`, so a server render is a no-op and\n * the component shows its placeholder until hydration.\n *\n * Read-only is enforced at three layers: `capability.mode` (server) →\n * `interactive` prop → `RFB.viewOnly`. v1 always resolves to read-only. On a\n * capability `url` change (a rotation), the old RFB disconnects and a fresh one\n * connects to the new URL — a brief \"desktop blink\", acceptable on rollover.\n *\n * Transport dispatch: a Modal box negotiates `transport: \"vnc-ws\"` and drives the\n * noVNC RFB below. A SELF-HOSTED machine negotiates `transport: \"relay-frames\"`\n * (PNG-per-frame over the relay, view-only) — that path is delegated to\n * `useRelayFrameStream`, which paints a `<canvas>`. Both hooks are ALWAYS called\n * (rules of hooks); each is dormant for the other's transport, and we return the\n * result of whichever owns the surface. The public interface is identical either\n * way, so `DesktopViewer` is transport-agnostic.\n */\nexport function useDesktopStream(options: UseDesktopStreamOptions): UseDesktopStreamResult {\n const { capability, containerRef, interactive, scaleViewport, rfbFactory, webSocketFactory } =\n options;\n\n // The self-hosted PNG-frame path. Always invoked (rules of hooks); dormant\n // unless `transport === \"relay-frames\"`, in which case it owns the surface.\n const frameStream = useRelayFrameStream({\n capability,\n containerRef,\n ...(webSocketFactory ? { webSocketFactory } : {}),\n });\n const [state, setState] = useState<DesktopConnectionState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [nonce, setNonce] = useState(0);\n const stateRef = useRef<DesktopConnectionState>(\"idle\");\n const setBoth = (next: DesktopConnectionState) => {\n stateRef.current = next;\n setState(next);\n };\n\n const reconnect = () => setNonce((n) => n + 1);\n\n const url = capability?.url ?? null;\n // The credential is keyed into the connect effect so a token rotation (new\n // password) reconnects, but NOT folded into the whole-`capability` identity —\n // a benign re-negotiation that re-mints the same cell must not churn the socket.\n const token = capability?.token ?? null;\n const transport = capability?.transport ?? null;\n const mode = capability?.mode ?? \"read-only\";\n\n // The live RFB handle. Holding it in a ref lets us flip view-only (take\n // control / return control) and re-scale on the OPEN connection instead of\n // tearing the socket down — the old behaviour reconnected on every\n // `interactive` change, which read as a constant \"refresh\" and (combined with\n // the canvas churn) bounced control back to watch.\n const rfbRef = useRef<DesktopRfbLike | null>(null);\n // Latest input/scale/factory the connect effect reads via refs so they are NOT\n // connect-effect dependencies: changing them must update the live RFB in place,\n // never reconnect it.\n const interactiveRef = useRef(interactive);\n const scaleViewportRef = useRef(scaleViewport);\n const modeRef = useRef(mode);\n const rfbFactoryRef = useRef(rfbFactory);\n interactiveRef.current = interactive;\n scaleViewportRef.current = scaleViewport;\n modeRef.current = mode;\n rfbFactoryRef.current = rfbFactory;\n\n // read-only is forced when the server says so OR the caller didn't opt in.\n const viewOnlyFor = (m: string, want: boolean | undefined) => m === \"read-only\" || !want;\n\n useEffect(() => {\n // SSR / no DOM / no usable transport: stay idle and show the placeholder.\n if (typeof window === \"undefined\") return;\n if (transport !== \"vnc-ws\" || !url) {\n setBoth(\"idle\");\n return;\n }\n const container = containerRef.current;\n if (!container) {\n // The mount target isn't in the DOM yet (e.g. the tab is still hidden).\n // Stay idle (not a stale negotiating/connecting) so a re-attach nudge —\n // fired by the viewer on becoming visible / on mount — can re-run this\n // effect once the container exists. Without this the surface can stick\n // forever on the idle scrim and never open a socket.\n setBoth(\"idle\");\n return;\n }\n\n let rfb: DesktopRfbLike | null = null;\n let disposed = false;\n setError(null);\n setBoth(\"negotiating\");\n\n const onConnect = () => {\n if (!disposed) setBoth(nextDesktopState(stateRef.current, { type: \"connected\" }));\n };\n const onDisconnect = () => {\n if (!disposed) setBoth(nextDesktopState(stateRef.current, { type: \"disconnected\" }));\n };\n const onSecurityFailure = () => {\n if (disposed) return;\n setError(new Error(\"desktop authentication failed (token expired or revoked)\"));\n setBoth(nextDesktopState(stateRef.current, { type: \"fail\" }));\n };\n\n void (async () => {\n try {\n const factory = rfbFactoryRef.current ?? (await defaultRfbFactory());\n if (disposed) return;\n const socketUrl = desktopSocketUrl({ url });\n setBoth(nextDesktopState(stateRef.current, { type: \"negotiated\" }));\n rfb = factory(container, socketUrl, {\n credentials: token ? { password: token } : undefined,\n });\n rfb.viewOnly = viewOnlyFor(modeRef.current, interactiveRef.current);\n // Fit-to-panel: SCALE the 1280x800 framebuffer down to the container\n // (aspect-preserved) and never 1:1-clip. `clipViewport=false` is pinned\n // explicitly — noVNC forces it off while scaling, but a fresh RFB on a\n // url rotation could otherwise start from a stale clip and read as\n // \"zoomed in\". Order matters: clip off, then scale on.\n rfb.clipViewport = false;\n rfb.scaleViewport = scaleViewportRef.current ?? true;\n rfb.addEventListener(\"connect\", onConnect);\n rfb.addEventListener(\"disconnect\", onDisconnect);\n rfb.addEventListener(\"securityfailure\", onSecurityFailure);\n rfbRef.current = rfb;\n } catch (cause) {\n if (!disposed) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setBoth(\"error\");\n }\n }\n })();\n\n return () => {\n disposed = true;\n if (rfbRef.current === rfb) rfbRef.current = null;\n if (rfb) {\n rfb.removeEventListener?.(\"connect\", onConnect);\n rfb.removeEventListener?.(\"disconnect\", onDisconnect);\n rfb.removeEventListener?.(\"securityfailure\", onSecurityFailure);\n try {\n rfb.disconnect();\n } catch {\n // ignore teardown errors\n }\n }\n };\n // ONLY a real transport change reconnects: a fresh url (rotation), a new\n // credential, the transport flipping, or an explicit manual reconnect\n // (`nonce`). `interactive`/`scaleViewport`/`mode`/`rfbFactory` are read via\n // refs and applied live below — they must never re-open the socket.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, token, transport, nonce]);\n\n // Apply take-control / return-control to the OPEN connection in place. noVNC\n // honours `viewOnly` live, so flipping it neither blinks the surface nor drops\n // the framebuffer — the cure for the take-control \"refresh + auto-release\" loop.\n useEffect(() => {\n const rfb = rfbRef.current;\n if (rfb) rfb.viewOnly = viewOnlyFor(mode, interactive);\n // viewOnlyFor is pure; re-run only when the inputs change.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [interactive, mode, state]);\n\n // Re-scale the live RFB in place (no reconnect) when the scale preference flips\n // OR the connection state advances (e.g. the first framebuffer paints after a\n // take-control flip / a re-attach). Re-asserting clip-off + scale-on here is the\n // belt-and-suspenders against a \"zoomed\" surface: it re-fits the canvas to the\n // panel on every meaningful transition, so a transient mis-measure at connect\n // time can never stick.\n useEffect(() => {\n const rfb = rfbRef.current;\n if (rfb) {\n rfb.clipViewport = false;\n rfb.scaleViewport = scaleViewport ?? true;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scaleViewport, state]);\n\n // Delegate to whichever transport owns the surface. For `relay-frames` the\n // noVNC effect above is dormant (it bailed to idle) and the frame renderer\n // drives; for `vnc-ws` (and everything else) the noVNC path drives while the\n // frame renderer stays idle. Same public shape either way.\n if (transport === \"relay-frames\") return frameStream;\n return { state, error, reconnect };\n}\n","// Minimal HAND-MIRROR of the relay stream wire messages the desktop frame client\n// needs (`StreamOpen` encode; `StreamOpenAck` + `StreamFrame` decode). It exists\n// because the publish-closure guard (scripts/publish-closure-guard.ts) forbids\n// `@opengeni/react` from depending on `@opengeni/agent-proto` — the published SDK\n// closure may only reach `@opengeni/sdk` among `@opengeni/*` packages. So, exactly\n// as the guard prescribes (\"hand-mirror it\"), we re-encode just these three\n// messages against the third-party `@bufbuild/protobuf/wire` runtime (the same\n// runtime `@opengeni/agent-proto` generates against), byte-compatible with the\n// generated code. Field numbers copied verbatim from\n// `packages/agent-proto/src/gen/opengeni_agent.ts`:\n// StreamChannel: channelId=1, workspaceId=2, agentId=3, kind=4(int32), port=5(uint32)\n// StreamOpen: channel=1(msg), token=2, role=3(int32), resumeFromSeq=4(uint64, omitted when \"0\")\n// StreamOpenAck: accepted=1(bool), error=2(AgentError msg), resumeFromSeq=3\n// AgentError: code=1, message=2, retryable=3, detail=4 (we read only message)\n// StreamFrame: channelId=1, seq=2, data=3(bytes), producedAtMs=4 (we read only data)\nimport { BinaryReader, BinaryWriter } from \"@bufbuild/protobuf/wire\";\n\n/** `StreamKind.STREAM_KIND_DESKTOP` (agent-proto enum value). */\nexport const STREAM_KIND_DESKTOP = 2;\n/** `StreamRole.STREAM_ROLE_CLIENT` (agent-proto enum value). */\nexport const STREAM_ROLE_CLIENT = 2;\n\nexport interface RelayChannel {\n channelId: string;\n workspaceId: string;\n agentId: string;\n kind: number;\n port: number;\n}\n\nexport interface RelayStreamOpen {\n channel: RelayChannel;\n token: string;\n role: number;\n resumeFromSeq: string;\n}\n\nfunction encodeChannel(message: RelayChannel, writer: BinaryWriter): BinaryWriter {\n if (message.channelId !== \"\") writer.uint32(10).string(message.channelId);\n if (message.workspaceId !== \"\") writer.uint32(18).string(message.workspaceId);\n if (message.agentId !== \"\") writer.uint32(26).string(message.agentId);\n if (message.kind !== 0) writer.uint32(32).int32(message.kind);\n if (message.port !== 0) writer.uint32(40).uint32(message.port);\n return writer;\n}\n\n/** Encode a `StreamOpen`, byte-compatible with `StreamOpen.encode(...).finish()`. */\nexport function encodeStreamOpen(message: RelayStreamOpen): Uint8Array {\n const writer = new BinaryWriter();\n encodeChannel(message.channel, writer.uint32(10).fork()).join();\n if (message.token !== \"\") writer.uint32(18).string(message.token);\n if (message.role !== 0) writer.uint32(24).int32(message.role);\n if (message.resumeFromSeq !== \"0\") writer.uint32(32).uint64(message.resumeFromSeq);\n return writer.finish();\n}\n\n/** The only `AgentError` field we surface from a rejected ack. */\nfunction decodeAgentErrorMessage(reader: BinaryReader, length: number): { message?: string } {\n const end = reader.pos + length;\n let message: string | undefined;\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 2 && tag === 18) {\n message = reader.string();\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return message !== undefined ? { message } : {};\n}\n\n/** Decode a `StreamOpenAck` (we need `accepted` + the error message). */\nexport function decodeStreamOpenAck(bytes: Uint8Array): {\n accepted: boolean;\n error?: { message?: string };\n} {\n const reader = new BinaryReader(bytes);\n const end = reader.len;\n let accepted = false;\n let error: { message?: string } | undefined;\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 1 && tag === 8) {\n accepted = reader.bool();\n continue;\n }\n if (tag >>> 3 === 2 && tag === 18) {\n error = decodeAgentErrorMessage(reader, reader.uint32());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return error !== undefined ? { accepted, error } : { accepted };\n}\n\n/** Decode a `StreamFrame`, extracting only the `data` (framebuffer PNG) bytes. */\nexport function decodeStreamFrame(bytes: Uint8Array): { data: Uint8Array } {\n const reader = new BinaryReader(bytes);\n const end = reader.len;\n let data = new Uint8Array(0);\n while (reader.pos < end) {\n const tag = reader.uint32();\n if (tag >>> 3 === 3 && tag === 26) {\n // Copy into a fresh ArrayBuffer-backed view: BinaryReader.bytes() returns\n // `Uint8Array<ArrayBufferLike>` (a view into the message buffer), which both\n // narrows the type to `Uint8Array<ArrayBuffer>` and isolates just this frame.\n data = new Uint8Array(reader.bytes());\n continue;\n }\n if ((tag & 7) === 4 || tag === 0) break;\n reader.skip(tag & 7);\n }\n return { data };\n}\n","import {\n decodeStreamFrame,\n decodeStreamOpenAck,\n encodeStreamOpen,\n STREAM_KIND_DESKTOP,\n STREAM_ROLE_CLIENT,\n} from \"../lib/relay-wire\";\nimport type { DesktopConnectionState, DesktopStreamCapability } from \"@opengeni/sdk\";\nimport { type RefObject, useEffect, useRef, useState } from \"react\";\n\n/**\n * The minimal WebSocket surface the frame renderer drives. Lets tests (and a\n * future transport swap) inject a fake without a live socket — the exact\n * analogue of `DesktopRfbFactory` for the noVNC path. Structurally a subset of\n * the browser `WebSocket`.\n */\nexport interface DesktopWebSocketLike {\n binaryType: string;\n send(data: ArrayBuffer): void;\n close(): void;\n addEventListener(\n type: \"open\" | \"message\" | \"error\" | \"close\",\n listener: (ev: { data?: unknown } & Record<string, unknown>) => void,\n ): void;\n removeEventListener(\n type: \"open\" | \"message\" | \"error\" | \"close\",\n listener: (ev: { data?: unknown } & Record<string, unknown>) => void,\n ): void;\n}\n\nexport type DesktopWebSocketFactory = (url: string) => DesktopWebSocketLike;\n\nexport type UseRelayFrameStreamOptions = {\n /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */\n capability: DesktopStreamCapability | null;\n /** The mount target. A `<canvas>` is appended here on connect. */\n containerRef: RefObject<HTMLDivElement | null>;\n /** Custom socket factory (tests / a transport swap). Defaults to `new WebSocket(url)`. */\n webSocketFactory?: DesktopWebSocketFactory | undefined;\n};\n\nexport type UseRelayFrameStreamResult = {\n state: DesktopConnectionState;\n error: Error | null;\n /** Tear down + reopen the socket (e.g. after a drop, once a fresh url arrives). */\n reconnect: () => void;\n};\n\n// Relay datagram tags: byte[0] of every binary message. Mirrors the proven wire\n// protocol in `apps/api/scripts/diagnose-mac-desktop-stream.ts`.\nconst TAG_OPEN = 1;\nconst TAG_OPENACK = 2;\nconst TAG_FRAME = 3;\n\n/** Build a relay datagram: a fresh Uint8Array of `body.length + 1` with the tag\n * at [0] and the protobuf body copied at offset 1 (so `.buffer` is exact). */\nfunction datagram(tag: number, body: Uint8Array): Uint8Array {\n const out = new Uint8Array(body.length + 1);\n out[0] = tag;\n out.set(body, 1);\n return out;\n}\n\nfunction defaultWebSocketFactory(url: string): DesktopWebSocketLike {\n // The browser `WebSocket` is structurally a superset of `DesktopWebSocketLike`\n // (its event maps are stricter); cast so the seam stays loosely typed for fakes.\n return new WebSocket(url) as unknown as DesktopWebSocketLike;\n}\n\n/**\n * VIEW-ONLY PNG-frame renderer for a SELF-HOSTED desktop stream — the relay\n * transport (`transport: \"relay-frames\"`, `client: \"frames\"`). The self-hosted\n * agent produces one PNG per frame as a protobuf datagram over the relay; there\n * is no RFB/noVNC here. This hook opens the relay DESKTOP channel as a CLIENT\n * (mirroring the proven diagnostic wire protocol), decodes each PNG onto a\n * `<canvas>` mounted into `containerRef`, and drives the connection state\n * machine: idle → connecting (ws opening) → connected (first painted frame) →\n * error (ws error/close/ack rejection).\n *\n * It is DORMANT for any other transport (or no url): it stays idle and touches\n * nothing, so the noVNC path owns the surface. SSR-safe: the socket + DOM attach\n * live inside `useEffect`.\n *\n * Backpressure (critical — frames are ~1.8MB at ~10fps): at most one frame is\n * decoded at a time; a frame arriving mid-decode replaces the pending one\n * (latest-wins), so a slow decode can never build an unbounded queue.\n */\nexport function useRelayFrameStream(\n options: UseRelayFrameStreamOptions,\n): UseRelayFrameStreamResult {\n const { capability, containerRef, webSocketFactory } = options;\n const [state, setState] = useState<DesktopConnectionState>(\"idle\");\n const [error, setError] = useState<Error | null>(null);\n const [nonce, setNonce] = useState(0);\n const stateRef = useRef<DesktopConnectionState>(\"idle\");\n const setBoth = (next: DesktopConnectionState) => {\n stateRef.current = next;\n setState(next);\n };\n\n const reconnect = () => setNonce((n) => n + 1);\n\n const transport = capability?.transport ?? null;\n const url = capability?.url ?? null;\n const token = capability?.token ?? null;\n\n // The factory is read via a ref so swapping it never re-opens the socket (it is\n // not a connect-effect dependency), symmetric with the noVNC `rfbFactory`.\n const factoryRef = useRef(webSocketFactory);\n factoryRef.current = webSocketFactory;\n\n useEffect(() => {\n // SSR / no DOM: stay idle and show the placeholder.\n if (typeof window === \"undefined\") return;\n // This hook OWNS the surface ONLY for the frame transport; anything else (or\n // no live url) → dormant idle so the noVNC path can drive.\n if (transport !== \"relay-frames\" || !url) {\n setBoth(\"idle\");\n return;\n }\n const container = containerRef.current;\n if (!container) {\n // Mount target not in the DOM yet (tab hidden) — stay idle so a re-attach\n // nudge can re-run this effect once the container exists.\n setBoth(\"idle\");\n return;\n }\n\n // Parse the 4 relay query params the channel is keyed on.\n let channel: {\n channelId: string;\n workspaceId: string;\n agentId: string;\n kind: number;\n port: number;\n };\n try {\n const u = new URL(url);\n channel = {\n channelId: u.searchParams.get(\"channel\") ?? \"\",\n workspaceId: u.searchParams.get(\"ws\") ?? \"\",\n agentId: u.searchParams.get(\"agent\") ?? \"\",\n kind: STREAM_KIND_DESKTOP,\n port: Number(u.searchParams.get(\"port\") ?? \"0\"),\n };\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setBoth(\"error\");\n return;\n }\n\n setError(null);\n setBoth(\"connecting\");\n\n // Canvas mount — mirror the noVNC surface conventions: absolute-fill the\n // panel and CONTAIN the framebuffer (aspect-preserved, centered, letterboxed)\n // — never distorted, never overflowing. `max-*: 100%` + `margin: auto` +\n // intrinsic size gives fit-to-panel without a resize observer.\n const canvas = document.createElement(\"canvas\");\n canvas.setAttribute(\"data-opengeni-desktop-frames\", \"\");\n const style = canvas.style;\n style.position = \"absolute\";\n style.top = \"0\";\n style.left = \"0\";\n style.right = \"0\";\n style.bottom = \"0\";\n style.margin = \"auto\";\n style.maxWidth = \"100%\";\n style.maxHeight = \"100%\";\n style.width = \"auto\";\n style.height = \"auto\";\n style.display = \"block\";\n style.imageRendering = \"auto\";\n container.appendChild(canvas);\n const ctx = canvas.getContext(\"2d\");\n\n let disposed = false;\n let acked = false;\n // Backpressure: decode at most ONE frame at a time; a frame arriving mid-\n // decode replaces `pending` (keep only the LATEST) — never a queue.\n let decoding = false;\n let pending: Uint8Array | null = null;\n\n const drainLatest = async () => {\n if (decoding) return;\n decoding = true;\n try {\n while (pending) {\n if (disposed) break;\n const data = pending;\n pending = null;\n let bmp: ImageBitmap;\n try {\n // Copy the exact frame bytes into a fresh ArrayBuffer-backed view:\n // ts-proto's `bytes()` hands back a subarray VIEW into the larger\n // message buffer, so slicing isolates just this PNG (and satisfies the\n // `BlobPart` typing, which rejects the generic `ArrayBufferLike`).\n bmp = await createImageBitmap(new Blob([new Uint8Array(data)], { type: \"image/png\" }));\n } catch {\n // A corrupt/partial frame is skipped; latest-wins keeps us live.\n continue;\n }\n if (disposed) {\n bmp.close();\n break;\n }\n // Size the backing store to the frame's natural WxH on the first frame\n // (or when the resolution changes); CSS then scales the element to fit.\n if (canvas.width !== bmp.width || canvas.height !== bmp.height) {\n canvas.width = bmp.width;\n canvas.height = bmp.height;\n }\n ctx?.drawImage(bmp, 0, 0, canvas.width, canvas.height);\n bmp.close();\n // First painted frame → connected.\n if (!disposed && stateRef.current !== \"connected\") setBoth(\"connected\");\n }\n } finally {\n decoding = false;\n }\n };\n\n let ws: DesktopWebSocketLike;\n try {\n ws = (factoryRef.current ?? defaultWebSocketFactory)(url);\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n setBoth(\"error\");\n canvas.remove();\n return;\n }\n ws.binaryType = \"arraybuffer\";\n\n const onOpen = () => {\n if (disposed) return;\n const body = encodeStreamOpen({\n channel,\n token: token ?? \"\",\n role: STREAM_ROLE_CLIENT,\n resumeFromSeq: \"0\",\n });\n try {\n ws.send(datagram(TAG_OPEN, body).buffer as ArrayBuffer);\n } catch {\n // Socket already closing; the close/error handler surfaces it.\n }\n };\n\n const onMessage = (ev: { data?: unknown }) => {\n if (disposed) return;\n const data = ev.data;\n if (!(data instanceof ArrayBuffer)) return;\n const buf = new Uint8Array(data);\n if (buf.length === 0) return;\n const tag = buf[0];\n const rest = buf.subarray(1);\n if (tag === TAG_OPENACK) {\n let ack: ReturnType<typeof decodeStreamOpenAck>;\n try {\n ack = decodeStreamOpenAck(rest);\n } catch {\n return;\n }\n if (!ack.accepted) {\n setError(\n new Error(\n ack.error?.message\n ? `desktop stream rejected: ${ack.error.message}`\n : \"desktop stream rejected by the relay\",\n ),\n );\n setBoth(\"error\");\n try {\n ws.close();\n } catch {\n // already closed\n }\n return;\n }\n // Accepted — stay \"connecting\" until the first frame paints.\n acked = true;\n } else if (tag === TAG_FRAME) {\n let fr: ReturnType<typeof decodeStreamFrame>;\n try {\n fr = decodeStreamFrame(rest);\n } catch {\n return;\n }\n if (fr.data && fr.data.length > 0) {\n pending = fr.data; // latest-wins backpressure\n void drainLatest();\n }\n }\n };\n\n const onError = () => {\n if (disposed) return;\n setError((prev) => prev ?? new Error(\"desktop stream connection error\"));\n setBoth(\"error\");\n };\n\n const onClose = () => {\n if (disposed) return;\n setError(\n (prev) =>\n prev ??\n new Error(acked ? \"desktop stream closed\" : \"desktop stream closed before it opened\"),\n );\n setBoth(\"error\");\n };\n\n ws.addEventListener(\"open\", onOpen);\n ws.addEventListener(\"message\", onMessage);\n ws.addEventListener(\"error\", onError);\n ws.addEventListener(\"close\", onClose);\n\n return () => {\n disposed = true;\n pending = null;\n ws.removeEventListener(\"open\", onOpen);\n ws.removeEventListener(\"message\", onMessage);\n ws.removeEventListener(\"error\", onError);\n ws.removeEventListener(\"close\", onClose);\n try {\n ws.close();\n } catch {\n // ignore teardown errors\n }\n canvas.remove();\n };\n // ONLY a real transport change reopens: a fresh url (rotation), a new token,\n // the transport flipping, or a manual reconnect (`nonce`). The factory is read\n // via a ref and must never re-open the socket.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url, token, transport, nonce]);\n\n return { state, error, reconnect };\n}\n","import {\n TTYD_SUBPROTOCOL,\n TerminalCapability,\n terminalSocketUrl,\n ttydAuthFrame,\n ttydInputFrame,\n ttydResizeFrame,\n TtydServerCommand,\n} from \"@opengeni/sdk\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\n\n/** The ttyd connection lifecycle as surfaced to the component. */\nexport type TerminalStreamStatus = \"connecting\" | \"open\" | \"closed\" | \"error\";\n\nexport type UseTerminalStreamOptions = {\n /** The Terminal cell of the negotiated capabilities (`capabilities.Terminal`).\n * The stream connects ONLY when `transport === \"pty-ws\"` and `url` is set; on a\n * cold box (`transport === \"sse-events\"` / no url) it stays idle and the caller\n * falls back to the Channel-A read-only firehose. */\n capability: Pick<TerminalCapability, \"transport\" | \"url\" | \"token\"> | null;\n /** Called for each OUTPUT payload from ttyd (write verbatim into xterm). */\n onOutput?: ((data: string) => void) | undefined;\n /** Called when ttyd sends a SET_WINDOW_TITLE frame. */\n onTitle?: ((title: string) => void) | undefined;\n /** Initial PTY size to seed the ttyd auth frame + first resize. */\n initialCols?: number | undefined;\n initialRows?: number | undefined;\n};\n\nexport type UseTerminalStreamResult = {\n /** True once the ttyd socket is open (and the auth frame has been sent). */\n connected: boolean;\n status: TerminalStreamStatus;\n /** Pipe a keystroke/paste to the PTY stdin. No-op until the socket is open. */\n write: (data: string) => void;\n /** Tell ttyd the PTY window changed size (on xterm fit/resize). */\n resize: (cols: number, rows: number) => void;\n /** Tear the socket down (the effect also tears down on unmount / url change). */\n disconnect: () => void;\n};\n\n/** Decode an inbound ttyd frame's payload (everything after the 1-char command).\n * ttyd may send either a text frame (string) or a binary frame (ArrayBuffer);\n * for binary we slice off the first byte (the command) and utf-8 decode the rest. */\nfunction decodeFrame(data: string | ArrayBuffer): { command: string; payload: string } {\n if (typeof data === \"string\") {\n return { command: data.charAt(0), payload: data.slice(1) };\n }\n const bytes = new Uint8Array(data);\n const command = bytes.length > 0 ? String.fromCharCode(bytes[0]!) : \"\";\n const payload = bytes.length > 1 ? new TextDecoder().decode(bytes.subarray(1)) : \"\";\n return { command, payload };\n}\n\n/**\n * Drive a ttyd PTY-over-websocket connection from a `pty-ws` Terminal capability,\n * symmetric with `use-desktop-stream` (the noVNC-over-tunnel hook). The scoped\n * stream token is already embedded in the minted tunnel `url`; the WebSocket is\n * opened with the REQUIRED ttyd subprotocol \"tty\".\n *\n * ttyd wire protocol (see `@opengeni/sdk/terminal`):\n * - first frame: `JSON.stringify({ AuthToken: \"\" })` (+ optional columns/rows).\n * - client→server: INPUT = \"0\"+data ; RESIZE = \"1\"+JSON({columns,rows}).\n * - server→client: \"0\" = OUTPUT (→ xterm) ; \"1\" = SET_WINDOW_TITLE ;\n * \"2\" = SET_PREFERENCES (ignored). Binary frames are decoded the same way.\n *\n * On a `url`/`token` rotation (a box rollover folds a fresh address into the cell)\n * the effect re-runs: the old socket closes and a fresh one connects — a brief\n * terminal blink, acceptable on rollover (mirrors the desktop's RFB hot-swap).\n * SSR-safe: the socket open lives in `useEffect`, so a server render is a no-op.\n */\nexport function useTerminalStream(options: UseTerminalStreamOptions): UseTerminalStreamResult {\n const { capability, onOutput, onTitle, initialCols, initialRows } = options;\n const [status, setStatus] = useState<TerminalStreamStatus>(\"closed\");\n const wsRef = useRef<WebSocket | null>(null);\n // Latest size, so a resize() before the socket opens is replayed on open, and a\n // reconnect seeds the right geometry.\n const sizeRef = useRef<{ cols: number; rows: number }>({\n cols: initialCols ?? 80,\n rows: initialRows ?? 24,\n });\n // Keep the callbacks current without re-running the connect effect on every\n // render (the parent passes fresh closures each time).\n const onOutputRef = useRef(onOutput);\n const onTitleRef = useRef(onTitle);\n onOutputRef.current = onOutput;\n onTitleRef.current = onTitle;\n\n const transport = capability?.transport ?? null;\n const url = capability?.url ?? null;\n const token = capability?.token ?? null;\n\n useEffect(() => {\n // SSR / no WebSocket / not a live pty-ws cell: stay closed; the caller falls\n // back to the Channel-A read-only firehose.\n if (typeof window === \"undefined\" || typeof WebSocket === \"undefined\") return;\n if (transport !== \"pty-ws\" || !url) {\n setStatus(\"closed\");\n return;\n }\n\n let disposed = false;\n let socket: WebSocket;\n setStatus(\"connecting\");\n try {\n // The ttyd \"tty\" subprotocol is REQUIRED — ttyd rejects a handshake without\n // it. The scoped token is already in the tunnel `url`.\n socket = new WebSocket(terminalSocketUrl({ url }), TTYD_SUBPROTOCOL);\n } catch {\n setStatus(\"error\");\n return;\n }\n socket.binaryType = \"arraybuffer\";\n wsRef.current = socket;\n\n socket.onopen = () => {\n if (disposed) return;\n // ttyd's required first frame: the auth message (empty token — the gate is\n // the tunnel url + scoped stream token, not a ttyd -c credential), seeded\n // with the current PTY geometry. Then an explicit resize to be safe.\n try {\n socket.send(ttydAuthFrame({ columns: sizeRef.current.cols, rows: sizeRef.current.rows }));\n socket.send(ttydResizeFrame(sizeRef.current.cols, sizeRef.current.rows));\n } catch {\n // a closed socket between open and send — onclose handles state.\n }\n setStatus(\"open\");\n };\n\n socket.onmessage = (ev: MessageEvent) => {\n if (disposed) return;\n const { command, payload } = decodeFrame(ev.data as string | ArrayBuffer);\n switch (command) {\n case TtydServerCommand.OUTPUT:\n onOutputRef.current?.(payload);\n break;\n case TtydServerCommand.SET_WINDOW_TITLE:\n onTitleRef.current?.(payload);\n break;\n // SET_PREFERENCES (\"2\") and anything else: ignored.\n default:\n break;\n }\n };\n\n socket.onerror = () => {\n if (!disposed) setStatus(\"error\");\n };\n socket.onclose = () => {\n if (!disposed) setStatus(\"closed\");\n };\n\n return () => {\n disposed = true;\n wsRef.current = null;\n // Drop handlers so an in-flight close/error doesn't mutate state post-unmount.\n socket.onopen = null;\n socket.onmessage = null;\n socket.onerror = null;\n socket.onclose = null;\n try {\n socket.close();\n } catch {\n // ignore teardown errors\n }\n };\n // A url/token change (rotation) re-runs this effect → close old, open new.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [transport, url, token]);\n\n return useMemo<UseTerminalStreamResult>(() => {\n const write = (data: string) => {\n const ws = wsRef.current;\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(ttydInputFrame(data));\n } catch {\n // socket raced closed — the reconnect effect will re-establish.\n }\n }\n };\n const resize = (cols: number, rows: number) => {\n if (cols <= 0 || rows <= 0) return;\n sizeRef.current = { cols, rows };\n const ws = wsRef.current;\n if (ws && ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(ttydResizeFrame(cols, rows));\n } catch {\n // socket raced closed — geometry is replayed on the next open.\n }\n }\n };\n const disconnect = () => {\n const ws = wsRef.current;\n wsRef.current = null;\n if (ws) {\n try {\n ws.close();\n } catch {\n // ignore\n }\n }\n };\n return { connected: status === \"open\", status, write, resize, disconnect };\n }, [status]);\n}\n","import type {\n SandboxCommandOutputDeltaPayload,\n SessionEvent,\n TerminalPtyExitedPayload,\n TerminalPtyOutputDeltaPayload,\n} from \"@opengeni/sdk\";\nimport { OpenGeniApiError } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type TerminalChunk = {\n /** Stable key (the source event id) so the xterm writer tracks a written-cursor. */\n id: string;\n /** Raw output bytes (utf-8 lossy) — written verbatim into xterm. */\n text: string;\n /** stdout vs stderr (drives optional tinting). */\n stream: \"stdout\" | \"stderr\";\n /** Global ordering: the source event sequence. */\n seq: number;\n};\n\nexport type UseSandboxTerminalOptions = ClientOverride & {\n /** The live session event log (usually `useSessionEvents().events`). */\n events: SessionEvent[];\n /** Restrict to one PTY (by ptyId). Omit to interleave the agent firehose +\n * every PTY. */\n ptyId?: string | undefined;\n /** Include the agent's command-output firehose (sandbox.command.output.delta).\n * Default true — the read-only \"terminal-as-events\" the data path settled on. */\n includeAgentFirehose?: boolean | undefined;\n /**\n * OPEN an interactive PTY against the box so the user can type, not just watch.\n * When true (and the session is live) the hook calls `terminalPtyOpen` once,\n * tracks the returned ptyId, exposes `write` immediately (bound to that ptyId),\n * and closes the PTY on unmount. The PTY's banner + every output delta ride the\n * SSE spine (`terminal.pty.*`) back into `events`, so xterm fills in. Default\n * false — a caller that only wants the read-only firehose stays projection-only.\n */\n interactive?: boolean | undefined;\n /** Lease liveness (\"cold\" | \"warm\" | \"draining\"). The interactive PTY is only\n * opened once the box is warm — opening on a cold box (ptyCapable is advertised\n * cold too) races the box and leaves a dead read-only terminal. */\n liveness?: string | undefined;\n};\n\nexport type UseSandboxTerminalResult = {\n /** Ordered, deduped output chunks to write() into xterm.js. */\n chunks: TerminalChunk[];\n /** Whether a PTY is currently open (drives the prompt/cursor affordance). */\n running: boolean;\n /**\n * Interactive write fn when a PTY is open and the backend supports stdin\n * (`terminal.transport === \"pty-ws\"` / `PtyOpenResponse.supportsInput`). Null\n * in the read-only event-projection case (v1 default).\n */\n write: ((data: string) => void) | null;\n /** The active PTY id, if one is open. */\n activePtyId: string | null;\n /** Close the active PTY (no-op when none is open). */\n close: () => void;\n /** A PTY-open failure (interactive mode), if any. */\n error: Error | null;\n};\n\n/**\n * Project the Channel-A event log into an xterm-writable byte stream. The\n * terminal is \"terminal-as-events\": there is NO new socket in v1 — the agent's\n * command output (`sandbox.command.output.delta`) and any interactive PTY\n * (`terminal.pty.output.delta`) ride the existing SSE spine. When a PTY is open\n * and the backend accepts stdin, `write` pipes keystrokes via the SDK\n * `terminalPtyWrite` (the synchronous Channel-A control path).\n */\nexport function useSandboxTerminal(\n sessionId: string | null | undefined,\n options: UseSandboxTerminalOptions,\n): UseSandboxTerminalResult {\n const { client, workspaceId } = useOpenGeni(options);\n const includeAgentFirehose = options.includeAgentFirehose ?? true;\n const interactive = options.interactive ?? false;\n // When the caller controls a fixed ptyId we project that one; otherwise (the\n // interactive default) the hook opens its OWN PTY and tracks it here so `write`\n // is live before the `terminal.pty.started` event round-trips through SSE.\n const ptyFilter = options.ptyId;\n const liveness = options.liveness;\n const [openedPtyId, setOpenedPtyId] = useState<string | null>(null);\n const [openError, setOpenError] = useState<Error | null>(null);\n // Bumped to force a fresh PTY open after a write reveals the old PTY was lost\n // (a 409 \"pty session lost\" — the box rolled over since the open). This makes\n // the interactive terminal self-heal instead of dead-ending on a stale session.\n const [reopenNonce, setReopenNonce] = useState(0);\n\n // Open ONE interactive PTY against the box, close it on unmount/identity\n // change. The open's banner + subsequent output deltas ride A1, so xterm fills\n // from `events` — we don't thread the open's body output here (the SSE\n // projection is the single source of truth for what's written). The open is\n // gated on a WARM box: opening on a cold/warming lease races the box (the PTY\n // exec-session is created on a box that the next op may not resume), which is\n // exactly the \"session not found\" terminal failure; we wait for warm/draining.\n const openInFlight = useRef(false);\n const boxWarm = liveness === undefined || liveness === \"warm\" || liveness === \"draining\";\n useEffect(() => {\n if (!interactive || !sessionId || ptyFilter || !boxWarm) return;\n let cancelled = false;\n openInFlight.current = true;\n let openedId: string | null = null;\n void client\n .terminalPtyOpen(workspaceId, sessionId, {})\n .then((res) => {\n if (cancelled) {\n // Raced past unmount — close the orphan we just opened.\n void client\n .terminalPtyClose(workspaceId, sessionId, { ptyId: res.ptyId })\n .catch(() => {});\n return;\n }\n openedId = res.ptyId;\n setOpenedPtyId(res.ptyId);\n })\n .catch((cause) => {\n if (!cancelled) setOpenError(cause instanceof Error ? cause : new Error(String(cause)));\n })\n .finally(() => {\n openInFlight.current = false;\n });\n return () => {\n cancelled = true;\n setOpenedPtyId(null);\n const id = openedId;\n if (id) void client.terminalPtyClose(workspaceId, sessionId, { ptyId: id }).catch(() => {});\n };\n }, [interactive, client, workspaceId, sessionId, ptyFilter, boxWarm, reopenNonce]);\n\n const { chunks, openPty, supportsInput } = useMemo(() => {\n const out: TerminalChunk[] = [];\n // Track PTY lifecycle so `running`/`write` reflect the latest state.\n const open = new Map<string, { supportsInput: boolean }>();\n let lastOpened: string | null = null;\n let lastSupportsInput = false;\n\n for (const event of options.events) {\n if (event.type === \"terminal.pty.started\") {\n const payload = event.payload as { ptyId?: string } | null;\n if (payload?.ptyId) {\n open.set(payload.ptyId, { supportsInput: true });\n lastOpened = payload.ptyId;\n }\n continue;\n }\n if (event.type === \"terminal.pty.exited\") {\n const payload = event.payload as TerminalPtyExitedPayload | null;\n if (payload?.ptyId) {\n open.delete(payload.ptyId);\n if (lastOpened === payload.ptyId) lastOpened = null;\n }\n continue;\n }\n if (event.type === \"terminal.pty.output.delta\") {\n const payload = event.payload as TerminalPtyOutputDeltaPayload | null;\n if (!payload || (ptyFilter && payload.ptyId !== ptyFilter)) continue;\n out.push({\n id: event.id,\n text: payload.chunk,\n stream: payload.stream === \"stderr\" ? \"stderr\" : \"stdout\",\n seq: event.sequence,\n });\n continue;\n }\n if (includeAgentFirehose && !ptyFilter && event.type === \"sandbox.command.output.delta\") {\n const payload = event.payload as SandboxCommandOutputDeltaPayload | null;\n if (!payload?.chunk) continue;\n out.push({\n id: event.id,\n text: payload.chunk,\n stream: payload.stream === \"stderr\" ? \"stderr\" : \"stdout\",\n seq: event.sequence,\n });\n }\n }\n\n // Stable order: by sequence (the SSE spine guarantees per-session ordering).\n out.sort((a, b) => a.seq - b.seq);\n const activePty = ptyFilter && open.has(ptyFilter) ? ptyFilter : lastOpened;\n lastSupportsInput = activePty ? (open.get(activePty)?.supportsInput ?? false) : false;\n return { chunks: out, openPty: activePty, supportsInput: lastSupportsInput };\n }, [options.events, ptyFilter, includeAgentFirehose]);\n\n // The PTY this hook actively drives: the one it opened (interactive) wins so\n // `write` is live the instant the open resolves — even before the\n // `terminal.pty.started` event arrives through SSE. Fall back to whatever the\n // event projection found (a PTY opened elsewhere, or a caller-pinned ptyId).\n const activePtyId = openedPtyId ?? openPty;\n // An interactively-opened PTY accepts stdin by construction (we only open it on\n // a pty-capable backend); a projected PTY uses its advertised supportsInput.\n const canWrite = openedPtyId !== null || supportsInput;\n\n const write = useMemo(() => {\n if (!activePtyId || !canWrite || !sessionId) return null;\n return (data: string) => {\n void client\n .terminalPtyWrite(workspaceId, sessionId, { ptyId: activePtyId, data })\n .catch((cause) => {\n // The PTY exec-session was lost on the live box (409/404 — the box rolled\n // over since the open). Self-heal: drop the stale id and re-open a fresh\n // PTY against the current box rather than silently swallowing keystrokes.\n if (\n cause instanceof OpenGeniApiError &&\n (cause.status === 409 || cause.status === 404) &&\n activePtyId === openedPtyId\n ) {\n setOpenedPtyId(null);\n setReopenNonce((n) => n + 1);\n }\n });\n };\n }, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId]);\n\n const close = useCallback(() => {\n if (!activePtyId || !sessionId) return;\n void client.terminalPtyClose(workspaceId, sessionId, { ptyId: activePtyId }).catch(() => {});\n }, [client, workspaceId, sessionId, activePtyId]);\n\n return {\n chunks,\n running: activePtyId !== null,\n write,\n activePtyId,\n close,\n error: openError,\n };\n}\n","import type {\n FsChangedPayload,\n FsReadResponse,\n FsTreeNode,\n FsWriteResponse,\n GitChangedPayload,\n GitFileStatusCode,\n SessionEvent,\n WorkspaceCaptureManifest,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\n/** The git-status overlay a file row may carry (tints modified files in the tree). */\nexport type FileTreeStatus = \"added\" | \"modified\" | \"deleted\" | \"renamed\" | \"untracked\";\n\n/** A node in the Pierre file tree. `children === undefined` ⇒ an unexpanded dir\n * (lazy treeMode); `children: []` ⇒ an expanded-but-empty dir. */\nexport type FileTreeNode = {\n path: string; // workspace-relative POSIX\n name: string;\n kind: \"file\" | \"dir\";\n children?: FileTreeNode[] | undefined;\n size?: number | null | undefined;\n status?: FileTreeStatus | undefined;\n /** A residue dir the capture COLLAPSED (node_modules, .git, dist, …): its\n * contents were never indexed. Cold, expanding it can't list children — the\n * UI shows an inline \"contents on machine\" row until the box is warm. */\n truncated?: boolean | undefined;\n};\n\nexport type UseSandboxFilesOptions = ClientOverride & {\n /** Live event log (usually `useSessionEvents().events`) — drives auto-refresh\n * on `fs.changed` / `git.changed`. */\n events?: SessionEvent[] | undefined;\n /** Initial path to list (workspace root by default). */\n rootPath?: string | undefined;\n /** Hold off the initial list (e.g. panel collapsed). Default true. */\n enabled?: boolean | undefined;\n /** The lease liveness (\"cold\" | \"warm\" | \"draining\"). The structured FileSystem\n * capability is advertised even on a COLD box, so the mount-time list can race\n * the box: it lists before the box is warm, gets an empty/errored result, and\n * (with no `fs.changed` event) never re-lists. Passing liveness re-lists when\n * the box first becomes warm, so the tree populates as soon as the box is up. */\n liveness?: string | undefined;\n /** The latest turn-end workspace capture (from `useWorkspaceCapture`). When the\n * box is NOT warm, the tree paints INSTANTLY from this capture's tree index (the\n * <200ms cold first paint) instead of blocking on a Channel-A list. A warm box\n * always wins (live path unchanged). On the cold→warm transition the live list\n * is merged in place — no remount, no flash (dossier §10.4 / §12-A1/D1). */\n capture?: WorkspaceCaptureManifest | null | undefined;\n /** Called when an OPTIMISTIC mutation is reverted because its background\n * Channel-A op failed (e.g. a 409 rename collision). The host wires this to a\n * toast — the tree silently rolls the node back, the user sees why. */\n onMutationError?: ((error: Error, op: string) => void) | undefined;\n};\n\nexport type UseSandboxFilesResult = {\n /** The tree roots (the listed root's children). */\n tree: FileTreeNode[];\n /** Lazy-expand a directory node in place (lists its immediate children). */\n expand: (path: string) => Promise<void>;\n /** Paths whose lazy `fs.list` is currently in flight — the FileBrowser shows a\n * spinner on these nodes so a 2-3s Channel-A list never looks frozen. */\n expandingPaths: Set<string>;\n /** Read a file for the preview pane (text or base64-for-binary, size-capped). */\n readFile: (path: string) => Promise<FsReadResponse>;\n /** Write a file (overwrite, last-writer-wins) — the editor save path.\n * Optimistic: a brand-new file is spliced into the tree immediately and the\n * Channel-A write runs in the background; on failure the splice is reverted. */\n writeFile: (path: string, content: string) => Promise<FsWriteResponse>;\n /** Create a new empty file (refuses to clobber an existing path: overwrite=false). */\n createFile: (path: string) => Promise<void>;\n /** Create a directory (recursive by default). */\n createDir: (path: string) => Promise<void>;\n /** Delete a path (pass recursive=true for a non-empty directory). */\n deleteEntry: (path: string, recursive?: boolean) => Promise<void>;\n /** Move / rename a path (rename == move). Refuses to clobber unless overwrite=true. */\n moveEntry: (path: string, newPath: string, opts?: { overwrite?: boolean }) => Promise<void>;\n /** Re-list the whole tree from the root. */\n refresh: () => Promise<void>;\n /** Which source the tree is currently served from: the live box, the turn-end\n * capture (cold/offline), or neither yet. M5's source badge reads this. */\n source: \"live\" | \"capture\" | null;\n /** When the served capture was taken (ISO), when `source === \"capture\"`. */\n capturedAt: string | null;\n loading: boolean;\n error: Error | null;\n};\n\n/** The workspace-relative parent directory of a POSIX path (\"\" for a root entry). */\nfunction parentOf(path: string): string {\n const i = path.lastIndexOf(\"/\");\n return i <= 0 ? \"\" : path.slice(0, i);\n}\n\n/** The leaf name of a POSIX path. */\nfunction leafOf(path: string): string {\n const i = path.lastIndexOf(\"/\");\n return i < 0 ? path : path.slice(i + 1);\n}\n\n/** Join a parent dir with a leaf name (handles the root \"\" parent). */\n/** Stable sibling ordering: dirs before files, then case-insensitive by name —\n * matches a typical depth-1 list so an optimistic insert lands where a real\n * re-list would put it (no jump when the server reconciles). */\nfunction sortNodes(nodes: FileTreeNode[]): FileTreeNode[] {\n return [...nodes].sort((a, b) => {\n if (a.kind !== b.kind) return a.kind === \"dir\" ? -1 : 1;\n return a.name.localeCompare(b.name, undefined, { sensitivity: \"base\" });\n });\n}\n\nfunction fsNodeToTree(node: FsTreeNode): FileTreeNode {\n const kind = node.type === \"dir\" ? \"dir\" : \"file\";\n // Lazy-tree contract: a depth-bounded `fsList` returns each directory at the\n // depth boundary with `children: []` (the dir is listed, but its grandchildren\n // are NOT). An empty array therefore means \"not yet expanded\", NOT \"empty\n // directory\" — so we must map it to `undefined` (the unexpanded marker the\n // FileBrowser keys lazy-expand on). If we kept `[]`, `toggle()`'s\n // `node.children === undefined` guard would never fire and clicking a folder\n // would do nothing (the reported bug). A directory we actually expand has its\n // children spliced in by `replaceChildren` (bypassing this mapper), so a\n // genuinely-empty dir correctly ends up as `[]` AFTER expansion.\n const mappedChildren =\n node.children && node.children.length > 0 ? node.children.map(fsNodeToTree) : undefined;\n return {\n path: node.path,\n name: node.name,\n kind,\n size: node.sizeBytes,\n ...(kind === \"dir\" ? { children: mappedChildren } : {}),\n // A collapsed residue dir from the capture index — carried through so the\n // tree can show an inline \"contents on machine\" row cold instead of nothing.\n ...(kind === \"dir\" && node.truncated ? { truncated: true } : {}),\n };\n}\n\nconst GIT_STATUS_TO_TREE: Partial<Record<GitFileStatusCode, FileTreeStatus>> = {\n added: \"added\",\n modified: \"modified\",\n deleted: \"deleted\",\n renamed: \"renamed\",\n copied: \"added\",\n untracked: \"untracked\",\n typechange: \"modified\",\n};\n\n/** Replace the children of `targetPath` within the tree (immutably). */\nfunction replaceChildren(\n nodes: FileTreeNode[],\n targetPath: string,\n children: FileTreeNode[],\n): FileTreeNode[] {\n return nodes.map((node) => {\n if (node.path === targetPath) {\n return { ...node, children };\n }\n if (node.kind === \"dir\" && node.children && targetPath.startsWith(`${node.path}/`)) {\n return { ...node, children: replaceChildren(node.children, targetPath, children) };\n }\n return node;\n });\n}\n\n/** Find a node by exact path (depth-first). */\nfunction findNodeByPath(nodes: FileTreeNode[], path: string): FileTreeNode | undefined {\n for (const node of nodes) {\n if (node.path === path) return node;\n if (node.kind === \"dir\" && node.children && path.startsWith(`${node.path}/`)) {\n const hit = findNodeByPath(node.children, path);\n if (hit) return hit;\n }\n }\n return undefined;\n}\n\n// ── In-place (optimistic) tree mutations ────────────────────────────────────\n// The Pierre mutation-handle analogue. These splice a single node in/out/across\n// the immutable tree, PRESERVING every other node's `children` (and therefore the\n// FileBrowser's expansion + selection). The old data flow re-listed the whole\n// root and `setTree(rootChildren)` — that dropped every expanded dir back to the\n// unexpanded marker, which is exactly the \"everything refreshes / collapses to\n// .config\" the user saw. Mutating in place is the fix.\n//\n// `parent === \"\"` targets the root list directly. A parent that isn't present in\n// the (lazily-loaded) tree means it's collapsed/unloaded — the helpers return the\n// tree UNCHANGED in that case (caller treats it as \"nothing visible to update\",\n// which is correct: a collapsed dir re-lists fresh when the user expands it).\n\n/** True when `parent` is the root (\"\") or a dir node that is actually present in\n * the loaded tree (so an insert/remove there would be visible). */\nfunction parentIsLoaded(nodes: FileTreeNode[], parent: string): boolean {\n if (parent === \"\") return true;\n const node = findNodeByPath(nodes, parent);\n return Boolean(node && node.kind === \"dir\" && node.children !== undefined);\n}\n\n/** Insert `child` under `parent` (immutably), keeping siblings sorted. A no-op\n * (returns the same array) when the parent isn't a loaded dir or the child\n * already exists. */\nfunction insertNode(nodes: FileTreeNode[], parent: string, child: FileTreeNode): FileTreeNode[] {\n if (parent === \"\") {\n if (nodes.some((n) => n.path === child.path)) return nodes;\n return sortNodes([...nodes, child]);\n }\n return nodes.map((node) => {\n if (node.path === parent) {\n if (node.kind !== \"dir\" || node.children === undefined) return node;\n if (node.children.some((n) => n.path === child.path)) return node;\n return { ...node, children: sortNodes([...node.children, child]) };\n }\n if (node.kind === \"dir\" && node.children && parent.startsWith(`${node.path}/`)) {\n return { ...node, children: insertNode(node.children, parent, child) };\n }\n return node;\n });\n}\n\n/** Remove the node at `path` (immutably). No-op when it isn't in the tree. */\nfunction removeNode(nodes: FileTreeNode[], path: string): FileTreeNode[] {\n const parent = parentOf(path);\n if (parent === \"\") {\n if (!nodes.some((n) => n.path === path)) return nodes;\n return nodes.filter((n) => n.path !== path);\n }\n return nodes.map((node) => {\n if (node.path === parent) {\n if (node.kind !== \"dir\" || node.children === undefined) return node;\n return { ...node, children: node.children.filter((n) => n.path !== path) };\n }\n if (node.kind === \"dir\" && node.children && parent.startsWith(`${node.path}/`)) {\n return { ...node, children: removeNode(node.children, path) };\n }\n return node;\n });\n}\n\n/** Reconcile a freshly-listed depth-1 set of children against the CURRENT nodes\n * at the same level, PRESERVING expansion: an existing dir keeps its already-\n * loaded `children` (so its expanded subtree survives), new entries are added,\n * and entries the server no longer returns are dropped. This is the in-place\n * merge a root (\"\") reconcile needs — a blind replace would collapse every\n * expanded top-level dir back to the unexpanded marker (the reported bug). */\n/** Shallow node equality for identity preservation across a reconcile — same\n * path/kind/name/size/status (children handled separately by the caller). */\nfunction sameNodeShallow(a: FileTreeNode, b: FileTreeNode): boolean {\n return (\n a.path === b.path &&\n a.kind === b.kind &&\n a.name === b.name &&\n (a.size ?? null) === (b.size ?? null) &&\n (a.status ?? undefined) === (b.status ?? undefined) &&\n (a.truncated ?? false) === (b.truncated ?? false)\n );\n}\n\nfunction mergeChildren(current: FileTreeNode[], listed: FileTreeNode[]): FileTreeNode[] {\n const byPath = new Map(current.map((n) => [n.path, n] as const));\n const merged = listed.map((next) => {\n const existing = byPath.get(next.path);\n if (!existing) return next; // brand-new entry\n // Keep an already-expanded dir's loaded children; otherwise take the listing's\n // marker (undefined = unexpanded). Carry forward size/status from the listing.\n if (existing.kind === \"dir\" && next.kind === \"dir\" && existing.children !== undefined) {\n const candidate: FileTreeNode = { ...next, children: existing.children };\n // Preserve identity when nothing observable changed — no remount (§12-D1).\n return sameNodeShallow(existing, candidate) ? existing : candidate;\n }\n // A file or an unexpanded dir: preserve identity when the node is unchanged.\n if (existing.children === next.children && sameNodeShallow(existing, next)) {\n return existing;\n }\n return next;\n });\n return sortNodes(merged);\n}\n\n/** Root-level (\"\") reconcile: merge a fresh depth-1 listing into the root list\n * without collapsing expanded top-level dirs. */\nfunction mergeRootChildren(nodes: FileTreeNode[], listed: FileTreeNode[]): FileTreeNode[] {\n return mergeChildren(nodes, listed);\n}\n\n/** Re-path a subtree rooted at `node` from `fromPrefix` to `toPrefix` (so a moved\n * dir's descendants keep correct paths without a re-list). */\nfunction repathNode(node: FileTreeNode, fromPrefix: string, toPrefix: string): FileTreeNode {\n const newPath = toPrefix + node.path.slice(fromPrefix.length);\n const next: FileTreeNode = { ...node, path: newPath, name: leafOf(newPath) };\n if (node.children) next.children = node.children.map((c) => repathNode(c, fromPrefix, toPrefix));\n return next;\n}\n\n/**\n * Project the FileSystem service into a lazy-loaded Pierre tree. The initial\n * list pulls one level (depth 1); `expand(path)` lists a directory's immediate\n * children on demand (the fast lazy-tree UX). A git-status overlay tints\n * modified files. Auto-refreshes when an `fs.changed` / `git.changed` event\n * arrives on the live log.\n */\nexport function useSandboxFiles(\n sessionId: string | null | undefined,\n options: UseSandboxFilesOptions = {},\n): UseSandboxFilesResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const rootPath = options.rootPath ?? \"\";\n\n const [tree, setTree] = useState<FileTreeNode[]>([]);\n // A ref mirror of the current tree — lets the optimistic path snapshot the\n // pre-op tree WITHOUT relying on a `setTree` updater (which StrictMode invokes\n // twice, corrupting an in-closure snapshot). Kept in sync on every set below\n // and in a layout effect for any path that sets `tree` directly.\n const treeRef = useRef<FileTreeNode[]>([]);\n const [loading, setLoading] = useState(false);\n const [expandingPaths, setExpandingPaths] = useState<Set<string>>(new Set());\n const [error, setError] = useState<Error | null>(null);\n // Which source the tree currently reflects — \"capture\" (cold paint) or \"live\".\n const [source, setSource] = useState<\"live\" | \"capture\" | null>(null);\n const statusRef = useRef<Map<string, FileTreeStatus>>(new Map());\n // Async reads, event cursors, and debounced work are scoped to the hook's\n // workspace/session/root identity. These refs are reset/fenced at that boundary.\n const refreshGenerationRef = useRef(0);\n const identityGenerationRef = useRef(0);\n const lastSeqRef = useRef(0);\n const pendingParentsRef = useRef<Set<string>>(new Set());\n const pendingGitRef = useRef(false);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // ── Self-emitted fs.changed de-dupe ───────────────────────────────────────\n // Every one of OUR mutations emits an `fs.changed` event back on the live log\n // (source:\"write\"). The old flow auto-refreshed on EVERY fs.changed, so each\n // edit self-triggered a full root collapse-reload (~5s, lost expansion). We now\n // (a) ignore fs.changed whose `source === \"write\"` (our own control-plane ops),\n // and (b) belt-and-braces, track the revisions WE caused so even a watch-sourced\n // echo of our own write is suppressed. Only EXTERNAL changes (the agent writing,\n // source:\"agent\"/\"watch\" we didn't cause) drive a targeted reconcile.\n const ownRevisionsRef = useRef<Set<number>>(new Set());\n const onMutationError = options.onMutationError;\n\n // Keep the ref mirror current for the optimistic snapshot path.\n treeRef.current = tree;\n\n // Overlay the git-status tint onto the tree. IDENTITY-PRESERVING: a node whose\n // tint and children are unchanged is returned by reference (not rebuilt), so a\n // re-tint or a cold→warm reconcile does NOT remount unchanged rows — the\n // no-flicker constraint (dossier §3 #6 / §12-D1). An empty overlay is still\n // meaningful: it strips stale tints after the repository becomes clean.\n const applyStatus = useCallback((nodes: FileTreeNode[]): FileTreeNode[] => {\n const overlay = statusRef.current;\n const walk = (list: FileTreeNode[]): FileTreeNode[] => {\n let changed = false;\n const out = list.map((node) => {\n const nextChildren = node.children ? walk(node.children) : node.children;\n const wantStatus = node.kind === \"file\" ? overlay.get(node.path) : undefined;\n const childrenChanged = nextChildren !== node.children;\n const statusChanged = (node.status ?? undefined) !== (wantStatus ?? undefined);\n if (!childrenChanged && !statusChanged) return node;\n changed = true;\n const next: FileTreeNode = {\n ...node,\n ...(node.children ? { children: nextChildren } : {}),\n };\n if (wantStatus) next.status = wantStatus;\n else delete next.status;\n return next;\n });\n return changed ? out : list;\n };\n return walk(nodes);\n }, []);\n\n const refresh = useCallback(async () => {\n if (!sessionId) return;\n const generation = (refreshGenerationRef.current += 1);\n setLoading(true);\n setError(null);\n try {\n // Pull the git-status overlay first (best-effort — a non-repo box just\n // returns isRepo:false), then the tree, so the first paint is tinted.\n try {\n const status = await client.gitStatus(workspaceId, sessionId, { path: rootPath });\n if (refreshGenerationRef.current !== generation) return;\n const overlay = new Map<string, FileTreeStatus>();\n for (const file of status.files) {\n const code = file.worktree ?? file.index;\n const mapped = code ? GIT_STATUS_TO_TREE[code] : undefined;\n if (mapped) overlay.set(file.path, mapped);\n }\n statusRef.current = overlay;\n } catch {\n if (refreshGenerationRef.current !== generation) return;\n statusRef.current = new Map();\n }\n const listed = await client.fsList(workspaceId, sessionId, { path: rootPath, depth: 1 });\n if (refreshGenerationRef.current !== generation) return;\n const children = (listed.root.children ?? []).map(fsNodeToTree);\n // Merge rather than replace so an explicit refresh / cold→warm re-list folds\n // in new entries WITHOUT collapsing the dirs the user already expanded (and,\n // via the identity-preserving merge, WITHOUT remounting unchanged rows — the\n // no-flicker cold→warm reconcile). On a first (empty) load this is a plain set.\n setTree((prev) =>\n applyStatus(prev.length === 0 ? children : mergeRootChildren(prev, children)),\n );\n // Live data is now serving — flip the source off the capture snapshot.\n setSource(\"live\");\n } catch (cause) {\n if (refreshGenerationRef.current !== generation) return;\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n if (refreshGenerationRef.current === generation) setLoading(false);\n }\n }, [client, workspaceId, sessionId, rootPath, applyStatus]);\n\n // Seed (or re-seed) the tree from a turn-end capture — the COLD/offline paint,\n // zero Channel-A calls. The tree index is workspace-relative (`treeIndex`); the\n // tint overlay comes from the capture's changed `files`. Uses the SAME merge as\n // the live reconcile so a re-seed (a newer capture arriving cold) patches deltas\n // in place instead of remounting the tree (§12-D1). Never runs while warm.\n const seedFromCapture = useCallback(\n (manifest: WorkspaceCaptureManifest) => {\n const overlay = new Map<string, FileTreeStatus>();\n for (const file of manifest.files) {\n if (file.deleted) continue;\n const mapped = GIT_STATUS_TO_TREE[file.status];\n if (mapped) overlay.set(file.path, mapped);\n }\n statusRef.current = overlay;\n const children = (manifest.treeIndex.children ?? []).map(fsNodeToTree);\n setTree((prev) =>\n applyStatus(prev.length === 0 ? children : mergeRootChildren(prev, children)),\n );\n setSource(\"capture\");\n setError(null);\n },\n [applyStatus],\n );\n\n const expand = useCallback(\n async (path: string) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n // Mark this node as expanding so the FileBrowser can render a spinner while\n // the (often 2-3s) Channel-A fs/list is in flight — the tree never looks\n // frozen on a click.\n setExpandingPaths((prev) => {\n const next = new Set(prev);\n next.add(path);\n return next;\n });\n try {\n const listed = await client.fsList(workspaceId, sessionId, { path, depth: 1 });\n if (identityGenerationRef.current !== identityGeneration) return;\n const children = (listed.root.children ?? []).map(fsNodeToTree);\n setTree((prev) => applyStatus(replaceChildren(prev, path, children)));\n } catch (cause) {\n if (identityGenerationRef.current !== identityGeneration) return;\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n if (identityGenerationRef.current === identityGeneration) {\n setExpandingPaths((prev) => {\n if (!prev.has(path)) return prev;\n const next = new Set(prev);\n next.delete(path);\n return next;\n });\n }\n }\n },\n [client, workspaceId, sessionId, applyStatus],\n );\n\n const readFile = useCallback(\n async (path: string) => {\n if (!sessionId) throw new Error(\"no session\");\n return await client.fsRead(workspaceId, sessionId, { path });\n },\n [client, workspaceId, sessionId],\n );\n\n // TARGETED reconcile of a single directory — re-list ONE parent at depth 1 and\n // splice its children in place via `replaceChildren`, preserving the rest of the\n // tree's expansion. NEVER falls back to a root refresh (that's the collapse).\n // Used to (a) reconcile an optimistic insert against the server's real\n // size/mtime, and (b) fold an EXTERNAL (agent) change into the tree. A reconcile\n // of a parent that isn't loaded (collapsed/unmounted) is a no-op — there's\n // nothing visible to update, and it re-lists fresh when the user expands it.\n const reconcilePath = useCallback(\n async (path: string) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n // Skip parents that aren't currently loaded/expanded in the tree (nothing\n // visible to update; they re-list fresh on the next expand).\n if (!parentIsLoaded(treeRef.current, path)) return;\n try {\n const listed = await client.fsList(workspaceId, sessionId, { path, depth: 1 });\n if (identityGenerationRef.current !== identityGeneration) return;\n const children = (listed.root.children ?? []).map(fsNodeToTree);\n if (path === \"\") setTree((prev) => applyStatus(mergeRootChildren(prev, children)));\n else\n setTree((prev) => {\n const existing = findNodeByPath(prev, path);\n const merged = existing?.children\n ? mergeChildren(existing.children, children)\n : children;\n return applyStatus(replaceChildren(prev, path, merged));\n });\n } catch {\n // A failed reconcile is non-fatal: the optimistic state stands. We never\n // root-refresh here (that would collapse the tree the user is working in).\n }\n },\n [client, workspaceId, sessionId, applyStatus],\n );\n\n // Run a Channel-A op behind an OPTIMISTIC tree edit. `apply` splices the change\n // in immediately (preserving expansion/selection); the op runs in the\n // background; on failure we revert to the pre-op snapshot and surface a toast.\n // On success we keep the optimistic state and (optionally) reconcile the\n // affected parent(s) to pick up the server's real size/revision — NEVER a full\n // refresh. The returned promise resolves/rejects with the op so callers (the\n // editor save, inline rename) can still await it.\n const runOptimistic = useCallback(\n async <T>(\n opName: string,\n apply: (nodes: FileTreeNode[]) => FileTreeNode[],\n op: () => Promise<T>,\n reconcileParents: string[],\n ): Promise<T> => {\n const identityGeneration = identityGenerationRef.current;\n // Snapshot the pre-op tree from the ref (StrictMode-safe — see treeRef).\n const snapshot = treeRef.current;\n setTree(applyStatus(apply(snapshot)));\n try {\n const res = await op();\n if (identityGenerationRef.current !== identityGeneration) return res;\n // Remember the revision WE caused so the matching fs.changed echo is\n // ignored by the event effect (no self-triggered refresh).\n if (res && typeof res === \"object\" && \"revision\" in res) {\n const rev = (res as { revision?: unknown }).revision;\n if (typeof rev === \"number\") ownRevisionsRef.current.add(rev);\n }\n // Reconcile loaded parents to fold the server's real metadata. Sequential\n // and best-effort — purely cosmetic over the already-correct optimistic UI.\n for (const parent of reconcileParents) {\n if (identityGenerationRef.current !== identityGeneration) return res;\n await reconcilePath(parent);\n }\n return res;\n } catch (cause) {\n const err = cause instanceof Error ? cause : new Error(String(cause));\n if (identityGenerationRef.current !== identityGeneration) throw err;\n // Revert the optimistic edit to the exact pre-op tree.\n setTree(applyStatus(snapshot));\n setError(err);\n onMutationError?.(err, opName);\n throw err;\n }\n },\n [applyStatus, reconcilePath, onMutationError],\n );\n\n const writeFile = useCallback(\n async (path: string, content: string): Promise<FsWriteResponse> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentOf(path);\n // Splice a new file node in immediately ONLY when the path doesn't already\n // exist in a loaded parent (an editor SAVE to an existing file mutates no\n // tree shape — just content — so it needs no optimistic node, no reconcile).\n const exists = Boolean(findNodeByPath(tree, path));\n const node: FileTreeNode = { path, name: leafOf(path), kind: \"file\", size: content.length };\n return await runOptimistic(\n \"write\",\n (nodes) => (exists ? nodes : insertNode(nodes, parent, node)),\n () => client.fsWrite(workspaceId, sessionId, { path, content, overwrite: true }),\n exists ? [] : [parent],\n );\n },\n [client, workspaceId, sessionId, tree, runOptimistic],\n );\n\n const createFile = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentOf(path);\n const node: FileTreeNode = { path, name: leafOf(path), kind: \"file\", size: 0 };\n await runOptimistic(\n \"create file\",\n (nodes) => insertNode(nodes, parent, node),\n () => client.fsWrite(workspaceId, sessionId, { path, content: \"\", overwrite: false }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n const createDir = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentOf(path);\n // A freshly-created dir is empty + expanded: children:[] (not undefined, so\n // it doesn't show the lazy-expand marker over a dir we KNOW is empty).\n const node: FileTreeNode = { path, name: leafOf(path), kind: \"dir\", children: [] };\n await runOptimistic(\n \"create folder\",\n (nodes) => insertNode(nodes, parent, node),\n () => client.fsMkdir(workspaceId, sessionId, { path, recursive: true }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n const deleteEntry = useCallback(\n async (path: string, recursive = false): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n await runOptimistic(\n \"delete\",\n (nodes) => removeNode(nodes, path),\n () => client.fsDelete(workspaceId, sessionId, { path, recursive }),\n [parentOf(path)],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n const moveEntry = useCallback(\n async (path: string, newPath: string, opts?: { overwrite?: boolean }): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const from = parentOf(path);\n const to = parentOf(newPath);\n await runOptimistic(\n \"move\",\n (nodes) => {\n const moving = findNodeByPath(nodes, path);\n if (!moving) return nodes; // not loaded — let the reconcile pick it up\n // Re-path the moved subtree, drop it from its old parent, splice into new.\n const moved = repathNode(moving, path, newPath);\n return insertNode(removeNode(nodes, path), to, moved);\n },\n () =>\n client.fsMove(workspaceId, sessionId, {\n path,\n newPath,\n overwrite: opts?.overwrite ?? false,\n }),\n to === from ? [from] : [from, to],\n );\n },\n [client, workspaceId, sessionId, runOptimistic],\n );\n\n // Initial paint + reset on identity change. Source selection (dossier §10.4):\n // • warm/draining box → the LIVE list (unchanged behavior).\n // • cold/offline box WITH a capture → paint instantly from the capture index\n // (no Channel-A; the box warms in the background and the warm effect below\n // reconciles live in place).\n // • cold box with NO capture → best-effort live list (status quo — never worse).\n const capture = options.capture ?? null;\n const isLive = options.liveness === \"warm\" || options.liveness === \"draining\";\n // Key the seed on the capture's REVISION (a primitive), not the manifest object\n // — a consumer passing a fresh object each render (or a new revision) must not\n // spin the effect. The latest manifest is read from a ref at run time.\n const captureRef = useRef<WorkspaceCaptureManifest | null>(capture);\n captureRef.current = capture;\n const captureRevision = capture?.revision ?? null;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${rootPath}`;\n const previousIdentityRef = useRef(identityKey);\n useEffect(() => {\n // Any source-selection change supersedes an older root refresh. A true data\n // identity change additionally fences all other async tree work and resets\n // event/debounce state before the event-folding effect runs.\n refreshGenerationRef.current += 1;\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged || !enabled) {\n identityGenerationRef.current += 1;\n lastSeqRef.current = 0;\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n debounceRef.current = null;\n }\n ownRevisionsRef.current = new Set();\n statusRef.current = new Map();\n treeRef.current = [];\n setTree([]);\n setExpandingPaths(new Set());\n setSource(null);\n setLoading(false);\n setError(null);\n }\n if (!enabled) {\n return;\n }\n if (isLive) {\n void refresh();\n } else if (captureRevision !== null && captureRef.current) {\n seedFromCapture(captureRef.current);\n } else {\n void refresh();\n }\n return () => {\n refreshGenerationRef.current += 1;\n };\n }, [enabled, isLive, captureRevision, identityKey, refresh, seedFromCapture]);\n\n // Re-pull JUST the git-status overlay and re-tint the existing tree in place —\n // no fs re-list, no collapse. This is all a `git.changed` (commit/stage/checkout)\n // needs: the tree SHAPE is unchanged, only the tints move.\n const refreshGitOverlay = useCallback(async () => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n try {\n const status = await client.gitStatus(workspaceId, sessionId, { path: rootPath });\n if (identityGenerationRef.current !== identityGeneration) return;\n const overlay = new Map<string, FileTreeStatus>();\n for (const file of status.files) {\n const code = file.worktree ?? file.index;\n const mapped = code ? GIT_STATUS_TO_TREE[code] : undefined;\n if (mapped) overlay.set(file.path, mapped);\n }\n statusRef.current = overlay;\n setTree((prev) => applyStatus(prev));\n } catch {\n /* a non-repo box has no overlay — leave the tree untinted */\n }\n }, [client, workspaceId, sessionId, rootPath, applyStatus]);\n\n // Auto-reconcile on fs/git change notifications — TARGETED, never a root\n // collapse-reload, and de-duped against our OWN mutations.\n //\n // • Our own ops (`source:\"write\"`, or a revision WE caused) are IGNORED —\n // the optimistic edit already reflects them, so a refresh here would be the\n // pointless 5s collapse the user reported.\n // • An EXTERNAL fs.changed (the agent writing files: `source:\"agent\"`/`watch`)\n // reconciles ONLY the affected parent directories (in place, expansion\n // preserved). Bursts are debounced into a single reconcile pass.\n // • A git.changed just re-tints (refreshes the status overlay) — no fs re-list.\n const events = options.events;\n\n useEffect(() => {\n if (!enabled || !events) return;\n let sawNew = false;\n for (const event of events) {\n if (event.sequence <= lastSeqRef.current) continue;\n if (event.type === \"fs.changed\") {\n sawNew = true;\n const payload = event.payload as FsChangedPayload | null;\n if (!payload || typeof payload !== \"object\") continue;\n // Suppress our own writes: the optimistic tree already shows them.\n if (payload.source === \"write\") continue;\n if (typeof payload.revision === \"number\" && ownRevisionsRef.current.has(payload.revision))\n continue;\n for (const change of payload.changes ?? []) {\n pendingParentsRef.current.add(parentOf(change.path));\n if (change.oldPath) pendingParentsRef.current.add(parentOf(change.oldPath));\n }\n } else if (event.type === \"git.changed\") {\n sawNew = true;\n const payload = event.payload as GitChangedPayload | null;\n // A git.changed our own write triggered (commit/stage from the agent is\n // external; a checkout we caused isn't — but we don't cause git ops here,\n // so any git.changed is external) → re-tint.\n if (\n payload &&\n typeof payload === \"object\" &&\n typeof payload.revision === \"number\" &&\n ownRevisionsRef.current.has(payload.revision)\n )\n continue;\n pendingGitRef.current = true;\n }\n }\n // Advance the high-water mark past everything we've folded.\n for (const event of events)\n if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;\n if (!sawNew) return;\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n const identityGeneration = identityGenerationRef.current;\n debounceRef.current = setTimeout(() => {\n debounceRef.current = null;\n if (identityGenerationRef.current !== identityGeneration) return;\n const parents = pendingParentsRef.current;\n pendingParentsRef.current = new Set();\n const wantGit = pendingGitRef.current;\n pendingGitRef.current = false;\n // Reconcile the changed directories (in place). A git change re-tints first\n // so the freshly-listed nodes get the correct overlay.\n void (async () => {\n if (wantGit) await refreshGitOverlay();\n if (identityGenerationRef.current !== identityGeneration) return;\n for (const parent of parents) {\n if (identityGenerationRef.current !== identityGeneration) return;\n await reconcilePath(parent);\n }\n })();\n }, 150);\n }, [enabled, events, reconcilePath, refreshGitOverlay]);\n\n useEffect(\n () => () => {\n identityGenerationRef.current += 1;\n if (debounceRef.current) clearTimeout(debounceRef.current);\n },\n [],\n );\n\n // Re-list when the box first becomes warm. The FileSystem capability is\n // advertised on a cold box too, so the mount-time `refresh()` can run before\n // the box is up (empty/errored result); without an `fs.changed` event the tree\n // would stay empty forever. A cold->warm transition re-lists once the box is\n // actually serving — the real fix for the \"No files\" the deployed app showed.\n const wasLiveRef = useRef(false);\n const liveness = options.liveness;\n useEffect(() => {\n const live = liveness === \"warm\" || liveness === \"draining\";\n if (enabled && live && !wasLiveRef.current) {\n wasLiveRef.current = true;\n void refresh();\n } else if (!live) {\n wasLiveRef.current = false;\n }\n }, [enabled, liveness, refresh]);\n\n return {\n tree,\n expand,\n expandingPaths,\n readFile,\n writeFile,\n createFile,\n createDir,\n deleteEntry,\n moveEntry,\n refresh,\n source,\n capturedAt: source === \"capture\" ? (capture?.capturedAt ?? null) : null,\n loading,\n error,\n };\n}\n","import type {\n GitFileDiff,\n SessionEvent,\n WorkspaceCaptureManifest,\n WorkspaceCaptureRepo,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\nexport type UseSandboxGitOptions = ClientOverride & {\n /** Live event log (usually `useSessionEvents().events`) — drives auto-refresh\n * on `git.changed`. */\n events?: SessionEvent[] | undefined;\n /** Repo root within the workspace (multi-repo). Default: workspace root. */\n repoPath?: string | undefined;\n /** Diff the staged index vs HEAD (`--cached`) instead of the working tree. */\n staged?: boolean | undefined;\n /** Hold off the initial fetch. Default true. */\n enabled?: boolean | undefined;\n /** Lease liveness (\"warm\" | \"draining\" | \"cold\"). When NOT warm, the diff is\n * served from the capture (cold/offline) instead of a live `gitDiff` RPC. */\n liveness?: string | undefined;\n /** The latest turn-end capture (from `useWorkspaceCapture`). Supplies the cold\n * diff for this repo. A warm box always wins (live `gitDiff` unchanged). */\n capture?: WorkspaceCaptureManifest | null | undefined;\n};\n\nexport type UseSandboxGitResult = {\n /** Working-tree (or staged) diff vs HEAD — the structured hunks the Pierre\n * diff view renders. */\n diff: GitFileDiff[];\n branch: string | null;\n /** Whether a repo is actually mounted (drives \"no repository\" vs \"no changes\"). */\n isRepo: boolean;\n ahead: number;\n behind: number;\n refresh: () => Promise<void>;\n /** Which source the diff is served from: the live box or the turn-end capture. */\n source: \"live\" | \"capture\" | null;\n /** When the served capture was taken (ISO), when `source === \"capture\"`. */\n capturedAt: string | null;\n loading: boolean;\n error: Error | null;\n};\n\n/** Normalize a repo root for matching (\"\" and \".\" both mean the workspace root). */\nfunction normalizeRoot(root: string): string {\n return root === \".\" ? \"\" : root;\n}\n\n/** Find the capture repo matching `repoPath` (default workspace root). */\nfunction repoForPath(\n manifest: WorkspaceCaptureManifest,\n repoPath: string,\n): WorkspaceCaptureRepo | null {\n const want = normalizeRoot(repoPath);\n const exact = manifest.repos.find((r) => normalizeRoot(r.root) === want);\n if (exact) return exact;\n // Root-scoped hook against a single-repo capture whose root isn't literally \"\":\n // fall back to the sole repo so the common single-repo case just works.\n if (want === \"\" && manifest.repos.length === 1) return manifest.repos[0] ?? null;\n return null;\n}\n\n/** Full diff equality for identity preservation. Hunk count/count summaries are\n * not sufficient: an edit can replace text without changing either shape. */\nfunction sameFileDiff(a: GitFileDiff, b: GitFileDiff): boolean {\n if (\n a.path !== b.path ||\n a.oldPath !== b.oldPath ||\n a.status !== b.status ||\n a.isBinary !== b.isBinary ||\n a.isImage !== b.isImage ||\n a.additions !== b.additions ||\n a.deletions !== b.deletions ||\n a.truncated !== b.truncated ||\n a.hunks.length !== b.hunks.length\n )\n return false;\n\n return a.hunks.every((hunk, hunkIndex) => {\n const other = b.hunks[hunkIndex];\n if (\n !other ||\n hunk.oldStart !== other.oldStart ||\n hunk.oldLines !== other.oldLines ||\n hunk.newStart !== other.newStart ||\n hunk.newLines !== other.newLines ||\n hunk.header !== other.header ||\n hunk.lines.length !== other.lines.length\n )\n return false;\n return hunk.lines.every((line, lineIndex) => {\n const otherLine = other.lines[lineIndex];\n return (\n otherLine !== undefined &&\n line.type === otherLine.type &&\n line.oldNo === otherLine.oldNo &&\n line.newNo === otherLine.newNo &&\n line.text === otherLine.text\n );\n });\n });\n}\n\n/** Merge a freshly-served diff over the current one, preserving the identity of\n * genuinely unchanged per-file entries so a cold→warm reconcile does NOT\n * remount unchanged file sections — no-flicker (§12-D1). */\nfunction mergeDiffs(current: GitFileDiff[], next: GitFileDiff[]): GitFileDiff[] {\n if (current.length === 0) return next;\n const byPath = new Map(current.map((d) => [d.path, d] as const));\n let changed = current.length !== next.length;\n const merged = next.map((file, index) => {\n const existing = byPath.get(file.path);\n if (existing && sameFileDiff(existing, file)) {\n if (current[index] !== existing) changed = true;\n return existing;\n }\n changed = true;\n return file;\n });\n return changed ? merged : current;\n}\n\n/**\n * Project the Git service into the Pierre diff data contract: structured\n * `GitFileDiff[]` (per-file hunks with per-line old/new numbers, rename\n * detection, binary flag, add/del counts) plus branch + ahead/behind. When the\n * box is warm the `git diff` runs in-box (API-direct); when it is cold/offline the\n * diff is served from the turn-end capture instead (dossier §10.4). Refreshes on\n * `git.changed`; reconciles live in place on the cold→warm transition.\n */\nexport function useSandboxGit(\n sessionId: string | null | undefined,\n options: UseSandboxGitOptions = {},\n): UseSandboxGitResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const repoPath = options.repoPath ?? \"\";\n const staged = options.staged ?? false;\n const capture = options.capture ?? null;\n const isLive = options.liveness === \"warm\" || options.liveness === \"draining\";\n\n const [diff, setDiff] = useState<GitFileDiff[]>([]);\n const [branch, setBranch] = useState<string | null>(null);\n const [isRepo, setIsRepo] = useState(false);\n const [ahead, setAhead] = useState(0);\n const [behind, setBehind] = useState(0);\n const [source, setSource] = useState<\"live\" | \"capture\" | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n // Live requests and event cursors are identity-scoped. The refs deliberately\n // survive renders, so they must be fenced/reset when that identity changes.\n const refreshGenerationRef = useRef(0);\n const lastChangeRef = useRef(0);\n\n const refresh = useCallback(async () => {\n if (!sessionId) return;\n const generation = (refreshGenerationRef.current += 1);\n setLoading(true);\n setError(null);\n try {\n const status = await client.gitStatus(workspaceId, sessionId, { path: repoPath });\n if (refreshGenerationRef.current !== generation) return;\n setIsRepo(status.isRepo);\n setBranch(status.head);\n setAhead(status.ahead);\n setBehind(status.behind);\n if (!status.isRepo) {\n setDiff([]);\n setSource(\"live\");\n return;\n }\n const result = await client.gitDiff(workspaceId, sessionId, { path: repoPath, staged });\n if (refreshGenerationRef.current !== generation) return;\n // Merge in place so the cold→warm swap keeps unchanged file sections mounted.\n setDiff((prev) => mergeDiffs(prev, result.files));\n setSource(\"live\");\n } catch (cause) {\n if (refreshGenerationRef.current !== generation) return;\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n if (refreshGenerationRef.current === generation) setLoading(false);\n }\n }, [client, workspaceId, sessionId, repoPath, staged]);\n\n // Serve the diff from a capture (the cold/offline source). `staged` has no\n // meaning here: the capture records the combined turn-end change surface vs HEAD.\n const seedFromCapture = useCallback(\n (manifest: WorkspaceCaptureManifest) => {\n const repo = repoForPath(manifest, repoPath);\n if (!repo) {\n setIsRepo(false);\n setBranch(null);\n setAhead(0);\n setBehind(0);\n setDiff((prev) => (prev.length === 0 ? prev : []));\n setSource(\"capture\");\n return;\n }\n setIsRepo(true);\n setBranch(repo.head);\n setAhead(repo.ahead);\n setBehind(repo.behind);\n setDiff((prev) => mergeDiffs(prev, repo.diff));\n setSource(\"capture\");\n setError(null);\n },\n [repoPath],\n );\n\n // Source selection on mount / liveness / capture-revision change. Key on the\n // capture REVISION (a primitive), not the manifest object, so a fresh object per\n // render can't spin the effect; the latest manifest is read from a ref.\n const captureRef = useRef<WorkspaceCaptureManifest | null>(capture);\n captureRef.current = capture;\n const captureRevision = capture?.revision ?? null;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${repoPath}\\u0000${staged}`;\n const previousIdentityRef = useRef(identityKey);\n useEffect(() => {\n // A liveness/capture source change supersedes any older live request. Only a\n // true data-identity change clears rendered state and the event high-water mark.\n refreshGenerationRef.current += 1;\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged || !enabled) {\n lastChangeRef.current = 0;\n setDiff([]);\n setIsRepo(false);\n setBranch(null);\n setAhead(0);\n setBehind(0);\n setSource(null);\n setLoading(false);\n setError(null);\n }\n if (!enabled) {\n return;\n }\n if (isLive) {\n void refresh();\n } else if (captureRevision !== null && captureRef.current) {\n seedFromCapture(captureRef.current);\n } else {\n void refresh();\n }\n return () => {\n refreshGenerationRef.current += 1;\n };\n }, [enabled, isLive, captureRevision, identityKey, refresh, seedFromCapture]);\n\n // git.changed → re-fetch the LIVE diff. A git.changed only originates from a\n // live box, so this both keeps warm sessions fresh and folds a cold box that\n // just came up (unchanged from the pre-capture behavior).\n const events = options.events;\n useEffect(() => {\n if (!enabled || !events) return;\n let latest = lastChangeRef.current;\n for (const event of events) {\n if (event.type === \"git.changed\" && event.sequence > latest) {\n latest = event.sequence;\n }\n }\n if (latest > lastChangeRef.current) {\n lastChangeRef.current = latest;\n void refresh();\n }\n }, [enabled, events, refresh]);\n\n return {\n diff,\n branch,\n isRepo,\n ahead,\n behind,\n refresh,\n source,\n capturedAt: source === \"capture\" ? (capture?.capturedAt ?? null) : null,\n loading,\n error,\n };\n}\n","import type {\n GetWorkspaceCaptureResponse,\n SessionEvent,\n WorkspaceCaptureDegradedReason,\n WorkspaceCaptureManifest,\n WorkspaceRevisionCapturedPayload,\n WorkspaceRevisionDegradedPayload,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\n/** The announce event M1 emits at turn end (metadata only, never content). */\nconst REVISION_CAPTURED = \"workspace.revision.captured\";\nconst REVISION_DEGRADED = \"workspace.revision.degraded\";\nconst MANIFEST_FETCH_TIMEOUT_MS = 15_000;\n\nexport type UseWorkspaceCaptureOptions = ClientOverride & {\n /** Live event log (usually `useSessionEvents().events`) — a\n * `workspace.revision.captured` for a NEWER revision refreshes the manifest. */\n events?: SessionEvent[] | undefined;\n /** Hold off the mount fetch (e.g. the workbench panel is collapsed). Default true. */\n enabled?: boolean | undefined;\n};\n\nexport type UseWorkspaceCaptureResult = {\n /** The resolved manifest (tree index + per-repo diffs + file refs), or null when\n * no capture exists (falls back to the live/wake path — status quo). */\n capture: WorkspaceCaptureManifest | null;\n /** The loaded capture's monotonic revision, or null when unavailable. */\n revision: number | null;\n /** When the loaded capture was taken (ISO), for the \"as of <time>\" source badge. */\n capturedAt: string | null;\n /** Whether a capture is available at all (the `{available:false}` discriminator). */\n available: boolean;\n /** Why the newest durable revision is unavailable. null means no capture has\n * been attempted yet; a value means capture explicitly failed closed and\n * consumers must use the live box rather than trust an incomplete snapshot. */\n degradedReason: WorkspaceCaptureDegradedReason | null;\n /** The changed-file count from the capture's stats, resolved on the FIRST GET\n * (from the response's top-level `stats`, before any manifest-URL hop). null\n * until that first resolve; 0 when no capture exists. This is the pre-paint\n * \"changes exist?\" signal the dock uses to pick its default tab with no\n * embedder events-at-mount contract. */\n fileCount: number | null;\n /** A newer revision has been ANNOUNCED than the one currently loaded (a refresh\n * is in flight or pending). M5's source badge can show a subtle \"updating…\". */\n isStale: boolean;\n loading: boolean;\n error: Error | null;\n /** Force a re-fetch of the latest capture. */\n refresh: () => Promise<void>;\n};\n\n/**\n * The cold-paint data source: fetch the latest turn-end workspace capture with a\n * SINGLE api round-trip on mount (no machine, no Channel-A — this is the <200ms\n * first paint, dossier §10.4/§12-A1). The manifest is served inline in the common\n * case; a rare >2MB manifest comes back as a short-TTL signed URL we follow.\n *\n * Subscribes to the live event log: a `workspace.revision.captured` for a revision\n * newer than the one loaded triggers a background refresh (stale-while-revalidate).\n * `{available:false}` is a value, never a crash — consumers fall back to the\n * live/wake path exactly as before the capture feature existed.\n */\nexport function useWorkspaceCapture(\n sessionId: string | null | undefined,\n options: UseWorkspaceCaptureOptions = {},\n): UseWorkspaceCaptureResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}`;\n\n const [capture, setCapture] = useState<WorkspaceCaptureManifest | null>(null);\n const [available, setAvailable] = useState(false);\n const [degradedReason, setDegradedReason] = useState<WorkspaceCaptureDegradedReason | null>(null);\n // Resolved from the FIRST GET's top-level stats (before any manifest-URL hop),\n // so the dock can pick its default tab as early as possible. null until then.\n const [fileCount, setFileCount] = useState<number | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n // The highest revision ANNOUNCED on the event log — compared against the loaded\n // manifest's revision to compute `isStale` and to gate refreshes.\n const [announcedRevision, setAnnouncedRevision] = useState<number | null>(null);\n // State updates are asynchronous, so the previous session's capture still\n // exists during the first render after an identity switch. Tag it and hide it\n // synchronously until the new identity's request owns the state.\n const [stateIdentity, setStateIdentity] = useState(identityKey);\n\n // A generation counter fences a slow in-flight fetch against a newer one (or an\n // identity change) so a stale response can never overwrite fresher state.\n const generationRef = useRef(0);\n // Event sequence numbers are scoped to a session. Keeping this cursor across an\n // identity switch would discard the new session's low-numbered announcements.\n const lastSeqRef = useRef(0);\n\n const refresh = useCallback(async () => {\n if (!sessionId) return;\n const generation = (generationRef.current += 1);\n setStateIdentity(identityKey);\n setLoading(true);\n setError(null);\n try {\n const res: GetWorkspaceCaptureResponse = await client.getWorkspaceCapture(\n workspaceId,\n sessionId,\n );\n if (generationRef.current !== generation) return;\n if (!res.available) {\n setCapture(null);\n setAvailable(false);\n setFileCount(0);\n setDegradedReason(res.degradedReason ?? null);\n return;\n }\n setDegradedReason(null);\n // Resolve the changed-file count immediately from the response's stats — the\n // default-tab signal must not wait on a >2MB manifest-URL hop.\n setFileCount(res.stats.fileCount);\n // Exactly one of manifest / manifestUrl is non-null (M2 contract). The inline\n // manifest is the <200ms common case; a >2MB manifest is a signed URL hop.\n let manifest = res.manifest;\n if (!manifest && res.manifestUrl) {\n const response = await fetch(res.manifestUrl.url, {\n signal: AbortSignal.timeout(MANIFEST_FETCH_TIMEOUT_MS),\n });\n if (generationRef.current !== generation) return;\n if (!response.ok)\n throw new Error(`workspace capture manifest fetch failed: ${response.status}`);\n manifest = (await response.json()) as WorkspaceCaptureManifest;\n if (generationRef.current !== generation) return;\n }\n if (!manifest) {\n // available:true but neither manifest nor a working URL — degrade, never crash.\n setCapture(null);\n setAvailable(false);\n return;\n }\n setCapture(manifest);\n setAvailable(true);\n // Fold the served revision into the announced high-water mark so a capture we\n // JUST loaded is never reported stale against an older announce.\n setAnnouncedRevision((prev) =>\n prev === null || manifest.revision > prev ? manifest.revision : prev,\n );\n } catch (cause) {\n if (generationRef.current !== generation) return;\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n if (generationRef.current === generation) setLoading(false);\n }\n }, [client, workspaceId, sessionId, identityKey]);\n\n // Mount fetch + reset on identity change.\n useEffect(() => {\n // Invalidate a request started for the previous identity before clearing its\n // state. The cleanup also fences a response that arrives after unmount.\n generationRef.current += 1;\n lastSeqRef.current = 0;\n setCapture(null);\n setAvailable(false);\n setDegradedReason(null);\n setFileCount(null);\n setAnnouncedRevision(null);\n setError(null);\n if (!enabled) {\n setLoading(false);\n return;\n }\n void refresh();\n return () => {\n generationRef.current += 1;\n };\n }, [enabled, refresh]);\n\n // Fold `workspace.revision.captured` announcements. A revision NEWER than the one\n // loaded bumps the announced high-water mark (→ isStale) and refreshes in the\n // background. The event is announce-only (metadata) — we still re-fetch the\n // manifest, since the payload carries no content.\n const events = options.events;\n useEffect(() => {\n if (!enabled || !events) return;\n let newest: number | null = null;\n for (const event of events) {\n if (event.sequence <= lastSeqRef.current) continue;\n if (event.type === REVISION_CAPTURED) {\n const payload = event.payload as WorkspaceRevisionCapturedPayload | null;\n if (payload && typeof payload === \"object\" && typeof payload.revision === \"number\") {\n newest = newest === null ? payload.revision : Math.max(newest, payload.revision);\n }\n } else if (event.type === REVISION_DEGRADED) {\n const payload = event.payload as WorkspaceRevisionDegradedPayload | null;\n if (payload && typeof payload === \"object\" && typeof payload.revision === \"number\") {\n newest = newest === null ? payload.revision : Math.max(newest, payload.revision);\n }\n }\n }\n for (const event of events)\n if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;\n if (newest === null) return;\n setAnnouncedRevision((prev) => (prev === null || newest > prev ? newest : prev));\n }, [enabled, events]);\n\n // A newer announced revision than the loaded manifest → refresh in the background.\n const identityMatches = enabled && stateIdentity === identityKey;\n const visibleCapture = identityMatches ? capture : null;\n const visibleAnnouncedRevision = identityMatches ? announcedRevision : null;\n const loadedRevision = visibleCapture?.revision ?? null;\n useEffect(() => {\n if (!enabled) return;\n if (visibleAnnouncedRevision === null) return;\n if (loadedRevision !== null && visibleAnnouncedRevision <= loadedRevision) return;\n // A newer capture exists than the one we hold (or we hold none) — pull it.\n void refresh();\n }, [enabled, visibleAnnouncedRevision, loadedRevision, refresh]);\n\n const isStale =\n loadedRevision !== null &&\n visibleAnnouncedRevision !== null &&\n visibleAnnouncedRevision > loadedRevision;\n\n return {\n capture: visibleCapture,\n revision: loadedRevision,\n capturedAt: visibleCapture?.capturedAt ?? null,\n available: identityMatches && available,\n degradedReason: identityMatches ? degradedReason : null,\n fileCount: identityMatches ? fileCount : null,\n isStale,\n loading: identityMatches && loading,\n error: identityMatches ? error : null,\n refresh,\n };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\n\n/**\n * The wake-on-edit state machine (dossier §3 #5 / §10.4 / §12-C). M3 OWNS this\n * logic; M5 renders it. States are explicit and exhaustive:\n *\n * viewing-cold — cold snapshot open, no local edits (editable, cloud).\n * buffering — local edits buffered; the box is not warm and no warm is\n * yet in flight (the host has not attached).\n * warming — edits buffered; the box is actively coming up (the host\n * attached a viewer in response to `wantsWarm`).\n * flushing — the box is warm; the guarded write is in flight.\n * flushed — the buffer was written to the live box.\n * conflict — the live file diverged from the captured base between\n * capture and flush; NO write was issued (C2).\n * readonly-offline — a self-hosted machine that is offline; read-only, no wake.\n */\nexport type WorkspaceEditState =\n | \"viewing-cold\"\n | \"buffering\"\n | \"warming\"\n | \"flushing\"\n | \"flushed\"\n | \"conflict\"\n | \"readonly-offline\";\n\nexport type WorkspaceEditConflict = {\n path: string;\n /** The capture-served content the edit was based on. */\n base: string;\n /** The live content found on the box at flush time (what would be overwritten). */\n live: string;\n};\n\nexport type UseWorkspaceEditOptions = ClientOverride & {\n /** The file being edited (workspace-relative). null disables the machine. */\n path?: string | null | undefined;\n /** The capture-served content loaded into the editor — the flush base (C2). */\n baseContent?: string | null | undefined;\n /** `capabilities.liveness` — \"warm\" | \"draining\" | \"cold\". Drives the flush. */\n liveness?: string | undefined;\n /** True while the host is actively warming the box (attach in flight, not warm\n * yet) — lifts `buffering` → `warming`. The host sets this after acting on\n * `wantsWarm` (e.g. flipping `attachFiles` on `useSessionCapabilities`). */\n warming?: boolean | undefined;\n /** A self-hosted machine that is OFFLINE: read-only, no remote wake possible. */\n offline?: boolean | undefined;\n /** Called once when the first cold edit needs the box warmed — the host wires\n * this to its liveness primitive (flip `attachFiles`/`attachViewer`). */\n onWarmRequested?: (() => void) | undefined;\n};\n\nexport type UseWorkspaceEditResult = {\n state: WorkspaceEditState;\n /** The editor should be read-only (self-hosted offline). */\n readOnly: boolean;\n /** The current buffered content (null = no local edit yet). */\n buffer: string | null;\n /** The host should warm the box (flip its attach primitive). Latches true from\n * the first cold edit until the buffer flushes or is discarded. */\n wantsWarm: boolean;\n /** Record an edit from the editor (idempotent per identical content). */\n edit: (content: string) => void;\n /** The conflict detail when `state === \"conflict\"`. */\n conflict: WorkspaceEditConflict | null;\n /** Flush the buffer regardless of the base guard (the user chose \"overwrite\"\n * from the conflict bar). Writes last-writer-wins. */\n overwrite: () => Promise<void>;\n /** Drop the local buffer and return to viewing the snapshot. */\n discard: () => void;\n error: Error | null;\n};\n\nfunction isLive(liveness: string | undefined): boolean {\n return liveness === \"warm\" || liveness === \"draining\";\n}\n\n/**\n * Cold-editing without a spinner: the editor opens instantly from the capture,\n * the first keystroke buffers locally AND signals the host to warm the box, and on\n * warm the buffer flushes IF the live file still matches the captured base — else a\n * non-blocking conflict is surfaced and nothing is overwritten (dossier §12-C2).\n *\n * The base guard compares the live content at flush time against `baseContent`\n * (the exact bytes the editor loaded). This is equivalent to the sha256 compare\n * the dossier describes — M1 leaves `baseHash` null, so the loaded content IS the\n * authoritative base — and avoids async Web Crypto in the render path.\n */\nexport function useWorkspaceEdit(\n sessionId: string | null | undefined,\n options: UseWorkspaceEditOptions = {},\n): UseWorkspaceEditResult {\n const { client, workspaceId } = useOpenGeni(options);\n const path = options.path ?? null;\n const baseContent = options.baseContent ?? null;\n const live = isLive(options.liveness);\n const offline = options.offline === true;\n\n const [buffer, setBuffer] = useState<string | null>(null);\n const [wantsWarm, setWantsWarm] = useState(false);\n const [flush, setFlush] = useState<\"idle\" | \"flushing\" | \"flushed\" | \"conflict\">(\"idle\");\n const [conflict, setConflict] = useState<WorkspaceEditConflict | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const onWarmRequested = options.onWarmRequested;\n const bufferRef = useRef<string | null>(null);\n bufferRef.current = buffer;\n // Guards a single in-flight flush against re-entry (liveness can re-render).\n const flushingRef = useRef(false);\n\n // Reset the machine when the edited file (or session) changes.\n useEffect(() => {\n setBuffer(null);\n setWantsWarm(false);\n setFlush(\"idle\");\n setConflict(null);\n setError(null);\n flushingRef.current = false;\n }, [sessionId, path]);\n\n const edit = useCallback(\n (content: string) => {\n if (offline) return; // read-only — no buffering, no wake.\n setBuffer((prev) => (prev === content ? prev : content));\n // Any new edit invalidates a prior flushed/conflict resolution.\n setFlush((prev) => (prev === \"flushing\" ? prev : \"idle\"));\n setConflict(null);\n if (!live) {\n // First cold edit signals the host to warm the box (once).\n setWantsWarm((prev) => {\n if (!prev) onWarmRequested?.();\n return true;\n });\n }\n },\n [offline, live, onWarmRequested],\n );\n\n const doFlush = useCallback(\n async (force: boolean) => {\n if (!sessionId || !path) return;\n const content = bufferRef.current;\n if (content === null) return;\n if (flushingRef.current) return;\n flushingRef.current = true;\n setFlush(\"flushing\");\n setError(null);\n try {\n if (!force) {\n // Base guard: re-read the live file and compare to the captured base. A\n // divergence means the box changed under us — surface a conflict, write\n // NOTHING (C2).\n const liveRead = await client.fsRead(workspaceId, sessionId, { path });\n const liveContent = liveRead.content;\n if (baseContent !== null && liveContent !== baseContent) {\n setConflict({ path, base: baseContent, live: liveContent });\n setFlush(\"conflict\");\n return;\n }\n }\n await client.fsWrite(workspaceId, sessionId, { path, content, overwrite: true });\n setConflict(null);\n setFlush(\"flushed\");\n setWantsWarm(false);\n } catch (cause) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n // Leave the buffer intact so the user can retry; fall back to buffering.\n setFlush(\"idle\");\n } finally {\n flushingRef.current = false;\n }\n },\n [client, workspaceId, sessionId, path, baseContent],\n );\n\n // Auto-flush once the box is warm and a buffer is pending (the wake completed).\n useEffect(() => {\n if (offline) return;\n if (!live) return;\n if (buffer === null) return;\n if (flush === \"flushed\" || flush === \"conflict\" || flush === \"flushing\") return;\n void doFlush(false);\n }, [offline, live, buffer, flush, doFlush]);\n\n const overwrite = useCallback(async () => {\n await doFlush(true);\n }, [doFlush]);\n\n const discard = useCallback(() => {\n setBuffer(null);\n setWantsWarm(false);\n setFlush(\"idle\");\n setConflict(null);\n setError(null);\n }, []);\n\n // Derive the exhaustive public state.\n let state: WorkspaceEditState;\n if (offline) {\n state = \"readonly-offline\";\n } else if (flush === \"flushing\") {\n state = \"flushing\";\n } else if (flush === \"flushed\") {\n state = \"flushed\";\n } else if (flush === \"conflict\") {\n state = \"conflict\";\n } else if (buffer === null) {\n state = \"viewing-cold\";\n } else if (live) {\n // Warm with a pending buffer that hasn't entered flush yet — a transient tick\n // before the auto-flush effect runs.\n state = \"flushing\";\n } else if (options.warming === true) {\n state = \"warming\";\n } else {\n state = \"buffering\";\n }\n\n return {\n state,\n readOnly: offline,\n buffer,\n wantsWarm,\n edit,\n conflict,\n overwrite,\n discard,\n error,\n };\n}\n","import { useMemo } from \"react\";\nimport type { MachineState } from \"@opengeni/sdk\";\nimport type { SessionCapabilitiesState } from \"./use-session-capabilities\";\n\n/** The one truthful machine indicator (dossier §3 #10). Honest staleness beats\n * fake liveness: a cold/asleep box reads \"offline — as of <time>\", never \"live\". */\nexport type MachineChipState = \"live\" | \"waking\" | \"offline\";\n\nexport type MachineChip = {\n state: MachineChipState;\n /** A ready-to-render label (\"Live\" / \"Waking…\" / \"Offline — as of 3m ago\"). */\n label: string;\n /** The capture time backing an offline/stale label (ISO), or null. M4 may\n * reformat this; `label` already embeds a relative form. */\n asOf: string | null;\n};\n\nexport type DeriveMachineChipInput = {\n /** `capabilities.liveness` — \"warm\" | \"draining\" | \"cold\" (or null pre-negotiation). */\n liveness?: string | null | undefined;\n /** `useSessionCapabilities().state` — drives the \"waking\" (negotiating) read. */\n capabilitiesState?: SessionCapabilitiesState | null | undefined;\n /** The ACTIVE machine's connection state (from `useMachines`), when known. A\n * self-hosted machine that is `offline` cannot be remotely woken. */\n activeMachineState?: MachineState | null | undefined;\n /** Whether the active sandbox is a user-owned self-hosted machine (no remote wake). */\n activeIsSelfhosted?: boolean | undefined;\n /** An interaction (wake-on-edit, terminal focus) is actively warming the box. */\n wantsWarm?: boolean | undefined;\n /** The latest capture's `capturedAt` (ISO) — the \"as of <time>\" backing. */\n capturedAt?: string | null | undefined;\n /** Injectable clock for deterministic relative labels (defaults to Date.now). */\n now?: number | undefined;\n};\n\n/** Compact relative-time for the \"as of\" label. Pure, no Intl dependency. */\nexport function formatAsOf(capturedAt: string, now: number): string {\n const then = Date.parse(capturedAt);\n if (Number.isNaN(then)) return \"recently\";\n const seconds = Math.max(0, Math.round((now - then) / 1000));\n if (seconds < 45) return \"just now\";\n const minutes = Math.round(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.round(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.round(hours / 24);\n return `${days}d ago`;\n}\n\n/**\n * Derive the machine-state chip from the live capability/liveness surface, the\n * active machine's connection state, and the latest capture time. PURE (M4 renders\n * it; the whole point is a deterministic, testable projection).\n *\n * Precedence:\n * 1. warm/draining lease → **live** (a warm box always wins).\n * 2. actively warming (negotiating, wake-on-edit, or a reconnecting/enrolling\n * machine) → **waking**.\n * 3. everything else (a cold/asleep box, a self-hosted machine that's offline,\n * an error) → **offline**, labelled \"as of <capture time>\".\n */\nexport function deriveMachineChip(input: DeriveMachineChipInput): MachineChip {\n const now = input.now ?? Date.now();\n const asOf = input.capturedAt ?? null;\n const offlineLabel = asOf ? `Offline — as of ${formatAsOf(asOf, now)}` : \"Offline\";\n\n // 1. A warm (or draining) lease is live regardless of anything else.\n if (input.liveness === \"warm\" || input.liveness === \"draining\") {\n return { state: \"live\", label: \"Live\", asOf: null };\n }\n\n // A self-hosted machine that reports offline cannot be woken remotely — honest\n // \"offline\", never \"waking\" (dossier §3 #5 / #10).\n const selfhostedOffline =\n input.activeIsSelfhosted === true && input.activeMachineState === \"offline\";\n\n // 2. Actively coming up: negotiation in flight, an edit/terminal is warming, or\n // the active machine is (re)connecting. Never when self-hosted is hard-offline.\n const machineWarming =\n input.activeMachineState === \"reconnecting\" || input.activeMachineState === \"enrolling\";\n if (\n !selfhostedOffline &&\n (input.capabilitiesState === \"negotiating\" || input.wantsWarm === true || machineWarming)\n ) {\n return { state: \"waking\", label: \"Waking…\", asOf };\n }\n\n // 3. Cold / asleep / offline / error → honest stale label.\n return { state: \"offline\", label: offlineLabel, asOf };\n}\n\nexport type UseMachineChipOptions = DeriveMachineChipInput;\n\n/**\n * Thin memoized wrapper over `deriveMachineChip` for the dock header (M4). The\n * dock already runs `useSessionCapabilities` + `useMachines` + `useWorkspace\n * capture`; it feeds their `liveness` / `state` / active-machine state /\n * `capturedAt` here. Pass a periodically-updated `now` if you want the relative\n * \"as of\" label to tick.\n */\nexport function useMachineChip(input: UseMachineChipOptions): MachineChip {\n const {\n liveness,\n capabilitiesState,\n activeMachineState,\n activeIsSelfhosted,\n wantsWarm,\n capturedAt,\n now,\n } = input;\n return useMemo(\n () =>\n deriveMachineChip({\n liveness,\n capabilitiesState,\n activeMachineState,\n activeIsSelfhosted,\n wantsWarm,\n capturedAt,\n now,\n }),\n // Depend on the primitive fields (not the object identity) so a caller passing\n // a fresh object each render doesn't recompute needlessly.\n [\n liveness,\n capabilitiesState,\n activeMachineState,\n activeIsSelfhosted,\n wantsWarm,\n capturedAt,\n now,\n ],\n );\n}\n","import type { SessionEvent } from \"@opengeni/sdk\";\n\n/* ----------------------------------------------------------------------------\n Pending-approvals projection\n\n `session.requiresAction` events live forever in the durable log, so a\n console that replays the log from sequence 0 must not render every\n historical approval as actionable. `projectPendingApprovals` folds the\n ordered event log into the approvals that are still undecided *now*:\n\n - `session.requiresAction` replaces the pending set with the payload's\n approvals (the producer always emits the full currently-pending set, so\n re-emission after a worker re-dispatch cannot duplicate cards);\n - `user.approvalDecision` subtracts the decided approval;\n - the owning turn finishing (`turn.completed`/`turn.failed`/\n `turn.cancelled`) clears the set — whatever was pending died with the\n turn. A `turn.cancelled` for a *different* turn (deleting a queued turn\n while the session waits on an approval) leaves the set alone.\n\n Pure function — same events in, same approvals out — so approve-then-reload\n projects to an empty set instead of a zombie Approve button.\n -------------------------------------------------------------------------- */\n\nexport type PendingApproval = {\n /** The id to send back via `user.approvalDecision` (`approvalId`). */\n id: string;\n /** Tool/function name awaiting the decision. */\n name: string;\n arguments?: unknown;\n /** The raw approval entry from the `session.requiresAction` payload. */\n raw?: unknown;\n};\n\n/** The approvals carried by one `session.requiresAction` payload. */\nexport function approvalsFromRequiresAction(payload: unknown): PendingApproval[] {\n const approvals =\n payload && typeof payload === \"object\"\n ? (payload as { approvals?: unknown }).approvals\n : undefined;\n if (!Array.isArray(approvals)) {\n return [];\n }\n return approvals.map((approval, index) => {\n const raw = (approval && typeof approval === \"object\" ? approval : {}) as Record<\n string,\n unknown\n >;\n const rawItem =\n raw.rawItem && typeof raw.rawItem === \"object\"\n ? (raw.rawItem as Record<string, unknown>)\n : {};\n return {\n id: String(raw.id ?? raw.callId ?? rawItem.callId ?? index),\n name: String(raw.name ?? \"approval\"),\n arguments: raw.arguments,\n raw: approval,\n };\n });\n}\n\n/** The approvals still awaiting a decision after replaying `events` in order. */\nexport function projectPendingApprovals(events: SessionEvent[]): PendingApproval[] {\n let pending: PendingApproval[] = [];\n let owningTurnId: string | null = null;\n for (const event of events) {\n switch (event.type) {\n case \"session.requiresAction\": {\n pending = approvalsFromRequiresAction(event.payload);\n owningTurnId = event.turnId ?? null;\n break;\n }\n case \"user.approvalDecision\": {\n const payload =\n event.payload && typeof event.payload === \"object\"\n ? (event.payload as { approvalId?: unknown })\n : {};\n if (typeof payload.approvalId === \"string\") {\n pending = pending.filter((approval) => approval.id !== payload.approvalId);\n }\n break;\n }\n case \"turn.completed\":\n case \"turn.failed\":\n case \"turn.cancelled\": {\n // Scope clearing to the turn that raised the approvals when both\n // sides carry a turn id; clear conservatively when either is unknown.\n if (owningTurnId === null || event.turnId == null || event.turnId === owningTurnId) {\n pending = [];\n owningTurnId = null;\n }\n break;\n }\n default:\n break;\n }\n }\n return pending;\n}\n","import type { Permission } from \"@opengeni/sdk\";\nimport type { CommandContext, SlashArg, SlashCommand } from \"./types\";\n\n/**\n * Parse a composer value into a command name + the rest. A command is\n * recognized ONLY when the value's first character is \"/\" (the start token);\n * anything else is plain chat and returns null.\n *\n * \"/cl\" -> { name: \"cl\", rest: \"\", hasTrailingSpace: false }\n * \"/goal \" -> { name: \"goal\", rest: \"\", hasTrailingSpace: true }\n * \"/goal pause\"-> { name: \"goal\", rest: \"pause\", hasTrailingSpace: false }\n */\nexport type ParsedCommandLine = {\n name: string;\n rest: string;\n /** True when the name token is closed by a space — arg-hint mode. */\n hasTrailingSpace: boolean;\n args: string[];\n};\n\nexport function parseCommandLine(value: string): ParsedCommandLine | null {\n if (value[0] !== \"/\") {\n return null;\n }\n const body = value.slice(1);\n const firstSpace = body.indexOf(\" \");\n if (firstSpace === -1) {\n return { name: body, rest: \"\", hasTrailingSpace: false, args: [] };\n }\n const name = body.slice(0, firstSpace);\n const rest = body.slice(firstSpace + 1);\n return {\n name,\n rest,\n hasTrailingSpace: true,\n args: rest.split(/\\s+/).filter((token) => token.length > 0),\n };\n}\n\nconst PERMISSION_SUPERUSER: Permission = \"workspace:admin\";\n\n/** Whether the operator's permission set satisfies a command's gate. */\nexport function hasPermission(\n required: Permission | undefined,\n permissions: Permission[],\n): boolean {\n if (!required) {\n return true;\n }\n return permissions.includes(required) || permissions.includes(PERMISSION_SUPERUSER);\n}\n\n/** Match a command (by name or alias) against the value. */\nexport function matchCommand(\n commands: readonly SlashCommand[],\n value: string,\n): SlashCommand | null {\n const parsed = parseCommandLine(value);\n if (!parsed) {\n return null;\n }\n const token = parsed.name.toLowerCase();\n return (\n commands.find((command) => command.name === token || command.aliases?.includes(token)) ?? null\n );\n}\n\ntype FilterCtx = Pick<CommandContext, \"sessionId\" | \"status\" | \"permissions\">;\n\n/**\n * The commands visible for the current token + context. Permission-absent and\n * `available()===false` commands are dropped entirely (a gated command is never\n * shown, not shown-disabled). Filtering is a prefix match on name/alias.\n */\nexport function filterCommands(\n commands: readonly SlashCommand[],\n token: string,\n ctx: FilterCtx,\n): SlashCommand[] {\n const needle = token.toLowerCase();\n return commands.filter((command) => {\n if (!hasPermission(command.permission, ctx.permissions)) {\n return false;\n }\n if (command.available && !command.available(ctx)) {\n return false;\n }\n if (needle.length === 0) {\n return true;\n }\n return (\n command.name.startsWith(needle) ||\n (command.aliases?.some((alias) => alias.startsWith(needle)) ?? false)\n );\n });\n}\n\n/** Render a command's arg hint for the palette footer / help, e.g. \"<pause|resume>\". */\nexport function argHint(args: readonly SlashArg[] | undefined): string {\n if (!args || args.length === 0) {\n return \"\";\n }\n return args\n .map((arg) => {\n const label = arg.oneOf ? arg.oneOf.join(\"|\") : arg.name;\n return arg.required ? `<${label}>` : `[${label}]`;\n })\n .join(\" \");\n}\n\n/** The first required arg that has not yet been supplied, if any. */\nexport function firstMissingRequiredArg(command: SlashCommand, args: string[]): SlashArg | null {\n const required = (command.args ?? []).filter((arg) => arg.required);\n for (let i = 0; i < required.length; i += 1) {\n const value = args[i];\n if (value === undefined || value.length === 0) {\n return required[i] ?? null;\n }\n }\n return null;\n}\n\nfunction requireSession(ctx: CommandContext): string {\n if (!ctx.sessionId) {\n throw new Error(\"No active session yet — start a session first.\");\n }\n return ctx.sessionId;\n}\n\nconst hasSession = (ctx: FilterCtx): boolean => ctx.sessionId !== null;\n\n/**\n * The default command set. Adding a command is one object literal here; the\n * palette list, filter, arg-hint footer, and /help all render from this array.\n * Apps concat their own commands via the ChatComposer `commands` prop.\n */\nexport const defaultCommands: readonly SlashCommand[] = [\n {\n name: \"help\",\n aliases: [\"?\"],\n description: \"Show available commands.\",\n run: (_args, ctx) => {\n ctx.openHelp();\n return { status: \"ok\" };\n },\n },\n {\n name: \"clear-view\",\n description: \"Clear the local timeline view (this device only; no server change).\",\n run: (_args, ctx) => {\n // clearView() reports whether the host actually wired a view-reset. If it\n // didn't (the console surface has no resettable local timeline), reporting\n // \"Local view cleared.\" would be a false success — return an honest error\n // instead so the operator isn't told something happened when nothing did.\n const cleared = ctx.clearView();\n if (!cleared) {\n return {\n status: \"error\",\n message: \"This view can't be cleared here (no local timeline to reset).\",\n };\n }\n return { status: \"ok\", message: \"Local view cleared.\" };\n },\n },\n {\n name: \"goal\",\n description: \"Pause or resume the session's goal loop.\",\n permission: \"sessions:control\",\n available: hasSession,\n args: [\n { name: \"action\", required: true, oneOf: [\"pause\", \"resume\"], description: \"pause | resume\" },\n ],\n run: async (args, ctx) => {\n const sessionId = requireSession(ctx);\n const action = args[0];\n if (action !== \"pause\" && action !== \"resume\") {\n return { status: \"error\", message: \"Usage: /goal pause | /goal resume\" };\n }\n try {\n await ctx.client.updateGoal(ctx.workspaceId, sessionId, {\n status: action === \"pause\" ? \"paused\" : \"active\",\n });\n return { status: \"ok\", message: action === \"pause\" ? \"Goal paused.\" : \"Goal resumed.\" };\n } catch (cause) {\n return { status: \"error\", message: goalErrorMessage(cause, action) };\n }\n },\n },\n {\n name: \"compact\",\n description: \"Compact the conversation context now.\",\n permission: \"sessions:control\",\n available: hasSession,\n run: async (_args, ctx) => {\n const sessionId = requireSession(ctx);\n try {\n const result = await ctx.client.compactSessionContext(ctx.workspaceId, sessionId);\n return { status: \"ok\", message: result.message };\n } catch (cause) {\n return { status: \"error\", message: errorMessage(cause) ?? \"Could not compact context.\" };\n }\n },\n },\n {\n name: \"clear\",\n description: \"Clear the conversation context (destructive; audit-preserved).\",\n permission: \"sessions:control\",\n danger: true,\n available: hasSession,\n run: async (_args, ctx) => {\n const sessionId = requireSession(ctx);\n const confirmed = await ctx.confirm();\n if (!confirmed) {\n // Canceled: no error, but keep the \"/clear\" draft so the operator who\n // backed out doesn't silently lose what they typed.\n return { status: \"ok\", keepDraft: true };\n }\n try {\n await ctx.client.clearSessionContext(ctx.workspaceId, sessionId);\n return { status: \"ok\", message: \"Context cleared.\" };\n } catch (cause) {\n return { status: \"error\", message: clearErrorMessage(cause) };\n }\n },\n },\n];\n\nfunction errorMessage(cause: unknown): string | undefined {\n if (\n cause &&\n typeof cause === \"object\" &&\n \"message\" in cause &&\n typeof (cause as { message?: unknown }).message === \"string\"\n ) {\n return (cause as { message: string }).message;\n }\n return undefined;\n}\n\nfunction statusCode(cause: unknown): number | undefined {\n if (\n cause &&\n typeof cause === \"object\" &&\n \"status\" in cause &&\n typeof (cause as { status?: unknown }).status === \"number\"\n ) {\n return (cause as { status: number }).status;\n }\n return undefined;\n}\n\nfunction goalErrorMessage(cause: unknown, action: \"pause\" | \"resume\"): string {\n const code = statusCode(cause);\n if (code === 404) {\n return \"This session has no goal to control.\";\n }\n if (code === 409) {\n return action === \"resume\"\n ? \"Only a paused goal can be resumed.\"\n : \"Goal is already in a terminal state.\";\n }\n return errorMessage(cause) ?? `Could not ${action} the goal.`;\n}\n\nfunction clearErrorMessage(cause: unknown): string {\n if (statusCode(cause) === 409) {\n return \"Pause the session and wait for the current inference to settle, then clear context.\";\n }\n return errorMessage(cause) ?? \"Could not clear context.\";\n}\n","import type { KeyboardEvent } from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n argHint,\n filterCommands,\n firstMissingRequiredArg,\n matchCommand,\n parseCommandLine,\n} from \"../commands/registry\";\nimport type { CommandContext, SlashCommand } from \"../commands/types\";\n\n/**\n * Context the composer supplies for command execution and visibility. The\n * composer owns the UI affordances (notice/openHelp/clearView/confirm), so they\n * are NOT part of this slice — the hook closes over them via `handlers`.\n */\nexport type SlashCommandContext = Pick<\n CommandContext,\n \"client\" | \"workspaceId\" | \"sessionId\" | \"status\" | \"permissions\"\n>;\n\n/**\n * UI affordances the composer supplies. `confirm` differs from the registry-\n * facing {@link CommandContext.confirm} (which takes no args): the composer's\n * confirm receives the command being run so the confirm bar renders from that\n * exact command's identity. The hook bridges the two in {@link buildContext}.\n */\nexport type SlashCommandHandlers = Pick<CommandContext, \"notice\" | \"openHelp\" | \"clearView\"> & {\n confirm: (command: SlashCommand) => Promise<boolean>;\n};\n\nexport type ConfirmState = {\n command: SlashCommand;\n /** Resolve the pending confirm() promise. */\n resolve: (confirmed: boolean) => void;\n} | null;\n\nexport type UseSlashCommandsOptions = {\n commands: readonly SlashCommand[];\n context: SlashCommandContext | undefined;\n handlers: SlashCommandHandlers;\n /** The current composer draft. */\n value: string;\n /** Replace the composer draft (autocomplete writes through this). */\n setValue: (value: string) => void;\n};\n\nexport type UseSlashCommandsResult = {\n /** Whether the palette is open (a command token is being typed). */\n open: boolean;\n /**\n * Whether the draft is a slash-command attempt (matches a registered command)\n * — true even after Escape dismisses the popover. The composer blocks its send\n * path while this holds so a command can't be delivered to the agent as chat.\n */\n isCommandDraft: boolean;\n /** Commands shown for the current token + context, in display order. */\n items: SlashCommand[];\n /** Index into `items` of the highlighted row. */\n highlight: number;\n setHighlight: (index: number) => void;\n /** The matched command once the name is closed by a space (arg-hint mode). */\n activeCommand: SlashCommand | null;\n /** The arg hint string for the active command (footer), or \"\". */\n activeArgHint: string;\n /**\n * Key handler for the textarea. Returns true when it consumed the event\n * (the composer must then NOT run its send path). Only consumes while open.\n */\n onKeyDown: (event: KeyboardEvent<HTMLTextAreaElement>) => boolean;\n /** Run the highlighted command (or the active command in arg-hint mode). */\n runHighlighted: () => Promise<void>;\n /**\n * Run the command at an explicitly chosen index (a pointer click on a row).\n * Bypasses the exact-match token heuristic that runHighlighted uses for\n * keyboard Enter, so an explicit click always runs the clicked command.\n */\n runAt: (index: number) => Promise<void>;\n /** Autocomplete the highlighted command name + a trailing space. */\n autocompleteHighlighted: () => void;\n};\n\nexport function useSlashCommands(options: UseSlashCommandsOptions): UseSlashCommandsResult {\n const { commands, context, handlers, value, setValue } = options;\n const [highlight, setHighlight] = useState(0);\n // Escape closes the palette but keeps the draft. We remember the dismissed\n // value; any further edit (value !== dismissed) re-opens the palette.\n const [dismissedValue, setDismissedValue] = useState<string | null>(null);\n const dismissed = dismissedValue !== null && dismissedValue === value;\n\n // Whether the operator has explicitly arrow-navigated the highlight for the\n // CURRENT draft. When they have, Enter is an explicit choice of the\n // highlighted row — the exact-match token override must NOT hijack it (else\n // ArrowDown to /clear-view + Enter would still fire the destructive /clear,\n // since \"clear\" exact-matches the token). Reset whenever the draft changes.\n const navigatedRef = useRef(false);\n const navTokenRef = useRef(value);\n if (navTokenRef.current !== value) {\n navTokenRef.current = value;\n navigatedRef.current = false;\n }\n\n const parsed = useMemo(() => parseCommandLine(value), [value]);\n const filterCtx = useMemo(\n () => ({\n sessionId: context?.sessionId ?? null,\n status: context?.status ?? null,\n permissions: context?.permissions ?? [],\n }),\n [context?.sessionId, context?.status, context?.permissions],\n );\n\n // In arg-hint mode (\"/name \"), the list collapses to the matched command so\n // the palette shows just its arg hint; while typing the name it filters.\n const activeCommand = useMemo(() => {\n if (!parsed || !parsed.hasTrailingSpace) {\n return null;\n }\n return matchCommand(commands, value);\n }, [commands, value, parsed]);\n\n const items = useMemo(() => {\n if (!parsed) {\n return [];\n }\n if (activeCommand) {\n return [activeCommand];\n }\n return filterCommands(commands, parsed.name, filterCtx);\n }, [commands, parsed, activeCommand, filterCtx]);\n\n const open = parsed !== null && items.length > 0 && !dismissed;\n\n // Whether the current draft is a slash-command ATTEMPT that should be run via\n // the palette, never delivered to the agent as plain chat. True even when the\n // palette is dismissed (Escape) — the draft still starts with \"/\" and matches\n // a command, so the composer must block its send path (button + Enter) to keep\n // commands from leaking into the conversation as messages the model reads.\n const isCommandDraft = parsed !== null && items.length > 0;\n\n // Keep highlight in range as items change.\n const clampedHighlight = items.length === 0 ? 0 : Math.min(highlight, items.length - 1);\n\n const activeArgHint = activeCommand ? argHint(activeCommand.args) : \"\";\n\n // Build the context for a SPECIFIC command. The danger confirm() is bound to\n // that command so the confirm bar names the command actually about to run —\n // not whatever near-match happens to sit highlighted in the palette (e.g.\n // typing \"/clear\"+Enter runs the destructive `clear`, but `clear-view` sorts\n // first and would otherwise mislabel the bar as a harmless local-view reset).\n const buildContext = useCallback(\n (command: SlashCommand): CommandContext | null => {\n if (!context) {\n return null;\n }\n return { ...context, ...handlers, confirm: () => handlers.confirm(command) };\n },\n [context, handlers],\n );\n\n const execute = useCallback(\n async (command: SlashCommand, args: string[]): Promise<void> => {\n const ctx = buildContext(command);\n if (!ctx) {\n return;\n }\n try {\n const result = await command.run(args, ctx);\n if (result.message) {\n ctx.notice({ tone: result.status === \"ok\" ? \"ok\" : \"error\", message: result.message });\n }\n if (result.status === \"ok\" && !result.keepDraft) {\n setValue(\"\");\n }\n } catch (cause) {\n ctx.notice({ tone: \"error\", message: errorMessage(cause) });\n }\n },\n [buildContext, setValue],\n );\n\n const autocomplete = useCallback(\n (command: SlashCommand) => {\n setValue(`/${command.name} `);\n setHighlight(0);\n },\n [setValue],\n );\n\n const autocompleteHighlighted = useCallback(() => {\n const command = items[clampedHighlight];\n if (command) {\n autocomplete(command);\n }\n }, [items, clampedHighlight, autocomplete]);\n\n // Resolve a SPECIFIC, already-chosen command against the current draft, then\n // either autocomplete (name-only / required arg missing) or execute. This is\n // the shared core for both Enter (which first resolves WHICH command via the\n // exact-match heuristic) and a pointer click (which has ALREADY chosen the\n // command — the clicked row — and must not re-resolve to a near-match).\n const runResolved = useCallback(\n async (command: SlashCommand, executionOptions?: { explicit?: boolean }): Promise<void> => {\n if (!parsed) {\n return;\n }\n const explicit = executionOptions?.explicit ?? false;\n // Token-vs-command equality is case-insensitive (matching the registry's\n // matchCommand/filterCommands), so a fully-typed \"/Clear\" counts as having\n // named `clear` and runs rather than autocompleting.\n const nameMatchesToken =\n command.name === parsed.name.toLowerCase() ||\n (command.aliases?.includes(parsed.name.toLowerCase()) ?? false);\n // A name-only token whose name doesn't yet equal the resolved command (e.g.\n // \"/cl\" -> clear) first autocompletes so the operator sees the full name.\n // An EXPLICIT pointer click skips this: the operator already chose the row,\n // so clicking \"/clear-view\" (while the token is \"clear\") runs it outright\n // rather than merely filling the name and waiting for a second Enter.\n if (!explicit && !activeCommand && !nameMatchesToken && !parsed.hasTrailingSpace) {\n autocomplete(command);\n return;\n }\n // When the click resolves a different command than the typed token, the\n // typed token's tail isn't this command's args — run with no positional\n // args and let the required-arg guard below prompt for them via autocomplete.\n const args = nameMatchesToken || parsed.hasTrailingSpace ? parsed.args : [];\n const missing = firstMissingRequiredArg(command, args);\n if (missing) {\n // A required arg is absent: keep the palette open at the arg hint rather\n // than firing a half-formed command.\n if (!parsed.hasTrailingSpace) {\n autocomplete(command);\n }\n return;\n }\n await execute(command, args);\n },\n [parsed, activeCommand, autocomplete, execute],\n );\n\n const runHighlighted = useCallback(async (): Promise<void> => {\n if (!parsed) {\n return;\n }\n // If the operator has arrow-navigated, Enter is an explicit choice of the\n // highlighted row — run it directly, exactly like a click. This makes\n // /clear-view reachable via ArrowDown+Enter even when \"/clear\" is fully\n // typed (otherwise the exact-match override below would hijack it).\n if (navigatedRef.current && !activeCommand) {\n const highlighted = items[clampedHighlight];\n if (highlighted) {\n await runResolved(highlighted, { explicit: true });\n }\n return;\n }\n // Otherwise (no explicit navigation): when the typed token is an exact\n // command name (e.g. \"/clear\" while the longer \"/clear-view\" sits first in\n // the filtered list), Enter should run THAT command, not autocomplete the\n // highlighted near-match. Exact match wins over the highlight; otherwise use\n // the highlighted row. A pointer click goes through runAt, never here.\n // Compare case-insensitively, matching filterCommands/matchCommand, so a\n // fully-typed \"/Clear\" still resolves to the exact (destructive) clear\n // rather than the highlighted prefix near-match.\n const token = parsed.name.toLowerCase();\n const exact = items.find((item) => item.name === token || item.aliases?.includes(token));\n const command = activeCommand ?? exact ?? items[clampedHighlight];\n if (!command) {\n return;\n }\n await runResolved(command);\n }, [parsed, activeCommand, items, clampedHighlight, runResolved]);\n\n // Run the command at an EXPLICITLY chosen index (a pointer click on a palette\n // row). Unlike runHighlighted this does NOT apply the exact-match override:\n // clicking the harmless `/clear-view` row while the draft is \"/clear\" must run\n // clear-view, never the destructive `/clear` that exact-matches the token. The\n // operator's pointer is the selection; token-resolution heuristics don't apply.\n const runAt = useCallback(\n async (index: number): Promise<void> => {\n const command = items[index];\n if (!command) {\n return;\n }\n await runResolved(command, { explicit: true });\n },\n [items, runResolved],\n );\n\n // Track an in-flight run so Enter can't double-fire.\n const runningRef = useRef(false);\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLTextAreaElement>): boolean => {\n if (!open) {\n return false;\n }\n switch (event.key) {\n case \"ArrowDown\": {\n event.preventDefault();\n navigatedRef.current = true;\n setHighlight((current) =>\n items.length === 0 ? 0 : (Math.min(current, items.length - 1) + 1) % items.length,\n );\n return true;\n }\n case \"ArrowUp\": {\n event.preventDefault();\n navigatedRef.current = true;\n setHighlight((current) => {\n const base = Math.min(current, items.length - 1);\n return items.length === 0 ? 0 : (base - 1 + items.length) % items.length;\n });\n return true;\n }\n case \"Tab\": {\n event.preventDefault();\n autocompleteHighlighted();\n return true;\n }\n case \"Enter\": {\n if (event.shiftKey || event.nativeEvent?.isComposing) {\n return false;\n }\n event.preventDefault();\n if (runningRef.current) {\n return true;\n }\n runningRef.current = true;\n void runHighlighted().finally(() => {\n runningRef.current = false;\n });\n return true;\n }\n case \"Escape\": {\n event.preventDefault();\n // Close the palette but keep the draft intact. Remember the dismissed\n // value; the next edit re-opens (value !== dismissedValue).\n setDismissedValue(value);\n return true;\n }\n default:\n return false;\n }\n },\n [open, items, autocompleteHighlighted, runHighlighted, value],\n );\n\n return {\n open,\n isCommandDraft,\n items,\n highlight: clampedHighlight,\n setHighlight,\n activeCommand,\n activeArgHint,\n onKeyDown,\n runHighlighted,\n runAt,\n autocompleteHighlighted,\n };\n}\n\nfunction errorMessage(cause: unknown): string {\n if (cause instanceof Error) {\n return cause.message;\n }\n return String(cause);\n}\n","import { AnimatePresence, motion } from \"motion/react\";\nimport { argHint } from \"../commands/registry\";\nimport type { SlashCommand } from \"../commands/types\";\nimport { cn } from \"../lib/cn\";\n\nexport type CommandPaletteProps = {\n open: boolean;\n items: SlashCommand[];\n highlight: number;\n /** Hover/click selects a row. */\n onHighlight: (index: number) => void;\n /** Click runs the row (same path as Enter). */\n onRun: (index: number) => void;\n /** Footer arg hint shown in arg-hint mode (e.g. \"<pause|resume>\"). */\n argHintText: string;\n /** id used for aria-activedescendant wiring from the textarea. */\n listboxId: string;\n};\n\n/**\n * The slash-command palette: a popover anchored above the textarea, rendered\n * entirely from the filtered registry. Dark-first, Linear/Vercel-calm, using\n * the opengeni#46 design tokens. Full keyboard nav lives in useSlashCommands;\n * this component is presentational + aria.\n */\nexport function CommandPalette({\n open,\n items,\n highlight,\n onHighlight,\n onRun,\n argHintText,\n listboxId,\n}: CommandPaletteProps) {\n return (\n <AnimatePresence>\n {open ? (\n <motion.div\n initial={{ opacity: 0, y: 6, scale: 0.99 }}\n animate={{ opacity: 1, y: 0, scale: 1 }}\n exit={{ opacity: 0, y: 6, scale: 0.99 }}\n transition={{ duration: 0.13, ease: \"easeOut\" }}\n className={cn(\n \"absolute bottom-full left-0 right-0 z-20 mb-2 overflow-hidden\",\n \"rounded-og-lg border border-og-border bg-og-surface-2 shadow-og-sm\",\n )}\n >\n <ul\n id={listboxId}\n role=\"listbox\"\n aria-label=\"Slash commands\"\n className=\"max-h-72 overflow-y-auto py-1\"\n >\n {items.map((command, index) => {\n const selected = index === highlight;\n const hint = argHint(command.args);\n return (\n <li\n key={command.name}\n id={`${listboxId}-option-${index}`}\n role=\"option\"\n aria-selected={selected}\n onMouseEnter={() => onHighlight(index)}\n onMouseDown={(event) => {\n // Keep textarea focus; run on click.\n event.preventDefault();\n onRun(index);\n }}\n className={cn(\n \"mx-1 flex cursor-pointer items-center gap-2 rounded-og-md px-2.5 py-1.5\",\n \"transition-colors duration-100\",\n selected\n ? \"bg-og-accent/15 text-og-fg\"\n : \"text-og-fg-muted hover:bg-og-surface-3\",\n )}\n >\n <span className=\"flex min-w-0 items-baseline gap-1.5\">\n <span\n className={cn(\n \"font-mono text-[13px]\",\n selected ? \"text-og-accent\" : \"text-og-fg\",\n )}\n >\n /{command.name}\n </span>\n {hint ? (\n <span className=\"truncate font-mono text-[11px] text-og-fg-subtle\">\n {hint}\n </span>\n ) : null}\n </span>\n <span className=\"ml-auto flex items-center gap-1.5\">\n {command.danger ? (\n <span className=\"rounded-og-xs bg-og-status-failed/15 px-1 text-[10px] uppercase tracking-wide text-og-status-failed\">\n danger\n </span>\n ) : null}\n <span className=\"truncate text-[12px] text-og-fg-subtle max-sm:hidden\">\n {command.description}\n </span>\n </span>\n </li>\n );\n })}\n </ul>\n {argHintText ? (\n <div className=\"border-t border-og-border px-3 py-1.5 font-mono text-[11px] text-og-fg-subtle\">\n {argHintText}\n </div>\n ) : null}\n </motion.div>\n ) : null}\n </AnimatePresence>\n );\n}\n","import type { ClientModel, SessionStatus } from \"@opengeni/sdk\";\nimport {\n ArrowUpIcon,\n FileIcon,\n ImageIcon,\n LoaderCircleIcon,\n PaperclipIcon,\n PlayIcon,\n RotateCwIcon,\n SquareIcon,\n XIcon,\n} from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport {\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type ClipboardEvent,\n type DragEvent,\n type KeyboardEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport { argHint } from \"../commands/registry\";\nimport type { Notice, SlashCommand } from \"../commands/types\";\nimport type { ComposerState } from \"../hooks/use-composer\";\nimport { composerModeForKey, shouldSubmitOnKey } from \"../hooks/use-composer\";\nimport type { UseFileAttachmentsResult } from \"../hooks/use-file-attachments\";\nimport { defaultCommands } from \"../commands/registry\";\nimport {\n useSlashCommands,\n type ConfirmState,\n type SlashCommandContext,\n} from \"../hooks/use-slash-commands\";\nimport { cn } from \"../lib/cn\";\nimport { formatBytes } from \"../lib/format\";\nimport { CommandPalette } from \"./command-palette\";\nimport { ModelPicker } from \"./model-picker\";\n\nexport type ChatComposerProps = {\n composer: ComposerState;\n /** Current session status; shows the stop control while a turn runs. */\n status?: SessionStatus | null | undefined;\n placeholder?: string | undefined;\n disabled?: boolean | undefined;\n autoFocus?: boolean | undefined;\n /** Replaces the default keyboard hint under the field. */\n hint?: string | undefined;\n /** App controls (model picker, attach button, ...) in the footer row, replacing the hint. */\n controlsStart?: ReactNode | undefined;\n /** Content rendered above the textarea, inside the field chrome (e.g. attachment chips). */\n header?: ReactNode | undefined;\n /** Paste hook on the textarea (e.g. paste-image-to-attach). */\n onPaste?: ((event: ClipboardEvent<HTMLTextAreaElement>) => void) | undefined;\n /**\n * Opt-in file attachments. When supplied (e.g. from {@link useFileAttachments}),\n * the composer renders a built-in attach button (prepended to `controlsStart`),\n * an attachment-chips strip (above the textarea, before any host `header`),\n * routes paste through `addFromPaste` (image/* filter lives in the hook), and\n * gates send while `uploading` so a message never departs without its files.\n * Absent → no attachment UI renders and the composer behaves exactly as before.\n */\n attachments?: UseFileAttachmentsResult | undefined;\n /**\n * Opt-in model picker. When supplied (e.g. from {@link useAvailableModels}),\n * the composer renders a {@link ModelPicker} at the start of `controlsStart`\n * so the operator can choose which host-exposed model serves the next message.\n * The host owns the selection (`selectedModel`/`onSelectModel`) and is\n * responsible for threading it into the composer's `sendExtras` (typically\n * `useComposer({ sendExtras: () => ({ model }) })`) so `composeSendInput`\n * carries it. Absent → no picker renders and the composer behaves as before.\n */\n models?: ClientModel[] | undefined;\n /** The currently selected model id (the picker's controlled value). */\n selectedModel?: string | undefined;\n /** Called with the chosen model id when the operator picks one. */\n onSelectModel?: ((modelId: string) => void) | undefined;\n className?: string | undefined;\n /**\n * Slash-command palette. Defaults to the built-in {@link defaultCommands};\n * apps concat their own. Backward-compatible: when `commandContext` is absent\n * the palette is inert and behavior is identical to before.\n */\n commands?: readonly SlashCommand[] | undefined;\n /**\n * Wiring the palette needs to run server commands and gate visibility. The\n * composer supplies notice/openHelp/clearView/confirm internally.\n */\n commandContext?: SlashCommandContext | undefined;\n /** Reset the local timeline view (the /clear-view command target). */\n onClearView?: (() => void) | undefined;\n};\n\nconst ACTIVE_STATUSES: ReadonlySet<SessionStatus> = new Set([\n \"queued\",\n \"running\",\n \"requires_action\",\n \"recovering\",\n \"waiting_capacity\",\n]);\n\n/**\n * The chat composer — the only human-to-agent input surface. Plain chat in,\n * everything else is the agent's job. Enter sends, Shift+Enter breaks the\n * line, and the stop control appears while a turn is running (sending while\n * running is legitimate steering, so send stays available too).\n *\n * Typing a leading \"/\" opens the slash-command palette — SESSION/OPERATOR\n * controls (clear, compact, pause goal, help), never a structured channel to\n * the agent. The palette is purely additive: with no `commandContext` it is\n * inert and the composer behaves exactly as before.\n */\nexport function ChatComposer({\n composer,\n status,\n placeholder,\n disabled,\n autoFocus,\n hint,\n controlsStart,\n header,\n onPaste,\n attachments,\n models,\n selectedModel,\n onSelectModel,\n className,\n commands = defaultCommands,\n commandContext,\n onClearView,\n}: ChatComposerProps) {\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n const fileInputRef = useRef<HTMLInputElement | null>(null);\n const active = status != null && ACTIVE_STATUSES.has(status);\n\n // Block sends while attachments are still uploading so a message never\n // departs without the files the user attached to it. This gates BOTH the\n // Enter-to-send path (which calls composer.send directly, bypassing canSend)\n // and the send button — dropping either path could ship a fileless message.\n const blockedByUpload = attachments?.uploading === true;\n\n // A ready attachment makes a file-only message (empty draft) sendable. The\n // composer (when wired with `sendExtras.resources`) already reflects this in\n // `canSend`; we OR it in here too so send-enablement is correct even for a\n // composer whose canSend doesn't know about attachments — and so this stays\n // the single home of the attachment send-gate.\n const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;\n // The send affordance: text OR a ready attachment, never mid-upload or mid-send.\n const canSend = (composer.canSend || hasReadyAttachment) && !blockedByUpload && !composer.sending;\n\n // Drag-and-drop file attach: only a drop target when `attachments` is wired,\n // and only reacts to drags that actually carry files (so it never hijacks\n // normal text drag/drop). `dragging` drives the drop overlay.\n const [dragging, setDragging] = useState(false);\n const dragCarriesFiles = (event: { dataTransfer: DataTransfer | null }): boolean =>\n event.dataTransfer != null && [...event.dataTransfer.types].includes(\"Files\");\n const handleDragOver = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (!attachments || !dragCarriesFiles(event)) {\n return;\n }\n // preventDefault marks this a valid drop target so the browser fires drop.\n event.preventDefault();\n setDragging(true);\n },\n [attachments],\n );\n const handleDragLeave = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (!attachments) {\n return;\n }\n // Ignore leaves bubbling from children: only clear when the pointer left\n // the composer bounds entirely (the related target is outside it).\n if (event.currentTarget.contains(event.relatedTarget as Node | null)) {\n return;\n }\n setDragging(false);\n },\n [attachments],\n );\n const handleDrop = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (!attachments || !dragCarriesFiles(event)) {\n return;\n }\n event.preventDefault();\n setDragging(false);\n // Same path the picker uses: addFiles accepts ALL files (no image filter).\n if (event.dataTransfer.files.length > 0) {\n attachments.addFiles(event.dataTransfer.files);\n }\n },\n [attachments],\n );\n\n const [notice, setNotice] = useState<Notice | null>(null);\n const [helpOpen, setHelpOpen] = useState(false);\n const [confirmState, setConfirmState] = useState<ConfirmState>(null);\n const listboxId = useId();\n\n const resize = useCallback(() => {\n const textarea = textareaRef.current;\n if (!textarea) {\n return;\n }\n textarea.style.height = \"0px\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, 220)}px`;\n }, []);\n\n useEffect(() => {\n resize();\n }, [composer.value, resize]);\n\n // The UI affordances commands reach: surface a notice, open the help panel,\n // reset the local view, and the danger confirm flow (resolves when the\n // operator confirms/cancels in the confirm bar).\n const handlers = useMemo(\n () => ({\n notice: (next: Notice) => {\n setNotice(next);\n composer.clearError();\n },\n openHelp: () => setHelpOpen(true),\n // Report whether a view-reset was actually wired by the host: with no\n // onClearView the command is a no-op and must say so (not a false success).\n clearView: () => {\n if (!onClearView) {\n return false;\n }\n onClearView();\n return true;\n },\n // The hook binds the command actually being run into confirm() (see\n // use-slash-commands buildContext), so the confirm bar renders from THAT\n // command — never a near-match highlighted in the palette. This is what\n // keeps the destructive /clear from being mislabeled as /clear-view.\n confirm: (command: SlashCommand) =>\n new Promise<boolean>((resolve) => {\n setConfirmState({\n command,\n resolve: (confirmed) => {\n setConfirmState(null);\n resolve(confirmed);\n },\n });\n }),\n }),\n [composer, onClearView],\n );\n\n const palette = useSlashCommands({\n commands,\n context: commandContext,\n handlers,\n value: composer.value,\n setValue: composer.setValue,\n });\n\n // The confirm bar renders from the command the hook is actually running —\n // carried into confirmState by handlers.confirm — NOT a near-match that\n // happens to be highlighted/active in the palette. (Re-deriving it from\n // palette.items[palette.highlight] mislabeled the destructive /clear as the\n // harmless /clear-view, since clear-view prefix-matches \"clear\" and sorts\n // first.)\n const pendingDangerCommand = confirmState ? confirmState.command : null;\n\n const paletteEnabled = commandContext !== undefined;\n\n // A slash-command draft must never be delivered to the agent as chat — it is\n // an operator control, not a message. The palette consumes Enter while open,\n // but after Escape the popover is closed yet the draft still matches a command;\n // block the send path (here and on the send button) so \"/clear\" can't be sent.\n const commandDraftBlocked = paletteEnabled && palette.isCommandDraft;\n\n const onKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {\n // Palette key handling runs FIRST and only when the palette is open; when\n // closed it returns false and the existing send path is untouched.\n if (paletteEnabled && palette.onKeyDown(event)) {\n return;\n }\n if (shouldSubmitOnKey(event)) {\n event.preventDefault();\n if (commandDraftBlocked) {\n // Dismissed palette + a \"/command\" draft: don't send it as chat. Nudge\n // the operator to re-open the palette (any edit re-opens it) or clear it.\n setNotice({\n tone: \"error\",\n message:\n \"That's a slash command — press Enter in the command list to run it, or edit the line to send a message.\",\n });\n return;\n }\n if (blockedByUpload) {\n // Files are still uploading: swallow the Enter so the message can't\n // depart without them. The send button is disabled in the same state.\n return;\n }\n void composer.send(undefined, composerModeForKey(event));\n }\n };\n\n // The host's onPaste still fires (model/tool/whatever paste handling); when\n // attachments are wired, also feed the clipboard through addFromPaste so the\n // image/* filter (owned by the hook) attaches pasted images.\n const handlePaste = useCallback(\n (event: ClipboardEvent<HTMLTextAreaElement>) => {\n onPaste?.(event);\n attachments?.addFromPaste(event);\n },\n [onPaste, attachments],\n );\n\n const handleFileChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n if (event.target.files) {\n attachments?.addFiles(event.target.files);\n }\n event.target.value = \"\";\n },\n [attachments],\n );\n\n const helpCommands = useMemo(\n () =>\n commands.filter((command) => {\n if (command.permission && commandContext) {\n const perms = commandContext.permissions;\n return perms.includes(command.permission) || perms.includes(\"workspace:admin\");\n }\n return true;\n }),\n [commands, commandContext],\n );\n\n const activeNotice =\n notice ??\n (composer.error\n ? {\n tone: \"error\" as const,\n message:\n composer.error.message || \"Sending failed — your draft is still here. Try again.\",\n }\n : null);\n\n return (\n // Respect the iOS home-indicator inset so the sticky composer never sits\n // under it (0 on non-notch devices and desktop, so it's inert there).\n <div\n className={cn(\"og-root\", className)}\n style={{ paddingBottom: \"env(safe-area-inset-bottom)\" }}\n >\n <div className=\"relative\">\n {paletteEnabled ? (\n <CommandPalette\n open={palette.open && confirmState === null}\n items={palette.items}\n highlight={palette.highlight}\n onHighlight={palette.setHighlight}\n onRun={(index) => {\n // Run the CLICKED row directly. We must not route a pointer click\n // through runHighlighted: its exact-match override would re-resolve\n // \"/clear\" to the destructive clear even when the operator clicked\n // the harmless clear-view row. runAt honors the explicit selection.\n palette.setHighlight(index);\n void palette.runAt(index);\n }}\n argHintText={palette.activeArgHint}\n listboxId={listboxId}\n />\n ) : null}\n <div\n // Drag-and-drop file attach lives on the field wrapper, but only when\n // `attachments` is wired — without it the composer is not a drop target\n // and behaves exactly as before.\n onDragOver={attachments ? handleDragOver : undefined}\n onDragLeave={attachments ? handleDragLeave : undefined}\n onDrop={attachments ? handleDrop : undefined}\n className={cn(\n \"relative rounded-og-lg border border-og-border bg-og-surface-1 shadow-og-sm\",\n \"transition-[border-color,box-shadow] duration-200\",\n \"focus-within:border-og-accent/60 focus-within:shadow-og-glow\",\n // While files are dragged over, swap to a dashed accent border to\n // signal a live drop target (the overlay carries the label).\n dragging && \"border-dashed border-og-accent\",\n )}\n >\n {dragging ? (\n <div\n aria-hidden\n className={cn(\n \"pointer-events-none absolute inset-0 z-10 flex items-center justify-center\",\n \"rounded-og-lg bg-og-surface-1/85 text-sm font-medium text-og-accent backdrop-blur-[1px]\",\n )}\n >\n <span className=\"inline-flex items-center gap-2\">\n <PaperclipIcon className=\"size-4\" />\n Drop files to attach\n </span>\n </div>\n ) : null}\n {attachments && attachments.attachments.length > 0 ? (\n <AttachmentChips\n attachments={attachments.attachments}\n onRemove={attachments.remove}\n onRetry={attachments.retry}\n />\n ) : null}\n {header}\n <textarea\n ref={textareaRef}\n rows={1}\n value={composer.value}\n onChange={(event) => composer.setValue(event.target.value)}\n onKeyDown={onKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder ?? \"Message the agent…\"}\n disabled={disabled}\n autoFocus={autoFocus}\n aria-label=\"Message the agent\"\n aria-keyshortcuts=\"Enter Meta+Enter Control+Enter Shift+Enter\"\n // A multiline textarea cannot legally take the combobox role or\n // aria-expanded. It remains a native textbox and advertises the\n // popup as list autocomplete; controls/active-descendant exist\n // only while the suggestion list itself exists.\n aria-autocomplete={paletteEnabled ? \"list\" : undefined}\n aria-controls={paletteEnabled && palette.open ? listboxId : undefined}\n aria-activedescendant={\n paletteEnabled && palette.open\n ? `${listboxId}-option-${palette.highlight}`\n : undefined\n }\n className={cn(\n // Font size steps up to 16px below `md` so iOS never zooms the\n // viewport on focus; desktop keeps the 15px og-md rhythm.\n \"block w-full resize-none bg-transparent px-4 pt-3.5 pb-1 text-base leading-6 md:text-og-md\",\n // The wrapper owns the whole-composer focus affordance (focus-within\n // border + soft glow). Suppress any self-scoped focus outline on the\n // textarea itself: `focus:outline-none` alone only sets outline-style\n // on `:focus`, which a host app's zero-specificity\n // `:where(...):focus-visible { outline: ... }` base rule re-applies as\n // the full shorthand. `focus-visible:outline-none` matches the same\n // state at class specificity and wins, so no second highlight (the\n // top-half rectangle bounded to the textarea box) ever paints.\n \"text-og-fg placeholder:text-og-fg-subtle focus:outline-none focus-visible:outline-none\",\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n )}\n />\n {confirmState && pendingDangerCommand ? (\n <ConfirmBar\n command={pendingDangerCommand}\n onCancel={() => confirmState.resolve(false)}\n onConfirm={() => confirmState.resolve(true)}\n returnFocusRef={textareaRef}\n />\n ) : (\n <div className=\"flex items-end gap-2 px-2.5 pb-2.5 pt-1\">\n {attachments || models || controlsStart ? (\n // The control group wraps onto extra rows when it can't fit\n // (narrow viewports) instead of clipping under the rounded\n // corner; send/stop stays anchored bottom-right (shrink-0).\n <span className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n {attachments ? (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n className=\"hidden\"\n onChange={handleFileChange}\n />\n <button\n type=\"button\"\n disabled={disabled === true}\n onClick={() => fileInputRef.current?.click()}\n aria-label=\"Attach files\"\n title=\"Attach files\"\n className={cn(\n \"inline-flex size-8 items-center justify-center rounded-og-md\",\n \"text-og-fg-muted transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg\",\n \"disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:size-11\",\n )}\n >\n <PaperclipIcon className=\"size-4\" />\n </button>\n </>\n ) : null}\n {models ? (\n <ModelPicker\n models={models}\n value={selectedModel}\n onChange={(modelId) => onSelectModel?.(modelId)}\n disabled={disabled === true}\n />\n ) : null}\n {controlsStart}\n </span>\n ) : (\n <span className=\"min-w-0 flex-1 px-1.5 text-og-xs text-og-fg-subtle max-sm:hidden\">\n {hint ?? \"Enter to queue · Cmd/Ctrl+Enter to steer · Shift+Enter for a new line\"}\n </span>\n )}\n <span className=\"ml-auto flex shrink-0 items-center gap-1.5\">\n <AnimatePresence initial={false}>\n {active || status === \"paused\" ? (\n <motion.button\n key=\"stop\"\n type=\"button\"\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() =>\n void (status === \"paused\" ? composer.resume() : composer.pause())\n }\n disabled={composer.pausing || composer.resuming}\n aria-label={status === \"paused\" ? \"Resume the session\" : \"Pause the session\"}\n title={\n status === \"paused\"\n ? \"Resume the current inference before queued prompts\"\n : \"Pause the session; queued prompts are preserved\"\n }\n className={cn(\n \"inline-flex size-8 items-center justify-center rounded-og-md border border-og-border pointer-coarse:size-11\",\n \"bg-og-surface-2 text-og-fg-muted transition-colors duration-150\",\n \"hover:border-og-status-failed/50 hover:text-og-status-failed\",\n \"disabled:opacity-50\",\n )}\n >\n {composer.pausing || composer.resuming ? (\n <LoaderCircleIcon className=\"size-3.5 animate-og-spin\" />\n ) : status === \"paused\" ? (\n <PlayIcon className=\"size-3.5 fill-current\" />\n ) : (\n <SquareIcon className=\"size-3 fill-current\" />\n )}\n </motion.button>\n ) : null}\n </AnimatePresence>\n <button\n type=\"button\"\n onClick={() => {\n if (blockedByUpload) {\n return;\n }\n void composer.send();\n }}\n disabled={!canSend || disabled === true || commandDraftBlocked}\n aria-label=\"Send message\"\n title=\"Queue message (Enter); steer with Cmd/Ctrl+Enter\"\n className={cn(\n \"inline-flex size-8 items-center justify-center rounded-og-md pointer-coarse:size-11\",\n \"bg-og-accent text-og-accent-fg shadow-og-sm\",\n \"transition-[background-color,transform,opacity] duration-150 ease-og-spring\",\n \"hover:bg-og-accent-strong active:scale-95\",\n \"disabled:cursor-not-allowed disabled:bg-og-surface-3 disabled:text-og-fg-subtle disabled:shadow-none\",\n )}\n >\n {composer.sending ? (\n <LoaderCircleIcon className=\"size-4 animate-og-spin\" />\n ) : (\n <ArrowUpIcon className=\"size-4\" />\n )}\n </button>\n </span>\n </div>\n )}\n </div>\n </div>\n <AnimatePresence>\n {helpOpen ? <HelpPanel commands={helpCommands} onClose={() => setHelpOpen(false)} /> : null}\n </AnimatePresence>\n <AnimatePresence>\n {activeNotice ? (\n <motion.p\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: \"auto\" }}\n exit={{ opacity: 0, height: 0 }}\n className={cn(\n \"overflow-hidden px-1 pt-1.5 text-xs\",\n activeNotice.tone === \"ok\" ? \"text-og-fg-muted\" : \"text-og-status-failed\",\n )}\n role={activeNotice.tone === \"error\" ? \"alert\" : \"status\"}\n onAnimationComplete={() => {\n if (activeNotice.tone === \"ok\") {\n // Auto-dismiss success notices after a beat.\n window.setTimeout(\n () => setNotice((current) => (current === activeNotice ? null : current)),\n 2400,\n );\n }\n }}\n >\n {activeNotice.message}\n </motion.p>\n ) : null}\n </AnimatePresence>\n </div>\n );\n}\n\n/**\n * The danger confirm bar — reuses og-status-failed tokens (like the stop\n * control). Inline (not a modal) but keyboard-complete: Escape cancels, focus\n * moves to the primary action when it appears and returns to the composer on\n * dismiss, and the primary button names the action rather than a bare \"Confirm\".\n */\nfunction ConfirmBar({\n command,\n onCancel,\n onConfirm,\n returnFocusRef,\n}: {\n command: SlashCommand;\n onCancel: () => void;\n onConfirm: () => void;\n /** Focus returns here when the bar dismisses (the composer textarea). */\n returnFocusRef?: RefObject<HTMLTextAreaElement | null> | undefined;\n}) {\n const confirmRef = useRef<HTMLButtonElement | null>(null);\n const descriptionId = useId();\n useEffect(() => {\n const returnTo = returnFocusRef?.current ?? null;\n confirmRef.current?.focus();\n return () => {\n returnTo?.focus();\n };\n }, [returnFocusRef]);\n return (\n <div\n role=\"alertdialog\"\n aria-label={`Confirm /${command.name}`}\n aria-describedby={descriptionId}\n data-testid=\"danger-confirm\"\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n onCancel();\n }\n }}\n className=\"flex items-end justify-between gap-2 px-2.5 pb-2.5 pt-1\"\n >\n <span id={descriptionId} className=\"min-w-0 flex-1 px-1.5 text-og-sm text-og-status-failed\">\n Run <span className=\"font-mono\">/{command.name}</span>? {command.description}\n </span>\n <span className=\"flex shrink-0 items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-og-md border border-og-border bg-og-surface-2 px-2.5 py-1 text-og-sm text-og-fg-muted hover:bg-og-surface-3 pointer-coarse:min-h-10\"\n >\n Cancel\n </button>\n <button\n ref={confirmRef}\n type=\"button\"\n onClick={onConfirm}\n className=\"rounded-og-md border border-og-status-failed/50 bg-og-status-failed/15 px-2.5 py-1 text-og-sm text-og-status-failed hover:bg-og-status-failed/25 pointer-coarse:min-h-10\"\n >\n Run /{command.name}\n </button>\n </span>\n </div>\n );\n}\n\n/**\n * The attachment-chips strip rendered above the textarea while files are\n * attached. Each chip shows an image preview (or a type icon), the filename,\n * an upload/size/failed status line, and a remove control. A failed upload\n * surfaces its actual error (inline, full text on hover via `title`) and offers\n * a retry alongside remove — a failed attachment never blocks send (only an\n * in-progress upload does), and removing it clears the way. Styled with the\n * package's og-* tokens so it themes in any consumer.\n */\nfunction AttachmentChips({\n attachments,\n onRemove,\n onRetry,\n}: {\n attachments: UseFileAttachmentsResult[\"attachments\"];\n onRemove: (id: string) => void;\n onRetry?: ((id: string) => void) | undefined;\n}) {\n return (\n <div className=\"flex flex-wrap gap-2 border-b border-og-border px-3 py-2\">\n {attachments.map((attachment) => {\n const failed = attachment.status === \"failed\";\n const statusText =\n attachment.status === \"uploading\"\n ? \"Uploading\"\n : failed\n ? attachment.error || \"Upload failed\"\n : formatBytes(attachment.sizeBytes);\n return (\n <div\n key={attachment.id}\n className={cn(\n \"flex min-w-0 max-w-[240px] items-center gap-2 rounded-og-md border px-2 py-1.5 text-og-sm\",\n failed\n ? \"border-og-status-failed/40 bg-og-status-failed/10\"\n : \"border-og-border bg-og-surface-2\",\n )}\n >\n {attachment.previewUrl ? (\n <img\n src={attachment.previewUrl}\n alt=\"\"\n className=\"size-8 shrink-0 rounded object-cover\"\n />\n ) : attachment.contentType.startsWith(\"image/\") ? (\n <ImageIcon className=\"size-4 shrink-0 text-og-fg-muted\" />\n ) : (\n <FileIcon className=\"size-4 shrink-0 text-og-fg-muted\" />\n )}\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate font-medium text-og-fg\">{attachment.name}</div>\n <div\n className={cn(\n \"truncate text-og-xs\",\n failed ? \"text-og-status-failed\" : \"text-og-fg-subtle\",\n )}\n title={failed ? statusText : undefined}\n >\n {statusText}\n </div>\n </div>\n {attachment.status === \"uploading\" ? (\n <LoaderCircleIcon className=\"size-3.5 shrink-0 animate-og-spin\" />\n ) : null}\n {failed && onRetry ? (\n <button\n type=\"button\"\n onClick={() => onRetry(attachment.id)}\n className=\"shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-10\"\n aria-label={`Retry ${attachment.name}`}\n title=\"Retry upload\"\n >\n <RotateCwIcon className=\"size-3.5\" />\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={() => onRemove(attachment.id)}\n className=\"shrink-0 rounded-og-xs p-1 text-og-fg-muted hover:bg-og-surface-1 hover:text-og-fg pointer-coarse:size-10\"\n aria-label={`Remove ${attachment.name}`}\n >\n <XIcon className=\"size-3.5\" />\n </button>\n </div>\n );\n })}\n </div>\n );\n}\n\n/** The in-composer /help panel, rendered entirely from the registry. */\nfunction HelpPanel({\n commands,\n onClose,\n}: {\n commands: readonly SlashCommand[];\n onClose: () => void;\n}) {\n return (\n <motion.div\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: \"auto\" }}\n exit={{ opacity: 0, height: 0 }}\n className=\"mt-2 overflow-hidden rounded-og-lg border border-og-border bg-og-surface-2\"\n >\n <div className=\"flex items-center justify-between border-b border-og-border px-3 py-1.5\">\n <span className=\"text-og-sm font-medium text-og-fg\">Commands</span>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-og-xs text-og-fg-subtle hover:text-og-fg\"\n >\n Close\n </button>\n </div>\n <ul className=\"py-1\">\n {commands.map((command) => {\n const hint = argHint(command.args);\n return (\n <li key={command.name} className=\"flex items-baseline gap-2 px-3 py-1\">\n <span className=\"font-mono text-og-sm text-og-accent\">\n /{command.name}\n {hint ? <span className=\"ml-1 text-og-fg-subtle\">{hint}</span> : null}\n </span>\n <span className=\"text-og-sm text-og-fg-muted\">{command.description}</span>\n {command.danger ? (\n <span className=\"ml-auto rounded-og-xs bg-og-status-failed/15 px-1 text-og-xs uppercase tracking-wide text-og-status-failed\">\n danger\n </span>\n ) : null}\n </li>\n );\n })}\n </ul>\n </motion.div>\n );\n}\n","import type { ClientModel } from \"@opengeni/sdk\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport { useId, useMemo } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type ModelPickerProps = {\n /** The host-exposed models to choose from (typically {@link useAvailableModels}). */\n models: ClientModel[];\n /** Controlled selection — the model id, or undefined for \"nothing chosen yet\". */\n value?: string | undefined;\n /** Called with the chosen model id when the operator picks a row. */\n onChange: (modelId: string) => void;\n disabled?: boolean | undefined;\n className?: string | undefined;\n};\n\n/**\n * The model picker — a compact dropdown for the composer footer, grouping the\n * host-exposed models by `providerLabel` (so \"OpenAI\" and \"Fireworks AI\" head\n * their own sections) and showing each model's display `label`. A native\n * `<select>` keeps it keyboard- and screen-reader-accessible for free and\n * themes via the package's og-* tokens; the chevron is a decorative overlay.\n *\n * Controlled: the host owns `value`/`onChange` and threads the selection into\n * the send path. Renders nothing when no models are exposed, so a single-model\n * deployment shows no chrome.\n */\nexport function ModelPicker({ models, value, onChange, disabled, className }: ModelPickerProps) {\n const selectId = useId();\n // Group by provider, preserving first-seen order for both the providers and\n // the models within each — the server already orders the list (default model\n // and built-in provider first), so we must not re-sort it.\n const groups = useMemo(() => {\n const byProvider = new Map<string, { label: string; models: ClientModel[] }>();\n for (const model of models) {\n let group = byProvider.get(model.provider);\n if (!group) {\n group = { label: model.providerLabel, models: [] };\n byProvider.set(model.provider, group);\n }\n group.models.push(model);\n }\n return [...byProvider.values()];\n }, [models]);\n\n if (models.length === 0) {\n return null;\n }\n\n return (\n <span className={cn(\"relative inline-flex items-center\", className)}>\n <label htmlFor={selectId} className=\"sr-only\">\n Model\n </label>\n <select\n id={selectId}\n value={value ?? \"\"}\n onChange={(event) => onChange(event.target.value)}\n disabled={disabled === true}\n aria-label=\"Model\"\n className={cn(\n // Sized like the other footer controls; the chevron overlay needs the\n // right padding so the value never collides with it.\n \"h-8 max-w-[180px] cursor-pointer appearance-none truncate rounded-og-md bg-transparent\",\n \"py-0 pl-2 pr-6 text-[13px] text-og-fg-muted\",\n \"transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg\",\n \"focus:outline-none focus-visible:outline-none\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n )}\n >\n {groups.map((group) => (\n <optgroup key={group.label} label={group.label}>\n {group.models.map((model) => (\n <option key={model.id} value={model.id}>\n {model.label}\n </option>\n ))}\n </optgroup>\n ))}\n </select>\n <ChevronDownIcon\n aria-hidden\n className=\"pointer-events-none absolute right-1.5 size-3.5 text-og-fg-subtle\"\n />\n </span>\n );\n}\n","import type { SessionEvent, SessionStatus } from \"@opengeni/sdk\";\nimport {\n ArrowDownIcon,\n ArrowRightIcon,\n BotIcon,\n CheckCircle2Icon,\n CheckIcon,\n ChevronRightIcon,\n PauseCircleIcon,\n PauseIcon,\n PencilLineIcon,\n PlayIcon,\n RefreshCwIcon,\n TargetIcon,\n Trash2Icon,\n TriangleAlertIcon,\n XCircleIcon,\n} from \"lucide-react\";\nimport type { ComponentType } from \"react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport { Collapsible } from \"radix-ui\";\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { formatRelativeTime, truncate } from \"../lib/format\";\nimport { Markdown } from \"./markdown\";\nimport {\n ActivityRail,\n buildTimeline,\n defaultToolRegistry,\n groupTimeline,\n LightboxProvider,\n type ActivityItem,\n type AgentMessageItem,\n type AuthNeededItem,\n type GoalItem,\n type NoticeItem,\n type TimelineGroup,\n type TimelineItem,\n type ToolRegistry,\n type UserMessageItem,\n type WorkerCompletionItem,\n TurnSummary,\n} from \"../timeline\";\nimport { SESSION_STATUS_META, StatusDot } from \"./session-status\";\nimport { EntranceAnimationProvider, useEntranceAnimation } from \"../timeline/entrance\";\n\nexport type MessageTimelineProps = {\n /** Raw session events (projected internally) … */\n events?: SessionEvent[] | undefined;\n /** … or pre-projected items (e.g. from `useSessionEvents().timeline`). */\n items?: TimelineItem[] | undefined;\n /** Current session status; drives the live \"working\" indicator. */\n status?: SessionStatus | null | undefined;\n /** Plug a markdown renderer for message bodies (e.g. streamdown). */\n renderMessageText?:\n | ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode)\n | undefined;\n /** Drill into a spawned worker session. */\n onOpenSession?: ((sessionId: string) => void) | undefined;\n /**\n * Deep-link a memory row (a `memory.saved` / `memory.corrected` step) to its\n * record in the host's memory pane. Opt-in, exactly like `onReconnect`: the\n * library draws no \"View in memory\" affordance without a handler — the memory\n * row is then non-interactive rich content. This is the switch that makes the\n * deep-link a first-party OpenGeni capability without other SDK consumers\n * opting into it. The app supplies it (it owns routing to the memory pane).\n */\n onMemoryClick?: ((memoryId: string) => void) | undefined;\n /**\n * Start the reconnect flow when a tool needs its connection reauthorized. The\n * app supplies this (it owns the SDK client + workspace): it typically kicks\n * off `startConnectionOAuth` and redirects, or routes to credential entry.\n * Rejecting surfaces a calm inline error on the card; the library never draws\n * a Reconnect button without a handler to run it.\n */\n onReconnect?: ((item: AuthNeededItem) => void | Promise<void>) | undefined;\n /**\n * Resolve a provider domain (from a reconnect card) to a logo URL the host\n * serves itself — the app maps it through its catalog + `catalogAssetUrl`.\n * Return null/undefined to fall back to a calm monogram. The library never\n * fetches an off-origin favicon (CSP + privacy); an unresolved logo is a\n * monogram, not an external image.\n */\n resolveProviderLogo?: ((providerDomain: string) => string | null | undefined) | undefined;\n /**\n * The tool-renderer registry that resolves how each tool call is drawn.\n * Defaults to {@link defaultToolRegistry}; pass a registry from\n * `createDefaultToolRegistry({ entries })` to add custom tool renderers.\n */\n toolRegistry?: ToolRegistry | undefined;\n /** Follow new events when pinned to the bottom. Defaults to true. */\n autoFollow?: boolean | undefined;\n /** Older durable history exists above the current window (see useSessionEvents). */\n hasOlder?: boolean | undefined;\n /** An older window is being fetched; shows the quiet top shimmer. */\n loadingOlder?: boolean | undefined;\n /** Called when the reader nears the top and older history should backfill. */\n onLoadOlder?: (() => void) | undefined;\n emptyState?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n/**\n * The session timeline: chat messages with streaming deltas, collapsed\n * activity clusters (reasoning, tool calls, sandbox work), spawned-worker\n * cards, goal markers, and status transitions. Owns stick-to-bottom scrolling\n * with a \"jump to latest\" affordance when the reader scrolls back.\n */\nexport function MessageTimeline({\n events,\n items,\n status,\n renderMessageText,\n onOpenSession,\n onMemoryClick,\n onReconnect,\n resolveProviderLogo,\n toolRegistry = defaultToolRegistry,\n autoFollow = true,\n hasOlder = false,\n loadingOlder = false,\n onLoadOlder,\n emptyState,\n className,\n}: MessageTimelineProps) {\n const resolvedItems = useMemo(() => items ?? buildTimeline(events ?? []), [items, events]);\n const groups = useMemo(() => groupTimeline(resolvedItems), [resolvedItems]);\n const firstGroupKey = groups[0] ? timelineGroupKey(groups[0]) : null;\n\n const scrollRef = useRef<HTMLDivElement | null>(null);\n const topSentinelRef = useRef<HTMLDivElement | null>(null);\n const previousBulkFirstKeyRef = useRef<string | null | undefined>(undefined);\n const [pinned, setPinned] = useState(true);\n const [bulkActive, setBulkActive] = useState(true);\n // Content stays invisible until its first bottom-anchored frame, so a flash\n // of the window's TOP while a large timeline lays out across commits is\n // structurally impossible — the reader only ever sees it already at the\n // bottom. An empty timeline reveals immediately (there is nothing to anchor).\n const [revealed, setRevealed] = useState(false);\n // Our own scrollTop assignments echo back as scroll events; those must never\n // UNPIN the reader (they are not reader intent). Marked around every\n // programmatic assignment and consumed by onScroll. When an assignment is a\n // NO-OP (already at the target) no scroll event will fire, so the mark must\n // self-clear — a stale mark would eat the reader's next real scroll-up.\n const programmaticScrollRef = useRef(false);\n const assignScrollTop = useCallback((node: HTMLElement, value: number) => {\n const previous = node.scrollTop;\n programmaticScrollRef.current = true;\n node.scrollTop = value;\n if (node.scrollTop === previous) {\n programmaticScrollRef.current = false;\n }\n }, []);\n // Mirror `pinned` into a ref so the ResizeObserver callback (a stable closure)\n // always reads the live value without re-subscribing on every scroll.\n const pinnedRef = useRef(true);\n // The reader's visual anchor: the topmost still-visible timeline element and\n // its offset from the viewport top. Recaptured on scroll and after every\n // height change, it lets us hold the reader's position when content above the\n // viewport expands or collapses (e.g. a turn folds when it settles).\n const anchorRef = useRef<{ el: Element; top: number } | null>(null);\n const lastItem = resolvedItems[resolvedItems.length - 1];\n const streaming =\n lastItem !== undefined &&\n (lastItem.kind === \"agent-message\" || lastItem.kind === \"reasoning\") &&\n lastItem.streaming;\n const working = status === \"running\" && !streaming;\n // Bulk paints (the initial tail window, a prepended older window — detected\n // by the first group key changing) must not run per-row entrance animations.\n const firstKeyChangedForBulk =\n previousBulkFirstKeyRef.current !== undefined &&\n previousBulkFirstKeyRef.current !== firstGroupKey;\n const bulkRender = groups.length > 0 && (bulkActive || firstKeyChangedForBulk);\n\n // Snapshot the topmost visible element and where it sits in the viewport, so a\n // later reflow can restore it to the same spot. Transient chrome (the backfill\n // sentinel and shimmer) is skipped — anchoring to a row that unmounts when the\n // older window lands would drop the correction mid-prepend.\n const captureAnchor = useCallback(() => {\n const node = scrollRef.current;\n const inner = node?.firstElementChild;\n if (!node || !inner) {\n anchorRef.current = null;\n return;\n }\n const containerTop = node.getBoundingClientRect().top;\n for (const child of Array.from(inner.children)) {\n if (child instanceof HTMLElement && child.dataset.ogTimelineChrome !== undefined) {\n continue;\n }\n const rect = child.getBoundingClientRect();\n if (rect.bottom > containerTop + 1) {\n anchorRef.current = { el: child, top: rect.top - containerTop };\n return;\n }\n }\n anchorRef.current = null;\n }, []);\n\n // Follow the stream while pinned to the bottom; never fight the reader.\n // A LAYOUT effect so the very first paint of a freshly loaded session is\n // already anchored at the bottom — no visible traversal down the history.\n useLayoutEffect(() => {\n const node = scrollRef.current;\n if (node && autoFollow && pinned) {\n assignScrollTop(node, node.scrollHeight);\n }\n if (!revealed && groups.length > 0) {\n setRevealed(true);\n }\n }, [resolvedItems, working, autoFollow, pinned, revealed, groups.length, assignScrollTop]);\n\n // A cleared timeline (stream identity change) re-arms the reveal so the next\n // session also first paints at its bottom.\n useLayoutEffect(() => {\n if (groups.length === 0 && revealed) {\n setRevealed(false);\n }\n }, [groups.length, revealed]);\n\n // Clear the bulk-paint marker a frame after it renders, so rows appended\n // live (streams, new turns) animate exactly as before.\n useLayoutEffect(() => {\n previousBulkFirstKeyRef.current = firstGroupKey;\n if (!bulkRender) {\n return;\n }\n setBulkActive(true);\n const frame = requestFrame(() => setBulkActive(false));\n return () => cancelFrame(frame);\n }, [bulkRender, firstGroupKey]);\n\n // Prefetch older history well before the reader reaches the top: the\n // sentinel sits above the first group and trips 1600px early, so backfill\n // is usually rendered (and anchored by the ResizeObserver below) before the\n // top of the window ever becomes visible.\n useEffect(() => {\n const root = scrollRef.current;\n const target = topSentinelRef.current;\n if (\n !root ||\n !target ||\n !hasOlder ||\n loadingOlder ||\n !onLoadOlder ||\n typeof IntersectionObserver === \"undefined\"\n ) {\n return;\n }\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n onLoadOlder();\n }\n },\n { root, rootMargin: \"1600px 0px 0px 0px\" },\n );\n observer.observe(target);\n return () => observer.disconnect();\n }, [hasOlder, loadingOlder, onLoadOlder, firstGroupKey]);\n\n // Scroll anchoring: when the content reflows (a fold expands/collapses, a\n // stream appends), keep following the bottom if pinned; otherwise pin the\n // reader's anchor in place. A change ABOVE the anchor shifts its viewport\n // offset — we correct scrollTop by that shift so the reader never gets yanked.\n // A change BELOW the anchor (a bottom append while scrolled up) leaves the\n // anchor put, so `diff` is 0 and we leave scrollTop alone.\n useEffect(() => {\n const node = scrollRef.current;\n const inner = node?.firstElementChild;\n if (!node || !inner || typeof ResizeObserver === \"undefined\") {\n return;\n }\n const observer = new ResizeObserver(() => {\n const current = scrollRef.current;\n if (!current) {\n return;\n }\n if (autoFollow && pinnedRef.current) {\n assignScrollTop(current, current.scrollHeight);\n } else {\n const anchor = anchorRef.current;\n if (anchor && anchor.el.isConnected) {\n const containerTop = current.getBoundingClientRect().top;\n const now = anchor.el.getBoundingClientRect().top - containerTop;\n const diff = now - anchor.top;\n if (diff !== 0) {\n assignScrollTop(current, current.scrollTop + diff);\n }\n }\n }\n captureAnchor();\n });\n observer.observe(inner);\n return () => observer.disconnect();\n }, [autoFollow, captureAnchor, assignScrollTop]);\n\n const onScroll = () => {\n const node = scrollRef.current;\n if (!node) {\n return;\n }\n const programmatic = programmaticScrollRef.current;\n programmaticScrollRef.current = false;\n const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;\n // Echoes of our own assignments may PIN but never UNPIN — only the reader\n // scrolling away releases the bottom-follow.\n if (nextPinned || !programmatic) {\n pinnedRef.current = nextPinned;\n setPinned(nextPinned);\n }\n captureAnchor();\n };\n\n return (\n <LightboxProvider>\n <EntranceAnimationProvider value={!bulkRender}>\n <div className={cn(\"og-root relative flex min-h-0 flex-col\", className)}>\n {/* overflow-anchor off: the browser's native scroll anchoring would fight\n the ResizeObserver corrections above — one authority only. */}\n <div\n ref={scrollRef}\n onScroll={onScroll}\n style={groups.length > 0 && !revealed ? { visibility: \"hidden\" } : undefined}\n className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 [overflow-anchor:none] sm:px-6\"\n >\n <div className=\"mx-auto flex w-full max-w-3xl flex-col gap-5\">\n {groups.length === 0 && !working\n ? (emptyState ?? (\n <p className=\"py-10 text-center text-sm text-og-fg-subtle\">No activity yet.</p>\n ))\n : null}\n {hasOlder ? (\n <div\n ref={topSentinelRef}\n data-og-top-sentinel=\"\"\n data-og-timeline-chrome=\"\"\n aria-hidden=\"true\"\n className=\"h-px w-full shrink-0\"\n />\n ) : null}\n {loadingOlder ? (\n <div data-og-timeline-chrome=\"\" className=\"flex items-center gap-2 text-sm\">\n <span className=\"og-shimmer-text font-medium\">Loading earlier activity…</span>\n </div>\n ) : null}\n {groups.map((group, index) => (\n <TimelineGroupView\n key={timelineGroupKey(group)}\n group={group}\n renderMessageText={renderMessageText}\n onOpenSession={onOpenSession}\n onMemoryClick={onMemoryClick}\n onReconnect={onReconnect}\n resolveProviderLogo={resolveProviderLogo}\n toolRegistry={toolRegistry}\n foldLiveCluster={isAgentProgress(groups[index + 1])}\n />\n ))}\n {working ? (\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"og-shimmer-text font-medium\">Working…</span>\n </div>\n ) : null}\n </div>\n </div>\n <AnimatePresence>\n {!pinned && autoFollow ? (\n <motion.button\n type=\"button\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: 8 }}\n transition={{ duration: 0.15, ease: \"easeOut\" }}\n onClick={() => {\n const node = scrollRef.current;\n if (node) {\n node.scrollTo({ top: node.scrollHeight, behavior: \"smooth\" });\n }\n pinnedRef.current = true;\n setPinned(true);\n }}\n className={cn(\n \"absolute bottom-4 left-1/2 -translate-x-1/2\",\n \"inline-flex items-center gap-1.5 rounded-full border border-og-border bg-og-surface-3/90 px-3 py-1.5\",\n \"text-xs font-medium text-og-fg shadow-og-md backdrop-blur\",\n \"hover:border-og-border-strong\",\n )}\n >\n <ArrowDownIcon className=\"size-3.5\" />\n Jump to latest\n </motion.button>\n ) : null}\n </AnimatePresence>\n </div>\n </EntranceAnimationProvider>\n </LightboxProvider>\n );\n}\n\nfunction requestFrame(callback: FrameRequestCallback): number {\n if (typeof requestAnimationFrame === \"function\") {\n return requestAnimationFrame(callback);\n }\n return window.setTimeout(() => callback(performance.now()), 16);\n}\n\nfunction cancelFrame(id: number): void {\n if (typeof cancelAnimationFrame === \"function\") {\n cancelAnimationFrame(id);\n return;\n }\n window.clearTimeout(id);\n}\n\nfunction TimelineGroupView({\n group,\n renderMessageText,\n onOpenSession,\n onMemoryClick,\n onReconnect,\n resolveProviderLogo,\n toolRegistry,\n insideTurn = false,\n foldLiveCluster = false,\n}: {\n group: TimelineGroup;\n renderMessageText?:\n | ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode)\n | undefined;\n onOpenSession?: ((sessionId: string) => void) | undefined;\n onMemoryClick?: ((memoryId: string) => void) | undefined;\n onReconnect?: ((item: AuthNeededItem) => void | Promise<void>) | undefined;\n resolveProviderLogo?: ((providerDomain: string) => string | null | undefined) | undefined;\n toolRegistry: ToolRegistry;\n /** A completed cluster of a still-RUNNING turn (not the live tail) folds\n behind a neutral chip — the one place activity without an outcome still\n folds, bounding the DOM of days-long autonomous turns. */\n foldLiveCluster?: boolean;\n /** Rendering inside an expanded turn group: the outer chip already owns the\n failure surface, so nested chips stay tinted but quiet (no repeated\n failure text, no auto-open) — one loud error, N calm sub-expands. */\n insideTurn?: boolean;\n}) {\n switch (group.kind) {\n case \"activity\":\n return group.outcome || (foldLiveCluster && clusterIsSettled(group)) ? (\n <TurnSummary\n items={group.items}\n outcome={group.outcome}\n failureText={insideTurn ? undefined : group.failureText}\n defaultOpen={!insideTurn && group.outcome === \"failed\" ? true : undefined}\n bare={insideTurn}\n >\n <ActivityRail\n items={group.items}\n onOpenSession={onOpenSession}\n onMemoryClick={onMemoryClick}\n toolRegistry={toolRegistry}\n bare={insideTurn}\n />\n </TurnSummary>\n ) : (\n // A nested live cluster hangs on the turn's rail (bare); a top-level one\n // owns its own rail.\n <ActivityRail\n items={group.items}\n onOpenSession={onOpenSession}\n onMemoryClick={onMemoryClick}\n toolRegistry={toolRegistry}\n bare={insideTurn}\n />\n );\n case \"turn\": {\n const activityItems = flattenActivityItems(group.groups);\n const body = group.groups.map((child) => (\n <TimelineGroupView\n key={timelineGroupKey(child)}\n group={child}\n renderMessageText={renderMessageText}\n onOpenSession={onOpenSession}\n onMemoryClick={onMemoryClick}\n onReconnect={onReconnect}\n resolveProviderLogo={resolveProviderLogo}\n toolRegistry={toolRegistry}\n insideTurn\n />\n ));\n return (\n <TurnSummary\n items={activityItems}\n outcome={group.outcome}\n // One loud error at the top; nested sub-turn chips stay calm — the\n // parent already renders the failure reason, so clear it here exactly\n // as the nested activity-cluster case does.\n failureText={insideTurn ? undefined : group.failureText}\n durationMs={durationBetween(group.startedAt, group.endedAt)}\n defaultOpen={!insideTurn && group.outcome === \"failed\" ? true : undefined}\n bare={insideTurn}\n >\n {insideTurn ? (\n // A nested turn is already on an ancestor rail — its body just stacks\n // flush (the bare-node body already indents it), so no second rule.\n <div className=\"flex flex-col gap-4\">{body}</div>\n ) : (\n // The top-level turn draws THE rail: one thin continuous rule that\n // every nested node and step hangs off of.\n <div className=\"flex flex-col gap-4 border-l-2 border-og-border pl-3 sm:pl-4\">\n {body}\n </div>\n )}\n </TurnSummary>\n );\n }\n case \"item\":\n return (\n <TimelineRow\n item={group.item}\n renderMessageText={renderMessageText}\n onReconnect={onReconnect}\n resolveProviderLogo={resolveProviderLogo}\n onOpenSession={onOpenSession}\n />\n );\n }\n}\n\nfunction timelineGroupKey(group: TimelineGroup): string {\n switch (group.kind) {\n case \"item\":\n return group.item.id;\n case \"activity\":\n return group.id;\n case \"turn\":\n return group.id;\n }\n}\n\n/** The agent has moved PAST a cluster only when what follows is more agent\n progress — new activity, a settled turn, or narration. A waiting notice\n (approval pause), a pending queued message, a goal pill, or nothing at all\n do NOT advance the story, and folding on them would hide exactly the work\n the reader needs in view. */\nfunction isAgentProgress(next: TimelineGroup | undefined): boolean {\n if (!next) {\n return false;\n }\n return (\n next.kind === \"activity\" ||\n next.kind === \"turn\" ||\n (next.kind === \"item\" && next.item.kind === \"agent-message\")\n );\n}\n\n/** No item still running or streaming — the only state safe to fold live.\n Position alone is a broken proxy: a pending queued message (or any trailing\n item) can sit after the ACTIVE cluster, which must never fold mid-work. */\nfunction clusterIsSettled(group: Extract<TimelineGroup, { kind: \"activity\" }>): boolean {\n return group.items.every((item) => {\n if (item.kind === \"reasoning\") {\n return !item.streaming;\n }\n // A memory write is a discrete, already-settled event — it has no running state.\n if (item.kind === \"memory\") {\n return true;\n }\n return item.status !== \"running\";\n });\n}\n\nfunction flattenActivityItems(groups: TimelineGroup[]): ActivityItem[] {\n const items: ActivityItem[] = [];\n for (const group of groups) {\n if (group.kind === \"activity\") {\n items.push(...group.items);\n } else if (group.kind === \"turn\") {\n items.push(...flattenActivityItems(group.groups));\n }\n }\n return items;\n}\n\nfunction durationBetween(startedAt: string, endedAt: string): number | undefined {\n const started = Date.parse(startedAt);\n const ended = Date.parse(endedAt);\n if (!Number.isFinite(started) || !Number.isFinite(ended) || ended < started) {\n return undefined;\n }\n return ended - started;\n}\n\n/* --- single rows ------------------------------------------------------------ */\n\n/**\n * Render one non-activity timeline item (chat message, status divider, goal\n * landmark, notice). Exported so the component demo draws the EXACT same rows as\n * the live app — no forked bubble/goal markup.\n */\nexport function TimelineRow({\n item,\n renderMessageText,\n onReconnect,\n resolveProviderLogo,\n onOpenSession,\n}: {\n item: TimelineItem;\n renderMessageText?:\n | ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode)\n | undefined;\n onReconnect?: ((item: AuthNeededItem) => void | Promise<void>) | undefined;\n resolveProviderLogo?: ((providerDomain: string) => string | null | undefined) | undefined;\n onOpenSession?: ((sessionId: string) => void) | undefined;\n}) {\n switch (item.kind) {\n case \"user-message\":\n return <UserMessageRow item={item} renderMessageText={renderMessageText} />;\n case \"agent-message\":\n return <AgentMessageRow item={item} renderMessageText={renderMessageText} />;\n case \"worker-completion\":\n return <WorkerCompletionRow item={item} onOpenSession={onOpenSession} />;\n case \"session-status\":\n return <SessionStatusRow item={item} />;\n case \"goal\":\n return <GoalRow item={item} />;\n case \"notice\":\n return <NoticeRow item={item} />;\n case \"auth-needed\":\n return (\n <AuthNeededRow\n item={item}\n onReconnect={onReconnect}\n resolveProviderLogo={resolveProviderLogo}\n />\n );\n default:\n return null;\n }\n}\n\nfunction UserMessageRow({\n item,\n renderMessageText,\n}: {\n item: UserMessageItem;\n renderMessageText?:\n | ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode)\n | undefined;\n}) {\n const enter = useEntranceAnimation();\n return (\n <div className={cn(enter && \"animate-og-enter\", \"flex justify-end\")}>\n <div className=\"flex max-w-[85%] min-w-0 flex-col items-end gap-1\">\n <div className=\"w-fit max-w-full min-w-0 rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-og-md leading-6 text-og-fg\">\n {renderMessageText ? (\n renderMessageText(item.text, item)\n ) : (\n <Markdown>{item.text}</Markdown>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction AgentMessageRow({\n item,\n renderMessageText,\n}: {\n item: AgentMessageItem;\n renderMessageText?:\n | ((text: string, item: AgentMessageItem | UserMessageItem) => ReactNode)\n | undefined;\n}) {\n const enter = useEntranceAnimation();\n const caret = item.streaming ? (\n <span\n className=\"ml-0.5 inline-block h-[1.1em] w-[2px] translate-y-[3px] animate-og-blink rounded-full bg-og-accent\"\n aria-hidden\n />\n ) : null;\n return (\n <div className={cn(enter && \"animate-og-enter\", \"min-w-0 text-og-md leading-7 text-og-fg\")}>\n {renderMessageText ? (\n <>\n {renderMessageText(item.text, item)}\n {caret}\n </>\n ) : (\n // While streaming, let the caret ride the end of the last rendered line:\n // the trailing block (usually a <p>) flows inline so the caret sits on\n // its baseline instead of dropping to a new line.\n <div className={item.streaming ? \"[&_>div>:last-child]:inline\" : undefined}>\n <Markdown>{item.text}</Markdown>\n {caret}\n </div>\n )}\n </div>\n );\n}\n\n/**\n * A worker session reporting back to its manager. The child's completion arrives\n * as a `user.message` carrying a `childCompletion` payload (the raw message text\n * used to render as an \"ugly\" user bubble); it projects to a `worker-completion`\n * item and draws here as a quietly-confident card — an inbound result, not\n * something the human said. One glyph + one line carry the outcome; the worker's\n * full report, evidence, and any paused reason live behind a collapsed\n * disclosure, and a \"View session\" affordance deep-links into the child.\n *\n * Color follows the timeline's restraint: green only for a completed goal, the\n * waiting hue only for a paused one, red only for a failed child — everything\n * else is a neutral inbound card.\n */\ntype WorkerCompletionMeta = {\n label: string;\n icon: ComponentType<{ className?: string }>;\n iconClass: string;\n /** The 2px left-accent hue — color spent only on the exceptional outcomes. */\n accentClass: string;\n};\n\nfunction workerCompletionMeta(item: WorkerCompletionItem): WorkerCompletionMeta {\n if (item.childStatus === \"failed\") {\n return {\n label: \"Worker failed\",\n icon: XCircleIcon,\n iconClass: \"text-og-status-failed\",\n accentClass: \"border-og-status-failed/60\",\n };\n }\n if (item.goalStatus === \"paused\") {\n return {\n label: \"Worker paused\",\n icon: PauseCircleIcon,\n iconClass: \"text-og-status-waiting\",\n accentClass: \"border-og-status-waiting/50\",\n };\n }\n if (item.goalStatus === \"completed\") {\n return {\n label: \"Worker completed\",\n icon: CheckCircle2Icon,\n iconClass: \"text-og-status-idle\",\n accentClass: \"border-og-status-idle/45\",\n };\n }\n return {\n label: \"Worker reported back\",\n icon: BotIcon,\n iconClass: \"text-og-accent\",\n accentClass: \"border-og-border-strong\",\n };\n}\n\nfunction WorkerCompletionRow({\n item,\n onOpenSession,\n}: {\n item: WorkerCompletionItem;\n onOpenSession?: ((sessionId: string) => void) | undefined;\n}) {\n const enter = useEntranceAnimation();\n const [open, setOpen] = useState(false);\n const meta = workerCompletionMeta(item);\n const Icon = meta.icon;\n // The worker's own report is the substance behind the fold; evidence and any\n // paused reason sit alongside it as quieter, labelled context.\n // \"Paused because\" only when the outcome actually IS a pause — completion\n // payloads can carry a leftover pausedReason/rationale from earlier in the\n // worker's life, and a \"Worker completed\" card must not show a pause section.\n const showPausedReason =\n item.childStatus !== \"failed\" &&\n item.goalStatus === \"paused\" &&\n Boolean(item.pausedReason?.trim());\n const details: { label: string; value: string; muted?: boolean }[] = [\n ...(item.text.trim() ? [{ label: \"Report\", value: item.text.trim() }] : []),\n ...(item.evidence?.trim()\n ? [{ label: \"Evidence\", value: item.evidence.trim(), muted: true }]\n : []),\n ...(showPausedReason\n ? [{ label: \"Paused because\", value: item.pausedReason!.trim(), muted: true }]\n : []),\n ];\n const hasDetails = details.length > 0;\n return (\n <div className={cn(enter && \"animate-og-enter\", \"min-w-0\")}>\n {/* An inbound result, not a bubble: a 2px left accent carries the outcome —\n no full frame, no surface fill. The report unfolds flush beneath. */}\n <div className={cn(\"flex flex-col gap-2 border-l-2 pl-3\", meta.accentClass)}>\n <div className=\"flex items-start gap-2.5\">\n <span className={cn(\"mt-0.5 shrink-0\", meta.iconClass)}>\n <Icon className=\"size-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-og-base leading-5 text-og-fg\">\n <span className=\"font-medium\">{meta.label}</span>\n {item.goalText ? (\n <span className=\"text-og-fg-muted\"> · {truncate(item.goalText, 90)}</span>\n ) : null}\n </p>\n </div>\n {item.childSessionId && onOpenSession ? (\n <button\n type=\"button\"\n onClick={() => onOpenSession(item.childSessionId)}\n className={cn(\n \"-my-0.5 -mr-1 inline-flex shrink-0 items-center gap-1 rounded-og-sm px-2 py-1 text-og-sm font-medium text-og-fg-muted pointer-coarse:py-2\",\n \"outline-none transition-colors duration-150 hover:bg-og-surface-2 hover:text-og-fg\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n >\n View session\n <ArrowRightIcon className=\"size-3.5\" />\n </button>\n ) : null}\n </div>\n {hasDetails ? (\n <Collapsible.Root open={open} onOpenChange={setOpen}>\n <Collapsible.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"group/wc -mx-1 inline-flex w-fit items-center gap-1 rounded-og-sm px-1 py-0.5 text-og-xs font-medium text-og-fg-subtle\",\n \"outline-none transition-colors duration-150 hover:text-og-fg-muted focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n >\n <ChevronRightIcon className=\"size-3 transition-transform duration-150 ease-og-in-out group-data-[state=open]/wc:rotate-90\" />\n {open ? \"Hide details\" : \"Show details\"}\n </button>\n </Collapsible.Trigger>\n <Collapsible.Content className=\"overflow-hidden data-[state=closed]:animate-og-collapse data-[state=open]:animate-og-expand\">\n <div className=\"ml-1 mt-1.5 flex flex-col gap-2.5\">\n {details.map((detail) => (\n <div key={detail.label} className=\"min-w-0\">\n <p className=\"mb-1 text-og-xs font-medium uppercase tracking-[0.08em] text-og-fg-subtle\">\n {detail.label}\n </p>\n <p\n className={cn(\n \"whitespace-pre-wrap break-words text-og-sm leading-6\",\n detail.muted ? \"text-og-fg-subtle\" : \"text-og-fg-muted\",\n )}\n >\n {detail.value}\n </p>\n </div>\n ))}\n </div>\n </Collapsible.Content>\n </Collapsible.Root>\n ) : null}\n </div>\n </div>\n );\n}\n\nfunction SessionStatusRow({ item }: { item: { status: SessionStatus; occurredAt: string } }) {\n const enter = useEntranceAnimation();\n const meta = SESSION_STATUS_META[item.status];\n return (\n <div\n className={cn(\n enter && \"animate-og-enter\",\n \"flex items-center gap-3 text-og-xs text-og-fg-subtle\",\n )}\n role=\"status\"\n >\n <span className=\"h-px flex-1 bg-og-border\" />\n <span className=\"inline-flex items-center gap-1.5\">\n <StatusDot status={item.status} className=\"size-1\" />\n {meta.label.toLowerCase()} · {formatRelativeTime(item.occurredAt)}\n </span>\n <span className=\"h-px flex-1 bg-og-border\" />\n </div>\n );\n}\n\n/**\n * The per-action presentation of a goal landmark pill. Each of the six goal\n * actions reads distinctly, but the palette stays quiet — color is spent only on\n * the two states that genuinely earn it, the rest are neutral pills set apart by\n * their glyph alone:\n *\n * completed success green (status-idle) check — the only \"done\" hue\n * paused attention waiting-tinted pause — a held goal asks to resume\n * set a landmark a quiet accent target — opening a fresh goal\n * resumed forward neutral play — motion picking back up\n * updated a revision neutral pencil — the goal text changed\n * continuation steady on neutral arrow — still tracking the same goal\n *\n * The pill class is the established badge convention (`text-X border-X/30\n * bg-X/10`); neutral actions reuse the surface/border tokens so a clean run of\n * landmarks stays calm rather than a row of colored chips.\n */\ntype GoalMeta = { label: string; pill: string; icon: ComponentType<{ className?: string }> };\n\nconst NEUTRAL_PILL = \"border-og-border bg-og-surface-1 text-og-fg-muted\";\n\nconst GOAL_META: Record<GoalItem[\"action\"], GoalMeta> = {\n set: {\n label: \"Goal set\",\n pill: \"border-og-accent/30 bg-og-accent/10 text-og-accent\",\n icon: TargetIcon,\n },\n updated: { label: \"Goal updated\", pill: NEUTRAL_PILL, icon: PencilLineIcon },\n completed: {\n label: \"Goal completed\",\n pill: \"border-og-status-idle/30 bg-og-status-idle/10 text-og-status-idle\",\n icon: CheckIcon,\n },\n paused: {\n label: \"Goal paused\",\n pill: \"border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting\",\n icon: PauseIcon,\n },\n resumed: { label: \"Goal resumed\", pill: NEUTRAL_PILL, icon: PlayIcon },\n cleared: { label: \"Goal cleared\", pill: NEUTRAL_PILL, icon: Trash2Icon },\n continuation: { label: \"Continuing toward the goal\", pill: NEUTRAL_PILL, icon: ArrowRightIcon },\n};\n\n/**\n * A goal landmark pill. Resolves its label, accent/tone, and glyph from\n * {@link GOAL_META} so all six actions are visually distinguishable while the\n * palette stays restrained — see that table for the per-action rationale.\n */\nfunction GoalRow({ item }: { item: GoalItem }) {\n const enter = useEntranceAnimation();\n const { label, pill, icon: Icon } = GOAL_META[item.action];\n return (\n <div className={cn(enter && \"animate-og-enter\", \"flex justify-center\")}>\n <span\n className={cn(\n \"inline-flex max-w-full items-center gap-1.5 rounded-full border px-3 py-1 text-og-sm\",\n pill,\n )}\n >\n <Icon className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">\n {label}\n {item.text ? `: ${truncate(item.text, 90)}` : \"\"}\n </span>\n </span>\n </div>\n );\n}\n\nfunction NoticeRow({ item }: { item: NoticeItem }) {\n const enter = useEntranceAnimation();\n const tone =\n item.tone === \"failed\"\n ? \"border-og-status-failed/35 bg-og-status-failed/10 text-og-status-failed\"\n : item.tone === \"waiting\"\n ? \"border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting\"\n : \"border-og-border bg-og-surface-1 text-og-fg-muted\";\n return (\n <div\n className={cn(\n enter && \"animate-og-enter\",\n \"flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm\",\n tone,\n )}\n role=\"status\"\n >\n <TriangleAlertIcon\n className={cn(\"mt-0.5 size-4 shrink-0\", item.tone === \"cancelled\" && \"opacity-60\")}\n />\n <div className=\"min-w-0 flex-1\">\n <span className=\"whitespace-pre-wrap break-words\">{item.text}</span>\n {item.details ? (\n <details className=\"mt-2 text-xs\">\n <summary className=\"cursor-pointer font-medium\">{item.details.label}</summary>\n <pre className=\"mt-2 max-h-64 overflow-auto whitespace-pre-wrap break-all rounded-og-sm bg-black/5 p-2 font-mono dark:bg-white/5\">\n {JSON.stringify(item.details.value, null, 2)}\n </pre>\n </details>\n ) : null}\n </div>\n {item.action ? (\n <a\n className=\"shrink-0 rounded-og-sm border border-current/25 px-2 py-1 text-xs font-medium hover:bg-current/10\"\n href={item.action.url}\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n {item.action.label}\n </a>\n ) : null}\n </div>\n );\n}\n\n/**\n * The inline reconnect card: a lapsed connection surfaces as a calm, tappable\n * affordance — provider logo, one human line, one primary Reconnect button —\n * instead of a raw \"linear.app needs to be reconnected.\" string. The `reason`\n * only shapes the helper copy; no domain or enum code is shown as a label.\n * `onReconnect` (from the app, which owns the SDK client) runs the flow; without\n * it, a pre-minted authorization link is offered, or the card stays informative.\n */\nfunction AuthNeededRow({\n item,\n onReconnect,\n resolveProviderLogo,\n}: {\n item: AuthNeededItem;\n onReconnect?: ((item: AuthNeededItem) => void | Promise<void>) | undefined;\n resolveProviderLogo?: ((providerDomain: string) => string | null | undefined) | undefined;\n}) {\n const enter = useEntranceAnimation();\n const [busy, setBusy] = useState(false);\n const [failed, setFailed] = useState(false);\n const provider = providerLabel(item.providerDomain);\n\n const start = async () => {\n if (!onReconnect || busy) {\n return;\n }\n setBusy(true);\n setFailed(false);\n try {\n // On success the app redirects to consent (or routes to credential entry),\n // so this row unmounts; a resolve without navigation just relaxes the button.\n await onReconnect(item);\n setBusy(false);\n } catch {\n setFailed(true);\n setBusy(false);\n }\n };\n\n return (\n <div className={cn(enter && \"animate-og-enter\", \"flex flex-col gap-2\")} role=\"status\">\n <div className=\"flex flex-col gap-3 rounded-og-lg border border-og-border bg-og-surface-1 px-3.5 py-3 sm:flex-row sm:items-center\">\n <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n <AuthProviderLogo\n src={resolveProviderLogo?.(item.providerDomain) ?? null}\n label={provider}\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-og-md font-medium text-og-fg\">Reconnect {provider}</p>\n <p className=\"truncate text-og-sm text-og-fg-subtle\">{authReasonLine(item.reason)}</p>\n </div>\n </div>\n {onReconnect ? (\n <button\n type=\"button\"\n onClick={() => void start()}\n disabled={busy}\n className={cn(\n \"inline-flex w-full shrink-0 items-center justify-center gap-1.5 rounded-og-md bg-og-accent px-3 py-1.5 text-sm font-medium text-og-accent-fg sm:w-auto\",\n \"transition-colors hover:bg-og-accent-strong disabled:opacity-70 pointer-coarse:min-h-9\",\n )}\n >\n <RefreshCwIcon className={cn(\"size-3.5\", busy && \"animate-og-spin\")} aria-hidden />\n {busy ? \"Reconnecting…\" : \"Reconnect\"}\n </button>\n ) : item.authorizationUrl ? (\n <a\n href={item.authorizationUrl}\n rel=\"noreferrer\"\n target=\"_blank\"\n className={cn(\n \"inline-flex w-full shrink-0 items-center justify-center gap-1.5 rounded-og-md bg-og-accent px-3 py-1.5 text-sm font-medium text-og-accent-fg sm:w-auto\",\n \"transition-colors hover:bg-og-accent-strong pointer-coarse:min-h-9\",\n )}\n >\n <RefreshCwIcon className=\"size-3.5\" aria-hidden />\n Reconnect\n </a>\n ) : null}\n </div>\n {failed ? (\n <p className=\"px-1 text-og-xs text-og-status-failed\">\n Couldn't start reconnecting {provider}. Try again.\n </p>\n ) : null}\n </div>\n );\n}\n\n/**\n * The provider's logo in a rounded tile, from a URL the HOST serves itself\n * (resolved via `resolveProviderLogo` → the app's catalog assets). A missing or\n * failed image falls back to a calm letter monogram — same as the rest of the\n * app — so the card never shows a broken-image glyph and never reaches off-origin\n * for a favicon (CSP + privacy).\n */\nfunction AuthProviderLogo({ src, label }: { src: string | null; label: string }) {\n const [failed, setFailed] = useState(false);\n // A resolver that only returns the URL after a lazy catalog fetch means `src`\n // can arrive on a later render; reset the error latch so it gets its attempt.\n useEffect(() => setFailed(false), [src]);\n const showImage = src && !failed;\n return (\n <span\n className=\"relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-og-md border border-og-border bg-og-surface-2 text-sm font-semibold text-og-fg-muted\"\n aria-hidden\n >\n {showImage ? (\n <img\n src={src}\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n className=\"size-full object-contain p-1.5\"\n onError={() => setFailed(true)}\n />\n ) : (\n <span>{monogram(label)}</span>\n )}\n </span>\n );\n}\n\n/** First one or two initials for the monogram fallback — mirrors the app's\n `capabilityMonogram` so the reconnect tile reads like every other logo tile. */\nfunction monogram(label: string): string {\n const words = label.trim().split(/\\s+/).filter(Boolean);\n if (words.length === 0) {\n return \"?\";\n }\n if (words.length === 1) {\n return words[0]!.slice(0, 2).toUpperCase();\n }\n return (words[0]![0]! + words[1]![0]!).toUpperCase();\n}\n\n/** \"linear.app\" -> \"Linear\": the first domain label, capitalized. A calm human\n name for the provider — never the raw domain shown as a label. */\nfunction providerLabel(domain: string): string {\n const host =\n domain\n .trim()\n .replace(/^https?:\\/\\//, \"\")\n .replace(/^www\\./, \"\")\n .split(\"/\")[0] ?? \"\";\n const first = host.split(\".\")[0] ?? host;\n if (!first) {\n return \"this service\";\n }\n return first.charAt(0).toUpperCase() + first.slice(1);\n}\n\n/** A calm, human helper line per reauth reason — the `reason` informs the copy\n but is never rendered as a raw enum/code. */\nfunction authReasonLine(reason: AuthNeededItem[\"reason\"]): string {\n switch (reason) {\n case \"insufficient_scope\":\n return \"It needs additional access to continue.\";\n case \"missing_connection\":\n return \"It isn't connected yet.\";\n case \"expired\":\n case \"refresh_failed\":\n return \"Its access expired.\";\n default:\n return \"Its connection needs attention.\";\n }\n}\n","import { memo } from \"react\";\nimport ReactMarkdown, { type Components } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"../lib/cn\";\n\n/**\n * The default renderer for chat message bodies in {@link MessageTimeline}.\n *\n * Agent (and user) messages arrive as GitHub-flavored markdown. This turns the\n * raw text into styled HTML using `react-markdown` + `remark-gfm`, themed to the\n * package's `og-*` design tokens so it reads as one cohesive dark surface — no\n * stock Tailwind colors leak in.\n *\n * It re-parses on every render, which is exactly right for streaming: a body\n * that is still arriving (an unterminated `**`, a half-open code fence, a table\n * mid-row) renders as best-effort markdown and resolves cleanly as the rest of\n * the tokens land. Consumers who want a different renderer can still pass\n * `renderMessageText` to `MessageTimeline` to override this entirely.\n */\nexport type MarkdownProps = {\n children: string;\n className?: string | undefined;\n};\n\n/* --- element renderers (themed to og-* tokens) ------------------------------ */\n\nconst components: Components = {\n h1: ({ children, ...props }) => (\n <h1\n className=\"mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0\"\n {...props}\n >\n {children}\n </h1>\n ),\n h2: ({ children, ...props }) => (\n <h2 className=\"mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0\" {...props}>\n {children}\n </h2>\n ),\n h3: ({ children, ...props }) => (\n <h3\n className=\"mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0\"\n {...props}\n >\n {children}\n </h3>\n ),\n h4: ({ children, ...props }) => (\n <h4\n className=\"mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0\"\n {...props}\n >\n {children}\n </h4>\n ),\n p: ({ children, ...props }) => (\n <p className=\"my-2.5 leading-7 first:mt-0 last:mb-0\" {...props}>\n {children}\n </p>\n ),\n strong: ({ children, ...props }) => (\n <strong className=\"font-semibold text-og-fg\" {...props}>\n {children}\n </strong>\n ),\n em: ({ children, ...props }) => (\n <em className=\"italic\" {...props}>\n {children}\n </em>\n ),\n a: ({ children, ...props }) => (\n <a\n className=\"break-words font-medium text-og-accent underline-offset-2 hover:underline\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n {...props}\n >\n {children}\n </a>\n ),\n ul: ({ children, ...props }) => (\n <ul\n className=\"my-2.5 ml-5 flex list-disc flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </ul>\n ),\n ol: ({ children, ...props }) => (\n <ol\n className=\"my-2.5 ml-5 flex list-decimal flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </ol>\n ),\n // GFM task-list items carry a leading checkbox <input>; `list-none` + a\n // negative margin pull the checkbox back to the bullet column so it aligns\n // with the text.\n li: ({ children, ...props }) => (\n <li\n className=\"leading-7 marker:text-og-fg-subtle [&>ul]:my-1 [&>ol]:my-1 [&:has(>input)]:list-none [&:has(>input)]:-ml-5\"\n {...props}\n >\n {children}\n </li>\n ),\n input: ({ type, ...props }) =>\n type === \"checkbox\" ? (\n <input\n {...props}\n type=\"checkbox\"\n disabled\n className=\"mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline\"\n />\n ) : (\n <input type={type} {...props} />\n ),\n blockquote: ({ children, ...props }) => (\n <blockquote\n className=\"my-3 border-l-2 border-og-border-strong pl-3.5 text-og-fg-muted [&>p]:my-1.5 first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </blockquote>\n ),\n hr: (props) => <hr className=\"my-4 border-0 border-t border-og-border\" {...props} />,\n // Inline `code` vs fenced code blocks. react-markdown v10 no longer passes an\n // `inline` flag; a fenced block is a <code> whose parent is <pre> (styled by\n // the `pre` renderer), so a `code` reaching here is treated as inline.\n code: ({ children, className: _className, ...props }) => (\n <code\n className=\"rounded-og-xs border border-og-border bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg\"\n {...props}\n >\n {children}\n </code>\n ),\n // Fenced code blocks — mirror the timeline's PayloadBlock <pre> styling for\n // visual consistency (bordered, scrollable, mono, surface background).\n pre: ({ children, ...props }) => (\n <pre\n className=\"my-3 max-h-96 overflow-auto rounded-og-md border border-og-border bg-og-bg/60 p-3 font-og-mono text-og-sm text-og-fg-muted [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:text-inherit first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </pre>\n ),\n table: ({ children, ...props }) => (\n <div className=\"my-3 max-w-full overflow-x-auto rounded-og-md border border-og-border first:mt-0 last:mb-0\">\n <table className=\"w-full border-collapse text-og-base\" {...props}>\n {children}\n </table>\n </div>\n ),\n thead: ({ children, ...props }) => (\n <thead className=\"bg-og-surface-1\" {...props}>\n {children}\n </thead>\n ),\n th: ({ children, ...props }) => (\n <th\n className=\"border-b border-og-border px-3 py-1.5 text-left font-medium text-og-fg\"\n {...props}\n >\n {children}\n </th>\n ),\n td: ({ children, ...props }) => (\n <td\n className=\"border-b border-og-border px-3 py-1.5 align-top text-og-fg-muted [tr:last-child>&]:border-b-0\"\n {...props}\n >\n {children}\n </td>\n ),\n img: ({ alt, ...props }) => (\n <img\n alt={alt ?? \"\"}\n className=\"my-3 max-w-full rounded-og-md border border-og-border\"\n {...props}\n />\n ),\n};\n\nfunction MarkdownImpl({ children, className }: MarkdownProps) {\n return (\n // `min-w-0` lets the prose shrink inside flex parents (message bubbles) so\n // long links and code blocks wrap/scroll instead of forcing overflow.\n <div className={cn(\"min-w-0 break-words\", className)}>\n <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>\n {children}\n </ReactMarkdown>\n </div>\n );\n}\n\n/** Memoized so streaming re-renders of the parent don't re-parse settled bodies. */\nexport const Markdown = memo(MarkdownImpl);\n","import type { SessionStatus as SessionStatusValue } from \"@opengeni/sdk\";\nimport { cn } from \"../lib/cn\";\n\nexport type SessionStatusMeta = {\n label: string;\n /** Token-backed color classes for the dot and tinted badge. */\n dotClassName: string;\n badgeClassName: string;\n /** Live states breathe; terminal states hold still. */\n pulse: boolean;\n};\n\nexport const SESSION_STATUS_META: Record<SessionStatusValue, SessionStatusMeta> = {\n queued: {\n label: \"Queued\",\n dotClassName: \"bg-og-status-queued\",\n badgeClassName: \"text-og-fg-muted border-og-border bg-og-status-queued/10\",\n pulse: true,\n },\n running: {\n label: \"Running\",\n dotClassName: \"bg-og-status-running\",\n badgeClassName: \"text-og-status-running border-og-status-running/30 bg-og-status-running/10\",\n pulse: true,\n },\n recovering: {\n label: \"Recovering\",\n dotClassName: \"bg-og-status-running\",\n badgeClassName: \"text-og-status-running border-og-status-running/30 bg-og-status-running/10\",\n pulse: true,\n },\n waiting_capacity: {\n label: \"Waiting for capacity\",\n dotClassName: \"bg-og-status-waiting\",\n badgeClassName: \"text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10\",\n pulse: true,\n },\n paused: {\n label: \"Paused\",\n dotClassName: \"bg-og-status-cancelled\",\n badgeClassName: \"text-og-fg-subtle border-og-border bg-og-status-cancelled/10\",\n pulse: false,\n },\n idle: {\n label: \"Idle\",\n dotClassName: \"bg-og-status-idle\",\n badgeClassName: \"text-og-status-idle border-og-status-idle/30 bg-og-status-idle/10\",\n pulse: false,\n },\n requires_action: {\n label: \"Waiting on you\",\n dotClassName: \"bg-og-status-waiting\",\n badgeClassName: \"text-og-status-waiting border-og-status-waiting/35 bg-og-status-waiting/10\",\n pulse: true,\n },\n failed: {\n label: \"Failed\",\n dotClassName: \"bg-og-status-failed\",\n badgeClassName: \"text-og-status-failed border-og-status-failed/35 bg-og-status-failed/10\",\n pulse: false,\n },\n cancelled: {\n label: \"Cancelled\",\n dotClassName: \"bg-og-status-cancelled\",\n badgeClassName: \"text-og-fg-subtle border-og-border bg-og-status-cancelled/10\",\n pulse: false,\n },\n};\n\nexport type SessionStatusProps = {\n status: SessionStatusValue;\n /** Override the label (\"Running\" -> \"Deploying\", ...). */\n label?: string | undefined;\n size?: \"sm\" | \"md\" | undefined;\n className?: string | undefined;\n};\n\n/** Status badge with a breathing dot for live states. */\nexport function SessionStatus({ status, label, size = \"md\", className }: SessionStatusProps) {\n const meta = SESSION_STATUS_META[status];\n return (\n <span\n data-status={status}\n className={cn(\n \"og-root inline-flex shrink-0 items-center rounded-full border font-medium\",\n size === \"sm\" ? \"gap-1 px-1.5 py-px text-og-xs\" : \"gap-1.5 px-2 py-0.5 text-xs\",\n meta.badgeClassName,\n className,\n )}\n >\n <StatusDot status={status} className={size === \"sm\" ? \"size-1\" : \"size-1.5\"} />\n {label ?? meta.label}\n </span>\n );\n}\n\nexport type StatusDotProps = {\n status: SessionStatusValue;\n className?: string | undefined;\n};\n\n/** Just the dot — for dense rows and tiles. */\nexport function StatusDot({ status, className }: StatusDotProps) {\n const meta = SESSION_STATUS_META[status];\n return (\n <span\n className={cn(\n \"relative inline-flex size-1.5 shrink-0 rounded-full\",\n meta.dotClassName,\n className,\n )}\n >\n {meta.pulse ? (\n <span className={cn(\"absolute inset-0 animate-og-pulse rounded-full\", meta.dotClassName)} />\n ) : null}\n </span>\n );\n}\n","import type { Session } from \"@opengeni/sdk\";\nimport { cn } from \"../lib/cn\";\nimport { formatRelativeTime, truncate } from \"../lib/format\";\nimport { SessionStatus } from \"./session-status\";\n\nexport type FleetTileProps = {\n session: Session;\n /** Overrides the derived title (metadata.title/name, else the initial message). */\n title?: string | undefined;\n /** Extra line under the title — e.g. \"drift check\" or the worker's task. */\n subtitle?: string | undefined;\n onOpen?: ((session: Session) => void) | undefined;\n className?: string | undefined;\n};\n\n/** Best-effort display title for a session. */\nexport function sessionDisplayTitle(session: Session): string {\n // A set title (agent-generated or user-renamed) wins over metadata + the\n // initial-message fallback.\n if (typeof session.title === \"string\" && session.title.trim().length > 0) {\n return session.title;\n }\n for (const key of [\"title\", \"name\"] as const) {\n const value = session.metadata[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n }\n return truncate(session.initialMessage, 100) || session.id.slice(0, 8);\n}\n\n/**\n * One session in the fleet/manager view: title, live status, model, and\n * recency — dense but calm. Running sessions carry a breathing status dot\n * and a faint accent edge so the live ones read at a glance.\n */\nexport function FleetTile({ session, title, subtitle, onOpen, className }: FleetTileProps) {\n const running = session.status === \"running\" || session.status === \"queued\";\n const needsYou = session.status === \"requires_action\";\n return (\n <button\n type=\"button\"\n data-status={session.status}\n onClick={onOpen ? () => onOpen(session) : undefined}\n disabled={!onOpen}\n className={cn(\n \"og-root group relative flex w-full flex-col gap-2.5 overflow-hidden rounded-og-lg border border-og-border\",\n \"bg-og-surface-1 p-4 text-left shadow-og-sm\",\n \"transition-[border-color,background-color,box-shadow,transform] duration-200 ease-og-out\",\n onOpen &&\n \"hover:-translate-y-px hover:border-og-border-strong hover:bg-og-surface-2 hover:shadow-og-md\",\n \"disabled:cursor-default\",\n className,\n )}\n >\n <span\n aria-hidden\n className={cn(\n \"absolute inset-y-0 left-0 w-0.5 transition-opacity duration-300\",\n running\n ? \"bg-og-accent opacity-100\"\n : needsYou\n ? \"bg-og-status-waiting opacity-100\"\n : \"opacity-0\",\n )}\n />\n <span className=\"flex w-full items-start justify-between gap-3\">\n <span className=\"line-clamp-2 min-w-0 text-og-base font-medium leading-snug text-og-fg\">\n {title ?? sessionDisplayTitle(session)}\n </span>\n <SessionStatus status={session.status} size=\"sm\" className=\"mt-px\" />\n </span>\n {subtitle ? (\n <span className=\"line-clamp-1 text-og-sm text-og-fg-muted\">{subtitle}</span>\n ) : null}\n <span className=\"mt-auto flex w-full items-center gap-2 text-og-xs text-og-fg-subtle\">\n <span className=\"font-og-mono\">{session.id.slice(0, 8)}</span>\n <span aria-hidden>·</span>\n <span className=\"truncate\">{session.model}</span>\n <span className=\"ml-auto shrink-0\" title={session.updatedAt}>\n {formatRelativeTime(session.updatedAt)}\n </span>\n </span>\n </button>\n );\n}\n","import type { TerminalCapability } from \"@opengeni/sdk\";\nimport { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useTerminalStream } from \"../hooks/use-terminal-stream\";\nimport type { UseSandboxTerminalResult } from \"../hooks/use-sandbox-terminal\";\nimport { resolveTerminalFont, xtermThemeFromTokens } from \"../lib/xterm-theme\";\nimport { attachRenderer, type RendererLoaders, type RendererTier } from \"../lib/xterm-renderer\";\n\n/**\n * A COMPLETE xterm `ITheme` (subset by intent, but every field xterm colors a\n * cell with is present so it never falls back to its stock VGA palette). Built\n * from the og tokens via `xtermThemeFromTokens`.\n */\nexport type XtermTheme = {\n background?: string;\n foreground?: string;\n cursor?: string;\n cursorAccent?: string;\n selectionBackground?: string;\n selectionForeground?: string;\n selectionInactiveBackground?: string;\n black?: string;\n red?: string;\n green?: string;\n yellow?: string;\n blue?: string;\n magenta?: string;\n cyan?: string;\n white?: string;\n brightBlack?: string;\n brightRed?: string;\n brightGreen?: string;\n brightYellow?: string;\n brightBlue?: string;\n brightMagenta?: string;\n brightCyan?: string;\n brightWhite?: string;\n};\n\nexport type SandboxTerminalProps = {\n /** From `useSandboxTerminal(...)`. */\n result: UseSandboxTerminalResult;\n /**\n * The negotiated Terminal capability cell. When it advertises `transport:\n * \"pty-ws\"` + a live `url` (a warm box with a viewer attached), the terminal is\n * driven by a REAL bidirectional PTY over the Modal tunnel (ttyd-over-websocket)\n * INSTEAD of the broken ptyWrite-over-HTTP path: xterm input → the socket, the\n * socket's output → xterm, xterm resize → the socket. On a cold box / no url\n * (`transport: \"sse-events\"`) it stays on the read-only Channel-A firehose\n * (`result.chunks`). Omit to force the legacy firehose-only behavior.\n */\n terminalCapability?: TerminalCapability | null | undefined;\n /**\n * Full xterm theme. When omitted the terminal self-derives it from the `--og-*`\n * tokens of its own container (correct even inside a nested `data-og-theme`\n * subtree). Passing it lets the host drive re-theme on a theme flip.\n */\n theme?: XtermTheme | undefined;\n fontFamily?: string | undefined;\n fontSize?: number | undefined;\n /**\n * Lease liveness (`cold` | `warming` | `warm` | `draining`). Drives the\n * boot-in-terminal status lines: once the user has focused the terminal and\n * the box is not yet warm, a styled \"● waking machine — Ns…\" line is rendered\n * INSIDE xterm (no overlay/spinner) until the live PTY connects.\n */\n liveness?: string | undefined;\n /**\n * Force read-only even when the PTY accepts stdin. Default: interactive\n * whenever a live pty-ws stream is connected OR `result.write !== null` (the box\n * advertises an interactive PTY); otherwise the read-only agent firehose.\n */\n readOnly?: boolean | undefined;\n /** Shown on the server / before xterm hydrates (SSR-safe placeholder). */\n placeholder?: ReactNode | undefined;\n /** Render the small status header (pty/shell + running dot + read-only pill). */\n showHeader?: boolean | undefined;\n /** Shell label for the header (e.g. `/bin/bash`). */\n shell?: string | undefined;\n /**\n * Fired the first time the user engages the terminal surface (focus or click).\n * The host wires this to warm the box for the REAL pty-ws terminal (the viewer\n * attach), so a cold box upgrades from the read-only firehose to a live PTY ON\n * INTERACT — never on mere mount (which would force a box spin-up and regress\n * the firehose-only default).\n */\n onActivate?: (() => void) | undefined;\n className?: string | undefined;\n};\n\n// The xterm.js handle the effect owns. `any`-free structural shape so we can\n// drive it without a hard type dep on the lazily-imported lib.\ntype XtermLike = {\n open: (el: HTMLElement) => void;\n write: (data: string) => void;\n clear: () => void;\n onData: (cb: (data: string) => void) => { dispose: () => void };\n onResize: (cb: (size: { cols: number; rows: number }) => void) => { dispose: () => void };\n loadAddon: (addon: unknown) => void;\n dispose: () => void;\n cols: number;\n rows: number;\n options: {\n theme?: XtermTheme;\n disableStdin?: boolean;\n cursorBlink?: boolean;\n fontFamily?: string;\n fontSize?: number;\n };\n};\ntype FitAddonLike = { fit: () => void };\n\n/** Debug seam (dev/evidence only, never a typed public API): a global hook the\n * screenshot harness reads to probe the settled renderer tier + resolved font\n * without mounting a real WebGL context in unit tests. */\ntype TerminalDebugInfo = {\n renderer: RendererTier | null;\n fontFamily: string | undefined;\n fontSize: number | undefined;\n hasVarInFont: boolean;\n theme: XtermTheme | undefined;\n /** The live xterm instance (opaque) — the evidence harness reads its buffer to\n * prove screen preservation (E5) and drive the burst-responsiveness probe. */\n term: unknown;\n};\ndeclare global {\n // eslint-disable-next-line no-var\n var __OG_TERMINAL_DEBUG__: ((info: TerminalDebugInfo) => void) | undefined;\n // A space/comma list of renderer tiers to force-fail, so the demo can prove the\n // WebGL→canvas→DOM fallback ladder without a real GPU context loss.\n // eslint-disable-next-line no-var\n var __OG_FORCE_RENDERER_FAIL__: string | undefined;\n}\n\n/** Which renderer tiers are force-failed (demo/evidence only). */\nfunction forcedRendererFailures(): Set<RendererTier> {\n const raw = typeof globalThis !== \"undefined\" ? globalThis.__OG_FORCE_RENDERER_FAIL__ : undefined;\n const set = new Set<RendererTier>();\n if (typeof raw === \"string\") {\n for (const tier of raw.split(/[\\s,]+/)) {\n if (tier === \"webgl\" || tier === \"canvas\") set.add(tier);\n }\n }\n return set;\n}\n\n/**\n * An xterm.js terminal fed by the Channel-A event projection\n * (`useSandboxTerminal`) or a live ttyd PTY. xterm + its addons are lazy-imported\n * inside an effect, so SSR renders the placeholder and the terminal mounts on\n * hydration.\n *\n * Renderer: WebGL (GPU-composited cells) with a canvas → DOM fallback ladder\n * (`attachRenderer`), so bursty output stays smooth but a lost/blocklisted\n * context degrades gracefully. Font + theme are resolved to CONCRETE values\n * from the og tokens BEFORE construction (xterm measures glyphs in a canvas\n * where `var()` never resolves, and colors every cell from a full ANSI palette).\n *\n * The terminal is mounted ONCE and its data source is swapped in place: the\n * read-only firehose (`result.chunks`) → the live PTY. Stdin is toggled via\n * `term.options.disableStdin` at runtime (not a remount), so scrollback and the\n * visible screen survive the projection→PTY handoff.\n *\n * Resizes are tracked with a `ResizeObserver` on the container (not just\n * `window.resize`) so dragging the dock handle refits the grid.\n */\nexport function SandboxTerminal({\n result,\n terminalCapability,\n theme,\n fontFamily,\n fontSize,\n liveness,\n readOnly,\n placeholder,\n showHeader,\n shell,\n onActivate,\n className,\n}: SandboxTerminalProps) {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const termRef = useRef<XtermLike | null>(null);\n const fitRef = useRef<FitAddonLike | null>(null);\n const rendererRef = useRef<RendererTier | null>(null);\n const writtenRef = useRef<Set<string>>(new Set());\n const wroteFirehoseRef = useRef(false);\n const bootActiveRef = useRef(false);\n const [ready, setReady] = useState(false);\n const [activated, setActivated] = useState(false);\n\n // ── Interactive transport switch ─────────────────────────────────────────────\n const ptyWs = terminalCapability?.transport === \"pty-ws\" && Boolean(terminalCapability?.url);\n // Output frames buffer here until xterm has mounted; the write effect drains it.\n const ptyOutputQueueRef = useRef<string[]>([]);\n const {\n status: ptyStatus,\n write: ptyWrite,\n resize: resizePty,\n connected: ptyConnected,\n } = useTerminalStream({\n capability: ptyWs\n ? {\n transport: terminalCapability!.transport,\n url: terminalCapability!.url,\n token: terminalCapability!.token,\n }\n : null,\n onOutput: (data) => {\n const term = termRef.current;\n if (term) term.write(data);\n else ptyOutputQueueRef.current.push(data);\n },\n });\n\n // PTY mode = a live ttyd socket drives the screen. Firehose mode = the\n // read-only projection (or the legacy HTTP-write fallback).\n const ptyMode = ptyWs && ptyStatus !== \"closed\";\n const interactive = !readOnly && (ptyMode || result.write !== null);\n\n // Boot-in-terminal: after the user focuses a not-yet-warm box, show styled\n // status lines INSIDE xterm instead of an overlay — but only when there is no\n // firehose transcript to show yet (otherwise the projected output is shown).\n const warm = liveness === \"warm\" || liveness === \"draining\";\n const booting = activated && !ptyMode && !warm && liveness != null && result.chunks.length === 0;\n\n function handleActivate() {\n if (!activated) setActivated(true);\n onActivate?.();\n }\n\n // Mount xterm once (client-only). Never re-mounts on interactive/theme flips —\n // stdin + theme are runtime options synced by the effects below, so the visible\n // screen survives the projection→PTY handoff (E5).\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const el = containerRef.current;\n if (!el) return;\n let disposed = false;\n\n // Wait for a real measured size before opening xterm so the first fit is at\n // the true width (belt-and-braces with the visibility gate below).\n const waitForSize = (node: HTMLElement) =>\n new Promise<void>((resolve) => {\n if (node.clientWidth > 0 && node.clientHeight > 0) return resolve();\n const ro = new ResizeObserver(() => {\n if (node.clientWidth > 0 && node.clientHeight > 0) {\n ro.disconnect();\n resolve();\n }\n });\n ro.observe(node);\n setTimeout(() => {\n ro.disconnect();\n resolve();\n }, 1000);\n });\n\n ensureXtermBaseCss();\n\n void (async () => {\n const [{ Terminal }, { FitAddon }, { WebLinksAddon }] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ]);\n if (disposed) return;\n await waitForSize(el);\n if (disposed) return;\n\n // Resolve font + theme to CONCRETE values BEFORE construction. `var()` in a\n // font family never resolves in xterm's canvas measurement, so we read the\n // computed `--og-font-mono` here; the theme is a full ANSI palette.\n const font = resolveTerminalFont(el, { fontFamily, fontSize });\n const initialTheme = theme ?? xtermThemeFromTokens(el);\n\n const term = new Terminal({\n convertEol: true,\n disableStdin: !interactive,\n cursorBlink: interactive,\n fontFamily: font.fontFamily,\n fontSize: font.fontSize,\n lineHeight: font.lineHeight,\n ...(initialTheme ? { theme: initialTheme } : {}),\n }) as unknown as XtermLike;\n const fit = new FitAddon() as unknown as FitAddonLike;\n term.loadAddon(fit);\n term.loadAddon(\n new WebLinksAddon((_e: MouseEvent, uri: string) =>\n window.open(uri, \"_blank\", \"noopener,noreferrer\"),\n ) as unknown,\n );\n term.open(el);\n termRef.current = term;\n fitRef.current = fit;\n\n // Attach the fastest available renderer. For xterm-6 the supported ladder\n // is WebGL → DOM (the standalone 2D-canvas addon targets xterm-5 internals,\n // so it is intentionally NOT in the shipped path). Init failure / context\n // loss steps down to xterm's built-in DOM renderer; the settled tier is\n // exposed for evidence.\n const failSet = forcedRendererFailures();\n const loaders: RendererLoaders = {\n webgl: async (onLoss) => {\n if (failSet.has(\"webgl\")) throw new Error(\"forced webgl failure\");\n const { WebglAddon } = await import(\"@xterm/addon-webgl\");\n const addon = new WebglAddon() as unknown as {\n dispose: () => void;\n onContextLoss?: (cb: () => void) => void;\n };\n addon.onContextLoss?.(() => {\n try {\n addon.dispose();\n } catch {\n // already disposed\n }\n onLoss();\n });\n term.loadAddon(addon);\n return addon;\n },\n };\n await attachRenderer(\"webgl\", loaders, (tier) => {\n rendererRef.current = tier;\n el.setAttribute(\"data-og-term-renderer\", tier);\n });\n if (disposed) return;\n\n // Fit BEFORE reveal so the first visible frame is already correctly sized\n // (no 80×24 rasterize-then-reflow flash — the container stays hidden until\n // now via the `ready` visibility gate).\n const settle = () => {\n try {\n fit.fit();\n } catch {\n // ignore fit before layout\n }\n };\n settle();\n requestAnimationFrame(() => {\n if (disposed) return;\n settle();\n if (ptyOutputQueueRef.current.length > 0) {\n for (const data of ptyOutputQueueRef.current) term.write(data);\n ptyOutputQueueRef.current = [];\n }\n el.setAttribute(\"data-og-term-ready\", \"true\");\n if (typeof globalThis.__OG_TERMINAL_DEBUG__ === \"function\") {\n globalThis.__OG_TERMINAL_DEBUG__({\n renderer: rendererRef.current,\n fontFamily: term.options.fontFamily,\n fontSize: term.options.fontSize,\n hasVarInFont: String(term.options.fontFamily ?? \"\").includes(\"var(\"),\n theme: term.options.theme,\n term,\n });\n }\n setReady(true);\n });\n })();\n\n return () => {\n disposed = true;\n termRef.current?.dispose();\n termRef.current = null;\n fitRef.current = null;\n rendererRef.current = null;\n writtenRef.current = new Set();\n wroteFirehoseRef.current = false;\n bootActiveRef.current = false;\n setReady(false);\n };\n // Mount ONCE — see the effects below for the runtime option syncs.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Sync stdin/cursor at runtime (NOT a remount) when interactivity flips, so the\n // projection→PTY handoff keeps the single Terminal instance + its scrollback.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term) return;\n term.options.disableStdin = !interactive;\n term.options.cursorBlink = interactive;\n }, [ready, interactive]);\n\n // Re-theme live (dark↔light flip) without re-mounting / losing scrollback. Uses\n // the passed theme, or self-derives from the container's tokens.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term) return;\n const next = theme ?? xtermThemeFromTokens(containerRef.current);\n if (next) term.options.theme = next;\n }, [ready, theme]);\n\n // Boot-in-terminal status lines. While `booting`, paint a styled \"● waking\n // machine — Ns…\" line and tick it. On exit, if those lines were the ONLY\n // content (no firehose transcript), clear them for the incoming live screen —\n // never clear a real transcript (E5 preservation).\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term) return;\n if (!booting) {\n if (bootActiveRef.current) {\n bootActiveRef.current = false;\n if (!wroteFirehoseRef.current) term.clear();\n }\n return;\n }\n bootActiveRef.current = true;\n const start = Date.now();\n const paint = () => {\n const s = Math.max(0, Math.round((Date.now() - start) / 1000));\n // Bright-blue dot (accent) + dim label; `\\r` + clear-line keeps it on one\n // line so the counter updates in place.\n term.write(`\\r\\x1b[2K\\x1b[94m●\\x1b[0m \\x1b[2mwaking machine — ${s}s…\\x1b[0m`);\n };\n term.write(\"\\r\\n\");\n paint();\n const id = setInterval(paint, 1000);\n return () => clearInterval(id);\n }, [ready, booting]);\n\n // Write new firehose chunks incrementally — ONLY in firehose mode. In PTY mode\n // the ttyd socket owns the screen. Records that a real transcript exists so the\n // boot cleanup never wipes it.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term || ptyMode) return;\n for (const chunk of result.chunks) {\n if (writtenRef.current.has(chunk.id)) continue;\n writtenRef.current.add(chunk.id);\n wroteFirehoseRef.current = true;\n term.write(chunk.text);\n }\n }, [ready, result.chunks, ptyMode]);\n\n // Wire interactive input when allowed. PTY mode pipes keystrokes to the ttyd\n // socket; firehose mode uses the legacy ptyWrite-over-HTTP fn.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term || !interactive) return;\n const sink = ptyMode ? ptyWrite : result.write;\n if (!sink) return;\n const sub = term.onData((data) => sink(data));\n return () => sub.dispose();\n }, [ready, interactive, ptyMode, ptyWrite, result.write]);\n\n // In PTY mode, tell ttyd the window size on the xterm resize event.\n useEffect(() => {\n const term = termRef.current;\n if (!ready || !term || !ptyMode) return;\n resizePty(term.cols, term.rows);\n const sub = term.onResize(({ cols, rows }) => resizePty(cols, rows));\n return () => sub.dispose();\n }, [ready, ptyMode, ptyConnected, resizePty]);\n\n // Refit on container resize (dock drag) AND window resize.\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const refit = () => {\n try {\n fitRef.current?.fit();\n } catch {\n // ignore\n }\n };\n window.addEventListener(\"resize\", refit);\n let observer: ResizeObserver | null = null;\n const el = containerRef.current;\n if (el && typeof ResizeObserver !== \"undefined\") {\n observer = new ResizeObserver(() => refit());\n observer.observe(el);\n }\n return () => {\n window.removeEventListener(\"resize\", refit);\n observer?.disconnect();\n };\n }, [ready]);\n\n return (\n <div className={cn(\"relative flex h-full w-full flex-col overflow-hidden\", className)}>\n {showHeader && (\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-og-border px-2 py-1 text-og-xs text-og-fg-subtle\">\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <span\n className={cn(\n \"size-1.5 shrink-0 rounded-full\",\n result.running ? \"bg-og-status-running\" : \"bg-og-fg-subtle\",\n )}\n />\n <span className=\"truncate font-og-mono\">pty: {shell ?? \"shell\"}</span>\n </span>\n <span className=\"flex shrink-0 items-center gap-2\">\n {!interactive && (\n <span className=\"rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-xs uppercase tracking-wide\">\n read-only\n </span>\n )}\n <button\n type=\"button\"\n onClick={() => {\n termRef.current?.clear();\n writtenRef.current = new Set();\n wroteFirehoseRef.current = false;\n }}\n className=\"rounded-og-sm px-1.5 py-0.5 text-og-xs hover:text-og-fg pointer-coarse:min-h-10\"\n >\n Clear\n </button>\n </span>\n </div>\n )}\n {/* `onPointerDownCapture`/`onFocusCapture` fire on the FIRST user engagement\n with the terminal surface (capture so they win even though xterm's own\n listeners stop propagation). The host warms the box for pty-ws here. The\n 12px inset + `--og-color-bg` ground match the dock surface. */}\n <div\n className=\"relative min-h-0 flex-1 bg-og-bg p-3\"\n onPointerDownCapture={handleActivate}\n onFocusCapture={handleActivate}\n >\n {!ready && (placeholder ?? <TerminalPlaceholder />)}\n {/* Kept `visibility:hidden` until the first successful fit so the first\n VISIBLE frame is already correctly sized (no 80×24 flash — E4). */}\n <div\n ref={containerRef}\n className=\"h-full w-full\"\n style={{ visibility: ready ? \"visible\" : \"hidden\" }}\n data-opengeni-terminal\n />\n </div>\n </div>\n );\n}\n\n// xterm.js ships a stylesheet (`@xterm/xterm/css/xterm.css`) that is REQUIRED for\n// correct layout — without it the `.xterm-helper-textarea` (an off-screen input\n// xterm uses for IME/keystrokes) is NOT clipped and renders as a visible 1-line\n// box in the top-left (the \"weird input box\" bug), and the viewport/screen aren't\n// positioned. The host app never imports that CSS (no global stylesheet here), so\n// we inject the structural rules once, idempotently (keyed by id), the first time\n// any terminal mounts. Scoped under `.xterm` so it can't leak into host styles.\nconst XTERM_STYLE_ID = \"opengeni-xterm-base-css\";\nconst XTERM_BASE_CSS = `\n.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}\n.xterm.focus,.xterm:focus{outline:none}\n.xterm .xterm-helpers{position:absolute;top:0;z-index:5}\n.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}\n.xterm .composition-view{background:var(--og-color-bg);color:var(--og-color-fg);display:none;position:absolute;white-space:nowrap;z-index:1}\n.xterm .composition-view.active{display:block}\n.xterm .xterm-viewport{background-color:transparent;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}\n.xterm .xterm-screen{position:relative}\n.xterm .xterm-screen canvas{position:absolute;left:0;top:0}\n.xterm .xterm-scroll-area{visibility:hidden}\n.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}\n.xterm.enable-mouse-events{cursor:default}\n.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}\n.xterm.column-select.focus{cursor:crosshair}\n.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}\n.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}\n.xterm .xterm-accessibility-tree{user-select:text;white-space:pre}\n.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}\n.xterm-dim{opacity:1!important}\n.xterm-underline-1{text-decoration:underline}\n.xterm-underline-2{text-decoration:double underline}\n.xterm-underline-3{text-decoration:wavy underline}\n.xterm-underline-4{text-decoration:dotted underline}\n.xterm-underline-5{text-decoration:dashed underline}\n.xterm-overline{text-decoration:overline}\n.xterm-strikethrough{text-decoration:line-through}\n.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}\n.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}\n.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}\n.xterm-decoration-top{z-index:2;position:relative}\n`;\n\nfunction ensureXtermBaseCss(): void {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(XTERM_STYLE_ID)) return;\n const style = document.createElement(\"style\");\n style.id = XTERM_STYLE_ID;\n style.textContent = XTERM_BASE_CSS;\n document.head.appendChild(style);\n}\n\nfunction TerminalPlaceholder() {\n return (\n <div className=\"absolute inset-0 flex items-center justify-center text-og-sm text-og-fg-subtle\">\n Loading terminal…\n </div>\n );\n}\n","import type { XtermTheme } from \"../components/sandbox-terminal\";\n\n/* ----------------------------------------------------------------------------\n xterm theming + font resolution from the `--og-*` token system.\n\n xterm paints glyphs into a canvas (WebGL / 2D) and builds its font strings by\n hand, so it can consume NEITHER CSS custom properties (`var(--og-font-mono)`\n never resolves in a canvas font string) NOR a partial palette (an unset ANSI\n slot falls back to xterm's stock VGA color). This module resolves both to\n concrete values: a full 16-color ANSI ITheme designed against the og palette\n for BOTH themes, and a concrete monospace family + px size.\n\n The color-building + font-resolution cores are pure over a token `read`\n function so they unit-test without a DOM; thin `*FromTokens` / `resolve*`\n wrappers do the `getComputedStyle` read on the client.\n -------------------------------------------------------------------------- */\n\nexport type ThemeMode = \"dark\" | \"light\";\n\n/** Reads a resolved token value (already `getComputedStyle`-flattened). */\nexport type TokenReader = (name: string) => string | undefined;\n\n/**\n * The 16 ANSI colors + selection/cursor treatment, designed against the og\n * OKLCH palette. Hues are borrowed from the og status ramp so terminal color\n * reads as part of the same system: red≈status-failed(22), green≈status-idle\n * (155), yellow≈status-running(80), blue≈accent(255), magenta≈status-waiting\n * (305), cyan≈200. Dark uses lifted lightness on the dark slate ground; light\n * uses deeper, more saturated inks on the near-white ground. Bright variants\n * add lightness + a touch of chroma. `black`/`white` are neutral slate ramp\n * stops (never pure #000/#fff — that clashes with the calm neutral ground).\n */\nexport type AnsiPalette = {\n black: string;\n red: string;\n green: string;\n yellow: string;\n blue: string;\n magenta: string;\n cyan: string;\n white: string;\n brightBlack: string;\n brightRed: string;\n brightGreen: string;\n brightYellow: string;\n brightBlue: string;\n brightMagenta: string;\n brightCyan: string;\n brightWhite: string;\n /** Selection wash + its foreground; sits over the terminal ground. */\n selectionBackground: string;\n selectionForeground: string;\n selectionInactiveBackground: string;\n};\n\nconst DARK_ANSI: AnsiPalette = {\n black: \"oklch(0.3 0.014 260)\",\n red: \"oklch(0.68 0.17 22)\",\n green: \"oklch(0.75 0.13 155)\",\n yellow: \"oklch(0.8 0.11 80)\",\n blue: \"oklch(0.7 0.14 255)\",\n magenta: \"oklch(0.72 0.13 305)\",\n cyan: \"oklch(0.75 0.1 210)\",\n white: \"oklch(0.8 0.01 260)\",\n brightBlack: \"oklch(0.45 0.014 260)\",\n brightRed: \"oklch(0.76 0.17 22)\",\n brightGreen: \"oklch(0.82 0.14 155)\",\n brightYellow: \"oklch(0.86 0.12 85)\",\n brightBlue: \"oklch(0.78 0.13 255)\",\n brightMagenta: \"oklch(0.8 0.13 305)\",\n brightCyan: \"oklch(0.83 0.1 200)\",\n brightWhite: \"oklch(0.97 0.005 260)\",\n selectionBackground: \"oklch(0.72 0.15 255 / 0.34)\",\n selectionForeground: \"oklch(0.985 0.005 260)\",\n selectionInactiveBackground: \"oklch(0.72 0.02 260 / 0.22)\",\n};\n\nconst LIGHT_ANSI: AnsiPalette = {\n black: \"oklch(0.35 0.015 260)\",\n red: \"oklch(0.52 0.19 22)\",\n green: \"oklch(0.5 0.13 155)\",\n yellow: \"oklch(0.56 0.13 80)\",\n blue: \"oklch(0.52 0.18 255)\",\n magenta: \"oklch(0.52 0.16 305)\",\n cyan: \"oklch(0.52 0.1 210)\",\n white: \"oklch(0.7 0.01 260)\",\n brightBlack: \"oklch(0.5 0.014 260)\",\n brightRed: \"oklch(0.55 0.2 22)\",\n brightGreen: \"oklch(0.54 0.14 155)\",\n brightYellow: \"oklch(0.6 0.14 80)\",\n brightBlue: \"oklch(0.48 0.19 255)\",\n brightMagenta: \"oklch(0.54 0.17 305)\",\n brightCyan: \"oklch(0.54 0.11 210)\",\n brightWhite: \"oklch(0.3 0.015 260)\",\n selectionBackground: \"oklch(0.55 0.18 255 / 0.24)\",\n selectionForeground: \"oklch(0.21 0.015 260)\",\n selectionInactiveBackground: \"oklch(0.6 0.02 260 / 0.16)\",\n};\n\n/** The designed ANSI-16 palette for a theme mode. Pure. */\nexport function ogAnsiPalette(mode: ThemeMode): AnsiPalette {\n return mode === \"light\" ? LIGHT_ANSI : DARK_ANSI;\n}\n\n/**\n * Build a COMPLETE xterm ITheme from token values. Background/foreground/cursor\n * come from the live `--og-*` tokens (so an embedder's rebrand flows through);\n * the ANSI-16 + selection come from the designed palette for `mode`. Every ANSI\n * slot is always set — xterm never falls back to its stock VGA colors. Pure.\n */\nexport function buildXtermTheme(read: TokenReader, mode: ThemeMode): XtermTheme {\n const ansi = ogAnsiPalette(mode);\n const bgFallback = mode === \"light\" ? \"oklch(0.978 0.003 260)\" : \"oklch(0.155 0.012 260)\";\n const fgFallback = mode === \"light\" ? \"oklch(0.21 0.015 260)\" : \"oklch(0.955 0.005 260)\";\n const bg = read(\"--og-color-bg\") ?? bgFallback;\n const fg = read(\"--og-color-fg\") ?? fgFallback;\n const accent = read(\"--og-color-accent\") ?? ansi.brightBlue;\n return {\n // Match the dock surface the terminal paints on (`--og-color-bg`).\n background: bg,\n foreground: fg,\n cursor: accent,\n cursorAccent: bg,\n selectionBackground: ansi.selectionBackground,\n selectionForeground: ansi.selectionForeground,\n selectionInactiveBackground: ansi.selectionInactiveBackground,\n black: ansi.black,\n red: ansi.red,\n green: ansi.green,\n yellow: ansi.yellow,\n blue: ansi.blue,\n magenta: ansi.magenta,\n cyan: ansi.cyan,\n white: ansi.white,\n brightBlack: ansi.brightBlack,\n brightRed: ansi.brightRed,\n brightGreen: ansi.brightGreen,\n brightYellow: ansi.brightYellow,\n brightBlue: ansi.brightBlue,\n brightMagenta: ansi.brightMagenta,\n brightCyan: ansi.brightCyan,\n brightWhite: ansi.brightWhite,\n };\n}\n\n/** Which og theme is active for `el`, matching the `use-theme-type` convention\n * (nearest `data-og-theme` / `.og-light` ancestor; else the computed\n * `color-scheme`; else dark, the first-class default). */\nfunction detectMode(el: Element, style: CSSStyleDeclaration): ThemeMode {\n const closest = el.closest?.bind(el);\n if (closest) {\n if (closest('[data-og-theme=\"light\"]') || closest(\".og-light\")) return \"light\";\n const explicit = closest(\"[data-og-theme]\");\n if (explicit) return explicit.getAttribute(\"data-og-theme\") === \"light\" ? \"light\" : \"dark\";\n }\n const scheme = (\n style.getPropertyValue(\"color-scheme\").trim() ||\n style.colorScheme ||\n \"\"\n ).toLowerCase();\n if (scheme.includes(\"light\") && !scheme.includes(\"dark\")) return \"light\";\n return \"dark\";\n}\n\n/**\n * Derive a COMPLETE xterm `ITheme` from the live `--og-*` token system on the\n * DOM. Reads the COMPUTED values so xterm gets concrete colors, detects the\n * active theme mode, and fills every ANSI slot. Call on mount + re-derive on a\n * `data-og-theme` flip. SSR-safe: returns undefined off the DOM.\n *\n * `root` should be an element INSIDE the themed subtree (e.g. the terminal\n * container) so nested `[data-og-theme]` themes resolve correctly; when omitted\n * it falls back to the nearest `[data-og-theme]` element, then documentElement.\n */\nexport function xtermThemeFromTokens(root?: HTMLElement | null): XtermTheme | undefined {\n if (typeof window === \"undefined\" || typeof getComputedStyle === \"undefined\") return undefined;\n const el =\n root ??\n (typeof document !== \"undefined\"\n ? ((document.querySelector(\"[data-og-theme]\") as HTMLElement | null) ??\n document.documentElement)\n : null);\n if (!el) return undefined;\n const style = getComputedStyle(el);\n const read: TokenReader = (name) => {\n const value = style.getPropertyValue(name).trim();\n return value || undefined;\n };\n return buildXtermTheme(read, detectMode(el, style));\n}\n\n// ── Font resolution ──────────────────────────────────────────────────────────\n\nexport type ResolvedTerminalFont = { fontFamily: string; fontSize: number; lineHeight: number };\n\n/** Concrete fallback if the token is unset or (defensively) still a `var()`. */\nconst FALLBACK_MONO = \"ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace\";\n\nexport type FontOverrides = { fontFamily?: string | undefined; fontSize?: number | undefined };\n\n/**\n * Resolve xterm's font from token values. The critical bug this fixes:\n * `fontFamily: \"var(--og-font-mono)\"` is measured by xterm via a canvas font\n * string where `var()` does NOT resolve, so xterm silently mis-measures every\n * glyph. Here the family is a CONCRETE stack; a `var(` in the input is treated\n * as unresolved and replaced with the fallback. Pure over a token `read`.\n */\nexport function resolveTerminalFontFromReader(\n read: TokenReader,\n overrides?: FontOverrides,\n): ResolvedTerminalFont {\n const rawFamily = overrides?.fontFamily ?? read(\"--og-font-mono\");\n const fontFamily =\n rawFamily && rawFamily.trim() && !rawFamily.includes(\"var(\") ? rawFamily.trim() : FALLBACK_MONO;\n\n let fontSize = overrides?.fontSize;\n if (fontSize == null) {\n const raw = read(\"--og-code-font-size\");\n const parsed = raw ? Number.parseFloat(raw) : Number.NaN;\n fontSize = Number.isFinite(parsed) && parsed > 0 ? parsed : 13;\n }\n\n return { fontFamily, fontSize, lineHeight: 1.3 };\n}\n\n/** DOM wrapper: resolve the terminal font from an element's computed tokens. */\nexport function resolveTerminalFont(\n el: HTMLElement,\n overrides?: FontOverrides,\n): ResolvedTerminalFont {\n const style = getComputedStyle(el);\n const read: TokenReader = (name) => {\n const value = style.getPropertyValue(name).trim();\n return value || undefined;\n };\n return resolveTerminalFontFromReader(read, overrides);\n}\n","/* ----------------------------------------------------------------------------\n xterm renderer selection ladder: WebGL → 2D canvas → DOM.\n\n WebGL is the fast path (GPU-composited cells — the whole point of the burst\n responsiveness win). But a WebGL context can fail to init (headless / no GPU /\n blocklisted driver) or be LOST at runtime (GPU reset, tab backgrounded). On\n either, we dispose the addon and step down one tier so the terminal keeps\n painting via the 2D canvas addon, and failing that xterm's built-in DOM\n renderer (no addon).\n\n `attachRenderer` is pure over its `loaders` (each closes over the xterm\n instance and constructs+loads its addon, throwing on failure), so the ladder\n + context-loss downgrade unit-test without a real WebGL context.\n -------------------------------------------------------------------------- */\n\nexport type RendererTier = \"webgl\" | \"canvas\" | \"dom\";\n\nexport type RendererAddon = { dispose: () => void };\n\n/** A loader constructs + `loadAddon`s its renderer, wiring `onLoss` to the\n * addon's context-loss event, and throws if the renderer can't initialize. */\nexport type RendererLoaders = {\n webgl?: ((onLoss: () => void) => Promise<RendererAddon>) | undefined;\n canvas?: (() => Promise<RendererAddon>) | undefined;\n};\n\nconst ORDER: RendererTier[] = [\"webgl\", \"canvas\", \"dom\"];\n\n/** The next lower renderer tier, or null at the bottom (DOM). Pure. */\nexport function nextRendererTier(tier: RendererTier): RendererTier | null {\n const i = ORDER.indexOf(tier);\n return i >= 0 && i < ORDER.length - 1 ? ORDER[i + 1]! : null;\n}\n\n/**\n * Attach the highest renderer tier at or below `prefer` that initializes,\n * reporting the settled tier via `onTier`. On a WebGL/canvas context loss the\n * loader's `onLoss` re-enters at the next tier down, so `onTier` is called again\n * with the downgraded tier. Returns the tier chosen on this pass.\n */\nexport async function attachRenderer(\n prefer: RendererTier,\n loaders: RendererLoaders,\n onTier: (tier: RendererTier) => void,\n): Promise<RendererTier> {\n const start = Math.max(0, ORDER.indexOf(prefer));\n for (let i = start; i < ORDER.length; i++) {\n const tier = ORDER[i]!;\n if (tier === \"dom\") break;\n const loader = tier === \"webgl\" ? loaders.webgl : loaders.canvas;\n if (!loader) continue;\n try {\n const downgrade = nextRendererTier(tier) ?? \"dom\";\n await loader(() => {\n void attachRenderer(downgrade, loaders, onTier);\n });\n onTier(tier);\n return tier;\n } catch {\n // Initialization failed — fall through to the next tier down.\n }\n }\n onTier(\"dom\");\n return \"dom\";\n}\n","import {\n ChevronRightIcon,\n FileIcon,\n FilePlusIcon,\n FolderIcon,\n FolderPlusIcon,\n PencilIcon,\n RefreshCwIcon,\n Trash2Icon,\n} from \"lucide-react\";\nimport {\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { VList, type VListHandle } from \"virtua\";\nimport { cn } from \"../lib/cn\";\nimport type { FileTreeNode, UseSandboxFilesResult } from \"../hooks/use-sandbox-files\";\n\nexport type FileBrowserProps = {\n /** From `useSandboxFiles(...)`. */\n result: UseSandboxFilesResult;\n /**\n * Rendered instead of the built-in tree when the file surface is unavailable\n * (e.g. a `FileSystem.available === false` capability). Default: a quiet notice.\n */\n fallback?: ReactNode | undefined;\n /** Selection callback for the preview pane. */\n onSelectFile?: ((path: string) => void) | undefined;\n selectedPath?: string | undefined;\n /** Render-prop to theme/replace a row entirely (the Pierre-swap escape hatch). */\n renderNode?: ((node: FileTreeNode, depth: number, expanded: boolean) => ReactNode) | undefined;\n /** Shown when the tree is empty (no files / not loaded yet). */\n emptyState?: ReactNode | undefined;\n /**\n * Enable the file-manager affordances (toolbar, context menu, drag-drop move,\n * inline rename, delete, new file/folder). Defaults to `true` when the hook\n * exposes the mutation methods; pass `false` for a strictly read-only tree.\n */\n editable?: boolean | undefined;\n /**\n * Confirm a (recursive) delete before it runs. Return `false` to cancel.\n * Defaults to `window.confirm`. Pass a no-op returning `true` to skip.\n */\n confirmDelete?: ((node: FileTreeNode) => boolean | Promise<boolean>) | undefined;\n className?: string | undefined;\n};\n\nconst STATUS_TINT: Record<NonNullable<FileTreeNode[\"status\"]>, string> = {\n added: \"text-og-status-idle\",\n modified: \"text-og-status-running\",\n deleted: \"text-og-status-failed line-through\",\n renamed: \"text-og-accent\",\n untracked: \"text-og-fg-subtle\",\n};\nconst useBrowserLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\n/** Parent dir of a workspace-relative POSIX path (\"\" for a root entry). */\nfunction parentOf(path: string): string {\n const i = path.lastIndexOf(\"/\");\n return i <= 0 ? \"\" : path.slice(0, i);\n}\n\n/** Join a parent dir with a leaf name (handles the root \"\" parent). */\nfunction joinPath(parent: string, name: string): string {\n return parent ? `${parent}/${name}` : name;\n}\n\n/** A stable React key for a flat render item. */\nfunction itemKey(item: RenderItem): string {\n switch (item.type) {\n case \"node\":\n return item.node.path;\n case \"create\":\n return `create:${item.parent}`;\n case \"skeleton\":\n return `skeleton:${item.path}`;\n case \"residue\":\n return `residue:${item.path}`;\n }\n}\n\n/** Walk the tree to find a node by path. */\nfunction findNode(nodes: FileTreeNode[], path: string): FileTreeNode | undefined {\n for (const node of nodes) {\n if (node.path === path) return node;\n if (node.kind === \"dir\" && node.children && path.startsWith(`${node.path}/`)) {\n const hit = findNode(node.children, path);\n if (hit) return hit;\n }\n }\n return undefined;\n}\n\n/** A pending inline-create: a phantom input row under `parent`. */\ntype DraftCreate = { parent: string; kind: \"file\" | \"dir\" };\n/** A pending inline-rename of an existing node. */\ntype DraftRename = { path: string };\ntype ContextMenuState = { node: FileTreeNode | null; x: number; y: number };\n\n/** One virtualized row. Nodes plus the synthetic rows the recursive renderer\n * used to nest inline. */\ntype RenderItem =\n | { type: \"node\"; node: FileTreeNode; depth: number }\n | { type: \"create\"; parent: string; kind: \"file\" | \"dir\"; depth: number }\n | { type: \"skeleton\"; path: string; depth: number }\n | { type: \"residue\"; path: string; depth: number };\n\n/**\n * The file MANAGER, fed by the FileSystem service via `useSandboxFiles`. This is\n * a first-class editable tree (not a render-only view): lazy-expand with a\n * spinner on the in-flight node, git-status tinting, full keyboard navigation,\n * selection, and the mutating affordances wired straight to the hook —\n *\n * • drag-and-drop MOVE → `moveEntry(from, to)`\n * • inline RENAME → `moveEntry(path, newPath)` (F2 / double-click / menu)\n * • DELETE → `deleteEntry(path, recursive)` (Del / menu, confirmed)\n * • NEW FILE / FOLDER → `createFile` / `createDir` (toolbar + menu), then open\n * • right-click CONTEXT MENU\n *\n * `renderNode` is still honoured as the Pierre-swap escape hatch for the row\n * chrome; the manager scaffolding (toolbar, dnd, menu, inline inputs) wraps it.\n */\nexport function FileBrowser({\n result,\n fallback,\n onSelectFile,\n selectedPath,\n renderNode,\n emptyState,\n editable = true,\n confirmDelete,\n className,\n}: FileBrowserProps) {\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n const [loadingPaths, setLoadingPaths] = useState<Set<string>>(new Set());\n const [active, setActive] = useState<string | null>(null);\n const [draftCreate, setDraftCreate] = useState<DraftCreate | null>(null);\n const [draftRename, setDraftRename] = useState<DraftRename | null>(null);\n const [dragOver, setDragOver] = useState<string | null>(null);\n const [menu, setMenu] = useState<ContextMenuState | null>(null);\n const [busy, setBusy] = useState(false);\n const [coarsePointer, setCoarsePointer] = useState(false);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const vlistRef = useRef<VListHandle>(null);\n\n useBrowserLayoutEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return;\n const query = window.matchMedia(\"(pointer: coarse)\");\n const update = () => setCoarsePointer(query.matches);\n update();\n if (typeof query.addEventListener === \"function\") {\n query.addEventListener(\"change\", update);\n return () => query.removeEventListener(\"change\", update);\n }\n if (typeof query.addListener === \"function\") {\n query.addListener(update);\n return () => query.removeListener(update);\n }\n }, []);\n\n // The keyboard cursor: an explicitly-navigated node falls back to the\n // externally-selected file so arrow keys pick up where the preview pane is.\n const cursor = active ?? selectedPath ?? null;\n\n const expand = useCallback(\n async (path: string) => {\n const node = findNode(result.tree, path);\n if (node && node.kind === \"dir\" && node.children === undefined) {\n setLoadingPaths((prev) => new Set(prev).add(path));\n try {\n await result.expand(path);\n } finally {\n setLoadingPaths((prev) => {\n const next = new Set(prev);\n next.delete(path);\n return next;\n });\n }\n }\n },\n [result],\n );\n\n const open = useCallback(\n (path: string) => {\n setExpanded((prev) => new Set(prev).add(path));\n void expand(path);\n },\n [expand],\n );\n\n const toggle = useCallback(\n async (node: FileTreeNode) => {\n if (node.kind !== \"dir\") return;\n const isOpen = expanded.has(node.path);\n setExpanded((prev) => {\n const next = new Set(prev);\n if (isOpen) next.delete(node.path);\n else next.add(node.path);\n return next;\n });\n if (!isOpen) await expand(node.path);\n },\n [expanded, expand],\n );\n\n // Flatten the VISIBLE (expanded) tree into a single ordered render list — the\n // input to the virtualizer. Interleaves the synthetic rows the recursive\n // renderer used to nest (inline create input, lazy-expand skeleton, and the\n // cold residue \"contents on machine\" row) so every visual row is one list item.\n const cold = result.source !== \"live\";\n const renderItems = useMemo(() => {\n const items: RenderItem[] = [];\n if (draftCreate && draftCreate.parent === \"\") {\n items.push({ type: \"create\", parent: \"\", kind: draftCreate.kind, depth: 0 });\n }\n const walk = (nodes: FileTreeNode[], depth: number) => {\n for (const node of nodes) {\n items.push({ type: \"node\", node, depth });\n if (node.kind !== \"dir\" || !expanded.has(node.path)) continue;\n if (draftCreate && draftCreate.parent === node.path) {\n items.push({\n type: \"create\",\n parent: node.path,\n kind: draftCreate.kind,\n depth: depth + 1,\n });\n }\n const childless = node.children === undefined || node.children.length === 0;\n const isLoading = loadingPaths.has(node.path) || result.expandingPaths.has(node.path);\n // A collapsed residue dir (node_modules, .git, …) can't list children from\n // the cold capture — offer to open it live rather than a dead skeleton.\n if (node.truncated && childless && cold && !isLoading) {\n items.push({ type: \"residue\", path: node.path, depth: depth + 1 });\n } else if (node.children && node.children.length > 0) {\n walk(node.children, depth + 1);\n } else if (isLoading && childless) {\n items.push({ type: \"skeleton\", path: node.path, depth: depth + 1 });\n }\n }\n };\n walk(result.tree, 0);\n return items;\n }, [result.tree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);\n\n // The visible NODE rows in order — drives keyboard up/down navigation.\n const flatRows = useMemo(\n () =>\n renderItems.flatMap((item) =>\n item.type === \"node\" ? [{ node: item.node, depth: item.depth }] : [],\n ),\n [renderItems],\n );\n\n const supportsMutation = editable;\n\n const runDelete = useCallback(\n async (node: FileTreeNode) => {\n if (!supportsMutation) return;\n const recursive = node.kind === \"dir\";\n const confirmFn =\n confirmDelete ??\n ((n: FileTreeNode) =>\n typeof window !== \"undefined\" && typeof window.confirm === \"function\"\n ? window.confirm(\n `Delete ${n.kind === \"dir\" ? \"folder\" : \"file\"} \"${n.name}\"${recursive ? \" and its contents\" : \"\"}?`,\n )\n : true);\n const ok = await confirmFn(node);\n if (!ok) return;\n setBusy(true);\n try {\n await result.deleteEntry(node.path, recursive);\n } catch {\n // The hook surfaces the error on `result.error`; the panel renders it.\n } finally {\n setBusy(false);\n }\n },\n [supportsMutation, confirmDelete, result],\n );\n\n const commitCreate = useCallback(\n async (name: string) => {\n const draft = draftCreate;\n setDraftCreate(null);\n if (!draft || !supportsMutation) return;\n const trimmed = name.trim().replace(/\\/+$/, \"\");\n if (!trimmed) return;\n const path = joinPath(draft.parent, trimmed);\n setBusy(true);\n try {\n if (draft.kind === \"dir\") {\n await result.createDir(path);\n open(path);\n } else {\n await result.createFile(path);\n // Open the freshly-created file in the preview/editor pane.\n setActive(path);\n onSelectFile?.(path);\n }\n } catch {\n /* error surfaced via result.error */\n } finally {\n setBusy(false);\n }\n },\n [draftCreate, supportsMutation, result, open, onSelectFile],\n );\n\n const commitRename = useCallback(\n async (name: string) => {\n const draft = draftRename;\n setDraftRename(null);\n if (!draft || !supportsMutation) return;\n const node = findNode(result.tree, draft.path);\n const trimmed = name.trim().replace(/\\/+$/, \"\");\n if (!node || !trimmed || trimmed === node.name) return;\n const newPath = joinPath(parentOf(draft.path), trimmed);\n setBusy(true);\n try {\n await result.moveEntry(draft.path, newPath);\n if (node.kind === \"file\" && (selectedPath === draft.path || active === draft.path)) {\n setActive(newPath);\n onSelectFile?.(newPath);\n }\n } catch {\n /* error surfaced via result.error */\n } finally {\n setBusy(false);\n }\n },\n [draftRename, supportsMutation, result, selectedPath, active, onSelectFile],\n );\n\n // Begin a new file/folder under the active node's directory (or root).\n const startCreate = useCallback(\n (kind: \"file\" | \"dir\") => {\n if (!supportsMutation) return;\n const anchor = cursor ? findNode(result.tree, cursor) : undefined;\n const parent = anchor ? (anchor.kind === \"dir\" ? anchor.path : parentOf(anchor.path)) : \"\";\n if (parent) open(parent);\n setDraftRename(null);\n setMenu(null);\n setDraftCreate({ parent, kind });\n },\n [supportsMutation, cursor, result.tree, open],\n );\n\n const startRename = useCallback(\n (node: FileTreeNode) => {\n if (!supportsMutation) return;\n setDraftCreate(null);\n setMenu(null);\n setDraftRename({ path: node.path });\n },\n [supportsMutation],\n );\n\n // Drag-drop move: drop a node onto a directory (or the root) → moveEntry.\n const onDropOnto = useCallback(\n async (targetDir: string, sourcePath: string) => {\n setDragOver(null);\n if (!supportsMutation || !sourcePath) return;\n const src = findNode(result.tree, sourcePath);\n if (!src) return;\n // No-op drops: onto its own current parent, onto itself, or into its own subtree.\n if (parentOf(sourcePath) === targetDir) return;\n if (targetDir === sourcePath || targetDir.startsWith(`${sourcePath}/`)) return;\n const newPath = joinPath(targetDir, src.name);\n if (newPath === sourcePath) return;\n setBusy(true);\n try {\n await result.moveEntry(sourcePath, newPath);\n if (src.kind === \"file\" && (selectedPath === sourcePath || active === sourcePath)) {\n setActive(newPath);\n onSelectFile?.(newPath);\n }\n } catch {\n /* 409/collision etc. surfaced via result.error */\n } finally {\n setBusy(false);\n }\n },\n [supportsMutation, result, selectedPath, active, onSelectFile],\n );\n\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLDivElement>) => {\n if (draftCreate || draftRename) return; // inline input owns the keyboard\n if (flatRows.length === 0) return;\n const idx = flatRows.findIndex((r) => r.node.path === cursor);\n const move = (next: number) => {\n const clamped = Math.max(0, Math.min(flatRows.length - 1, next));\n const row = flatRows[clamped];\n if (row) setActive(row.node.path);\n e.preventDefault();\n };\n const cur = idx >= 0 ? flatRows[idx] : undefined;\n switch (e.key) {\n case \"ArrowDown\":\n move(idx < 0 ? 0 : idx + 1);\n break;\n case \"ArrowUp\":\n move(idx < 0 ? 0 : idx - 1);\n break;\n case \"ArrowRight\":\n if (cur?.node.kind === \"dir\") {\n if (!expanded.has(cur.node.path)) open(cur.node.path);\n else move(idx + 1);\n e.preventDefault();\n }\n break;\n case \"ArrowLeft\":\n if (cur) {\n if (cur.node.kind === \"dir\" && expanded.has(cur.node.path)) {\n setExpanded((prev) => {\n const n = new Set(prev);\n n.delete(cur.node.path);\n return n;\n });\n } else {\n const parent = parentOf(cur.node.path);\n if (parent) setActive(parent);\n }\n e.preventDefault();\n }\n break;\n case \"Enter\":\n if (cur) {\n if (cur.node.kind === \"dir\") void toggle(cur.node);\n else onSelectFile?.(cur.node.path);\n e.preventDefault();\n }\n break;\n case \"F2\":\n if (cur) {\n startRename(cur.node);\n e.preventDefault();\n }\n break;\n case \"Delete\":\n case \"Backspace\":\n if (cur && supportsMutation) {\n void runDelete(cur.node);\n e.preventDefault();\n }\n break;\n }\n },\n [\n draftCreate,\n draftRename,\n flatRows,\n cursor,\n expanded,\n open,\n toggle,\n onSelectFile,\n startRename,\n runDelete,\n supportsMutation,\n ],\n );\n\n // Close the context menu on any outside interaction.\n useEffect(() => {\n if (!menu) return;\n const close = () => setMenu(null);\n window.addEventListener(\"click\", close);\n window.addEventListener(\"scroll\", close, true);\n window.addEventListener(\"resize\", close);\n return () => {\n window.removeEventListener(\"click\", close);\n window.removeEventListener(\"scroll\", close, true);\n window.removeEventListener(\"resize\", close);\n };\n }, [menu]);\n\n const showErrorEmpty = result.error && result.tree.length === 0 && !draftCreate;\n const showEmpty = !result.loading && result.tree.length === 0 && !draftCreate;\n const showToolbar = supportsMutation || Boolean(result.error) || result.loading;\n\n // Render a SINGLE node row (no recursion — children are separate flat items the\n // virtualizer renders). Returns the row element; the caller assigns the key.\n const renderNodeRow = (node: FileTreeNode, depth: number): ReactNode => {\n const isOpen = expanded.has(node.path);\n if (renderNode) {\n return <div>{renderNode(node, depth, isOpen)}</div>;\n }\n const isDir = node.kind === \"dir\";\n const isSelected = node.path === selectedPath || node.path === active;\n const isCursor = node.path === cursor;\n const isLoading = loadingPaths.has(node.path) || result.expandingPaths.has(node.path);\n const isRenaming = draftRename?.path === node.path;\n const isDropTarget = dragOver === (isDir ? node.path : parentOf(node.path));\n const dropDir = isDir ? node.path : parentOf(node.path);\n\n return (\n <div\n role=\"treeitem\"\n aria-expanded={isDir ? isOpen : undefined}\n aria-selected={isCursor || undefined}\n aria-busy={isLoading || undefined}\n onDragOver={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n setDragOver(dropDir);\n }\n : undefined\n }\n onDragLeave={\n supportsMutation\n ? (e) => {\n e.stopPropagation();\n setDragOver((cur) => (cur === dropDir ? null : cur));\n }\n : undefined\n }\n onDrop={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n e.stopPropagation();\n const src = e.dataTransfer.getData(\"text/og-path\");\n void onDropOnto(dropDir, src);\n }\n : undefined\n }\n >\n {isRenaming ? (\n <InlineInput\n depth={depth}\n kind={node.kind}\n initialValue={node.name}\n onCommit={(name) => void commitRename(name)}\n onCancel={() => setDraftRename(null)}\n />\n ) : (\n <button\n type=\"button\"\n draggable={supportsMutation || undefined}\n onDragStart={\n supportsMutation\n ? (e) => {\n e.dataTransfer.setData(\"text/og-path\", node.path);\n e.dataTransfer.effectAllowed = \"move\";\n }\n : undefined\n }\n onClick={() => {\n setActive(node.path);\n if (isDir) void toggle(node);\n else onSelectFile?.(node.path);\n }}\n onDoubleClick={() => supportsMutation && startRename(node)}\n onContextMenu={(e) => {\n if (!supportsMutation) return;\n e.preventDefault();\n setActive(node.path);\n setMenu({ node, x: e.clientX, y: e.clientY });\n }}\n className={cn(\n \"group relative flex min-h-7 w-full items-center gap-1 truncate rounded-og-sm px-1 py-0.5 text-left text-og-sm pointer-coarse:min-h-11\",\n \"hover:bg-og-surface-2\",\n isSelected && \"bg-og-surface-2\",\n isCursor && \"outline outline-1 -outline-offset-1 outline-og-accent\",\n isDropTarget && \"bg-og-accent-soft ring-1 ring-inset ring-og-accent\",\n // A thin progress shimmer on the expanding row — no per-node spinner.\n isLoading &&\n \"after:pointer-events-none after:absolute after:inset-x-1 after:bottom-0 after:h-px after:animate-pulse after:rounded-full after:bg-og-accent-soft\",\n node.status ? STATUS_TINT[node.status] : undefined,\n )}\n style={{ paddingLeft: `${depth * 12 + 4}px` }}\n >\n {isDir ? (\n <ChevronRightIcon\n className={cn(\n \"size-3 shrink-0 transition-transform\",\n isOpen && \"rotate-90\",\n isLoading && \"text-og-accent\",\n )}\n />\n ) : (\n <span className=\"inline-block w-3 shrink-0\" />\n )}\n {isDir ? (\n <FolderIcon className=\"size-3.5 shrink-0\" />\n ) : (\n <FileIcon className=\"size-3.5 shrink-0\" />\n )}\n <span className=\"truncate\">{node.name}</span>\n {supportsMutation && (\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label=\"More actions\"\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n setActive(node.path);\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n setMenu({ node, x: rect.right, y: rect.bottom });\n }}\n className=\"ml-auto hidden shrink-0 px-1 text-og-fg-subtle hover:text-og-fg group-hover:inline\"\n >\n ⋯\n </span>\n )}\n </button>\n )}\n </div>\n );\n };\n\n // Render one flat list item (node row or a synthetic create/skeleton/residue row).\n const renderItem = (item: RenderItem): ReactNode => {\n switch (item.type) {\n case \"node\":\n return renderNodeRow(item.node, item.depth);\n case \"create\":\n return (\n <InlineInput\n depth={item.depth}\n kind={item.kind}\n initialValue=\"\"\n onCommit={(name) => void commitCreate(name)}\n onCancel={() => setDraftCreate(null)}\n />\n );\n case \"skeleton\":\n return (\n <div\n role=\"group\"\n aria-hidden\n style={{ paddingLeft: `${item.depth * 12 + 4}px` }}\n className=\"space-y-1 py-1\"\n >\n {[0, 1, 2].map((i) => (\n <div\n key={i}\n className=\"h-2.5 animate-pulse rounded-og-sm bg-og-surface-2\"\n style={{ width: `${70 - i * 12}%` }}\n />\n ))}\n </div>\n );\n case \"residue\":\n return (\n <div\n style={{ paddingLeft: `${item.depth * 12 + 4}px` }}\n className=\"flex items-center gap-1.5 py-0.5 pr-1 text-og-xs italic text-og-fg-subtle\"\n >\n <span className=\"inline-block w-3 shrink-0\" />\n <span className=\"min-w-0 truncate\">contents on machine — open when live</span>\n </div>\n );\n }\n };\n\n // Keep the keyboard cursor's row on screen even though off-screen rows unmount.\n useEffect(() => {\n if (!cursor) return;\n const index = renderItems.findIndex((it) => it.type === \"node\" && it.node.path === cursor);\n if (index >= 0) vlistRef.current?.scrollToIndex(index);\n }, [cursor, renderItems]);\n\n return (\n <div className={cn(\"flex min-h-0 min-w-0 flex-col\", className)}>\n {showToolbar && (\n <div className=\"flex shrink-0 flex-wrap items-center gap-0.5 border-b border-og-border px-1 py-1\">\n {supportsMutation ? (\n <>\n <ToolbarButton label=\"New file\" onClick={() => startCreate(\"file\")} disabled={busy}>\n <FilePlusIcon className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton label=\"New folder\" onClick={() => startCreate(\"dir\")} disabled={busy}>\n <FolderPlusIcon className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n label=\"Rename\"\n onClick={() => {\n const node = cursor ? findNode(result.tree, cursor) : undefined;\n if (node) startRename(node);\n }}\n disabled={busy || !cursor}\n >\n <PencilIcon className=\"size-3.5\" />\n </ToolbarButton>\n <ToolbarButton\n label=\"Delete\"\n onClick={() => {\n const node = cursor ? findNode(result.tree, cursor) : undefined;\n if (node) void runDelete(node);\n }}\n disabled={busy || !cursor}\n >\n <Trash2Icon className=\"size-3.5\" />\n </ToolbarButton>\n </>\n ) : null}\n <span className=\"ml-auto\" />\n <ToolbarButton\n label=\"Refresh\"\n onClick={() => void result.refresh()}\n disabled={busy || result.loading}\n >\n <RefreshCwIcon className={cn(\"size-3.5\", result.loading && \"animate-spin\")} />\n </ToolbarButton>\n </div>\n )}\n\n {/* The tree itself. The root is a drop target so a node can be moved to \"\". */}\n {/* biome-ignore lint/a11y/noNoninteractiveTabindex: the tree owns keyboard nav */}\n <div\n ref={containerRef}\n role=\"tree\"\n tabIndex={0}\n aria-multiselectable={false}\n onKeyDown={onKeyDown}\n onDragOver={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = \"move\";\n setDragOver(\"\");\n }\n : undefined\n }\n onDrop={\n supportsMutation\n ? (e) => {\n e.preventDefault();\n const src = e.dataTransfer.getData(\"text/og-path\");\n void onDropOnto(\"\", src);\n }\n : undefined\n }\n className={cn(\n \"flex min-h-0 min-w-0 flex-1 flex-col p-1 outline-none\",\n dragOver === \"\" && \"ring-1 ring-inset ring-og-accent\",\n )}\n data-opengeni-file-tree\n >\n {showErrorEmpty ? (\n <div className=\"flex flex-col items-start gap-2 p-2 text-og-sm text-og-fg-subtle\">\n <div>\n {fallback ??\n `Could not load files: ${result.error?.message ?? \"refresh the file list to try again\"}`}\n </div>\n <button\n type=\"button\"\n onClick={() => void result.refresh()}\n disabled={result.loading}\n className=\"inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-10\"\n >\n <RefreshCwIcon\n className={cn(\"size-3.5\", result.loading && \"animate-spin\")}\n aria-hidden\n />\n Retry\n </button>\n </div>\n ) : showEmpty ? (\n <div className=\"p-2 text-og-sm text-og-fg-subtle\">\n {emptyState ?? \"This directory is empty\"}\n </div>\n ) : (\n // Virtualized: only the rows in/near the viewport mount, so a 3k-node\n // tree stays responsive. The flat item list already carries the\n // expanded subtree + synthetic (create/skeleton/residue) rows.\n <VList\n ref={vlistRef}\n className=\"min-h-0 flex-1\"\n itemSize={coarsePointer ? 44 : 28}\n ssrCount={Math.min(32, renderItems.length)}\n >\n {renderItems.map((item) => (\n <div key={itemKey(item)} className=\"min-w-0\">\n {renderItem(item)}\n </div>\n ))}\n </VList>\n )}\n </div>\n\n {menu && menu.node && (\n <ContextMenu\n node={menu.node}\n x={menu.x}\n y={menu.y}\n onRename={() => menu.node && startRename(menu.node)}\n onDelete={() => menu.node && void runDelete(menu.node)}\n onNewFile={() => startCreate(\"file\")}\n onNewFolder={() => startCreate(\"dir\")}\n />\n )}\n </div>\n );\n}\n\nfunction ToolbarButton({\n label,\n onClick,\n disabled,\n children,\n}: {\n label: string;\n onClick: () => void;\n disabled?: boolean;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n title={label}\n aria-label={label}\n onClick={onClick}\n disabled={disabled}\n className={cn(\n \"inline-flex size-7 items-center justify-center rounded-og-sm p-1 text-og-fg-muted max-[1023px]:size-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11\",\n \"hover:bg-og-surface-2 hover:text-og-fg\",\n \"disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n >\n {children}\n </button>\n );\n}\n\n/** An inline text input for create / rename, indented to match its row depth. */\nfunction InlineInput({\n depth,\n kind,\n initialValue,\n onCommit,\n onCancel,\n}: {\n depth: number;\n kind: \"file\" | \"dir\";\n initialValue: string;\n onCommit: (value: string) => void;\n onCancel: () => void;\n}) {\n const [value, setValue] = useState(initialValue);\n const ref = useRef<HTMLInputElement | null>(null);\n // Track whether we've already resolved so a blur after Enter/Escape is a no-op.\n const doneRef = useRef(false);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n el.focus();\n // Select the basename (excluding any extension) for a rename, like an IDE.\n const dot = initialValue.lastIndexOf(\".\");\n if (initialValue && dot > 0) el.setSelectionRange(0, dot);\n else el.select();\n }, [initialValue]);\n\n const finish = (commit: boolean) => {\n if (doneRef.current) return;\n doneRef.current = true;\n if (commit) onCommit(value);\n else onCancel();\n };\n\n return (\n <div\n className=\"flex items-center gap-1 px-1 py-0.5\"\n style={{ paddingLeft: `${depth * 12 + 4}px` }}\n >\n <span className=\"inline-block w-3 shrink-0\" />\n {kind === \"dir\" ? (\n <FolderIcon className=\"size-3.5 shrink-0\" />\n ) : (\n <FileIcon className=\"size-3.5 shrink-0\" />\n )}\n <input\n ref={ref}\n value={value}\n spellCheck={false}\n autoComplete=\"off\"\n aria-label={kind === \"dir\" ? \"Folder name\" : \"File name\"}\n onChange={(e) => setValue(e.target.value)}\n onBlur={() => finish(true)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n finish(true);\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n finish(false);\n }\n e.stopPropagation();\n }}\n className={cn(\n \"min-w-0 flex-1 rounded-og-sm border bg-og-bg px-1 py-0 text-og-sm\",\n \"border-og-accent text-og-fg\",\n \"outline-none\",\n )}\n />\n </div>\n );\n}\n\n/** The right-click / kebab context menu, positioned at the click point. */\nfunction ContextMenu({\n node,\n x,\n y,\n onRename,\n onDelete,\n onNewFile,\n onNewFolder,\n}: {\n node: FileTreeNode;\n x: number;\n y: number;\n onRename: () => void;\n onDelete: () => void;\n onNewFile: () => void;\n onNewFolder: () => void;\n}) {\n const isDir = node.kind === \"dir\";\n // Keep the menu on-screen when opened near the viewport edge.\n const vw = typeof window !== \"undefined\" ? window.innerWidth : 9999;\n const vh = typeof window !== \"undefined\" ? window.innerHeight : 9999;\n const left = Math.min(x, vw - 180);\n const top = Math.min(y, vh - 160);\n\n const item = (label: string, icon: ReactNode, onClick: () => void, danger?: boolean) => (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n className={cn(\n \"flex w-full items-center gap-2 px-2.5 py-1 text-left text-og-sm pointer-coarse:min-h-10\",\n \"hover:bg-og-surface-2\",\n danger ? \"text-og-status-failed\" : \"text-og-fg\",\n )}\n >\n {icon}\n {label}\n </button>\n );\n\n return (\n <div\n role=\"menu\"\n onClick={(e) => e.stopPropagation()}\n style={{ left, top }}\n className={cn(\n \"fixed z-50 min-w-[160px] overflow-hidden rounded-md border py-1 shadow-lg\",\n \"border-og-border\",\n \"bg-og-surface-1\",\n )}\n >\n {isDir && (\n <>\n {item(\"New file\", <FilePlusIcon className=\"size-3.5\" />, onNewFile)}\n {item(\"New folder\", <FolderPlusIcon className=\"size-3.5\" />, onNewFolder)}\n <div className=\"my-1 h-px bg-og-border\" />\n </>\n )}\n {item(\"Rename\", <PencilIcon className=\"size-3.5\" />, onRename)}\n {item(\"Delete\", <Trash2Icon className=\"size-3.5\" />, onDelete, true)}\n </div>\n );\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { type ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { PierreDiff } from \"./pierre-diff\";\n\n/**\n * @deprecated Use {@link PierreDiff} directly. Retained only as a thin,\n * back-compat alias that renders the Pierre (Shiki) renderer with a plain-text\n * degrade. The old hand-rolled hunk renderer was removed in Workbench v2 — the\n * workbench keeps exactly ONE diff renderer. This alias is removed next major.\n */\nexport type DiffTheme = {\n addBackground?: string;\n delBackground?: string;\n contextBackground?: string;\n metaForeground?: string;\n};\n\n/**\n * @deprecated Use {@link PierreDiff}. `theme`/`onSelectFile`/`emptyState` from the\n * removed hand-rolled renderer are accepted for source compatibility and ignored;\n * `fallback` still overrides the plain-text degrade.\n */\nexport type DiffViewProps = {\n diff: GitFileDiff[];\n fallback?: ReactNode | undefined;\n layout?: \"unified\" | \"split\" | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n /** @deprecated line-background theming was part of the removed renderer. */\n theme?: DiffTheme | undefined;\n /** @deprecated the alias no longer renders a clickable file header. */\n onSelectFile?: ((path: string) => void) | undefined;\n isRepo?: boolean | undefined;\n emptyState?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n/**\n * @deprecated Use {@link PierreDiff} directly. Thin alias: renders `PierreDiff`\n * (Shiki-highlighted, unified/split) with a plain-text fallback for a host\n * without `@pierre/diffs`. Removed next major.\n */\nexport function DiffView({\n diff,\n fallback,\n layout = \"unified\",\n themeType,\n isRepo = true,\n emptyState,\n className,\n}: DiffViewProps) {\n if (diff.length === 0) {\n return (\n <div className={cn(\"p-3 text-og-sm text-og-fg-subtle\", className)}>\n {emptyState ?? (isRepo ? \"No changes\" : \"No repository mounted\")}\n </div>\n );\n }\n return (\n <PierreDiff\n diff={diff}\n layout={layout}\n themeType={themeType}\n {...(fallback !== undefined ? { fallback } : {})}\n className={className}\n />\n );\n}\n","import {\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n lazy,\n Suspense,\n useEffect,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/** Pierre `File` props subset we drive — the single-file, syntax-highlighted view\n * (Shiki), the read counterpart of `PatchDiff`. */\ntype FileComponent = ComponentType<{\n file: { name: string; contents: string; lang?: string };\n options?: {\n theme?: string | { dark: string; light: string };\n themeType?: \"dark\" | \"light\";\n overflow?: \"scroll\" | \"wrap\";\n stickyHeader?: boolean;\n showLineNumbers?: boolean;\n };\n disableWorkerPool?: boolean;\n className?: string;\n}>;\n\nexport type PierreFileProps = {\n /** Workspace-relative path (used for the header + language inference). */\n path: string;\n /** The decoded text contents. */\n contents: string;\n themeType?: \"dark\" | \"light\" | undefined;\n /** Shiki bundled theme names (dark/light) — derived from the host palette. */\n theme?: { dark: string; light: string } | undefined;\n /** Disable Pierre's worker pool if its worker bundling fights the host bundler. */\n disableWorkerPool?: boolean | undefined;\n /** Rendered while the (lazy) Pierre bundle loads. */\n loading?: ReactNode | undefined;\n /** Rendered if `@pierre/diffs/react` is not installed / fails to import. */\n fallback?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n// Lazy-load `@pierre/diffs/react`'s `File` so Shiki + the worker pool stay off the\n// critical path (and out of an SSR bundle) until a file is actually viewed.\nconst LazyFile = lazy(async () => {\n const mod = (await import(\"@pierre/diffs/react\")) as unknown as { File: FileComponent };\n return { default: mod.File };\n});\n\n/**\n * The Pierre-backed single-file VIEWER: Shiki-highlighted, language inferred from\n * the filename — the read complement of `PierreDiff`. Wired to `fs.read` so\n * clicking any file in the tree shows its contents (NOT a diff; no repo needed).\n * Falls back to a plain `<pre>` when `@pierre/diffs` is absent / fails to import.\n */\nexport function PierreFile({\n path,\n contents,\n themeType,\n theme,\n disableWorkerPool,\n loading,\n fallback,\n className,\n}: PierreFileProps) {\n const [failed, setFailed] = useState(false);\n\n // Probe the import once so a hard failure (peer missing) shows `fallback`\n // rather than a Suspense boundary that never resolves.\n useEffect(() => {\n let cancelled = false;\n void import(\"@pierre/diffs/react\").catch(() => {\n if (!cancelled) setFailed(true);\n });\n return () => {\n cancelled = true;\n };\n }, []);\n\n const name = path.split(\"/\").filter(Boolean).pop() ?? path;\n\n if (failed) {\n return (\n <div className={className}>{fallback ?? <PlainFile name={name} contents={contents} />}</div>\n );\n }\n\n const options = {\n overflow: \"scroll\" as const,\n stickyHeader: true,\n showLineNumbers: true,\n ...(theme\n ? { theme }\n : {\n theme: {\n dark: \"github-dark-high-contrast\",\n light: \"github-light-high-contrast\",\n },\n }),\n themeType: themeType ?? \"dark\",\n };\n\n // Same shadow-DOM override vars as PierreDiff: pin the base background to the\n // dock surface so the viewer reads as part of the panel, not a black seam.\n const pierreVars = {\n \"--diffs-dark-bg\": \"var(--og-color-bg)\",\n \"--diffs-light-bg\": \"var(--og-color-bg)\",\n \"--diffs-bg-buffer-override\": \"var(--og-color-surface-1)\",\n \"--diffs-bg-separator-override\": \"var(--og-color-surface-1)\",\n \"--diffs-font-size\": \"var(--og-code-font-size)\",\n \"--diffs-line-height\": \"var(--og-code-line-height)\",\n } as CSSProperties;\n\n return (\n <div className={cn(\"min-w-0\", className)} data-opengeni-pierre-file style={pierreVars}>\n <Suspense fallback={loading ?? <FileSkeleton />}>\n {/* `cacheKey` keys Pierre's worker-pool highlight cache on path+size so a\n re-select of the same file is instant but an edited file re-highlights. */}\n <LazyFile\n file={{ name, contents }}\n options={options}\n {...(disableWorkerPool !== undefined ? { disableWorkerPool } : {})}\n />\n </Suspense>\n </div>\n );\n}\n\nfunction PlainFile({ name, contents }: { name: string; contents: string }) {\n return (\n <pre\n className=\"overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg\"\n data-file={name}\n >\n {contents}\n </pre>\n );\n}\n\nfunction FileSkeleton() {\n return <div className=\"p-3 text-og-sm text-og-fg-subtle\">Loading file…</div>;\n}\n","import { Loader2Icon, SaveIcon } from \"lucide-react\";\nimport {\n type ComponentType,\n type CSSProperties,\n type ReactNode,\n lazy,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\n\n// --- Lazy CodeMirror surface ----------------------------------------------\n//\n// CodeMirror 6 (via @uiw/react-codemirror) plus the per-language grammars are a\n// heavy bundle (lezer parsers, the view layer). We keep them OFF the critical\n// path and out of any SSR bundle by lazy-importing only when a file is actually\n// EDITED. The read-only viewer stays Pierre's Shiki `File`; this is the\n// editable complement, mounted on demand.\n\n/** The subset of `@uiw/react-codemirror`'s props we drive. */\ntype ReactCodeMirrorComponent = ComponentType<{\n value?: string;\n height?: string;\n theme?: \"light\" | \"dark\" | \"none\" | unknown;\n editable?: boolean;\n readOnly?: boolean;\n basicSetup?: boolean | Record<string, boolean>;\n extensions?: unknown[];\n onChange?: ((value: string) => void) | undefined;\n className?: string;\n style?: CSSProperties;\n}>;\n\n// Resolved lazily on first edit: the editor component + the keymap/Prec helpers\n// (both re-exported from @uiw/react-codemirror, which re-exports @codemirror/view\n// and @codemirror/state) + the chosen language extension.\ntype EditorBundle = {\n Editor: ReactCodeMirrorComponent;\n saveKeymapExtension: (onSave: () => void) => unknown;\n languageExtension: unknown | null;\n};\n\n/** Language grammar loaders, keyed by the extension class we infer from the path. */\nconst LANGUAGE_LOADERS: Record<string, () => Promise<unknown>> = {\n javascript: async () =>\n (await import(\"@codemirror/lang-javascript\")).javascript({ jsx: true, typescript: true }),\n json: async () => (await import(\"@codemirror/lang-json\")).json(),\n python: async () => (await import(\"@codemirror/lang-python\")).python(),\n markdown: async () => (await import(\"@codemirror/lang-markdown\")).markdown(),\n css: async () => (await import(\"@codemirror/lang-css\")).css(),\n html: async () => (await import(\"@codemirror/lang-html\")).html(),\n};\n\n/** Map a filename to a grammar key (or null for plain text — still fully editable). */\nexport function languageForPath(path: string): keyof typeof LANGUAGE_LOADERS | null {\n const name = path.split(\"/\").pop() ?? path;\n const ext = name.includes(\".\") ? (name.split(\".\").pop() ?? \"\").toLowerCase() : \"\";\n switch (ext) {\n case \"js\":\n case \"jsx\":\n case \"ts\":\n case \"tsx\":\n case \"mjs\":\n case \"cjs\":\n return \"javascript\";\n case \"json\":\n case \"jsonc\":\n return \"json\";\n case \"py\":\n case \"pyi\":\n return \"python\";\n case \"md\":\n case \"markdown\":\n case \"mdx\":\n return \"markdown\";\n case \"css\":\n case \"scss\":\n case \"less\":\n return \"css\";\n case \"html\":\n case \"htm\":\n case \"xml\":\n case \"svg\":\n case \"vue\":\n return \"html\";\n default:\n return null;\n }\n}\n\nconst LazyCodeMirror = lazy(async () => {\n const mod = (await import(\"@uiw/react-codemirror\")) as unknown as {\n default: ReactCodeMirrorComponent;\n };\n return { default: mod.default };\n});\n\nexport type CodeEditorProps = {\n /** Workspace-relative path — drives language inference (and the save target upstream). */\n path: string;\n /** The decoded text contents to seed the editor with. */\n initialContents: string;\n /** Persist the current buffer. Resolves when the write lands; rejects to surface an error. */\n onSave: (contents: string) => Promise<unknown>;\n /** Fired once when the buffer FIRST diverges from its baseline (the first real\n * keystroke) — the wake-on-edit intent. The host warms the box on this so the\n * eventual save lands fast; merely opening the file for reading never fires it. */\n onEditIntent?: (() => void) | undefined;\n /** Read-only mode (e.g. a truncated/too-large file shown for reference only). */\n readOnly?: boolean | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n /** Rendered while the (lazy) CodeMirror bundle loads. */\n loading?: ReactNode | undefined;\n /** Rendered if `@uiw/react-codemirror` is not installed / fails to import. */\n fallback?: ReactNode | undefined;\n className?: string | undefined;\n};\n\n/**\n * The EDITABLE single-file pane: CodeMirror 6 with a per-language grammar chosen\n * from the filename, og-* themed, with dirty tracking and a save path wired to\n * `Cmd/Ctrl+S` *and* an explicit Save button. The viewer (Pierre `File`) stays\n * the read-only complement — this is only mounted when the user opts to edit.\n *\n * Save semantics: the buffer is \"dirty\" the moment it diverges from the last\n * saved baseline; a successful `onSave` clears dirty and re-baselines. A failed\n * save keeps the buffer dirty (nothing is lost) and surfaces the error inline.\n * `readOnly` suppresses every mutation path so a truncated/binary file can never\n * be saved back (which would corrupt it by writing the truncated prefix).\n */\nexport function CodeEditor({\n path,\n initialContents,\n onSave,\n onEditIntent,\n readOnly = false,\n themeType = \"dark\",\n loading,\n fallback,\n className,\n}: CodeEditorProps) {\n const [failed, setFailed] = useState(false);\n const [bundle, setBundle] = useState<EditorBundle | null>(null);\n\n // The live buffer + the baseline it's compared against for dirtiness. The\n // baseline resets whenever a *new* file is loaded (path/initialContents change)\n // or after a successful save.\n const [value, setValue] = useState(initialContents);\n const [baseline, setBaseline] = useState(initialContents);\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<Error | null>(null);\n const [savedTick, setSavedTick] = useState(false);\n\n const dirty = value !== baseline;\n\n // Reload the buffer when the file identity changes. Guard on initialContents\n // too so an external refresh of the SAME path (e.g. fs.changed re-read) reseeds\n // a clean buffer — but only when the user hasn't got unsaved edits in flight.\n // Fire the wake-on-edit intent at most once per opened file — reset on re-seed.\n const editIntentFiredRef = useRef(false);\n const lastSeed = useRef<{ path: string; contents: string }>({ path, contents: initialContents });\n useEffect(() => {\n const seedChanged =\n lastSeed.current.path !== path || lastSeed.current.contents !== initialContents;\n if (!seedChanged) return;\n lastSeed.current = { path, contents: initialContents };\n editIntentFiredRef.current = false;\n setValue(initialContents);\n setBaseline(initialContents);\n setSaveError(null);\n setSavedTick(false);\n }, [path, initialContents]);\n\n // Record a buffer change: the FIRST divergence from the baseline is the edit\n // intent that warms the box (idempotent — latched per opened file).\n const noteEdit = useCallback(\n (next: string) => {\n setValue(next);\n setSavedTick(false);\n if (!editIntentFiredRef.current && next !== baseline) {\n editIntentFiredRef.current = true;\n onEditIntent?.();\n }\n },\n [baseline, onEditIntent],\n );\n\n // Resolve the lazy bundle (editor + keymap/Prec helpers + language grammar)\n // once, re-resolving the grammar when the file's language class changes.\n const langKey = useMemo(() => languageForPath(path), [path]);\n useEffect(() => {\n let cancelled = false;\n void (async () => {\n try {\n const cmMod = (await import(\"@uiw/react-codemirror\")) as unknown as {\n default: ReactCodeMirrorComponent;\n keymap: { of: (binds: unknown[]) => unknown };\n Prec: { highest: (ext: unknown) => unknown };\n };\n const languageExtension = langKey ? await LANGUAGE_LOADERS[langKey]?.() : null;\n if (cancelled) return;\n // A high-precedence Cmd/Ctrl-S keymap that calls back into the latest\n // save handler (kept fresh via a ref) and swallows the browser's\n // \"save page\" default.\n const saveKeymapExtension = (run: () => void) =>\n cmMod.Prec.highest(\n cmMod.keymap.of([\n {\n key: \"Mod-s\",\n preventDefault: true,\n run: () => {\n run();\n return true;\n },\n },\n ]),\n );\n setBundle({\n Editor: cmMod.default,\n saveKeymapExtension,\n languageExtension: languageExtension ?? null,\n });\n } catch {\n if (!cancelled) setFailed(true);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [langKey]);\n\n // Keep the freshest save closure reachable from the (stable) keymap binding.\n const saveRef = useRef<() => void>(() => {});\n\n const save = useCallback(async () => {\n if (readOnly) return;\n // Snapshot the buffer at call time so an in-flight edit can't race the write.\n const snapshot = value;\n if (snapshot === baseline) return; // nothing to persist\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onSave(snapshot);\n setBaseline(snapshot);\n lastSeed.current = { path, contents: snapshot };\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n setSaving(false);\n }\n }, [readOnly, value, baseline, onSave, path]);\n\n saveRef.current = () => {\n void save();\n };\n\n // A brief \"Saved\" affordance after a successful write, cleared on the next edit.\n useEffect(() => {\n if (!savedTick) return;\n const t = setTimeout(() => setSavedTick(false), 1800);\n return () => clearTimeout(t);\n }, [savedTick]);\n\n const fileName = path.split(\"/\").filter(Boolean).pop() ?? path;\n\n const cmExtensions = useMemo(() => {\n if (!bundle) return [] as unknown[];\n const exts: unknown[] = [bundle.saveKeymapExtension(() => saveRef.current())];\n if (bundle.languageExtension) exts.push(bundle.languageExtension);\n return exts;\n }, [bundle]);\n\n if (failed) {\n return (\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n {fallback ?? <PlainTextarea value={value} readOnly={readOnly} onChange={noteEdit} />}\n </div>\n );\n }\n\n return (\n <div\n className={cn(\"flex h-full min-h-0 flex-col\", className)}\n data-opengeni-code-editor\n style={editorVars}\n >\n {/* Save bar: dirty indicator + status + the explicit Save button. */}\n <div className=\"flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1\">\n <span\n className={cn(\n \"size-1.5 shrink-0 rounded-full transition-colors\",\n readOnly ? \"bg-transparent\" : dirty ? \"bg-og-status-running\" : \"bg-og-status-idle\",\n )}\n title={readOnly ? \"read-only\" : dirty ? \"unsaved changes\" : \"saved\"}\n />\n <span className=\"truncate font-og-mono text-og-xs text-og-fg-muted\">\n {fileName}\n {dirty && !readOnly ? \" •\" : \"\"}\n </span>\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {saveError && (\n <span\n className=\"max-w-[220px] truncate text-og-xs text-og-status-failed\"\n title={saveError.message}\n >\n {saveError.message}\n </span>\n )}\n {!saveError && savedTick && <span className=\"text-og-xs text-og-status-idle\">Saved</span>}\n {readOnly ? (\n <span className=\"text-og-xs uppercase tracking-wide text-og-fg-subtle\">Read-only</span>\n ) : (\n <button\n type=\"button\"\n onClick={() => void save()}\n disabled={saving || !dirty}\n className={cn(\n \"flex items-center gap-1 rounded-og-sm border border-og-border px-1.5 py-0.5 text-og-xs pointer-coarse:min-h-10\",\n saving || !dirty\n ? \"cursor-default text-og-fg-subtle opacity-60\"\n : \"text-og-fg hover:bg-og-accent-soft\",\n )}\n title=\"Save (⌘/Ctrl+S)\"\n >\n {saving ? (\n <Loader2Icon className=\"size-3 animate-spin\" />\n ) : (\n <SaveIcon className=\"size-3\" />\n )}\n Save\n </button>\n )}\n </div>\n </div>\n\n {/* The editor surface. */}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <Suspense fallback={loading ?? <EditorSkeleton />}>\n <LazyCodeMirror\n value={value}\n theme={themeType === \"light\" ? \"light\" : \"dark\"}\n editable={!readOnly}\n readOnly={readOnly}\n basicSetup={true}\n extensions={cmExtensions}\n height=\"100%\"\n className=\"og-cm-editor min-h-full text-og-sm\"\n onChange={readOnly ? undefined : noteEdit}\n />\n </Suspense>\n </div>\n </div>\n );\n}\n\n/** og-* themed CSS-var overrides handed to CodeMirror's container. */\nconst editorVars = {\n \"--og-cm-bg\": \"var(--og-color-bg)\",\n fontFamily: \"var(--og-font-mono)\",\n} as CSSProperties;\n\nfunction PlainTextarea({\n value,\n readOnly,\n onChange,\n}: {\n value: string;\n readOnly: boolean;\n onChange: (value: string) => void;\n}) {\n return (\n <textarea\n value={value}\n readOnly={readOnly}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n className=\"h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-none\"\n />\n );\n}\n\nfunction EditorSkeleton() {\n return <div className=\"p-3 text-og-sm text-og-fg-subtle\">Loading editor…</div>;\n}\n","import type { FsReadResponse } from \"@opengeni/sdk\";\nimport { type ReactNode, useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport type { UseSandboxFilesResult } from \"../hooks/use-sandbox-files\";\nimport type { UseSandboxGitResult } from \"../hooks/use-sandbox-git\";\nimport { CodeEditor } from \"./code-editor\";\nimport { FileBrowser } from \"./file-browser\";\nimport { PierreFile } from \"./pierre-file\";\n\nexport type SandboxFilesProps = {\n /** From `useSandboxFiles(...)`. */\n files: UseSandboxFilesResult;\n /** From `useSandboxGit(...)` — drives the branch/dirty header only. */\n git: UseSandboxGitResult;\n /** @deprecated Diffs live in the dedicated Changes tab now; accepted for\n * source-compat but unused (the Files surface is a browser + viewer). */\n stagedGit?: UseSandboxGitResult | undefined;\n /** Whether a FileSystem surface is advertised (drives the unavailable notice). */\n fileSystemAvailable?: boolean | undefined;\n /** Use Pierre's Shiki highlighter for the viewer (default true; plain fallback). */\n usePierre?: boolean | undefined;\n /** Allow in-place editing of tree files (CodeMirror). Default true. When false\n * the surface is review-only: every text file opens in the read-only viewer. */\n editable?: boolean | undefined;\n /** Fired once when the user first edits an open file (wake-on-edit intent). The\n * dock warms the box on this so the save lands fast; opening/reading never fires\n * it. Browsing the tree/diff must not warm a box. */\n onEditIntent?: (() => void) | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n className?: string | undefined;\n};\n\n/**\n * The Files surface: a branch/dirty header, the full lazy file tree, and a\n * viewer/editor pane for the selected file. This is the workspace BROWSER — pick\n * a file to read or edit it. Diff review lives in the dedicated Changes tab (this\n * surface deliberately does NOT replicate the changed-files list, and does not\n * diff here — one job per tab). The agent commits; the human reviews.\n */\nexport function SandboxFiles({\n files,\n git,\n fileSystemAvailable = true,\n usePierre = true,\n editable = true,\n onEditIntent,\n themeType,\n className,\n}: SandboxFilesProps) {\n const [selected, setSelected] = useState<string | null>(null);\n // View vs Edit for the selected file. Resets to View on every new selection so\n // opening a file never lands you in a stale dirty editor for a different path.\n const [editMode, setEditMode] = useState(false);\n\n // Side-by-side (tree left, viewer right) once the surface is wide enough;\n // stacked (tree over viewer) on a narrow dock. Tracked off the container so it\n // reacts to the dock resize, not just the viewport.\n const rootRef = useRef<HTMLDivElement | null>(null);\n const [wide, setWide] = useState(false);\n useEffect(() => {\n const el = rootRef.current;\n if (!el || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver((entries) => {\n const w = entries[0]?.contentRect.width ?? 0;\n setWide(w >= 720);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n // Resolve the effective viewer theme from the host palette (the `data-og-theme`\n // attribute the demo/app sets), defaulting to dark, unless the caller forced one.\n const resolvedTheme = useThemeType(themeType);\n\n // The selected tree file opens in the viewer (read-only) or the editor (when\n // writable). Nothing is auto-selected — the pane waits for a tree click, so the\n // Files tab opens as a calm browser, not a diff.\n const viewPath = selected;\n const fileView = useFileView(viewPath, files.readFile);\n\n // Selecting a (different) file always returns to View — never drop the user into\n // an editor whose buffer belongs to the previously-selected path.\n const selectFile = useCallback((path: string) => {\n setSelected(path);\n setEditMode(false);\n }, []);\n\n // A tree file is editable only when it is a real, fully-loaded text file: not\n // binary (would corrupt on save) and not truncated (we only hold a PREFIX). The\n // editor is then additionally gated on the `editable` prop; anything failing this\n // opens read-only in the viewer.\n const canEdit =\n editable &&\n viewPath !== null &&\n !fileView.loading &&\n fileView.error === null &&\n !fileView.isBinary &&\n !fileView.truncated &&\n fileView.content !== null;\n const showEditor = canEdit && editMode;\n\n if (!fileSystemAvailable) {\n return <Notice className={className}>This sandbox does not expose a file system.</Notice>;\n }\n\n return (\n <div ref={rootRef} className={cn(\"flex h-full min-h-0 min-w-0 flex-col\", className)}>\n {/* Branch + dirty header (context; NOT the changed-files list). */}\n <GitHeader git={git} dirtyCount={git.diff.length} />\n\n <div className={cn(\"flex min-h-0 flex-1\", wide ? \"flex-row\" : \"flex-col\")}>\n {/* Tree pane: the full lazy file tree. A fixed left column when wide, a top\n band when narrow. */}\n <div\n className={cn(\n \"flex min-h-0 flex-col\",\n wide ? \"w-[280px] shrink-0 border-r border-og-border\" : \"flex-1\",\n )}\n >\n <FileBrowser\n result={files}\n selectedPath={selected ?? undefined}\n onSelectFile={selectFile}\n editable={editable}\n emptyState=\"This directory is empty\"\n className=\"min-w-0 flex-1\"\n />\n </div>\n\n {/* Viewer pane: the selected file's contents (read-only) or the editor.\n Fills the remaining width when side-by-side, sits below the tree when\n stacked. */}\n <div\n className={cn(\n \"flex min-h-0 min-w-0 flex-col\",\n wide ? \"flex-1\" : \"flex-[1.4] border-t border-og-border\",\n )}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1\">\n <span className=\"min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted\">\n {selected ?? \"No file selected\"}\n </span>\n {/* View/Edit toggle — only for a real, fully-loaded text file the editor\n can safely round-trip. Binary/truncated/read-only files never get an\n Edit affordance (they'd corrupt on save or can't be written). */}\n {canEdit && (\n <Segmented\n options={[\n { value: \"view\", label: \"View\" },\n { value: \"edit\", label: \"Edit\" },\n ]}\n value={editMode ? \"edit\" : \"view\"}\n onChange={(v) => setEditMode(v === \"edit\")}\n />\n )}\n </div>\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {viewPath ? (\n showEditor && fileView.content !== null ? (\n <CodeEditor\n key={viewPath}\n path={viewPath}\n initialContents={fileView.content}\n themeType={resolvedTheme}\n onSave={(contents) => files.writeFile(viewPath, contents)}\n {...(onEditIntent ? { onEditIntent } : {})}\n className=\"h-full\"\n />\n ) : fileView.error ? (\n <Notice>\n Could not open {viewPath}: {fileView.error.message}\n </Notice>\n ) : fileView.loading ? (\n <Notice>Loading {viewPath}…</Notice>\n ) : fileView.isBinary ? (\n <Notice>\n {viewPath} is a binary file ({fileView.sizeBytes ?? 0} bytes).\n </Notice>\n ) : fileView.content !== null ? (\n <>\n {fileView.truncated && (\n <div className=\"border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-status-running\">\n Large file — showing a truncated preview ({fileView.sizeBytes ?? 0} bytes\n loaded). Editing is disabled to avoid corrupting the file.\n </div>\n )}\n {usePierre ? (\n <PierreFile\n path={viewPath}\n contents={fileView.content}\n themeType={resolvedTheme}\n fallback={\n <pre className=\"overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg\">\n {fileView.content}\n </pre>\n }\n className=\"p-1\"\n />\n ) : (\n <pre className=\"overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg\">\n {fileView.content}\n </pre>\n )}\n </>\n ) : (\n <Notice>Loading {viewPath}…</Notice>\n )\n ) : (\n // Nothing selected — the tree shows the whole workspace; pick a file.\n <Notice>Select a file in the tree to view it.</Notice>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction GitHeader({ git, dirtyCount }: { git: UseSandboxGitResult; dirtyCount: number }) {\n const dirty = dirtyCount > 0;\n return (\n <div className=\"flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm\">\n <span\n className={cn(\n \"size-2 shrink-0 rounded-full\",\n dirty ? \"bg-og-status-running\" : \"bg-og-status-idle\",\n )}\n title={dirty ? `${dirtyCount} changed` : \"clean\"}\n />\n <span className=\"truncate font-og-mono text-og-fg\">\n {git.branch ?? (git.isRepo ? \"(detached)\" : \"no repo\")}\n </span>\n {(git.ahead > 0 || git.behind > 0) && (\n <span className=\"flex shrink-0 items-center gap-1.5 text-og-xs text-og-fg-subtle\">\n {git.ahead > 0 && <span>↑{git.ahead}</span>}\n {git.behind > 0 && <span>↓{git.behind}</span>}\n </span>\n )}\n {dirty && (\n <span className=\"ml-auto shrink-0 text-og-xs text-og-fg-subtle\">{dirtyCount} changed</span>\n )}\n </div>\n );\n}\n\nfunction Segmented({\n options,\n value,\n onChange,\n}: {\n options: { value: string; label: string }[];\n value: string;\n onChange: (value: string) => void;\n}) {\n return (\n <div className=\"flex flex-wrap items-center rounded-og-sm border border-og-border p-0.5\">\n {options.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => onChange(opt.value)}\n className={cn(\n \"min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs max-[1023px]:min-h-11 pointer-coarse:min-h-11\",\n opt.value === value\n ? \"bg-og-accent-soft text-og-fg\"\n : \"text-og-fg-subtle hover:text-og-fg\",\n )}\n >\n {opt.label}\n </button>\n ))}\n </div>\n );\n}\n\ntype FileViewState = {\n content: string | null;\n isBinary: boolean;\n /** The backend truncated the read (size cap hit) — content is a PREFIX only.\n * Editing+saving such a file would write the prefix back and corrupt it, so\n * the editor must stay read-only for a truncated read. */\n truncated: boolean;\n sizeBytes: number | null;\n loading: boolean;\n error: Error | null;\n};\n\n/**\n * Read a file's contents for the viewer pane. Calls `fs.read` (text by default;\n * the backend flags binary), decodes a base64 payload if one comes back, and\n * exposes loading/error/binary state. Re-fetches when the path changes; ignores\n * a stale resolve after the selection moves on.\n */\nfunction useFileView(\n path: string | null,\n readFile: (path: string) => Promise<FsReadResponse>,\n): FileViewState {\n const [state, setState] = useState<FileViewState>({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: false,\n error: null,\n });\n useEffect(() => {\n if (!path) {\n setState({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: false,\n error: null,\n });\n return;\n }\n let cancelled = false;\n setState({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: true,\n error: null,\n });\n void readFile(path)\n .then((res) => {\n if (cancelled) return;\n const content = res.isBinary\n ? null\n : res.encoding === \"base64\"\n ? decodeBase64Utf8(res.content)\n : res.content;\n setState({\n content,\n isBinary: res.isBinary,\n truncated: res.truncated,\n sizeBytes: res.sizeBytes,\n loading: false,\n error: null,\n });\n })\n .catch((cause) => {\n if (cancelled) return;\n setState({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: false,\n error: cause instanceof Error ? cause : new Error(String(cause)),\n });\n });\n return () => {\n cancelled = true;\n };\n }, [path, readFile]);\n return state;\n}\n\n/** Decode a base64 payload to a UTF-8 string (browser `atob` + TextDecoder). */\nfunction decodeBase64Utf8(b64: string): string {\n try {\n if (typeof atob === \"function\") {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n } catch {\n /* fall through to returning the raw payload */\n }\n return b64;\n}\n\nfunction Notice({ children, className }: { children: ReactNode; className?: string | undefined }) {\n return (\n <div\n className={cn(\n \"flex h-full items-center justify-center p-4 text-center text-og-sm text-og-fg-subtle\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n","import type {\n CapabilityUnavailableReason,\n DesktopRfbFactory,\n DesktopStreamCapability,\n} from \"@opengeni/sdk\";\nimport { LoaderCircleIcon, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from \"lucide-react\";\nimport { type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useDesktopStream } from \"../hooks/use-desktop-stream\";\nimport type { DesktopWebSocketFactory } from \"../hooks/use-relay-frame-stream\";\n\nexport type DesktopViewerProps = {\n /** The desktop cell of the negotiated capabilities (`capabilities.DesktopStream`). */\n capability: DesktopStreamCapability | null;\n /**\n * Initial control mode. Default false (watch). When the user flips\n * \"Take control\" the viewer drives input — but only if `capability.mode`\n * permits it (server-gated; a read-only deployment disables the toggle).\n * Pass a value to control it externally; omit to let the viewer own the state.\n */\n interactive?: boolean | undefined;\n /** Render the built-in Watching ⇄ Take control toggle (default true). */\n showControlToggle?: boolean | undefined;\n scaleViewport?: boolean | undefined;\n /** Custom RFB factory (tests / a WebRTC swap). Defaults to lazy @novnc/novnc. */\n rfbFactory?: DesktopRfbFactory | undefined;\n /** Custom socket factory for the self-hosted `relay-frames` transport (tests).\n * Defaults to `new WebSocket(url)`. Mirrors `rfbFactory`. */\n webSocketFactory?: DesktopWebSocketFactory | undefined;\n /**\n * Consent gate for the un-redacted (and possibly shared) pixel plane. Rendered\n * BEFORE connecting whenever the desktop requires acknowledgment that hasn't\n * been given. Call `onAccept` to record consent (the host wires it to\n * `client.acknowledgeStream` + a re-negotiate). When omitted, a default\n * banner is shown.\n */\n renderConsentGate?: ((onAccept: () => void, shared: boolean) => ReactNode) | undefined;\n /** Called when the default consent gate's accept button is pressed. */\n onAcknowledge?: (() => void) | undefined;\n /**\n * Whether the host has the viewer attach engaged (i.e. the user has opted into\n * watching — the parent's `watchDesktop`/`attachDesktop`). Drives the\n * cold-state behaviour: when watching, a cold-but-warmable lease AUTO-WARMS\n * (and re-warms when the box drains) instead of dead-ending. When omitted we\n * infer it from a recorded consent (the default gate's accept), so the\n * component still self-heals after the first acknowledgment.\n */\n watching?: boolean | undefined;\n /**\n * Request a (re)warm of the sandbox WITHOUT re-acknowledging (the consent has\n * already been recorded — only the box drained). The host wires this to\n * \"engage the viewer attach + re-negotiate\". Called automatically when a\n * watched desktop is found cold-but-warmable, and behind the manual retry on\n * the warming notice. Distinct from `onAcknowledge`, which is the FIRST,\n * consent-bearing warm.\n */\n onWarm?: (() => void) | undefined;\n /** Shown when transport is null (headless backend / degraded / disabled). */\n renderUnavailable?: ((reason: CapabilityUnavailableReason | null) => ReactNode) | undefined;\n /** Shown while the box is cold/warming (no live address yet). */\n renderWarming?: (() => ReactNode) | undefined;\n /** Shown when the per-session viewer cap (429) was hit. */\n renderViewerCap?: (() => ReactNode) | undefined;\n /** Surface the 429 cap state from `useSessionCapabilities().viewerCapReached`. */\n viewerCapReached?: boolean | undefined;\n /**\n * Connect watchdog (ms): if a live url is present but the RFB hasn't connected\n * within this window, surface a \"Couldn't connect\" + Reconnect instead of an\n * eternal idle scrim. Default 13000. 0 disables the watchdog.\n */\n connectTimeoutMs?: number | undefined;\n className?: string | undefined;\n};\n\n/**\n * The derived desktop surface state. A single source of truth so the overlay,\n * the scrim, the auto-warm effect, and the watchdog all agree. Priority order\n * (highest first): viewer-cap → unavailable → consent → warming → connect-failed\n * → error → connecting → connected.\n */\ntype DesktopUiState =\n | \"viewer_cap\" // 429 — the per-session live-viewer limit is reached.\n | \"unavailable\" // genuinely unsupported (headless/policy/os/backend/not-provisioned).\n | \"consent\" // un-redacted/shared plane needs acknowledgment first.\n | \"warming\" // cold-but-warmable: box not running yet (we auto-warm + spin).\n | \"connecting\" // url is live, RFB negotiating/handshaking (we spin, with a watchdog).\n | \"connect_failed\" // watchdog fired: url present but never connected.\n | \"error\" // RFB error / securityfailure after a connect.\n | \"connected\"; // live framebuffer painting.\n\n// Media-inspection exception: the framebuffer sits on true black so screenshots\n// and desktop pixels are not tinted by the product chrome palette.\nconst DESKTOP_MEDIA_BACKGROUND = \"#000\";\n\n/** Reasons that are genuinely-unavailable (never warmable from the viewer). A\n * `lease_cold` is deliberately EXCLUDED — that's the warmable cold state. */\nfunction isHardUnavailable(reason: CapabilityUnavailableReason | null): boolean {\n switch (reason) {\n case \"backend_unsupported\":\n case \"os_unsupported\":\n case \"not_provisioned\":\n case \"disabled_by_policy\":\n case \"tier_headless\":\n return true;\n default:\n // null or \"lease_cold\" → not a hard reason (cold-but-warmable / live).\n return false;\n }\n}\n\n/**\n * The desktop surface: a noVNC client connecting to the Channel-B scoped tunnel\n * URL from the capability doc. Owns the mount `<div ref>`, drives\n * `useDesktopStream` (SSR-safe lazy RFB), and renders a real\n * cold → warming → connecting → connected → error state machine with live\n * feedback (spinners, transitions) — never a dead black box with stale text.\n *\n * The read-only vs interactive decision is enforced server-first\n * (`capability.mode`): when the deployment advertises mode \"interactive\" the\n * viewer can TAKE CONTROL and drive the mouse & keyboard into the box's :0; a\n * \"read-only\" deployment disables the take-control affordance (graceful, with a\n * reason).\n *\n * Warming: a cold-but-warmable lease (`reason: \"lease_cold\"`) is NOT a dead end.\n * When the user is watching (consented), the viewer asks the host to (re)warm\n * the box (`onWarm`) and shows a \"Warming…\" spinner; if the box later drains to\n * cold it re-warms. Genuinely-unavailable surfaces (headless/policy/os/backend)\n * keep a clear, static unavailable notice.\n */\nexport function DesktopViewer({\n capability,\n interactive,\n showControlToggle = true,\n scaleViewport,\n rfbFactory,\n webSocketFactory,\n renderConsentGate,\n onAcknowledge,\n watching,\n onWarm,\n renderUnavailable,\n renderWarming,\n renderViewerCap,\n viewerCapReached,\n connectTimeoutMs = 13_000,\n className,\n}: DesktopViewerProps) {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const [consented, setConsented] = useState(false);\n // Local control state when not externally controlled. The server gate\n // (`capability.mode`) is the hard ceiling — a read-only deployment can never\n // be flipped to interactive regardless of this toggle.\n const [takeControl, setTakeControl] = useState(interactive ?? false);\n const externallyControlled = interactive !== undefined;\n const serverAllowsControl = capability?.mode !== \"read-only\";\n const wantControl = externallyControlled ? interactive : takeControl;\n const inControl = Boolean(wantControl) && serverAllowsControl;\n\n // Whether the host has the viewer attach engaged. Prefer the explicit prop;\n // fall back to a locally-recorded consent so the component still self-heals\n // (auto-warms / re-warms) once the user has accepted the gate at least once.\n const isWatching = watching ?? consented;\n\n // ── Decide the rendered state (before touching the stream hook) ─────────────\n const transportNull = !capability || capability.transport === null;\n const reason = capability?.reason ?? null;\n const needsAck =\n capability?.requiresAcknowledgment === true && capability.acknowledged !== true && !consented;\n // No live address yet on an otherwise-live transport (post-ack, mid-warm).\n const noLiveAddress = Boolean(capability) && !transportNull && !capability!.url;\n\n // Cold-but-warmable: the lease is cold (`lease_cold`) OR the transport is up\n // but no url has been minted yet — either way warming, not unavailable.\n const coldWarmable =\n (transportNull && reason === \"lease_cold\") || (!transportNull && noLiveAddress);\n // Genuinely-unavailable: transport null for a HARD reason (not lease_cold).\n const hardUnavailable = transportNull && isHardUnavailable(reason);\n\n const accept = () => {\n setConsented(true);\n onAcknowledge?.();\n };\n\n // Release control WITHOUT ever swallowing a key the desktop needs. Esc, and\n // every other key, pass straight through to noVNC/:0 — vital for vim, menus,\n // and dialogs inside the box. Exactly ONE non-trapping keyboard exit:\n // • A single non-conflicting chord — Ctrl+Alt+Shift pressed on its own (no\n // other key) — which no app binds, so it never eats a real keystroke.\n // (Plus the always-visible \"Return control\" button in the in-control bar.)\n //\n // We deliberately DO NOT release on pointer-leave (or window blur): those fire\n // as a SIDE EFFECT of connecting — the noVNC canvas re-laying-out, the surface\n // grabbing focus, the connecting scrim swapping in — which bounced control\n // straight back to \"watch\" the instant the user took it. Control is given up\n // only on an explicit, intentional gesture (the button or the chord).\n useEffect(() => {\n if (!inControl || externallyControlled) return;\n const onKey = (event: KeyboardEvent) => {\n // Only the bare modifier chord releases; if any non-modifier key is also\n // down (event.key is a real key like \"a\"/\"Escape\"), let it pass through.\n if (\n event.ctrlKey &&\n event.altKey &&\n event.shiftKey &&\n (event.key === \"Control\" || event.key === \"Alt\" || event.key === \"Shift\")\n ) {\n event.preventDefault();\n setTakeControl(false);\n }\n };\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"keydown\", onKey);\n };\n }, [inControl, externallyControlled]);\n\n // The hook is always called (rules of hooks); it stays idle until `url` is set.\n // Do NOT open a socket while the viewer-cap (429) notice is showing — the slot\n // is already exhausted, so connecting would only burn a doomed attempt (and in\n // tests leak an unhandled ws error from the never-resolving tunnel URL).\n const connectCapability = !transportNull && !needsAck && !viewerCapReached ? capability : null;\n const stream = useDesktopStream({\n capability: connectCapability,\n containerRef,\n interactive: inControl,\n ...(scaleViewport !== undefined ? { scaleViewport } : {}),\n ...(rfbFactory ? { rfbFactory } : {}),\n ...(webSocketFactory ? { webSocketFactory } : {}),\n });\n\n const connected = stream.state === \"connected\";\n const hasLiveUrl = Boolean(connectCapability?.url);\n // The latest stream state, read without making it an effect dependency — so the\n // re-attach below can consult it on a visibility change WITHOUT re-subscribing\n // (and re-firing) every time the state walks idle→negotiating→connected.\n const streamStateRef = useRef(stream.state);\n streamStateRef.current = stream.state;\n\n // ── AUTO-WARM ───────────────────────────────────────────────────────────────\n // When the user is watching and the desktop is cold-but-warmable, ask the host\n // to (re)warm the box. This covers BOTH (a) the user just accepted consent and\n // (b) a previously-warm box that drained back to cold under a live viewer. We\n // fire once per distinct cold episode (keyed on the lease epoch + url) so we\n // don't spam the attach while a single warm is in flight. `onWarm` is the\n // no-re-ack path; if the host only wired `onAcknowledge` (no `onWarm`), the\n // first warm still rides consent and subsequent drains fall back to it.\n const warmKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (!isWatching || !coldWarmable || needsAck || viewerCapReached) {\n // Reset the de-dupe once we leave the cold episode so a future drain warms.\n if (!coldWarmable) warmKeyRef.current = null;\n return;\n }\n const warm = onWarm ?? onAcknowledge;\n if (!warm) return;\n // Key the de-dupe on the cell fields available to the viewer: while cold,\n // `reason`/`url`/`expiresAt` are stable, so we warm exactly once; once the box\n // warms the cell changes (url+expiresAt minted) and `coldWarmable` flips false,\n // resetting the ref so a later drain re-warms.\n const key = `${capability?.reason ?? \"\"}:${capability?.url ?? \"\"}:${capability?.expiresAt ?? \"\"}`;\n if (warmKeyRef.current === key) return; // already kicked this episode.\n warmKeyRef.current = key;\n warm();\n // capability identity is the trigger; leaseEpoch/expiresAt key the episode.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isWatching, coldWarmable, needsAck, viewerCapReached, capability, onWarm, onAcknowledge]);\n\n // ── TAB RE-ATTACH ───────────────────────────────────────────────────────────\n // The \"stuck Watching, never connects\" bug: the RFB socket never (re)fires when\n // the Desktop tab is shown without a refresh. When a live url exists but we are\n // not connected/connecting, nudge the stream hook to (re)attach — on mount, on\n // the document becoming visible, and on a fresh capability. Re-attach is cheap\n // (disconnect-old/connect-new) and idempotent: the hook ignores it once live.\n useEffect(() => {\n if (!hasLiveUrl || typeof document === \"undefined\") return;\n const maybeReattach = () => {\n if (document.visibilityState !== \"visible\") return;\n // Only kick a socket that never OPENED (idle — e.g. the tab was hidden when\n // the url arrived, so the connect effect bailed on a missing container).\n // Deliberately NOT on \"error\": that surfaces an overlay with an explicit\n // Reconnect, and auto-retrying here would hammer (reconnect → error →\n // reconnect…). We read the live state via a ref so this effect does NOT\n // depend on `stream.state` — depending on it re-ran the effect on every\n // transition and re-fired the kick, which is the reconnect loop.\n if (streamStateRef.current === \"idle\") stream.reconnect();\n };\n // The connect effect already opens the socket on mount / a fresh url. The\n // ONLY gap it can't self-heal is a tab that was hidden when the url arrived\n // (container not in the DOM → connect effect bailed to idle): the socket then\n // never (re)fires on its own. So we revive it on the tab becoming visible —\n // NOT on mount (that double-opens the socket the connect effect just opened).\n document.addEventListener(\"visibilitychange\", maybeReattach);\n return () => document.removeEventListener(\"visibilitychange\", maybeReattach);\n // Re-run ONLY on a fresh live url, never on a state transition.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hasLiveUrl, connectCapability?.url]);\n\n // ── CONNECT WATCHDOG ─────────────────────────────────────────────────────────\n // If a live url is present but the RFB hasn't reached \"connected\" within the\n // window, stop spinning forever and surface \"Couldn't connect\" + Reconnect.\n // Cleared whenever we connect, the url rotates, or the user reconnects.\n const [connectTimedOut, setConnectTimedOut] = useState(false);\n // Bumped on every manual reconnect so the watchdog re-arms its window (the\n // stream hook's url/error don't change on a reconnect, so we need our own key).\n const [reconnectNonce, setReconnectNonce] = useState(0);\n useEffect(() => {\n // Re-arm on a fresh url / a reconnect and clear the moment we connect or hit a\n // real RFB error. We deliberately do NOT key on `stream.state`, so the benign\n // idle→connecting walk doesn't keep resetting the window — the full timeout\n // runs from the url becoming live.\n setConnectTimedOut(false);\n if (!hasLiveUrl || connected || stream.error || connectTimeoutMs <= 0) return;\n const timer = setTimeout(() => setConnectTimedOut(true), connectTimeoutMs);\n return () => clearTimeout(timer);\n }, [\n hasLiveUrl,\n connected,\n connectTimeoutMs,\n connectCapability?.url,\n stream.error,\n reconnectNonce,\n ]);\n\n const reconnect = () => {\n setConnectTimedOut(false);\n setReconnectNonce((n) => n + 1);\n stream.reconnect();\n };\n\n // ── Resolve the single UI state (priority order) ────────────────────────────\n let uiState: DesktopUiState;\n if (viewerCapReached) uiState = \"viewer_cap\";\n else if (hardUnavailable) uiState = \"unavailable\";\n else if (needsAck && !isWatching) uiState = \"consent\";\n else if (coldWarmable) uiState = \"warming\";\n else if (connected) uiState = \"connected\";\n else if (stream.error) uiState = \"error\";\n else if (connectTimedOut) uiState = \"connect_failed\";\n else uiState = \"connecting\"; // hasLiveUrl && not yet connected (idle/negotiating/connecting).\n\n // An overlay blocks the surface for every state except connected; the toggle\n // and the live scrim are suppressed under an overlay.\n const overlayShown = uiState !== \"connected\" && uiState !== \"connecting\";\n const showToggle = showControlToggle && !overlayShown;\n\n let overlay: ReactNode = null;\n switch (uiState) {\n case \"viewer_cap\":\n overlay =\n renderViewerCap?.() ??\n defaultNotice(\n \"Too many viewers\",\n \"This session has reached its live-viewer limit. Try again shortly.\",\n );\n break;\n case \"unavailable\":\n overlay =\n renderUnavailable?.(reason) ??\n defaultNotice(\"Desktop unavailable\", unavailableCopy(reason));\n break;\n case \"consent\":\n overlay = renderConsentGate ? (\n renderConsentGate(accept, capability?.shared ?? false)\n ) : (\n <DefaultConsentGate shared={capability?.shared ?? false} onAccept={accept} />\n );\n break;\n case \"warming\":\n overlay = renderWarming?.() ?? <WarmingNotice />;\n break;\n case \"connect_failed\":\n overlay = defaultNotice(\n \"Couldn’t connect\",\n \"The desktop is warm but the live stream didn’t come up. This usually clears on a retry.\",\n reconnect,\n );\n break;\n case \"error\":\n overlay = defaultNotice(\n \"Desktop disconnected\",\n stream.error?.message ?? \"The stream dropped.\",\n reconnect,\n );\n break;\n case \"connecting\":\n case \"connected\":\n overlay = null;\n break;\n }\n\n return (\n <div\n className={cn(\n \"relative h-full w-full overflow-hidden\",\n inControl && \"ring-2 ring-inset ring-og-accent\",\n className,\n )}\n style={{ backgroundColor: DESKTOP_MEDIA_BACKGROUND }}\n data-opengeni-desktop\n data-state={stream.state}\n data-ui-state={uiState}\n data-in-control={inControl ? \"true\" : undefined}\n >\n {/* noVNC mount target. It appends a `width:100%;height:100%` `_screen` div\n and AUTOSCALES the 1280x800 framebuffer to fit THIS box. We pin it to\n the bounded `relative` wrapper with `absolute inset-0` (not just\n `h-full w-full`) so its measured size is ALWAYS the panel — never the\n canvas content. A content-sized mount is exactly what makes noVNC\n measure a huge screen and paint the desktop \"zoomed in\". `overflow-hidden`\n keeps the centered (margin:auto) canvas from ever spilling the panel. */}\n <div\n ref={containerRef}\n className=\"absolute inset-0 overflow-hidden\"\n data-opengeni-desktop-canvas\n data-state={stream.state}\n />\n\n {/* Idle / connecting scrim: a quiet, ALIVE \"connecting to the desktop\"\n state behind the canvas so the surface never reads as a dead black\n rectangle before the first framebuffer paints. Only shown in the\n `connecting` UI-state (every other non-connected state has an explicit\n overlay). A spinner + transitional copy makes it feel live. */}\n {uiState === \"connecting\" && (\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-3 text-og-fg-subtle\">\n <span className=\"relative flex items-center justify-center\">\n <MonitorIcon className=\"size-8 opacity-30\" strokeWidth={1.5} />\n <LoaderCircleIcon\n className=\"absolute size-12 animate-og-spin text-og-accent opacity-70\"\n strokeWidth={1.25}\n />\n </span>\n <span className=\"text-og-sm\">Connecting to the desktop…</span>\n </div>\n )}\n\n {/* Take-control affordance. Two distinct states:\n - WATCHING → a prominent, centered call-to-action button overlaid on\n the desktop (the primary CTA; tasteful so the screen stays visible).\n - IN CONTROL → a small top bar (\"You're in control · click Return\n control (or Ctrl+Alt+Shift)\") with a clearly-visible Return-control\n button; the desktop stays fully usable and EVERY key — Esc included —\n passes through to the box. Server-gated: when the deployment is\n read-only the CTA renders disabled with a reason so it degrades\n gracefully. */}\n {showToggle && !externallyControlled && inControl && (\n <InControlBar\n shared={capability?.shared ?? false}\n onRelease={() => setTakeControl(false)}\n />\n )}\n {/* The big CTA only appears once the framebuffer is live + the viewer is\n watching: before connect the scrim already communicates state, so we\n don't double up. A read-only deployment (serverAllowsControl=false) still\n surfaces the CTA disabled-with-reason once connected, so it degrades\n gracefully and stays discoverable. */}\n {showToggle && !externallyControlled && !inControl && connected && (\n <TakeControlCallToAction\n disabled={!serverAllowsControl}\n disabledReason={\n !serverAllowsControl\n ? capability?.client === \"frames\"\n ? \"View-only — live control isn't available for this machine yet.\"\n : \"This deployment streams the desktop read-only.\"\n : undefined\n }\n onTakeControl={() => setTakeControl(true)}\n />\n )}\n\n {overlay && (\n <div className=\"absolute inset-0 flex items-center justify-center p-4\">{overlay}</div>\n )}\n </div>\n );\n}\n\n/**\n * The primary WATCHING-state call-to-action: a large, centered pill button\n * overlaid on the desktop inviting the viewer to drive the mouse & keyboard.\n * Tasteful by default — it sits in the LOWER-center with a soft scrim only behind\n * the button (not the whole screen) and lifts on hover, so a watcher can still see\n * the agent work. Server-gated: when the deployment is read-only (or the desktop\n * hasn't connected yet) it renders disabled with a reason. Accessible: a real\n * <button> with a title, focus ring, and Enter/Space activation.\n */\nfunction TakeControlCallToAction({\n disabled,\n disabledReason,\n onTakeControl,\n}: {\n disabled: boolean;\n disabledReason?: string | undefined;\n onTakeControl: () => void;\n}) {\n return (\n // The wrapper spans the surface but is click-through (pointer-events-none); only\n // the button itself is interactive, so watchers can still see the desktop.\n <div className=\"pointer-events-none absolute inset-0 flex items-end justify-center pb-[8%]\">\n <button\n type=\"button\"\n disabled={disabled}\n aria-label=\"Take control of the desktop\"\n title={disabled ? disabledReason : \"Take control of the desktop\"}\n onClick={onTakeControl}\n className={cn(\n \"group pointer-events-auto flex items-center gap-3 rounded-og-lg border px-5 py-3\",\n \"border-og-border\",\n \"bg-og-bg/85 backdrop-blur-md\",\n \"shadow-og-lg\",\n \"outline-none transition-all duration-150 ease-out\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg\",\n disabled\n ? \"cursor-not-allowed opacity-60\"\n : cn(\n \"cursor-pointer opacity-90 hover:-translate-y-0.5 hover:opacity-100\",\n \"hover:border-og-accent\",\n \"hover:bg-og-accent/10\",\n ),\n )}\n >\n <span\n className={cn(\n \"flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\",\n \"bg-og-accent\",\n \"text-og-accent-fg\",\n disabled ? \"\" : \"group-hover:scale-105\",\n )}\n >\n <MousePointerClickIcon className=\"size-5\" strokeWidth={2} />\n </span>\n <span className=\"flex flex-col items-start leading-tight\">\n <span className=\"text-og-base font-semibold text-og-fg\">Take control</span>\n <span className=\"text-og-xs text-og-fg-subtle\">\n {disabled && disabledReason ? disabledReason : \"Drive the mouse & keyboard\"}\n </span>\n </span>\n </button>\n </div>\n );\n}\n\n/**\n * The IN-CONTROL state: a small top bar so the desktop stays fully usable while\n * driving (the accent ring around the viewport carries the primary \"you're\n * driving\" signal). Every keystroke — including Esc — passes through to the box,\n * so release lives only on explicit, non-trapping affordances: a clearly-visible\n * \"Return control\" button and the Ctrl+Alt+Shift chord. The button is solid\n * (not a faint ghost) so it's always discoverable as the way out.\n */\nfunction InControlBar({ shared, onRelease }: { shared: boolean; onRelease: () => void }) {\n return (\n <div className=\"pointer-events-none absolute inset-x-0 top-0 flex items-center justify-between gap-2 p-2\">\n <span className=\"pointer-events-auto inline-flex items-center gap-2 rounded-og-sm bg-og-accent px-2.5 py-1 text-og-xs font-medium text-og-accent-fg shadow-og-md\">\n <span className=\"size-1.5 animate-pulse rounded-full bg-current\" aria-hidden />\n You&apos;re in control\n <span className=\"opacity-75\">· click Return control (or Ctrl+Alt+Shift)</span>\n </span>\n <div className=\"pointer-events-auto flex items-center gap-1.5\">\n {shared && (\n <span className=\"rounded-og-sm bg-og-status-failed/85 px-2 py-0.5 text-og-xs text-og-accent-fg\">\n Shared sandbox — others are watching\n </span>\n )}\n <button\n type=\"button\"\n onClick={onRelease}\n title=\"Return control (or press Ctrl+Alt+Shift)\"\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-og-sm border px-2.5 py-1 text-og-xs font-semibold shadow-og-md transition-colors\",\n \"border-og-accent bg-og-bg/90 text-og-fg backdrop-blur-sm\",\n \"outline-none hover:bg-og-accent hover:text-og-accent-fg focus-visible:ring-2 focus-visible:ring-og-accent\",\n )}\n >\n <MonitorIcon className=\"size-3.5\" strokeWidth={2} aria-hidden />\n Return control\n </button>\n </div>\n </div>\n );\n}\n\nfunction unavailableCopy(reason: CapabilityUnavailableReason | null): string {\n switch (reason) {\n case \"backend_unsupported\":\n return \"This sandbox backend cannot stream a desktop.\";\n case \"tier_headless\":\n return \"This deployment is headless — terminal, files, and diff only.\";\n case \"os_unsupported\":\n return \"The sandbox OS does not support a desktop stream.\";\n case \"not_provisioned\":\n return \"This sandbox doesn't have a desktop yet.\";\n case \"disabled_by_policy\":\n return \"Desktop streaming is disabled on this deployment.\";\n case \"lease_cold\":\n // Should not reach the unavailable notice (lease_cold warms), but keep\n // friendly copy as a fallback rather than the old dead-end wording.\n return \"Waiting for the sandbox to start…\";\n default:\n return \"The desktop isn’t available for this sandbox.\";\n }\n}\n\n/**\n * The WARMING state: a cold-but-warmable box that is being spun up. A spinner +\n * clear, accurate copy — and (when the host wired a manual warm) an explicit\n * retry so a slow warm never feels stuck. This is the cure for the old\n * \"Desktop unavailable — Start a turn or attach to warm it\" dead-end: the box IS\n * being warmed automatically; we just tell the user it's happening.\n */\nfunction WarmingNotice({ onRetry }: { onRetry?: (() => void) | undefined }) {\n return (\n <div className=\"flex max-w-sm flex-col items-center gap-3 rounded-og-lg border border-og-border bg-og-bg/90 p-5 text-center text-og-base text-og-fg backdrop-blur-sm\">\n <LoaderCircleIcon className=\"size-7 animate-og-spin text-og-accent\" strokeWidth={1.5} />\n <div className=\"space-y-1\">\n <div className=\"font-medium\">Warming the sandbox…</div>\n <p className=\"text-og-sm text-og-fg-subtle\">\n Spinning up the desktop — this takes a few seconds.\n </p>\n </div>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm text-og-fg-muted transition-colors hover:text-og-fg pointer-coarse:min-h-10\"\n >\n Taking too long? Retry\n </button>\n )}\n </div>\n );\n}\n\nfunction DefaultConsentGate({ shared, onAccept }: { shared: boolean; onAccept: () => void }) {\n return (\n <div className=\"max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg\">\n <div className=\"mb-1 font-medium\">Watch the live desktop?</div>\n <p className=\"mb-3 text-og-sm text-og-fg-subtle\">\n The desktop pixel stream is <strong>un-redacted</strong> — it can show secrets the agent\n prints on screen.\n {shared\n ? \" This sandbox is shared: you'll also see other sessions' agents on the same screen.\"\n : \"\"}\n </p>\n <button\n type=\"button\"\n onClick={onAccept}\n className=\"rounded-og-sm bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg pointer-coarse:min-h-10\"\n >\n I understand — show the desktop\n </button>\n </div>\n );\n}\n\nfunction defaultNotice(title: string, body: string, onRetry?: () => void): ReactNode {\n return (\n <div className=\"max-w-sm rounded-og-lg border border-og-border bg-og-bg p-4 text-center text-og-base text-og-fg\">\n <div className=\"mb-1 flex items-center justify-center gap-1.5 font-medium\">\n {onRetry && <WifiOffIcon className=\"size-4 opacity-70\" strokeWidth={1.75} />}\n {title}\n </div>\n <p className=\"text-og-sm text-og-fg-subtle\">{body}</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-3 rounded-og-sm border border-og-border px-3 py-1.5 text-og-sm transition-colors hover:border-og-accent pointer-coarse:min-h-10\"\n >\n Reconnect\n </button>\n )}\n </div>\n );\n}\n","import {\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n ChevronsLeftRightIcon,\n Maximize2Icon,\n Minimize2Icon,\n PanelRightCloseIcon,\n XIcon,\n} from \"lucide-react\";\nimport { Group, Panel, Separator, useDefaultLayout, usePanelRef } from \"react-resizable-panels\";\nimport { cn } from \"../lib/cn\";\n\nexport type WorkspaceTab = {\n id: string;\n label: ReactNode;\n /** Rendered as the active surface. */\n content: ReactNode;\n /** A small badge after the label (e.g. dirty count, live pill). */\n badge?: ReactNode | undefined;\n};\n\nexport type WorkspaceDockProps = {\n /** The chat / primary pane shown beside the dock. */\n primary: ReactNode;\n tabs: WorkspaceTab[];\n /** Controlled active tab. Falls back to the first tab. */\n activeTab?: string | undefined;\n onActiveTabChange?: ((id: string) => void) | undefined;\n /** Controlled collapsed state for hosts that expose their own dock toggle. */\n collapsed?: boolean | undefined;\n onCollapsedChange?: ((collapsed: boolean) => void) | undefined;\n /** A status accessory pinned to the right of the tab strip, left of the\n * maximize/collapse controls (e.g. the machine-state chip). Renders in both\n * the docked header and the full-screen overlay header. */\n headerAccessory?: ReactNode | undefined;\n /** Optional host navigation shown at the start of the phone overlay header.\n * It is intentionally absent from desktop dock chrome. */\n mobileLeadingControl?: ReactNode | undefined;\n /** Persisted layout id (localStorage key) for react-resizable-panels. */\n autoSaveId?: string | undefined;\n /** Default dock width as a percent of the session area. */\n defaultSize?: number | undefined;\n minSize?: number | undefined;\n maxSize?: number | undefined;\n className?: string | undefined;\n};\n\n/**\n * The resizable / collapsible / maximizable right-hand Workspace dock. Replaces\n * a fixed grid column: drag the separator to set width, collapse to a thin rail\n * that re-opens on click, and maximize to a full-workspace overlay (Esc /\n * restore button returns). Layout persists via `useDefaultLayout` keyed on\n * `autoSaveId`. Maximize is a mode ABOVE the Group (a `fixed inset-0` overlay) —\n * pushing a Panel to ~100% still fights min sizes and leaves a chat sliver.\n *\n * Below {@link DOCK_OVERLAY_BREAKPOINT} the side-by-side split can't work on a\n * phone-width viewport, so the resizable panels are dropped entirely: the\n * primary pane goes full-width and the dock becomes a full-screen overlay driven\n * by the same `collapsed` / `onCollapsedChange` contract (collapsed → hidden).\n * No drag splitter renders below the breakpoint.\n */\nconst useDockLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\n/**\n * The dock stops being a side column at this width and becomes a full-screen\n * overlay — matches the app's rail-drawer breakpoint (the single `isMobile`\n * source). The package can't read app context, so it detects the width itself.\n */\nconst DOCK_OVERLAY_BREAKPOINT = 1024;\n\n/** SSR-safe `(max-width: …)` match; false until mounted, then live. */\nfunction useIsNarrow(maxWidth: number): boolean {\n const [narrow, setNarrow] = useState(false);\n useDockLayoutEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return;\n }\n const mql = window.matchMedia(`(max-width: ${maxWidth - 1}px)`);\n const update = () => setNarrow(mql.matches);\n update();\n if (typeof mql.addEventListener === \"function\") {\n mql.addEventListener(\"change\", update);\n return () => mql.removeEventListener(\"change\", update);\n }\n // Legacy Safari.\n mql.addListener(update);\n return () => mql.removeListener(update);\n }, [maxWidth]);\n return narrow;\n}\n\nexport function WorkspaceDock({\n primary,\n tabs,\n activeTab,\n onActiveTabChange,\n collapsed: collapsedProp,\n onCollapsedChange,\n headerAccessory,\n mobileLeadingControl,\n autoSaveId = \"og.session.dock\",\n defaultSize = 34,\n minSize = 22,\n maxSize = 70,\n className,\n}: WorkspaceDockProps) {\n const narrow = useIsNarrow(DOCK_OVERLAY_BREAKPOINT);\n const dockPanelRef = usePanelRef();\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const [maximized, setMaximized] = useState(false);\n const [internalTab, setInternalTab] = useState(tabs[0]?.id ?? \"\");\n const collapsed = collapsedProp ?? internalCollapsed;\n // When the host supplies `collapsed` it owns the open/close affordance (e.g.\n // the app header's panel toggle) — the dock must not offer a SECOND\n // open/close control (duplicate buttons with near-identical icons read as a\n // bug). Standalone (uncontrolled) usage keeps the built-in collapse button\n // and the thin re-open rail as its only affordances.\n const hostControlled = collapsedProp !== undefined;\n\n // Persisted layout (width split) keyed by autoSaveId.\n const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n panelIds: [\"primary\", \"dock\"],\n storage: typeof window !== \"undefined\" ? window.localStorage : undefined,\n id: autoSaveId,\n } as Parameters<typeof useDefaultLayout>[0]);\n\n const requestedTab = activeTab ?? internalTab;\n const tabIds = tabs.map((tab) => tab.id);\n const firstTabId = tabs[0]?.id ?? \"\";\n const requestedTabIsValid = tabIds.includes(requestedTab);\n const current = requestedTabIsValid ? requestedTab : firstTabId;\n const setTab = useCallback(\n (id: string) => {\n setInternalTab(id);\n onActiveTabChange?.(id);\n },\n [onActiveTabChange],\n );\n const setCollapsed = useCallback(\n (next: boolean) => {\n setInternalCollapsed((previous) => (previous === next ? previous : next));\n onCollapsedChange?.(next);\n },\n [onCollapsedChange],\n );\n\n useDockLayoutEffect(() => {\n if (collapsedProp === undefined) {\n return;\n }\n if (collapsedProp) {\n dockPanelRef.current?.collapse();\n setMaximized(false);\n } else {\n dockPanelRef.current?.expand();\n }\n }, [collapsedProp, dockPanelRef]);\n\n // Keep the active tab valid if the available tabs change.\n useEffect(() => {\n if (firstTabId && !requestedTabIsValid) {\n setTab(firstTabId);\n }\n // Depend on tab identity, not the tab content objects. Session live events\n // rebuild tab JSX frequently; only id changes can invalidate the active tab.\n }, [firstTabId, requestedTabIsValid, setTab]);\n\n const collapse = useCallback(() => {\n dockPanelRef.current?.collapse();\n setCollapsed(true);\n }, [dockPanelRef, setCollapsed]);\n const expand = useCallback(() => {\n dockPanelRef.current?.expand();\n setCollapsed(false);\n }, [dockPanelRef, setCollapsed]);\n\n // Esc restores from maximize (desktop) and closes the mobile overlay.\n useEffect(() => {\n const overlayOpen = maximized || (narrow && !collapsed);\n if (!overlayOpen) return;\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return;\n if (maximized) setMaximized(false);\n else collapse();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [maximized, narrow, collapsed, collapse]);\n\n // Below the breakpoint the dock is a full-screen overlay, not a resizable\n // column: primary goes full-width and no splitter ever mounts. The overlay is\n // driven by the same `collapsed` contract (collapsed → hidden).\n if (narrow) {\n return (\n <div className={cn(\"relative flex h-full min-h-0 w-full min-w-0\", className)}>\n <div className=\"min-h-0 min-w-0 flex-1\">{primary}</div>\n {!collapsed && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Workspace\"\n className=\"fixed inset-0 z-40 flex flex-col bg-og-bg\"\n style={{\n paddingTop: \"env(safe-area-inset-top)\",\n paddingBottom: \"env(safe-area-inset-bottom)\",\n }}\n >\n <DockChrome\n tabs={tabs}\n current={current}\n onTab={setTab}\n leading={mobileLeadingControl}\n accessory={headerAccessory}\n controls={\n <ChromeButton onClick={collapse} title=\"Close workspace\" label=\"Close workspace\">\n <XIcon className=\"size-4\" />\n </ChromeButton>\n }\n />\n </div>\n )}\n </div>\n );\n }\n\n const dockChrome = (\n <DockChrome\n tabs={tabs}\n current={current}\n onTab={setTab}\n accessory={headerAccessory}\n controls={\n <>\n <ChromeButton\n onClick={() => setMaximized((m) => !m)}\n title={maximized ? \"Restore (Esc)\" : \"Maximize\"}\n label={maximized ? \"Restore dock\" : \"Maximize dock\"}\n >\n {maximized ? (\n <Minimize2Icon className=\"size-3.5\" />\n ) : (\n <Maximize2Icon className=\"size-3.5\" />\n )}\n </ChromeButton>\n {hostControlled ? null : (\n <ChromeButton onClick={collapse} title=\"Collapse\" label=\"Collapse dock\">\n <PanelRightCloseIcon className=\"size-3.5\" />\n </ChromeButton>\n )}\n </>\n }\n />\n );\n\n return (\n <div className={cn(\"relative flex h-full min-h-0 w-full min-w-0\", className)}>\n <Group\n orientation=\"horizontal\"\n className=\"min-h-0 flex-1\"\n {...(defaultLayout ? { defaultLayout } : {})}\n onLayoutChanged={onLayoutChanged}\n >\n <Panel id=\"primary\" minSize=\"30%\" className=\"min-h-0 min-w-0\">\n {primary}\n </Panel>\n\n {!collapsed && (\n <Separator className=\"group relative w-1.5 shrink-0 outline-none\">\n <span className=\"absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-og-border transition-colors group-hover:bg-og-accent group-data-[separator-state=dragging]:bg-og-accent\" />\n </Separator>\n )}\n\n <Panel\n id=\"dock\"\n panelRef={dockPanelRef}\n collapsible\n collapsedSize=\"0%\"\n defaultSize={`${defaultSize}%`}\n minSize={`${minSize}%`}\n maxSize={`${maxSize}%`}\n onResize={(size, _id, previousSize) => {\n // `asPercentage` is 0..100; treat a near-zero panel as collapsed.\n const isCollapsed = size.asPercentage <= 1;\n const canInferCollapse = collapsedProp === undefined || previousSize !== undefined;\n if (canInferCollapse && isCollapsed !== collapsed) {\n setCollapsed(isCollapsed);\n }\n }}\n className=\"min-h-0 min-w-0\"\n >\n {/* Hidden behind the overlay while maximized (avoids double-mounting\n the surfaces). */}\n {!collapsed && !maximized && (\n <div className=\"flex h-full min-h-0 min-w-0 flex-col border-l border-og-border bg-og-bg\">\n {dockChrome}\n </div>\n )}\n </Panel>\n </Group>\n\n {/* Collapsed rail: the standalone fallback re-open affordance. Hidden\n when the host controls collapse — its own toggle is the one way in. */}\n {collapsed && !maximized && !hostControlled && (\n <button\n type=\"button\"\n onClick={expand}\n title=\"Open workspace\"\n className=\"absolute inset-y-0 right-0 flex w-6 shrink-0 items-center justify-center border-l border-og-border bg-og-surface-1 text-og-fg-subtle hover:text-og-fg\"\n >\n <ChevronsLeftRightIcon className=\"size-3.5\" />\n </button>\n )}\n\n {/* Maximize overlay: full-workspace surface above everything. */}\n {maximized && <div className=\"fixed inset-0 z-40 flex flex-col bg-og-bg\">{dockChrome}</div>}\n </div>\n );\n}\n\n/** A dock-chrome control button — compact on fine pointers, ≥40px on coarse. */\nfunction ChromeButton({\n onClick,\n title,\n label,\n children,\n}: {\n onClick: () => void;\n title: string;\n label: string;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={title}\n aria-label={label}\n className=\"inline-flex size-7 items-center justify-center rounded-og-sm p-1 transition-colors hover:bg-og-surface-2 hover:text-og-fg max-[1023px]:size-11 pointer-coarse:size-11\"\n >\n {children}\n </button>\n );\n}\n\nfunction DockChrome({\n tabs,\n current,\n onTab,\n leading,\n accessory,\n controls,\n}: {\n tabs: WorkspaceTab[];\n current: string;\n onTab: (id: string) => void;\n /** Host navigation at the start of mobile overlay chrome. */\n leading?: ReactNode | undefined;\n /** A status accessory (machine chip) between the tab strip and the controls. */\n accessory?: ReactNode | undefined;\n /** Right-aligned chrome controls (maximize / collapse, or the overlay close). */\n controls: ReactNode;\n}) {\n const active = tabs.find((t) => t.id === current) ?? tabs[0];\n const activeIndex = tabs.findIndex((tab) => tab.id === active?.id);\n const tabsetId = useId();\n const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);\n const panelId = `${tabsetId}-panel`;\n\n const activateTab = (index: number) => {\n const tab = tabs[index];\n if (!tab) return;\n onTab(tab.id);\n tabRefs.current[index]?.focus();\n };\n\n const onTabKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>, index: number) => {\n if (tabs.length === 0) return;\n let nextIndex: number | null = null;\n if (event.key === \"ArrowRight\") nextIndex = (index + 1) % tabs.length;\n else if (event.key === \"ArrowLeft\") nextIndex = (index - 1 + tabs.length) % tabs.length;\n else if (event.key === \"Home\") nextIndex = 0;\n else if (event.key === \"End\") nextIndex = tabs.length - 1;\n if (nextIndex === null) return;\n event.preventDefault();\n activateTab(nextIndex);\n };\n\n return (\n <>\n <div className=\"flex shrink-0 items-center gap-2 border-b border-og-border px-1.5 py-1\">\n {leading ? <div className=\"flex shrink-0 items-center\">{leading}</div> : null}\n {/* The tab list scrolls horizontally when it can't fit — it must never\n grow into or overlap the chrome controls (they stay shrink-0). The\n scrollbar is hidden to keep the strip calm. */}\n <div\n className=\"flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n role=\"tablist\"\n aria-orientation=\"horizontal\"\n >\n {tabs.map((tab, index) => (\n <button\n key={tab.id}\n ref={(node) => {\n tabRefs.current[index] = node;\n }}\n id={`${tabsetId}-tab-${index}`}\n type=\"button\"\n role=\"tab\"\n aria-selected={tab.id === current}\n aria-controls={panelId}\n tabIndex={tab.id === current ? 0 : -1}\n onClick={() => onTab(tab.id)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n className={cn(\n \"flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors max-[1023px]:min-h-11 max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11\",\n tab.id === current\n ? \"bg-og-accent-soft text-og-fg\"\n : \"text-og-fg-subtle hover:text-og-fg\",\n )}\n >\n <span>{tab.label}</span>\n {tab.badge}\n </button>\n ))}\n </div>\n {accessory ? <div className=\"flex shrink-0 items-center\">{accessory}</div> : null}\n <div className=\"flex shrink-0 items-center gap-0.5 text-og-fg-subtle\">{controls}</div>\n </div>\n <div\n id={panelId}\n aria-label={activeIndex < 0 ? \"Workspace\" : undefined}\n aria-labelledby={activeIndex >= 0 ? `${tabsetId}-tab-${activeIndex}` : undefined}\n className=\"min-h-0 min-w-0 flex-1 overflow-hidden\"\n role=\"tabpanel\"\n >\n {active?.content}\n </div>\n </>\n );\n}\n","// The sandbox workbench — the SDK-embeddable dock \"brain\" (Workbench v2, M4).\n//\n// This module owns the whole session workspace surface an embedder mounts:\n// Changes — review-first git: turn-end capture (cold) or live diff (warm)\n// Files — tree + inline editor (capture-backed cold, live warm)\n// Terminal — interactive xterm wired to the box PTY (Channel-A projection)\n// Desktop — noVNC (Channel-B), watch by default + a server-gated take-control\n// plus a machine-state chip in the dock header (the one truthful live/waking/\n// offline indicator) and any host-injected extra tabs (Run/Debug in apps/web).\n//\n// It is decoupled from the host app: the client comes from <OpenGeniProvider>\n// (never an app context), notifications flow through an optional `onNotify` prop\n// (no `sonner` import), and every surface renders with package primitives + og\n// tokens only. `apps/web` consumes this through the exact public surface an\n// external embedder (cloudgeni #1577) uses — that is criterion F1.\nimport { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Popover } from \"radix-ui\";\nimport type { SessionEvent } from \"@opengeni/sdk\";\nimport { CpuIcon, LaptopIcon, RefreshCwIcon } from \"lucide-react\";\n\nimport { type ClientOverride, useOpenGeni } from \"../provider\";\nimport { cn } from \"../lib/cn\";\nimport { xtermThemeFromTokens } from \"../lib/xterm-theme\";\nimport { useSessionCapabilities } from \"../hooks/use-session-capabilities\";\nimport { useSandboxFiles } from \"../hooks/use-sandbox-files\";\nimport { useSandboxGit, type UseSandboxGitResult } from \"../hooks/use-sandbox-git\";\nimport { useSandboxTerminal } from \"../hooks/use-sandbox-terminal\";\nimport { useWorkspaceCapture } from \"../hooks/use-workspace-capture\";\nimport { formatAsOf, useMachineChip, type MachineChip } from \"../hooks/use-machine-chip\";\nimport { useMachines } from \"../hooks/use-machines\";\nimport type { MachineView } from \"../types/machines\";\nimport { connectionStatusForState } from \"../types/machines\";\nimport { ConnectionStatusPill } from \"./machine-status-pill\";\nimport { SharedMachineDisclosure } from \"./machine-dock-bar\";\nimport { SandboxFiles } from \"./sandbox-files\";\nimport { WorkbenchChanges } from \"./workbench-changes\";\nimport { SandboxTerminal, type XtermTheme } from \"./sandbox-terminal\";\nimport { DesktopViewer } from \"./desktop-viewer\";\nimport { WorkspaceDock, type WorkspaceDockProps, type WorkspaceTab } from \"./workspace-dock\";\n\n/** A host-routed notification (replaces the app-only `sonner` toast coupling). */\nexport type WorkspaceNotification = { kind: \"error\" | \"info\"; message: string };\n\n/** The workbench's canonical tab ids (a host injects extras around these). */\nexport const WORKBENCH_TAB_CHANGES = \"changes\";\nexport const WORKBENCH_TAB_FILES = \"files\";\n\nfunction captureDegradedMessage(reason: string): string {\n switch (reason) {\n case \"repository_discovery_timed_out\":\n return \"Workspace capture is incomplete because repository discovery timed out. Live files remain authoritative.\";\n case \"repository_discovery_result_limit_exceeded\":\n return \"Workspace capture is incomplete because the repository limit was exceeded. Live files remain authoritative.\";\n default:\n return \"Workspace capture is incomplete because repository discovery failed. Live files remain authoritative.\";\n }\n}\n\n/**\n * Decide a workspace tab from an already-local event log: the newest\n * `workspace.revision.captured` announce carries the change surface stats, so\n * \"changes exist → Changes, else Files\" needs zero machine round-trips. A host\n * `override` (e.g. a landing \"run\" tab) wins when supplied.\n *\n * NOTE: the dock no longer uses this for its default tab — `<SandboxWorkspace>`\n * now derives the default from its OWN capture fetch (`useWorkspaceCapture`'s\n * `fileCount`), so a pure embedder needs no events-at-mount contract (Refinement\n * 2). This remains exported as a standalone helper for hosts that already hold\n * the event log and want the same decision without the capture fetch.\n */\nexport function initialWorkspaceTab(\n events: SessionEvent[] | undefined,\n override?: string | null,\n): string {\n if (override) return override;\n let bestSeq = -1;\n let bestFileCount = 0;\n for (const event of events ?? []) {\n if (event.type !== \"workspace.revision.captured\") continue;\n if (event.sequence <= bestSeq) continue;\n const stats = (event.payload as { stats?: { fileCount?: number } } | null)?.stats;\n bestSeq = event.sequence;\n bestFileCount = typeof stats?.fileCount === \"number\" ? stats.fileCount : 0;\n }\n return bestFileCount > 0 ? WORKBENCH_TAB_CHANGES : WORKBENCH_TAB_FILES;\n}\n\n/**\n * Whether a lazy sandbox provision is in flight on this event stream: the latest\n * `sandbox.provision` operation event is a `.started` not yet closed by a\n * `.completed`/`.failed`. Package-local twin of apps/web's events helper so the\n * dock brain can wake its on-demand capability negotiation when the box warms.\n */\nfunction sandboxProvisionInFlight(events: SessionEvent[]): boolean {\n let inFlight = false;\n for (const event of events) {\n if (\n event.type !== \"sandbox.operation.started\" &&\n event.type !== \"sandbox.operation.completed\" &&\n event.type !== \"sandbox.operation.failed\"\n ) {\n continue;\n }\n const payload = event.payload;\n const name =\n payload && typeof payload === \"object\" && !Array.isArray(payload)\n ? (payload as Record<string, unknown>).name\n : null;\n if (name !== \"sandbox.provision\") continue;\n if (event.type === \"sandbox.operation.started\") {\n inFlight = true;\n } else {\n inFlight = false;\n }\n }\n return inFlight;\n}\n\nexport type WorkspaceMachine = {\n /** The derived live/waking/offline chip model (dossier §3 #10). */\n chip: MachineChip;\n /** The machine these surfaces are bound to (the Modal group box or a\n * self-hosted machine), or null while the fleet is still resolving. */\n activeMachine: MachineView | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\nexport type UseSandboxWorkspaceTabsOptions = ClientOverride & {\n sessionId: string;\n /** Live event log (usually `useSessionEvents().events`). */\n events: SessionEvent[];\n /** Override the capture-driven default tab (e.g. a host landing tab id). When\n * omitted the workbench picks Changes-vs-Files from its own capture fetch. */\n initialTab?: string | null | undefined;\n /** Host-routed notifications (mutation errors, desktop-consent failures). The\n * package never imports a toast library — the host decides how to surface. */\n onNotify?: ((notification: WorkspaceNotification) => void) | undefined;\n};\n\nexport type UseSandboxWorkspaceTabsResult = {\n /** Changes | Files | Terminal | Desktop (capability-gated where noted). */\n tabs: WorkspaceTab[];\n /** The capture-driven default tab: Changes when the session has changes, else\n * Files (a host `initialTab` overrides). null during the brief window before the\n * capture GET first resolves (and no host override was given) — consumers render\n * their dock's own first-tab fallback until it latches, which it does ONCE, so it\n * never causes a post-render switch. */\n defaultTab: string | null;\n /** The machine-state model for the dock-header chip. */\n machine: WorkspaceMachine;\n};\n\ntype SessionWarmIntents = {\n sessionId: string;\n watchDesktop: boolean;\n warmTerminal: boolean;\n warmEdit: boolean;\n};\n\nfunction emptyWarmIntents(sessionId: string): SessionWarmIntents {\n return {\n sessionId,\n watchDesktop: false,\n warmTerminal: false,\n warmEdit: false,\n };\n}\n\n/**\n * Build the workbench tabs + the machine-chip model for one session. This is the\n * dock \"brain\": capability negotiation, capture-backed cold reads, prewarm\n * flags, desktop consent, and the xterm theme observer — all package-local.\n */\nexport function useSandboxWorkspaceTabs(\n options: UseSandboxWorkspaceTabsOptions,\n): UseSandboxWorkspaceTabsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const { sessionId, events, onNotify } = options;\n const initialTab = options.initialTab ?? null;\n\n // The three — and only three — box-warming INTENTS, each off by default and each\n // flipped true by a genuine user action (never on mount, never on a passive\n // capture glance): desktop watch consent, terminal engagement (`onActivate`), and\n // the first wake-on-edit keystroke in the Files editor. Browsing capture-served\n // Changes/Files warms nothing — that is the whole point of Refinement 1.\n const [storedWarmIntents, setStoredWarmIntents] = useState<SessionWarmIntents>(() =>\n emptyWarmIntents(sessionId),\n );\n const warmIntents =\n storedWarmIntents.sessionId === sessionId ? storedWarmIntents : emptyWarmIntents(sessionId);\n const { watchDesktop, warmTerminal, warmEdit } = warmIntents;\n const requestWarmIntent = useCallback(\n (intent: Exclude<keyof SessionWarmIntents, \"sessionId\">) => {\n setStoredWarmIntents((previous) => {\n const current = previous.sessionId === sessionId ? previous : emptyWarmIntents(sessionId);\n return current[intent] ? current : { ...current, [intent]: true };\n });\n },\n [sessionId],\n );\n\n // The session's machine fleet + the active-sandbox pointer. Drives the header\n // chip (which machine + its connection state). Polls slowly — ambient context.\n const machines = useMachines({\n workspaceId,\n sessionId,\n pollIntervalMs: 8000,\n });\n const activeMachine: MachineView | null =\n machines.machines.find((m) => m.sandboxId === machines.activeSandboxId) ??\n machines.machines.find((m) => m.active) ??\n null;\n\n const caps = useSessionCapabilities(sessionId, {\n events,\n attachDesktop: watchDesktop,\n attachTerminal: warmTerminal,\n // Edit intent only — NOT \"the Files tab is open\". A cold edit warms the box\n // (that is the wake); a cold glance at the tree/diff does not.\n attachFiles: warmEdit,\n });\n const capabilities = caps.capabilities;\n const liveness = capabilities?.liveness;\n const fileSystemOn = capabilities?.FileSystem.available ?? false;\n // The FS is writable only when it's live AND not read-only. A self-hosted box\n // that's offline (or any read-only advertisement) or a capture-served cold tree\n // must not offer create/rename/delete/edit affordances — you cannot mutate a\n // machine you can't reach (dossier §12-A2/C3). Tree-structure ops need a warm\n // writable box; content editing on a cold CLOUD box is the wake-on-edit path in\n // the editor, not tree mutation.\n const fsReadOnly = capabilities?.FileSystem.readOnly ?? false;\n const filesEditable = fileSystemOn && !fsReadOnly;\n const gitOn = capabilities?.Git.available ?? false;\n const terminalOn = (capabilities?.Terminal.transport ?? null) !== null;\n // The REAL interactive terminal is the ttyd pty-ws stream. When it's live the\n // legacy HTTP PTY must NOT run; `useSandboxTerminal` opens its HTTP PTY only as\n // the firehose-mode fallback (a backend without ttyd).\n const ptyWsLive =\n capabilities?.Terminal.transport === \"pty-ws\" && Boolean(capabilities?.Terminal.url);\n const ptyCapable = (capabilities?.Terminal.ptyCapable ?? false) && !ptyWsLive;\n const terminal = useSandboxTerminal(sessionId, {\n events,\n interactive: ptyCapable,\n liveness,\n });\n const desktopAdvertised =\n (capabilities?.DesktopStream.transport ?? null) !== null ||\n capabilities?.DesktopStream.reason === \"lease_cold\";\n\n // Lazy provisioning (#315) creates the box mid-turn on the first sandbox tool\n // call, emitting sandbox.provision started→completed/failed on the live stream.\n // The on-demand resting hook rests without polling, so when the box warms the\n // cold capability doc never refreshes on its own — Terminal/Desktop would stay\n // hidden. Watch the provision edge and renegotiate when it settles so the\n // freshly-warm box's surfaces fill in.\n const provisioning = sandboxProvisionInFlight(events);\n const renegotiate = caps.renegotiate;\n const provisioningRef = useRef({ sessionId, provisioning });\n useEffect(() => {\n const previous = provisioningRef.current;\n if (previous.sessionId === sessionId && previous.provisioning && !provisioning) {\n renegotiate();\n }\n provisioningRef.current = { sessionId, provisioning };\n }, [sessionId, provisioning, renegotiate]);\n\n // The cold-paint data source: the latest turn-end capture, fetched with a single\n // api round-trip on mount (no machine). Feeds the Files tree + the Changes/Git\n // diff when the box is not warm; a warm box always wins (live path unchanged).\n const captureState = useWorkspaceCapture(sessionId, { events });\n const captureAvailable = captureState.available;\n const notifiedCaptureDegradedReason = useRef<{\n sessionId: string;\n reason: string | null;\n }>({\n sessionId,\n reason: null,\n });\n if (notifiedCaptureDegradedReason.current.sessionId !== sessionId) {\n notifiedCaptureDegradedReason.current = { sessionId, reason: null };\n }\n useEffect(() => {\n const reason = captureState.degradedReason;\n if (!reason || notifiedCaptureDegradedReason.current.reason === reason) return;\n notifiedCaptureDegradedReason.current = { sessionId, reason };\n onNotify?.({ kind: \"error\", message: captureDegradedMessage(reason) });\n }, [sessionId, captureState.degradedReason, onNotify]);\n\n const files = useSandboxFiles(sessionId, {\n events,\n enabled: fileSystemOn || captureAvailable,\n liveness,\n capture: captureState.capture,\n // A reverted optimistic mutation (e.g. a 409 rename collision) surfaces as a\n // host notification — the tree silently rolls back, the user sees why.\n onMutationError: (error, op) =>\n onNotify?.({\n kind: \"error\",\n message: `Could not ${op}: ${error.message}`,\n }),\n });\n const git = useSandboxGit(sessionId, {\n events,\n enabled: gitOn || captureAvailable,\n liveness,\n capture: captureState.capture,\n });\n const stagedGit = useSandboxGit(sessionId, {\n events,\n enabled: gitOn,\n staged: true,\n liveness,\n capture: captureState.capture,\n });\n\n // Token-derived xterm theme; re-derive on a `data-og-theme` flip. Generic — it\n // belongs in the package (an embedder's theme toggle drives it too).\n const [xtermTheme, setXtermTheme] = useState<XtermTheme | undefined>(undefined);\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const derive = () => setXtermTheme(xtermThemeFromTokens());\n derive();\n const observer = new MutationObserver(derive);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"data-og-theme\", \"class\"],\n });\n return () => observer.disconnect();\n }, []);\n\n async function acknowledgeAndWatch() {\n try {\n const shared = capabilities?.DesktopStream.shared ?? false;\n await client.acknowledgeStream(workspaceId, sessionId, {\n acknowledgeUnredacted: true,\n acknowledgeShared: shared,\n });\n requestWarmIntent(\"watchDesktop\");\n caps.renegotiate();\n } catch (error) {\n onNotify?.({\n kind: \"error\",\n message: `Could not start the desktop stream: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n }\n\n // Re-warm WITHOUT re-acknowledging: the consent was already recorded, only the\n // box drained back to cold. Idempotent — the viewer auto-warm de-dupes.\n function rewarmDesktop() {\n if (!watchDesktop) requestWarmIntent(\"watchDesktop\");\n caps.renegotiate();\n }\n\n const dirtyCount = git.diff.length;\n\n // The one truthful machine indicator, derived from the live capability/liveness\n // surface + the active machine's connection state + the latest capture time.\n const chip = useMachineChip({\n liveness,\n capabilitiesState: caps.state,\n activeMachineState: activeMachine?.state ?? null,\n activeIsSelfhosted: activeMachine?.kind === \"selfhosted\",\n wantsWarm: warmTerminal || watchDesktop || warmEdit,\n capturedAt: captureState.capturedAt,\n });\n\n // The pre-paint default tab, decided from the workbench's OWN capture fetch — no\n // embedder events-at-mount contract (Refinement 2). A host `initialTab` wins\n // immediately; otherwise the default stays null until the capture GET first\n // resolves, then latches Changes (changes exist) or Files, ONCE — live data can\n // never switch it afterward. Committing at first-resolve — before the tab body's\n // first CONTENT paint (both bodies show a connecting/loading state until the\n // capture lands) — means the first real content is the correct tab, no switch. A\n // pure embedder that never preloads events now gets the right default for free.\n const defaultTabRef = useRef<{ sessionId: string; value: string | null }>({\n sessionId,\n value: null,\n });\n if (defaultTabRef.current.sessionId !== sessionId) {\n defaultTabRef.current = { sessionId, value: null };\n }\n if (defaultTabRef.current.value === null) {\n if (initialTab) {\n defaultTabRef.current.value = initialTab;\n } else if (captureState.fileCount !== null) {\n defaultTabRef.current.value =\n captureState.fileCount > 0 ? WORKBENCH_TAB_CHANGES : WORKBENCH_TAB_FILES;\n }\n }\n // null only during the brief pre-first-resolve window (no host override yet).\n const defaultTab = defaultTabRef.current.value;\n\n const tabs = useMemo(() => {\n const list: WorkspaceTab[] = [];\n\n // Changes — always present (capture-backed, works cold/offline). The default\n // primary surface. M5 replaces this body with the windowed diff renderer; the\n // seam is the `<ChangesTabBody>` element (this is the minimal placeholder).\n list.push({\n id: WORKBENCH_TAB_CHANGES,\n label: \"Changes\",\n badge: dirtyCount > 0 ? <DirtyBadge count={dirtyCount} /> : undefined,\n content: (\n <ChangesTabBody\n git={git}\n captureAvailable={captureAvailable}\n captureRevision={captureState.revision}\n capabilitiesState={caps.state}\n capabilitiesError={caps.error}\n onRetry={caps.renegotiate}\n />\n ),\n });\n\n // Files — always present (capture-backed cold tree; live warm). M5 virtualizes.\n list.push({\n id: WORKBENCH_TAB_FILES,\n label: \"Files\",\n content: (\n <SandboxFiles\n files={files}\n git={git}\n stagedGit={stagedGit}\n fileSystemAvailable={fileSystemOn || captureAvailable}\n editable={filesEditable}\n // The first keystroke in the editor is the wake-on-edit INTENT: warm the\n // box (even cold) so the write lands fast. Opening/reading files does not.\n onEditIntent={() => requestWarmIntent(\"warmEdit\")}\n className=\"h-full\"\n />\n ),\n });\n\n // Terminal — capability-gated (appears after negotiation; never the default).\n if (terminalOn) {\n list.push({\n id: \"terminal\",\n label: \"Terminal\",\n content: (\n <div className=\"h-full bg-og-bg p-1\">\n <SandboxTerminal\n result={terminal}\n terminalCapability={capabilities?.Terminal ?? null}\n onActivate={() => requestWarmIntent(\"warmTerminal\")}\n showHeader\n shell={capabilities?.Terminal.shell ?? undefined}\n liveness={liveness}\n {...(xtermTheme ? { theme: xtermTheme } : {})}\n />\n </div>\n ),\n });\n }\n\n // Desktop — capability-gated + consent-gated.\n if (desktopAdvertised) {\n list.push({\n id: \"desktop\",\n label: \"Desktop\",\n badge: watchDesktop ? (\n <span className=\"rounded-og-xs bg-og-status-running/20 px-1 text-2xs text-og-status-running\">\n Live\n </span>\n ) : undefined,\n content: (\n <DesktopViewer\n capability={capabilities?.DesktopStream ?? null}\n viewerCapReached={caps.viewerCapReached}\n watching={watchDesktop}\n onAcknowledge={() => void acknowledgeAndWatch()}\n onWarm={rewarmDesktop}\n className=\"h-full\"\n />\n ),\n });\n }\n\n return list;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n fileSystemOn,\n terminalOn,\n desktopAdvertised,\n captureAvailable,\n dirtyCount,\n watchDesktop,\n warmTerminal,\n files,\n git,\n stagedGit,\n terminal,\n xtermTheme,\n capabilities,\n caps.state,\n caps.error,\n caps.viewerCapReached,\n requestWarmIntent,\n ]);\n\n return {\n tabs,\n defaultTab,\n machine: {\n chip,\n activeMachine,\n loading: machines.loading,\n error: machines.error,\n refresh: machines.refresh,\n },\n };\n}\n\nexport type SandboxWorkspaceProps = ClientOverride & {\n sessionId: string;\n /** Live event log (usually `useSessionEvents().events`). */\n events: SessionEvent[];\n /** The chat / primary pane shown beside the dock. */\n primary: ReactNode;\n /** Host tabs injected BEFORE the workbench tabs (e.g. a \"Run\" landing tab). */\n leadingTabs?: WorkspaceTab[] | undefined;\n /** Host tabs injected AFTER the workbench tabs (e.g. a \"Debug\" tab). */\n trailingTabs?: WorkspaceTab[] | undefined;\n /** Override the pre-paint default tab (e.g. a host landing tab id). When\n * omitted the workbench decides Changes-vs-Files from local capture stats. */\n initialTab?: string | undefined;\n /** Host-routed notifications (no toast dependency in the package). */\n onNotify?: ((notification: WorkspaceNotification) => void) | undefined;\n /** Controlled collapsed state for hosts with their own dock toggle. */\n collapsed?: boolean | undefined;\n onCollapsedChange?: ((collapsed: boolean) => void) | undefined;\n /** Host navigation shown only in the phone workspace overlay header. */\n mobileLeadingControl?: ReactNode | undefined;\n autoSaveId?: string | undefined;\n defaultSize?: number | undefined;\n minSize?: number | undefined;\n maxSize?: number | undefined;\n className?: string | undefined;\n};\n\n/**\n * The whole session workspace, ready to mount: `<SandboxWorkspace>` assembles the\n * capability-gated tabs, pins the machine-state chip in the dock header, and\n * renders the resizable `<WorkspaceDock>`. Wrap the tree in `<OpenGeniProvider>`\n * (client + workspaceId) and import `@opengeni/react/styles.css`; that is the\n * entire integration (see `docs/embedding-workbench.md`).\n */\nexport function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {\n const {\n sessionId,\n events,\n primary,\n leadingTabs,\n trailingTabs,\n initialTab,\n onNotify,\n collapsed,\n onCollapsedChange,\n mobileLeadingControl,\n autoSaveId,\n defaultSize,\n minSize,\n maxSize,\n className,\n } = props;\n\n const {\n tabs: workbenchTabs,\n machine,\n defaultTab,\n } = useSandboxWorkspaceTabs({\n ...(props.client ? { client: props.client } : {}),\n ...(props.workspaceId ? { workspaceId: props.workspaceId } : {}),\n sessionId,\n events,\n ...(initialTab ? { initialTab } : {}),\n ...(onNotify ? { onNotify } : {}),\n });\n\n // A user's tab click wins forever; before that we follow the capture-driven\n // default. While it is still resolving (null, pure-embedder pre-first-resolve)\n // we pass no controlled tab, so the dock renders its own first-tab fallback\n // (Changes) — whose body is a connecting/loading state until the capture lands,\n // so committing the real default at first-resolve produces no CONTENT switch.\n const tabs: WorkspaceTab[] = [...(leadingTabs ?? []), ...workbenchTabs, ...(trailingTabs ?? [])];\n const [storedSelection, setStoredSelection] = useState<{\n sessionId: string;\n tab: string;\n } | null>(null);\n const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;\n const activeTab = selectedTab ?? defaultTab ?? tabs[0]?.id;\n const selectTab = useCallback(\n (tab: string) => setStoredSelection({ sessionId, tab }),\n [sessionId],\n );\n\n return (\n <WorkspaceDock\n primary={primary}\n tabs={tabs}\n {...(activeTab !== undefined ? { activeTab } : {})}\n onActiveTabChange={selectTab}\n headerAccessory={\n <MachineStateChip\n chip={machine.chip}\n activeMachine={machine.activeMachine}\n error={machine.error}\n onRetry={() => void machine.refresh()}\n />\n }\n {...(mobileLeadingControl !== undefined ? { mobileLeadingControl } : {})}\n {...(collapsed !== undefined ? { collapsed } : {})}\n {...(onCollapsedChange ? { onCollapsedChange } : {})}\n {...(autoSaveId !== undefined ? { autoSaveId } : {})}\n {...(defaultSize !== undefined ? { defaultSize } : {})}\n {...(minSize !== undefined ? { minSize } : {})}\n {...(maxSize !== undefined ? { maxSize } : {})}\n {...(className !== undefined ? { className } : {})}\n />\n );\n}\n\n// Re-export the dock so an embedder can grab the shell type off one import.\nexport type { WorkspaceDockProps };\n\nfunction DirtyBadge({ count }: { count: number }) {\n return (\n <span className=\"rounded-og-xs bg-og-accent-soft px-1 text-2xs text-og-fg-muted\">{count}</span>\n );\n}\n\n/** A machine-kind glyph for the chip popover. */\nfunction MachineKindIcon({\n kind,\n className,\n}: {\n kind: MachineView[\"kind\"] | undefined;\n className?: string;\n}) {\n const Icon = kind === \"selfhosted\" ? LaptopIcon : CpuIcon;\n return <Icon className={cn(\"size-3.5 shrink-0 text-og-fg-subtle\", className)} aria-hidden />;\n}\n\nfunction chipDotClass(state: MachineChip[\"state\"]): string {\n if (state === \"live\") return \"bg-og-status-running\";\n if (state === \"waking\") return \"bg-og-status-idle animate-pulse\";\n return \"bg-og-fg-subtle\";\n}\n\n/**\n * The dock-header machine chip: the one truthful live/waking/offline indicator,\n * with a popover carrying the machine identity, connection state, the \"shown as\n * of <time>\" staleness note, the shared-session disclosure, and a retry when the\n * fleet failed to resolve (the old per-surface machine bar + Sandbox info tab,\n * folded into one header affordance — dossier §10.6 recommendation).\n */\nfunction MachineStateChip({\n chip,\n activeMachine,\n error,\n onRetry,\n}: {\n chip: MachineChip;\n activeMachine: MachineView | null;\n error: Error | null;\n onRetry: () => void;\n}) {\n return (\n <Popover.Root>\n <Popover.Trigger asChild>\n <button\n type=\"button\"\n aria-label={`Machine: ${chip.label}`}\n className=\"inline-flex min-h-7 items-center gap-1.5 rounded-og-sm px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:bg-og-surface-2 hover:text-og-fg max-[1023px]:min-h-11 pointer-coarse:min-h-11\"\n >\n <span\n className={cn(\"size-1.5 shrink-0 rounded-full\", chipDotClass(chip.state))}\n aria-hidden\n />\n <span className=\"max-w-[11rem] truncate\">{chip.label}</span>\n </button>\n </Popover.Trigger>\n <Popover.Portal forceMount>\n <Popover.Content\n forceMount\n align=\"end\"\n sideOffset={6}\n className=\"z-50 w-64 rounded-og-md border border-og-border bg-og-surface-1 p-3 text-og-sm text-og-fg shadow-lg outline-none data-[state=closed]:hidden\"\n >\n <div className=\"flex min-w-0 items-center gap-1.5\">\n <MachineKindIcon kind={activeMachine?.kind} />\n <span className=\"min-w-0 truncate font-medium\">{activeMachine?.name ?? \"Sandbox\"}</span>\n </div>\n <div className=\"mt-2.5 flex items-center justify-between gap-2\">\n <span className=\"text-og-xs text-og-fg-subtle\">Connection</span>\n {activeMachine ? (\n <ConnectionStatusPill\n status={connectionStatusForState(activeMachine.state)}\n size=\"sm\"\n />\n ) : (\n <span className=\"text-og-xs text-og-fg-muted\">{chip.label}</span>\n )}\n </div>\n {chip.asOf ? (\n <p className=\"mt-2.5 text-og-xs leading-4 text-og-fg-subtle\">\n Workspace shown as of {formatAsOf(chip.asOf, Date.now())} — the machine is not live.\n </p>\n ) : null}\n {activeMachine && activeMachine.sharedSessionCount > 1 ? (\n <div className=\"mt-2.5\">\n <SharedMachineDisclosure\n sharedSessionCount={activeMachine.sharedSessionCount}\n density=\"full\"\n />\n </div>\n ) : null}\n {error ? (\n <div className=\"mt-2.5 space-y-1.5 border-t border-og-border pt-2.5\">\n <p className=\"text-og-xs leading-4 text-og-status-danger\">\n Couldn't reach the sandbox for this session.\n </p>\n <DockActionButton onClick={onRetry}>\n <RefreshCwIcon className=\"size-3\" />\n Retry\n </DockActionButton>\n </div>\n ) : null}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\n/** A minimal token-styled action button (the package has no app Button import). */\nfunction DockActionButton({ onClick, children }: { onClick: () => void; children: ReactNode }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg pointer-coarse:min-h-9\"\n >\n {children}\n </button>\n );\n}\n\n/**\n * The Changes tab body: the real PR-review surface (`WorkbenchChanges` — file\n * rail + windowed Pierre diff pane) when there are changes, wrapped in the honest\n * connecting/offline/empty states so the default tab is never a blank surface.\n * The dock frame is untouched; this is the M5 seam.\n */\nfunction ChangesTabBody({\n git,\n captureAvailable,\n captureRevision,\n capabilitiesState,\n capabilitiesError,\n onRetry,\n}: {\n git: UseSandboxGitResult;\n captureAvailable: boolean;\n captureRevision: number | null;\n capabilitiesState: string;\n capabilitiesError: Error | null;\n onRetry: () => void;\n}) {\n const diff = git.diff;\n\n if (diff.length > 0) {\n return (\n <WorkbenchChanges\n diff={diff}\n source={git.source}\n capturedAt={git.capturedAt}\n captureRevision={captureRevision}\n />\n );\n }\n\n if (capabilitiesError && !captureAvailable) {\n return (\n <CenteredState>\n <p className=\"text-og-sm font-medium text-og-fg\">Sandbox unavailable</p>\n <p className=\"text-og-sm leading-5 text-og-fg-muted\">\n {capabilitiesError.message || \"Couldn't reach the sandbox for this session.\"}\n </p>\n <DockActionButton onClick={onRetry}>\n <RefreshCwIcon className=\"size-3\" />\n Retry\n </DockActionButton>\n </CenteredState>\n );\n }\n\n if ((capabilitiesState === \"negotiating\" || capabilitiesState === \"cold\") && !captureAvailable) {\n return (\n <CenteredState>\n <p className=\"text-og-sm text-og-fg-muted\">Connecting sandbox…</p>\n </CenteredState>\n );\n }\n\n return (\n <CenteredState>\n <p className=\"text-og-sm font-medium text-og-fg\">No changes yet</p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">\n File edits from this session's turns show up here.\n </p>\n </CenteredState>\n );\n}\n\nfunction CenteredState({ children }: { children: ReactNode }) {\n return (\n <div className=\"grid h-full place-items-center p-6 text-center\">\n <div className=\"flex max-w-sm flex-col items-center gap-2.5\">{children}</div>\n </div>\n );\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { FileWarningIcon, HistoryIcon } from \"lucide-react\";\nimport {\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { VList } from \"virtua\";\nimport { cn } from \"../lib/cn\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport { formatAsOf } from \"../hooks/use-machine-chip\";\nimport { useWindowedSections } from \"../hooks/use-windowed-sections\";\nimport { PierreDiff } from \"./pierre-diff\";\n\n/* ----------------------------------------------------------------------------\n Changes tab — a PR-review surface.\n\n A file rail (status glyph, ±counts, grouped by top-level dir when the change\n set is large) on the left; a stacked, WINDOWED diff pane on the right. Only\n the file sections inside the visible window ± overscan mount a Pierre/Shiki\n highlighter (the one renderer), so a 40- or 400-file change set never mounts N\n highlighters at once (dossier §10.7, D2). A per-file >guard (binary / diff too\n large) degrades to an \"open live\" affordance instead of a diff body.\n\n `git.diff` is a single flat scope, so \"group by repo then directory\" here means\n \"group by top-level directory\" — which is exactly the repo dir in a multi-repo\n workspace and the top folder otherwise. Grouping only kicks in past the\n threshold; a small change set stays a flat list.\n -------------------------------------------------------------------------- */\n\n/** Group the rail (and reorder the pane) once the change set is larger than this. */\nconst GROUP_THRESHOLD = 20;\n/** Mount this many sections beyond the visible window on each side. */\nconst OVERSCAN = 2;\nconst HEADER_PX = 30;\nconst LINE_PX = 18;\nconst GUARD_BODY_PX = 52;\nconst COMPACT_SURFACE_PX = 560;\nconst useChangesLayoutEffect = typeof window === \"undefined\" ? useEffect : useLayoutEffect;\n\nconst STATUS_TINT: Record<GitFileDiff[\"status\"], string> = {\n added: \"text-og-status-idle\",\n modified: \"text-og-status-running\",\n deleted: \"text-og-status-failed\",\n renamed: \"text-og-accent\",\n copied: \"text-og-accent\",\n untracked: \"text-og-fg-subtle\",\n ignored: \"text-og-fg-subtle\",\n conflicted: \"text-og-status-failed\",\n typechange: \"text-og-status-running\",\n};\n\nconst STATUS_LETTER: Record<GitFileDiff[\"status\"], string> = {\n added: \"A\",\n modified: \"M\",\n deleted: \"D\",\n renamed: \"R\",\n copied: \"C\",\n untracked: \"U\",\n ignored: \"I\",\n conflicted: \"!\",\n typechange: \"T\",\n};\n\nexport type WorkbenchChangesProps = {\n /** The changed files (`useSandboxGit().diff`). Assumed non-empty by the caller. */\n diff: GitFileDiff[];\n /** Which source the diff came from — drives the \"live\" vs \"as of turn\" badge. */\n source: \"live\" | \"capture\" | null;\n /** When the served capture was taken (ISO), when `source === \"capture\"`. */\n capturedAt: string | null;\n /** The capture's turn revision, for the \"as of turn N\" badge. */\n captureRevision?: number | null | undefined;\n themeType?: \"dark\" | \"light\" | undefined;\n className?: string | undefined;\n};\n\ntype RailRow =\n | { kind: \"group\"; label: string; count: number }\n | { kind: \"file\"; file: GitFileDiff; index: number };\n\n/** Order the files and build the rail rows (grouped past the threshold). The\n * returned `orderedFiles` drives BOTH the rail and the diff pane so a rail row's\n * `index` addresses the matching pane section. Exported for tests. */\nexport function buildRail(files: GitFileDiff[]): { orderedFiles: GitFileDiff[]; rows: RailRow[] } {\n if (files.length <= GROUP_THRESHOLD) {\n return {\n orderedFiles: files,\n rows: files.map((file, index) => ({ kind: \"file\", file, index })),\n };\n }\n const groups = new Map<string, GitFileDiff[]>();\n for (const file of files) {\n const slash = file.path.indexOf(\"/\");\n const key = slash > 0 ? file.path.slice(0, slash) : \"(root)\";\n const bucket = groups.get(key);\n if (bucket) bucket.push(file);\n else groups.set(key, [file]);\n }\n const labels = [...groups.keys()].sort((a, b) => a.localeCompare(b));\n const orderedFiles: GitFileDiff[] = [];\n const rows: RailRow[] = [];\n for (const label of labels) {\n const bucket = (groups.get(label) ?? []).slice().sort((a, b) => a.path.localeCompare(b.path));\n rows.push({ kind: \"group\", label, count: bucket.length });\n for (const file of bucket) {\n rows.push({ kind: \"file\", file, index: orderedFiles.length });\n orderedFiles.push(file);\n }\n }\n return { orderedFiles, rows };\n}\n\n/** A file's diff body is \"too large to inline\" when it's binary or the diff guard\n * tripped (the backend omits hunks past its size cap) — open it live instead. */\nfunction isGuarded(file: GitFileDiff): boolean {\n return file.isBinary || file.truncated;\n}\n\n/** Estimate a section's rendered height for the windowing math. Line-count based,\n * so it is close enough that the first paint barely shifts as real heights land. */\nfunction estimateSectionHeight(file: GitFileDiff): number {\n if (isGuarded(file)) return HEADER_PX + GUARD_BODY_PX;\n let lines = 0;\n for (const hunk of file.hunks) lines += hunk.lines.length + 1;\n return HEADER_PX + Math.max(lines, 1) * LINE_PX + 8;\n}\n\nexport function WorkbenchChanges({\n diff,\n source,\n capturedAt,\n captureRevision,\n themeType,\n className,\n}: WorkbenchChangesProps) {\n const rootRef = useRef<HTMLDivElement | null>(null);\n const [compact, setCompact] = useState(false);\n const [coarsePointer, setCoarsePointer] = useState(false);\n const resolvedTheme = useThemeType(themeType);\n const [layout, setLayout] = useState<\"unified\" | \"split\">(\"unified\");\n const [activePath, setActivePath] = useState<string | null>(null);\n const pickerId = useId();\n\n const { orderedFiles, rows } = useMemo(() => buildRail(diff), [diff]);\n const grouped = diff.length > GROUP_THRESHOLD;\n const selectedIndex = orderedFiles.findIndex((file) => file.path === activePath);\n const activeIndex = selectedIndex >= 0 ? selectedIndex : 0;\n\n useChangesLayoutEffect(() => {\n const root = rootRef.current;\n if (!root || typeof ResizeObserver === \"undefined\") return;\n const update = (width: number) => {\n // DOM test environments report a zero geometry. Keep the deterministic\n // desktop/SSR branch until the observer has a real measurement.\n if (width > 0) setCompact(width < COMPACT_SURFACE_PX);\n };\n update(root.getBoundingClientRect().width);\n const observer = new ResizeObserver((entries) => {\n update(entries[0]?.contentRect.width ?? root.getBoundingClientRect().width);\n });\n observer.observe(root);\n return () => observer.disconnect();\n }, []);\n\n useChangesLayoutEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return;\n const query = window.matchMedia(\"(pointer: coarse)\");\n const update = () => setCoarsePointer(query.matches);\n update();\n if (typeof query.addEventListener === \"function\") {\n query.addEventListener(\"change\", update);\n return () => query.removeEventListener(\"change\", update);\n }\n if (typeof query.addListener === \"function\") {\n query.addListener(update);\n return () => query.removeListener(update);\n }\n }, []);\n\n const additions = useMemo(() => diff.reduce((sum, f) => sum + f.additions, 0), [diff]);\n const deletions = useMemo(() => diff.reduce((sum, f) => sum + f.deletions, 0), [diff]);\n\n const estimateHeight = useCallback(\n (index: number) => {\n const file = orderedFiles[index];\n return file ? estimateSectionHeight(file) : HEADER_PX + LINE_PX;\n },\n [orderedFiles],\n );\n\n const windowed = useWindowedSections({\n count: orderedFiles.length,\n estimateHeight,\n overscan: OVERSCAN,\n });\n\n const jumpTo = useCallback(\n (index: number) => {\n setActivePath(orderedFiles[index]?.path ?? null);\n windowed.scrollToIndex(index);\n },\n [orderedFiles, windowed],\n );\n\n // Track which section is at the top of the pane so the rail highlights it.\n const onPaneScroll = useCallback(() => {\n const el = windowed.scrollRef.current;\n if (!el) return;\n const top = el.scrollTop;\n const offsets = windowed.offsets;\n let idx = 0;\n for (let i = 0; i < orderedFiles.length; i++) {\n if ((offsets[i] ?? 0) <= top + 4) idx = i;\n else break;\n }\n const nextPath = orderedFiles[idx]?.path ?? null;\n setActivePath((previous) => (previous === nextPath ? previous : nextPath));\n }, [windowed, orderedFiles]);\n\n useEffect(() => {\n const el = windowed.scrollRef.current;\n if (!el) return;\n el.addEventListener(\"scroll\", onPaneScroll, { passive: true });\n return () => el.removeEventListener(\"scroll\", onPaneScroll);\n }, [windowed.scrollRef, onPaneScroll]);\n\n const sourceBadge = describeSource(source, capturedAt, captureRevision ?? null);\n const activeFile = orderedFiles[activeIndex] ?? orderedFiles[0];\n\n return (\n <div\n ref={rootRef}\n className={cn(\"flex h-full min-h-0 min-w-0 flex-col\", className)}\n data-workbench-changes-layout={compact ? \"compact\" : \"rail\"}\n >\n {/* Summary + source badge + layout toggle. */}\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-og-border px-3 py-1.5\">\n <span className=\"min-w-0 truncate text-og-xs text-og-fg-muted\">\n {diff.length} {diff.length === 1 ? \"file\" : \"files\"} changed\n <span className=\"ml-2 text-og-status-idle\">+{additions}</span>\n <span className=\"ml-1 text-og-status-failed\">−{deletions}</span>\n </span>\n <div className=\"flex shrink-0 items-center gap-2\">\n {compact ? null : <LayoutToggle layout={layout} onChange={setLayout} />}\n <SourceBadge source={source} capturedAt={capturedAt} label={sourceBadge} />\n </div>\n </div>\n\n {compact ? (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"shrink-0 border-b border-og-border bg-og-surface-1 p-2\">\n <label className=\"sr-only\" htmlFor={pickerId}>\n Changed file\n </label>\n <select\n id={pickerId}\n aria-label=\"Changed file\"\n value={activeIndex}\n onChange={(event) => {\n const index = Number(event.currentTarget.value);\n setActivePath(orderedFiles[index]?.path ?? null);\n }}\n data-compact-file-picker\n className=\"h-11 w-full rounded-og-md border border-og-border bg-og-bg px-3 font-og-mono text-og-sm text-og-fg outline-none transition-colors focus:border-og-accent focus:ring-2 focus:ring-og-accent-soft\"\n >\n {orderedFiles.map((file, index) => (\n <option key={file.path} value={index}>\n {STATUS_LETTER[file.status]} · {file.path} · +{file.additions} −{file.deletions}\n </option>\n ))}\n </select>\n </div>\n <div className=\"min-h-0 min-w-0 flex-1 overflow-auto\" data-opengeni-changes-pane>\n {activeFile ? (\n <DiffSection file={activeFile} layout=\"unified\" themeType={resolvedTheme} />\n ) : null}\n </div>\n </div>\n ) : (\n <div className=\"flex min-h-0 flex-1\">\n {/* File rail — virtualized (virtua): a dense change set is fine. */}\n <div className=\"w-[240px] shrink-0 border-r border-og-border\">\n <VList\n className=\"h-full\"\n itemSize={coarsePointer ? 44 : 28}\n ssrCount={Math.min(30, rows.length)}\n >\n {rows.map((row) =>\n row.kind === \"group\" ? (\n <div\n key={`g:${row.label}`}\n data-rail-group\n className=\"flex items-center gap-1.5 px-2 pb-0.5 pt-2 text-2xs font-medium uppercase tracking-wide text-og-fg-subtle\"\n >\n <span className=\"min-w-0 truncate\">{row.label}</span>\n <span className=\"shrink-0\">{row.count}</span>\n </div>\n ) : (\n <RailFileRow\n key={row.file.path}\n file={row.file}\n grouped={grouped}\n active={row.index === activeIndex}\n onClick={() => jumpTo(row.index)}\n />\n ),\n )}\n </VList>\n </div>\n\n {/* Diff pane — windowed file sections. Only the sections inside the\n visible window ± overscan are in the DOM; the container reserves the\n full scroll height so scrolling + the rail-jump stay accurate. */}\n <div\n ref={windowed.scrollRef}\n className=\"min-h-0 min-w-0 flex-1 overflow-auto\"\n data-opengeni-changes-pane\n >\n <div style={{ position: \"relative\", height: windowed.totalHeight }}>\n {orderedFiles.map((file, index) => {\n if (index < windowed.range.start || index >= windowed.range.end) return null;\n return (\n <MeasuredSection\n key={file.path}\n index={index}\n top={windowed.offsets[index] ?? 0}\n onMeasure={windowed.measure}\n >\n <DiffSection file={file} layout={layout} themeType={resolvedTheme} />\n </MeasuredSection>\n );\n })}\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n/**\n * The data-source badge. \"live\" stays understated (the header chip already\n * carries machine liveness) — but a capture-served diff is honestly labelled\n * historical: a muted clock + the \"as of turn N · <time>\" so the reviewer always\n * knows they are looking at a turn-end snapshot, not the live tree.\n */\nfunction SourceBadge({\n source,\n capturedAt,\n label,\n}: {\n source: \"live\" | \"capture\" | null;\n capturedAt: string | null;\n label: string;\n}) {\n if (source === \"capture\" && capturedAt) {\n return (\n <span\n className=\"inline-flex items-center gap-1 rounded-og-xs border border-og-border px-1.5 py-px text-2xs text-og-fg-muted\"\n title={new Date(capturedAt).toLocaleString()}\n >\n <HistoryIcon className=\"size-3 shrink-0 text-og-status-running\" aria-hidden />\n {label}\n </span>\n );\n }\n return (\n <span className=\"rounded-og-xs bg-og-surface-2 px-1.5 py-px text-2xs text-og-fg-subtle\">\n {label}\n </span>\n );\n}\n\n/** \"live\" · \"as of turn 7 · 14:32\" · \"as of 14:32\" (no revision). */\nfunction describeSource(\n source: \"live\" | \"capture\" | null,\n capturedAt: string | null,\n revision: number | null,\n): string {\n if (source !== \"capture\" || !capturedAt) return \"live\";\n const time = formatAsOf(capturedAt, Date.now());\n return revision !== null ? `as of turn ${revision} · ${time}` : `as of ${time}`;\n}\n\nfunction RailFileRow({\n file,\n grouped,\n active,\n onClick,\n}: {\n file: GitFileDiff;\n grouped: boolean;\n active: boolean;\n onClick: () => void;\n}) {\n // In a grouped rail the top-level dir is the group header, so show the path\n // beneath it; otherwise show the whole path.\n const shown = grouped ? file.path.slice(file.path.indexOf(\"/\") + 1) || file.path : file.path;\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={file.path}\n data-rail-file\n className={cn(\n \"flex min-h-7 w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-og-sm hover:bg-og-surface-2 pointer-coarse:min-h-11\",\n grouped && \"pl-3\",\n active && \"bg-og-surface-2\",\n )}\n >\n <span\n className={cn(\"w-3 shrink-0 text-center font-og-mono text-og-xs\", STATUS_TINT[file.status])}\n >\n {STATUS_LETTER[file.status]}\n </span>\n <span className=\"min-w-0 flex-1 truncate\">{shown}</span>\n <span className=\"ml-auto flex shrink-0 items-center gap-1 pl-1 font-og-mono text-2xs\">\n <span className=\"text-og-status-idle\">+{file.additions}</span>\n <span className=\"text-og-status-failed\">−{file.deletions}</span>\n </span>\n </button>\n );\n}\n\n/** A windowed section wrapper. Absolutely positioned at `top`; a ResizeObserver\n * reports its real height back so the layout refines as Pierre's async Shiki\n * render grows (else short estimates would overlap sections). */\nfunction MeasuredSection({\n index,\n top,\n onMeasure,\n children,\n}: {\n index: number;\n top: number;\n onMeasure: (index: number, height: number) => void;\n children: ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const report = () => onMeasure(index, el.offsetHeight);\n report();\n const ro = typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(report) : null;\n ro?.observe(el);\n return () => ro?.disconnect();\n }, [index, onMeasure]);\n return (\n <div\n ref={ref}\n data-diff-section\n data-diff-index={index}\n style={{ position: \"absolute\", top, left: 0, right: 0 }}\n >\n {children}\n </div>\n );\n}\n\nfunction DiffSection({\n file,\n layout,\n themeType,\n}: {\n file: GitFileDiff;\n layout: \"unified\" | \"split\";\n themeType: \"dark\" | \"light\";\n}) {\n // The guard files (binary / over-cap) get a minimal header + \"open live\" body\n // since Pierre has nothing to render; real diffs use Pierre's own sticky file\n // header (one header — no redundant chrome).\n if (isGuarded(file)) {\n const renamed = file.oldPath && file.oldPath !== file.path;\n return (\n <section className=\"border-b border-og-border pb-1\">\n <header className=\"flex items-center justify-between gap-2 bg-og-surface-1 px-3 py-1.5 text-og-sm\">\n <span className=\"min-w-0 truncate font-og-mono text-og-xs\">\n {renamed ? `${file.oldPath} → ${file.path}` : file.path}\n </span>\n <span className=\"flex shrink-0 items-center gap-2 font-og-mono text-2xs\">\n <span className=\"text-og-status-idle\">+{file.additions}</span>\n <span className=\"text-og-status-failed\">−{file.deletions}</span>\n </span>\n </header>\n <GuardBody file={file} />\n </section>\n );\n }\n return (\n <section className=\"border-b border-og-border pb-2\">\n <PierreDiff diff={[file]} layout={layout} themeType={themeType} className=\"px-1\" />\n </section>\n );\n}\n\n/** The per-file guard: a binary file or an over-cap diff opens live rather than\n * inlining a body we don't (fully) have. */\nfunction GuardBody({ file }: { file: GitFileDiff }) {\n const reason = file.isBinary ? \"Binary file\" : \"Diff too large to show here\";\n return (\n <div className=\"flex items-center gap-2 px-3 py-3 text-og-sm text-og-fg-subtle\">\n <FileWarningIcon className=\"size-3.5 shrink-0\" />\n <span className=\"min-w-0\">{reason} — open it on the machine to view.</span>\n </div>\n );\n}\n\nfunction LayoutToggle({\n layout,\n onChange,\n}: {\n layout: \"unified\" | \"split\";\n onChange: (next: \"unified\" | \"split\") => void;\n}) {\n return (\n <div className=\"inline-flex items-center rounded-og-sm border border-og-border p-0.5\">\n {([\"unified\", \"split\"] as const).map((value) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => onChange(value)}\n className={cn(\n \"min-h-7 rounded-og-xs px-1.5 py-0.5 text-2xs capitalize pointer-coarse:min-h-11\",\n layout === value\n ? \"bg-og-accent-soft text-og-fg\"\n : \"text-og-fg-subtle hover:text-og-fg\",\n )}\n >\n {value}\n </button>\n ))}\n </div>\n );\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\n/* ----------------------------------------------------------------------------\n Windowed sections — variable-height file-section virtualization.\n\n The Changes tab stacks N file diffs in one scroll pane. Mounting N Shiki\n highlighters (Pierre's `PatchDiff`) at once is the exact wart this replaces,\n so we mount only the sections inside the visible window ± overscan and reserve\n the rest as empty space (dossier §10.7, D2).\n\n Why NOT `virtua` here (unlike the file tree/rail): Pierre renders each diff in\n a shadow DOM with its own internal overflow/virtualization, so an outer\n measuring virtualizer can read a collapsed or fixed height and lay sections\n out wrong (dossier risk #6). This hook windows by mounting/unmounting whole\n file sections off a scroll offset and a per-section height ESTIMATE (refined\n by measurement when a real browser provides it), which never depends on\n Pierre reporting its own height — and the math is pure + deterministic, so\n D2 is provable in both happy-dom (drive scrollTop/clientHeight) and a real\n browser (Playwright, the verification-matrix path).\n -------------------------------------------------------------------------- */\n\nexport type WindowRange = {\n /** First mounted index (inclusive). */\n start: number;\n /** One past the last mounted index (exclusive). */\n end: number;\n};\n\n/**\n * Pure windowing math: given each section's height (px), the scroll offset, the\n * viewport height, and an overscan count, return the `[start, end)` index window\n * to mount. Robust to a zero viewport (a headless/pre-layout pass) — it then\n * mounts a small overscan window anchored at the item under `scrollTop` rather\n * than the whole list.\n */\nexport function computeWindowRange(\n heights: readonly number[],\n scrollTop: number,\n viewport: number,\n overscan: number,\n): WindowRange {\n const n = heights.length;\n if (n === 0) return { start: 0, end: 0 };\n const top = Math.max(scrollTop, 0);\n const bottom = top + Math.max(viewport, 0);\n\n let firstVisible = -1;\n let lastVisible = -1;\n let acc = 0;\n let anchor = 0; // the item containing `scrollTop` — the zero-viewport fallback\n for (let i = 0; i < n; i++) {\n const secTop = acc;\n const secBottom = secTop + Math.max(heights[i] ?? 0, 0);\n if (secTop <= top) anchor = i;\n // A section is visible when it overlaps [top, bottom); with viewport 0 the\n // half-open interval is empty, so nothing matches and we fall back to anchor.\n if (secBottom > top && secTop < bottom) {\n if (firstVisible === -1) firstVisible = i;\n lastVisible = i;\n }\n acc = secBottom;\n }\n\n if (firstVisible === -1) {\n firstVisible = anchor;\n lastVisible = anchor;\n }\n\n return {\n start: Math.max(0, firstVisible - overscan),\n end: Math.min(n, lastVisible + 1 + overscan),\n };\n}\n\nexport type WindowedSections = {\n /** Attach to the scroll container. */\n scrollRef: React.RefObject<HTMLDivElement | null>;\n /** The mounted window `[start, end)`. */\n range: WindowRange;\n /** Prefix offsets: `offsets[i]` is the top px of section `i`; `offsets[count]`\n * is the total content height. */\n offsets: number[];\n /** Total content height (px) — set on the spacer so scroll length is stable. */\n totalHeight: number;\n /** Report a MOUNTED section's real height (px) so the layout refines as async\n * content — e.g. Pierre's Shiki render — grows. Drive it from a ResizeObserver;\n * a zero/idle value is ignored so a headless pass keeps the estimate. */\n measure: (index: number, height: number) => void;\n /** Scroll section `index` to the top of the pane (the rail-jump). */\n scrollToIndex: (index: number) => void;\n};\n\n/**\n * Variable-height section windowing over a scroll container. Seeds every section\n * to `estimateHeight(i)`, mounts only `range`, and refines heights from real\n * measurements (a no-op in a zero-layout headless pass, which keeps the estimate\n * — deterministic for tests). Pass a STABLE `estimateHeight` (wrap in useCallback).\n */\nexport function useWindowedSections(opts: {\n count: number;\n estimateHeight: (index: number) => number;\n overscan?: number | undefined;\n}): WindowedSections {\n const { count, estimateHeight, overscan = 3 } = opts;\n const scrollRef = useRef<HTMLDivElement | null>(null);\n\n const [heights, setHeights] = useState<number[]>(() =>\n Array.from({ length: count }, (_, i) => estimateHeight(i)),\n );\n\n // Re-seed heights when the section count changes (a new diff arrives), keeping\n // any already-measured heights for surviving indices.\n useEffect(() => {\n setHeights((prev) => {\n if (prev.length === count) return prev;\n return Array.from({ length: count }, (_, i) => prev[i] ?? estimateHeight(i));\n });\n // estimateHeight is expected stable; count is the real trigger.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [count]);\n\n const heightsRef = useRef(heights);\n heightsRef.current = heights;\n\n const [range, setRange] = useState<WindowRange>(() => ({\n start: 0,\n end: Math.min(count, overscan + 1),\n }));\n\n const recompute = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n const next = computeWindowRange(heightsRef.current, el.scrollTop, el.clientHeight, overscan);\n setRange((prev) => (prev.start === next.start && prev.end === next.end ? prev : next));\n }, [overscan]);\n\n // Recompute on scroll (rAF-coalesced) and on container resize.\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n let raf = 0;\n const onScroll = () => {\n if (raf) return;\n raf =\n typeof requestAnimationFrame === \"function\"\n ? requestAnimationFrame(() => {\n raf = 0;\n recompute();\n })\n : (recompute(), 0);\n };\n el.addEventListener(\"scroll\", onScroll, { passive: true });\n const ro = typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(() => recompute()) : null;\n ro?.observe(el);\n recompute();\n return () => {\n el.removeEventListener(\"scroll\", onScroll);\n ro?.disconnect();\n if (raf && typeof cancelAnimationFrame === \"function\") cancelAnimationFrame(raf);\n };\n }, [recompute, count]);\n\n const measure = useCallback((index: number, height: number) => {\n if (height <= 0) return; // zero-layout pass — keep the estimate\n setHeights((prev) => {\n if (Math.abs((prev[index] ?? 0) - height) < 1) return prev;\n const next = prev.slice();\n next[index] = height;\n return next;\n });\n }, []);\n\n const offsets = useMemo(() => {\n const out = new Array<number>(count + 1);\n out[0] = 0;\n for (let i = 0; i < count; i++) out[i + 1] = (out[i] ?? 0) + Math.max(heights[i] ?? 0, 0);\n return out;\n }, [heights, count]);\n\n // A measured height can shift the window (e.g. estimates were short) — keep the\n // mounted set in sync without waiting for the next scroll.\n useEffect(() => {\n recompute();\n }, [offsets, recompute]);\n\n const scrollToIndex = useCallback(\n (index: number) => {\n const el = scrollRef.current;\n if (!el) return;\n const clamped = Math.max(0, Math.min(count - 1, index));\n el.scrollTop = offsets[clamped] ?? 0;\n },\n [offsets, count],\n );\n\n return {\n scrollRef,\n range,\n offsets,\n totalHeight: offsets[count] ?? 0,\n measure,\n scrollToIndex,\n };\n}\n","import { useCallback, useState } from \"react\";\nimport type {\n CodexAccount,\n CodexAccountsResponse,\n CodexRotationSettings,\n SessionEvent,\n} from \"@opengeni/sdk\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport {\n useMutationRunner,\n usePolledValue,\n useSessionEventTrigger,\n type SessionEventFeedOptions,\n} from \"./internal\";\n\n/** Events that change which Codex account a session runs on (or just ran). */\nexport function isCodexAccountEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type === \"codex.account.switched\" || event.type === \"turn.started\";\n}\n\n/**\n * The structural slice of the SDK client the Codex-accounts surface needs. Method\n * NAMES + SIGNATURES match `OpenGeniClient` so the real client satisfies it\n * directly; declared structurally (not a hard Pick) so a test/Geni client can\n * stand in. `getSession` reads the session's pin/last; `pinSessionCodexAccount`\n * is the optional mutation (absent ⇒ the indicator hides the switch affordance).\n */\nexport type CodexAccountsClientLike = {\n listCodexAccounts: (workspaceId: string) => Promise<CodexAccountsResponse>;\n getSession?: (\n workspaceId: string,\n sessionId: string,\n ) => Promise<{ codexPinnedCredentialId?: string | null; codexLastCredentialId?: string | null }>;\n pinSessionCodexAccount?: (\n workspaceId: string,\n sessionId: string,\n target: string,\n ) => Promise<{ pinned: string }>;\n /** Optional (absent ⇒ the card hides live refresh): batched live /wham/usage refresh. */\n refreshCodexUsage?: (workspaceId: string) => Promise<{ usage: Record<string, unknown> }>;\n};\n\nexport type UseCodexAccountsOptions = ClientOverride &\n SessionEventFeedOptions & {\n pollIntervalMs?: number | undefined;\n /** Scope to a session so the hook resolves the pin + the effective account. */\n sessionId?: string | undefined;\n /** Override the client with one implementing `CodexAccountsClientLike`. */\n codexClient?: CodexAccountsClientLike | undefined;\n };\n\nexport type UseCodexAccountsResult = {\n accounts: CodexAccount[];\n /** The workspace ACTIVE account (used when a session is unpinned). */\n activeAccountId: string | null;\n /** The session's PINNED account (null ⇒ following workspace active). */\n pinnedAccountId: string | null;\n /** The account the next turn will run on: pin > workspace active. */\n effectiveAccountId: string | null;\n /** The account the session's last turn ACTUALLY ran on (the \"Running on:\" source). */\n lastAccountId: string | null;\n settings: CodexRotationSettings;\n loading: boolean;\n refresh: () => Promise<void>;\n /**\n * Trigger a LIVE batched /wham/usage refresh across all accounts, then re-read\n * the cached metadata so the new windows land on `accounts`. Modeled on `pin`.\n * No-op (resolves false) when the client can't refresh usage.\n */\n refreshUsage: () => Promise<boolean>;\n /** True while a live usage refresh is in flight (drives the bar skeleton). */\n refreshingUsage: boolean;\n /** Pin (or unpin via \"auto\") the session's account; returns true on success. */\n pin: (target: string) => Promise<boolean>;\n pinning: boolean;\n /** The target of the in-flight pin (for per-row spinner gating). */\n pinningTarget: string | null;\n mutationError: Error | null;\n};\n\nconst EMPTY_SETTINGS: CodexRotationSettings = {\n rotationEnabled: false,\n rotationStrategy: \"most_remaining\",\n activeCredentialId: null,\n};\n\ntype CodexAccountsState = {\n accounts: CodexAccount[];\n activeAccountId: string | null;\n settings: CodexRotationSettings;\n pinnedAccountId: string | null;\n lastAccountId: string | null;\n};\n\nconst EMPTY_STATE: CodexAccountsState = {\n accounts: [],\n activeAccountId: null,\n settings: EMPTY_SETTINGS,\n pinnedAccountId: null,\n lastAccountId: null,\n};\n\n/**\n * The workspace's Codex accounts + the per-workspace active pointer + (when\n * session-scoped) the session pin and last-ran-on account. Composed like\n * `useMachines`: slow polling (the realtime work is done by the\n * `codex.account.switched` / `turn.started` event trigger) + a `pin` mutation.\n * Dual-consumer safe via the structural `CodexAccountsClientLike` surface.\n */\nexport function useCodexAccounts(options: UseCodexAccountsOptions = {}): UseCodexAccountsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const codexClient = options.codexClient ?? (client as unknown as CodexAccountsClientLike);\n const sessionId = options.sessionId;\n const sharedEvents = options.events;\n\n const load = useCallback(async (): Promise<CodexAccountsState> => {\n const accountsP = codexClient.listCodexAccounts(workspaceId);\n const sessionP =\n sessionId && codexClient.getSession\n ? codexClient.getSession(workspaceId, sessionId).catch(() => null)\n : Promise.resolve(null);\n const [acc, session] = await Promise.all([accountsP, sessionP]);\n return {\n accounts: acc.accounts,\n activeAccountId: acc.activeAccountId,\n settings: acc.settings,\n pinnedAccountId: session?.codexPinnedCredentialId ?? null,\n lastAccountId: session?.codexLastCredentialId ?? null,\n };\n }, [codexClient, workspaceId, sessionId]);\n\n const {\n data: loadedData,\n loading,\n refresh,\n } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run: runMutation, mutating: pinning, mutationError } = useMutationRunner();\n const { run: runUsageMutation, mutating: refreshingUsage } = useMutationRunner();\n const [pinningTarget, setPinningTarget] = useState<string | null>(null);\n\n // Live flip: a manual switch (P1) or a failover (P3) emits codex.account.switched;\n // turn.started covers the case where the worker recorded the actual account.\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isCodexAccountEvent,\n () => void refresh(),\n {\n enabled: options.enabled ?? true,\n ...(sharedEvents !== undefined ? { events: sharedEvents } : {}),\n },\n );\n\n const pin = useCallback(\n async (target: string): Promise<boolean> => {\n if (!sessionId || !codexClient.pinSessionCodexAccount) {\n return false;\n }\n setPinningTarget(target);\n const result = await runMutation(async () => {\n await codexClient.pinSessionCodexAccount!(workspaceId, sessionId, target);\n return true;\n });\n setPinningTarget(null);\n if (result) await refresh();\n return result === true;\n },\n [codexClient, workspaceId, sessionId, runMutation, refresh],\n );\n\n // Live usage refresh: hit the batched provider read, then re-read cached\n // metadata so the fresh windows land on `accounts`. The provider read writes the\n // cache columns server-side; state.refresh() pulls them back.\n const refreshUsage = useCallback(async (): Promise<boolean> => {\n if (!codexClient.refreshCodexUsage) {\n return false;\n }\n const result = await runUsageMutation(async () => {\n await codexClient.refreshCodexUsage!(workspaceId);\n return true;\n });\n if (result) await refresh();\n return result === true;\n }, [codexClient, workspaceId, runUsageMutation, refresh]);\n\n const data = loadedData ?? EMPTY_STATE;\n const effectiveAccountId = data.pinnedAccountId ?? data.activeAccountId;\n\n return {\n accounts: data.accounts,\n activeAccountId: data.activeAccountId,\n pinnedAccountId: data.pinnedAccountId,\n effectiveAccountId,\n lastAccountId: data.lastAccountId,\n settings: data.settings,\n loading,\n refresh,\n refreshUsage,\n refreshingUsage,\n pin,\n pinning,\n pinningTarget,\n mutationError,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,SAAS,aAAa,gBAAgB;AA6B/B,SAAS,aAAa,OAA4C;AACvE,SAAO,MAAM,SAAS;AACxB;AAGO,SAAS,WACd,WACA,UAA6B,CAAC,GACZ;AAClB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,CAAC,UAAU,WAAW,IAAI,SAAyB,IAAI;AAC7D,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAC/E,QAAM,OAAO,YAAY,YAAY;AACnC,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,IACT;AACA,UAAM,UAAU,MAAM,OAAO,WAAW,aAAa,SAAS;AAE9D,gBAAY,IAAI;AAChB,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,aAAa,SAAS,CAAC;AACnC,QAAM,EAAE,MAAM,SAAS,OAAO,QAAQ,IAAI,eAAe,MAAM;AAAA,IAC7D,gBAAgB,QAAQ;AAAA,IACxB;AAAA,EACF,CAAC;AAED,QAAM,OAAO,QAAQ;AAGrB,QAAM,UACJ,QAAQ,YAAY,SAAS,OAAO,KAAK,KACrC,EAAE,GAAG,MAAM,OAAO,SAAS,OAAO,aAAa,SAAS,YAAY,IACpE;AAIN,QAAM,eAAe;AAAA,IACnB,CAAC,UAAwB;AACvB,YAAM,UAAW,MAAM,WAAW,CAAC;AACnC,YAAM,QAAQ,QAAQ;AACtB,UAAI,OAAO,UAAU,UAAU;AAC7B;AAAA,MACF;AACA,YAAM,SACJ,QAAQ,WAAW,UAAU,QAAQ,WAAW,UAAU,QAAQ,SAAS;AAC7E,kBAAY,CAAC,YAA4B;AACvC,cAAM,OAAO,WAAW;AACxB,YAAI,CAAC,MAAM;AACT,iBAAO;AAAA,QACT;AACA,eAAO,EAAE,GAAG,MAAM,OAAO,aAAa,OAAO;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,IACA,CAAC,IAAI;AAAA,EACP;AACA,yBAAuB,QAAQ,aAAa,WAAW,cAAc,cAAc;AAAA,IACjF;AAAA,IACA,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,EACnE,CAAC;AAED,QAAM,cAAc;AAAA,IAClB,OAAO,UAA2C;AAChD,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,MACT;AACA,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,cAAc,aAAa,WAAW,EAAE,MAAM,CAAC,CAAC;AACtF,UAAI,QAAQ;AACV,oBAAY,MAAM;AAAA,MACpB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,GAAG;AAAA,EACtC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AACF;;;AClHA,SAAS,eAAAA,cAAa,aAAAC,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgB;;;ACoClE,IAAM,oBAAoB;AAC1B,IAAM,sBAAsB;AAErB,SAAS,cAAc,QAAwC;AACpE,QAAM,QAAwB,CAAC;AAC/B,QAAM,UAAU,mBAAmB,MAAM;AACzC,QAAM,UAAU,oBAAoB,QAAQ,OAAO;AAEnD,QAAM,OAAO,MAAgC,MAAM,MAAM,SAAS,CAAC;AAGnE,QAAM,qBAAqB,MAAY;AACrC,UAAM,OAAO,KAAK;AAClB,SAAK,MAAM,SAAS,mBAAmB,MAAM,SAAS,gBAAgB,KAAK,WAAW;AACpF,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,eAAe,CACnB,QACA,cAAmD,eAC1C;AACT,eAAW,QAAQ,OAAO;AACxB,UACE,WAAW,UACX,YAAY,QACZ,KAAK,UACL,UACA,KAAK,WAAW,QAChB;AACA;AAAA,MACF;AACA,WAAK,KAAK,SAAS,mBAAmB,KAAK,SAAS,gBAAgB,KAAK,WAAW;AAClF,aAAK,YAAY;AAAA,MACnB;AACA,WAAK,KAAK,SAAS,eAAe,KAAK,SAAS,aAAa,KAAK,WAAW,WAAW;AACtF,aAAK,SAAS;AAAA,MAChB;AACA,UAAI,KAAK,SAAS,aAAa,KAAK,WAAW,WAAW;AACxD,aAAK,SAAS;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAU,SAAS,MAAM,OAAO;AACtC,UAAM,SAAS,MAAM,UAAU;AAE/B,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,gBAAgB;AAGnB,2BAAmB;AACnB,cAAM,kBAAkB,wBAAwB,QAAQ,eAAe;AACvE,YAAI,iBAAiB;AACnB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,IAAI,MAAM;AAAA,YACV;AAAA,YACA,YAAY,MAAM;AAAA,YAClB,gBAAgB,gBAAgB;AAAA,YAChC,aAAa,gBAAgB;AAAA,YAC7B,YAAY,gBAAgB;AAAA,YAC5B,UAAU,gBAAgB;AAAA,YAC1B,UAAU,gBAAgB;AAAA,YAC1B,cAAc,gBAAgB;AAAA,YAC9B,MAAM,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAAA,UAC1D,CAAC;AACD;AAAA,QACF;AACA,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAAA,UACxD,WAAW,aAAa,QAAQ,SAAS;AAAA,UACzC,OAAO,SAAS,QAAQ,KAAK;AAAA,UAC7B,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,uBAAuB;AAC1B,cAAM,OAAO,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAC/D,YAAI,CAAC,MAAM;AACT;AAAA,QACF;AACA,cAAM,OAAO,KAAK;AAClB,YAAI,MAAM,SAAS,mBAAmB,KAAK,aAAa,KAAK,WAAW,QAAQ;AAC9E,eAAK,QAAQ;AACb;AAAA,QACF;AACA,2BAAmB;AACnB,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,2BAA2B;AAC9B,cAAM,OAAO,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAI/D,cAAM,OAAO,CAAC,GAAG,KAAK,EACnB,QAAQ,EACR;AAAA,UACC,CAAC,SACC,KAAK,SAAS,mBAAmB,KAAK,WAAW;AAAA,QACrD;AACF,YACE,SACC,KAAK,aAAa,CAAC,KAAK,QAAQ,SAAS,KAAK,QAAQ,KAAK,WAAW,KAAK,IAAI,IAChF;AAEA,cAAI,CAAC,KAAK,QAAS,QAAQ,KAAK,WAAW,KAAK,IAAI,GAAI;AACtD,iBAAK,OAAO,QAAQ,KAAK;AAAA,UAC3B;AACA,eAAK,YAAY;AACjB;AAAA,QACF;AACA,YAAI,MAAM;AACR,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,IAAI,MAAM;AAAA,YACV;AAAA,YACA;AAAA,YACA,WAAW;AAAA,YACX,YAAY,MAAM;AAAA,UACpB,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MAEA,KAAK,yBAAyB;AAC5B,cAAM,OAAO,cAAc,MAAM,OAAO;AACxC,YAAI,CAAC,MAAM;AACT;AAAA,QACF;AACA,cAAM,OAAO,KAAK;AAClB,YAAI,MAAM,SAAS,eAAe,KAAK,aAAa,KAAK,WAAW,QAAQ;AAC1E,eAAK,QAAQ;AACb;AAAA,QACF;AACA,2BAAmB;AACnB,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,0BAA0B;AAC7B,cAAM,OAAO,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAC/D,cAAM,SAAS,OAAO,QAAQ,OAAO,WAAW,QAAQ,KAAK;AAC7D,cAAM,OAAO,QAAQ,aAAa;AAClC,2BAAmB;AACnB,YAAI,SAAS,qBAAqB,SAAS,qBAAqB;AAC9D,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,IAAI,MAAM;AAAA,YACV;AAAA,YACA;AAAA,YACA,QAAQ,SAAS,oBAAoB,UAAU;AAAA,YAC/C,QAAQ,aAAa,IAAI;AAAA,YACzB,iBAAiB,kBAAkB,IAAI;AAAA,YACvC,QAAQ;AAAA,YACR,YAAY,MAAM;AAAA,UACpB,CAAC;AACD;AAAA,QACF;AACA,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV;AAAA,UACA;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,QAAQ;AAAA;AAAA;AAAA,UAGR,KAAK,QAAQ;AAAA,UACb,QAAQ;AAAA,UACR,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,yBAAyB;AAC5B,cAAM,SAAS,OAAO,QAAQ,OAAO,WAAW,QAAQ,KAAK;AAC7D,cAAM,SAAS,aAAa,OAAO,MAAM;AACzC,YAAI,CAAC,QAAQ;AACX;AAAA,QACF;AACA,YAAI,OAAO,SAAS,UAAU;AAG5B,iBAAO,SAAS,cAAc,OAAO,IAAI,WAAW;AACpD,iBAAO,kBAAkB,OAAO,mBAAmB,kBAAkB,QAAQ,MAAM;AACnF;AAAA,QACF;AAGA,eAAO,SAAS,cAAc,OAAO,IAAI,WAAW;AACpD,eAAO,SAAS,QAAQ;AACxB;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,4BAA4B;AAC/B,cAAM,OAAO,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAC/D,cAAM,SAAS,MAAM,KAAK,SAAS,SAAS,IACxC,WACA,MAAM,KAAK,SAAS,YAAY,IAC9B,aACA;AAWN,aACG,SAAS,sBAAsB,SAAS,6BACzC,WAAW,UACX;AACA;AAAA,QACF;AACA,cAAM,WAAW,gBAAgB,OAAO,IAAI;AAC5C,YAAI,YAAY,WAAW,WAAW;AACpC,mBAAS,SAAS;AAClB,cACE,QAAQ,WAAW,aACnB,QAAQ,WAAW,cACnB,QAAQ,WAAW,WACnB;AACA,qBAAS,SAAS,QAAQ;AAAA,UAC5B;AACA,gBAAM,UAAU,eAAe,OAAO;AACtC,cAAI,SAAS;AACX,qBAAS,SAAS,SAAS,SAAS,GAAG,SAAS,MAAM;AAAA,EAAK,OAAO,KAAK;AAAA,UACzE;AACA;AAAA,QACF;AACA,YAAI,CAAC,UAAU;AACb,6BAAmB;AACnB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,IAAI,MAAM;AAAA,YACV;AAAA,YACA;AAAA,YACA,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU;AAAA,YACjE,QAAQ,eAAe,OAAO,KAAK;AAAA,YACnC,QACE,QAAQ,WAAW,aACnB,QAAQ,WAAW,cACnB,QAAQ,WAAW,YACf,QAAQ,SACR;AAAA,YACN;AAAA,YACA,YAAY,MAAM;AAAA,UACpB,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MAEA,KAAK,gCAAgC;AAEnC,cAAM,OACJ,OAAO,QAAQ,UAAU,WACrB,QAAQ,QACR,OAAO,QAAQ,SAAS,WACtB,QAAQ,OACR,OAAO,QAAQ,WAAW,WACxB,QAAQ,SACR;AACV,YAAI,CAAC,MAAM;AACT;AAAA,QACF;AAGA,cAAM,QACH,OAAO,QAAQ,SAAS,WAAW,gBAAgB,OAAO,QAAQ,IAAI,IAAI,WAC3E,CAAC,GAAG,KAAK,EACN,QAAQ,EACR;AAAA,UACC,CAAC,SAA8B,KAAK,SAAS,aAAa,KAAK,WAAW;AAAA,QAC5E;AACJ,YAAI,MAAM;AACR,eAAK,UAAU;AAAA,QACjB;AACA;AAAA,MACF;AAAA,MAEA,KAAK,0BAA0B;AAC7B,cAAM,SAAS,QAAQ;AACvB,YAAI,CAAC,gBAAgB,MAAM,GAAG;AAC5B;AAAA,QACF;AAMA,YAAI,CAAC,mBAAmB,IAAI,MAAM,GAAG;AACnC;AAAA,QACF;AACA,cAAM,WAAW,CAAC,GAAG,KAAK,EACvB,QAAQ,EACR,KAAK,CAAC,SAAoC,KAAK,SAAS,gBAAgB;AAC3E,YAAI,UAAU,WAAW,QAAQ;AAC/B;AAAA,QACF;AACA,cAAM,KAAK,EAAE,MAAM,kBAAkB,IAAI,MAAM,IAAI,QAAQ,YAAY,MAAM,WAAW,CAAC;AACzF;AAAA,MACF;AAAA,MAEA,KAAK,0BAA0B;AAC7B,qBAAa,MAAM;AACnB,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM;AAAA,UACN,MAAM;AAAA,UACN,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,6BAA6B;AAChC,2BAAmB;AACnB,cAAM,SACJ,OAAO,QAAQ,0BAA0B,WACrC,KAAK,MAAM,QAAQ,qBAAqB,EAAE,eAAe,OAAO,IAChE;AACN,cAAM,QACJ,OAAO,QAAQ,yBAAyB,WACpC,KAAK,MAAM,QAAQ,oBAAoB,EAAE,eAAe,OAAO,IAC/D;AACN,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM;AAAA,UACN,MACE,UAAU,QACN,wCAAwC,MAAM,OAAO,KAAK,aAC1D;AAAA,UACN,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,sCAAsC;AACzC,2BAAmB;AACnB,cAAM,SAAS,OAAO,QAAQ,WAAW,WAAW,QAAQ,SAAS;AACrE,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM;AAAA,UACN,MACE,WAAW,eACP,8EACA,WAAW,4BACT,8FACA;AAAA,UACR,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,2BAA2B;AAI9B;AAAA,MACF;AAAA,MAEA,KAAK,4BAA4B;AAI/B;AAAA,MACF;AAAA,MAEA,KAAK,oBAAoB;AAKvB,2BAAmB;AACnB,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV;AAAA,UACA,gBAAgB,OAAO,QAAQ,mBAAmB,WAAW,QAAQ,iBAAiB;AAAA,UACtF,cAAc,OAAO,QAAQ,iBAAiB,WAAW,QAAQ,eAAe;AAAA,UAChF,QAAQ,iBAAiB,QAAQ,MAAM;AAAA,UACvC,QAAQ,WAAW,QAAQ,MAAM;AAAA,UACjC,UAAU,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW;AAAA,UACpE,UAAU,OAAO,QAAQ,aAAa,WAAW,QAAQ,WAAW;AAAA,UACpE,kBACE,OAAO,QAAQ,qBAAqB,WAAW,QAAQ,mBAAmB;AAAA,UAC5E,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,kBAAkB;AAMrB,YAAI,QAAQ,gBAAgB,sBAAsB;AAChD,uBAAa,MAAM;AACnB;AAAA,QACF;AAOA,YAAI,0BAA0B,OAAO,GAAG;AACtC,uBAAa,MAAM;AACnB,gBAAM,KAAK,YAAY,OAAO,UAAU,yBAAyB,CAAC;AAClE,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,IAAI,MAAM;AAAA,YACV,MAAM;AAAA,YACN,MAAM;AAAA,YACN,YAAY,MAAM;AAAA,UACpB,CAAC;AACD;AAAA,QACF;AACA,qBAAa,MAAM;AACnB,cAAM,KAAK,YAAY,OAAO,YAAY,IAAI,CAAC;AAC/C;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAClB,cAAM,cAAc,gBAAgB,OAAO,MAAM;AAIjD,cAAM,cAAc,0BAA0B,OAAO,IACjD,4BACA,eAAe,OAAO;AAK1B,qBAAa,QAAQ,WAAW;AAChC,cAAM,KAAK,YAAY,OAAO,UAAU,WAAW,CAAC;AACpD,YAAI,CAAC,aAAa;AAChB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,IAAI,MAAM;AAAA,YACV,MAAM;AAAA,YACN,MAAM,eAAe;AAAA,YACrB,YAAY,MAAM;AAAA,UACpB,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MAEA,KAAK,kBAAkB;AAIrB,YAAI,UAAU,CAAC,QAAQ,eAAe,IAAI,MAAM,GAAG;AACjD;AAAA,QACF;AACA,cAAM,cAAc,gBAAgB,OAAO,MAAM;AACjD,qBAAa,QAAQ,WAAW;AAChC,cAAM,KAAK,YAAY,OAAO,aAAa,IAAI,CAAC;AAChD,YAAI,CAAC,aAAa;AAChB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,IAAI,MAAM;AAAA,YACV,MAAM;AAAA,YACN,MAAM;AAAA,YACN,YAAY,MAAM;AAAA,UACpB,CAAC;AAAA,QACH;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK,oBAAoB;AAIvB,cAAM,SAAS,WAAW,MAAM,IAAI,MAAM,MAAM,QAAQ,SAAS,MAAM,UAAU;AACjF,YAAI,QAAQ;AACV,6BAAmB;AACnB,gBAAM,KAAK,MAAM;AAAA,QACnB;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,qBAAqB;AACxB,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,QAAQ,MAAM,KAAK,MAAM,QAAQ,MAAM;AAAA,UACvC,MAAM,SAAS,OAAO;AAAA,UACtB,YAAY,MAAM;AAAA,QACpB,CAAC;AACD;AAAA,MACF;AAAA,MAEA;AACE;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AACT;AAGA,SAAS,0BAA0B,SAA2C;AAC5E,SAAO,mBAAmB;AAAA,IACxB,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ;AAAA,IAC3D,QAAQ,OAAO,QAAQ,WAAW,WAAW,QAAQ,SAAS;AAAA,IAC9D,cAAc,OAAO,QAAQ,iBAAiB,WAAW,QAAQ,eAAe;AAAA,EAClF,CAAC;AACH;AAQO,SAAS,0BAA0B,QAAiC;AACzE,QAAM,UAAU,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAClE,WAAS,QAAQ,QAAQ,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC3D,UAAM,QAAQ,QAAQ,KAAK;AAC3B,QACE,OAAO,SAAS,oBAChB,OAAO,SAAS,iBAChB,OAAO,SAAS,kBAChB;AACA;AAAA,IACF;AACA,WAAO,0BAA0B,SAAS,MAAM,OAAO,CAAC;AAAA,EAC1D;AACA,SAAO;AACT;AAGO,SAAS,wBAAwB,QAA8C;AACpF,WAAS,QAAQ,OAAO,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC1D,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,OAAO,SAAS,0BAA0B;AAC5C;AAAA,IACF;AACA,UAAM,SAAS,SAAS,MAAM,OAAO,EAAE;AACvC,QAAI,gBAAgB,MAAM,GAAG;AAC3B,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAaA,SAAS,eAAe,MAA0C;AAChE,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,cAAc,OAAwC;AACpE,QAAM,SAA0B,CAAC;AACjC,aAAW,QAAQ,OAAO;AACxB,QAAI,eAAe,IAAI,GAAG;AACxB,YAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,UAAI,MAAM,SAAS,cAAc,KAAK,YAAY,QAAW;AAC3D,aAAK,MAAM,KAAK,IAAI;AAAA,MACtB,OAAO;AACL,eAAO,KAAK,EAAE,MAAM,YAAY,IAAI,YAAY,KAAK,EAAE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;AAAA,MAC5E;AACA;AAAA,IACF;AACA,QAAI,KAAK,SAAS,YAAY;AAC5B,uBAAiB,QAAQ,IAAI;AAC7B,sBAAgB,QAAQ,IAAI;AAC5B;AAAA,IACF;AACA,WAAO,KAAK,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,EACpC;AACA,SAAO;AACT;AAWA,SAAS,mBAAmB,QAA2C;AACrE,QAAM,UAAU,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAClE,QAAM,sBAAsB,oBAAI,IAAoB;AACpD,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,mBAAmB,oBAAI,IAAY;AACzC,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,iBAAiB,oBAAI,IAAY;AAEvC,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAU,SAAS,MAAM,OAAO;AACtC,UAAM,SAAS,MAAM,UAAU;AAC/B,QAAI,MAAM,SAAS,eAAe;AAChC,YAAM,iBACJ,OAAO,QAAQ,mBAAmB,WAAW,QAAQ,iBAAiB;AACxE,YAAM,eAAe,OAAO,QAAQ,WAAW,WAAW,QAAQ,SAAS;AAC3E,UAAI,kBAAkB,cAAc;AAClC,4BAAoB,IAAI,gBAAgB,YAAY;AAAA,MACtD;AACA;AAAA,IACF;AACA,QAAI,MAAM,SAAS,gBAAgB;AACjC,YAAM,iBACJ,OAAO,QAAQ,mBAAmB,WAAW,QAAQ,iBAAiB;AACxE,UAAI,kBAAkB,CAAC,kBAAkB,IAAI,cAAc,GAAG;AAC5D,0BAAkB,IAAI,gBAAgB,MAAM,QAAQ;AAAA,MACtD;AACA,UAAI,QAAQ;AACV,uBAAe,IAAI,MAAM;AAAA,MAC3B;AAAA,IACF,WAAW,MAAM,SAAS,oBAAoB,QAAQ;AACpD,uBAAiB,IAAI,MAAM;AAAA,IAC7B;AAEA,QAAI,UAAU,MAAM,SAAS,iBAAiB,MAAM,SAAS,kBAAkB;AAC7E,YAAM,WAAW,kBAAkB,IAAI,MAAM;AAC7C,UAAI,aAAa,UAAa,MAAM,WAAW,UAAU;AACvD,0BAAkB,IAAI,QAAQ,MAAM,QAAQ;AAAA,MAC9C;AAAA,IACF;AACA,QAAI,UAAU,qBAAqB,MAAM,IAAI,GAAG;AAC9C,qBAAe,IAAI,MAAM;AAAA,IAC3B;AAAA,EACF;AAEA,aAAW,CAAC,gBAAgB,MAAM,KAAK,qBAAqB;AAC1D,QAAI,CAAC,kBAAkB,IAAI,cAAc,GAAG;AAC1C,YAAM,cAAc,kBAAkB,IAAI,MAAM;AAChD,UAAI,gBAAgB,QAAW;AAC7B,0BAAkB,IAAI,gBAAgB,WAAW;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,+BAA+B,oBAAI,IAAY;AACrD,aAAW,CAAC,gBAAgB,MAAM,KAAK,qBAAqB;AAC1D,QACE,iBAAiB,IAAI,MAAM,KAC3B,CAAC,kBAAkB,IAAI,cAAc,KACrC,CAAC,kBAAkB,IAAI,MAAM,GAC7B;AACA,mCAA6B,IAAI,cAAc;AAAA,IACjD;AAAA,EACF;AAEA,SAAO,EAAE,qBAAqB,mBAAmB,8BAA8B,eAAe;AAChG;AAEA,SAAS,oBAAoB,QAAwB,SAA4C;AAC/F,QAAM,UAAU,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAClE,QAAM,aAAa,oBAAI,IAA4B;AAEnD,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,SAAS,gBAAgB;AACjC;AAAA,IACF;AACA,UAAM,eAAe,QAAQ,oBAAoB,IAAI,MAAM,EAAE;AAC7D,QAAI,CAAC,cAAc;AACjB,oBAAc,YAAY,MAAM,UAAU,KAAK;AAC/C;AAAA,IACF;AACA,QAAI,QAAQ,6BAA6B,IAAI,MAAM,EAAE,GAAG;AACtD;AAAA,IACF;AACA,UAAM,WAAW,QAAQ,kBAAkB,IAAI,MAAM,EAAE;AACvD,QAAI,aAAa,QAAW;AAC1B,oBAAc,YAAY,UAAU,KAAK;AACzC;AAAA,IACF;AAAA,EAIF;AAEA,QAAM,YAA4B,CAAC;AACnC,aAAW,SAAS,SAAS;AAC3B,UAAM,SAAS,WAAW,IAAI,MAAM,QAAQ;AAC5C,QAAI,QAAQ;AACV,gBAAU,KAAK,GAAG,MAAM;AAAA,IAC1B;AACA,QAAI,MAAM,SAAS,gBAAgB;AACjC,gBAAU,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cACP,YACA,UACA,OACM;AACN,QAAM,SAAS,WAAW,IAAI,QAAQ;AACtC,MAAI,QAAQ;AACV,WAAO,KAAK,KAAK;AAAA,EACnB,OAAO;AACL,eAAW,IAAI,UAAU,CAAC,KAAK,CAAC;AAAA,EAClC;AACF;AAEA,SAAS,qBAAqB,MAAuB;AACnD,SAAO,KAAK,WAAW,QAAQ,KAAK,KAAK,WAAW,UAAU;AAChE;AAEA,SAAS,YACP,OACA,SACA,aACa;AACb,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI,GAAG,MAAM,EAAE;AAAA,IACf,QAAQ,MAAM,UAAU;AAAA,IACxB;AAAA,IACA;AAAA,IACA,YAAY,MAAM;AAAA,EACpB;AACF;AAEA,SAAS,gBAAgB,OAAuB,QAAgC;AAC9E,MAAI,QAAQ;AACV,WAAO,MAAM,KAAK,CAAC,SAAS,eAAe,IAAI,KAAK,KAAK,WAAW,MAAM;AAAA,EAC5E;AACA,WAAS,QAAQ,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AACzD,UAAM,OAAO,MAAM,KAAK;AACxB,QAAI,CAAC,QAAQ,KAAK,SAAS,cAAc,KAAK,SAAS,gBAAgB;AACrE,aAAO;AAAA,IACT;AACA,QAAI,eAAe,IAAI,GAAG;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,QAAyB,SAA4B;AAC7E,MAAI,QAAQ,WAAW,MAAM;AAC3B,UAAM,WAAW,OAAO,OAAO,SAAS,CAAC;AACzC,QAAI,UAAU,SAAS,cAAc,SAAS,YAAY,QAAW;AACnE,uBAAiB,UAAU,OAAO;AAAA,IACpC;AACA;AAAA,EACF;AACA,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,cAAc,MAAM,YAAY,QAAW;AAC5D;AAAA,IACF;AACA,QAAI,MAAM,MAAM,KAAK,CAAC,aAAa,SAAS,WAAW,QAAQ,MAAM,GAAG;AACtE,uBAAiB,OAAO,OAAO;AAAA,IACjC;AAAA,EACF;AACF;AAEA,SAAS,iBACP,OACA,SACM;AAMN,MAAI,QAAQ,YAAY,YAAY;AAClC,UAAM,UAAU;AAChB;AAAA,EACF;AACA,QAAM,YAAY,MAAM,MAAM,KAAK,CAAC,SAAS,YAAY,QAAQ,KAAK,WAAW,QAAQ;AACzF,QAAM,iBAAiB,MAAM,MAAM;AAAA,IACjC,CAAC,SAAS,YAAY,QAAQ,KAAK,WAAW;AAAA,EAChD;AACA,QAAM,UAAU,YAAY,WAAW,iBAAiB,cAAc;AACtE,MAAI,QAAQ,eAAe,WAAW;AACpC,UAAM,cAAc,QAAQ;AAAA,EAC9B;AACF;AAEA,SAAS,gBAAgB,QAAyB,SAA4B;AAC5E,MAAI,aAAa,OAAO;AACxB,MAAI,uBAAuB;AAC3B,SAAO,aAAa,GAAG;AACrB,UAAM,WAAW,OAAO,aAAa,CAAC;AACtC,QAAI,eAAe,QAAQ,GAAG;AAC5B;AAAA,IACF;AACA,QAAI,uBAAuB,UAAU,QAAQ,MAAM,GAAG;AACpD,6BAAuB;AACvB;AAAA,IACF;AACA,kBAAc;AAAA,EAChB;AACA,MAAI,sBAAsB;AACxB,WAAO,aAAa,OAAO,UAAU,qBAAqB,OAAO,UAAU,CAAC,GAAG;AAC7E,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,YAAY,OAAO,MAAM,UAAU;AACzC,MAAI,UAAU,WAAW,GAAG;AAC1B;AAAA,EACF;AAEA,QAAM,eAAe,yBAAyB,WAAW,OAAO;AAChE,QAAM,OAAO,eAAe,UAAU,MAAM,GAAG,EAAE,IAAI;AACrD,MAAI,KAAK,WAAW,GAAG;AACrB;AAAA,EACF;AAEA,QAAM,kBAAkB,eAAe,KAAK,CAAC,CAAC,KAAK,QAAQ;AAC3D,QAAM,YAA2B;AAAA,IAC/B,MAAM;AAAA,IACN,IAAI,QAAQ,QAAQ,UAAU,QAAQ,EAAE;AAAA,IACxC,SAAS,QAAQ;AAAA,IACjB,WAAW;AAAA,IACX,SAAS,QAAQ;AAAA,IACjB,QAAQ;AAAA,EACV;AACA,MAAI,QAAQ,aAAa;AACvB,cAAU,cAAc,QAAQ;AAAA,EAClC;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,GAAI,eAAe,CAAC,WAAW,YAAY,IAAI,CAAC,SAAS;AAAA,EAC3D;AACF;AAEA,SAAS,eAAe,OAA2C;AACjE,SAAO,OAAO,SAAS,UAAW,OAAO,SAAS,UAAU,MAAM,KAAK,SAAS;AAClF;AAEA,SAAS,uBAAuB,OAAkC,QAAgC;AAChG,MAAI,CAAC,SAAS,CAAC,QAAQ;AACrB,WAAO;AAAA,EACT;AACA,MAAI,MAAM,SAAS,YAAY;AAC7B,WACE,MAAM,MAAM,SAAS,KACrB,MAAM,MAAM,MAAM,CAAC,SAAS,KAAK,WAAW,QAAQ,KAAK,WAAW,MAAM;AAAA,EAE9E;AACA,SACE,MAAM,SAAS,UACf,MAAM,KAAK,SAAS,mBACpB,MAAM,KAAK,WAAW,QACtB,MAAM,KAAK,WAAW;AAE1B;AAEA,SAAS,qBAAqB,OAA2C;AACvE,SACE,OAAO,SAAS,UAChB,MAAM,KAAK,SAAS,oBACpB,MAAM,KAAK,WAAW;AAE1B;AAEA,SAAS,yBACP,QACA,SACiD;AACjD,QAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,MAAI,MAAM,SAAS,UAAU,KAAK,KAAK,SAAS,mBAAmB,KAAK,KAAK,WAAW;AACtF,WAAO;AAAA,EACT;AACA,MAAI,KAAK,KAAK,UAAU,QAAQ,UAAU,KAAK,KAAK,WAAW,QAAQ,QAAQ;AAC7E,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAAsD;AAC5E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,MAAM,KAAK;AAAA,IACpB,KAAK;AACH,aAAO,MAAM,MAAM,CAAC,GAAG;AAAA,IACzB,KAAK;AACH,aAAO,MAAM;AAAA,EACjB;AACF;AAEA,SAAS,SAAS,OAAyC;AACzD,SAAO,UAAU,QAAQ,OAAO,UAAU,WAAY,QAAoC,CAAC;AAC7F;AAEA,IAAM,mBAA6C;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,qBAAiD,oBAAI,IAAI;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,SAAS,aAAa,OAAuD;AAC3E,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,CAAC;AAAA,EACV;AACA,SAAO,MAAM,OAAO,CAAC,UAAwD;AAC3E,UAAM,SAAS,SAAS,KAAK;AAC7B,QAAI,OAAO,SAAS,cAAc;AAChC,aAAO,OAAO,OAAO,QAAQ,YAAY,OAAO,OAAO,QAAQ;AAAA,IACjE;AACA,WAAO,OAAO,SAAS,UAAU,OAAO,OAAO,WAAW;AAAA,EAC5D,CAAC;AACH;AAEA,SAAS,SAAS,OAAmD;AACnE,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,CAAC;AAAA,EACV;AACA,SAAO,MAAM,OAAO,CAAC,UAAoD;AACvE,UAAM,SAAS,SAAS,KAAK;AAC7B,WAAO,OAAO,SAAS,SAAS,OAAO,OAAO,OAAO;AAAA,EACvD,CAAC;AACH;AAEA,SAAS,wBAAwB,OAOxB;AACP,QAAM,UAAU,SAAS,KAAK;AAC9B,QAAM,cAAc;AACpB,MACE,OAAO,QAAQ,mBAAmB,YAClC,CAAC,YAAY,KAAK,QAAQ,cAAc,KACxC,OAAO,QAAQ,WAAW,YAC1B,QAAQ,OAAO,KAAK,MAAM,IAC1B;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,SAAO;AAAA,IACL,gBAAgB,QAAQ;AAAA,IACxB,aAAa,QAAQ;AAAA,IACrB,YAAY,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAAA,IAC5D,UAAU,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,IACtD,UAAU,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA,IAI9D,cACE,OAAO,KAAK,iBAAiB,WACzB,KAAK,eACL,OAAO,KAAK,cAAc,WACxB,KAAK,YACL;AAAA,EACV;AACF;AAEA,SAAS,gBAAgB,OAAwC;AAC/D,SAAO,OAAO,UAAU,YAAa,iBAAuC,SAAS,KAAK;AAC5F;AAGA,SAAS,cAAc,SAA2C;AAChE,MAAI,QAAQ,UAAU,QAAQ,QAAQ,WAAW,MAAM;AACrD,WAAO;AAAA,EACT;AACA,QAAM,SAAS,QAAQ;AACvB,SACE,CAAC,CAAC,UAAU,OAAO,WAAW,YAAa,OAAiC,YAAY;AAE5F;AAEA,SAAS,aACP,OACA,QACuC;AACvC,QAAM,WAAW,CAAC,GAAG,KAAK,EAAE,QAAQ;AACpC,QAAM,SAAS,CAAC,SACd,KAAK,SAAS,eAAe,KAAK,SAAS;AAC7C,MAAI,QAAQ;AACV,UAAM,OAAO,SAAS,KAAK,CAAC,SAAS,OAAO,IAAI,KAAK,KAAK,WAAW,MAAM;AAC3E,QAAI,MAAM;AACR,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,SAAS;AAAA,IACd,CAAC,SAA4C,OAAO,IAAI,KAAK,KAAK,WAAW;AAAA,EAC/E;AACF;AAEA,SAAS,gBAAgB,OAAuB,MAAuC;AACrF,SAAO,CAAC,GAAG,KAAK,EACb,QAAQ,EACR;AAAA,IACC,CAAC,SACC,KAAK,SAAS,aAAa,KAAK,SAAS,QAAQ,KAAK,WAAW;AAAA,EACrE;AACJ;AAEA,SAAS,eAAe,SAAiD;AACvE,aAAW,OAAO,CAAC,SAAS,SAAS,GAAY;AAC/C,UAAM,QAAQ,QAAQ,GAAG;AACzB,QAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG;AAGxD,aAAO,sBAAsB,KAAK;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,SAAS,SAAiD;AACjE,MAAI,OAAO,QAAQ,SAAS,YAAY,QAAQ,MAAM;AACpD,WAAO,QAAQ;AAAA,EACjB;AACA,QAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,MAAI,OAAO,KAAK,SAAS,YAAY,KAAK,MAAM;AAC9C,WAAO,KAAK;AAAA,EACd;AACA,MAAI,OAAO,QAAQ,WAAW,YAAY,QAAQ,QAAQ;AACxD,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO;AACT;AAOA,SAAS,WACP,IACA,MACA,QACA,SACA,YACmB;AACnB,QAAM,WACJ,OAAO,QAAQ,aAAa,YAAY,QAAQ,WAAW,QAAQ,WAAW;AAChF,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AACA,QAAM,qBACJ,OAAO,QAAQ,uBAAuB,WAAW,QAAQ,qBAAqB;AAChF,QAAM,sBACJ,OAAO,QAAQ,wBAAwB,WAAW,QAAQ,sBAAsB;AAClF,QAAM,SAAS,OAAO,QAAQ,WAAW,WAAW,QAAQ,SAAS;AACrE,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,SAAS,SAAS,qBAAqB,cAAc;AAAA,IACrD,YAAY,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAAA,IAC9D,SAAS,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU;AAAA,IACjE,GAAI,QAAQ,YAAY,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,IACpD,GAAI,qBAAqB,EAAE,mBAAmB,IAAI,CAAC;AAAA,IACnD,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B;AAAA,IACA,GAAI,sBAAsB,EAAE,oBAAoB,IAAI,CAAC;AAAA,IACrD;AAAA,EACF;AACF;AAEA,IAAM,sBAA2C,oBAAI,IAAI;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,iBAAiB,OAA0C;AAClE,SAAO,OAAO,UAAU,YAAY,oBAAoB,IAAI,KAAK,IAC5D,QACD;AACN;AAEA,SAAS,WAAW,OAA0B;AAC5C,SAAO,MAAM,QAAQ,KAAK,IACtB,MAAM,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,CAAC,IAC7F,CAAC;AACP;AAEA,SAAS,cAAc,SAA0B;AAC/C,QAAM,SAAS,SAAS,OAAO;AAC/B,MAAI,OAAO,OAAO,SAAS,UAAU;AACnC,WAAO,OAAO;AAAA,EAChB;AACA,QAAM,UAAU,SAAS,SAAS,OAAO,IAAI,EAAE,OAAO,EAAE;AACxD,MAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,WAAO;AAAA,EACT;AACA,SAAO,QACJ,IAAI,CAAC,SAAS;AACb,UAAM,OAAO,SAAS,IAAI,EAAE;AAC5B,WAAO,OAAO,SAAS,WAAW,OAAO;AAAA,EAC3C,CAAC,EACA,KAAK,EAAE;AACZ;AAGA,SAAS,aAAa,MAA8B;AAClD,QAAM,SAAS,SAAS,OAAO,SAAS,WAAW,aAAa,IAAI,IAAI,IAAI;AAC5E,aAAW,OAAO,CAAC,kBAAkB,WAAW,QAAQ,QAAQ,GAAY;AAC1E,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG;AACxD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,kBAAkB,OAAgB,QAAQ,GAAkB;AAC1E,MAAI,QAAQ,KAAK,UAAU,QAAQ,UAAU,QAAW;AACtD,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,kBAAkB,aAAa,KAAK,GAAG,QAAQ,CAAC;AAAA,EACzD;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAW,SAAS,OAAO;AACzB,YAAM,QAAQ,kBAAkB,OAAO,QAAQ,CAAC;AAChD,UAAI,OAAO;AACT,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,SAAS;AACf,MAAI,OAAO,OAAO,cAAc,YAAY,YAAY,OAAO,SAAS,GAAG;AACzE,WAAO,OAAO;AAAA,EAChB;AACA,MACE,OAAO,OAAO,OAAO,YACrB,YAAY,OAAO,EAAE,MACpB,YAAY,UAAU,iBAAiB,UAAU,oBAAoB,SACtE;AACA,WAAO,OAAO;AAAA,EAChB;AACA,aAAW,OAAO,CAAC,qBAAqB,WAAW,UAAU,SAAS,GAAY;AAChF,QAAI,OAAO,QAAQ;AACjB,YAAM,QAAQ,kBAAkB,OAAO,GAAG,GAAG,QAAQ,CAAC;AACtD,UAAI,OAAO;AACT,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,OAAO,SAAS,UAAU;AACnC,WAAO,kBAAkB,aAAa,OAAO,IAAI,GAAG,QAAQ,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAAwB;AAC3C,SAAO,kEAAkE,KAAK,KAAK;AACrF;AAYO,SAAS,gBAAgB,MAAsB;AAGpD,QAAM,WAAW,KAAK,QAAQ,IAAI;AAClC,QAAM,WAAW,YAAY,IAAI,KAAK,MAAM,WAAW,CAAC,IAAI;AAC5D,SAAO,SAAS,QAAQ,UAAU,GAAG,EAAE,KAAK;AAC9C;;;ACptCO,SAAS,UAAU,MAAmC;AAC3D,QAAM,MAAM,KAAK;AACjB,MAAI,OAAO,OAAO,QAAQ,YAAY,OAAQ,IAA2B,SAAS,UAAU;AAC1F,WAAQ,IAAyB;AAAA,EACnC;AACA,SAAO;AACT;AAQO,SAAS,mBACd,aACA,cACA,UAAqC,CAAC,GACxB;AACd,QAAM,UAAU,CAAC,GAAI,QAAQ,WAAW,CAAC,GAAI,GAAG,WAAW;AAC3D,QAAM,WAAW,QAAQ,YAAY;AAErC,QAAM,YAAY,oBAAI,IAA0B;AAChD,QAAM,SAAS,oBAAI,IAA0B;AAC7C,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,UAAU,WAAW;AAC7B,UAAI,CAAC,UAAU,IAAI,MAAM,IAAI,GAAG;AAC9B,kBAAU,IAAI,MAAM,MAAM,MAAM,MAAM;AAAA,MACxC;AAAA,IACF,WAAW,CAAC,OAAO,IAAI,MAAM,IAAI,GAAG;AAClC,aAAO,IAAI,MAAM,MAAM,MAAM,MAAM;AAAA,IACrC;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,SAAqC;AACpD,UAAM,UAAU,UAAU,IAAI;AAC9B,QAAI,SAAS;AACX,YAAM,SAAS,UAAU,IAAI,OAAO;AACpC,UAAI,QAAQ;AACV,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO,OAAO,IAAI,KAAK,IAAI,KAAK;AAAA,EAClC;AAEA,SAAO,EAAE,SAAS,SAAS;AAC7B;;;AC9FA;AAAA,EACE,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACGA,SAAS,uBAAuB,KAA6B;AAClE,QAAM,QAAQ,OAAO,OAAO,EAAE,EAAE,MAAM,kCAAkC;AACxE,SAAO,QAAQ,OAAO,MAAM,CAAC,CAAC,IAAI;AACpC;AAOO,SAAS,yBAAyB,KAA6B;AACpE,QAAM,OAAO,OAAO,OAAO,EAAE;AAC7B,QAAM,YAAY,KAAK,QAAQ,aAAa;AAC5C,QAAM,SACJ,aAAa,IAAI,KAAK,MAAM,GAAG,SAAS,IAAI,KAAK,WAAW,WAAW,IAAI,KAAK;AAClF,QAAM,QAAQ,OAAO,MAAM,uCAAuC;AAClE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM,IAAI,OAAO,SAAS,MAAM,CAAC,GAAI,EAAE;AACvC,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAGO,SAAS,gBAAgB,KAAsB;AACpD,QAAM,OAAO,OAAO,OAAO,EAAE;AAC7B,QAAM,SAAS,KAAK,QAAQ,aAAa;AACzC,MAAI,UAAU,GAAG;AACf,WAAO,KAAK,MAAM,SAAS,cAAc,MAAM;AAAA,EACjD;AACA,MAAI,KAAK,WAAW,WAAW,GAAG;AAChC,WAAO,KAAK,MAAM,YAAY,MAAM;AAAA,EACtC;AACA,SAAO;AACT;AAGO,SAAS,cAAc,KAAuB;AACnD,SAAO,qFAAqF;AAAA,IAC1F,OAAO,OAAO,EAAE;AAAA,EAClB;AACF;AAGO,SAAS,wBAAwB,KAAuB;AAC7D,SAAO,6CAA6C,KAAK,OAAO,OAAO,EAAE,CAAC;AAC5E;AAGO,SAAS,YAAY,MAAuB;AACjD,SAAO,KAAK,SAAS,IAAQ,KAAK,KAAK,WAAW,SAAW;AAC/D;AAMO,SAAS,aAAa,WAA2B;AACtD,SAAO,OAAO,SAAS,EAAE;AAAA,IACvB;AAAA,IACA,CAAC,MAAM,IAAI,OAAO,aAAa,EAAE,WAAW,CAAC,IAAI,EAAE,CAAC;AAAA,EACtD;AACF;AA0BO,SAAS,iBAAiB,IAAsC;AACrE,QAAM,SACJ,GAAG,SAAS,gBACR,UACA,GAAG,SAAS,gBACV,YACA,GAAG,SACD,YACA;AACV,QAAM,UAAU,GAAG,SAAS,GAAG,OAAO;AACtC,QAAM,OAAO,GAAG,UAAU,GAAG;AAE7B,QAAM,QAA8B,CAAC;AACrC,MAAI,YAAY;AAChB,MAAI,YAAY;AAChB,MAAI,gBAAgB;AAEpB,MAAI,GAAG,SAAS,eAAe;AAC7B,UAAM,SAAS,GAAG,QAAQ,IAAI,MAAM,IAAI;AACxC,QAAI,MAA2C;AAC/C,QAAI,QAAQ;AACZ,QAAI,QAAQ;AACZ,eAAW,OAAO,OAAO;AACvB,UAAI,IAAI,WAAW,IAAI,GAAG;AACxB,wBAAgB;AAChB,cAAM,QAAQ,IAAI,MAAM,2BAA2B;AACnD,gBAAQ,QAAQ,OAAO,MAAM,CAAC,CAAC,IAAI;AACnC,gBAAQ,QAAQ,OAAO,MAAM,CAAC,CAAC,IAAI;AACnC,cAAM;AAAA,UACJ,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,OAAO,CAAC,EAAE,MAAM,QAAQ,OAAO,MAAM,OAAO,MAAM,MAAM,IAAI,CAAC;AAAA,QAC/D;AACA,cAAM,KAAK,GAAG;AAAA,MAChB,WAAW,OAAO,GAAG,SAAS,eAAe;AAC3C,YAAI,CAAC,KAAK;AAMR,gBAAM,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,IAAI,OAAO,CAAC,EAAE;AAClF,gBAAM,KAAK,GAAG;AACd,kBAAQ;AACR,kBAAQ;AAAA,QACV;AACA,YAAI,IAAI,WAAW,GAAG,GAAG;AACvB,cAAI,MAAM,KAAK,EAAE,MAAM,OAAO,OAAO,MAAM,OAAO,SAAS,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC;AAC/E,cAAI,YAAY;AAChB,uBAAa;AAAA,QACf,WAAW,IAAI,WAAW,GAAG,GAAG;AAC9B,cAAI,MAAM,KAAK,EAAE,MAAM,OAAO,OAAO,SAAS,OAAO,MAAM,MAAM,IAAI,MAAM,CAAC,EAAE,CAAC;AAC/E,cAAI,YAAY;AAChB,uBAAa;AAAA,QACf,OAAO;AACL,cAAI,MAAM,KAAK;AAAA,YACb,MAAM;AAAA,YACN,OAAO;AAAA,YACP,OAAO;AAAA,YACP,MAAM,IAAI,QAAQ,MAAM,EAAE;AAAA,UAC5B,CAAC;AACD,cAAI,YAAY;AAChB,cAAI,YAAY;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,GAAG,SAAS,iBAAiB,CAAC,iBAAiB,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,GAAG;AACzF,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,IACV,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb;AACF;AAQO,SAAS,cAAc,KAAqC;AACjE,QAAM,IAAK,OAAO,CAAC;AACnB,MAAI,MAAM,QAAQ,EAAE,UAAU,GAAG;AAC/B,WAAO,EAAE;AAAA,EACX;AACA,SAAO,EAAE,YAAY,CAAC,EAAE,SAAS,IAAI,CAAC;AACxC;AAOO,SAAS,aAAa,MAA+C;AAC1E,QAAM,OACJ,KAAK,OAAO,OAAO,KAAK,QAAQ,WAAY,KAAK,IAA2B,OAAO;AACrF,SAAO,SAAS,sBAAsB,KAAK,SAAS;AACtD;AAIA,IAAM,aAAa;AAGZ,SAAS,cAAc,OAAyB;AACrD,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,aAAa;AAAA,EAChC;AACA,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,MAA+B,CAAC;AACtC,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACrE,UAAI,CAAC,IAAI,WAAW,KAAK,CAAC,IAAI,6BAAS,cAAc,CAAC;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,SAAS,cAAc,MAAwC;AACpE,MAAI,QAAQ,MAAM;AAChB,WAAO,CAAC;AAAA,EACV;AACA,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,SAAS,aAAa,IAAI;AAChC,WAAO,UAAU,OAAO,WAAW,WAAY,SAAqC,CAAC;AAAA,EACvF;AACA,SAAO,OAAO,SAAS,WAAY,OAAmC,CAAC;AACzE;AAGO,SAAS,SAAS,MAAsB;AAC7C,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,SAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACpC;AAOO,SAAS,gBAAgB,QAAqD;AACnF,MAAI,UAAU,OAAO,WAAW,YAAY,aAAa,QAAQ;AAC/D,UAAM,SAAS;AACf,UAAM,UAAU,QAAQ,OAAO,OAAO;AACtC,QAAI,MAAM,QAAQ,OAAO,OAAO,GAAG;AACjC,YAAM,WAAW,OAAO,QAAQ;AAAA,QAC9B,CAAC,SACC,CAAC,CAAC,QAAQ,OAAO,SAAS,YAAa,KAA4B,SAAS;AAAA,MAChF;AACA,aAAO,EAAE,MAAM,WAAW,OAAO,SAAS,IAAI,IAAI,KAAK,UAAU,MAAM,GAAG,QAAQ;AAAA,IACpF;AACA,WAAO,EAAE,MAAM,KAAK,UAAU,MAAM,GAAG,QAAQ;AAAA,EACjD;AACA,SAAO;AAAA,IACL,MAAM,OAAO,WAAW,WAAW,SAAS,UAAU,OAAO,KAAK,KAAK,UAAU,MAAM;AAAA,IACvF,SAAS;AAAA,EACX;AACF;AAeO,SAAS,kBAAkB,KAA6B;AAC7D,MAAI,OAAO,QAAQ,UAAU;AAC3B,QAAI,IAAI,WAAW,YAAY,GAAG;AAChC,aAAO;AAAA,IACT;AAEA,QAAI,IAAI,WAAW,GAAG,KAAK,IAAI,WAAW,GAAG,GAAG;AAC9C,YAAM,SAAS,aAAa,GAAG;AAC/B,UAAI,WAAW,UAAa,WAAW,KAAK;AAC1C,eAAO,kBAAkB,MAAM;AAAA,MACjC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,eAAW,SAAS,KAAK;AACvB,YAAM,MAAM,kBAAkB,KAAK;AACnC,UAAI,KAAK;AACP,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,WAAO;AAAA,EACT;AACA,QAAM,SAAS;AAEf,QAAM,WAAW,OAAO,aAAa,OAAO;AAC5C,MAAI,OAAO,aAAa,YAAY,SAAS,WAAW,YAAY,GAAG;AACrE,WAAO;AAAA,EACT;AACA,MAAI,YAAY,OAAO,aAAa,UAAU;AAC5C,UAAM,MAAO,SAAqC;AAClD,QAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,YAAY,GAAG;AAC3D,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO;AACrB,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,YAAY,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;AAC1E,UAAM,SAAS,cAAc,MAAM,IAAI;AACvC,QAAI,QAAQ;AACV,aAAO,QAAQ,SAAS,WAAW,MAAM;AAAA,IAC3C;AACA,QAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,SAAS,GAAG;AAE3D,aAAO,QAAQ,SAAS,WAAW,MAAM,IAAI;AAAA,IAC/C;AAAA,EACF;AACA,SAAO;AACT;AAIA,SAAS,cAAc,MAA8B;AACnD,QAAM,SAAS,CAAC,MACd,OAAO,MAAM,YAAY,OAAO,UAAU,CAAC,KAAK,KAAK,KAAK,KAAK;AACjE,MAAI,QAAyB;AAC7B,MAAI,MAAM,QAAQ,IAAI,KAAK,KAAK,MAAM,MAAM,GAAG;AAC7C,YAAQ;AAAA,EACV,WAAW,QAAQ,OAAO,SAAS,UAAU;AAC3C,UAAM,SAAS;AACf,QAAI,OAAO,SAAS,YAAY,MAAM,QAAQ,OAAO,IAAI,KAAK,OAAO,KAAK,MAAM,MAAM,GAAG;AACvF,cAAQ,OAAO;AAAA,IACjB,OAAO;AACL,YAAM,OAAO,OAAO,KAAK,MAAM;AAC/B,UAAI,KAAK,SAAS,KAAK,KAAK,MAAM,CAAC,QAAQ,QAAQ,KAAK,GAAG,CAAC,GAAG;AAC7D,cAAM,SAAS,KAAK,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,OAAO,GAAG,CAAC;AAClF,YAAI,OAAO,MAAM,MAAM,GAAG;AACxB,kBAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,WAAO;AAAA,EACT;AACA,MAAI;AACF,QAAI,SAAS;AACb,UAAM,QAAQ;AACd,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,OAAO;AAC5C,gBAAU,OAAO,aAAa,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC;AAAA,IAC5D;AACA,WAAO,OAAO,SAAS,aACnB,KAAK,MAAM,IACX,OAAO,KAAK,QAAQ,QAAQ,EAAE,SAAS,QAAQ;AAAA,EACrD,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;;;ACtYA,SAAS,YAAY,eAAe,wBAAwB;AAC5D,SAAS,YAAAC,iBAAgC;AACzC,SAAS,mBAAmB;;;ACF5B,SAAS,eAAe,kBAAkC;AA+BtD;AAdJ,IAAM,4BAA4B,cAAmC,MAAS;AAMvE,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AACF,GAGG;AACD,SACE,oBAAC,0BAA0B,UAA1B,EAAmC,OAAO,aACxC,UACH;AAEJ;AAMO,SAAS,uBAA4C;AAC1D,SAAO,WAAW,yBAAyB;AAC7C;;;AC3CA,SAAS,aAAa;AACtB,SAAS,iBAAiB,cAAc;AACxC,SAAS,iBAAAC,gBAAe,eAAAC,cAAa,cAAAC,aAAY,SAAS,YAAAC,iBAAgC;AAC1F,SAAS,cAAc;AAmDZ,0BAAAC,MA6DS,YA7DT;AA/BX,IAAM,kBAAkBC,eAAyC,IAAI;AAG9D,SAAS,cAAkC;AAChD,SAAOC,YAAW,eAAe,KAAK;AACxC;AAOO,SAAS,sBAAiD;AAC/D,SAAOA,YAAW,eAAe;AACnC;AAEA,IAAM,OAA2B,EAAE,MAAM,MAAM;AAAC,EAAE;AAY3C,SAAS,iBAAiB,EAAE,SAAS,GAA4B;AACtE,QAAM,WAAWA,YAAW,eAAe;AAC3C,MAAI,UAAU;AACZ,WAAO,gBAAAF,KAAA,YAAG,UAAS;AAAA,EACrB;AACA,SAAO,gBAAAA,KAAC,gBAAc,UAAS;AACjC;AAEA,SAAS,aAAa,EAAE,SAAS,GAA4B;AAC3D,QAAM,CAAC,OAAO,QAAQ,IAAIG,UAAmD,IAAI;AAEjF,QAAM,OAAOC,aAAY,CAAC,KAAa,YAAqB;AAC1D,aAAS,UAAU,EAAE,KAAK,QAAQ,IAAI,EAAE,IAAI,CAAC;AAAA,EAC/C,GAAG,CAAC,CAAC;AAEL,QAAM,aAAa,QAA4B,OAAO,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC;AAEvE,SACE,qBAAC,gBAAgB,UAAhB,EAAyB,OAAO,YAC9B;AAAA;AAAA,IACD,gBAAAJ,KAAC,OAAO,MAAP,EAAY,MAAM,UAAU,MAAM,cAAc,CAAC,SAAS,CAAC,QAAQ,SAAS,IAAI,GAC/E,0BAAAA,KAAC,mBACE,oBAAU,OACT,qBAAC,OAAO,QAAP,EAAc,YAAU,MACvB;AAAA,sBAAAA,KAAC,OAAO,SAAP,EAAe,SAAO,MAAC,YAAU,MAChC,0BAAAA;AAAA,QAAC,OAAO;AAAA,QAAP;AAAA,UACC,SAAS,EAAE,SAAS,EAAE;AAAA,UACtB,SAAS,EAAE,SAAS,EAAE;AAAA,UACtB,MAAM,EAAE,SAAS,EAAE;AAAA,UACnB,YAAY,EAAE,UAAU,KAAK;AAAA,UAC7B,WAAU;AAAA;AAAA,MACZ,GACF;AAAA,MACA,gBAAAA;AAAA,QAAC,OAAO;AAAA,QAAP;AAAA,UACC,SAAO;AAAA,UACP,YAAU;AAAA,UACV,cAAW;AAAA,UACX,iBAAiB,CAAC,UAAU,MAAM,eAAe;AAAA,UAEjD;AAAA,YAAC,OAAO;AAAA,YAAP;AAAA,cACC,SAAS,EAAE,SAAS,GAAG,OAAO,KAAK;AAAA,cACnC,SAAS,EAAE,SAAS,GAAG,OAAO,EAAE;AAAA,cAChC,MAAM,EAAE,SAAS,GAAG,OAAO,KAAK;AAAA,cAChC,YAAY,EAAE,UAAU,MAAM,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE;AAAA,cAOtD,SAAS,CAAC,UAAU;AAClB,oBAAI,MAAM,WAAW,MAAM,eAAe;AACxC,2BAAS,IAAI;AAAA,gBACf;AAAA,cACF;AAAA,cACA,WAAU;AAAA,cAEV;AAAA,gCAAAA,KAAC,OAAO,OAAP,EAAa,WAAU,WAAU,wBAAU;AAAA,gBAM5C,qBAAC,YAAO,WAAU,6DAChB;AAAA,uCAAC,SAAI,WAAU,0CAEb;AAAA,oCAAAA;AAAA,sBAAC;AAAA;AAAA,wBACC,KAAK,MAAM;AAAA,wBACX,KAAK,MAAM,WAAW;AAAA,wBACtB,WAAU;AAAA;AAAA,oBACZ;AAAA,oBACA,gBAAAA;AAAA,sBAAC,OAAO;AAAA,sBAAP;AAAA,wBACC,WAAW;AAAA,0BACT;AAAA,0BACA;AAAA,0BACA;AAAA,wBACF;AAAA,wBACA,cAAW;AAAA,wBAEX,0BAAAA,KAAC,SAAM,WAAU,UAAS;AAAA;AAAA,oBAC5B;AAAA,qBACF;AAAA,kBACC,MAAM,UACL,gBAAAA,KAAC,gBAAW,WAAU,+DACnB,gBAAM,SACT,IAEA,gBAAAA,KAAC,gBAAW,WAAU,oEAAmE,2CAEzF;AAAA,mBAEJ;AAAA;AAAA;AAAA,UACF;AAAA;AAAA,MACF;AAAA,OACF,IACE,MACN,GACF;AAAA,KACF;AAEJ;;;AFaI,qBAAAK,WAEI,OAAAC,MAFJ,QAAAC,aAAA;AA7EJ,IAAM,YAA8E;AAAA,EAClF,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AACT;AAQO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA,UAAU,eAAe;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AACF,GAA4B;AAO1B,QAAM,WAAW,UAAU,iBAAiB,UAAU,WAAW;AACjE,QAAM,OACJ,aACC,SACI,EAAE,MAAM,OAAO,MAAM,SAAS,IAC/B,YACG,EAAE,MAAM,eAAe,MAAM,cAAc,IAC5C;AAGR,QAAM,oBAAoB,qBAAqB;AAC/C,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,qBAAqB,KAAK;AAC3D,QAAM,UAAU,cAAc,YAAY;AAI1C,QAAM,iBAAiB,WAAW,QAAQ,CAAC;AAkB3C,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA;AAAA;AAAA,IAGA;AAAA,EACF;AAGA,QAAM,QACJ,gBAAAD,MAAAF,WAAA,EACG;AAAA,cACC,gBAAAC,KAAC,oBAAiB,WAAU,qIAAoI,IAEhK,gBAAAA,KAAC,UAAK,WAAU,qBAAoB;AAAA,IAEtC,gBAAAA,KAAC,UAAK,WAAW,GAAG,YAAY,UAAU,QAAQ,CAAC,GAAI,gBAAK;AAAA,IAC5D,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,aAAa;AAAA,UACb,WAAW;AAAA,QACb;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,IACC,kBAAkB,CAAC,QAClB,gBAAAA,KAAC,UAAK,WAAU,wDAAwD,mBAAQ,IAEhF,gBAAAA,KAAC,UAAK,WAAU,UAAS;AAAA,IAI1B,QACC,gBAAAA,KAAC,UAAK,WAAU,iDAAiD,iBAAM,IACrE,QAAQ,CAAC,OACX,gBAAAA,KAAC,UAAK,WAAU,yBACd,0BAAAA,KAAC,QAAK,MAAY,GACpB,IACE;AAAA,KACN;AAKF,QAAM,aAAa,YAAY,cAAc,SAAS,WAAW;AAEjE,MAAI,CAAC,SAAS;AACZ,WACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,UAAU,gBAAgB,GAAG,eAAa,YAC1D,iBACH;AAAA,EAEJ;AAEA,SACE,gBAAAC,MAAC,YAAY,MAAZ,EAAiB,MAAY,cAAc,SAC1C;AAAA,oBAAAD,KAAC,YAAY,SAAZ,EAAoB,SAAO,MAC1B,0BAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,UAAU;AAAA,QAIV,WAAW,CAAC,UAAU;AACpB,cAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;AAC9C,kBAAM,eAAe;AACrB,oBAAQ,CAAC,SAAS,CAAC,IAAI;AAAA,UACzB;AAAA,QACF;AAAA,QACA,eAAa;AAAA,QACb,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEC;AAAA;AAAA,IACH,GACF;AAAA,IACA,gBAAAA,KAAC,YAAY,SAAZ,EAAoB,WAAU,+FAC7B,0BAAAA,KAAC,SAAI,WAAU,wCAAwC,UAAS,GAClE;AAAA,KACF;AAEJ;AAQA,SAAS,KAAK,EAAE,KAAK,GAA6B;AAChD,QAAM,OAAO;AACb,QAAM,WAAW,KAAK,OAAO,YAAY;AACzC,MAAI,KAAK,SAAS,OAAO;AACvB,WACE,gBAAAC,MAAC,UAAK,WAAW,GAAG,MAAM,UAAU,uBAAuB,GACzD;AAAA,sBAAAD,KAAC,UAAK,WAAU,6CAA4C;AAAA,MAC3D,KAAK;AAAA,OACR;AAAA,EAEJ;AAIA,MAAI,KAAK,SAAS,eAAe;AAC/B,WAAO,gBAAAA,KAAC,UAAK,WAAW,GAAG,MAAM,qCAAqC,GAAI,eAAK,MAAK;AAAA,EACtF;AAEA,SAAO,gBAAAA,KAAC,UAAK,WAAW,GAAG,MAAM,mBAAmB,GAAI,eAAK,MAAK;AACpE;AAIO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAoBG;AACD,QAAM,CAAC,MAAM,OAAO,IAAIE,UAAS,KAAK;AACtC,QAAM,QAAQ,OAAO,KAAK,MAAM;AAChC,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,MAAM,MAAM,SAAS,YAAY;AACvC,QAAM,QAAQ,QAAQ,CAAC,MAAM,SAAS,MAAM,MAAM,CAAC,SAAS,EAAE,KAAK,IAAI;AACvE,QAAM,WAAW,OAAO,CAAC;AACzB,QAAM,aAAa,WAAW,QAAQ,WAAW;AAMjD,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,SACI,+BACA,OACE,gCACA;AAAA,MACR;AAAA,MAEC;AAAA,qBACC,gBAAAA,MAAC,SAAI,WAAU,gCACb;AAAA,0BAAAD,KAAC,UAAK,WAAU,mCAAkC,eAAC;AAAA,UAClD,WAAW,OACV,gBAAAA,KAAC,UAAK,WAAU,oEACb,mBACH,IAEA,gBAAAA,KAAC,UAAK,WAAU,UAAS;AAAA,UAE1B,UACC,gBAAAA,KAAC,UAAK,WAAU,sDAAsD,mBAAQ,IAC5E;AAAA,WACN,IACE;AAAA,QACH,QACC,gBAAAA,KAAC,OAAE,WAAU,oDAAmD,yBAAW,IAE3E,gBAAAC,MAAC,SAAI,WAAU,2GACZ;AAAA;AAAA,UACA,OACC,gBAAAD,KAAC,UAAK,WAAU,mGAAkG,IAChH;AAAA,WACN;AAAA,QAED,WACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM,QAAQ,IAAI;AAAA,YAC3B,WAAU;AAAA,YACX;AAAA;AAAA,cACoB,MAAM;AAAA,cAAO;AAAA;AAAA;AAAA,QAClC,IACE;AAAA;AAAA;AAAA,EACN;AAEJ;AAIO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,iBAAiB,KAAK;AACvE,MAAI,CAAC,QAAQ,KAAK,KAAK,MAAM,IAAI;AAC/B,WAAO;AAAA,EACT;AAIA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,SAAS,+BAA+B;AAAA,MAC1C;AAAA,MAEA;AAAA,wBAAAD,KAAC,OAAE,WAAU,6EACV,iBACH;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,SAAS,0BAA0B;AAAA,YACrC;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAGO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AACF,GAGG;AACD,MAAI,SAAS,SAAS;AAGpB,WACE,gBAAAA,KAAC,SAAI,WAAU,sGACZ,UACH;AAAA,EAEJ;AACA,SAAO,gBAAAA,KAAC,OAAE,WAAU,wDAAwD,UAAS;AACvF;AASA,IAAM,YAAY;AAOX,SAAS,gBAAgB;AAC9B,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAD,KAAC,UAAK,WAAU,wDAAuD;AAAA,QACvE,gBAAAA,KAAC,cAAW,WAAU,uCAAsC;AAAA;AAAA;AAAA,EAC9D;AAEJ;AAGO,SAAS,aAAa;AAC3B,SACE,gBAAAA,KAAC,UAAK,WAAW,GAAG,WAAW,kDAAkD,GAC/E,0BAAAA,KAAC,iBAAc,WAAU,8BAA6B,GACxD;AAEJ;AASO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA,MAAM;AACR,GAIG;AACD,QAAM,WAAW,oBAAoB;AACrC,QAAM,CAAC,QAAQ,SAAS,IAAIE,UAAS,KAAK;AAC1C,MAAI,QAAQ;AACV,WAAO,gBAAAF,KAAC,cAAW;AAAA,EACrB;AAGA,QAAM,MACJ,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,SAAS,MAAM,UAAU,IAAI;AAAA,MAC7B,WAAU;AAAA;AAAA,EACZ;AAEF,MAAI,CAAC,UAAU;AACb,WAAO,gBAAAA,KAAC,UAAK,WAAW,GAAG,WAAW,sCAAsC,GAAI,eAAI;AAAA,EACtF;AAIA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,CAAC,UAAU;AAClB,cAAM,gBAAgB;AACtB,iBAAS,KAAK,KAAK,OAAO;AAAA,MAC5B;AAAA,MACA,WAAW,CAAC,UAAU;AACpB,YAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;AAC9C,gBAAM,gBAAgB;AAAA,QACxB;AAAA,MACF;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,cAAW;AAAA,MAEV;AAAA;AAAA,EACH;AAEJ;AAQO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA,MAAM;AACR,GAIG;AACD,QAAM,WAAW,oBAAoB;AACrC,QAAM,CAAC,QAAQ,SAAS,IAAIE,UAAS,KAAK;AAC1C,QAAM,UAAU;AAGhB,QAAM,MACJ,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,SAAS,MAAM,UAAU,IAAI;AAAA,MAC7B,WAAU;AAAA;AAAA,EACZ;AAEF,SACE,gBAAAC,MAAC,YAAO,WAAU,eACf;AAAA,aACC,gBAAAD,KAAC,SAAI,WAAU,kHAAiH,+BAEhI,IACE,WACF,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,SAAS,KAAK,KAAK,OAAO;AAAA,QACzC,WAAW;AAAA,QACX,cAAW;AAAA,QAEV;AAAA;AAAA,IACH,IAEA,gBAAAA,KAAC,SAAI,WAAW,SAAU,eAAI;AAAA,IAE/B,UACC,gBAAAA,KAAC,gBAAW,WAAU,oDACnB,mBACH,IACE;AAAA,KACN;AAEJ;;;AGzjBA,SAAS,YAAAG,iBAAgB;;;ACDzB,SAAS,WAAW,YAAAC,iBAAgB;AAoB7B,SAAS,aAAa,QAAwD;AACnF,QAAM,CAAC,UAAU,WAAW,IAAIA,UAA2B,MAAM;AACjE,YAAU,MAAM;AACd,QAAI,UAAU,OAAO,aAAa,YAAa;AAC/C,UAAM,OAAO,MAAM;AACjB,YAAM,KAAK,SAAS,cAAc,iBAAiB;AACnD,YAAM,QAAQ,IAAI,aAAa,eAAe;AAC9C,kBAAY,UAAU,UAAU,UAAU,MAAM;AAAA,IAClD;AACA,SAAK;AACL,UAAM,WAAW,IAAI,iBAAiB,IAAI;AAC1C,aAAS,QAAQ,SAAS,iBAAiB;AAAA,MACzC,YAAY;AAAA,MACZ,iBAAiB,CAAC,eAAe;AAAA,MACjC,SAAS;AAAA,IACX,CAAC;AACD,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,MAAM,CAAC;AACX,SAAO,UAAU;AACnB;;;ACtCA;AAAA,EAIE;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA,YAAAC;AAAA,OACK;;;ACDA,SAAS,mBAAmB,MAA2B;AAC5D,QAAM,UAAU,KAAK,WAAW,KAAK;AACrC,QAAM,UAAU,KAAK;AACrB,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,gBAAgB,OAAO,MAAM,OAAO,EAAE;AACjD,MAAI,KAAK,WAAW,WAAW;AAC7B,UAAM,KAAK,SAAS,OAAO,EAAE;AAC7B,UAAM,KAAK,eAAe;AAAA,EAC5B,WAAW,KAAK,WAAW,WAAW,KAAK,WAAW,aAAa;AACjE,UAAM,KAAK,eAAe;AAC1B,UAAM,KAAK,SAAS,OAAO,EAAE;AAAA,EAC/B,OAAO;AACL,UAAM,KAAK,SAAS,OAAO,EAAE;AAC7B,UAAM,KAAK,SAAS,OAAO,EAAE;AAAA,EAC/B;AACA,aAAW,QAAQ,KAAK,OAAO;AAO7B,UAAM,gBAAgB,sCAAsC,KAAK,KAAK,UAAU,EAAE;AAClF,UAAM,SAAS,gBACX,KAAK,SACL,OAAO,KAAK,QAAQ,IAAI,KAAK,QAAQ,KAAK,KAAK,QAAQ,IAAI,KAAK,QAAQ;AAC5E,UAAM,KAAK,MAAM;AACjB,eAAW,QAAQ,KAAK,OAAO;AAC7B,UAAI,KAAK,SAAS,OAAQ;AAC1B,YAAM,SAAS,KAAK,SAAS,QAAQ,MAAM,KAAK,SAAS,QAAQ,MAAM;AACvE,YAAM,KAAK,GAAG,MAAM,GAAG,KAAK,IAAI,EAAE;AAAA,IACpC;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;;;ADwDmD,gBAAAC,YAAA;AA5CnD,IAAM,gBAAgB,KAAK,YAAY;AACrC,QAAM,MAAO,MAAM,OAAO,qBAAqB;AAG/C,SAAO,EAAE,SAAS,IAAI,UAAU;AAClC,CAAC;AAQM,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AACF,GAAoB;AAClB,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,KAAK;AAI1C,EAAAC,WAAU,MAAM;AACd,QAAI,MAAO;AACX,QAAI,YAAY;AAChB,SAAK,OAAO,qBAAqB,EAAE,MAAM,MAAM;AAC7C,UAAI,CAAC,UAAW,WAAU,IAAI;AAAA,IAChC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,MAAI,SAAS,QAAQ;AAInB,WAAO,gBAAAF,KAAC,SAAI,WAAuB,sBAAY,gBAAAA,KAAC,cAAW,MAAY,GAAG;AAAA,EAC5E;AAKA,QAAM,UAAU;AAAA,IACd,WAAW;AAAA,IACX;AAAA,IACA,cAAc;AAAA,IACd,GAAI,QACA,EAAE,MAAM,IACR;AAAA,MACE,OAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACJ,WAAW,aAAa;AAAA,EAC1B;AAMA,QAAM,aAAa;AAAA,IACjB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,8BAA8B;AAAA,IAC9B,iCAAiC;AAAA,IACjC,mCAAmC;AAAA,IACnC,mCAAmC;AAAA,IACnC,uCAAuC;AAAA,IACvC,uCAAuC;AAAA,IACvC,gCACE;AAAA,IACF,gCACE;AAAA,IACF,yCACE;AAAA,IACF,yCACE;AAAA,IACF,qBAAqB;AAAA,IACrB,uBAAuB;AAAA,EACzB;AAEA,SACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,WAAW,SAAS,GAAG,6BAAyB,MAAC,OAAO,YACzE,0BAAAA,KAAC,YAAS,UAAU,WAAW,gBAAAA,KAAC,gBAAa,GAC1C,eAAK,IAAI,CAAC,SACT,gBAAAA,KAAC,SAAoB,WAAU,QAC7B,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,mBAAmB,IAAI;AAAA,MAC9B;AAAA,MACC,GAAI,sBAAsB,SAAY,EAAE,kBAAkB,IAAI,CAAC;AAAA;AAAA,EAClE,KALQ,KAAK,IAMf,CACD,GACH,GACF;AAEJ;AAEA,SAAS,eAAe;AACtB,SAAO,gBAAAA,KAAC,SAAI,WAAU,oCAAmC,gCAAa;AACxE;AAOA,SAAS,WAAW,EAAE,KAAK,GAA4B;AACrD,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,gBAAAA,KAAC,SAAI,WAAU,oCAAmC,wBAAU;AAAA,EACrE;AACA,SACE,gBAAAA,KAAC,SAAI,WAAU,WACZ,eAAK,IAAI,CAAC,SACT,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEC,WAAU;AAAA,MAET,6BAAmB,IAAI,EACrB,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,UACV,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAIC,WAAW;AAAA,YACT;AAAA,YACA,KAAK,WAAW,IAAI,IAChB,mBACA,KAAK,WAAW,GAAG,IACjB,wBACA,KAAK,WAAW,GAAG,IACjB,0BACA;AAAA,UACV;AAAA,UAEC,kBAAQ;AAAA;AAAA,QAZJ;AAAA,MAaP,CACD;AAAA;AAAA,IAvBE,KAAK;AAAA,EAwBZ,CACD,GACH;AAEJ;;;AFvLI,SAEI,OAAAG,MAFJ,QAAAC,aAAA;AAPG,SAAS,SAAS,EAAE,MAAM,GAA6B;AAC5D,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAA8B,SAAS;AAInE,QAAM,YAAY,aAAa,MAAS;AACxC,SACE,gBAAAD,MAAC,SAAI,WAAU,WACb;AAAA,oBAAAD,KAAC,SAAI,WAAU,2BACb,0BAAAA,KAAC,gBAAa,QAAgB,UAAU,WAAW,GACrD;AAAA,IACA,gBAAAA,KAAC,cAAW,MAAM,OAAO,QAAgB,WAAsB;AAAA,KACjE;AAEJ;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AACF,GAGG;AACD,SACE,gBAAAA,KAAC,SAAI,WAAU,8EACX,WAAC,WAAW,OAAO,EAAY,IAAI,CAAC,UACpC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,SAAS,KAAK;AAAA,MAC7B,WAAW;AAAA,QACT;AAAA,QACA,WAAW,QACP,+BACA;AAAA,MACN;AAAA,MAEC;AAAA;AAAA,IAVI;AAAA,EAWP,CACD,GACH;AAEJ;AAGO,SAAS,SAAS,EAAE,KAAK,GAAqB;AACnD,QAAM,cAAc,oBAAI,IAAoB;AAC5C,QAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,IAAI,CAAC,SAAS;AAC3C,UAAM,cAAc,YAAY,IAAI,IAAI,KAAK,KAAK;AAClD,gBAAY,IAAI,MAAM,UAAU;AAChC,WAAO,EAAE,KAAK,GAAG,IAAI,KAAS,UAAU,IAAI,KAAK;AAAA,EACnD,CAAC;AACD,SACE,gBAAAC,MAAC,SAAI,WAAU,WACb;AAAA,oBAAAD,KAAC,OAAE,WAAU,6EAA4E,+CAEzF;AAAA,IACA,gBAAAA,KAAC,SAAI,WAAU,6FACZ,gBAAM,IAAI,CAAC,EAAE,KAAK,KAAK,MACtB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW;AAAA,UACT;AAAA,UACA,KAAK,WAAW,IAAI,IAChB,mBACA,KAAK,WAAW,GAAG,IACjB,wBACA,KAAK,WAAW,GAAG,IACjB,0BACA;AAAA,QACV;AAAA,QAEC,kBAAQ;AAAA;AAAA,MAZJ;AAAA,IAaP,CACD,GACH;AAAA,KACF;AAEJ;;;ALlBI,SACE,OAAAG,MADF,QAAAC,aAAA;AAVJ,IAAM,YAAY;AAQlB,SAAS,eAAe,EAAE,SAAS,GAA4B;AAC7D,SACE,gBAAAA,MAAC,UAAK,WAAU,oCACd;AAAA,oBAAAD,KAAC,UAAK,WAAU,wEAAuE;AAAA,IACvF,gBAAAA,KAAC,UAAK,WAAU,oBAAoB,UAAS;AAAA,KAC/C;AAEJ;AAIA,SAAS,aAAa,EAAE,KAAK,GAAsB;AACjD,QAAM,OAAO,cAAc,KAAK,SAAS;AACzC,QAAM,MAAM,OAAO,KAAK,QAAQ,WAAW,KAAK,MAAM;AACtD,QAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;AAClE,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,MAAM,KAAK;AACjB,QAAM,QAAQ,KAAK,GAAG;AAMtB,MAAI,KAAK,WAAW,YAAY,QAAQ,QAAW;AACjD,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT;AAAA,QACA,WAAS;AAAA,QACT,MAAM,EAAE,MAAM,OAAO,MAAM,SAAS;AAAA,QACpC,SAAQ;AAAA,QAER,0BAAAA,KAAC,YAAS,MAAK,SAAQ,oJAGvB;AAAA;AAAA,IACF;AAAA,EAEJ;AAKA,MAAI,KAAK,WAAW,aAAa,OAAO,QAAQ,QAAQ,KAAK;AAC3D,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT;AAAA,QACA,WAAS;AAAA,QACT,MAAM,EAAE,MAAM,OAAO,MAAM,SAAS;AAAA,QACpC,SAAQ;AAAA,QAER,0BAAAA,KAAC,YAAS,MAAK,SAAQ,kDAAoC;AAAA;AAAA,IAC7D;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,UAAM,WAAW,OAAO,QAAQ,WAAW,gBAAgB,GAAG,IAAI;AAClE,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT;AAAA,QACA,WAAS;AAAA,QACT,SAAO;AAAA,QACP,SACE,gBAAAA,KAAC,kBACE,qBAAW,GAAG,SAAS,MAAM,IAAI,EAAE,MAAM,WAAW,iBACvD;AAAA,QAKF,0BAAAA,KAAC,aAAU,SAAS,MAAM,SAAkB,QAAQ,UAAU,MAAI,MAAC;AAAA;AAAA,IACrE;AAAA,EAEJ;AAEA,QAAM,OAAO,OAAO,QAAQ,WAAW,MAAM,iBAAiB,GAAG;AACjE,QAAM,WAAW,gBAAgB,IAAI;AACrC,QAAM,YAAY,yBAAyB,IAAI;AAC/C,QAAM,WAAW,uBAAuB,IAAI;AAC5C,QAAM,SAAS,YAAY,QAAQ;AAKnC,MAAI;AACJ,MAAI,WAA0C;AAC9C,MAAI,aAAa,MAAM;AACrB,WAAO,EAAE,MAAM,SAAS,MAAM,WAAW,SAAS,GAAG;AAAA,EACvD,WAAW,YAAY,QAAQ,aAAa,GAAG;AAC7C,WAAO,EAAE,MAAM,OAAO,MAAM,QAAQ,QAAQ,GAAG;AAC/C,eAAW;AAAA,EACb;AAEA,QAAM,UAAU,SAAS,kBAAkB,SAAS,QAAQ,KAAK;AACjE,QAAM,YAAY,cAAc,IAAI;AAEpC,QAAM,OAAO,SAAS,+BAA+B;AAErD,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAD,KAAC,gBAAa,WAAW,WAAW;AAAA,MAC1C;AAAA,MACA;AAAA,MACA,WAAS;AAAA,MACR,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACxB,QAAQ,KAAK,WAAW;AAAA,MACxB,WAAW,KAAK,WAAW;AAAA,MAC3B,SAAS,YAAY,yBAAiB,OAAO,KAAK;AAAA,MAElD;AAAA,wBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT;AAAA,YACA,QAAQ;AAAA,YACR,QAAQ,KAAK,WAAW,YAAa,YAAY,QAAQ,aAAa;AAAA;AAAA,QACxE;AAAA,QACC,aAAa,OACZ,gBAAAC,MAAC,YAAS;AAAA;AAAA,UAAW;AAAA,UAAU;AAAA,WAA2C,IACxE;AAAA;AAAA;AAAA,EACN;AAEJ;AAIA,SAAS,mBAAmB,EAAE,KAAK,GAAsB;AACvD,QAAM,OAAO,cAAc,KAAK,SAAS;AACzC,QAAM,YACJ,OAAO,KAAK,eAAe,YAAY,OAAO,KAAK,eAAe,WAC9D,KAAK,aACL;AACN,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,OAAO,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,iBAAiB,KAAK,MAAM;AACzF,QAAM,OAAO,wBAAwB,IAAI;AACzC,QAAM,OAAO,aAAa,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,EAAE;AAC1E,QAAM,WAAW,uBAAuB,IAAI;AAC5C,QAAM,WAAW,gBAAgB,IAAI;AAErC,MAAI,SAAS;AACX,WACE,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,WAAW,SAAS,WAAM,QAAQ,QAAG;AAAA,QAC5C,WAAS;AAAA,QACT,SAAO;AAAA,QACP,SAAS,gBAAAA,KAAC,kBAAe,2BAAQ;AAAA,QAEjC,0BAAAC,MAAC,YAAS;AAAA;AAAA,UAA0B;AAAA,UAAU;AAAA,WAAC;AAAA;AAAA,IACjD;AAAA,EAEJ;AAIA,MAAI;AACJ,MAAI,MAAM;AACR,WAAO,EAAE,MAAM,OAAO,MAAM,OAAO;AAAA,EACrC,WAAW,YAAY,QAAQ,aAAa,GAAG;AAC7C,WAAO,EAAE,MAAM,OAAO,MAAM,QAAQ,QAAQ,GAAG;AAAA,EACjD;AAEA,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,MAC1C,UAAU,OAAO,WAAW;AAAA,MAC5B,OAAO,WAAW,SAAS,WAAM,QAAQ,QAAG;AAAA,MAC5C,WAAS;AAAA,MACR,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACxB,QAAQ,KAAK,WAAW;AAAA,MACxB,WAAW,KAAK,WAAW;AAAA,MAC3B,SAAS,OAAO,WAAW,SAAS,kBAAkB,SAAS,QAAQ,KAAK;AAAA,MAE3E,iBACC,gBAAAA,KAAC,YAAS,MAAK,SAAS,sBAAY,MAAK,IAEzC,gBAAAA,KAAC,aAAU,SAAS,8BAAyB,SAAS,IAAI,QAAQ,UAAU;AAAA;AAAA,EAEhF;AAEJ;AAIA,SAAS,UAAU,IAA6C;AAC9D,MAAI,CAAC,IAAI;AACP,WAAO;AAAA,EACT;AACA,SAAO,GAAG,SAAS,gBACf,YACA,GAAG,SAAS,gBACV,YACA,GAAG,SACD,YACA;AACV;AAEA,SAAS,SAAS,MAAsB;AACtC,QAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAC5C,SAAO,MAAM,SAAS,MAAM,MAAM,SAAS,CAAC,IAAK;AACnD;AAEA,SAAS,QAAQ,MAAsB;AACrC,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,SAAO,OAAO,IAAI,KAAK,MAAM,GAAG,MAAM,CAAC,IAAI;AAC7C;AAQA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,gBAAAC,MAAC,UAAK,WAAU,wDACd;AAAA,oBAAAA,MAAC,UAAK,WAAU,YACd;AAAA,sBAAAD,KAAC,UAAK,WAAU,qBAAqB,kBAAQ,IAAI,GAAE;AAAA,MACnD,gBAAAA,KAAC,UAAK,WAAU,oBAAoB,mBAAS,IAAI,GAAE;AAAA,OACrD;AAAA,IACC,OAAO,QAAQ,OAAO,OACrB,gBAAAC,MAAC,UAAK,WAAU,8BACb;AAAA,aAAO,OAAO,IAAI,GAAG,KAAK;AAAA,MAC1B,OAAO,QAAQ,OAAO,OAAO,MAAM;AAAA,MACnC,OAAO,OAAO,SAAI,GAAG,KAAK;AAAA,OAC7B,IACE;AAAA,KACN;AAEJ;AAEA,SAAS,mBAAmB,EAAE,KAAK,GAAsB;AACvD,QAAM,MAAM,cAAc,KAAK,GAAG;AAClC,QAAM,SAAS,KAAK,WAAW;AAC/B,QAAM,YAAY,KAAK,WAAW;AAClC,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,UAAU,IAAI,CAAC;AAErB,MAAI,SAAS;AAGX,UAAM,YAAY,IAAI;AACtB,UAAM,YAAY,UAAU,YAAY,SAAS,QAAQ,IAAI,CAAC,KAAK;AACnE,WACE,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,YAAY,IAAI,YAAY,SAAS,WAAW;AAAA,QACvD,SAAO;AAAA,QACP,SACE,gBAAAA,KAAC,kBACE,sBAAY,IAAI,GAAG,SAAS,WAAW,UAAU,QAAQ,OAAO,kBACnE;AAAA,QAGD,cAAI,IAAI,CAAC,OAAO;AACf,gBAAME,QAAO,YAAY,EAAE;AAC3B,iBAAOA,QACL,gBAAAF,KAAC,YAAuB,OAAO,CAACE,KAAI,KAArB,GAAG,IAAqB,IAEvC,gBAAAD,MAAC,SACC;AAAA,4BAAAD,KAAC,OAAE,WAAU,iDAAiD,aAAG,MAAK;AAAA,YACtE,gBAAAA,KAAC,YAAS,MAAM,GAAG,QAAQ,IAAI;AAAA,eAFvB,GAAG,IAGb;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,QAAQ;AACV,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,UAAU,GAAG,UAAU,OAAO,CAAC,IAAI,SAAS,QAAQ,IAAI,CAAC,KAAK;AAAA,QACrE,MAAM,EAAE,MAAM,OAAO,MAAM,SAAS;AAAA,QACpC,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAAA,QAEzD,0BAAAA,KAAC,gBAAa,OAAM,SAAQ,OAAO,KAAK,QAAQ,QAAM,MAAC;AAAA;AAAA,IACzD;AAAA,EAEJ;AAIA,MAAI,IAAI,SAAS,GAAG;AAKlB,UAAM,SAAS,IAAI,IAAI,CAAC,OAAO,YAAY,EAAE,CAAC;AAC9C,UAAM,YAAY,OAAO,OAAO,CAAC,MAAwB,MAAM,IAAI;AACnE,UAAM,MAAM,UAAU,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,WAAW,CAAC;AACzD,UAAM,MAAM,UAAU,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,WAAW,CAAC;AACzD,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,UAAU,IAAI,MAAM;AAAA,QAC3B;AAAA,QACA,SACE,gBAAAC,MAAC,UAAK,WAAU,+CACd;AAAA,0BAAAA,MAAC,UAAK,WAAU,oBAAoB;AAAA,gBAAI;AAAA,YAAO;AAAA,aAAM;AAAA,UACrD,gBAAAA,MAAC,UAAK,WAAU,qBAAoB;AAAA;AAAA,YAChC;AAAA,YAAI;AAAA,YAAG;AAAA,aACX;AAAA,WACF;AAAA,QAGD,cAAI,IAAI,CAAC,IAAI,UAAU;AACtB,gBAAMC,QAAO,OAAO,KAAK;AACzB,iBAAOA,QACL,gBAAAF,KAAC,YAAuB,OAAO,CAACE,KAAI,KAArB,GAAG,IAAqB,IAEvC,gBAAAD,MAAC,SACC;AAAA,4BAAAD,KAAC,OAAE,WAAU,iDAAiD,aAAG,MAAK;AAAA,YACtE,gBAAAA,KAAC,YAAS,MAAM,GAAG,QAAQ,IAAI;AAAA,eAFvB,GAAG,IAGb;AAAA,QAEJ,CAAC;AAAA;AAAA,IACH;AAAA,EAEJ;AAGA,MAAI,CAAC,SAAS;AACZ,WAAO,gBAAAA,KAAC,mBAAgB,MAAY;AAAA,EACtC;AACA,MAAI,QAAQ,SAAS,eAAe;AAClC,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,WAAW,SAAS,QAAQ,IAAI,CAAC;AAAA,QACxC;AAAA,QACA,SAAS,gBAAAA,KAAC,eAAY,MAAM,QAAQ,MAAM;AAAA,QAE1C,0BAAAA,KAAC,YAAS,kDAA+B;AAAA;AAAA,IAC3C;AAAA,EAEJ;AAEA,QAAM,OAAO,YAAY,OAAO;AAChC,MAAI,CAAC,MAAM;AACT,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,GAAG,UAAU,OAAO,CAAC,IAAI,SAAS,QAAQ,IAAI,CAAC;AAAA,QACtD;AAAA,QACA,SACE,gBAAAC,MAAC,UAAK,WAAU,+CACd;AAAA,0BAAAD,KAAC,UAAK,WAAU,oBAAoB,mBAAS,QAAQ,IAAI,GAAE;AAAA,UAC3D,gBAAAA,KAAC,UAAK,WAAU,qBAAoB,2BAAa;AAAA,WACnD;AAAA,QAGF,0BAAAA,KAAC,YAAS,MAAM,QAAQ,QAAQ,IAAI;AAAA;AAAA,IACtC;AAAA,EAEJ;AAKA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,MAC1C,UAAS;AAAA,MACT,OAAO,GAAG,UAAU,OAAO,CAAC,IAAI,SAAS,KAAK,IAAI,CAAC;AAAA,MACnD;AAAA,MACA,SAAS,gBAAAA,KAAC,eAAY,MAAM,KAAK,MAAM,KAAK,KAAK,WAAW,KAAK,KAAK,WAAW;AAAA,MAEjF,0BAAAA,KAAC,YAAS,OAAO,CAAC,IAAI,GAAG;AAAA;AAAA,EAC3B;AAEJ;AAEA,SAAS,YAAY,IAA6C;AAChE,MAAI;AACF,WAAO,iBAAiB,EAAE;AAAA,EAC5B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAaA,SAAS,aAAa,QAA4C;AAChE,MAAI,CAAC,UAAU,CAAC,OAAO,MAAM;AAC3B,WAAO;AAAA,EACT;AACA,UAAQ,OAAO,MAAM;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,YAAY,OAAO,CAAC,KAAK,OAAO,CAAC;AAAA,IAC1C,KAAK;AACH,aAAO,mBAAmB,OAAO,CAAC,KAAK,OAAO,CAAC;AAAA,IACjD,KAAK;AACH,aAAO,UAAU,OAAO,CAAC,KAAK,OAAO,CAAC;AAAA,IACxC,KAAK;AACH,aAAO;AAAA,IACT,KAAK,QAAQ;AACX,YAAM,IAAI,OAAO,QAAQ;AACzB,aAAO,eAAU,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,WAAM,EAAE;AAAA,IAC5D;AAAA,IACA,KAAK;AACH,aAAO,YAAY,OAAO,QAAQ,CAAC,GAAG,KAAK,GAAG,CAAC;AAAA,IACjD,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,OAAO;AAAA,EAClB;AACF;AAGA,SAAS,eAAe,MAAwC;AAC9D,MAAI,CAAC,MAAM;AACT,WAAO,CAAC;AAAA,EACV;AACA,QAAM,SAAS,OAAO,SAAS,WAAW,aAAa,IAAI,IAAI;AAC/D,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,WAAO,CAAC;AAAA,EACV;AACA,QAAM,SAAS;AACf,SAAO;AAAA,IACL,GAAI,OAAO,OAAO,MAAM,WAAW,EAAE,GAAG,OAAO,EAAE,IAAI,CAAC;AAAA,IACtD,GAAI,OAAO,OAAO,MAAM,WAAW,EAAE,GAAG,OAAO,EAAE,IAAI,CAAC;AAAA,IACtD,GAAI,OAAO,OAAO,SAAS,WAAW,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,IAC/D,GAAI,MAAM,QAAQ,OAAO,IAAI,IAAI,EAAE,MAAM,OAAO,KAAiB,IAAI,CAAC;AAAA,IACtE,GAAI,OAAO,OAAO,WAAW,WAAW,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,EACvE;AACF;AAEA,SAAS,qBAAqB,EAAE,KAAK,GAAsB;AACzD,QAAM,MAAO,KAAK,OAAO,CAAC;AAU1B,QAAM,iBACJ,CAAC,IAAI,UAAU,KAAK,KAAK,WAAW,WAAW,KAAK,KAAK,SAAS,kBAC9D,EAAE,MAAM,KAAK,KAAK,MAAM,YAAY,MAAM,GAAG,GAAG,eAAe,KAAK,SAAS,EAAE,IAC/E;AACN,QAAM,SAAS,IAAI,UAAU;AAC7B,QAAM,UAAU,IAAI,YAAY,SAAS,CAAC,MAAM,IAAI,CAAC;AACrD,QAAM,OAAO,aAAa,MAAM;AAChC,QAAM,MAAM,KAAK;AACjB,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,WAAW,IAAI,cAAc,mBAAmB;AACtD,QAAM,WAAW,OAAO,QAAQ,YAAY,IAAI,SAAS,WAAW;AACpE,QAAM,UAAU,kBAAkB,GAAG;AACrC,QAAM,QAAQ,QAAQ,MAAM,OAAO;AACnC,QAAM,UAAU,QAAQ,SAAS,IAAI,QAAQ,IAAI,CAAC,MAAM,aAAa,CAAC,CAAC,EAAE,KAAK,QAAK,IAAI;AAGvF,QAAM,cAAc,QAAQ,SAAS,IAAI,QAAK,QAAQ,MAAM,KAAK;AACjE,QAAM,SAAS,QAAQ,SAAS;AAEhC,MAAI,SAAS;AACX,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MACE,SACE,gBAAAA,KAACG,aAAA,EAAW,WAAW,WAAW,IAElC,gBAAAH,KAAC,qBAAkB,WAAW,WAAW;AAAA,QAG7C,UAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAO;AAAA,QACP,OAAO,gBAAAA,KAAC,iBAAc;AAAA,QAEtB,0BAAAA,KAAC,YAAS,mCAAgB;AAAA;AAAA,IAC5B;AAAA,EAEJ;AAEA,MAAI,UAAU;AACZ,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,qBAAkB,WAAW,WAAW;AAAA,QAC/C,UAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM,EAAE,MAAM,OAAO,MAAM,YAAY;AAAA,QACvC,SAAQ;AAAA,QAER,0BAAAA,KAAC,YAAS,MAAK,SAAQ,0EAAuD;AAAA;AAAA,IAChF;AAAA,EAEJ;AAEA,MAAI,UAAU;AACZ,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,YAAS,WAAW,WAAW;AAAA,QACtC,UAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAQ;AAAA,QAER,0BAAAA,KAAC,YAAS,+DAA4C;AAAA;AAAA,IACxD;AAAA,EAEJ;AAEA,QAAM,WAAW,KAAK,WAAW;AACjC,QAAM,cAAc,KAAK,WAAW;AAEpC,MAAI,SAAS;AACX,UAAM,UAAU,GAAG,IAAI,GAAG,QAAQ,SAAS,IAAI,MAAM,QAAQ,SAAS,CAAC,WAAW,EAAE;AACpF,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MACE,SACE,gBAAAD,KAACG,aAAA,EAAW,WAAW,WAAW,IAElC,gBAAAH,KAAC,qBAAkB,WAAW,WAAW;AAAA,QAG7C,UAAU,WAAW,WAAW;AAAA,QAChC,OAAO,GAAG,IAAI,GAAG,WAAW;AAAA,QAC5B,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,OAAO,gBAAAA,KAAC,aAAU,KAAK,SAAS,SAAkB;AAAA,QAElD;AAAA,0BAAAA,KAAC,oBAAiB,KAAK,SAAS,SAAkB;AAAA,UACjD,UAAU,gBAAAC,MAAC,YAAS;AAAA;AAAA,YAAU;AAAA,aAAQ,IAAc;AAAA;AAAA;AAAA,IACvD;AAAA,EAEJ;AAEA,MAAI,OAAO;AACT,WACE,gBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAACI,gBAAA,EAAc,WAAW,WAAW;AAAA,QAC3C,UAAU,WAAW,WAAW;AAAA,QAChC,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,OAAO,gBAAAJ,KAAC,cAAW;AAAA,QAEnB,0BAAAA,KAAC,YACE,qBACG,mDACA,cACE,wDACA,+DACR;AAAA;AAAA,IACF;AAAA,EAEJ;AAGA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAA,KAAC,qBAAkB,WAAW,WAAW;AAAA,MAC/C,UAAU,WAAW,WAAW;AAAA,MAChC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,SAAS,WAAW;AAAA,MACpB,YAAY,WAAW;AAAA,MAEtB,oBAAU,gBAAAA,KAAC,YAAU,mBAAQ,IAAc;AAAA;AAAA,EAC9C;AAEJ;AAMA,SAAS,kBAAkB,EAAE,KAAK,GAAsB;AACtD,QAAM,MAAO,KAAK,OAAO,CAAC;AAG1B,QAAM,SAAS,IAAI,cAAc,UAAU,CAAC;AAC5C,QAAM,QAAQ,OAAO,SAAS;AAC9B,QAAM,UAAU,OAAO,WAAW,CAAC;AACnC,QAAM,WAAW,QAAQ,SAAS,IAAI,KAAK,QAAQ,SAAS,CAAC,cAAc;AAC3E,QAAM,UAAU,KAAK,WAAW;AAIhC,QAAM,aAAc,KAAK,QAA8C;AACvE,QAAM,UAAU,MAAM,QAAQ,UAAU,IACnC,WAAyB,OAAO,CAAC,MAA4B,CAAC,CAAC,KAAK,OAAO,MAAM,QAAQ,IAC1F;AACJ,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,eAAe,SAAS,IAAI,CAAC,WAAW;AAC5C,UAAM,aAAa,GAAG,OAAO,MAAM,KAAS,OAAO,KAAK,KAAS,OAAO,OAAO;AAC/E,UAAM,cAAc,kBAAkB,IAAI,UAAU,KAAK,KAAK;AAC9D,sBAAkB,IAAI,YAAY,UAAU;AAC5C,WAAO,EAAE,KAAK,GAAG,UAAU,KAAS,UAAU,IAAI,OAAO;AAAA,EAC3D,CAAC;AAED,MAAI,SAAS;AACX,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,cAAW,WAAW,WAAW;AAAA,QACxC,UAAS;AAAA,QACT,OAAM;AAAA,QACN,SAAO;AAAA,QACP,SAAS,gBAAAA,KAAC,kBAAgB,aAAG,KAAK,GAAG,QAAQ,IAAG;AAAA,QAEhD,0BAAAA,KAAC,YAAS,oFAAiE;AAAA;AAAA,IAC7E;AAAA,EAEJ;AAEA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAA,KAAC,cAAW,WAAW,WAAW;AAAA,MACxC,UAAS;AAAA,MACT,OAAM;AAAA,MACN,SAAS,GAAG,KAAK,GAAG,QAAQ;AAAA,MAC5B,QAAQ,KAAK,WAAW;AAAA,MACxB,WAAW,KAAK,WAAW;AAAA,MAE1B,0BAAgB,aAAa,SAC5B,gBAAAA,KAAC,QAAG,WAAU,uBACX,uBAAa,IAAI,CAAC,EAAE,KAAK,OAAO,MAC/B,gBAAAC,MAAC,QAAa,WAAU,gBACtB;AAAA,wBAAAD,KAAC,aAAU,WAAU,8CAA6C;AAAA,QAClE,gBAAAC,MAAC,SAAI,WAAU,WACb;AAAA,0BAAAA,MAAC,OAAE,WAAU,oCACV;AAAA,mBAAO;AAAA,YAAM;AAAA,YAAC,gBAAAD,KAAC,UAAK,WAAU,qBAAqB,iBAAO,QAAO;AAAA,aACpE;AAAA,UACA,gBAAAA,KAAC,OAAE,WAAU,yCAAyC,iBAAO,SAAQ;AAAA,WACvE;AAAA,WAPO,GAQT,CACD,GACH,IAEA,gBAAAA,KAAC,YAAS,yEAAsD;AAAA;AAAA,EAEpE;AAEJ;AAIA,IAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,kBAAkB,EAAE,KAAK,GAAsB;AACtD,QAAM,OAAO,cAAc,KAAK,SAAS;AACzC,QAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,QAAM,MAAM,KAAK;AACjB,QAAM,OAAO,OAAO,QAAQ,WAAW,MAAM;AAE7C,MAAI,KAAK,WAAW,WAAW;AAC7B,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,aAAU,WAAW,WAAW;AAAA,QACvC,UAAS;AAAA,QACT,OAAO,QAAQ,SAAS,IAAI,CAAC;AAAA,QAC7B,SAAO;AAAA,QACP,SAAS,gBAAAA,KAAC,kBAAe,2BAAQ;AAAA,QACjC,OAAO,gBAAAA,KAAC,iBAAc;AAAA,QAEtB,0BAAAA,KAAC,YAAS,iCAAc;AAAA;AAAA,IAC1B;AAAA,EAEJ;AAEA,QAAM,aAAa,KAAK,WAAW;AACnC,QAAM,gBAAgB,KAAK,WAAW;AAEtC,QAAM,WAAW,kBAAkB,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AAC/D,MAAI,UAAU;AACZ,UAAM,SAAS,KAAK,SAAS,2BAA2B;AACxD,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,aAAU,WAAW,WAAW;AAAA,QACvC,UAAS;AAAA,QACT,OAAO,QAAQ,SAAS,IAAI,CAAC;AAAA,QAC7B,MAAM,EAAE,MAAM,OAAO,MAAM,SAAS,cAAc,QAAQ;AAAA,QAC1D,SAAS;AAAA,QAET,0BAAAA,KAAC,YAAS,MAAK,SAAS,gBAAK;AAAA;AAAA,IAC/B;AAAA,EAEJ;AACA,MAAI,KAAK,WAAW,wBAAwB,GAAG;AAC7C,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,aAAU,WAAW,WAAW;AAAA,QACvC,UAAU,aAAa,WAAW;AAAA,QAClC,OAAO,UAAU,SAAS,IAAI,CAAC;AAAA,QAC/B,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAS;AAAA,QAET,0BAAAA,KAAC,YAAU,gBAAK;AAAA;AAAA,IAClB;AAAA,EAEJ;AACA,MAAI,KAAK,SAAS,eAAe,GAAG;AAClC,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,aAAU,WAAW,WAAW;AAAA,QACvC,UAAU,aAAa,WAAW;AAAA,QAClC,OAAO,UAAU,SAAS,IAAI,CAAC;AAAA,QAC/B,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,SAAQ;AAAA,QAER,0BAAAA,KAAC,YACE,uBACG,qDACA,gBACE,4BACA,iEACR;AAAA;AAAA,IACF;AAAA,EAEJ;AACA,MAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,aAAU,WAAW,WAAW;AAAA,QACvC,UAAU,aAAa,WAAW;AAAA,QAClC,OAAO,UAAU,SAAS,IAAI,CAAC;AAAA,QAC/B,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,OAAO,gBAAAA,KAAC,aAAU,KAAK,MAAM,SAAS,MAAM,KAAK,MAAM;AAAA,QAEvD,0BAAAA,KAAC,oBAAiB,KAAK,MAAM,SAAS,MAAM,KAAK,MAAM;AAAA;AAAA,IACzD;AAAA,EAEJ;AACA,SAAO,gBAAAA,KAAC,mBAAgB,MAAY;AACtC;AAIA,SAAS,kBAAkB,EAAE,KAAK,GAAsB;AACtD,QAAM,OAAO,cAAc,KAAK,SAAS;AACzC,QAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAEzD,MAAI,KAAK,WAAW,WAAW;AAC7B,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,OAAO,IAAI;AAAA,QAClB,SAAO;AAAA,QACP,SAAS,gBAAAA,KAAC,kBAAe,2BAAQ;AAAA,QAEjC,0BAAAA,KAAC,gBAAa,OAAM,aAAY,OAAO,cAAc,IAAI,GAAG;AAAA;AAAA,IAC9D;AAAA,EAEJ;AAEA,MAAI,KAAK,WAAW,UAAU;AAC5B,UAAM,YAAY,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAClE,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAD,KAAC,gBAAa,WAAW,WAAW;AAAA,QAC1C,UAAS;AAAA,QACT,OAAO,OAAO,IAAI;AAAA,QAClB,QAAM;AAAA,QACN,SAAS,aAAa;AAAA,QAEtB;AAAA,0BAAAA,KAAC,gBAAa,OAAM,aAAY,OAAO,cAAc,IAAI,GAAG;AAAA,UAC3D,YACC,gBAAAA,KAAC,gBAAa,OAAM,SAAQ,OAAO,WAAW,QAAM,MAAC,IAErD,gBAAAA,KAAC,YAAS,MAAK,SAAQ,kDAAoC;AAAA;AAAA;AAAA,IAE/D;AAAA,EAEJ;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAD,KAAC,gBAAa,WAAW,WAAW;AAAA,MAC1C,UAAS;AAAA,MACT,OAAO,OAAO,IAAI;AAAA,MAClB,WAAW,KAAK,WAAW;AAAA,MAC3B,SAAQ;AAAA,MAER;AAAA,wBAAAA,KAAC,gBAAa,OAAM,aAAY,OAAO,cAAc,IAAI,GAAG;AAAA,QAC5D,gBAAAA,KAAC,YAAS,4FAAyE;AAAA;AAAA;AAAA,EACrF;AAEJ;AAIA,SAAS,gBAAgB,EAAE,KAAK,GAAsB;AACpD,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,OAAO,cAAc,cAAc,KAAK,SAAS,CAAC;AACxD,QAAM,UAAU,gBAAgB,KAAK,IAAI;AAEzC,MAAI,SAAS;AACX,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAA,KAAC,YAAS,WAAW,WAAW;AAAA,QACtC,UAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAO;AAAA,QACP,SAAS,gBAAAA,KAAC,kBAAgB,sBAAY,IAAI,KAAK,iBAAW;AAAA,QAE1D,0BAAAA,KAAC,gBAAa,OAAM,aAAY,OAAO,MAAM;AAAA;AAAA,IAC/C;AAAA,EAEJ;AAEA,QAAM,EAAE,MAAM,SAAS,QAAQ,IAAI,gBAAgB,KAAK,MAAM;AAI9D,OAAK,WAAW,KAAK,WAAW,aAAa,KAAK,WAAW,aAAa;AACxE,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAAD,KAAC,cAAW,WAAW,WAAW;AAAA,QACxC,UAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM,EAAE,MAAM,OAAO,MAAM,QAAQ;AAAA,QACnC,SAAS,QAAQ,MAAM,GAAG,EAAE;AAAA,QAE5B;AAAA,0BAAAA,KAAC,gBAAa,OAAM,aAAY,OAAO,MAAM;AAAA,UAC7C,gBAAAA,KAAC,gBAAa,OAAM,SAAQ,OAAO,SAAS,QAAM,MAAC;AAAA;AAAA;AAAA,IACrD;AAAA,EAEJ;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAD,KAAC,cAAW,WAAW,WAAW;AAAA,MACxC,UAAS;AAAA,MACT,OAAO;AAAA,MACP,WAAW,KAAK,WAAW;AAAA,MAC3B,SAAS,YAAY,IAAI;AAAA,MAEzB;AAAA,wBAAAA,KAAC,gBAAa,OAAM,aAAY,OAAO,MAAM;AAAA,QAC7C,gBAAAA,KAAC,gBAAa,OAAM,UAAS,OAAO,SAAS;AAAA;AAAA;AAAA,EAC/C;AAEJ;AAEA,SAAS,YAAY,MAAuB;AAC1C,QAAM,OAAO,iBAAiB,IAAI,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC9D,SAAO,SAAS,OAAO,KAAK,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC,WAAM;AAC3E;AAIA,IAAM,eAAoC;AAAA;AAAA;AAAA,EAGxC,EAAE,OAAO,WAAW,MAAM,oBAAoB,QAAQ,mBAAmB;AAAA,EACzE,EAAE,OAAO,WAAW,MAAM,iBAAiB,QAAQ,qBAAqB;AAAA,EACxE,EAAE,OAAO,WAAW,MAAM,oBAAoB,QAAQ,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKxE,EAAE,OAAO,QAAQ,MAAM,gBAAgB,QAAQ,aAAa;AAAA,EAC5D,EAAE,OAAO,QAAQ,MAAM,eAAe,QAAQ,mBAAmB;AAAA,EACjE,EAAE,OAAO,QAAQ,MAAM,oBAAoB,QAAQ,mBAAmB;AAAA,EACtE,EAAE,OAAO,QAAQ,MAAM,iBAAiB,QAAQ,qBAAqB;AAAA;AAAA,EAErE,EAAE,OAAO,QAAQ,MAAM,uBAAuB,QAAQ,qBAAqB;AAAA,EAC3E,EAAE,OAAO,QAAQ,MAAM,kBAAkB,QAAQ,qBAAqB;AAAA,EACtE,EAAE,OAAO,QAAQ,MAAM,yBAAyB,QAAQ,qBAAqB;AAAA,EAC7E,EAAE,OAAO,QAAQ,MAAM,iBAAiB,QAAQ,qBAAqB;AAAA,EACrE,EAAE,OAAO,QAAQ,MAAM,mBAAmB,QAAQ,qBAAqB;AAAA,EACvE,EAAE,OAAO,QAAQ,MAAM,iBAAiB,QAAQ,qBAAqB;AAAA,EACrE,EAAE,OAAO,QAAQ,MAAM,qBAAqB,QAAQ,qBAAqB;AAAA,EACzE,EAAE,OAAO,QAAQ,MAAM,iBAAiB,QAAQ,qBAAqB;AAAA,EACrE,EAAE,OAAO,QAAQ,MAAM,mBAAmB,QAAQ,kBAAkB;AAAA,EACpE,EAAE,OAAO,QAAQ,MAAM,cAAc,QAAQ,kBAAkB;AAAA,EAC/D,EAAE,OAAO,QAAQ,MAAM,4BAA4B,QAAQ,kBAAkB;AAC/E;AAGO,IAAM,sBAAoC,mBAAmB,cAAc,eAAe;AAG1F,SAAS,0BACd,UAAoD,CAAC,GACvC;AACd,SAAO,mBAAmB,cAAc,iBAAiB,OAAO;AAClE;;;ASr+BA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACNP,SAAS,iBAAAK,gBAAe,cAAAC,aAAY,cAAc;AAgBlD,IAAM,2BAA2BD,eAAc,IAAI;AAE5C,IAAM,4BAA4B,yBAAyB;AAO3D,SAAS,uBAAgC;AAC9C,QAAM,UAAUC,YAAW,wBAAwB;AACnD,QAAM,WAAW,OAAO,OAAO;AAC/B,SAAO,SAAS;AAClB;;;ADoDU,SA8HF,YAAAC,WA9HE,OAAAC,MAqGF,QAAAC,aArGE;AAhCV,SAAS,SAAS,MAA4B;AAC5C,MAAI,KAAK,SAAS,aAAa;AAC7B,WAAO,KAAK,SAAS,kBAAkB,KAAK,SAAS,gBAAgB,aAAa,KAAK;AAAA,EACzF;AACA,SAAO,KAAK;AACd;AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,QAAQ,qBAAqB;AACnC,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA;AAAA;AAAA;AAAA,QAIT;AAAA,QACA,CAAC,QAAQ;AAAA,QACT,CAAC,QAAQ,SAAS;AAAA,QAClB;AAAA,MACF;AAAA,MAEC,gBAAM,IAAI,CAAC,MAAM,UAAU;AAC1B,cAAM,YAAY,QAAQ,KAAK,SAAS,IAAI,MAAM,SAAS,MAAM,QAAQ,CAAC,CAAE;AAC5E,cAAM,MAAM,eAAe,MAAM,cAAc,eAAe,aAAa;AAC3E,eACE,gBAAAA,KAAC,SAAkB,WAAW,GAAG,aAAa,MAAM,GACjD,iBADO,KAAK,EAEf;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;AAGA,SAAS,YAAY,MAAoB;AACvC,QAAM,IAAI,MAAM,yCAAyC,KAAK,UAAU,IAAI,CAAC,EAAE;AACjF;AAEA,SAAS,eACP,MACA,cACA,eACA,eACA;AACA,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,gBAAAA,KAAC,gBAAa,MAAY;AAAA,IACnC,KAAK,aAAa;AAChB,YAAM,WAAW,aAAa,QAAQ,IAAI;AAC1C,aAAO,gBAAAA,KAAC,YAAS,MAAY;AAAA,IAC/B;AAAA,IACA,KAAK;AACH,aAAO,gBAAAA,KAAC,aAAU,MAAY,eAA8B;AAAA,IAC9D,KAAK;AACH,aAAO,gBAAAA,KAAC,cAAW,MAAY;AAAA,IACjC,KAAK;AACH,aAAO,gBAAAA,KAAC,aAAU,MAAY,eAA8B;AAAA,IAC9D;AACE,aAAO,YAAY,IAAI;AAAA,EAC3B;AACF;AAEA,SAAS,aAAa,EAAE,KAAK,GAA4B;AAGvD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAA,KAAC,aAAU,WAAU,YAAW;AAAA,MACtC,UAAS;AAAA,MACT,OACE,KAAK,YACH,aAEA,gBAAAA,KAAC,UAAK,WAAU,wCAAuC,qBAAO;AAAA,MAGlE,SAAS,KAAK;AAAA,MACd,SAAS,SAAS,KAAK,MAAM,GAAG;AAAA,MAEhC,0BAAAA,KAAC,OAAE,WAAU,+DAA+D,eAAK,MAAK;AAAA;AAAA,EACxF;AAEJ;AAOA,IAAM,oBAA4C;AAAA,EAChD,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,UAAU;AACZ;AAUA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AACF,GAGG;AACD,QAAM,YAAY,KAAK,YAAY;AACnC,QAAM,YAAY,kBAAkB,KAAK,UAAU;AAGnD,QAAM,aAAa,aAAa,QAAQ,KAAK,kBAAkB;AAE/D,QAAM,WAAW,YAAa,KAAK,uBAAuB,KAAK,WAAY,KAAK;AAChF,QAAM,WAAW,QAAQ,aAAa;AACtC,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAD,KAAC,oBAAiB,WAAU,YAAW;AAAA,MAC7C,UAAS;AAAA,MACT,OACE,gBAAAC,MAAC,UAAK,WAAU,0CACd;AAAA,wBAAAD,KAAC,UAAK,WAAU,YAAY,sBAAY,mBAAmB,mBAAkB;AAAA,QAC5E,YACC,gBAAAA,KAAC,UAAK,WAAU,8GACb,qBACH,IACE;AAAA,SACN;AAAA,MAEF,SAAS,aAAa,KAAK,qBAAqB,KAAK;AAAA,MAEpD;AAAA;AAAA;AAAA;AAAA,UAGC,gBAAAC,MAAC,SAAI,WAAU,yBACb;AAAA,4BAAAD,KAAC,OAAE,WAAU,2EACV,eAAK,SACR;AAAA,YACA,gBAAAA,KAAC,OAAE,WAAU,+DACV,eAAK,oBACR;AAAA,aACF;AAAA,YACE,aAAa,KAAK,WAAW;AAAA;AAAA;AAAA,UAG/B,gBAAAC,MAAAF,WAAA,EACE;AAAA,4BAAAC,KAAC,OAAE,WAAU,+DACV,eAAK,SACR;AAAA,YACA,gBAAAA,KAAC,YAAS,MAAK,SAAQ,+BAAiB;AAAA,aAC1C;AAAA,YACE;AAAA;AAAA,UAEF,gBAAAA,KAAC,YAAS,MAAK,SAAQ,uBAAS;AAAA,YAEhC,gBAAAA,KAAC,OAAE,WAAU,+DACV,eAAK,SACR;AAAA,QAED,KAAK,UAAU,gBAAAA,KAAC,YAAS,MAAK,SAAQ,6CAA+B,IAAc;AAAA,QACnF,WACC,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM,gBAAgB,QAAQ;AAAA,YACvC,WAAW;AAAA,cACT;AAAA,cACA;AAAA,YACF;AAAA,YACD;AAAA;AAAA,cAEC,gBAAAD,KAAC,kBAAe,WAAU,kFAAiF;AAAA;AAAA;AAAA,QAC7G,IACE;AAAA;AAAA;AAAA,EACN;AAEJ;AASA,SAAS,gBAAgB,MAA2B;AAClD,MAAI,KAAK,SAAS,qBAAqB;AACrC,QAAI,KAAK,WAAW,SAAU,QAAO;AACrC,QAAI,KAAK,WAAW,UAAW,QAAO;AACtC,QAAI,KAAK,WAAW,UAAW,QAAO;AACtC,QAAI,KAAK,WAAW,WAAY,QAAO;AACvC,QAAI,KAAK,WAAW,UAAW,QAAO;AACtC,WAAO;AAAA,EACT;AACA,SAAO,gBAAgB,KAAK,IAAI;AAClC;AAEA,SAAS,WAAW,EAAE,KAAK,GAA0B;AACnD,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,gBAAAD,KAAC,sBAAmB,WAAU,YAAW;AAAA,MAC/C,UACE,KAAK,WAAW,WAAW,WAAW,KAAK,WAAW,YAAY,YAAY;AAAA,MAEhF,OAAO,gBAAgB,IAAI;AAAA,MAC3B,SAAS,KAAK,WAAW;AAAA,MACzB,QAAQ,KAAK,WAAW;AAAA,MACxB,WAAW,KAAK,WAAW;AAAA,MAC3B,SAAS,KAAK,WAAW;AAAA,MAExB;AAAA,aAAK,UAAU,gBAAAA,KAAC,gBAAa,OAAM,WAAU,OAAO,KAAK,SAAS,IAAK;AAAA,QACvE,KAAK,SAAS,gBAAAA,KAAC,gBAAa,OAAM,UAAS,OAAO,KAAK,QAAQ,IAAK;AAAA;AAAA;AAAA,EACvE;AAEJ;AAGA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AACF,GAGG;AACD,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,SAAS,KAAK,WAAW;AAC/B,QAAM,YAAY,KAAK,WAAW;AAClC,QAAM,QACJ,KAAK,WAAW,UACZ,UACE,oBACA,SACE,wBACA,YACE,uBACA,mBACN,UACE,qBACA,SACE,0BACA,YACE,uBACA;AAYZ,QAAM,YAAY,KAAK;AACvB,QAAM,WAAW,QAAQ,SAAS,KAAK,QAAQ,aAAa,KAAK,CAAC,UAAU,CAAC;AAC7E,QAAM,QACJ,gBAAAC,MAAAF,WAAA,EACE;AAAA,oBAAAC,KAAC,UAAK,WAAU,qBAAoB,eAAW,MAAC;AAAA,IAChD,gBAAAA,KAAC,UAAK,WAAW,GAAG,kBAAkB,SAAS,0BAA0B,gBAAgB,GACvF,0BAAAA,KAAC,WAAQ,WAAU,YAAW,GAChC;AAAA,IACA,gBAAAC,MAAC,SAAI,WAAU,kBAGb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,UAAU,oBAAoB,SAAS,0BAA0B;AAAA,UACnE;AAAA,UAEC;AAAA;AAAA,MACH;AAAA,MACC,KAAK,SACJ,gBAAAA,KAAC,OAAE,WAAU,+CACV,mBAAS,KAAK,QAAQ,GAAG,GAC5B,IACE;AAAA,OACN;AAAA,IACC,SACC,gBAAAC,MAAC,UAAK,WAAU,oHACd;AAAA,sBAAAD,KAAC,UAAK,WAAU,6CAA4C;AAAA,MAAE;AAAA,OAEhE,IACE,YACF,gBAAAA,KAAC,UAAK,WAAU,iGAAgG,yBAEhH,IACE,WACF,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,QACX,WAAU;AAAA;AAAA,IACZ,IACE;AAAA,KACN;AAGF,MAAI,YAAY,aAAa,eAAe;AAC1C,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,cAAc,SAAS;AAAA,QACtC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,EAEJ;AACA,SAAO,gBAAAA,KAAC,SAAI,WAAU,wCAAwC,iBAAM;AACtE;;;AEtXA,SAAS,WAAW,oBAAAE,mBAAkB,iBAAiB,yBAAyB;AAChF,SAAS,YAAAC,iBAAgB;AACzB,SAAS,eAAAC,oBAAmB;AA8FpB,gBAAAC,MAyBI,QAAAC,aAzBJ;AA/CD,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AAGnB,QAAM,oBAAoB,qBAAqB;AAC/C,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,eAAe,qBAAqB,KAAK;AAC1E,QAAM,QAAQ,qBAAqB;AACnC,QAAM,SAAS,cAAc,OAAO,UAAU;AAE9C,SACE,gBAAAD;AAAA,IAACE,aAAY;AAAA,IAAZ;AAAA,MACC;AAAA,MACA,cAAc;AAAA,MACd,WAAW,SAAS,CAAC,OAAO,qBAAqB;AAAA,MAEjD;AAAA,wBAAAF;AAAA,UAACE,aAAY;AAAA,UAAZ;AAAA,YACC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAOT;AAAA;AAAA;AAAA,cAGA;AAAA,cACA,OACI,oDACA;AAAA;AAAA;AAAA;AAAA,cAIJ,YAAY,WACR,sDACA;AAAA,YACN;AAAA,YAIA;AAAA,8BAAAH,KAACI,mBAAA,EAAiB,WAAU,2GAA0G;AAAA,cAKtI,gBAAAJ;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACA,OAAO,aAAa;AAAA,oBACpB,YAAY,WAAW,0BAA0B;AAAA,kBACnD;AAAA,kBAEC,sBAAY,WACX,gBAAAA,KAAC,qBAAkB,WAAU,UAAS,IACpC,YAAY,cACd,gBAAAA,KAAC,mBAAgB,WAAU,UAAS,IAClC,YAAY,aACd,gBAAAA,KAAC,aAAU,WAAW,OAAO,WAAW,YAAY,IAEpD,gBAAAA,KAAC,UAAK,WAAU,0DAAyD;AAAA;AAAA,cAE7E;AAAA,cACA,gBAAAC,MAAC,UAAK,WAAW,GAAG,2BAA2B,OAAO,eAAe,kBAAkB,GACpF;AAAA;AAAA,gBACA,YAAY,YAAY,cACvB,gBAAAA,MAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,kBAAI;AAAA,mBAAY,IACtD;AAAA,gBACH,YAAY,cACX,gBAAAD,KAAC,UAAK,WAAU,qBAAoB,+BAAc,IAChD;AAAA,iBACN;AAAA,cAMA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,eAAW;AAAA,kBACX,WAAW;AAAA,oBACT;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,kBAEC,iBAAO,eAAe;AAAA;AAAA,cACzB;AAAA;AAAA;AAAA,QACF;AAAA,QACA,gBAAAA,KAACG,aAAY,SAAZ,EAAoB,WAAU,+FAG7B,0BAAAH,KAAC,SAAI,WAAW,OAAO,cAAc,QAAS,UAAS,GACzD;AAAA;AAAA;AAAA,EACF;AAEJ;AAGA,SAAS,cAAc,OAAuB,YAA6B;AACzE,MAAI,QAAQ;AACZ,MAAI,WAAW;AACf,MAAI,cAAc;AAClB,MAAI,gBAAgB;AACpB,MAAI,kBAAkB;AACtB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,UAAU;AAG1B,UAAI,KAAK,YAAY,aAAa;AAChC,2BAAmB;AAAA,MACrB,OAAO;AACL,yBAAiB;AAAA,MACnB;AACA;AAAA,IACF;AACA,QAAI,KAAK,SAAS,aAAa;AAC7B;AAAA,IACF;AAEA,QAAI,aAAa,IAAI,GAAG;AACtB,eAAS,cAAc,KAAK,GAAG,EAAE;AAAA,IACnC,WAAW,KAAK,SAAS,gBAAgB;AACvC,kBAAY;AAAA,IACd,WACE,UAAU,IAAI,MAAM,mBACpB,KAAK,SAAS,mBACd,KAAK,SAAS,uBACd;AACA,UAAI,kBAAkB,KAAK,MAAM,MAAM,MAAM;AAC3C,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,QAAM,QAAQ,CAAC,GAAG,MAAM,MAAM,IAAI,MAAM,WAAW,IAAI,SAAS,OAAO,EAAE;AACzE,MAAI,OAAO;AACT,UAAM,KAAK,GAAG,KAAK,IAAI,UAAU,IAAI,SAAS,OAAO,SAAS;AAAA,EAChE;AACA,MAAI,UAAU;AACZ,UAAM,KAAK,GAAG,QAAQ,IAAI,aAAa,IAAI,YAAY,UAAU,EAAE;AAAA,EACrE;AACA,MAAI,aAAa;AACf,UAAM,KAAK,GAAG,WAAW,IAAI,gBAAgB,IAAI,eAAe,aAAa,EAAE;AAAA,EACjF;AACA,MAAI,eAAe;AACjB,UAAM,KAAK,GAAG,aAAa,IAAI,kBAAkB,IAAI,WAAW,UAAU,QAAQ;AAAA,EACpF;AACA,MAAI,iBAAiB;AACnB,UAAM,KAAK,GAAG,eAAe,IAAI,oBAAoB,IAAI,WAAW,UAAU,UAAU;AAAA,EAC1F;AACA,QAAM,WAAW,oBAAoB,UAAU;AAC/C,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AACA,SAAO,MAAM,KAAK,QAAK;AACzB;AAEA,SAAS,oBAAoB,YAA+C;AAC1E,MAAI,eAAe,UAAa,CAAC,OAAO,SAAS,UAAU,KAAK,aAAa,KAAM;AACjF,WAAO;AAAA,EACT;AACA,QAAM,eAAe,KAAK,MAAM,aAAa,GAAI;AACjD,MAAI,eAAe,IAAI;AACrB,WAAO,GAAG,YAAY;AAAA,EACxB;AACA,QAAM,eAAe,KAAK,MAAM,eAAe,EAAE;AACjD,MAAI,eAAe,IAAI;AACrB,WAAO,GAAG,YAAY;AAAA,EACxB;AACA,QAAM,QAAQ,KAAK,MAAM,eAAe,EAAE;AAC1C,QAAM,UAAU,eAAe;AAC/B,SAAO,GAAG,KAAK,KAAK,OAAO,OAAO,EAAE,SAAS,GAAG,GAAG,CAAC;AACtD;;;AdvLA,IAAM,yBAAyB;AAC/B,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAC1B,IAAM,qBAAqB;AAC3B,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAC1B,IAAM,eAA+B,CAAC;AAO/B,SAAS,iBACd,WACA,UAAmC,CAAC,GACZ;AACxB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,aAAa,WAAW,UAAU,UAAU;AAClD,QAAM,YAAY,GAAG,WAAW,KAAS,aAAa,EAAE,KAAS,KAAK,KAAS,aAAa,SAAS,UAAU;AAE/G,QAAM,CAAC,QAAQ,SAAS,IAAIK,UAAyB,CAAC,CAAC;AACvD,QAAM,CAAC,iBAAiB,kBAAkB,IAAIA,UAAuC,MAAM;AAC3F,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAuB,IAAI;AACrD,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,KAAK;AAC9C,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,UAAS,IAAI;AACzD,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAS,KAAK;AACtD,QAAM,kBAAkBC,QAAO,KAAK;AACpC,QAAM,oBAAoBA,QAAsB,IAAI;AACpD,QAAM,cAAcA,QAAO,KAAK;AAChC,QAAM,kBAAkBA,QAAO,KAAK;AACpC,QAAM,eAAeA,QAAsB,IAAI;AAC/C,QAAM,gBAAgBA,QAAO,CAAC;AAG9B,QAAM,CAAC,gBAAgB,iBAAiB,IAAID,UAAS,SAAS;AAE9D,EAAAE,WAAU,MAAM;AAGd,QAAI,aAAa,YAAY,WAAW;AACtC,mBAAa,UAAU;AACvB,oBAAc,WAAW;AACzB,wBAAkB,SAAS;AAC3B,gBAAU,CAAC,CAAC;AACZ,eAAS,IAAI;AACb,kBAAY,KAAK;AACjB,sBAAgB,KAAK;AACrB,wBAAkB,IAAI;AACtB,sBAAgB,UAAU;AAC1B,wBAAkB,UAAU;AAC5B,kBAAY,UAAU;AACtB,sBAAgB,UAAU;AAAA,IAC5B;AACA,QAAI,CAAC,aAAa,CAAC,SAAS;AAC1B,yBAAmB,MAAM;AACzB;AAAA,IACF;AACA,UAAM,aAAa,IAAI,gBAAgB;AAGvC,QAAI,UAA0B,CAAC;AAC/B,QAAI,aAAmD;AACvD,UAAM,QAAQ,MAAM;AAClB,mBAAa;AACb,UAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,MACF;AACA,YAAM,QAAQ;AACd,gBAAU,CAAC;AAIX,YAAM,cAAc,MAAM,MAAM,SAAS,CAAC;AAC1C,UAAI,aAAa;AACf,wBAAgB,UAAU,KAAK;AAAA,UAC7B,gBAAgB;AAAA,UAChB,GAAG,MAAM,IAAI,mBAAmB;AAAA,QAClC;AAAA,MACF;AACA,gBAAU,CAAC,aAAa,CAAC,GAAG,UAAU,GAAG,KAAK,CAAC;AAAA,IACjD;AACA,UAAM,gBAAgB,MAAM;AAC1B,qBAAe,WAAW,OAAO,EAAE;AAAA,IACrC;AAEA,UAAM,YAAY;AAChB,UAAI;AACF,YAAI,CAAC,YAAY;AACf,6BAAmB,YAAY;AAI/B,gBAAMC,UAAS,MAAM,gBAAgB,QAAQ,aAAa,WAAW;AAAA,YACnE,QAAQ,OAAO;AAAA,YACf,UAAU;AAAA,YACV,cAAc,OAAO;AAAA,YACrB,YAAY;AAAA,YACZ,QAAQ,WAAW;AAAA,UACrB,CAAC;AACD,cAAI,WAAW,OAAO,SAAS;AAC7B;AAAA,UACF;AACA,4BAAkB,UAAUA,QAAO;AACnC,sBAAY,UAAUA,QAAO;AAC7B,0BAAgB,UAAUA,QAAO;AACjC,sBAAYA,QAAO,QAAQ;AAC3B,oBAAUA,QAAO,MAAM;AACvB,4BAAkB,KAAK;AAAA,QACzB;AACA,YAAI,YAAY;AACd,4BAAkB,KAAK;AAAA,QACzB;AACA,cAAM,SAAS,OAAO,aAAa,aAAa,WAAW;AAAA,UACzD,OAAO,gBAAgB;AAAA,UACvB,QAAQ,WAAW;AAAA,UACnB,eAAe,CAAC,UAAU;AACxB,gBAAI,CAAC,WAAW,OAAO,SAAS;AAC9B,iCAAmB,KAAK;AAAA,YAC1B;AAAA,UACF;AAAA,QACF,CAAC;AACD,yBAAiB,SAAS,QAAQ;AAChC,kBAAQ,KAAK,KAAK;AAClB,wBAAc;AAAA,QAChB;AACA,YAAI,CAAC,WAAW,OAAO,SAAS;AAC9B,gBAAM;AACN,6BAAmB,OAAO;AAAA,QAC5B;AAAA,MACF,SAAS,OAAO;AACd,YAAI,CAAC,WAAW,OAAO,SAAS;AAC9B,gBAAM;AACN,mBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAClE,6BAAmB,OAAO;AAAA,QAC5B;AAAA,MACF;AAAA,IACF,GAAG;AAEH,WAAO,MAAM;AACX,iBAAW,MAAM;AACjB,UAAI,eAAe,MAAM;AACvB,qBAAa,UAAU;AAAA,MACzB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,OAAO,SAAS,YAAY,SAAS,CAAC;AAE1E,QAAM,YAAYC,aAAY,YAA8B;AAC1D,QAAI,CAAC,aAAa,cAAc,gBAAgB,WAAW,CAAC,YAAY,SAAS;AAC/E,aAAO;AAAA,IACT;AACA,UAAM,SAAS,kBAAkB;AACjC,QAAI,WAAW,MAAM;AACnB,kBAAY,UAAU;AACtB,kBAAY,KAAK;AACjB,aAAO;AAAA,IACT;AACA,UAAM,aAAa,cAAc;AACjC,oBAAgB,UAAU;AAC1B,oBAAgB,IAAI;AACpB,QAAI;AACF,YAAMD,UAAS,MAAM,gBAAgB,QAAQ,aAAa,WAAW;AAAA,QACnE;AAAA,QACA,UAAU;AAAA,QACV,cAAc;AAAA,QACd,YAAY;AAAA,MACd,CAAC;AACD,UAAI,cAAc,YAAY,YAAY;AACxC,eAAO;AAAA,MACT;AACA,UAAIA,QAAO,OAAO,WAAW,GAAG;AAC9B,0BAAkB,UAAU;AAC5B,oBAAY,UAAU;AACtB,oBAAY,KAAK;AACjB,eAAO;AAAA,MACT;AACA,wBAAkB,UAAUA,QAAO;AACnC,kBAAY,UAAUA,QAAO;AAC7B,kBAAYA,QAAO,QAAQ;AAC3B,gBAAU,CAAC,aAAa;AACtB,2BAAmB,UAAUA,QAAO,MAAM;AAC1C,eAAO,CAAC,GAAGA,QAAO,QAAQ,GAAG,QAAQ;AAAA,MACvC,CAAC;AACD,aAAOA,QAAO;AAAA,IAChB,UAAE;AACA,UAAI,cAAc,YAAY,YAAY;AACxC,wBAAgB,UAAU;AAC1B,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,UAAU,CAAC;AAE/C,QAAM,kBAAkB,mBAAmB;AAC3C,QAAM,gBAAgB,kBAAkB,SAAS;AACjD,QAAM,WAAWE,SAAQ,MAAM,cAAc,aAAa,GAAG,CAAC,aAAa,CAAC;AAC5E,QAAM,gBAAgBA,SAAQ,MAAM,wBAAwB,aAAa,GAAG,CAAC,aAAa,CAAC;AAE3F,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,iBAAiB,kBAAkB,kBAAkB;AAAA,IACrD,cAAc,kBAAkB,gBAAgB,UAAU;AAAA,IAC1D,gBAAgB,aAAa,QAAQ,kBAAkB,iBAAiB;AAAA,IACxE,UAAU,cAAc,CAAC,kBAAkB,QAAQ;AAAA,IACnD,cAAc,cAAc,CAAC,kBAAkB,QAAQ;AAAA,IACvD;AAAA,IACA,OAAO,kBAAkB,QAAQ;AAAA,EACnC;AACF;AASA,eAAe,gBACb,QACA,aACA,WACA,SAO4B;AAC5B,MAAI,SAAS,QAAQ;AACrB,MAAI,SAAyB,CAAC;AAC9B,MAAI,eAAe;AACnB,MAAI,UAAU;AAEd,SAAO,UAAU,QAAQ,YAAY;AACnC,QAAI,OAAO,SAAS,KAAK,WAAW,MAAM,KAAK,QAAQ,cAAc;AACnE;AAAA,IACF;AACA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,aAAa,WAAW,QAAQ;AAAA,MAC1E,UAAU,QAAQ;AAAA,MAClB,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACrD,CAAC;AACD,eAAW;AACX,QAAI,KAAK,WAAW,GAAG;AACrB,qBAAe;AACf;AAAA,IACF;AACA,oBAAgB,IAAI;AACpB,aAAS,CAAC,GAAG,MAAM,GAAG,MAAM;AAC5B,aAAS,KAAK,CAAC,EAAG;AAClB,QAAI,WAAW,KAAK,CAAC,CAAE,GAAG;AACxB,qBAAe;AACf;AAAA,IACF;AAAA,EACF;AAQA,MAAI,YAAY;AAChB,SACE,CAAC,gBACD,kBAAkB,MAAM,MAAM,MAC9B,YAAY,qBACZ,UAAU,QAAQ,YAClB;AACA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,aAAa,WAAW,QAAQ;AAAA,MAC1E,UAAU,QAAQ;AAAA,MAClB,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,IACrD,CAAC;AACD,eAAW;AACX,iBAAa;AACb,QAAI,KAAK,WAAW,GAAG;AACrB,qBAAe;AACf;AAAA,IACF;AACA,oBAAgB,IAAI;AACpB,aAAS,CAAC,GAAG,MAAM,GAAG,MAAM;AAC5B,aAAS,KAAK,CAAC,EAAG;AAClB,QAAI,WAAW,KAAK,CAAC,CAAE,GAAG;AACxB,qBAAe;AACf;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,cAAc;AACjB,UAAM,WAAW,kBAAkB,MAAM;AACzC,QAAI,WAAW,GAAG;AAChB,eAAS,OAAO,MAAM,QAAQ;AAAA,IAChC;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,CAAC,KAAK;AAC5B,QAAM,SAAS,OAAO,OAAO,SAAS,CAAC,KAAK;AAC5C,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,gBAAgB,QAAQ,YAAY;AAAA,IACpC,gBAAgB,SAAS,kBAAkB,MAAM,IAAI;AAAA,IACrD,UAAU,OAAO,SAAS,KAAK,CAAC,gBAAgB,QAAQ,SAAS;AAAA,EACnE;AACF;AAGA,SAAS,kBAAkB,QAAgC;AACzD,WAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,UAAM,OAAO,OAAO,KAAK,EAAG;AAC5B,QAAI,SAAS,qBAAqB,SAAS,gBAAgB;AACzD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAIA,eAAe,iBACb,QACA,aACA,WACA,QACA,SAIuB;AACvB,MAAI,QAAQ,QAAQ,SAAS;AAC3B,UAAM,WAAW;AAAA,EACnB;AACA,QAAM,YAAY,QAAQ;AAC1B,MAAI,cAAc,GAAG;AACnB,WAAO,OAAO,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC;AAAA,EACxC;AACA,QAAM,OAAO,MAAM,OAAO,WAAW,aAAa,WAAW;AAAA,IAC3D;AAAA,IACA,OAAO;AAAA,IACP,SAAS;AAAA,EACX,CAAC;AACD,MAAI,QAAQ,QAAQ,SAAS;AAC3B,UAAM,WAAW;AAAA,EACnB;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,UAAU,CAAC;AAC1C;AAEA,SAAS,WAAW,QAAgC;AAClD,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO,cAAc,cAAc,MAAM,CAAC,EAAE;AAC9C;AAEA,SAAS,WAAW,OAA8B;AAChD,SAAO,MAAM,SAAS,qBAAqB,MAAM,YAAY;AAC/D;AAEA,SAAS,kBAAkB,QAAgC;AACzD,SAAO,OAAO,OAAO,CAAC,KAAK,UAAU,KAAK,IAAI,KAAK,oBAAoB,KAAK,CAAC,GAAG,CAAC;AACnF;AAEA,SAAS,oBAAoB,OAA6B;AACxD,QAAM,UAAUC,UAAS,MAAM,OAAO;AACtC,QAAM,iBAAiB,OAAO,QAAQ,cAAc;AACpD,SAAO,KAAK,IAAI,MAAM,UAAU,OAAO,SAAS,cAAc,IAAI,KAAK,MAAM,cAAc,IAAI,CAAC;AAClG;AAEA,SAASA,UAAS,OAAyC;AACzD,SAAO,SAAS,OAAO,UAAU,WAAY,QAAoC,CAAC;AACpF;AAEA,SAAS,gBAAgB,QAA8B;AACrD,WAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,QAAI,OAAO,QAAQ,CAAC,EAAG,YAAY,OAAO,KAAK,EAAG,UAAU;AAC1D,YAAM,IAAI,MAAM,uEAAuE;AAAA,IACzF;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,UAA0B,OAA6B;AACjF,MAAI,CAAC,wBAAwB,KAAK,SAAS,WAAW,KAAK,MAAM,WAAW,GAAG;AAC7E;AAAA,EACF;AACA,MAAI,MAAM,MAAM,SAAS,CAAC,EAAG,YAAY,SAAS,CAAC,EAAG,UAAU;AAC9D,UAAM,IAAI,MAAM,gEAAgE;AAAA,EAClF;AACF;AAEA,SAAS,0BAAmC;AAC1C,QAAM,aAAc,WAA6D,SAAS;AAC1F,SAAO,eAAe,UAAa,WAAW,aAAa;AAC7D;AAEA,SAAS,aAAoB;AAC3B,QAAM,QAAQ,IAAI,MAAM,4BAA4B;AACpD,QAAM,OAAO;AACb,SAAO;AACT;;;Ae1bA,SAAS,eAAAC,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,iBAAgB;AA4ClD,SAAS,YACd,WACA,UAA8B,CAAC,GAChB;AACf,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,EAAE;AACrC,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,KAAK;AAC9C,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAuB,IAAI;AACrD,QAAM,uBAAuBC,QAAsB,IAAI;AACvD,QAAM,SAAS,QAAQ;AAGvB,QAAM,gBAAgBA,QAAO,QAAQ,UAAU;AAC/C,gBAAc,UAAU,QAAQ;AAIhC,QAAM,YAAY,GAAG,WAAW,KAAS,aAAa,EAAE;AACxD,QAAM,eAAeA,QAAO,SAAS;AACrC,EAAAC,WAAU,MAAM;AACd,QAAI,aAAa,YAAY,WAAW;AACtC,mBAAa,UAAU;AACvB,2BAAqB,UAAU;AAC/B,eAAS,EAAE;AACX,eAAS,IAAI;AAAA,IACf;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,OAAOC;AAAA,IACX,OAAO,UAAmB,WAAyB,YAA8B;AAC/E,YAAM,cAAc;AACpB,YAAM,QAAQ,YAAY,aAAa,KAAK;AAG5C,YAAM,SAAS,kBAAkB,cAAc,OAAO;AACtD,YAAM,gBAAgB,OAAO,WAAW,UAAU,KAAK;AACvD,UAAK,CAAC,QAAQ,CAAC,gBAAiB,CAAC,aAAa,SAAS;AACrD,eAAO;AAAA,MACT;AAGA,2BAAqB,YAAY,sBAAsB;AACvD,iBAAW,IAAI;AACf,eAAS,IAAI;AACb,UAAI;AAIF,cAAM,WAAW,QAAQ;AACzB,cAAM,QAAQ,iBAAiB,UAAU,qBAAqB,SAAS,MAAM;AAC7E,YAAI,aAAa,SAAS;AACxB,gBAAM,OAAO,aAAa,aAAa,WAAW,KAAK;AAAA,QACzD,OAAO;AACL,gBAAM,OAAO,YAAY,aAAa,WAAW,KAAK;AAAA,QACxD;AACA,6BAAqB,UAAU;AAC/B,YAAI,aAAa,QAAW;AAG1B,mBAAS,CAAC,YAAa,YAAY,cAAc,KAAK,OAAQ;AAAA,QAChE;AACA,iBAAS,QAAQ;AACjB,eAAO;AAAA,MACT,SAAS,OAAO;AACd,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAClE,eAAO;AAAA,MACT,UAAE;AACA,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,OAAO,SAAS,MAAM;AAAA,EACzD;AAOA,QAAM,qBAAqB,kBAAkB,cAAc,OAAO,EAAE,WAAW,UAAU,KAAK;AAE9F,QAAM,QAAQA;AAAA,IACZ,OAAO,WAAmC;AACxC,UAAI,CAAC,aAAa,SAAS;AACzB;AAAA,MACF;AACA,iBAAW,IAAI;AACf,eAAS,IAAI;AACb,UAAI;AACF,cAAM,OAAO,aAAa,aAAa,WAAW,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MAC1F,SAAS,OAAO;AACd,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,MACpE,UAAE;AACA,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,OAAO;AAAA,EAC1C;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,WAAmC;AACxC,UAAI,CAAC,aAAa,SAAU;AAC5B,kBAAY,IAAI;AAChB,eAAS,IAAI;AACb,UAAI;AACF,cAAM,OAAO,cAAc,aAAa,WAAW,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MAC3F,SAAS,OAAO;AACd,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,MACpE,UAAE;AACA,oBAAY,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,QAAQ;AAAA,EAC3C;AAEA,QAAM,cAAcA,aAAY,CAAC,SAAiB;AAChD,yBAAqB,UAAU;AAC/B,aAAS,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,SAAS,QAAQ,SAAS,KAAK,CAAC,YAAY,MAAM,KAAK,EAAE,SAAS,KAAK;AAAA,IACvE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAYA,aAAY,MAAM,SAAS,IAAI,GAAG,CAAC,CAAC;AAAA,EAClD;AACF;AAQO,IAAM,yBAAyB;AAG/B,SAAS,kBACd,QACoB;AACpB,UAAQ,OAAO,WAAW,aAAa,OAAO,IAAI,WAAW,CAAC;AAChE;AAMO,SAAS,iBACd,MACA,eACA,QACkB;AAClB,SAAO,EAAE,GAAG,kBAAkB,MAAM,GAAG,MAAM,cAAc;AAC7D;AAGO,SAAS,kBAAkB,OAMtB;AACV,MAAI,MAAM,QAAQ,WAAW,MAAM,UAAU;AAC3C,WAAO;AAAA,EACT;AACA,SAAO,MAAM,aAAa,gBAAgB;AAC5C;AAGO,SAAS,mBAAmB,OAA+D;AAChG,SAAO,MAAM,WAAW,MAAM,UAAU,UAAU;AACpD;AAEA,SAAS,wBAAgC;AACvC,QAAM,YAAY,WAAW;AAC7B,MAAI,aAAa,gBAAgB,WAAW;AAC1C,WAAO,UAAU,WAAW;AAAA,EAC9B;AACA,SAAO,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACpE;;;ACxOA,SAAS,eAAAC,cAAa,UAAAC,SAAQ,YAAAC,kBAAgB;AAmD9C,IAAM,UAAU,CAAC,SAAwB,KAAK,KAAK,WAAW,QAAQ;AAW/D,SAAS,mBACd,UAAqC,CAAC,GACZ;AAC1B,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,CAAC,aAAa,cAAc,IAAIC,WAA2B,CAAC,CAAC;AAGnE,QAAM,UAAUC,QAA0B,oBAAI,IAAI,CAAC;AAKnD,QAAM,cAAcC;AAAA,IAClB,CAAC,IAAY,SAAe;AAC1B,WAAK,OACF,WAAW,aAAa;AAAA,QACvB,UAAU,KAAK,QAAQ;AAAA,QACvB,aAAa,KAAK,QAAQ;AAAA,QAC1B,MAAM;AAAA,MACR,CAAC,EACA,KAAK,CAAC,UAAU;AACf;AAAA,UAAe,CAAC,YACd,QAAQ;AAAA,YAAI,CAAC,eACX,WAAW,OAAO,KACd;AAAA,cACE,GAAG;AAAA,cACH,QAAQ;AAAA,cACR,MAAM;AAAA,cACN,MAAM,MAAM;AAAA,cACZ,aAAa,MAAM;AAAA,cACnB,WAAW,MAAM;AAAA,cACjB,OAAO;AAAA,YACT,IACA;AAAA,UACN;AAAA,QACF;AAAA,MACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB;AAAA,UAAe,CAAC,YACd,QAAQ;AAAA,YAAI,CAAC,eACX,WAAW,OAAO,KACd;AAAA,cACE,GAAG;AAAA,cACH,QAAQ;AAAA,cACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC9D,IACA;AAAA,UACN;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACL;AAAA,IACA,CAAC,QAAQ,WAAW;AAAA,EACtB;AAEA,QAAM,WAAWA;AAAA,IACf,CAAC,UAA0B;AACzB,iBAAW,QAAQ,OAAO;AACxB,cAAM,KAAK,OAAO,WAAW;AAC7B,gBAAQ,QAAQ,IAAI,IAAI,IAAI;AAC5B,cAAM,aAAa,QAAQ,IAAI,IAAI,IAAI,gBAAgB,IAAI,IAAI;AAC/D,uBAAe,CAAC,YAAY;AAAA,UAC1B,GAAG;AAAA,UACH;AAAA,YACE;AAAA,YACA,MAAM,KAAK,QAAQ;AAAA,YACnB,aAAa,KAAK,QAAQ;AAAA,YAC1B,WAAW,KAAK;AAAA,YAChB,QAAQ;AAAA,YACR,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,UACrC;AAAA,QACF,CAAC;AACD,oBAAY,IAAI,IAAI;AAAA,MACtB;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,QAAQA;AAAA,IACZ,CAAC,OAAe;AACd,YAAM,OAAO,QAAQ,QAAQ,IAAI,EAAE;AACnC,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AACA;AAAA,QAAe,CAAC,YACd,QAAQ;AAAA,UAAI,CAAC,eACX,WAAW,OAAO,KACd,EAAE,GAAG,YAAY,QAAQ,aAAa,OAAO,OAAU,IACvD;AAAA,QACN;AAAA,MACF;AACA,kBAAY,IAAI,IAAI;AAAA,IACtB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,eAAeA;AAAA,IACnB,CAAC,UAAkD;AACjD,YAAM,iBAAiB,MAAM,eAAe;AAC5C,UAAI,CAAC,gBAAgB;AACnB;AAAA,MACF;AACA,YAAM,QAAQ,CAAC,GAAG,cAAc,EAAE,OAAO,WAAW;AACpD,UAAI,MAAM,SAAS,GAAG;AACpB,iBAAS,KAAK;AAAA,MAChB;AAAA,IACF;AAAA,IACA,CAAC,UAAU,WAAW;AAAA,EACxB;AAEA,QAAM,SAASA,aAAY,CAAC,OAAe;AACzC,YAAQ,QAAQ,OAAO,EAAE;AACzB,mBAAe,CAAC,YAAY;AAC1B,YAAM,UAAU,QAAQ,KAAK,CAAC,eAAe,WAAW,OAAO,EAAE;AACjE,UAAI,SAAS,YAAY;AACvB,YAAI,gBAAgB,QAAQ,UAAU;AAAA,MACxC;AACA,aAAO,QAAQ,OAAO,CAAC,eAAe,WAAW,OAAO,EAAE;AAAA,IAC5D,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQA,aAAY,MAAM;AAC9B,YAAQ,QAAQ,MAAM;AACtB,mBAAe,CAAC,YAAY;AAC1B,iBAAW,cAAc,SAAS;AAChC,YAAI,WAAW,YAAY;AACzB,cAAI,gBAAgB,WAAW,UAAU;AAAA,QAC3C;AAAA,MACF;AACA,aAAO,CAAC;AAAA,IACV,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,SAAO;AAAA,IACL;AAAA,IACA,gBAAgB,YAAY;AAAA,MAAQ,CAAC,eACnC,WAAW,WAAW,WAAW,WAAW,OACxC,CAAC,EAAE,MAAM,QAAQ,QAAQ,WAAW,KAAK,GAAG,CAAC,IAC7C,CAAC;AAAA,IACP;AAAA,IACA,WAAW,YAAY,KAAK,CAAC,eAAe,WAAW,WAAW,WAAW;AAAA,IAC7E;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACjNA,SAAS,eAAAC,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,kBAAgB;AAUlD,SAAS,iBAAiB,OAA4C;AAC3E,SACE,MAAM,KAAK,WAAW,OAAO,KAC7B,MAAM,KAAK,WAAW,gBAAgB,KACtC,MAAM,KAAK,WAAW,kBAAkB,KACxC,MAAM,KAAK,WAAW,sBAAsB;AAEhD;AA8BO,SAAS,aACd,WACA,UAA+B,CAAC,GACZ;AACpB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,CAAC,UAAU,WAAW,IAAIC,WAAsC,IAAI;AAC1E,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,OAAO;AAC9C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AACrD,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAC/E,QAAM,aAAaC,QAAO,CAAC;AAC3B,QAAM,eAAeA,QAAsB,IAAI;AAC/C,QAAM,cAAcA,QAAoC,IAAI;AAE5D,QAAM,kBAAkBC,aAAY,CAAC,SAA4C;AAC/E,gBAAY,UAAU;AACtB,gBAAY,IAAI;AAAA,EAClB,GAAG,CAAC,CAAC;AAEL,QAAM,OAAOA,aAAY,YAA2B;AAClD,QAAI,CAAC,UAAW;AAChB,UAAM,SAAS,EAAE,WAAW;AAC5B,QAAI;AACF,YAAM,UAAU,MAAM,OAAO,SAAS,aAAa,SAAS;AAC5D,UAAI,WAAW,WAAW,SAAS;AACjC,wBAAgB,OAAO;AACvB,iBAAS,IAAI;AACb,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,SAAS,OAAO;AACd,UAAI,WAAW,WAAW,SAAS;AACjC,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAClE,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,eAAe,CAAC;AAEpD,EAAAC,WAAU,MAAM;AACd,UAAM,YAAY,GAAG,WAAW,KAAS,aAAa,EAAE;AACxD,QAAI,aAAa,YAAY,WAAW;AACtC,mBAAa,UAAU;AACvB,sBAAgB,IAAI;AACpB,eAAS,IAAI;AAAA,IACf;AACA,QAAI,CAAC,SAAS;AACZ,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,eAAW,IAAI;AACf,SAAK,KAAK;AACV,UAAM,iBAAiB,QAAQ;AAC/B,QAAI,mBAAmB,UAAa,kBAAkB,GAAG;AACvD,aAAO,MAAM;AACX,mBAAW,WAAW;AAAA,MACxB;AAAA,IACF;AACA,UAAM,QAAQ,YAAY,MAAM,KAAK,KAAK,GAAG,cAAc;AAC3D,WAAO,MAAM;AACX,oBAAc,KAAK;AACnB,iBAAW,WAAW;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,MAAM,SAAS,aAAa,WAAW,QAAQ,gBAAgB,eAAe,CAAC;AAEnF,QAAM,kBAAkB,qBAAqB,MAAM,KAAK,KAAK,CAAC;AAC9D,yBAAuB,QAAQ,aAAa,WAAW,kBAAkB,iBAAiB;AAAA,IACxF;AAAA,IACA,GAAI,QAAQ,WAAW,SAAY,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAAA,EACnE,CAAC;AAED,QAAM,aAAaD;AAAA,IACjB,OAAO,WAAqC;AAC1C,UAAI,CAAC,UAAW,QAAO;AACvB,YAAM,UAAU,YAAY;AAC5B,YAAM,OAAO,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,MAAM;AAC7D,UAAI,CAAC,WAAW,CAAC,KAAM,QAAO;AAC9B,YAAM,SAAS,MAAM;AAAA,QAAI,MACvB,OAAO,gBAAgB,aAAa,WAAW,QAAQ;AAAA,UACrD,sBAAsB,QAAQ;AAAA,UAC9B,qBAAqB,KAAK;AAAA,QAC5B,CAAC;AAAA,MACH;AACA,UAAI,CAAC,QAAQ;AACX,aAAK,KAAK;AACV,eAAO;AAAA,MACT;AACA,sBAAgB,OAAO,QAAQ;AAC/B,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,KAAK,MAAM,eAAe;AAAA,EAC7D;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,UAAU,SAAS,CAAC;AAAA,IAC3B,cAAc,UAAU,gBAAgB;AAAA,IACxC,mBAAmB,UAAU,qBAAqB;AAAA,IAClD,yBAAyB,UAAU,2BAA2B;AAAA,IAC9D,8BAA8B,UAAU,gCAAgC;AAAA,IACxE,iCAAiC,UAAU,mCAAmC;AAAA,IAC9E;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC3JA,SAAS,wBAA6D;AACtE,SAAS,eAAAE,cAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,kBAAgB;AAUlD,SAAS,YAAY,OAA4C;AACtE,SAAO,MAAM,KAAK,WAAW,OAAO;AACtC;AAsCO,SAAS,QACd,WACA,UAA0B,CAAC,GACZ;AACf,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,eAAe,QAAQ;AAC7B,QAAM,aAAa,iBAAiB;AACpC,QAAM,CAAC,MAAM,OAAO,IAAIC,WAA6B,IAAI;AACzD,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,OAAO;AAC9C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AACrD,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAC/E,QAAM,aAAaC,QAAO,CAAC;AAC3B,QAAM,eAAeA,QAAsB,IAAI;AAE/C,QAAM,OAAOC,aAAY,YAA2B;AAClD,QAAI,CAAC,WAAW;AACd;AAAA,IACF;AACA,UAAM,SAAS,EAAE,WAAW;AAC5B,QAAI;AACF,YAAM,UAAU,MAAM,OAAO,QAAQ,aAAa,SAAS;AAC3D,UAAI,WAAW,WAAW,SAAS;AACjC,gBAAQ,OAAO;AACf,iBAAS,IAAI;AACb,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,SAAS,OAAO;AACd,UAAI,WAAW,WAAW,SAAS;AACjC;AAAA,MACF;AACA,UAAI,iBAAiB,oBAAoB,MAAM,WAAW,KAAK;AAE7D,gBAAQ,IAAI;AACZ,iBAAS,IAAI;AAAA,MACf,OAAO;AACL,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,MACpE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,SAAS,CAAC;AAEnC,EAAAC,WAAU,MAAM;AACd,UAAM,YAAY,GAAG,WAAW,IAAI,aAAa,EAAE;AACnD,QAAI,aAAa,YAAY,WAAW;AACtC,mBAAa,UAAU;AACvB,cAAQ,IAAI;AACZ,eAAS,IAAI;AAAA,IACf;AACA,QAAI,CAAC,SAAS;AACZ,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,QAAI,YAAY;AACd,iBAAW,KAAK;AAChB,aAAO,MAAM;AACX,mBAAW,WAAW;AAAA,MACxB;AAAA,IACF;AACA,eAAW,IAAI;AACf,SAAK,KAAK;AACV,UAAM,iBAAiB,QAAQ;AAC/B,QAAI,mBAAmB,UAAa,kBAAkB,GAAG;AACvD,aAAO,MAAM;AACX,mBAAW,WAAW;AAAA,MACxB;AAAA,IACF;AACA,UAAM,QAAQ,YAAY,MAAM,KAAK,KAAK,GAAG,cAAc;AAC3D,WAAO,MAAM;AACX,oBAAc,KAAK;AACnB,iBAAW,WAAW;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,MAAM,SAAS,aAAa,WAAW,QAAQ,gBAAgB,UAAU,CAAC;AAE9E,QAAM,kBAAkB,qBAAqB,MAAM,KAAK,KAAK,CAAC;AAC9D,yBAAuB,QAAQ,aAAa,WAAW,aAAa,iBAAiB;AAAA,IACnF;AAAA,IACA,GAAI,iBAAiB,SAAY,EAAE,QAAQ,aAAa,IAAI,CAAC;AAAA,EAC/D,CAAC;AAED,QAAM,QAAQD;AAAA,IACZ,OAAO,cAAoD;AACzD,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,MACT;AACA,YAAM,SAAS,MAAM;AAAA,QAAI,MACvB,OAAO,WAAW,aAAa,WAAW;AAAA,UACxC,QAAQ;AAAA,UACR,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,QACjD,CAAC;AAAA,MACH;AACA,UAAI,QAAQ;AACV,gBAAQ,MAAM;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,GAAG;AAAA,EACtC;AAEA,QAAM,SAASA,aAAY,YAAyC;AAClE,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,IACT;AACA,UAAM,SAAS,MAAM,IAAI,MAAM,OAAO,WAAW,aAAa,WAAW,EAAE,QAAQ,SAAS,CAAC,CAAC;AAC9F,QAAI,QAAQ;AACV,cAAQ,MAAM;AAAA,IAChB;AACA,WAAO;AAAA,EACT,GAAG,CAAC,QAAQ,aAAa,WAAW,GAAG,CAAC;AAExC,QAAM,YAAYA,aAAY,YAA2B;AACvD,QAAI,CAAC,WAAW;AACd;AAAA,IACF;AAMA,UAAM,KAAK,MAAM,IAAI,YAAY;AAC/B,YAAM,OAAO,WAAW,aAAa,SAAS;AAC9C,aAAO;AAAA,IACT,CAAC;AACD,QAAI,IAAI;AACN,iBAAW,WAAW;AACtB,cAAQ,IAAI;AACZ,eAAS,IAAI;AAAA,IACf;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,GAAG,CAAC;AAExC,SAAO;AAAA,IACL;AAAA,IACA,UAAU,MAAM,WAAW;AAAA,IAC3B,UAAU,MAAM,WAAW;AAAA,IAC3B,aAAa,MAAM,WAAW;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF;AACF;;;ACpMA,SAAS,eAAAE,oBAAmB;AAyBrB,SAAS,kBACd,WACA,UAAoC,CAAC,GACZ;AACzB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM;AAAA,IACJ,KAAK;AAAA,IACL,UAAU;AAAA,IACV,eAAe;AAAA,IACf,oBAAoB;AAAA,EACtB,IAAI,kBAAkB;AACtB,QAAM;AAAA,IACJ,KAAK;AAAA,IACL,UAAU;AAAA,IACV,eAAe;AAAA,IACf,oBAAoB;AAAA,EACtB,IAAI,kBAAkB;AAEtB,QAAM,QAAQC;AAAA,IACZ,OAAO,WAAkD;AACvD,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,MACT;AACA,aAAO,MAAM;AAAA,QAAW,MACtB,OAAO,aAAa,aAAa,WAAW,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MACpF;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,UAAU;AAAA,EAC7C;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,WAAkD;AACvD,UAAI,CAAC,UAAW,QAAO;AACvB,YAAM,SAAS,MAAM;AAAA,QAAW,MAC9B,OAAO,cAAc,aAAa,WAAW,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC,CAAC;AAAA,MACrF;AACA,aAAO,QAAQ,SAAS;AAAA,IAC1B;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,UAAU;AAAA,EAC7C;AAEA,QAAM,SAASA;AAAA,IACb,OACE,YACA,UACA,YACiC;AACjC,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,MACT;AACA,aAAO,MAAM;AAAA,QAAY,MACvB,OAAO,qBAAqB,aAAa,WAAW;AAAA,UAClD;AAAA,UACA;AAAA,UACA,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,QAC7C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,WAAW;AAAA,EAC9C;AAEA,QAAM,UAAUA;AAAA,IACd,OAAO,YAAoB,YAAqB,MAAM,OAAO,YAAY,WAAW,OAAO;AAAA,IAC3F,CAAC,MAAM;AAAA,EACT;AACA,QAAM,SAASA;AAAA,IACb,OAAO,YAAoB,YAAqB,MAAM,OAAO,YAAY,UAAU,OAAO;AAAA,IAC1F,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,QAAQ,iBAAiB;AAC/B,QAAM,aAAaA,aAAY,MAAM;AACnC,sBAAkB;AAClB,uBAAmB;AAAA,EACrB,GAAG,CAAC,mBAAmB,kBAAkB,CAAC;AAE1C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC/GA,SAAS,eAAAC,oBAAmB;AAkBrB,SAAS,kBAAkB,UAAoC,CAAC,GAA4B;AACjG,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,QAAQ,QAAQ;AACtB,QAAM,OAAOC;AAAA,IACX,YAAY,MAAM,OAAO,mBAAmB,aAAa,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC,CAAC;AAAA,IAC7F,CAAC,QAAQ,aAAa,KAAK;AAAA,EAC7B;AACA,QAAM,QAAQ,eAAe,MAAM;AAAA,IACjC,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,SAAO;AAAA,IACL,OAAO,MAAM,QAAQ,CAAC;AAAA,IACtB,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,EACjB;AACF;;;ACnCA,SAAS,eAAAC,qBAAmB;AA6BrB,SAAS,qBACd,UAAuC,CAAC,GACZ;AAC5B,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,QAAQ,QAAQ;AACtB,QAAM,kBAAkB,QAAQ;AAChC,QAAM,SAAS,QAAQ;AACvB,QAAM,SAAS,QAAQ;AACvB,QAAM,WAAW,KAAK,UAAU,EAAE,aAAa,OAAO,iBAAiB,QAAQ,OAAO,CAAC;AACvF,QAAM,OAAOC;AAAA,IACX,aAAa;AAAA,MACX;AAAA,MACA,MAAM,MAAM,OAAO,gBAAgB,aAAa;AAAA,QAC9C,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,QACvC,GAAI,oBAAoB,SAAY,EAAE,gBAAgB,IAAI,CAAC;AAAA,QAC3D,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,QACzC,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,IACA,CAAC,QAAQ,aAAa,OAAO,iBAAiB,QAAQ,QAAQ,QAAQ;AAAA,EACxE;AACA,QAAM,QAAQ,eAAe,MAAM;AAAA,IACjC,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AAID,QAAM,OAAO,MAAM,MAAM,aAAa,WAAW,MAAM,KAAK,OAAO;AACnE,QAAM,SAAS,MAAM,UAAU,CAAC;AAChC,QAAM,WAAW,MAAM,YAAY,CAAC;AACpC,SAAO;AAAA;AAAA;AAAA;AAAA,IAIL,UAAU,CAAC,GAAG,QAAQ,GAAG,QAAQ;AAAA,IACjC;AAAA,IACA,YAAY,MAAM,cAAc;AAAA,IAChC,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,EACjB;AACF;;;ACvEA,SAAS,eAAAC,eAAa,aAAAC,YAAW,UAAAC,eAAc;AAkBxC,SAAS,sBAAsB,OAA8B;AAClE,MAAI,MAAM,SAAS,4BAA4B,MAAM,SAAS,mBAAmB;AAC/E,WAAO;AAAA,EACT;AAKA,MAAI,MAAM,SAAS,yBAAyB;AAC1C,UAAM,UAAU,MAAM;AACtB,UAAM,OACJ,OAAO,SAAS,SAAS,WACrB,QAAQ,OACR,OAAO,SAAS,aAAa,WAC3B,QAAQ,WACR;AACR,WAAO,SAAS,oBAAoB,KAAK,SAAS,kBAAkB;AAAA,EACtE;AACA,SAAO;AACT;AAEA,SAAS,+BAA+B,OAA8B;AACpE,MAAI,MAAM,SAAS,0BAA0B;AAC3C,WAAO;AAAA,EACT;AACA,QAAM,UAAU,MAAM;AACtB,QAAM,OACJ,OAAO,SAAS,SAAS,WACrB,QAAQ,OACR,OAAO,SAAS,aAAa,WAC3B,QAAQ,WACR;AACR,SAAO,SAAS,oBAAoB,KAAK,SAAS,kBAAkB;AACtE;AAGO,SAAS,kBACd,WACA,UAAoC,CAAC,GACZ;AACzB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,OAAOC;AAAA,IACX,YACE,YACI,MAAM,OAAO,kBAAkB,aAAa,SAAS,IACrD,EAAE,WAAW,CAAC,GAAG,UAAU,CAAC,GAAG,WAAW,MAAM;AAAA,IACtD,CAAC,QAAQ,aAAa,SAAS;AAAA,EACjC;AACA,QAAM,QAAQ,eAAe,MAAM,EAAE,gBAAgB,QAAQ,gBAAgB,QAAQ,CAAC;AACtF,QAAM,cAAc,qBAAqB,MAAM,KAAK,MAAM,QAAQ,GAAG,GAAG;AACxE,QAAM,yBAAyBC,QAA6C,IAAI;AAIhF,EAAAC,WAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,uBAAuB,YAAY,MAAM;AAC3C,qBAAa,uBAAuB,OAAO;AAC3C,+BAAuB,UAAU;AAAA,MACnC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,WAAW,WAAW,CAAC;AAC3B,QAAM,0BAA0BF,cAAY,MAAM;AAChD,SAAK,MAAM,QAAQ;AACnB,QAAI,uBAAuB,YAAY,MAAM;AAC3C,mBAAa,uBAAuB,OAAO;AAAA,IAC7C;AACA,2BAAuB,UAAU,WAAW,MAAM;AAChD,6BAAuB,UAAU;AACjC,WAAK,MAAM,QAAQ;AAAA,IACrB,GAAG,IAAI;AAAA,EACT,GAAG,CAAC,KAAK,CAAC;AACV;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,EAAE,QAAQ,QAAQ,QAAQ,SAAS,WAAW,QAAQ,WAAW,OAAU;AAAA,EAC7E;AACA;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,QAAQ,QAAQ,SAAS,WAAW,QAAQ,WAAW,OAAU;AAAA,EAC7E;AACA,SAAO;AAAA,IACL,SAAS,MAAM;AAAA,IACf,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,EACjB;AACF;;;AChHA,SAAS,eAAAG,eAAa,WAAAC,gBAAe;AAkC9B,SAAS,gBAAgB,UAAkC,CAAC,GAA0B;AAC3F,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,OAAOC;AAAA,IACX,YAAY,MAAM,OAAO,iBAAiB,WAAW;AAAA,IACrD,CAAC,QAAQ,WAAW;AAAA,EACtB;AACA,QAAM,EAAE,MAAM,SAAS,OAAO,QAAQ,IAAI,eAAe,MAAM;AAAA,IAC7D,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAE/E,QAAM,SAASA;AAAA,IACb,OAAO,YAAmE;AACxE,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,kBAAkB,aAAa,OAAO,CAAC;AAC7E,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,SAASA;AAAA,IACb,OACE,eACA,YACgC;AAChC,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,kBAAkB,aAAa,eAAe,OAAO,CAAC;AAC5F,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,kBAA4C;AACjD,YAAM,SAAS,MAAM,IAAI,YAAY;AACnC,cAAM,OAAO,kBAAkB,aAAa,aAAa;AACzD,eAAO;AAAA,MACT,CAAC;AACD,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,cAAcA;AAAA,IAClB,OACE,eACA,MACA,UACgD;AAChD,YAAM,SAAS,MAAM;AAAA,QAAI,MACvB,OAAO,uBAAuB,aAAa,eAAe,MAAM,KAAK;AAAA,MACvE;AACA,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,iBAAiBA;AAAA,IACrB,OAAO,eAAuB,SAAmC;AAC/D,YAAM,SAAS,MAAM,IAAI,YAAY;AACnC,cAAM,OAAO,0BAA0B,aAAa,eAAe,IAAI;AACvE,eAAO;AAAA,MACT,CAAC;AACD,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,SAAO;AAAA,IACL,cAAc,QAAQ,CAAC;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAOO,SAAS,gBAAgB,UAAkC,CAAC,GAA0B;AAC3F,QAAM,eAAeC,SAAQ,MAAM;AACjC,QAAI,CAAC,QAAQ,QAAQ;AACnB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL,GAAG,QAAQ;AAAA,MACX,kBAAkB,QAAQ,OAAO,oBAAoB,QAAQ,OAAO;AAAA,MACpE,mBAAmB,QAAQ,OAAO,qBAAqB,QAAQ,OAAO;AAAA,MACtE,mBAAmB,QAAQ,OAAO,qBAAqB,QAAQ,OAAO;AAAA,MACtE,mBAAmB,QAAQ,OAAO,qBAAqB,QAAQ,OAAO;AAAA,MACtE,wBACE,QAAQ,OAAO,0BAA0B,QAAQ,OAAO;AAAA,MAC1D,2BACE,QAAQ,OAAO,6BAA6B,QAAQ,OAAO;AAAA,IAC/D;AAAA,EACF,GAAG,CAAC,QAAQ,MAAM,CAAC;AACnB,QAAM,SAAS,gBAAgB,EAAE,GAAG,SAAS,GAAI,eAAe,EAAE,QAAQ,aAAa,IAAI,CAAC,EAAG,CAAC;AAChG,SAAO,EAAE,GAAG,QAAQ,cAAc,OAAO,aAAa;AACxD;;;AC1JA,SAAS,eAAAC,qBAAmB;AA+BrB,SAAS,QAAQ,UAA0B,CAAC,GAAkB;AACnE,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,OAAOC,cAAY,YAAY,MAAM,OAAO,SAAS,WAAW,GAAG,CAAC,QAAQ,WAAW,CAAC;AAC9F,QAAM,EAAE,MAAM,SAAS,OAAO,QAAQ,IAAI,eAAe,MAAM;AAAA,IAC7D,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAE/E,QAAM,SAASA;AAAA,IACb,OAAO,YAAmD;AACxD,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,UAAU,aAAa,OAAO,CAAC;AACrE,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,OAAe,YAAmD;AACvE,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,UAAU,aAAa,OAAO,OAAO,CAAC;AAC5E,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,UAAoC;AACzC,YAAM,SAAS,MAAM,IAAI,YAAY;AACnC,cAAM,OAAO,UAAU,aAAa,KAAK;AACzC,eAAO;AAAA,MACT,CAAC;AACD,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,eAAeA;AAAA,IACnB,OAAO,UAAgD;AACrD,aAAO,MAAM,IAAI,MAAM,OAAO,gBAAgB,aAAa,KAAK,CAAC;AAAA,IACnE;AAAA,IACA,CAAC,QAAQ,aAAa,GAAG;AAAA,EAC3B;AAEA,QAAM,kBAAkBA;AAAA,IACtB,OAAO,OAAe,cAAkD;AACtE,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,mBAAmB,aAAa,OAAO,SAAS,CAAC;AACvF,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,cAAcA;AAAA,IAClB,OAAO,UAA+C;AACpD,aAAO,MAAM,IAAI,MAAM,OAAO,eAAe,aAAa,KAAK,CAAC;AAAA,IAClE;AAAA,IACA,CAAC,QAAQ,aAAa,GAAG;AAAA,EAC3B;AAEA,QAAM,gBAAgBA;AAAA,IACpB,OAAO,OAAe,YAAgE;AACpF,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,iBAAiB,aAAa,OAAO,OAAO,CAAC;AACnF,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,SAAO;AAAA,IACL,MAAM,QAAQ,CAAC;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAgCO,SAAS,OAAO,OAAe,UAAyB,CAAC,GAAiB;AAC/E,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,OAAOA;AAAA,IACX,YAAY,MAAM,OAAO,OAAO,aAAa,KAAK;AAAA,IAClD,CAAC,QAAQ,aAAa,KAAK;AAAA,EAC7B;AACA,QAAM,EAAE,MAAM,SAAS,OAAO,QAAQ,IAAI,eAAe,MAAM;AAAA,IAC7D,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAE/E,QAAM,SAASA;AAAA,IACb,OAAO,YAAmD;AACxD,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,UAAU,aAAa,OAAO,OAAO,CAAC;AAC5E,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,OAAO,KAAK,OAAO;AAAA,EAC3C;AAEA,QAAM,SAASA,cAAY,YAA8B;AACvD,UAAM,SAAS,MAAM,IAAI,YAAY;AACnC,YAAM,OAAO,UAAU,aAAa,KAAK;AACzC,aAAO;AAAA,IACT,CAAC;AACD,WAAO,WAAW;AAAA,EACpB,GAAG,CAAC,QAAQ,aAAa,OAAO,GAAG,CAAC;AAEpC,QAAM,kBAAkBA;AAAA,IACtB,OAAO,cAAkD;AACvD,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,mBAAmB,aAAa,OAAO,SAAS,CAAC;AACvF,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,OAAO,KAAK,OAAO;AAAA,EAC3C;AAEA,QAAM,gBAAgBA;AAAA,IACpB,OAAO,YAAgE;AACrE,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,iBAAiB,aAAa,OAAO,OAAO,CAAC;AACnF,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,OAAO,KAAK,OAAO;AAAA,EAC3C;AAEA,QAAM,eAAeA;AAAA,IACnB,OAAO,aAAgD;AACrD,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,gBAAgB,aAAa,OAAO,QAAQ,CAAC;AACnF,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,OAAO,KAAK,OAAO;AAAA,EAC3C;AAEA,QAAM,gBAAgBA;AAAA,IACpB,OAAO,aAAiD;AACtD,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,iBAAiB,aAAa,OAAO,QAAQ,CAAC;AACpF,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,OAAO,KAAK,OAAO;AAAA,EAC3C;AAEA,QAAM,SAASA,cAAY,YAAgE;AACzF,WAAO,MAAM,IAAI,MAAM,OAAO,UAAU,aAAa,KAAK,CAAC;AAAA,EAC7D,GAAG,CAAC,QAAQ,aAAa,OAAO,GAAG,CAAC;AAEpC,SAAO;AAAA,IACL,KAAK;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAeO,SAAS,eACd,OACA,UAAiC,CAAC,GACZ;AACtB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,OAAOA;AAAA,IACX,YAAY,MAAM,OAAO,gBAAgB,aAAa,KAAK;AAAA,IAC3D,CAAC,QAAQ,aAAa,KAAK;AAAA,EAC7B;AACA,QAAM,QAAQ,eAAe,MAAM;AAAA,IACjC,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,SAAO;AAAA,IACL,UAAU,MAAM,QAAQ,CAAC;AAAA,IACzB,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,EACjB;AACF;AAkBO,SAAS,cACd,OACA,UAAgC,CAAC,GACZ;AACrB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,OAAOA;AAAA,IACX,YAAY,MAAM,OAAO,eAAe,aAAa,KAAK;AAAA,IAC1D,CAAC,QAAQ,aAAa,KAAK;AAAA,EAC7B;AACA,QAAM,QAAQ,eAAe,MAAM;AAAA,IACjC,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,SAAO;AAAA,IACL,SAAS,MAAM,QAAQ,CAAC;AAAA,IACxB,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,EACjB;AACF;;;ACvUA,SAAS,eAAAC,qBAAmB;AAI5B,IAAM,sBAA0C,CAAC;AA4B1C,SAAS,SAAS,UAA2B,CAAC,GAAmB;AACtE,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,OAAOC,cAAY,YAAY,MAAM,OAAO,UAAU,WAAW,GAAG,CAAC,QAAQ,WAAW,CAAC;AAC/F,QAAM,EAAE,MAAM,SAAS,OAAO,QAAQ,IAAI,eAAe,MAAM;AAAA,IAC7D,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAE/E,QAAM,WAAWA;AAAA,IACf,OAAO,aAAqF;AAC1F,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,aAAa,aAAa,QAAQ,CAAC;AACzE,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,QAAgB,UAA6B,CAAC,MAAwC;AAC3F,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,WAAW,aAAa,QAAQ,OAAO,CAAC;AAC9E,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,WAAqC;AAC1C,YAAM,SAAS,MAAM,IAAI,YAAY;AACnC,cAAM,OAAO,WAAW,aAAa,MAAM;AAC3C,eAAO;AAAA,MACT,CAAC;AACD,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,CAAC,QAAQ,aAAa,KAAK,OAAO;AAAA,EACpC;AAEA,QAAM,gBAAgB,MAAM,iBAAiB;AAC7C,QAAM,kBAAkBA;AAAA,IACtB,CAAC,WACC,cAAc,KAAK,CAAC,iBAAiB,aAAa,WAAW,MAAM,KAAK;AAAA,IAC1E,CAAC,aAAa;AAAA,EAChB;AAEA,SAAO;AAAA,IACL,OAAO,MAAM,SAAS,CAAC;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACxGA,SAAS,eAAAC,qBAAmB;AAyBrB,SAAS,cAAc,UAAgC,CAAC,GAAwB;AACrF,QAAM,SAAS,kBAAkB,OAAO;AACxC,QAAM,OAAOC,cAAY,YAAY,MAAM,OAAO,eAAe,GAAG,CAAC,MAAM,CAAC;AAC5E,QAAM,EAAE,MAAM,SAAS,OAAO,QAAQ,IAAI,eAAe,MAAM;AAAA,IAC7D,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,EAAE,KAAK,UAAU,eAAe,mBAAmB,IAAI,kBAAkB;AAE/E,QAAM,SAASA;AAAA,IACb,OAAO,YAA+D;AACpE,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,gBAAgB,OAAO,CAAC;AAC9D,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,KAAK,OAAO;AAAA,EACvB;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,aAAqB,YAA+D;AACzF,YAAM,SAAS,MAAM,IAAI,MAAM,OAAO,gBAAgB,aAAa,OAAO,CAAC;AAC3E,UAAI,QAAQ;AACV,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,KAAK,OAAO;AAAA,EACvB;AAEA,SAAO;AAAA,IACL,YAAY,QAAQ,CAAC;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACnEA,SAAS,eAAAC,qBAAmB;AA6BrB,SAAS,gBAAgB,UAAkC,CAAC,GAA0B;AAC3F,QAAM,SAAS,kBAAkB,OAAO;AACxC,QAAM,YAAY,QAAQ;AAC1B,QAAM,cAAc,QAAQ;AAC5B,QAAM,OAAOC;AAAA,IACX,YACE,MAAM,OAAO,gBAAgB;AAAA,MAC3B,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MAC/C,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,IACrD,CAAC;AAAA,IACH,CAAC,QAAQ,WAAW,WAAW;AAAA,EACjC;AACA,QAAM,QAAQ,eAAe,MAAM;AAAA,IACjC,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,SAAO;AAAA,IACL,SAAS,MAAM,MAAM,WAAW;AAAA,IAChC,OAAO,MAAM,MAAM,SAAS,CAAC;AAAA,IAC7B,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,EACjB;AACF;;;ACpDA,SAAS,eAAAC,qBAAmB;AA0BrB,SAAS,mBACd,UAAqC,CAAC,GACZ;AAC1B,QAAM,SAAS,kBAAkB,OAAO;AACxC,QAAM,OAAOC,cAAY,YAAY,MAAM,OAAO,gBAAgB,GAAG,CAAC,MAAM,CAAC;AAC7E,QAAM,QAAQ,eAAe,MAAM;AAAA,IACjC,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,SAAO;AAAA,IACL,QAAQ,MAAM,MAAM,UAAU,CAAC;AAAA,IAC/B,cAAc,MAAM,MAAM,gBAAgB;AAAA,IAC1C,SAAS,MAAM;AAAA,IACf,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,EACjB;AACF;;;AC3CA;AAAA,EACE,oBAAAC;AAAA,EACA;AAAA,OAIK;AACP,SAAS,eAAAC,eAAa,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,kBAAgB;AAkGzD,SAAS,kBAAkB,MAAqD;AAC9E,MAAI,KAAK,cAAc,KAAM,QAAO;AAEpC,SAAO,KAAK,WAAW,gBAAgB,KAAK,WAAW,qBAAqB,KAAK,WAAW;AAC9F;AAUA,SAAS,mBAAmB,MAAgD;AAC1E,MAAI,KAAK,cAAc,MAAM;AAE3B,WACE,KAAK,WAAW,gBAAgB,KAAK,WAAW,qBAAqB,KAAK,WAAW;AAAA,EAEzF;AAGA,SAAO;AACT;AAGA,SAAS,cAAc,QAAmD;AACxE,QAAM,MAAiC,CAAC;AACxC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,wBAAwB,MAAM,WAAW,OAAO,MAAM,YAAY,UAAU;AAC7F,UAAI,KAAK,MAAM,OAAkC;AAAA,IACnD;AAAA,EACF;AACA,SAAO;AACT;AAaO,SAAS,uBACd,WACA,UAAyC,CAAC,GACZ;AAC9B,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,QAAM,iBAAiB,QAAQ,kBAAkB;AACjD,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,QAAM,oBAAoB,QAAQ,qBAAqB;AAEvD,QAAM,CAAC,cAAc,eAAe,IAAIC,WAAqC,IAAI;AACjF,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAmC,MAAM;AACnE,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AACrD,QAAM,CAAC,wBAAwB,yBAAyB,IAAIA,WAE1D,IAAI;AACN,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,WAAS,KAAK;AAC9D,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAwB,IAAI;AAE5D,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAS,CAAC;AAIpC,QAAM,WAAWC,QAAO,CAAC;AACzB,QAAM,cAAcA,QAAsB,IAAI;AAE9C,QAAM,cAAcC,cAAY,MAAM;AACpC,aAAS,CAAC,MAAM,IAAI,CAAC;AAAA,EACvB,GAAG,CAAC,CAAC;AAGL,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,WAAW;AAC1B,eAAS,MAAM;AACf,sBAAgB,IAAI;AACpB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,QAAI,YAAkD;AACtD,QAAI,iBAAwD;AAC5D,QAAI,gBAA+B;AACnC,UAAM,YAAY,KAAK,IAAI;AAE3B,UAAM,cAAc,MAAM;AACxB,UAAI,cAAc,KAAM,cAAa,SAAS;AAC9C,UAAI,mBAAmB,KAAM,eAAc,cAAc;AACzD,kBAAY;AACZ,uBAAiB;AAAA,IACnB;AAEA,UAAM,SAAS,CAAC,SAA8B;AAC5C,UAAI,UAAW;AACf,eAAS,UAAU,KAAK;AACxB,sBAAgB,IAAI;AACpB,eAAS,IAAI;AAAA,IACf;AAEA,UAAM,iBAAiB,CAAC,SAA8B;AACpD,UAAI,CAAC,iBAAiB,mBAAmB,KAAM;AAC/C,YAAM,aACJ,KAAK,4BAA4B,IAAI,KAAK,4BAA4B;AACxE,uBAAiB,YAAY,MAAM;AACjC,YAAI,aAAa,CAAC,cAAe;AACjC,aAAK,OACF,gBAAgB,aAAa,WAAW,eAAe,EAAE,YAAY,SAAS,QAAQ,CAAC,EACvF,KAAK,CAAC,QAAQ;AAGb,cAAI,CAAC,IAAI,SAAS,CAAC,WAAW;AAC5B,wBAAY;AAAA,UACd;AAAA,QACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,cAAI,UAAW;AACf,cACE,iBAAiBC,sBAChB,MAAM,WAAW,OAAO,MAAM,WAAW,MAC1C;AACA,wBAAY;AAAA,UACd;AAAA,QACF,CAAC;AAAA,MACL,GAAG,UAAU;AAAA,IACf;AAEA,UAAM,gBAAgB,MAAM;AAC1B,kBAAY,WAAW,MAAM;AAC3B,YAAI,UAAW;AACf,aAAK,OACF,sBAAsB,aAAa,SAAS,EAC5C,KAAK,CAAC,SAAS;AACd,cAAI,UAAW;AACf,iBAAO,IAAI;AACX,cAAI,KAAK,aAAa,UAAU,KAAK,aAAa,YAAY;AAC5D,qBAAS,OAAO;AAChB;AAAA,UACF;AACA,cAAI,oBAAoB,KAAK,KAAK,IAAI,IAAI,YAAY,mBAAmB;AACvE,qBAAS,OAAO;AAChB,qBAAS,IAAI,MAAM,2DAAsD,CAAC;AAC1E;AAAA,UACF;AACA,wBAAc;AAAA,QAChB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,cAAI,CAAC,WAAW;AACd,qBAAS,OAAO;AAChB,qBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,UACpE;AAAA,QACF,CAAC;AAAA,MACL,GAAG,aAAa;AAAA,IAClB;AAEA,UAAM,YAAY;AAChB,eAAS,aAAa;AACtB,gCAA0B,IAAI;AAC9B,0BAAoB,KAAK;AACzB,UAAI;AACF,cAAM,OAAO,MAAM,OAAO,sBAAsB,aAAa,SAAS;AACtE,YAAI,UAAW;AACf,eAAO,IAAI;AAkBX,cAAM,oBAAoB,iBAAiB,kBAAkB,KAAK,aAAa;AAC/E,cAAM,qBAAqB,kBAAkB,mBAAmB,KAAK,QAAQ;AAS7E,cAAM,kBAAkB,eAAe,KAAK,WAAW;AACvD,YAAI,qBAAqB,sBAAsB,iBAAiB;AAC9D,cAAI;AAKF,kBAAM,SAAS,MAAM,OAAO,aAAa,aAAa,WAAW;AAAA,cAC/D,SAAS;AAAA,YACX,CAAC;AACD,gBAAI,UAAW;AACf,4BAAgB,OAAO;AACvB,wBAAY,UAAU,OAAO;AAC7B,wBAAY,OAAO,QAAQ;AAC3B,qBAAS,UAAU,OAAO;AAI1B;AAAA,cAAgB,CAAC,SACf,OACI;AAAA,gBACE,GAAG;AAAA,gBACH,UAAU,OAAO;AAAA,gBACjB,YAAY,OAAO;AAAA,gBACnB,2BAA2B,OAAO;AAAA,gBAClC,eAAe,oBACX;AAAA,kBACE,GAAG,KAAK;AAAA,kBACR,WAAW,OAAO,aAAa,KAAK,cAAc;AAAA,kBAClD,QAAQ,OAAO,UAAU,KAAK,cAAc;AAAA,kBAC5C,KAAK,OAAO,gBAAgB,KAAK,cAAc;AAAA,kBAC/C,OAAO,OAAO,eAAe,KAAK,cAAc;AAAA,kBAChD,WAAW,OAAO,mBAAmB,KAAK,cAAc;AAAA,kBACxD,YAAY,OAAO,cAAc,KAAK,cAAc;AAAA,gBACtD,IACA,KAAK;AAAA,gBACT,UACE,OAAO,eAAe,OAAO,oBACzB;AAAA,kBACE,GAAG,KAAK;AAAA,kBACR,WAAW,OAAO;AAAA,kBAClB,KAAK,OAAO;AAAA,kBACZ,OAAO,OAAO,iBAAiB,KAAK,SAAS;AAAA;AAAA,kBAE7C,YAAY;AAAA,kBACZ,QAAQ;AAAA,gBACV,IACA,KAAK;AAAA,cACb,IACA;AAAA,YACN;AAAA,UACF,SAAS,OAAO;AACd,gBAAI,UAAW;AACf,gBAAI,iBAAiBA,mBAAkB;AACrC,kBAAI,MAAM,WAAW,KAAK;AAMxB,oBAAI,mBAAmB;AACrB;AAAA,oBACE,MAAM,QAAQ,SAAS,uBAAuB,IAAI,WAAW;AAAA,kBAC/D;AAAA,gBACF;AAAA,cACF,WAAW,MAAM,WAAW,KAAK;AAC/B,oCAAoB,IAAI;AAAA,cAC1B,WAAW,MAAM,WAAW,KAAK;AAC/B,yBAAS,OAAO;AAChB,yBAAS,KAAK;AACd;AAAA,cACF;AAAA,YAGF,OAAO;AACL,oBAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAMA,cAAM,kBAAkB,qBAAqB,sBAAsB;AACnE,YAAI,KAAK,aAAa,UAAU,KAAK,aAAa,cAAc,eAAe;AAC7E,mBAAS,OAAO;AAChB,yBAAe,IAAI;AAAA,QACrB,WAAW,iBAAiB;AAI1B,mBAAS,MAAM;AACf,wBAAc;AAAA,QAChB,OAAO;AAKL,mBAAS,WAAW;AAAA,QACtB;AAAA,MACF,SAAS,OAAO;AACd,YAAI,UAAW;AACf,YAAI,iBAAiBA,qBAAoB,MAAM,WAAW,KAAK;AAC7D,mBAAS,OAAO;AAChB,mBAAS,IAAI,MAAM,8CAA8C,CAAC;AAClE;AAAA,QACF;AACA,iBAAS,OAAO;AAChB,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,MACpE;AAAA,IACF,GAAG;AAEH,WAAO,MAAM;AACX,kBAAY;AACZ,kBAAY;AAGZ,YAAM,YAAY,iBAAiB,YAAY;AAC/C,UAAI,WAAW;AACb,aAAK,OAAO,aAAa,aAAa,WAAW,SAAS,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAC5E;AAAA,IACF;AAAA,EAEF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,QAAM,SAAS,QAAQ;AACvB,EAAAD,WAAU,MAAM;AACd,QAAI,CAAC,UAAU,OAAO,WAAW,EAAG;AACpC,oBAAgB,CAAC,SAAS;AACxB,UAAI,CAAC,QAAQ,CAAC,KAAK,cAAc,IAAK,QAAO;AAC7C,UAAI,OAAO,KAAK;AAChB,UAAI,UAAU;AACd,iBAAW,YAAY,cAAc,MAAM,GAAG;AAE5C,YAAI,SAAS,YAAY,YAAY,WAAW,SAAS,aAAa,YAAY,SAAS;AACzF;AAAA,QACF;AACA,cAAM,UAAU,iBAAiB,MAAM,UAAU,SAAS,OAAO;AACjE,YAAI,SAAS;AACX,iBAAO,EAAE,GAAG,MAAM,KAAK,QAAQ,KAAK,OAAO,QAAQ,OAAO,WAAW,QAAQ,UAAU;AACvF,mBAAS,UAAU,KAAK,IAAI,SAAS,SAAS,SAAS,UAAU;AACjE,oBAAU;AAAA,QACZ;AAAA,MACF;AACA,aAAO,UAAU,EAAE,GAAG,MAAM,eAAe,MAAM,YAAY,SAAS,QAAQ,IAAI;AAAA,IACpF,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACxdA;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AACP,SAAyB,aAAAE,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;;;ACO5D,SAAS,cAAc,oBAAoB;AAGpC,IAAM,sBAAsB;AAE5B,IAAM,qBAAqB;AAiBlC,SAAS,cAAc,SAAuB,QAAoC;AAChF,MAAI,QAAQ,cAAc,GAAI,QAAO,OAAO,EAAE,EAAE,OAAO,QAAQ,SAAS;AACxE,MAAI,QAAQ,gBAAgB,GAAI,QAAO,OAAO,EAAE,EAAE,OAAO,QAAQ,WAAW;AAC5E,MAAI,QAAQ,YAAY,GAAI,QAAO,OAAO,EAAE,EAAE,OAAO,QAAQ,OAAO;AACpE,MAAI,QAAQ,SAAS,EAAG,QAAO,OAAO,EAAE,EAAE,MAAM,QAAQ,IAAI;AAC5D,MAAI,QAAQ,SAAS,EAAG,QAAO,OAAO,EAAE,EAAE,OAAO,QAAQ,IAAI;AAC7D,SAAO;AACT;AAGO,SAAS,iBAAiB,SAAsC;AACrE,QAAM,SAAS,IAAI,aAAa;AAChC,gBAAc,QAAQ,SAAS,OAAO,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK;AAC9D,MAAI,QAAQ,UAAU,GAAI,QAAO,OAAO,EAAE,EAAE,OAAO,QAAQ,KAAK;AAChE,MAAI,QAAQ,SAAS,EAAG,QAAO,OAAO,EAAE,EAAE,MAAM,QAAQ,IAAI;AAC5D,MAAI,QAAQ,kBAAkB,IAAK,QAAO,OAAO,EAAE,EAAE,OAAO,QAAQ,aAAa;AACjF,SAAO,OAAO,OAAO;AACvB;AAGA,SAAS,wBAAwB,QAAsB,QAAsC;AAC3F,QAAM,MAAM,OAAO,MAAM;AACzB,MAAI;AACJ,SAAO,OAAO,MAAM,KAAK;AACvB,UAAM,MAAM,OAAO,OAAO;AAC1B,QAAI,QAAQ,MAAM,KAAK,QAAQ,IAAI;AACjC,gBAAU,OAAO,OAAO;AACxB;AAAA,IACF;AACA,SAAK,MAAM,OAAO,KAAK,QAAQ,EAAG;AAClC,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AACA,SAAO,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAChD;AAGO,SAAS,oBAAoB,OAGlC;AACA,QAAM,SAAS,IAAI,aAAa,KAAK;AACrC,QAAM,MAAM,OAAO;AACnB,MAAI,WAAW;AACf,MAAI;AACJ,SAAO,OAAO,MAAM,KAAK;AACvB,UAAM,MAAM,OAAO,OAAO;AAC1B,QAAI,QAAQ,MAAM,KAAK,QAAQ,GAAG;AAChC,iBAAW,OAAO,KAAK;AACvB;AAAA,IACF;AACA,QAAI,QAAQ,MAAM,KAAK,QAAQ,IAAI;AACjC,cAAQ,wBAAwB,QAAQ,OAAO,OAAO,CAAC;AACvD;AAAA,IACF;AACA,SAAK,MAAM,OAAO,KAAK,QAAQ,EAAG;AAClC,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AACA,SAAO,UAAU,SAAY,EAAE,UAAU,MAAM,IAAI,EAAE,SAAS;AAChE;AAGO,SAAS,kBAAkB,OAAyC;AACzE,QAAM,SAAS,IAAI,aAAa,KAAK;AACrC,QAAM,MAAM,OAAO;AACnB,MAAI,OAAO,IAAI,WAAW,CAAC;AAC3B,SAAO,OAAO,MAAM,KAAK;AACvB,UAAM,MAAM,OAAO,OAAO;AAC1B,QAAI,QAAQ,MAAM,KAAK,QAAQ,IAAI;AAIjC,aAAO,IAAI,WAAW,OAAO,MAAM,CAAC;AACpC;AAAA,IACF;AACA,SAAK,MAAM,OAAO,KAAK,QAAQ,EAAG;AAClC,WAAO,KAAK,MAAM,CAAC;AAAA,EACrB;AACA,SAAO,EAAE,KAAK;AAChB;;;AC3GA,SAAyB,aAAAC,YAAW,UAAAC,SAAQ,YAAAC,kBAAgB;AA0C5D,IAAM,WAAW;AACjB,IAAM,cAAc;AACpB,IAAM,YAAY;AAIlB,SAAS,SAAS,KAAa,MAA8B;AAC3D,QAAM,MAAM,IAAI,WAAW,KAAK,SAAS,CAAC;AAC1C,MAAI,CAAC,IAAI;AACT,MAAI,IAAI,MAAM,CAAC;AACf,SAAO;AACT;AAEA,SAAS,wBAAwB,KAAmC;AAGlE,SAAO,IAAI,UAAU,GAAG;AAC1B;AAoBO,SAAS,oBACd,SAC2B;AAC3B,QAAM,EAAE,YAAY,cAAc,iBAAiB,IAAI;AACvD,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAiC,MAAM;AACjE,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AACrD,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAS,CAAC;AACpC,QAAM,WAAWD,QAA+B,MAAM;AACtD,QAAM,UAAU,CAAC,SAAiC;AAChD,aAAS,UAAU;AACnB,aAAS,IAAI;AAAA,EACf;AAEA,QAAM,YAAY,MAAM,SAAS,CAAC,MAAM,IAAI,CAAC;AAE7C,QAAM,YAAY,YAAY,aAAa;AAC3C,QAAM,MAAM,YAAY,OAAO;AAC/B,QAAM,QAAQ,YAAY,SAAS;AAInC,QAAM,aAAaA,QAAO,gBAAgB;AAC1C,aAAW,UAAU;AAErB,EAAAD,WAAU,MAAM;AAEd,QAAI,OAAO,WAAW,YAAa;AAGnC,QAAI,cAAc,kBAAkB,CAAC,KAAK;AACxC,cAAQ,MAAM;AACd;AAAA,IACF;AACA,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,WAAW;AAGd,cAAQ,MAAM;AACd;AAAA,IACF;AAGA,QAAI;AAOJ,QAAI;AACF,YAAM,IAAI,IAAI,IAAI,GAAG;AACrB,gBAAU;AAAA,QACR,WAAW,EAAE,aAAa,IAAI,SAAS,KAAK;AAAA,QAC5C,aAAa,EAAE,aAAa,IAAI,IAAI,KAAK;AAAA,QACzC,SAAS,EAAE,aAAa,IAAI,OAAO,KAAK;AAAA,QACxC,MAAM;AAAA,QACN,MAAM,OAAO,EAAE,aAAa,IAAI,MAAM,KAAK,GAAG;AAAA,MAChD;AAAA,IACF,SAAS,OAAO;AACd,eAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAClE,cAAQ,OAAO;AACf;AAAA,IACF;AAEA,aAAS,IAAI;AACb,YAAQ,YAAY;AAMpB,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,aAAa,gCAAgC,EAAE;AACtD,UAAM,QAAQ,OAAO;AACrB,UAAM,WAAW;AACjB,UAAM,MAAM;AACZ,UAAM,OAAO;AACb,UAAM,QAAQ;AACd,UAAM,SAAS;AACf,UAAM,SAAS;AACf,UAAM,WAAW;AACjB,UAAM,YAAY;AAClB,UAAM,QAAQ;AACd,UAAM,SAAS;AACf,UAAM,UAAU;AAChB,UAAM,iBAAiB;AACvB,cAAU,YAAY,MAAM;AAC5B,UAAM,MAAM,OAAO,WAAW,IAAI;AAElC,QAAI,WAAW;AACf,QAAI,QAAQ;AAGZ,QAAI,WAAW;AACf,QAAI,UAA6B;AAEjC,UAAM,cAAc,YAAY;AAC9B,UAAI,SAAU;AACd,iBAAW;AACX,UAAI;AACF,eAAO,SAAS;AACd,cAAI,SAAU;AACd,gBAAM,OAAO;AACb,oBAAU;AACV,cAAI;AACJ,cAAI;AAKF,kBAAM,MAAM,kBAAkB,IAAI,KAAK,CAAC,IAAI,WAAW,IAAI,CAAC,GAAG,EAAE,MAAM,YAAY,CAAC,CAAC;AAAA,UACvF,QAAQ;AAEN;AAAA,UACF;AACA,cAAI,UAAU;AACZ,gBAAI,MAAM;AACV;AAAA,UACF;AAGA,cAAI,OAAO,UAAU,IAAI,SAAS,OAAO,WAAW,IAAI,QAAQ;AAC9D,mBAAO,QAAQ,IAAI;AACnB,mBAAO,SAAS,IAAI;AAAA,UACtB;AACA,eAAK,UAAU,KAAK,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACrD,cAAI,MAAM;AAEV,cAAI,CAAC,YAAY,SAAS,YAAY,YAAa,SAAQ,WAAW;AAAA,QACxE;AAAA,MACF,UAAE;AACA,mBAAW;AAAA,MACb;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,YAAM,WAAW,WAAW,yBAAyB,GAAG;AAAA,IAC1D,SAAS,OAAO;AACd,eAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAClE,cAAQ,OAAO;AACf,aAAO,OAAO;AACd;AAAA,IACF;AACA,OAAG,aAAa;AAEhB,UAAM,SAAS,MAAM;AACnB,UAAI,SAAU;AACd,YAAM,OAAO,iBAAiB;AAAA,QAC5B;AAAA,QACA,OAAO,SAAS;AAAA,QAChB,MAAM;AAAA,QACN,eAAe;AAAA,MACjB,CAAC;AACD,UAAI;AACF,WAAG,KAAK,SAAS,UAAU,IAAI,EAAE,MAAqB;AAAA,MACxD,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,YAAY,CAAC,OAA2B;AAC5C,UAAI,SAAU;AACd,YAAM,OAAO,GAAG;AAChB,UAAI,EAAE,gBAAgB,aAAc;AACpC,YAAM,MAAM,IAAI,WAAW,IAAI;AAC/B,UAAI,IAAI,WAAW,EAAG;AACtB,YAAM,MAAM,IAAI,CAAC;AACjB,YAAM,OAAO,IAAI,SAAS,CAAC;AAC3B,UAAI,QAAQ,aAAa;AACvB,YAAI;AACJ,YAAI;AACF,gBAAM,oBAAoB,IAAI;AAAA,QAChC,QAAQ;AACN;AAAA,QACF;AACA,YAAI,CAAC,IAAI,UAAU;AACjB;AAAA,YACE,IAAI;AAAA,cACF,IAAI,OAAO,UACP,4BAA4B,IAAI,MAAM,OAAO,KAC7C;AAAA,YACN;AAAA,UACF;AACA,kBAAQ,OAAO;AACf,cAAI;AACF,eAAG,MAAM;AAAA,UACX,QAAQ;AAAA,UAER;AACA;AAAA,QACF;AAEA,gBAAQ;AAAA,MACV,WAAW,QAAQ,WAAW;AAC5B,YAAI;AACJ,YAAI;AACF,eAAK,kBAAkB,IAAI;AAAA,QAC7B,QAAQ;AACN;AAAA,QACF;AACA,YAAI,GAAG,QAAQ,GAAG,KAAK,SAAS,GAAG;AACjC,oBAAU,GAAG;AACb,eAAK,YAAY;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,MAAM;AACpB,UAAI,SAAU;AACd,eAAS,CAAC,SAAS,QAAQ,IAAI,MAAM,iCAAiC,CAAC;AACvE,cAAQ,OAAO;AAAA,IACjB;AAEA,UAAM,UAAU,MAAM;AACpB,UAAI,SAAU;AACd;AAAA,QACE,CAAC,SACC,QACA,IAAI,MAAM,QAAQ,0BAA0B,wCAAwC;AAAA,MACxF;AACA,cAAQ,OAAO;AAAA,IACjB;AAEA,OAAG,iBAAiB,QAAQ,MAAM;AAClC,OAAG,iBAAiB,WAAW,SAAS;AACxC,OAAG,iBAAiB,SAAS,OAAO;AACpC,OAAG,iBAAiB,SAAS,OAAO;AAEpC,WAAO,MAAM;AACX,iBAAW;AACX,gBAAU;AACV,SAAG,oBAAoB,QAAQ,MAAM;AACrC,SAAG,oBAAoB,WAAW,SAAS;AAC3C,SAAG,oBAAoB,SAAS,OAAO;AACvC,SAAG,oBAAoB,SAAS,OAAO;AACvC,UAAI;AACF,WAAG,MAAM;AAAA,MACX,QAAQ;AAAA,MAER;AACA,aAAO,OAAO;AAAA,IAChB;AAAA,EAKF,GAAG,CAAC,KAAK,OAAO,WAAW,KAAK,CAAC;AAEjC,SAAO,EAAE,OAAO,OAAO,UAAU;AACnC;;;AFxSA,eAAe,oBAAgD;AAC7D,QAAM,MAAO,MAAM,OAAO,cAAc;AAOxC,QAAM,MAAM,IAAI;AAChB,SAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,QAAQ,KAAK,IAAI;AACzD;AAqBO,SAAS,iBAAiB,SAA0D;AACzF,QAAM,EAAE,YAAY,cAAc,aAAa,eAAe,YAAY,iBAAiB,IACzF;AAIF,QAAM,cAAc,oBAAoB;AAAA,IACtC;AAAA,IACA;AAAA,IACA,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;AAAA,EACjD,CAAC;AACD,QAAM,CAAC,OAAO,QAAQ,IAAIG,WAAiC,MAAM;AACjE,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AACrD,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAS,CAAC;AACpC,QAAM,WAAWC,SAA+B,MAAM;AACtD,QAAM,UAAU,CAAC,SAAiC;AAChD,aAAS,UAAU;AACnB,aAAS,IAAI;AAAA,EACf;AAEA,QAAM,YAAY,MAAM,SAAS,CAAC,MAAM,IAAI,CAAC;AAE7C,QAAM,MAAM,YAAY,OAAO;AAI/B,QAAM,QAAQ,YAAY,SAAS;AACnC,QAAM,YAAY,YAAY,aAAa;AAC3C,QAAM,OAAO,YAAY,QAAQ;AAOjC,QAAM,SAASA,SAA8B,IAAI;AAIjD,QAAM,iBAAiBA,SAAO,WAAW;AACzC,QAAM,mBAAmBA,SAAO,aAAa;AAC7C,QAAM,UAAUA,SAAO,IAAI;AAC3B,QAAM,gBAAgBA,SAAO,UAAU;AACvC,iBAAe,UAAU;AACzB,mBAAiB,UAAU;AAC3B,UAAQ,UAAU;AAClB,gBAAc,UAAU;AAGxB,QAAM,cAAc,CAAC,GAAW,SAA8B,MAAM,eAAe,CAAC;AAEpF,EAAAC,YAAU,MAAM;AAEd,QAAI,OAAO,WAAW,YAAa;AACnC,QAAI,cAAc,YAAY,CAAC,KAAK;AAClC,cAAQ,MAAM;AACd;AAAA,IACF;AACA,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,WAAW;AAMd,cAAQ,MAAM;AACd;AAAA,IACF;AAEA,QAAI,MAA6B;AACjC,QAAI,WAAW;AACf,aAAS,IAAI;AACb,YAAQ,aAAa;AAErB,UAAM,YAAY,MAAM;AACtB,UAAI,CAAC,SAAU,SAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,YAAY,CAAC,CAAC;AAAA,IAClF;AACA,UAAM,eAAe,MAAM;AACzB,UAAI,CAAC,SAAU,SAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,eAAe,CAAC,CAAC;AAAA,IACrF;AACA,UAAM,oBAAoB,MAAM;AAC9B,UAAI,SAAU;AACd,eAAS,IAAI,MAAM,0DAA0D,CAAC;AAC9E,cAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC;AAAA,IAC9D;AAEA,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,UAAU,cAAc,WAAY,MAAM,kBAAkB;AAClE,YAAI,SAAU;AACd,cAAM,YAAY,iBAAiB,EAAE,IAAI,CAAC;AAC1C,gBAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,aAAa,CAAC,CAAC;AAClE,cAAM,QAAQ,WAAW,WAAW;AAAA,UAClC,aAAa,QAAQ,EAAE,UAAU,MAAM,IAAI;AAAA,QAC7C,CAAC;AACD,YAAI,WAAW,YAAY,QAAQ,SAAS,eAAe,OAAO;AAMlE,YAAI,eAAe;AACnB,YAAI,gBAAgB,iBAAiB,WAAW;AAChD,YAAI,iBAAiB,WAAW,SAAS;AACzC,YAAI,iBAAiB,cAAc,YAAY;AAC/C,YAAI,iBAAiB,mBAAmB,iBAAiB;AACzD,eAAO,UAAU;AAAA,MACnB,SAAS,OAAO;AACd,YAAI,CAAC,UAAU;AACb,mBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAClE,kBAAQ,OAAO;AAAA,QACjB;AAAA,MACF;AAAA,IACF,GAAG;AAEH,WAAO,MAAM;AACX,iBAAW;AACX,UAAI,OAAO,YAAY,IAAK,QAAO,UAAU;AAC7C,UAAI,KAAK;AACP,YAAI,sBAAsB,WAAW,SAAS;AAC9C,YAAI,sBAAsB,cAAc,YAAY;AACpD,YAAI,sBAAsB,mBAAmB,iBAAiB;AAC9D,YAAI;AACF,cAAI,WAAW;AAAA,QACjB,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EAMF,GAAG,CAAC,KAAK,OAAO,WAAW,KAAK,CAAC;AAKjC,EAAAA,YAAU,MAAM;AACd,UAAM,MAAM,OAAO;AACnB,QAAI,IAAK,KAAI,WAAW,YAAY,MAAM,WAAW;AAAA,EAGvD,GAAG,CAAC,aAAa,MAAM,KAAK,CAAC;AAQ7B,EAAAA,YAAU,MAAM;AACd,UAAM,MAAM,OAAO;AACnB,QAAI,KAAK;AACP,UAAI,eAAe;AACnB,UAAI,gBAAgB,iBAAiB;AAAA,IACvC;AAAA,EAEF,GAAG,CAAC,eAAe,KAAK,CAAC;AAMzB,MAAI,cAAc,eAAgB,QAAO;AACzC,SAAO,EAAE,OAAO,OAAO,UAAU;AACnC;;;AG/OA;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAAC,aAAW,WAAAC,UAAS,UAAAC,UAAQ,YAAAC,kBAAgB;AAmCrD,SAAS,YAAY,MAAkE;AACrF,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,EAAE,SAAS,KAAK,OAAO,CAAC,GAAG,SAAS,KAAK,MAAM,CAAC,EAAE;AAAA,EAC3D;AACA,QAAM,QAAQ,IAAI,WAAW,IAAI;AACjC,QAAM,UAAU,MAAM,SAAS,IAAI,OAAO,aAAa,MAAM,CAAC,CAAE,IAAI;AACpE,QAAM,UAAU,MAAM,SAAS,IAAI,IAAI,YAAY,EAAE,OAAO,MAAM,SAAS,CAAC,CAAC,IAAI;AACjF,SAAO,EAAE,SAAS,QAAQ;AAC5B;AAmBO,SAAS,kBAAkB,SAA4D;AAC5F,QAAM,EAAE,YAAY,UAAU,SAAS,aAAa,YAAY,IAAI;AACpE,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAA+B,QAAQ;AACnE,QAAM,QAAQD,SAAyB,IAAI;AAG3C,QAAM,UAAUA,SAAuC;AAAA,IACrD,MAAM,eAAe;AAAA,IACrB,MAAM,eAAe;AAAA,EACvB,CAAC;AAGD,QAAM,cAAcA,SAAO,QAAQ;AACnC,QAAM,aAAaA,SAAO,OAAO;AACjC,cAAY,UAAU;AACtB,aAAW,UAAU;AAErB,QAAM,YAAY,YAAY,aAAa;AAC3C,QAAM,MAAM,YAAY,OAAO;AAC/B,QAAM,QAAQ,YAAY,SAAS;AAEnC,EAAAF,YAAU,MAAM;AAGd,QAAI,OAAO,WAAW,eAAe,OAAO,cAAc,YAAa;AACvE,QAAI,cAAc,YAAY,CAAC,KAAK;AAClC,gBAAU,QAAQ;AAClB;AAAA,IACF;AAEA,QAAI,WAAW;AACf,QAAI;AACJ,cAAU,YAAY;AACtB,QAAI;AAGF,eAAS,IAAI,UAAU,kBAAkB,EAAE,IAAI,CAAC,GAAG,gBAAgB;AAAA,IACrE,QAAQ;AACN,gBAAU,OAAO;AACjB;AAAA,IACF;AACA,WAAO,aAAa;AACpB,UAAM,UAAU;AAEhB,WAAO,SAAS,MAAM;AACpB,UAAI,SAAU;AAId,UAAI;AACF,eAAO,KAAK,cAAc,EAAE,SAAS,QAAQ,QAAQ,MAAM,MAAM,QAAQ,QAAQ,KAAK,CAAC,CAAC;AACxF,eAAO,KAAK,gBAAgB,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,IAAI,CAAC;AAAA,MACzE,QAAQ;AAAA,MAER;AACA,gBAAU,MAAM;AAAA,IAClB;AAEA,WAAO,YAAY,CAAC,OAAqB;AACvC,UAAI,SAAU;AACd,YAAM,EAAE,SAAS,QAAQ,IAAI,YAAY,GAAG,IAA4B;AACxE,cAAQ,SAAS;AAAA,QACf,KAAK,kBAAkB;AACrB,sBAAY,UAAU,OAAO;AAC7B;AAAA,QACF,KAAK,kBAAkB;AACrB,qBAAW,UAAU,OAAO;AAC5B;AAAA;AAAA,QAEF;AACE;AAAA,MACJ;AAAA,IACF;AAEA,WAAO,UAAU,MAAM;AACrB,UAAI,CAAC,SAAU,WAAU,OAAO;AAAA,IAClC;AACA,WAAO,UAAU,MAAM;AACrB,UAAI,CAAC,SAAU,WAAU,QAAQ;AAAA,IACnC;AAEA,WAAO,MAAM;AACX,iBAAW;AACX,YAAM,UAAU;AAEhB,aAAO,SAAS;AAChB,aAAO,YAAY;AACnB,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,UAAI;AACF,eAAO,MAAM;AAAA,MACf,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EAGF,GAAG,CAAC,WAAW,KAAK,KAAK,CAAC;AAE1B,SAAOC,SAAiC,MAAM;AAC5C,UAAM,QAAQ,CAAC,SAAiB;AAC9B,YAAM,KAAK,MAAM;AACjB,UAAI,MAAM,GAAG,eAAe,UAAU,MAAM;AAC1C,YAAI;AACF,aAAG,KAAK,eAAe,IAAI,CAAC;AAAA,QAC9B,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,UAAM,SAAS,CAAC,MAAc,SAAiB;AAC7C,UAAI,QAAQ,KAAK,QAAQ,EAAG;AAC5B,cAAQ,UAAU,EAAE,MAAM,KAAK;AAC/B,YAAM,KAAK,MAAM;AACjB,UAAI,MAAM,GAAG,eAAe,UAAU,MAAM;AAC1C,YAAI;AACF,aAAG,KAAK,gBAAgB,MAAM,IAAI,CAAC;AAAA,QACrC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,UAAM,aAAa,MAAM;AACvB,YAAM,KAAK,MAAM;AACjB,YAAM,UAAU;AAChB,UAAI,IAAI;AACN,YAAI;AACF,aAAG,MAAM;AAAA,QACX,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,WAAW,WAAW,QAAQ,QAAQ,OAAO,QAAQ,WAAW;AAAA,EAC3E,GAAG,CAAC,MAAM,CAAC;AACb;;;ACxMA,SAAS,oBAAAG,yBAAwB;AACjC,SAAS,eAAAC,eAAa,aAAAC,aAAW,WAAAC,UAAS,UAAAC,UAAQ,YAAAC,kBAAgB;AAiE3D,SAAS,mBACd,WACA,SAC0B;AAC1B,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,uBAAuB,QAAQ,wBAAwB;AAC7D,QAAM,cAAc,QAAQ,eAAe;AAI3C,QAAM,YAAY,QAAQ;AAC1B,QAAM,WAAW,QAAQ;AACzB,QAAM,CAAC,aAAa,cAAc,IAAIC,WAAwB,IAAI;AAClE,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAuB,IAAI;AAI7D,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAS,CAAC;AAShD,QAAM,eAAeC,SAAO,KAAK;AACjC,QAAM,UAAU,aAAa,UAAa,aAAa,UAAU,aAAa;AAC9E,EAAAC,YAAU,MAAM;AACd,QAAI,CAAC,eAAe,CAAC,aAAa,aAAa,CAAC,QAAS;AACzD,QAAI,YAAY;AAChB,iBAAa,UAAU;AACvB,QAAI,WAA0B;AAC9B,SAAK,OACF,gBAAgB,aAAa,WAAW,CAAC,CAAC,EAC1C,KAAK,CAAC,QAAQ;AACb,UAAI,WAAW;AAEb,aAAK,OACF,iBAAiB,aAAa,WAAW,EAAE,OAAO,IAAI,MAAM,CAAC,EAC7D,MAAM,MAAM;AAAA,QAAC,CAAC;AACjB;AAAA,MACF;AACA,iBAAW,IAAI;AACf,qBAAe,IAAI,KAAK;AAAA,IAC1B,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,UAAI,CAAC,UAAW,cAAa,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACxF,CAAC,EACA,QAAQ,MAAM;AACb,mBAAa,UAAU;AAAA,IACzB,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AACZ,qBAAe,IAAI;AACnB,YAAM,KAAK;AACX,UAAI,GAAI,MAAK,OAAO,iBAAiB,aAAa,WAAW,EAAE,OAAO,GAAG,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5F;AAAA,EACF,GAAG,CAAC,aAAa,QAAQ,aAAa,WAAW,WAAW,SAAS,WAAW,CAAC;AAEjF,QAAM,EAAE,QAAQ,SAAS,cAAc,IAAIC,SAAQ,MAAM;AACvD,UAAM,MAAuB,CAAC;AAE9B,UAAM,OAAO,oBAAI,IAAwC;AACzD,QAAI,aAA4B;AAChC,QAAI,oBAAoB;AAExB,eAAW,SAAS,QAAQ,QAAQ;AAClC,UAAI,MAAM,SAAS,wBAAwB;AACzC,cAAM,UAAU,MAAM;AACtB,YAAI,SAAS,OAAO;AAClB,eAAK,IAAI,QAAQ,OAAO,EAAE,eAAe,KAAK,CAAC;AAC/C,uBAAa,QAAQ;AAAA,QACvB;AACA;AAAA,MACF;AACA,UAAI,MAAM,SAAS,uBAAuB;AACxC,cAAM,UAAU,MAAM;AACtB,YAAI,SAAS,OAAO;AAClB,eAAK,OAAO,QAAQ,KAAK;AACzB,cAAI,eAAe,QAAQ,MAAO,cAAa;AAAA,QACjD;AACA;AAAA,MACF;AACA,UAAI,MAAM,SAAS,6BAA6B;AAC9C,cAAM,UAAU,MAAM;AACtB,YAAI,CAAC,WAAY,aAAa,QAAQ,UAAU,UAAY;AAC5D,YAAI,KAAK;AAAA,UACP,IAAI,MAAM;AAAA,UACV,MAAM,QAAQ;AAAA,UACd,QAAQ,QAAQ,WAAW,WAAW,WAAW;AAAA,UACjD,KAAK,MAAM;AAAA,QACb,CAAC;AACD;AAAA,MACF;AACA,UAAI,wBAAwB,CAAC,aAAa,MAAM,SAAS,gCAAgC;AACvF,cAAM,UAAU,MAAM;AACtB,YAAI,CAAC,SAAS,MAAO;AACrB,YAAI,KAAK;AAAA,UACP,IAAI,MAAM;AAAA,UACV,MAAM,QAAQ;AAAA,UACd,QAAQ,QAAQ,WAAW,WAAW,WAAW;AAAA,UACjD,KAAK,MAAM;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAGA,QAAI,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;AAChC,UAAM,YAAY,aAAa,KAAK,IAAI,SAAS,IAAI,YAAY;AACjE,wBAAoB,YAAa,KAAK,IAAI,SAAS,GAAG,iBAAiB,QAAS;AAChF,WAAO,EAAE,QAAQ,KAAK,SAAS,WAAW,eAAe,kBAAkB;AAAA,EAC7E,GAAG,CAAC,QAAQ,QAAQ,WAAW,oBAAoB,CAAC;AAMpD,QAAM,cAAc,eAAe;AAGnC,QAAM,WAAW,gBAAgB,QAAQ;AAEzC,QAAM,QAAQA,SAAQ,MAAM;AAC1B,QAAI,CAAC,eAAe,CAAC,YAAY,CAAC,UAAW,QAAO;AACpD,WAAO,CAAC,SAAiB;AACvB,WAAK,OACF,iBAAiB,aAAa,WAAW,EAAE,OAAO,aAAa,KAAK,CAAC,EACrE,MAAM,CAAC,UAAU;AAIhB,YACE,iBAAiBC,sBAChB,MAAM,WAAW,OAAO,MAAM,WAAW,QAC1C,gBAAgB,aAChB;AACA,yBAAe,IAAI;AACnB,yBAAe,CAAC,MAAM,IAAI,CAAC;AAAA,QAC7B;AAAA,MACF,CAAC;AAAA,IACL;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,aAAa,UAAU,WAAW,CAAC;AAEvE,QAAM,QAAQC,cAAY,MAAM;AAC9B,QAAI,CAAC,eAAe,CAAC,UAAW;AAChC,SAAK,OAAO,iBAAiB,aAAa,WAAW,EAAE,OAAO,YAAY,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7F,GAAG,CAAC,QAAQ,aAAa,WAAW,WAAW,CAAC;AAEhD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,gBAAgB;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACT;AACF;;;AC3NA,SAAS,eAAAC,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;AAiFzD,SAAS,SAAS,MAAsB;AACtC,QAAM,IAAI,KAAK,YAAY,GAAG;AAC9B,SAAO,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG,CAAC;AACtC;AAGA,SAAS,OAAO,MAAsB;AACpC,QAAM,IAAI,KAAK,YAAY,GAAG;AAC9B,SAAO,IAAI,IAAI,OAAO,KAAK,MAAM,IAAI,CAAC;AACxC;AAMA,SAAS,UAAU,OAAuC;AACxD,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC/B,QAAI,EAAE,SAAS,EAAE,KAAM,QAAO,EAAE,SAAS,QAAQ,KAAK;AACtD,WAAO,EAAE,KAAK,cAAc,EAAE,MAAM,QAAW,EAAE,aAAa,OAAO,CAAC;AAAA,EACxE,CAAC;AACH;AAEA,SAAS,aAAa,MAAgC;AACpD,QAAM,OAAO,KAAK,SAAS,QAAQ,QAAQ;AAU3C,QAAM,iBACJ,KAAK,YAAY,KAAK,SAAS,SAAS,IAAI,KAAK,SAAS,IAAI,YAAY,IAAI;AAChF,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,MAAM,KAAK;AAAA,IACX;AAAA,IACA,MAAM,KAAK;AAAA,IACX,GAAI,SAAS,QAAQ,EAAE,UAAU,eAAe,IAAI,CAAC;AAAA;AAAA;AAAA,IAGrD,GAAI,SAAS,SAAS,KAAK,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;AAAA,EAChE;AACF;AAEA,IAAM,qBAAyE;AAAA,EAC7E,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,YAAY;AACd;AAGA,SAAS,gBACP,OACA,YACA,UACgB;AAChB,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,QAAI,KAAK,SAAS,YAAY;AAC5B,aAAO,EAAE,GAAG,MAAM,SAAS;AAAA,IAC7B;AACA,QAAI,KAAK,SAAS,SAAS,KAAK,YAAY,WAAW,WAAW,GAAG,KAAK,IAAI,GAAG,GAAG;AAClF,aAAO,EAAE,GAAG,MAAM,UAAU,gBAAgB,KAAK,UAAU,YAAY,QAAQ,EAAE;AAAA,IACnF;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAGA,SAAS,eAAe,OAAuB,MAAwC;AACrF,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,KAAM,QAAO;AAC/B,QAAI,KAAK,SAAS,SAAS,KAAK,YAAY,KAAK,WAAW,GAAG,KAAK,IAAI,GAAG,GAAG;AAC5E,YAAM,MAAM,eAAe,KAAK,UAAU,IAAI;AAC9C,UAAI,IAAK,QAAO;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AACT;AAiBA,SAAS,eAAe,OAAuB,QAAyB;AACtE,MAAI,WAAW,GAAI,QAAO;AAC1B,QAAM,OAAO,eAAe,OAAO,MAAM;AACzC,SAAO,QAAQ,QAAQ,KAAK,SAAS,SAAS,KAAK,aAAa,MAAS;AAC3E;AAKA,SAAS,WAAW,OAAuB,QAAgB,OAAqC;AAC9F,MAAI,WAAW,IAAI;AACjB,QAAI,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI,EAAG,QAAO;AACrD,WAAO,UAAU,CAAC,GAAG,OAAO,KAAK,CAAC;AAAA,EACpC;AACA,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,QAAI,KAAK,SAAS,QAAQ;AACxB,UAAI,KAAK,SAAS,SAAS,KAAK,aAAa,OAAW,QAAO;AAC/D,UAAI,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI,EAAG,QAAO;AAC7D,aAAO,EAAE,GAAG,MAAM,UAAU,UAAU,CAAC,GAAG,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,IACnE;AACA,QAAI,KAAK,SAAS,SAAS,KAAK,YAAY,OAAO,WAAW,GAAG,KAAK,IAAI,GAAG,GAAG;AAC9E,aAAO,EAAE,GAAG,MAAM,UAAU,WAAW,KAAK,UAAU,QAAQ,KAAK,EAAE;AAAA,IACvE;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAGA,SAAS,WAAW,OAAuB,MAA8B;AACvE,QAAM,SAAS,SAAS,IAAI;AAC5B,MAAI,WAAW,IAAI;AACjB,QAAI,CAAC,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,EAAG,QAAO;AAChD,WAAO,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,EAC5C;AACA,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,QAAI,KAAK,SAAS,QAAQ;AACxB,UAAI,KAAK,SAAS,SAAS,KAAK,aAAa,OAAW,QAAO;AAC/D,aAAO,EAAE,GAAG,MAAM,UAAU,KAAK,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE;AAAA,IAC3E;AACA,QAAI,KAAK,SAAS,SAAS,KAAK,YAAY,OAAO,WAAW,GAAG,KAAK,IAAI,GAAG,GAAG;AAC9E,aAAO,EAAE,GAAG,MAAM,UAAU,WAAW,KAAK,UAAU,IAAI,EAAE;AAAA,IAC9D;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAUA,SAAS,gBAAgB,GAAiB,GAA0B;AAClE,SACE,EAAE,SAAS,EAAE,QACb,EAAE,SAAS,EAAE,QACb,EAAE,SAAS,EAAE,SACZ,EAAE,QAAQ,WAAW,EAAE,QAAQ,UAC/B,EAAE,UAAU,aAAgB,EAAE,UAAU,YACxC,EAAE,aAAa,YAAY,EAAE,aAAa;AAE/C;AAEA,SAAS,cAAc,SAAyB,QAAwC;AACtF,QAAM,SAAS,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAU,CAAC;AAC/D,QAAM,SAAS,OAAO,IAAI,CAAC,SAAS;AAClC,UAAM,WAAW,OAAO,IAAI,KAAK,IAAI;AACrC,QAAI,CAAC,SAAU,QAAO;AAGtB,QAAI,SAAS,SAAS,SAAS,KAAK,SAAS,SAAS,SAAS,aAAa,QAAW;AACrF,YAAM,YAA0B,EAAE,GAAG,MAAM,UAAU,SAAS,SAAS;AAEvE,aAAO,gBAAgB,UAAU,SAAS,IAAI,WAAW;AAAA,IAC3D;AAEA,QAAI,SAAS,aAAa,KAAK,YAAY,gBAAgB,UAAU,IAAI,GAAG;AAC1E,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC;AACD,SAAO,UAAU,MAAM;AACzB;AAIA,SAAS,kBAAkB,OAAuB,QAAwC;AACxF,SAAO,cAAc,OAAO,MAAM;AACpC;AAIA,SAAS,WAAW,MAAoB,YAAoB,UAAgC;AAC1F,QAAM,UAAU,WAAW,KAAK,KAAK,MAAM,WAAW,MAAM;AAC5D,QAAM,OAAqB,EAAE,GAAG,MAAM,MAAM,SAAS,MAAM,OAAO,OAAO,EAAE;AAC3E,MAAI,KAAK,SAAU,MAAK,WAAW,KAAK,SAAS,IAAI,CAAC,MAAM,WAAW,GAAG,YAAY,QAAQ,CAAC;AAC/F,SAAO;AACT;AASO,SAAS,gBACd,WACA,UAAkC,CAAC,GACZ;AACvB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,WAAW,QAAQ,YAAY;AAErC,QAAM,CAAC,MAAM,OAAO,IAAIC,WAAyB,CAAC,CAAC;AAKnD,QAAM,UAAUC,SAAuB,CAAC,CAAC;AACzC,QAAM,CAAC,SAAS,UAAU,IAAID,WAAS,KAAK;AAC5C,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAsB,oBAAI,IAAI,CAAC;AAC3E,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AAErD,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAoC,IAAI;AACpE,QAAM,YAAYC,SAAoC,oBAAI,IAAI,CAAC;AAG/D,QAAM,uBAAuBA,SAAO,CAAC;AACrC,QAAM,wBAAwBA,SAAO,CAAC;AACtC,QAAM,aAAaA,SAAO,CAAC;AAC3B,QAAM,oBAAoBA,SAAoB,oBAAI,IAAI,CAAC;AACvD,QAAM,gBAAgBA,SAAO,KAAK;AAClC,QAAM,cAAcA,SAA6C,IAAI;AAUrE,QAAM,kBAAkBA,SAAoB,oBAAI,IAAI,CAAC;AACrD,QAAM,kBAAkB,QAAQ;AAGhC,UAAQ,UAAU;AAOlB,QAAM,cAAcC,cAAY,CAAC,UAA0C;AACzE,UAAM,UAAU,UAAU;AAC1B,UAAM,OAAO,CAAC,SAAyC;AACrD,UAAI,UAAU;AACd,YAAM,MAAM,KAAK,IAAI,CAAC,SAAS;AAC7B,cAAM,eAAe,KAAK,WAAW,KAAK,KAAK,QAAQ,IAAI,KAAK;AAChE,cAAM,aAAa,KAAK,SAAS,SAAS,QAAQ,IAAI,KAAK,IAAI,IAAI;AACnE,cAAM,kBAAkB,iBAAiB,KAAK;AAC9C,cAAM,iBAAiB,KAAK,UAAU,aAAgB,cAAc;AACpE,YAAI,CAAC,mBAAmB,CAAC,cAAe,QAAO;AAC/C,kBAAU;AACV,cAAM,OAAqB;AAAA,UACzB,GAAG;AAAA,UACH,GAAI,KAAK,WAAW,EAAE,UAAU,aAAa,IAAI,CAAC;AAAA,QACpD;AACA,YAAI,WAAY,MAAK,SAAS;AAAA,YACzB,QAAO,KAAK;AACjB,eAAO;AAAA,MACT,CAAC;AACD,aAAO,UAAU,MAAM;AAAA,IACzB;AACA,WAAO,KAAK,KAAK;AAAA,EACnB,GAAG,CAAC,CAAC;AAEL,QAAM,UAAUA,cAAY,YAAY;AACtC,QAAI,CAAC,UAAW;AAChB,UAAM,aAAc,qBAAqB,WAAW;AACpD,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AAGF,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,UAAU,aAAa,WAAW,EAAE,MAAM,SAAS,CAAC;AAChF,YAAI,qBAAqB,YAAY,WAAY;AACjD,cAAM,UAAU,oBAAI,IAA4B;AAChD,mBAAW,QAAQ,OAAO,OAAO;AAC/B,gBAAM,OAAO,KAAK,YAAY,KAAK;AACnC,gBAAM,SAAS,OAAO,mBAAmB,IAAI,IAAI;AACjD,cAAI,OAAQ,SAAQ,IAAI,KAAK,MAAM,MAAM;AAAA,QAC3C;AACA,kBAAU,UAAU;AAAA,MACtB,QAAQ;AACN,YAAI,qBAAqB,YAAY,WAAY;AACjD,kBAAU,UAAU,oBAAI,IAAI;AAAA,MAC9B;AACA,YAAM,SAAS,MAAM,OAAO,OAAO,aAAa,WAAW,EAAE,MAAM,UAAU,OAAO,EAAE,CAAC;AACvF,UAAI,qBAAqB,YAAY,WAAY;AACjD,YAAM,YAAY,OAAO,KAAK,YAAY,CAAC,GAAG,IAAI,YAAY;AAK9D;AAAA,QAAQ,CAAC,SACP,YAAY,KAAK,WAAW,IAAI,WAAW,kBAAkB,MAAM,QAAQ,CAAC;AAAA,MAC9E;AAEA,gBAAU,MAAM;AAAA,IAClB,SAAS,OAAO;AACd,UAAI,qBAAqB,YAAY,WAAY;AACjD,eAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACpE,UAAE;AACA,UAAI,qBAAqB,YAAY,WAAY,YAAW,KAAK;AAAA,IACnE;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,UAAU,WAAW,CAAC;AAO1D,QAAM,kBAAkBA;AAAA,IACtB,CAAC,aAAuC;AACtC,YAAM,UAAU,oBAAI,IAA4B;AAChD,iBAAW,QAAQ,SAAS,OAAO;AACjC,YAAI,KAAK,QAAS;AAClB,cAAM,SAAS,mBAAmB,KAAK,MAAM;AAC7C,YAAI,OAAQ,SAAQ,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3C;AACA,gBAAU,UAAU;AACpB,YAAM,YAAY,SAAS,UAAU,YAAY,CAAC,GAAG,IAAI,YAAY;AACrE;AAAA,QAAQ,CAAC,SACP,YAAY,KAAK,WAAW,IAAI,WAAW,kBAAkB,MAAM,QAAQ,CAAC;AAAA,MAC9E;AACA,gBAAU,SAAS;AACnB,eAAS,IAAI;AAAA,IACf;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,SAAiB;AACtB,UAAI,CAAC,UAAW;AAChB,YAAM,qBAAqB,sBAAsB;AAIjD,wBAAkB,CAAC,SAAS;AAC1B,cAAM,OAAO,IAAI,IAAI,IAAI;AACzB,aAAK,IAAI,IAAI;AACb,eAAO;AAAA,MACT,CAAC;AACD,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,OAAO,aAAa,WAAW,EAAE,MAAM,OAAO,EAAE,CAAC;AAC7E,YAAI,sBAAsB,YAAY,mBAAoB;AAC1D,cAAM,YAAY,OAAO,KAAK,YAAY,CAAC,GAAG,IAAI,YAAY;AAC9D,gBAAQ,CAAC,SAAS,YAAY,gBAAgB,MAAM,MAAM,QAAQ,CAAC,CAAC;AAAA,MACtE,SAAS,OAAO;AACd,YAAI,sBAAsB,YAAY,mBAAoB;AAC1D,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,MACpE,UAAE;AACA,YAAI,sBAAsB,YAAY,oBAAoB;AACxD,4BAAkB,CAAC,SAAS;AAC1B,gBAAI,CAAC,KAAK,IAAI,IAAI,EAAG,QAAO;AAC5B,kBAAM,OAAO,IAAI,IAAI,IAAI;AACzB,iBAAK,OAAO,IAAI;AAChB,mBAAO;AAAA,UACT,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,WAAW;AAAA,EAC9C;AAEA,QAAM,WAAWA;AAAA,IACf,OAAO,SAAiB;AACtB,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,YAAY;AAC5C,aAAO,MAAM,OAAO,OAAO,aAAa,WAAW,EAAE,KAAK,CAAC;AAAA,IAC7D;AAAA,IACA,CAAC,QAAQ,aAAa,SAAS;AAAA,EACjC;AASA,QAAM,gBAAgBA;AAAA,IACpB,OAAO,SAAiB;AACtB,UAAI,CAAC,UAAW;AAChB,YAAM,qBAAqB,sBAAsB;AAGjD,UAAI,CAAC,eAAe,QAAQ,SAAS,IAAI,EAAG;AAC5C,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,OAAO,aAAa,WAAW,EAAE,MAAM,OAAO,EAAE,CAAC;AAC7E,YAAI,sBAAsB,YAAY,mBAAoB;AAC1D,cAAM,YAAY,OAAO,KAAK,YAAY,CAAC,GAAG,IAAI,YAAY;AAC9D,YAAI,SAAS,GAAI,SAAQ,CAAC,SAAS,YAAY,kBAAkB,MAAM,QAAQ,CAAC,CAAC;AAAA;AAE/E,kBAAQ,CAAC,SAAS;AAChB,kBAAM,WAAW,eAAe,MAAM,IAAI;AAC1C,kBAAM,SAAS,UAAU,WACrB,cAAc,SAAS,UAAU,QAAQ,IACzC;AACJ,mBAAO,YAAY,gBAAgB,MAAM,MAAM,MAAM,CAAC;AAAA,UACxD,CAAC;AAAA,MACL,QAAQ;AAAA,MAGR;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,WAAW;AAAA,EAC9C;AASA,QAAM,gBAAgBA;AAAA,IACpB,OACE,QACA,OACA,IACA,qBACe;AACf,YAAM,qBAAqB,sBAAsB;AAEjD,YAAM,WAAW,QAAQ;AACzB,cAAQ,YAAY,MAAM,QAAQ,CAAC,CAAC;AACpC,UAAI;AACF,cAAM,MAAM,MAAM,GAAG;AACrB,YAAI,sBAAsB,YAAY,mBAAoB,QAAO;AAGjE,YAAI,OAAO,OAAO,QAAQ,YAAY,cAAc,KAAK;AACvD,gBAAM,MAAO,IAA+B;AAC5C,cAAI,OAAO,QAAQ,SAAU,iBAAgB,QAAQ,IAAI,GAAG;AAAA,QAC9D;AAGA,mBAAW,UAAU,kBAAkB;AACrC,cAAI,sBAAsB,YAAY,mBAAoB,QAAO;AACjE,gBAAM,cAAc,MAAM;AAAA,QAC5B;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,cAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AACpE,YAAI,sBAAsB,YAAY,mBAAoB,OAAM;AAEhE,gBAAQ,YAAY,QAAQ,CAAC;AAC7B,iBAAS,GAAG;AACZ,0BAAkB,KAAK,MAAM;AAC7B,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,aAAa,eAAe,eAAe;AAAA,EAC9C;AAEA,QAAM,YAAYA;AAAA,IAChB,OAAO,MAAc,YAA8C;AACjE,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,YAAY;AAC5C,YAAM,SAAS,SAAS,IAAI;AAI5B,YAAM,SAAS,QAAQ,eAAe,MAAM,IAAI,CAAC;AACjD,YAAM,OAAqB,EAAE,MAAM,MAAM,OAAO,IAAI,GAAG,MAAM,QAAQ,MAAM,QAAQ,OAAO;AAC1F,aAAO,MAAM;AAAA,QACX;AAAA,QACA,CAAC,UAAW,SAAS,QAAQ,WAAW,OAAO,QAAQ,IAAI;AAAA,QAC3D,MAAM,OAAO,QAAQ,aAAa,WAAW,EAAE,MAAM,SAAS,WAAW,KAAK,CAAC;AAAA,QAC/E,SAAS,CAAC,IAAI,CAAC,MAAM;AAAA,MACvB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,MAAM,aAAa;AAAA,EACtD;AAEA,QAAM,aAAaA;AAAA,IACjB,OAAO,SAAgC;AACrC,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,YAAY;AAC5C,YAAM,SAAS,SAAS,IAAI;AAC5B,YAAM,OAAqB,EAAE,MAAM,MAAM,OAAO,IAAI,GAAG,MAAM,QAAQ,MAAM,EAAE;AAC7E,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,UAAU,WAAW,OAAO,QAAQ,IAAI;AAAA,QACzC,MAAM,OAAO,QAAQ,aAAa,WAAW,EAAE,MAAM,SAAS,IAAI,WAAW,MAAM,CAAC;AAAA,QACpF,CAAC,MAAM;AAAA,MACT;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,aAAa;AAAA,EAChD;AAEA,QAAM,YAAYA;AAAA,IAChB,OAAO,SAAgC;AACrC,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,YAAY;AAC5C,YAAM,SAAS,SAAS,IAAI;AAG5B,YAAM,OAAqB,EAAE,MAAM,MAAM,OAAO,IAAI,GAAG,MAAM,OAAO,UAAU,CAAC,EAAE;AACjF,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,UAAU,WAAW,OAAO,QAAQ,IAAI;AAAA,QACzC,MAAM,OAAO,QAAQ,aAAa,WAAW,EAAE,MAAM,WAAW,KAAK,CAAC;AAAA,QACtE,CAAC,MAAM;AAAA,MACT;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,aAAa;AAAA,EAChD;AAEA,QAAM,cAAcA;AAAA,IAClB,OAAO,MAAc,YAAY,UAAyB;AACxD,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,YAAY;AAC5C,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,UAAU,WAAW,OAAO,IAAI;AAAA,QACjC,MAAM,OAAO,SAAS,aAAa,WAAW,EAAE,MAAM,UAAU,CAAC;AAAA,QACjE,CAAC,SAAS,IAAI,CAAC;AAAA,MACjB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,aAAa;AAAA,EAChD;AAEA,QAAM,YAAYA;AAAA,IAChB,OAAO,MAAc,SAAiB,SAAkD;AACtF,UAAI,CAAC,UAAW,OAAM,IAAI,MAAM,YAAY;AAC5C,YAAM,OAAO,SAAS,IAAI;AAC1B,YAAM,KAAK,SAAS,OAAO;AAC3B,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,UAAU;AACT,gBAAM,SAAS,eAAe,OAAO,IAAI;AACzC,cAAI,CAAC,OAAQ,QAAO;AAEpB,gBAAM,QAAQ,WAAW,QAAQ,MAAM,OAAO;AAC9C,iBAAO,WAAW,WAAW,OAAO,IAAI,GAAG,IAAI,KAAK;AAAA,QACtD;AAAA,QACA,MACE,OAAO,OAAO,aAAa,WAAW;AAAA,UACpC;AAAA,UACA;AAAA,UACA,WAAW,MAAM,aAAa;AAAA,QAChC,CAAC;AAAA,QACH,OAAO,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE;AAAA,MAClC;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,aAAa;AAAA,EAChD;AAQA,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAMC,UAAS,QAAQ,aAAa,UAAU,QAAQ,aAAa;AAInE,QAAM,aAAaF,SAAwC,OAAO;AAClE,aAAW,UAAU;AACrB,QAAM,kBAAkB,SAAS,YAAY;AAC7C,QAAM,cAAc,GAAG,WAAW,KAAS,aAAa,EAAE,KAAS,QAAQ;AAC3E,QAAM,sBAAsBA,SAAO,WAAW;AAC9C,EAAAG,YAAU,MAAM;AAId,yBAAqB,WAAW;AAChC,UAAM,kBAAkB,oBAAoB,YAAY;AACxD,wBAAoB,UAAU;AAC9B,QAAI,mBAAmB,CAAC,SAAS;AAC/B,4BAAsB,WAAW;AACjC,iBAAW,UAAU;AACrB,wBAAkB,UAAU,oBAAI,IAAI;AACpC,oBAAc,UAAU;AACxB,UAAI,YAAY,SAAS;AACvB,qBAAa,YAAY,OAAO;AAChC,oBAAY,UAAU;AAAA,MACxB;AACA,sBAAgB,UAAU,oBAAI,IAAI;AAClC,gBAAU,UAAU,oBAAI,IAAI;AAC5B,cAAQ,UAAU,CAAC;AACnB,cAAQ,CAAC,CAAC;AACV,wBAAkB,oBAAI,IAAI,CAAC;AAC3B,gBAAU,IAAI;AACd,iBAAW,KAAK;AAChB,eAAS,IAAI;AAAA,IACf;AACA,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,QAAID,SAAQ;AACV,WAAK,QAAQ;AAAA,IACf,WAAW,oBAAoB,QAAQ,WAAW,SAAS;AACzD,sBAAgB,WAAW,OAAO;AAAA,IACpC,OAAO;AACL,WAAK,QAAQ;AAAA,IACf;AACA,WAAO,MAAM;AACX,2BAAqB,WAAW;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,SAASA,SAAQ,iBAAiB,aAAa,SAAS,eAAe,CAAC;AAK5E,QAAM,oBAAoBD,cAAY,YAAY;AAChD,QAAI,CAAC,UAAW;AAChB,UAAM,qBAAqB,sBAAsB;AACjD,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,UAAU,aAAa,WAAW,EAAE,MAAM,SAAS,CAAC;AAChF,UAAI,sBAAsB,YAAY,mBAAoB;AAC1D,YAAM,UAAU,oBAAI,IAA4B;AAChD,iBAAW,QAAQ,OAAO,OAAO;AAC/B,cAAM,OAAO,KAAK,YAAY,KAAK;AACnC,cAAM,SAAS,OAAO,mBAAmB,IAAI,IAAI;AACjD,YAAI,OAAQ,SAAQ,IAAI,KAAK,MAAM,MAAM;AAAA,MAC3C;AACA,gBAAU,UAAU;AACpB,cAAQ,CAAC,SAAS,YAAY,IAAI,CAAC;AAAA,IACrC,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,UAAU,WAAW,CAAC;AAY1D,QAAM,SAAS,QAAQ;AAEvB,EAAAE,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,OAAQ;AACzB,QAAI,SAAS;AACb,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,YAAY,WAAW,QAAS;AAC1C,UAAI,MAAM,SAAS,cAAc;AAC/B,iBAAS;AACT,cAAM,UAAU,MAAM;AACtB,YAAI,CAAC,WAAW,OAAO,YAAY,SAAU;AAE7C,YAAI,QAAQ,WAAW,QAAS;AAChC,YAAI,OAAO,QAAQ,aAAa,YAAY,gBAAgB,QAAQ,IAAI,QAAQ,QAAQ;AACtF;AACF,mBAAW,UAAU,QAAQ,WAAW,CAAC,GAAG;AAC1C,4BAAkB,QAAQ,IAAI,SAAS,OAAO,IAAI,CAAC;AACnD,cAAI,OAAO,QAAS,mBAAkB,QAAQ,IAAI,SAAS,OAAO,OAAO,CAAC;AAAA,QAC5E;AAAA,MACF,WAAW,MAAM,SAAS,eAAe;AACvC,iBAAS;AACT,cAAM,UAAU,MAAM;AAItB,YACE,WACA,OAAO,YAAY,YACnB,OAAO,QAAQ,aAAa,YAC5B,gBAAgB,QAAQ,IAAI,QAAQ,QAAQ;AAE5C;AACF,sBAAc,UAAU;AAAA,MAC1B;AAAA,IACF;AAEA,eAAW,SAAS;AAClB,UAAI,MAAM,WAAW,WAAW,QAAS,YAAW,UAAU,MAAM;AACtE,QAAI,CAAC,OAAQ;AAEb,QAAI,YAAY,QAAS,cAAa,YAAY,OAAO;AACzD,UAAM,qBAAqB,sBAAsB;AACjD,gBAAY,UAAU,WAAW,MAAM;AACrC,kBAAY,UAAU;AACtB,UAAI,sBAAsB,YAAY,mBAAoB;AAC1D,YAAM,UAAU,kBAAkB;AAClC,wBAAkB,UAAU,oBAAI,IAAI;AACpC,YAAM,UAAU,cAAc;AAC9B,oBAAc,UAAU;AAGxB,YAAM,YAAY;AAChB,YAAI,QAAS,OAAM,kBAAkB;AACrC,YAAI,sBAAsB,YAAY,mBAAoB;AAC1D,mBAAW,UAAU,SAAS;AAC5B,cAAI,sBAAsB,YAAY,mBAAoB;AAC1D,gBAAM,cAAc,MAAM;AAAA,QAC5B;AAAA,MACF,GAAG;AAAA,IACL,GAAG,GAAG;AAAA,EACR,GAAG,CAAC,SAAS,QAAQ,eAAe,iBAAiB,CAAC;AAEtD,EAAAA;AAAA,IACE,MAAM,MAAM;AACV,4BAAsB,WAAW;AACjC,UAAI,YAAY,QAAS,cAAa,YAAY,OAAO;AAAA,IAC3D;AAAA,IACA,CAAC;AAAA,EACH;AAOA,QAAM,aAAaH,SAAO,KAAK;AAC/B,QAAM,WAAW,QAAQ;AACzB,EAAAG,YAAU,MAAM;AACd,UAAM,OAAO,aAAa,UAAU,aAAa;AACjD,QAAI,WAAW,QAAQ,CAAC,WAAW,SAAS;AAC1C,iBAAW,UAAU;AACrB,WAAK,QAAQ;AAAA,IACf,WAAW,CAAC,MAAM;AAChB,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,SAAS,UAAU,OAAO,CAAC;AAE/B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,WAAW,YAAa,SAAS,cAAc,OAAQ;AAAA,IACnE;AAAA,IACA;AAAA,EACF;AACF;;;ACr0BA,SAAS,eAAAC,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;AAwCzD,SAAS,cAAc,MAAsB;AAC3C,SAAO,SAAS,MAAM,KAAK;AAC7B;AAGA,SAAS,YACP,UACA,UAC6B;AAC7B,QAAM,OAAO,cAAc,QAAQ;AACnC,QAAM,QAAQ,SAAS,MAAM,KAAK,CAAC,MAAM,cAAc,EAAE,IAAI,MAAM,IAAI;AACvE,MAAI,MAAO,QAAO;AAGlB,MAAI,SAAS,MAAM,SAAS,MAAM,WAAW,EAAG,QAAO,SAAS,MAAM,CAAC,KAAK;AAC5E,SAAO;AACT;AAIA,SAAS,aAAa,GAAgB,GAAyB;AAC7D,MACE,EAAE,SAAS,EAAE,QACb,EAAE,YAAY,EAAE,WAChB,EAAE,WAAW,EAAE,UACf,EAAE,aAAa,EAAE,YACjB,EAAE,YAAY,EAAE,WAChB,EAAE,cAAc,EAAE,aAClB,EAAE,cAAc,EAAE,aAClB,EAAE,cAAc,EAAE,aAClB,EAAE,MAAM,WAAW,EAAE,MAAM;AAE3B,WAAO;AAET,SAAO,EAAE,MAAM,MAAM,CAAC,MAAM,cAAc;AACxC,UAAM,QAAQ,EAAE,MAAM,SAAS;AAC/B,QACE,CAAC,SACD,KAAK,aAAa,MAAM,YACxB,KAAK,aAAa,MAAM,YACxB,KAAK,aAAa,MAAM,YACxB,KAAK,aAAa,MAAM,YACxB,KAAK,WAAW,MAAM,UACtB,KAAK,MAAM,WAAW,MAAM,MAAM;AAElC,aAAO;AACT,WAAO,KAAK,MAAM,MAAM,CAAC,MAAM,cAAc;AAC3C,YAAM,YAAY,MAAM,MAAM,SAAS;AACvC,aACE,cAAc,UACd,KAAK,SAAS,UAAU,QACxB,KAAK,UAAU,UAAU,SACzB,KAAK,UAAU,UAAU,SACzB,KAAK,SAAS,UAAU;AAAA,IAE5B,CAAC;AAAA,EACH,CAAC;AACH;AAKA,SAAS,WAAW,SAAwB,MAAoC;AAC9E,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QAAM,SAAS,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAU,CAAC;AAC/D,MAAI,UAAU,QAAQ,WAAW,KAAK;AACtC,QAAM,SAAS,KAAK,IAAI,CAAC,MAAM,UAAU;AACvC,UAAM,WAAW,OAAO,IAAI,KAAK,IAAI;AACrC,QAAI,YAAY,aAAa,UAAU,IAAI,GAAG;AAC5C,UAAI,QAAQ,KAAK,MAAM,SAAU,WAAU;AAC3C,aAAO;AAAA,IACT;AACA,cAAU;AACV,WAAO;AAAA,EACT,CAAC;AACD,SAAO,UAAU,SAAS;AAC5B;AAUO,SAAS,cACd,WACA,UAAgC,CAAC,GACZ;AACrB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAMC,UAAS,QAAQ,aAAa,UAAU,QAAQ,aAAa;AAEnE,QAAM,CAAC,MAAM,OAAO,IAAIC,WAAwB,CAAC,CAAC;AAClD,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAwB,IAAI;AACxD,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAS,KAAK;AAC1C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAS,CAAC;AACpC,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAS,CAAC;AACtC,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAoC,IAAI;AACpE,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AAGrD,QAAM,uBAAuBC,SAAO,CAAC;AACrC,QAAM,gBAAgBA,SAAO,CAAC;AAE9B,QAAM,UAAUC,cAAY,YAAY;AACtC,QAAI,CAAC,UAAW;AAChB,UAAM,aAAc,qBAAqB,WAAW;AACpD,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,MAAM,OAAO,UAAU,aAAa,WAAW,EAAE,MAAM,SAAS,CAAC;AAChF,UAAI,qBAAqB,YAAY,WAAY;AACjD,gBAAU,OAAO,MAAM;AACvB,gBAAU,OAAO,IAAI;AACrB,eAAS,OAAO,KAAK;AACrB,gBAAU,OAAO,MAAM;AACvB,UAAI,CAAC,OAAO,QAAQ;AAClB,gBAAQ,CAAC,CAAC;AACV,kBAAU,MAAM;AAChB;AAAA,MACF;AACA,YAAM,SAAS,MAAM,OAAO,QAAQ,aAAa,WAAW,EAAE,MAAM,UAAU,OAAO,CAAC;AACtF,UAAI,qBAAqB,YAAY,WAAY;AAEjD,cAAQ,CAAC,SAAS,WAAW,MAAM,OAAO,KAAK,CAAC;AAChD,gBAAU,MAAM;AAAA,IAClB,SAAS,OAAO;AACd,UAAI,qBAAqB,YAAY,WAAY;AACjD,eAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACpE,UAAE;AACA,UAAI,qBAAqB,YAAY,WAAY,YAAW,KAAK;AAAA,IACnE;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,UAAU,MAAM,CAAC;AAIrD,QAAM,kBAAkBA;AAAA,IACtB,CAAC,aAAuC;AACtC,YAAM,OAAO,YAAY,UAAU,QAAQ;AAC3C,UAAI,CAAC,MAAM;AACT,kBAAU,KAAK;AACf,kBAAU,IAAI;AACd,iBAAS,CAAC;AACV,kBAAU,CAAC;AACX,gBAAQ,CAAC,SAAU,KAAK,WAAW,IAAI,OAAO,CAAC,CAAE;AACjD,kBAAU,SAAS;AACnB;AAAA,MACF;AACA,gBAAU,IAAI;AACd,gBAAU,KAAK,IAAI;AACnB,eAAS,KAAK,KAAK;AACnB,gBAAU,KAAK,MAAM;AACrB,cAAQ,CAAC,SAAS,WAAW,MAAM,KAAK,IAAI,CAAC;AAC7C,gBAAU,SAAS;AACnB,eAAS,IAAI;AAAA,IACf;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAKA,QAAM,aAAaD,SAAwC,OAAO;AAClE,aAAW,UAAU;AACrB,QAAM,kBAAkB,SAAS,YAAY;AAC7C,QAAM,cAAc,GAAG,WAAW,KAAS,aAAa,EAAE,KAAS,QAAQ,KAAS,MAAM;AAC1F,QAAM,sBAAsBA,SAAO,WAAW;AAC9C,EAAAE,YAAU,MAAM;AAGd,yBAAqB,WAAW;AAChC,UAAM,kBAAkB,oBAAoB,YAAY;AACxD,wBAAoB,UAAU;AAC9B,QAAI,mBAAmB,CAAC,SAAS;AAC/B,oBAAc,UAAU;AACxB,cAAQ,CAAC,CAAC;AACV,gBAAU,KAAK;AACf,gBAAU,IAAI;AACd,eAAS,CAAC;AACV,gBAAU,CAAC;AACX,gBAAU,IAAI;AACd,iBAAW,KAAK;AAChB,eAAS,IAAI;AAAA,IACf;AACA,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,QAAIJ,SAAQ;AACV,WAAK,QAAQ;AAAA,IACf,WAAW,oBAAoB,QAAQ,WAAW,SAAS;AACzD,sBAAgB,WAAW,OAAO;AAAA,IACpC,OAAO;AACL,WAAK,QAAQ;AAAA,IACf;AACA,WAAO,MAAM;AACX,2BAAqB,WAAW;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,SAASA,SAAQ,iBAAiB,aAAa,SAAS,eAAe,CAAC;AAK5E,QAAM,SAAS,QAAQ;AACvB,EAAAI,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,OAAQ;AACzB,QAAI,SAAS,cAAc;AAC3B,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,SAAS,iBAAiB,MAAM,WAAW,QAAQ;AAC3D,iBAAS,MAAM;AAAA,MACjB;AAAA,IACF;AACA,QAAI,SAAS,cAAc,SAAS;AAClC,oBAAc,UAAU;AACxB,WAAK,QAAQ;AAAA,IACf;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,OAAO,CAAC;AAE7B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,WAAW,YAAa,SAAS,cAAc,OAAQ;AAAA,IACnE;AAAA,IACA;AAAA,EACF;AACF;;;ACjRA,SAAS,eAAAC,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;AAIzD,IAAM,oBAAoB;AAC1B,IAAM,oBAAoB;AAC1B,IAAM,4BAA4B;AAkD3B,SAAS,oBACd,WACA,UAAsC,CAAC,GACZ;AAC3B,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,WAAW,QAAQ,WAAW,SAAS,QAAQ,SAAS;AAC9D,QAAM,cAAc,GAAG,WAAW,KAAS,aAAa,EAAE;AAE1D,QAAM,CAAC,SAAS,UAAU,IAAIC,WAA0C,IAAI;AAC5E,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,KAAK;AAChD,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAgD,IAAI;AAGhG,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAwB,IAAI;AAC9D,QAAM,CAAC,SAAS,UAAU,IAAIA,WAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AAGrD,QAAM,CAAC,mBAAmB,oBAAoB,IAAIA,WAAwB,IAAI;AAI9E,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAS,WAAW;AAI9D,QAAM,gBAAgBC,SAAO,CAAC;AAG9B,QAAM,aAAaA,SAAO,CAAC;AAE3B,QAAM,UAAUC,cAAY,YAAY;AACtC,QAAI,CAAC,UAAW;AAChB,UAAM,aAAc,cAAc,WAAW;AAC7C,qBAAiB,WAAW;AAC5B,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,MAAmC,MAAM,OAAO;AAAA,QACpD;AAAA,QACA;AAAA,MACF;AACA,UAAI,cAAc,YAAY,WAAY;AAC1C,UAAI,CAAC,IAAI,WAAW;AAClB,mBAAW,IAAI;AACf,qBAAa,KAAK;AAClB,qBAAa,CAAC;AACd,0BAAkB,IAAI,kBAAkB,IAAI;AAC5C;AAAA,MACF;AACA,wBAAkB,IAAI;AAGtB,mBAAa,IAAI,MAAM,SAAS;AAGhC,UAAI,WAAW,IAAI;AACnB,UAAI,CAAC,YAAY,IAAI,aAAa;AAChC,cAAM,WAAW,MAAM,MAAM,IAAI,YAAY,KAAK;AAAA,UAChD,QAAQ,YAAY,QAAQ,yBAAyB;AAAA,QACvD,CAAC;AACD,YAAI,cAAc,YAAY,WAAY;AAC1C,YAAI,CAAC,SAAS;AACZ,gBAAM,IAAI,MAAM,4CAA4C,SAAS,MAAM,EAAE;AAC/E,mBAAY,MAAM,SAAS,KAAK;AAChC,YAAI,cAAc,YAAY,WAAY;AAAA,MAC5C;AACA,UAAI,CAAC,UAAU;AAEb,mBAAW,IAAI;AACf,qBAAa,KAAK;AAClB;AAAA,MACF;AACA,iBAAW,QAAQ;AACnB,mBAAa,IAAI;AAGjB;AAAA,QAAqB,CAAC,SACpB,SAAS,QAAQ,SAAS,WAAW,OAAO,SAAS,WAAW;AAAA,MAClE;AAAA,IACF,SAAS,OAAO;AACd,UAAI,cAAc,YAAY,WAAY;AAC1C,eAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACpE,UAAE;AACA,UAAI,cAAc,YAAY,WAAY,YAAW,KAAK;AAAA,IAC5D;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,WAAW,WAAW,CAAC;AAGhD,EAAAC,YAAU,MAAM;AAGd,kBAAc,WAAW;AACzB,eAAW,UAAU;AACrB,eAAW,IAAI;AACf,iBAAa,KAAK;AAClB,sBAAkB,IAAI;AACtB,iBAAa,IAAI;AACjB,yBAAqB,IAAI;AACzB,aAAS,IAAI;AACb,QAAI,CAAC,SAAS;AACZ,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,SAAK,QAAQ;AACb,WAAO,MAAM;AACX,oBAAc,WAAW;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,SAAS,OAAO,CAAC;AAMrB,QAAM,SAAS,QAAQ;AACvB,EAAAA,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,OAAQ;AACzB,QAAI,SAAwB;AAC5B,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,YAAY,WAAW,QAAS;AAC1C,UAAI,MAAM,SAAS,mBAAmB;AACpC,cAAM,UAAU,MAAM;AACtB,YAAI,WAAW,OAAO,YAAY,YAAY,OAAO,QAAQ,aAAa,UAAU;AAClF,mBAAS,WAAW,OAAO,QAAQ,WAAW,KAAK,IAAI,QAAQ,QAAQ,QAAQ;AAAA,QACjF;AAAA,MACF,WAAW,MAAM,SAAS,mBAAmB;AAC3C,cAAM,UAAU,MAAM;AACtB,YAAI,WAAW,OAAO,YAAY,YAAY,OAAO,QAAQ,aAAa,UAAU;AAClF,mBAAS,WAAW,OAAO,QAAQ,WAAW,KAAK,IAAI,QAAQ,QAAQ,QAAQ;AAAA,QACjF;AAAA,MACF;AAAA,IACF;AACA,eAAW,SAAS;AAClB,UAAI,MAAM,WAAW,WAAW,QAAS,YAAW,UAAU,MAAM;AACtE,QAAI,WAAW,KAAM;AACrB,yBAAqB,CAAC,SAAU,SAAS,QAAQ,SAAS,OAAO,SAAS,IAAK;AAAA,EACjF,GAAG,CAAC,SAAS,MAAM,CAAC;AAGpB,QAAM,kBAAkB,WAAW,kBAAkB;AACrD,QAAM,iBAAiB,kBAAkB,UAAU;AACnD,QAAM,2BAA2B,kBAAkB,oBAAoB;AACvE,QAAM,iBAAiB,gBAAgB,YAAY;AACnD,EAAAA,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,QAAI,6BAA6B,KAAM;AACvC,QAAI,mBAAmB,QAAQ,4BAA4B,eAAgB;AAE3E,SAAK,QAAQ;AAAA,EACf,GAAG,CAAC,SAAS,0BAA0B,gBAAgB,OAAO,CAAC;AAE/D,QAAM,UACJ,mBAAmB,QACnB,6BAA6B,QAC7B,2BAA2B;AAE7B,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY,gBAAgB,cAAc;AAAA,IAC1C,WAAW,mBAAmB;AAAA,IAC9B,gBAAgB,kBAAkB,iBAAiB;AAAA,IACnD,WAAW,kBAAkB,YAAY;AAAA,IACzC;AAAA,IACA,SAAS,mBAAmB;AAAA,IAC5B,OAAO,kBAAkB,QAAQ;AAAA,IACjC;AAAA,EACF;AACF;;;ACxOA,SAAS,eAAAC,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;AA0EzD,SAAS,OAAO,UAAuC;AACrD,SAAO,aAAa,UAAU,aAAa;AAC7C;AAaO,SAAS,iBACd,WACA,UAAmC,CAAC,GACZ;AACxB,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,OAAO,OAAO,QAAQ,QAAQ;AACpC,QAAM,UAAU,QAAQ,YAAY;AAEpC,QAAM,CAAC,QAAQ,SAAS,IAAIC,WAAwB,IAAI;AACxD,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,KAAK;AAChD,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuD,MAAM;AACvF,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAuC,IAAI;AAC3E,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAuB,IAAI;AAErD,QAAM,kBAAkB,QAAQ;AAChC,QAAM,YAAYC,SAAsB,IAAI;AAC5C,YAAU,UAAU;AAEpB,QAAM,cAAcA,SAAO,KAAK;AAGhC,EAAAC,YAAU,MAAM;AACd,cAAU,IAAI;AACd,iBAAa,KAAK;AAClB,aAAS,MAAM;AACf,gBAAY,IAAI;AAChB,aAAS,IAAI;AACb,gBAAY,UAAU;AAAA,EACxB,GAAG,CAAC,WAAW,IAAI,CAAC;AAEpB,QAAM,OAAOC;AAAA,IACX,CAAC,YAAoB;AACnB,UAAI,QAAS;AACb,gBAAU,CAAC,SAAU,SAAS,UAAU,OAAO,OAAQ;AAEvD,eAAS,CAAC,SAAU,SAAS,aAAa,OAAO,MAAO;AACxD,kBAAY,IAAI;AAChB,UAAI,CAAC,MAAM;AAET,qBAAa,CAAC,SAAS;AACrB,cAAI,CAAC,KAAM,mBAAkB;AAC7B,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,CAAC,SAAS,MAAM,eAAe;AAAA,EACjC;AAEA,QAAM,UAAUA;AAAA,IACd,OAAO,UAAmB;AACxB,UAAI,CAAC,aAAa,CAAC,KAAM;AACzB,YAAM,UAAU,UAAU;AAC1B,UAAI,YAAY,KAAM;AACtB,UAAI,YAAY,QAAS;AACzB,kBAAY,UAAU;AACtB,eAAS,UAAU;AACnB,eAAS,IAAI;AACb,UAAI;AACF,YAAI,CAAC,OAAO;AAIV,gBAAM,WAAW,MAAM,OAAO,OAAO,aAAa,WAAW,EAAE,KAAK,CAAC;AACrE,gBAAM,cAAc,SAAS;AAC7B,cAAI,gBAAgB,QAAQ,gBAAgB,aAAa;AACvD,wBAAY,EAAE,MAAM,MAAM,aAAa,MAAM,YAAY,CAAC;AAC1D,qBAAS,UAAU;AACnB;AAAA,UACF;AAAA,QACF;AACA,cAAM,OAAO,QAAQ,aAAa,WAAW,EAAE,MAAM,SAAS,WAAW,KAAK,CAAC;AAC/E,oBAAY,IAAI;AAChB,iBAAS,SAAS;AAClB,qBAAa,KAAK;AAAA,MACpB,SAAS,OAAO;AACd,iBAAS,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAElE,iBAAS,MAAM;AAAA,MACjB,UAAE;AACA,oBAAY,UAAU;AAAA,MACxB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,aAAa,WAAW,MAAM,WAAW;AAAA,EACpD;AAGA,EAAAD,YAAU,MAAM;AACd,QAAI,QAAS;AACb,QAAI,CAAC,KAAM;AACX,QAAI,WAAW,KAAM;AACrB,QAAI,UAAU,aAAa,UAAU,cAAc,UAAU,WAAY;AACzE,SAAK,QAAQ,KAAK;AAAA,EACpB,GAAG,CAAC,SAAS,MAAM,QAAQ,OAAO,OAAO,CAAC;AAE1C,QAAM,YAAYC,cAAY,YAAY;AACxC,UAAM,QAAQ,IAAI;AAAA,EACpB,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,UAAUA,cAAY,MAAM;AAChC,cAAU,IAAI;AACd,iBAAa,KAAK;AAClB,aAAS,MAAM;AACf,gBAAY,IAAI;AAChB,aAAS,IAAI;AAAA,EACf,GAAG,CAAC,CAAC;AAGL,MAAI;AACJ,MAAI,SAAS;AACX,YAAQ;AAAA,EACV,WAAW,UAAU,YAAY;AAC/B,YAAQ;AAAA,EACV,WAAW,UAAU,WAAW;AAC9B,YAAQ;AAAA,EACV,WAAW,UAAU,YAAY;AAC/B,YAAQ;AAAA,EACV,WAAW,WAAW,MAAM;AAC1B,YAAQ;AAAA,EACV,WAAW,MAAM;AAGf,YAAQ;AAAA,EACV,WAAW,QAAQ,YAAY,MAAM;AACnC,YAAQ;AAAA,EACV,OAAO;AACL,YAAQ;AAAA,EACV;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACtOA,SAAS,WAAAC,gBAAe;AAoCjB,SAAS,WAAW,YAAoB,KAAqB;AAClE,QAAM,OAAO,KAAK,MAAM,UAAU;AAClC,MAAI,OAAO,MAAM,IAAI,EAAG,QAAO;AAC/B,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,OAAO,MAAM,QAAQ,GAAI,CAAC;AAC3D,MAAI,UAAU,GAAI,QAAO;AACzB,QAAM,UAAU,KAAK,MAAM,UAAU,EAAE;AACvC,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO;AACnC,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,MAAI,QAAQ,GAAI,QAAO,GAAG,KAAK;AAC/B,QAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;AAClC,SAAO,GAAG,IAAI;AAChB;AAcO,SAAS,kBAAkB,OAA4C;AAC5E,QAAM,MAAM,MAAM,OAAO,KAAK,IAAI;AAClC,QAAM,OAAO,MAAM,cAAc;AACjC,QAAM,eAAe,OAAO,wBAAmB,WAAW,MAAM,GAAG,CAAC,KAAK;AAGzE,MAAI,MAAM,aAAa,UAAU,MAAM,aAAa,YAAY;AAC9D,WAAO,EAAE,OAAO,QAAQ,OAAO,QAAQ,MAAM,KAAK;AAAA,EACpD;AAIA,QAAM,oBACJ,MAAM,uBAAuB,QAAQ,MAAM,uBAAuB;AAIpE,QAAM,iBACJ,MAAM,uBAAuB,kBAAkB,MAAM,uBAAuB;AAC9E,MACE,CAAC,sBACA,MAAM,sBAAsB,iBAAiB,MAAM,cAAc,QAAQ,iBAC1E;AACA,WAAO,EAAE,OAAO,UAAU,OAAO,gBAAW,KAAK;AAAA,EACnD;AAGA,SAAO,EAAE,OAAO,WAAW,OAAO,cAAc,KAAK;AACvD;AAWO,SAAS,eAAe,OAA2C;AACxE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,SAAOA;AAAA,IACL,MACE,kBAAkB;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA;AAAA;AAAA,IAGH;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;ACnGO,SAAS,4BAA4B,SAAqC;AAC/E,QAAM,YACJ,WAAW,OAAO,YAAY,WACzB,QAAoC,YACrC;AACN,MAAI,CAAC,MAAM,QAAQ,SAAS,GAAG;AAC7B,WAAO,CAAC;AAAA,EACV;AACA,SAAO,UAAU,IAAI,CAAC,UAAU,UAAU;AACxC,UAAM,MAAO,YAAY,OAAO,aAAa,WAAW,WAAW,CAAC;AAIpE,UAAM,UACJ,IAAI,WAAW,OAAO,IAAI,YAAY,WACjC,IAAI,UACL,CAAC;AACP,WAAO;AAAA,MACL,IAAI,OAAO,IAAI,MAAM,IAAI,UAAU,QAAQ,UAAU,KAAK;AAAA,MAC1D,MAAM,OAAO,IAAI,QAAQ,UAAU;AAAA,MACnC,WAAW,IAAI;AAAA,MACf,KAAK;AAAA,IACP;AAAA,EACF,CAAC;AACH;AAGO,SAAS,wBAAwB,QAA2C;AACjF,MAAI,UAA6B,CAAC;AAClC,MAAI,eAA8B;AAClC,aAAW,SAAS,QAAQ;AAC1B,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,0BAA0B;AAC7B,kBAAU,4BAA4B,MAAM,OAAO;AACnD,uBAAe,MAAM,UAAU;AAC/B;AAAA,MACF;AAAA,MACA,KAAK,yBAAyB;AAC5B,cAAM,UACJ,MAAM,WAAW,OAAO,MAAM,YAAY,WACrC,MAAM,UACP,CAAC;AACP,YAAI,OAAO,QAAQ,eAAe,UAAU;AAC1C,oBAAU,QAAQ,OAAO,CAAC,aAAa,SAAS,OAAO,QAAQ,UAAU;AAAA,QAC3E;AACA;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,kBAAkB;AAGrB,YAAI,iBAAiB,QAAQ,MAAM,UAAU,QAAQ,MAAM,WAAW,cAAc;AAClF,oBAAU,CAAC;AACX,yBAAe;AAAA,QACjB;AACA;AAAA,MACF;AAAA,MACA;AACE;AAAA,IACJ;AAAA,EACF;AACA,SAAO;AACT;;;AC7EO,SAAS,iBAAiB,OAAyC;AACxE,MAAI,MAAM,CAAC,MAAM,KAAK;AACpB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,MAAM,MAAM,CAAC;AAC1B,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,MAAI,eAAe,IAAI;AACrB,WAAO,EAAE,MAAM,MAAM,MAAM,IAAI,kBAAkB,OAAO,MAAM,CAAC,EAAE;AAAA,EACnE;AACA,QAAM,OAAO,KAAK,MAAM,GAAG,UAAU;AACrC,QAAM,OAAO,KAAK,MAAM,aAAa,CAAC;AACtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB,MAAM,KAAK,MAAM,KAAK,EAAE,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AAAA,EAC5D;AACF;AAEA,IAAM,uBAAmC;AAGlC,SAAS,cACd,UACA,aACS;AACT,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AACA,SAAO,YAAY,SAAS,QAAQ,KAAK,YAAY,SAAS,oBAAoB;AACpF;AAGO,SAAS,aACd,UACA,OACqB;AACrB,QAAM,SAAS,iBAAiB,KAAK;AACrC,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,OAAO,KAAK,YAAY;AACtC,SACE,SAAS,KAAK,CAAC,YAAY,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,KAAK,CAAC,KAAK;AAE9F;AASO,SAAS,eACd,UACA,OACA,KACgB;AAChB,QAAM,SAAS,MAAM,YAAY;AACjC,SAAO,SAAS,OAAO,CAAC,YAAY;AAClC,QAAI,CAAC,cAAc,QAAQ,YAAY,IAAI,WAAW,GAAG;AACvD,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,aAAa,CAAC,QAAQ,UAAU,GAAG,GAAG;AAChD,aAAO;AAAA,IACT;AACA,QAAI,OAAO,WAAW,GAAG;AACvB,aAAO;AAAA,IACT;AACA,WACE,QAAQ,KAAK,WAAW,MAAM,MAC7B,QAAQ,SAAS,KAAK,CAAC,UAAU,MAAM,WAAW,MAAM,CAAC,KAAK;AAAA,EAEnE,CAAC;AACH;AAGO,SAAS,QAAQ,MAA+C;AACrE,MAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AACA,SAAO,KACJ,IAAI,CAAC,QAAQ;AACZ,UAAM,QAAQ,IAAI,QAAQ,IAAI,MAAM,KAAK,GAAG,IAAI,IAAI;AACpD,WAAO,IAAI,WAAW,IAAI,KAAK,MAAM,IAAI,KAAK;AAAA,EAChD,CAAC,EACA,KAAK,GAAG;AACb;AAGO,SAAS,wBAAwB,SAAuB,MAAiC;AAC9F,QAAM,YAAY,QAAQ,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ;AAClE,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;AAC3C,UAAM,QAAQ,KAAK,CAAC;AACpB,QAAI,UAAU,UAAa,MAAM,WAAW,GAAG;AAC7C,aAAO,SAAS,CAAC,KAAK;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,eAAe,KAA6B;AACnD,MAAI,CAAC,IAAI,WAAW;AAClB,UAAM,IAAI,MAAM,qDAAgD;AAAA,EAClE;AACA,SAAO,IAAI;AACb;AAEA,IAAM,aAAa,CAAC,QAA4B,IAAI,cAAc;AAO3D,IAAM,kBAA2C;AAAA,EACtD;AAAA,IACE,MAAM;AAAA,IACN,SAAS,CAAC,GAAG;AAAA,IACb,aAAa;AAAA,IACb,KAAK,CAAC,OAAO,QAAQ;AACnB,UAAI,SAAS;AACb,aAAO,EAAE,QAAQ,KAAK;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,KAAK,CAAC,OAAO,QAAQ;AAKnB,YAAM,UAAU,IAAI,UAAU;AAC9B,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,QACX;AAAA,MACF;AACA,aAAO,EAAE,QAAQ,MAAM,SAAS,sBAAsB;AAAA,IACxD;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,MAAM;AAAA,MACJ,EAAE,MAAM,UAAU,UAAU,MAAM,OAAO,CAAC,SAAS,QAAQ,GAAG,aAAa,iBAAiB;AAAA,IAC9F;AAAA,IACA,KAAK,OAAO,MAAM,QAAQ;AACxB,YAAM,YAAY,eAAe,GAAG;AACpC,YAAM,SAAS,KAAK,CAAC;AACrB,UAAI,WAAW,WAAW,WAAW,UAAU;AAC7C,eAAO,EAAE,QAAQ,SAAS,SAAS,oCAAoC;AAAA,MACzE;AACA,UAAI;AACF,cAAM,IAAI,OAAO,WAAW,IAAI,aAAa,WAAW;AAAA,UACtD,QAAQ,WAAW,UAAU,WAAW;AAAA,QAC1C,CAAC;AACD,eAAO,EAAE,QAAQ,MAAM,SAAS,WAAW,UAAU,iBAAiB,gBAAgB;AAAA,MACxF,SAAS,OAAO;AACd,eAAO,EAAE,QAAQ,SAAS,SAAS,iBAAiB,OAAO,MAAM,EAAE;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,KAAK,OAAO,OAAO,QAAQ;AACzB,YAAM,YAAY,eAAe,GAAG;AACpC,UAAI;AACF,cAAM,SAAS,MAAM,IAAI,OAAO,sBAAsB,IAAI,aAAa,SAAS;AAChF,eAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,QAAQ;AAAA,MACjD,SAAS,OAAO;AACd,eAAO,EAAE,QAAQ,SAAS,SAAS,aAAa,KAAK,KAAK,6BAA6B;AAAA,MACzF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,KAAK,OAAO,OAAO,QAAQ;AACzB,YAAM,YAAY,eAAe,GAAG;AACpC,YAAM,YAAY,MAAM,IAAI,QAAQ;AACpC,UAAI,CAAC,WAAW;AAGd,eAAO,EAAE,QAAQ,MAAM,WAAW,KAAK;AAAA,MACzC;AACA,UAAI;AACF,cAAM,IAAI,OAAO,oBAAoB,IAAI,aAAa,SAAS;AAC/D,eAAO,EAAE,QAAQ,MAAM,SAAS,mBAAmB;AAAA,MACrD,SAAS,OAAO;AACd,eAAO,EAAE,QAAQ,SAAS,SAAS,kBAAkB,KAAK,EAAE;AAAA,MAC9D;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,aAAa,OAAoC;AACxD,MACE,SACA,OAAO,UAAU,YACjB,aAAa,SACb,OAAQ,MAAgC,YAAY,UACpD;AACA,WAAQ,MAA8B;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAAoC;AACtD,MACE,SACA,OAAO,UAAU,YACjB,YAAY,SACZ,OAAQ,MAA+B,WAAW,UAClD;AACA,WAAQ,MAA6B;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAgB,QAAoC;AAC5E,QAAM,OAAO,WAAW,KAAK;AAC7B,MAAI,SAAS,KAAK;AAChB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,KAAK;AAChB,WAAO,WAAW,WACd,uCACA;AAAA,EACN;AACA,SAAO,aAAa,KAAK,KAAK,aAAa,MAAM;AACnD;AAEA,SAAS,kBAAkB,OAAwB;AACjD,MAAI,WAAW,KAAK,MAAM,KAAK;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,aAAa,KAAK,KAAK;AAChC;;;AC5QA,SAAS,eAAAC,eAAa,WAAAC,UAAS,UAAAC,UAAQ,YAAAC,kBAAgB;AAiFhD,SAAS,iBAAiB,SAA0D;AACzF,QAAM,EAAE,UAAU,SAAS,UAAU,OAAO,SAAS,IAAI;AACzD,QAAM,CAAC,WAAW,YAAY,IAAIC,WAAS,CAAC;AAG5C,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAwB,IAAI;AACxE,QAAM,YAAY,mBAAmB,QAAQ,mBAAmB;AAOhE,QAAM,eAAeC,SAAO,KAAK;AACjC,QAAM,cAAcA,SAAO,KAAK;AAChC,MAAI,YAAY,YAAY,OAAO;AACjC,gBAAY,UAAU;AACtB,iBAAa,UAAU;AAAA,EACzB;AAEA,QAAM,SAASC,SAAQ,MAAM,iBAAiB,KAAK,GAAG,CAAC,KAAK,CAAC;AAC7D,QAAM,YAAYA;AAAA,IAChB,OAAO;AAAA,MACL,WAAW,SAAS,aAAa;AAAA,MACjC,QAAQ,SAAS,UAAU;AAAA,MAC3B,aAAa,SAAS,eAAe,CAAC;AAAA,IACxC;AAAA,IACA,CAAC,SAAS,WAAW,SAAS,QAAQ,SAAS,WAAW;AAAA,EAC5D;AAIA,QAAM,gBAAgBA,SAAQ,MAAM;AAClC,QAAI,CAAC,UAAU,CAAC,OAAO,kBAAkB;AACvC,aAAO;AAAA,IACT;AACA,WAAO,aAAa,UAAU,KAAK;AAAA,EACrC,GAAG,CAAC,UAAU,OAAO,MAAM,CAAC;AAE5B,QAAM,QAAQA,SAAQ,MAAM;AAC1B,QAAI,CAAC,QAAQ;AACX,aAAO,CAAC;AAAA,IACV;AACA,QAAI,eAAe;AACjB,aAAO,CAAC,aAAa;AAAA,IACvB;AACA,WAAO,eAAe,UAAU,OAAO,MAAM,SAAS;AAAA,EACxD,GAAG,CAAC,UAAU,QAAQ,eAAe,SAAS,CAAC;AAE/C,QAAM,OAAO,WAAW,QAAQ,MAAM,SAAS,KAAK,CAAC;AAOrD,QAAM,iBAAiB,WAAW,QAAQ,MAAM,SAAS;AAGzD,QAAM,mBAAmB,MAAM,WAAW,IAAI,IAAI,KAAK,IAAI,WAAW,MAAM,SAAS,CAAC;AAEtF,QAAM,gBAAgB,gBAAgB,QAAQ,cAAc,IAAI,IAAI;AAOpE,QAAM,eAAeC;AAAA,IACnB,CAAC,YAAiD;AAChD,UAAI,CAAC,SAAS;AACZ,eAAO;AAAA,MACT;AACA,aAAO,EAAE,GAAG,SAAS,GAAG,UAAU,SAAS,MAAM,SAAS,QAAQ,OAAO,EAAE;AAAA,IAC7E;AAAA,IACA,CAAC,SAAS,QAAQ;AAAA,EACpB;AAEA,QAAM,UAAUA;AAAA,IACd,OAAO,SAAuB,SAAkC;AAC9D,YAAM,MAAM,aAAa,OAAO;AAChC,UAAI,CAAC,KAAK;AACR;AAAA,MACF;AACA,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,IAAI,MAAM,GAAG;AAC1C,YAAI,OAAO,SAAS;AAClB,cAAI,OAAO,EAAE,MAAM,OAAO,WAAW,OAAO,OAAO,SAAS,SAAS,OAAO,QAAQ,CAAC;AAAA,QACvF;AACA,YAAI,OAAO,WAAW,QAAQ,CAAC,OAAO,WAAW;AAC/C,mBAAS,EAAE;AAAA,QACb;AAAA,MACF,SAAS,OAAO;AACd,YAAI,OAAO,EAAE,MAAM,SAAS,SAASC,cAAa,KAAK,EAAE,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,IACA,CAAC,cAAc,QAAQ;AAAA,EACzB;AAEA,QAAM,eAAeD;AAAA,IACnB,CAAC,YAA0B;AACzB,eAAS,IAAI,QAAQ,IAAI,GAAG;AAC5B,mBAAa,CAAC;AAAA,IAChB;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,0BAA0BA,cAAY,MAAM;AAChD,UAAM,UAAU,MAAM,gBAAgB;AACtC,QAAI,SAAS;AACX,mBAAa,OAAO;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,OAAO,kBAAkB,YAAY,CAAC;AAO1C,QAAM,cAAcA;AAAA,IAClB,OAAO,SAAuB,qBAA6D;AACzF,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AACA,YAAM,WAAW,kBAAkB,YAAY;AAI/C,YAAM,mBACJ,QAAQ,SAAS,OAAO,KAAK,YAAY,MACxC,QAAQ,SAAS,SAAS,OAAO,KAAK,YAAY,CAAC,KAAK;AAM3D,UAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,OAAO,kBAAkB;AAChF,qBAAa,OAAO;AACpB;AAAA,MACF;AAIA,YAAM,OAAO,oBAAoB,OAAO,mBAAmB,OAAO,OAAO,CAAC;AAC1E,YAAM,UAAU,wBAAwB,SAAS,IAAI;AACrD,UAAI,SAAS;AAGX,YAAI,CAAC,OAAO,kBAAkB;AAC5B,uBAAa,OAAO;AAAA,QACtB;AACA;AAAA,MACF;AACA,YAAM,QAAQ,SAAS,IAAI;AAAA,IAC7B;AAAA,IACA,CAAC,QAAQ,eAAe,cAAc,OAAO;AAAA,EAC/C;AAEA,QAAM,iBAAiBA,cAAY,YAA2B;AAC5D,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAKA,QAAI,aAAa,WAAW,CAAC,eAAe;AAC1C,YAAM,cAAc,MAAM,gBAAgB;AAC1C,UAAI,aAAa;AACf,cAAM,YAAY,aAAa,EAAE,UAAU,KAAK,CAAC;AAAA,MACnD;AACA;AAAA,IACF;AASA,UAAM,QAAQ,OAAO,KAAK,YAAY;AACtC,UAAM,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,SAAS,KAAK,SAAS,SAAS,KAAK,CAAC;AACvF,UAAM,UAAU,iBAAiB,SAAS,MAAM,gBAAgB;AAChE,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,UAAM,YAAY,OAAO;AAAA,EAC3B,GAAG,CAAC,QAAQ,eAAe,OAAO,kBAAkB,WAAW,CAAC;AAOhE,QAAM,QAAQA;AAAA,IACZ,OAAO,UAAiC;AACtC,YAAM,UAAU,MAAM,KAAK;AAC3B,UAAI,CAAC,SAAS;AACZ;AAAA,MACF;AACA,YAAM,YAAY,SAAS,EAAE,UAAU,KAAK,CAAC;AAAA,IAC/C;AAAA,IACA,CAAC,OAAO,WAAW;AAAA,EACrB;AAGA,QAAM,aAAaF,SAAO,KAAK;AAE/B,QAAM,YAAYE;AAAA,IAChB,CAAC,UAAuD;AACtD,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AACA,cAAQ,MAAM,KAAK;AAAA,QACjB,KAAK,aAAa;AAChB,gBAAM,eAAe;AACrB,uBAAa,UAAU;AACvB;AAAA,YAAa,CAAC,YACZ,MAAM,WAAW,IAAI,KAAK,KAAK,IAAI,SAAS,MAAM,SAAS,CAAC,IAAI,KAAK,MAAM;AAAA,UAC7E;AACA,iBAAO;AAAA,QACT;AAAA,QACA,KAAK,WAAW;AACd,gBAAM,eAAe;AACrB,uBAAa,UAAU;AACvB,uBAAa,CAAC,YAAY;AACxB,kBAAM,OAAO,KAAK,IAAI,SAAS,MAAM,SAAS,CAAC;AAC/C,mBAAO,MAAM,WAAW,IAAI,KAAK,OAAO,IAAI,MAAM,UAAU,MAAM;AAAA,UACpE,CAAC;AACD,iBAAO;AAAA,QACT;AAAA,QACA,KAAK,OAAO;AACV,gBAAM,eAAe;AACrB,kCAAwB;AACxB,iBAAO;AAAA,QACT;AAAA,QACA,KAAK,SAAS;AACZ,cAAI,MAAM,YAAY,MAAM,aAAa,aAAa;AACpD,mBAAO;AAAA,UACT;AACA,gBAAM,eAAe;AACrB,cAAI,WAAW,SAAS;AACtB,mBAAO;AAAA,UACT;AACA,qBAAW,UAAU;AACrB,eAAK,eAAe,EAAE,QAAQ,MAAM;AAClC,uBAAW,UAAU;AAAA,UACvB,CAAC;AACD,iBAAO;AAAA,QACT;AAAA,QACA,KAAK,UAAU;AACb,gBAAM,eAAe;AAGrB,4BAAkB,KAAK;AACvB,iBAAO;AAAA,QACT;AAAA,QACA;AACE,iBAAO;AAAA,MACX;AAAA,IACF;AAAA,IACA,CAAC,MAAM,OAAO,yBAAyB,gBAAgB,KAAK;AAAA,EAC9D;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAASC,cAAa,OAAwB;AAC5C,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AACA,SAAO,OAAO,KAAK;AACrB;;;AC/WA,SAAS,mBAAAC,kBAAiB,UAAAC,eAAc;AA6EpB,SASE,OAAAC,MATF,QAAAC,aAAA;AApDb,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,SACE,gBAAAD,KAACE,kBAAA,EACE,iBACC,gBAAAD;AAAA,IAACE,QAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG,OAAO,KAAK;AAAA,MACzC,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG,OAAO,EAAE;AAAA,MACtC,MAAM,EAAE,SAAS,GAAG,GAAG,GAAG,OAAO,KAAK;AAAA,MACtC,YAAY,EAAE,UAAU,MAAM,MAAM,UAAU;AAAA,MAC9C,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAH;AAAA,UAAC;AAAA;AAAA,YACC,IAAI;AAAA,YACJ,MAAK;AAAA,YACL,cAAW;AAAA,YACX,WAAU;AAAA,YAET,gBAAM,IAAI,CAAC,SAAS,UAAU;AAC7B,oBAAM,WAAW,UAAU;AAC3B,oBAAM,OAAO,QAAQ,QAAQ,IAAI;AACjC,qBACE,gBAAAC;AAAA,gBAAC;AAAA;AAAA,kBAEC,IAAI,GAAG,SAAS,WAAW,KAAK;AAAA,kBAChC,MAAK;AAAA,kBACL,iBAAe;AAAA,kBACf,cAAc,MAAM,YAAY,KAAK;AAAA,kBACrC,aAAa,CAAC,UAAU;AAEtB,0BAAM,eAAe;AACrB,0BAAM,KAAK;AAAA,kBACb;AAAA,kBACA,WAAW;AAAA,oBACT;AAAA,oBACA;AAAA,oBACA,WACI,+BACA;AAAA,kBACN;AAAA,kBAEA;AAAA,oCAAAA,MAAC,UAAK,WAAU,uCACd;AAAA,sCAAAA;AAAA,wBAAC;AAAA;AAAA,0BACC,WAAW;AAAA,4BACT;AAAA,4BACA,WAAW,mBAAmB;AAAA,0BAChC;AAAA,0BACD;AAAA;AAAA,4BACG,QAAQ;AAAA;AAAA;AAAA,sBACZ;AAAA,sBACC,OACC,gBAAAD,KAAC,UAAK,WAAU,oDACb,gBACH,IACE;AAAA,uBACN;AAAA,oBACA,gBAAAC,MAAC,UAAK,WAAU,qCACb;AAAA,8BAAQ,SACP,gBAAAD,KAAC,UAAK,WAAU,uGAAsG,oBAEtH,IACE;AAAA,sBACJ,gBAAAA,KAAC,UAAK,WAAU,wDACb,kBAAQ,aACX;AAAA,uBACF;AAAA;AAAA;AAAA,gBA1CK,QAAQ;AAAA,cA2Cf;AAAA,YAEJ,CAAC;AAAA;AAAA,QACH;AAAA,QACC,cACC,gBAAAA,KAAC,SAAI,WAAU,iFACZ,uBACH,IACE;AAAA;AAAA;AAAA,EACN,IACE,MACN;AAEJ;;;ACjHA;AAAA,EACE;AAAA,EACA;AAAA,EACA,aAAAI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAAC;AAAA,OACK;AACP,SAAS,mBAAAC,kBAAiB,UAAAC,eAAc;AACxC;AAAA,EACE,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OAOK;;;ACzBP,SAAS,uBAAuB;AAChC,SAAS,OAAO,WAAAC,gBAAe;AAgD3B,SACE,OAAAC,OADF,QAAAC,aAAA;AAvBG,SAAS,YAAY,EAAE,QAAQ,OAAO,UAAU,UAAU,UAAU,GAAqB;AAC9F,QAAM,WAAW,MAAM;AAIvB,QAAM,SAASC,SAAQ,MAAM;AAC3B,UAAM,aAAa,oBAAI,IAAsD;AAC7E,eAAW,SAAS,QAAQ;AAC1B,UAAI,QAAQ,WAAW,IAAI,MAAM,QAAQ;AACzC,UAAI,CAAC,OAAO;AACV,gBAAQ,EAAE,OAAO,MAAM,eAAe,QAAQ,CAAC,EAAE;AACjD,mBAAW,IAAI,MAAM,UAAU,KAAK;AAAA,MACtC;AACA,YAAM,OAAO,KAAK,KAAK;AAAA,IACzB;AACA,WAAO,CAAC,GAAG,WAAW,OAAO,CAAC;AAAA,EAChC,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,SACE,gBAAAD,MAAC,UAAK,WAAW,GAAG,qCAAqC,SAAS,GAChE;AAAA,oBAAAD,MAAC,WAAM,SAAS,UAAU,WAAU,WAAU,mBAE9C;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,IAAI;AAAA,QACJ,OAAO,SAAS;AAAA,QAChB,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QAChD,UAAU,aAAa;AAAA,QACvB,cAAW;AAAA,QACX,WAAW;AAAA;AAAA;AAAA,UAGT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEC,iBAAO,IAAI,CAAC,UACX,gBAAAA,MAAC,cAA2B,OAAO,MAAM,OACtC,gBAAM,OAAO,IAAI,CAAC,UACjB,gBAAAA,MAAC,YAAsB,OAAO,MAAM,IACjC,gBAAM,SADI,MAAM,EAEnB,CACD,KALY,MAAM,KAMrB,CACD;AAAA;AAAA,IACH;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,eAAW;AAAA,QACX,WAAU;AAAA;AAAA,IACZ;AAAA,KACF;AAEJ;;;ADgRU,SA6GU,YAAAG,WA7GV,OAAAC,OAyCI,QAAAC,aAzCJ;AArQV,IAAM,kBAA8C,oBAAI,IAAI;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAaM,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,cAAcC,SAAmC,IAAI;AAC3D,QAAM,eAAeA,SAAgC,IAAI;AACzD,QAAM,SAAS,UAAU,QAAQ,gBAAgB,IAAI,MAAM;AAM3D,QAAM,kBAAkB,aAAa,cAAc;AAOnD,QAAM,sBAAsB,aAAa,eAAe,UAAU,KAAK;AAEvE,QAAM,WAAW,SAAS,WAAW,uBAAuB,CAAC,mBAAmB,CAAC,SAAS;AAK1F,QAAM,CAAC,UAAU,WAAW,IAAIC,WAAS,KAAK;AAC9C,QAAM,mBAAmB,CAAC,UACxB,MAAM,gBAAgB,QAAQ,CAAC,GAAG,MAAM,aAAa,KAAK,EAAE,SAAS,OAAO;AAC9E,QAAM,iBAAiBC;AAAA,IACrB,CAAC,UAAqC;AACpC,UAAI,CAAC,eAAe,CAAC,iBAAiB,KAAK,GAAG;AAC5C;AAAA,MACF;AAEA,YAAM,eAAe;AACrB,kBAAY,IAAI;AAAA,IAClB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AACA,QAAM,kBAAkBA;AAAA,IACtB,CAAC,UAAqC;AACpC,UAAI,CAAC,aAAa;AAChB;AAAA,MACF;AAGA,UAAI,MAAM,cAAc,SAAS,MAAM,aAA4B,GAAG;AACpE;AAAA,MACF;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AACA,QAAM,aAAaA;AAAA,IACjB,CAAC,UAAqC;AACpC,UAAI,CAAC,eAAe,CAAC,iBAAiB,KAAK,GAAG;AAC5C;AAAA,MACF;AACA,YAAM,eAAe;AACrB,kBAAY,KAAK;AAEjB,UAAI,MAAM,aAAa,MAAM,SAAS,GAAG;AACvC,oBAAY,SAAS,MAAM,aAAa,KAAK;AAAA,MAC/C;AAAA,IACF;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,CAAC,QAAQ,SAAS,IAAID,WAAwB,IAAI;AACxD,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,KAAK;AAC9C,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAuB,IAAI;AACnE,QAAM,YAAYE,OAAM;AAExB,QAAM,SAASD,cAAY,MAAM;AAC/B,UAAM,WAAW,YAAY;AAC7B,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AACA,aAAS,MAAM,SAAS;AACxB,aAAS,MAAM,SAAS,GAAG,KAAK,IAAI,SAAS,cAAc,GAAG,CAAC;AAAA,EACjE,GAAG,CAAC,CAAC;AAEL,EAAAE,YAAU,MAAM;AACd,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,OAAO,MAAM,CAAC;AAK3B,QAAM,WAAWC;AAAA,IACf,OAAO;AAAA,MACL,QAAQ,CAAC,SAAiB;AACxB,kBAAU,IAAI;AACd,iBAAS,WAAW;AAAA,MACtB;AAAA,MACA,UAAU,MAAM,YAAY,IAAI;AAAA;AAAA;AAAA,MAGhC,WAAW,MAAM;AACf,YAAI,CAAC,aAAa;AAChB,iBAAO;AAAA,QACT;AACA,oBAAY;AACZ,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,SAAS,CAAC,YACR,IAAI,QAAiB,CAAC,YAAY;AAChC,wBAAgB;AAAA,UACd;AAAA,UACA,SAAS,CAAC,cAAc;AACtB,4BAAgB,IAAI;AACpB,oBAAQ,SAAS;AAAA,UACnB;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACL;AAAA,IACA,CAAC,UAAU,WAAW;AAAA,EACxB;AAEA,QAAM,UAAU,iBAAiB;AAAA,IAC/B;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA,OAAO,SAAS;AAAA,IAChB,UAAU,SAAS;AAAA,EACrB,CAAC;AAQD,QAAM,uBAAuB,eAAe,aAAa,UAAU;AAEnE,QAAM,iBAAiB,mBAAmB;AAM1C,QAAM,sBAAsB,kBAAkB,QAAQ;AAEtD,QAAM,YAAY,CAAC,UAA8C;AAG/D,QAAI,kBAAkB,QAAQ,UAAU,KAAK,GAAG;AAC9C;AAAA,IACF;AACA,QAAI,kBAAkB,KAAK,GAAG;AAC5B,YAAM,eAAe;AACrB,UAAI,qBAAqB;AAGvB,kBAAU;AAAA,UACR,MAAM;AAAA,UACN,SACE;AAAA,QACJ,CAAC;AACD;AAAA,MACF;AACA,UAAI,iBAAiB;AAGnB;AAAA,MACF;AACA,WAAK,SAAS,KAAK,QAAW,mBAAmB,KAAK,CAAC;AAAA,IACzD;AAAA,EACF;AAKA,QAAM,cAAcH;AAAA,IAClB,CAAC,UAA+C;AAC9C,gBAAU,KAAK;AACf,mBAAa,aAAa,KAAK;AAAA,IACjC;AAAA,IACA,CAAC,SAAS,WAAW;AAAA,EACvB;AAEA,QAAM,mBAAmBA;AAAA,IACvB,CAAC,UAAyC;AACxC,UAAI,MAAM,OAAO,OAAO;AACtB,qBAAa,SAAS,MAAM,OAAO,KAAK;AAAA,MAC1C;AACA,YAAM,OAAO,QAAQ;AAAA,IACvB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,eAAeG;AAAA,IACnB,MACE,SAAS,OAAO,CAAC,YAAY;AAC3B,UAAI,QAAQ,cAAc,gBAAgB;AACxC,cAAM,QAAQ,eAAe;AAC7B,eAAO,MAAM,SAAS,QAAQ,UAAU,KAAK,MAAM,SAAS,iBAAiB;AAAA,MAC/E;AACA,aAAO;AAAA,IACT,CAAC;AAAA,IACH,CAAC,UAAU,cAAc;AAAA,EAC3B;AAEA,QAAM,eACJ,WACC,SAAS,QACN;AAAA,IACE,MAAM;AAAA,IACN,SACE,SAAS,MAAM,WAAW;AAAA,EAC9B,IACA;AAEN;AAAA;AAAA;AAAA,IAGE,gBAAAN;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,GAAG,WAAW,SAAS;AAAA,QAClC,OAAO,EAAE,eAAe,8BAA8B;AAAA,QAEtD;AAAA,0BAAAA,MAAC,SAAI,WAAU,YACZ;AAAA,6BACC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,QAAQ,QAAQ,iBAAiB;AAAA,gBACvC,OAAO,QAAQ;AAAA,gBACf,WAAW,QAAQ;AAAA,gBACnB,aAAa,QAAQ;AAAA,gBACrB,OAAO,CAAC,UAAU;AAKhB,0BAAQ,aAAa,KAAK;AAC1B,uBAAK,QAAQ,MAAM,KAAK;AAAA,gBAC1B;AAAA,gBACA,aAAa,QAAQ;AAAA,gBACrB;AAAA;AAAA,YACF,IACE;AAAA,YACJ,gBAAAC;AAAA,cAAC;AAAA;AAAA,gBAIC,YAAY,cAAc,iBAAiB;AAAA,gBAC3C,aAAa,cAAc,kBAAkB;AAAA,gBAC7C,QAAQ,cAAc,aAAa;AAAA,gBACnC,WAAW;AAAA,kBACT;AAAA,kBACA;AAAA,kBACA;AAAA;AAAA;AAAA,kBAGA,YAAY;AAAA,gBACd;AAAA,gBAEC;AAAA,6BACC,gBAAAD;AAAA,oBAAC;AAAA;AAAA,sBACC,eAAW;AAAA,sBACX,WAAW;AAAA,wBACT;AAAA,wBACA;AAAA,sBACF;AAAA,sBAEA,0BAAAC,MAAC,UAAK,WAAU,kCACd;AAAA,wCAAAD,MAAC,iBAAc,WAAU,UAAS;AAAA,wBAAE;AAAA,yBAEtC;AAAA;AAAA,kBACF,IACE;AAAA,kBACH,eAAe,YAAY,YAAY,SAAS,IAC/C,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,aAAa,YAAY;AAAA,sBACzB,UAAU,YAAY;AAAA,sBACtB,SAAS,YAAY;AAAA;AAAA,kBACvB,IACE;AAAA,kBACH;AAAA,kBACD,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,KAAK;AAAA,sBACL,MAAM;AAAA,sBACN,OAAO,SAAS;AAAA,sBAChB,UAAU,CAAC,UAAU,SAAS,SAAS,MAAM,OAAO,KAAK;AAAA,sBACzD;AAAA,sBACA,SAAS;AAAA,sBACT,aAAa,eAAe;AAAA,sBAC5B;AAAA,sBACA;AAAA,sBACA,cAAW;AAAA,sBACX,qBAAkB;AAAA,sBAKlB,qBAAmB,iBAAiB,SAAS;AAAA,sBAC7C,iBAAe,kBAAkB,QAAQ,OAAO,YAAY;AAAA,sBAC5D,yBACE,kBAAkB,QAAQ,OACtB,GAAG,SAAS,WAAW,QAAQ,SAAS,KACxC;AAAA,sBAEN,WAAW;AAAA;AAAA;AAAA,wBAGT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBASA;AAAA,wBACA;AAAA,sBACF;AAAA;AAAA,kBACF;AAAA,kBACC,gBAAgB,uBACf,gBAAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,SAAS;AAAA,sBACT,UAAU,MAAM,aAAa,QAAQ,KAAK;AAAA,sBAC1C,WAAW,MAAM,aAAa,QAAQ,IAAI;AAAA,sBAC1C,gBAAgB;AAAA;AAAA,kBAClB,IAEA,gBAAAC,MAAC,SAAI,WAAU,2CACZ;AAAA,mCAAe,UAAU;AAAA;AAAA;AAAA;AAAA,sBAIxB,gBAAAA,MAAC,UAAK,WAAU,sDACb;AAAA,sCACC,gBAAAA,MAAAF,WAAA,EACE;AAAA,0CAAAC;AAAA,4BAAC;AAAA;AAAA,8BACC,KAAK;AAAA,8BACL,MAAK;AAAA,8BACL,UAAQ;AAAA,8BACR,WAAU;AAAA,8BACV,UAAU;AAAA;AAAA,0BACZ;AAAA,0BACA,gBAAAA;AAAA,4BAAC;AAAA;AAAA,8BACC,MAAK;AAAA,8BACL,UAAU,aAAa;AAAA,8BACvB,SAAS,MAAM,aAAa,SAAS,MAAM;AAAA,8BAC3C,cAAW;AAAA,8BACX,OAAM;AAAA,8BACN,WAAW;AAAA,gCACT;AAAA,gCACA;AAAA,gCACA;AAAA,8BACF;AAAA,8BAEA,0BAAAA,MAAC,iBAAc,WAAU,UAAS;AAAA;AAAA,0BACpC;AAAA,2BACF,IACE;AAAA,wBACH,SACC,gBAAAA;AAAA,0BAAC;AAAA;AAAA,4BACC;AAAA,4BACA,OAAO;AAAA,4BACP,UAAU,CAAC,YAAY,gBAAgB,OAAO;AAAA,4BAC9C,UAAU,aAAa;AAAA;AAAA,wBACzB,IACE;AAAA,wBACH;AAAA,yBACH;AAAA,wBAEA,gBAAAA,MAAC,UAAK,WAAU,oEACb,kBAAQ,+EACX;AAAA,oBAEF,gBAAAC,MAAC,UAAK,WAAU,8CACd;AAAA,sCAAAD,MAACQ,kBAAA,EAAgB,SAAS,OACvB,oBAAU,WAAW,WACpB,gBAAAR;AAAA,wBAACS,QAAO;AAAA,wBAAP;AAAA,0BAEC,MAAK;AAAA,0BACL,SAAS,EAAE,SAAS,GAAG,OAAO,IAAI;AAAA,0BAClC,SAAS,EAAE,SAAS,GAAG,OAAO,EAAE;AAAA,0BAChC,MAAM,EAAE,SAAS,GAAG,OAAO,IAAI;AAAA,0BAC/B,YAAY,EAAE,UAAU,MAAM,MAAM,UAAU;AAAA,0BAC9C,SAAS,MACP,MAAM,WAAW,WAAW,SAAS,OAAO,IAAI,SAAS,MAAM;AAAA,0BAEjE,UAAU,SAAS,WAAW,SAAS;AAAA,0BACvC,cAAY,WAAW,WAAW,uBAAuB;AAAA,0BACzD,OACE,WAAW,WACP,uDACA;AAAA,0BAEN,WAAW;AAAA,4BACT;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,0BACF;AAAA,0BAEC,mBAAS,WAAW,SAAS,WAC5B,gBAAAT,MAAC,oBAAiB,WAAU,4BAA2B,IACrD,WAAW,WACb,gBAAAA,MAAC,YAAS,WAAU,yBAAwB,IAE5C,gBAAAA,MAAC,cAAW,WAAU,uBAAsB;AAAA;AAAA,wBA5B1C;AAAA,sBA8BN,IACE,MACN;AAAA,sBACA,gBAAAA;AAAA,wBAAC;AAAA;AAAA,0BACC,MAAK;AAAA,0BACL,SAAS,MAAM;AACb,gCAAI,iBAAiB;AACnB;AAAA,4BACF;AACA,iCAAK,SAAS,KAAK;AAAA,0BACrB;AAAA,0BACA,UAAU,CAAC,WAAW,aAAa,QAAQ;AAAA,0BAC3C,cAAW;AAAA,0BACX,OAAM;AAAA,0BACN,WAAW;AAAA,4BACT;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,4BACA;AAAA,0BACF;AAAA,0BAEC,mBAAS,UACR,gBAAAA,MAAC,oBAAiB,WAAU,0BAAyB,IAErD,gBAAAA,MAAC,eAAY,WAAU,UAAS;AAAA;AAAA,sBAEpC;AAAA,uBACF;AAAA,qBACF;AAAA;AAAA;AAAA,YAEJ;AAAA,aACF;AAAA,UACA,gBAAAA,MAACQ,kBAAA,EACE,qBAAW,gBAAAR,MAAC,aAAU,UAAU,cAAc,SAAS,MAAM,YAAY,KAAK,GAAG,IAAK,MACzF;AAAA,UACA,gBAAAA,MAACQ,kBAAA,EACE,yBACC,gBAAAR;AAAA,YAACS,QAAO;AAAA,YAAP;AAAA,cACC,SAAS,EAAE,SAAS,GAAG,QAAQ,EAAE;AAAA,cACjC,SAAS,EAAE,SAAS,GAAG,QAAQ,OAAO;AAAA,cACtC,MAAM,EAAE,SAAS,GAAG,QAAQ,EAAE;AAAA,cAC9B,WAAW;AAAA,gBACT;AAAA,gBACA,aAAa,SAAS,OAAO,qBAAqB;AAAA,cACpD;AAAA,cACA,MAAM,aAAa,SAAS,UAAU,UAAU;AAAA,cAChD,qBAAqB,MAAM;AACzB,oBAAI,aAAa,SAAS,MAAM;AAE9B,yBAAO;AAAA,oBACL,MAAM,UAAU,CAAC,YAAa,YAAY,eAAe,OAAO,OAAQ;AAAA,oBACxE;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,cAEC,uBAAa;AAAA;AAAA,UAChB,IACE,MACN;AAAA;AAAA;AAAA,IACF;AAAA;AAEJ;AAQA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,aAAaP,SAAiC,IAAI;AACxD,QAAM,gBAAgBG,OAAM;AAC5B,EAAAC,YAAU,MAAM;AACd,UAAM,WAAW,gBAAgB,WAAW;AAC5C,eAAW,SAAS,MAAM;AAC1B,WAAO,MAAM;AACX,gBAAU,MAAM;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,cAAc,CAAC;AACnB,SACE,gBAAAL;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY,YAAY,QAAQ,IAAI;AAAA,MACpC,oBAAkB;AAAA,MAClB,eAAY;AAAA,MACZ,WAAW,CAAC,UAAU;AACpB,YAAI,MAAM,QAAQ,UAAU;AAC1B,gBAAM,eAAe;AACrB,gBAAM,gBAAgB;AACtB,mBAAS;AAAA,QACX;AAAA,MACF;AAAA,MACA,WAAU;AAAA,MAEV;AAAA,wBAAAA,MAAC,UAAK,IAAI,eAAe,WAAU,0DAAyD;AAAA;AAAA,UACtF,gBAAAA,MAAC,UAAK,WAAU,aAAY;AAAA;AAAA,YAAE,QAAQ;AAAA,aAAK;AAAA,UAAO;AAAA,UAAG,QAAQ;AAAA,WACnE;AAAA,QACA,gBAAAA,MAAC,UAAK,WAAU,sCACd;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,UACA,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,gBACO,QAAQ;AAAA;AAAA;AAAA,UAChB;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAWA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,gBAAAD,MAAC,SAAI,WAAU,4DACZ,sBAAY,IAAI,CAAC,eAAe;AAC/B,UAAM,SAAS,WAAW,WAAW;AACrC,UAAM,aACJ,WAAW,WAAW,cAClB,cACA,SACE,WAAW,SAAS,kBACpB,YAAY,WAAW,SAAS;AACxC,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW;AAAA,UACT;AAAA,UACA,SACI,sDACA;AAAA,QACN;AAAA,QAEC;AAAA,qBAAW,aACV,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,KAAK,WAAW;AAAA,cAChB,KAAI;AAAA,cACJ,WAAU;AAAA;AAAA,UACZ,IACE,WAAW,YAAY,WAAW,QAAQ,IAC5C,gBAAAA,MAACU,YAAA,EAAU,WAAU,oCAAmC,IAExD,gBAAAV,MAAC,YAAS,WAAU,oCAAmC;AAAA,UAEzD,gBAAAC,MAAC,SAAI,WAAU,kBACb;AAAA,4BAAAD,MAAC,SAAI,WAAU,mCAAmC,qBAAW,MAAK;AAAA,YAClE,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,SAAS,0BAA0B;AAAA,gBACrC;AAAA,gBACA,OAAO,SAAS,aAAa;AAAA,gBAE5B;AAAA;AAAA,YACH;AAAA,aACF;AAAA,UACC,WAAW,WAAW,cACrB,gBAAAA,MAAC,oBAAiB,WAAU,qCAAoC,IAC9D;AAAA,UACH,UAAU,UACT,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,QAAQ,WAAW,EAAE;AAAA,cACpC,WAAU;AAAA,cACV,cAAY,SAAS,WAAW,IAAI;AAAA,cACpC,OAAM;AAAA,cAEN,0BAAAA,MAAC,gBAAa,WAAU,YAAW;AAAA;AAAA,UACrC,IACE;AAAA,UACJ,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,SAAS,WAAW,EAAE;AAAA,cACrC,WAAU;AAAA,cACV,cAAY,UAAU,WAAW,IAAI;AAAA,cAErC,0BAAAA,MAACW,QAAA,EAAM,WAAU,YAAW;AAAA;AAAA,UAC9B;AAAA;AAAA;AAAA,MApDK,WAAW;AAAA,IAqDlB;AAAA,EAEJ,CAAC,GACH;AAEJ;AAGA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AACF,GAGG;AACD,SACE,gBAAAV;AAAA,IAACQ,QAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,SAAS,GAAG,QAAQ,EAAE;AAAA,MACjC,SAAS,EAAE,SAAS,GAAG,QAAQ,OAAO;AAAA,MACtC,MAAM,EAAE,SAAS,GAAG,QAAQ,EAAE;AAAA,MAC9B,WAAU;AAAA,MAEV;AAAA,wBAAAR,MAAC,SAAI,WAAU,2EACb;AAAA,0BAAAD,MAAC,UAAK,WAAU,qCAAoC,sBAAQ;AAAA,UAC5D,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WACF;AAAA,QACA,gBAAAA,MAAC,QAAG,WAAU,QACX,mBAAS,IAAI,CAAC,YAAY;AACzB,gBAAM,OAAO,QAAQ,QAAQ,IAAI;AACjC,iBACE,gBAAAC,MAAC,QAAsB,WAAU,uCAC/B;AAAA,4BAAAA,MAAC,UAAK,WAAU,uCAAsC;AAAA;AAAA,cAClD,QAAQ;AAAA,cACT,OAAO,gBAAAD,MAAC,UAAK,WAAU,0BAA0B,gBAAK,IAAU;AAAA,eACnE;AAAA,YACA,gBAAAA,MAAC,UAAK,WAAU,+BAA+B,kBAAQ,aAAY;AAAA,YAClE,QAAQ,SACP,gBAAAA,MAAC,UAAK,WAAU,8GAA6G,oBAE7H,IACE;AAAA,eAVG,QAAQ,IAWjB;AAAA,QAEJ,CAAC,GACH;AAAA;AAAA;AAAA,EACF;AAEJ;;;AEtyBA;AAAA,EACE;AAAA,EACA,kBAAAY;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EACA,aAAAC;AAAA,EACA,oBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAAC;AAAA,EACA;AAAA,OACK;AAEP,SAAS,mBAAAC,kBAAiB,UAAAC,eAAc;AACxC,SAAS,eAAAC,oBAAmB;AAC5B;AAAA,EACE,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OAEK;;;AC7BP,SAAS,YAAY;AACrB,OAAO,mBAAwC;AAC/C,OAAO,eAAe;AA0BlB,gBAAAC,aAAA;AAFJ,IAAM,aAAyB;AAAA,EAC7B,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA,MAAC,QAAG,WAAU,wEAAwE,GAAG,OACtF,UACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,GAAG,CAAC,EAAE,UAAU,GAAG,MAAM,MACvB,gBAAAA,MAAC,OAAE,WAAU,yCAAyC,GAAG,OACtD,UACH;AAAA,EAEF,QAAQ,CAAC,EAAE,UAAU,GAAG,MAAM,MAC5B,gBAAAA,MAAC,YAAO,WAAU,4BAA4B,GAAG,OAC9C,UACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA,MAAC,QAAG,WAAU,UAAU,GAAG,OACxB,UACH;AAAA,EAEF,GAAG,CAAC,EAAE,UAAU,GAAG,MAAM,MACvB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,QAAO;AAAA,MACP,KAAI;AAAA,MACH,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,MACvB,SAAS,aACP,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,MAAK;AAAA,MACL,UAAQ;AAAA,MACR,WAAU;AAAA;AAAA,EACZ,IAEA,gBAAAA,MAAC,WAAM,MAAa,GAAG,OAAO;AAAA,EAElC,YAAY,CAAC,EAAE,UAAU,GAAG,MAAM,MAChC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,IAAI,CAAC,UAAU,gBAAAA,MAAC,QAAG,WAAU,2CAA2C,GAAG,OAAO;AAAA;AAAA;AAAA;AAAA,EAIlF,MAAM,CAAC,EAAE,UAAU,WAAW,YAAY,GAAG,MAAM,MACjD,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA;AAAA;AAAA,EAIF,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,MACzB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,MAC3B,gBAAAA,MAAC,SAAI,WAAU,8FACb,0BAAAA,MAAC,WAAM,WAAU,uCAAuC,GAAG,OACxD,UACH,GACF;AAAA,EAEF,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,MAC3B,gBAAAA,MAAC,WAAM,WAAU,mBAAmB,GAAG,OACpC,UACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,MACxB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAAA,EAEF,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,MACpB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,OAAO;AAAA,MACZ,WAAU;AAAA,MACT,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,aAAa,EAAE,UAAU,UAAU,GAAkB;AAC5D;AAAA;AAAA;AAAA,IAGE,gBAAAA,MAAC,SAAI,WAAW,GAAG,uBAAuB,SAAS,GACjD,0BAAAA,MAAC,iBAAc,eAAe,CAAC,SAAS,GAAG,YACxC,UACH,GACF;AAAA;AAEJ;AAGO,IAAM,WAAW,KAAK,YAAY;;;ACtHrC,SASE,OAAAC,OATF,QAAAC,cAAA;AArEG,IAAM,sBAAqE;AAAA,EAChF,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,SAAS;AAAA,IACP,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,YAAY;AAAA,IACV,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,kBAAkB;AAAA,IAChB,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EACA,WAAW;AAAA,IACT,OAAO;AAAA,IACP,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AACF;AAWO,SAAS,cAAc,EAAE,QAAQ,OAAO,OAAO,MAAM,UAAU,GAAuB;AAC3F,QAAM,OAAO,oBAAoB,MAAM;AACvC,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,eAAa;AAAA,MACb,WAAW;AAAA,QACT;AAAA,QACA,SAAS,OAAO,kCAAkC;AAAA,QAClD,KAAK;AAAA,QACL;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAD,MAAC,aAAU,QAAgB,WAAW,SAAS,OAAO,WAAW,YAAY;AAAA,QAC5E,SAAS,KAAK;AAAA;AAAA;AAAA,EACjB;AAEJ;AAQO,SAAS,UAAU,EAAE,QAAQ,UAAU,GAAmB;AAC/D,QAAM,OAAO,oBAAoB,MAAM;AACvC,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,KAAK;AAAA,QACL;AAAA,MACF;AAAA,MAEC,eAAK,QACJ,gBAAAA,MAAC,UAAK,WAAW,GAAG,kDAAkD,KAAK,YAAY,GAAG,IACxF;AAAA;AAAA,EACN;AAEJ;;;AFyNY,SAqWJ,YAAAE,WAlWY,OAAAC,OAHR,QAAAC,cAAA;AA1NL,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,aAAa;AAAA,EACb,WAAW;AAAA,EACX,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,gBAAgBC,UAAQ,MAAM,SAAS,cAAc,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC;AACzF,QAAM,SAASA,UAAQ,MAAM,cAAc,aAAa,GAAG,CAAC,aAAa,CAAC;AAC1E,QAAM,gBAAgB,OAAO,CAAC,IAAI,iBAAiB,OAAO,CAAC,CAAC,IAAI;AAEhE,QAAM,YAAYC,SAA8B,IAAI;AACpD,QAAM,iBAAiBA,SAA8B,IAAI;AACzD,QAAM,0BAA0BA,SAAkC,MAAS;AAC3E,QAAM,CAAC,QAAQ,SAAS,IAAIC,WAAS,IAAI;AACzC,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAS,IAAI;AAKjD,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,KAAK;AAM9C,QAAM,wBAAwBD,SAAO,KAAK;AAC1C,QAAM,kBAAkBE,cAAY,CAAC,MAAmB,UAAkB;AACxE,UAAM,WAAW,KAAK;AACtB,0BAAsB,UAAU;AAChC,SAAK,YAAY;AACjB,QAAI,KAAK,cAAc,UAAU;AAC/B,4BAAsB,UAAU;AAAA,IAClC;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,YAAYF,SAAO,IAAI;AAK7B,QAAM,YAAYA,SAA4C,IAAI;AAClE,QAAM,WAAW,cAAc,cAAc,SAAS,CAAC;AACvD,QAAM,YACJ,aAAa,WACZ,SAAS,SAAS,mBAAmB,SAAS,SAAS,gBACxD,SAAS;AACX,QAAM,UAAU,WAAW,aAAa,CAAC;AAGzC,QAAM,yBACJ,wBAAwB,YAAY,UACpC,wBAAwB,YAAY;AACtC,QAAM,aAAa,OAAO,SAAS,MAAM,cAAc;AAMvD,QAAM,gBAAgBE,cAAY,MAAM;AACtC,UAAM,OAAO,UAAU;AACvB,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,QAAQ,CAAC,OAAO;AACnB,gBAAU,UAAU;AACpB;AAAA,IACF;AACA,UAAM,eAAe,KAAK,sBAAsB,EAAE;AAClD,eAAW,SAAS,MAAM,KAAK,MAAM,QAAQ,GAAG;AAC9C,UAAI,iBAAiB,eAAe,MAAM,QAAQ,qBAAqB,QAAW;AAChF;AAAA,MACF;AACA,YAAM,OAAO,MAAM,sBAAsB;AACzC,UAAI,KAAK,SAAS,eAAe,GAAG;AAClC,kBAAU,UAAU,EAAE,IAAI,OAAO,KAAK,KAAK,MAAM,aAAa;AAC9D;AAAA,MACF;AAAA,IACF;AACA,cAAU,UAAU;AAAA,EACtB,GAAG,CAAC,CAAC;AAKL,kBAAgB,MAAM;AACpB,UAAM,OAAO,UAAU;AACvB,QAAI,QAAQ,cAAc,QAAQ;AAChC,sBAAgB,MAAM,KAAK,YAAY;AAAA,IACzC;AACA,QAAI,CAAC,YAAY,OAAO,SAAS,GAAG;AAClC,kBAAY,IAAI;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,eAAe,SAAS,YAAY,QAAQ,UAAU,OAAO,QAAQ,eAAe,CAAC;AAIzF,kBAAgB,MAAM;AACpB,QAAI,OAAO,WAAW,KAAK,UAAU;AACnC,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,OAAO,QAAQ,QAAQ,CAAC;AAI5B,kBAAgB,MAAM;AACpB,4BAAwB,UAAU;AAClC,QAAI,CAAC,YAAY;AACf;AAAA,IACF;AACA,kBAAc,IAAI;AAClB,UAAM,QAAQ,aAAa,MAAM,cAAc,KAAK,CAAC;AACrD,WAAO,MAAM,YAAY,KAAK;AAAA,EAChC,GAAG,CAAC,YAAY,aAAa,CAAC;AAM9B,EAAAC,YAAU,MAAM;AACd,UAAM,OAAO,UAAU;AACvB,UAAM,SAAS,eAAe;AAC9B,QACE,CAAC,QACD,CAAC,UACD,CAAC,YACD,gBACA,CAAC,eACD,OAAO,yBAAyB,aAChC;AACA;AAAA,IACF;AACA,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,YAAY;AACX,YAAI,QAAQ,KAAK,CAAC,UAAU,MAAM,cAAc,GAAG;AACjD,sBAAY;AAAA,QACd;AAAA,MACF;AAAA,MACA,EAAE,MAAM,YAAY,qBAAqB;AAAA,IAC3C;AACA,aAAS,QAAQ,MAAM;AACvB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,UAAU,cAAc,aAAa,aAAa,CAAC;AAQvD,EAAAA,YAAU,MAAM;AACd,UAAM,OAAO,UAAU;AACvB,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,QAAQ,CAAC,SAAS,OAAO,mBAAmB,aAAa;AAC5D;AAAA,IACF;AACA,UAAM,WAAW,IAAI,eAAe,MAAM;AACxC,YAAM,UAAU,UAAU;AAC1B,UAAI,CAAC,SAAS;AACZ;AAAA,MACF;AACA,UAAI,cAAc,UAAU,SAAS;AACnC,wBAAgB,SAAS,QAAQ,YAAY;AAAA,MAC/C,OAAO;AACL,cAAM,SAAS,UAAU;AACzB,YAAI,UAAU,OAAO,GAAG,aAAa;AACnC,gBAAM,eAAe,QAAQ,sBAAsB,EAAE;AACrD,gBAAM,MAAM,OAAO,GAAG,sBAAsB,EAAE,MAAM;AACpD,gBAAM,OAAO,MAAM,OAAO;AAC1B,cAAI,SAAS,GAAG;AACd,4BAAgB,SAAS,QAAQ,YAAY,IAAI;AAAA,UACnD;AAAA,QACF;AAAA,MACF;AACA,oBAAc;AAAA,IAChB,CAAC;AACD,aAAS,QAAQ,KAAK;AACtB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,YAAY,eAAe,eAAe,CAAC;AAE/C,QAAM,WAAW,MAAM;AACrB,UAAM,OAAO,UAAU;AACvB,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AACA,UAAM,eAAe,sBAAsB;AAC3C,0BAAsB,UAAU;AAChC,UAAM,aAAa,KAAK,eAAe,KAAK,YAAY,KAAK,eAAe;AAG5E,QAAI,cAAc,CAAC,cAAc;AAC/B,gBAAU,UAAU;AACpB,gBAAU,UAAU;AAAA,IACtB;AACA,kBAAc;AAAA,EAChB;AAEA,SACE,gBAAAN,MAAC,oBACC,0BAAAA,MAAC,6BAA0B,OAAO,CAAC,YACjC,0BAAAC,OAAC,SAAI,WAAW,GAAG,0CAA0C,SAAS,GAGpE;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA,OAAO,OAAO,SAAS,KAAK,CAAC,WAAW,EAAE,YAAY,SAAS,IAAI;AAAA,QACnE,WAAU;AAAA,QAEV,0BAAAC,OAAC,SAAI,WAAU,gDACZ;AAAA,iBAAO,WAAW,KAAK,CAAC,UACpB,cACC,gBAAAD,MAAC,OAAE,WAAU,+CAA8C,8BAAgB,IAE7E;AAAA,UACH,WACC,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,wBAAqB;AAAA,cACrB,2BAAwB;AAAA,cACxB,eAAY;AAAA,cACZ,WAAU;AAAA;AAAA,UACZ,IACE;AAAA,UACH,eACC,gBAAAA,MAAC,SAAI,2BAAwB,IAAG,WAAU,mCACxC,0BAAAA,MAAC,UAAK,WAAU,+BAA8B,4CAAyB,GACzE,IACE;AAAA,UACH,OAAO,IAAI,CAAC,OAAO,UAClB,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA,iBAAiB,gBAAgB,OAAO,QAAQ,CAAC,CAAC;AAAA;AAAA,YAR7C,iBAAiB,KAAK;AAAA,UAS7B,CACD;AAAA,UACA,UACC,gBAAAA,MAAC,SAAI,WAAU,mCACb,0BAAAA,MAAC,UAAK,WAAU,+BAA8B,2BAAQ,GACxD,IACE;AAAA,WACN;AAAA;AAAA,IACF;AAAA,IACA,gBAAAA,MAACO,kBAAA,EACE,WAAC,UAAU,aACV,gBAAAN;AAAA,MAACO,QAAO;AAAA,MAAP;AAAA,QACC,MAAK;AAAA,QACL,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,QAC5B,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,QAC5B,MAAM,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,QACzB,YAAY,EAAE,UAAU,MAAM,MAAM,UAAU;AAAA,QAC9C,SAAS,MAAM;AACb,gBAAM,OAAO,UAAU;AACvB,cAAI,MAAM;AACR,iBAAK,SAAS,EAAE,KAAK,KAAK,cAAc,UAAU,SAAS,CAAC;AAAA,UAC9D;AACA,oBAAU,UAAU;AACpB,oBAAU,IAAI;AAAA,QAChB;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,0BAAAR,MAAC,iBAAc,WAAU,YAAW;AAAA,UAAE;AAAA;AAAA;AAAA,IAExC,IACE,MACN;AAAA,KACF,GACF,GACF;AAEJ;AAEA,SAAS,aAAa,UAAwC;AAC5D,MAAI,OAAO,0BAA0B,YAAY;AAC/C,WAAO,sBAAsB,QAAQ;AAAA,EACvC;AACA,SAAO,OAAO,WAAW,MAAM,SAAS,YAAY,IAAI,CAAC,GAAG,EAAE;AAChE;AAEA,SAAS,YAAY,IAAkB;AACrC,MAAI,OAAO,yBAAyB,YAAY;AAC9C,yBAAqB,EAAE;AACvB;AAAA,EACF;AACA,SAAO,aAAa,EAAE;AACxB;AAEA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,kBAAkB;AACpB,GAkBG;AACD,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,MAAM,WAAY,mBAAmB,iBAAiB,KAAK,IAChE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,MAAM;AAAA,UACb,SAAS,MAAM;AAAA,UACf,aAAa,aAAa,SAAY,MAAM;AAAA,UAC5C,aAAa,CAAC,cAAc,MAAM,YAAY,WAAW,OAAO;AAAA,UAChE,MAAM;AAAA,UAEN,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO,MAAM;AAAA,cACb;AAAA,cACA;AAAA,cACA;AAAA,cACA,MAAM;AAAA;AAAA,UACR;AAAA;AAAA,MACF;AAAA;AAAA;AAAA,QAIA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,MAAM;AAAA,YACb;AAAA,YACA;AAAA,YACA;AAAA,YACA,MAAM;AAAA;AAAA,QACR;AAAA;AAAA,IAEJ,KAAK,QAAQ;AACX,YAAM,gBAAgB,qBAAqB,MAAM,MAAM;AACvD,YAAM,OAAO,MAAM,OAAO,IAAI,CAAC,UAC7B,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAU;AAAA;AAAA,QARL,iBAAiB,KAAK;AAAA,MAS7B,CACD;AACD,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,SAAS,MAAM;AAAA,UAIf,aAAa,aAAa,SAAY,MAAM;AAAA,UAC5C,YAAY,gBAAgB,MAAM,WAAW,MAAM,OAAO;AAAA,UAC1D,aAAa,CAAC,cAAc,MAAM,YAAY,WAAW,OAAO;AAAA,UAChE,MAAM;AAAA,UAEL;AAAA;AAAA;AAAA,YAGC,gBAAAA,MAAC,SAAI,WAAU,uBAAuB,gBAAK;AAAA;AAAA;AAAA;AAAA,YAI3C,gBAAAA,MAAC,SAAI,WAAU,gEACZ,gBACH;AAAA;AAAA;AAAA,MAEJ;AAAA,IAEJ;AAAA,IACA,KAAK;AACH,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,MAAM;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,EAEN;AACF;AAEA,SAAS,iBAAiB,OAA8B;AACtD,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,MAAM,KAAK;AAAA,IACpB,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AACH,aAAO,MAAM;AAAA,EACjB;AACF;AAOA,SAAS,gBAAgB,MAA0C;AACjE,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AACA,SACE,KAAK,SAAS,cACd,KAAK,SAAS,UACb,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS;AAEhD;AAKA,SAAS,iBAAiB,OAA8D;AACtF,SAAO,MAAM,MAAM,MAAM,CAAC,SAAS;AACjC,QAAI,KAAK,SAAS,aAAa;AAC7B,aAAO,CAAC,KAAK;AAAA,IACf;AAEA,QAAI,KAAK,SAAS,UAAU;AAC1B,aAAO;AAAA,IACT;AACA,WAAO,KAAK,WAAW;AAAA,EACzB,CAAC;AACH;AAEA,SAAS,qBAAqB,QAAyC;AACrE,QAAM,QAAwB,CAAC;AAC/B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,YAAY;AAC7B,YAAM,KAAK,GAAG,MAAM,KAAK;AAAA,IAC3B,WAAW,MAAM,SAAS,QAAQ;AAChC,YAAM,KAAK,GAAG,qBAAqB,MAAM,MAAM,CAAC;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,WAAmB,SAAqC;AAC/E,QAAM,UAAU,KAAK,MAAM,SAAS;AACpC,QAAM,QAAQ,KAAK,MAAM,OAAO;AAChC,MAAI,CAAC,OAAO,SAAS,OAAO,KAAK,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,SAAS;AAC3E,WAAO;AAAA,EACT;AACA,SAAO,QAAQ;AACjB;AASO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQG;AACD,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,gBAAAA,MAAC,kBAAe,MAAY,mBAAsC;AAAA,IAC3E,KAAK;AACH,aAAO,gBAAAA,MAAC,mBAAgB,MAAY,mBAAsC;AAAA,IAC5E,KAAK;AACH,aAAO,gBAAAA,MAAC,uBAAoB,MAAY,eAA8B;AAAA,IACxE,KAAK;AACH,aAAO,gBAAAA,MAAC,oBAAiB,MAAY;AAAA,IACvC,KAAK;AACH,aAAO,gBAAAA,MAAC,WAAQ,MAAY;AAAA,IAC9B,KAAK;AACH,aAAO,gBAAAA,MAAC,aAAU,MAAY;AAAA,IAChC,KAAK;AACH,aACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,qBAAqB;AACnC,SACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,SAAS,oBAAoB,kBAAkB,GAChE,0BAAAA,MAAC,SAAI,WAAU,qDACb,0BAAAA,MAAC,SAAI,WAAU,+IACZ,8BACC,kBAAkB,KAAK,MAAM,IAAI,IAEjC,gBAAAA,MAAC,YAAU,eAAK,MAAK,GAEzB,GACF,GACF;AAEJ;AAEA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,qBAAqB;AACnC,QAAM,QAAQ,KAAK,YACjB,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAW;AAAA;AAAA,EACb,IACE;AACJ,SACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,SAAS,oBAAoB,yCAAyC,GACtF,8BACC,gBAAAC,OAAAF,WAAA,EACG;AAAA,sBAAkB,KAAK,MAAM,IAAI;AAAA,IACjC;AAAA,KACH;AAAA;AAAA;AAAA;AAAA,IAKA,gBAAAE,OAAC,SAAI,WAAW,KAAK,YAAY,gCAAgC,QAC/D;AAAA,sBAAAD,MAAC,YAAU,eAAK,MAAK;AAAA,MACpB;AAAA,OACH;AAAA,KAEJ;AAEJ;AAuBA,SAAS,qBAAqB,MAAkD;AAC9E,MAAI,KAAK,gBAAgB,UAAU;AACjC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF;AACA,MAAI,KAAK,eAAe,UAAU;AAChC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF;AACA,MAAI,KAAK,eAAe,aAAa;AACnC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF;AACA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAMS;AAAA,IACN,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AACF;AAEA,SAAS,oBAAoB;AAAA,EAC3B;AAAA,EACA;AACF,GAGG;AACD,QAAM,QAAQ,qBAAqB;AACnC,QAAM,CAAC,MAAM,OAAO,IAAIL,WAAS,KAAK;AACtC,QAAM,OAAO,qBAAqB,IAAI;AACtC,QAAM,OAAO,KAAK;AAMlB,QAAM,mBACJ,KAAK,gBAAgB,YACrB,KAAK,eAAe,YACpB,QAAQ,KAAK,cAAc,KAAK,CAAC;AACnC,QAAM,UAA+D;AAAA,IACnE,GAAI,KAAK,KAAK,KAAK,IAAI,CAAC,EAAE,OAAO,UAAU,OAAO,KAAK,KAAK,KAAK,EAAE,CAAC,IAAI,CAAC;AAAA,IACzE,GAAI,KAAK,UAAU,KAAK,IACpB,CAAC,EAAE,OAAO,YAAY,OAAO,KAAK,SAAS,KAAK,GAAG,OAAO,KAAK,CAAC,IAChE,CAAC;AAAA,IACL,GAAI,mBACA,CAAC,EAAE,OAAO,kBAAkB,OAAO,KAAK,aAAc,KAAK,GAAG,OAAO,KAAK,CAAC,IAC3E,CAAC;AAAA,EACP;AACA,QAAM,aAAa,QAAQ,SAAS;AACpC,SACE,gBAAAJ,MAAC,SAAI,WAAW,GAAG,SAAS,oBAAoB,SAAS,GAGvD,0BAAAC,OAAC,SAAI,WAAW,GAAG,uCAAuC,KAAK,WAAW,GACxE;AAAA,oBAAAA,OAAC,SAAI,WAAU,4BACb;AAAA,sBAAAD,MAAC,UAAK,WAAW,GAAG,mBAAmB,KAAK,SAAS,GACnD,0BAAAA,MAAC,QAAK,WAAU,UAAS,GAC3B;AAAA,MACA,gBAAAA,MAAC,SAAI,WAAU,kBACb,0BAAAC,OAAC,OAAE,WAAU,qCACX;AAAA,wBAAAD,MAAC,UAAK,WAAU,eAAe,eAAK,OAAM;AAAA,QACzC,KAAK,WACJ,gBAAAC,OAAC,UAAK,WAAU,oBAAmB;AAAA;AAAA,UAAI,SAAS,KAAK,UAAU,EAAE;AAAA,WAAE,IACjE;AAAA,SACN,GACF;AAAA,MACC,KAAK,kBAAkB,gBACtB,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,cAAc,KAAK,cAAc;AAAA,UAChD,WAAW;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACD;AAAA;AAAA,YAEC,gBAAAD,MAACU,iBAAA,EAAe,WAAU,YAAW;AAAA;AAAA;AAAA,MACvC,IACE;AAAA,OACN;AAAA,IACC,aACC,gBAAAT,OAACU,aAAY,MAAZ,EAAiB,MAAY,cAAc,SAC1C;AAAA,sBAAAX,MAACW,aAAY,SAAZ,EAAoB,SAAO,MAC1B,0BAAAV;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAW;AAAA,YACT;AAAA,YACA;AAAA,UACF;AAAA,UAEA;AAAA,4BAAAD,MAACY,mBAAA,EAAiB,WAAU,gGAA+F;AAAA,YAC1H,OAAO,iBAAiB;AAAA;AAAA;AAAA,MAC3B,GACF;AAAA,MACA,gBAAAZ,MAACW,aAAY,SAAZ,EAAoB,WAAU,+FAC7B,0BAAAX,MAAC,SAAI,WAAU,qCACZ,kBAAQ,IAAI,CAAC,WACZ,gBAAAC,OAAC,SAAuB,WAAU,WAChC;AAAA,wBAAAD,MAAC,OAAE,WAAU,6EACV,iBAAO,OACV;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,OAAO,QAAQ,sBAAsB;AAAA,YACvC;AAAA,YAEC,iBAAO;AAAA;AAAA,QACV;AAAA,WAXQ,OAAO,KAYjB,CACD,GACH,GACF;AAAA,OACF,IACE;AAAA,KACN,GACF;AAEJ;AAEA,SAAS,iBAAiB,EAAE,KAAK,GAA4D;AAC3F,QAAM,QAAQ,qBAAqB;AACnC,QAAM,OAAO,oBAAoB,KAAK,MAAM;AAC5C,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT,SAAS;AAAA,QACT;AAAA,MACF;AAAA,MACA,MAAK;AAAA,MAEL;AAAA,wBAAAD,MAAC,UAAK,WAAU,4BAA2B;AAAA,QAC3C,gBAAAC,OAAC,UAAK,WAAU,oCACd;AAAA,0BAAAD,MAAC,aAAU,QAAQ,KAAK,QAAQ,WAAU,UAAS;AAAA,UAClD,KAAK,MAAM,YAAY;AAAA,UAAE;AAAA,UAAI,mBAAmB,KAAK,UAAU;AAAA,WAClE;AAAA,QACA,gBAAAA,MAAC,UAAK,WAAU,4BAA2B;AAAA;AAAA;AAAA,EAC7C;AAEJ;AAqBA,IAAM,eAAe;AAErB,IAAM,YAAkD;AAAA,EACtD,KAAK;AAAA,IACH,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,SAAS,EAAE,OAAO,gBAAgB,MAAM,cAAc,MAAM,eAAe;AAAA,EAC3E,WAAW;AAAA,IACT,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAMa;AAAA,EACR;AAAA,EACA,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,SAAS,EAAE,OAAO,gBAAgB,MAAM,cAAc,MAAMC,UAAS;AAAA,EACrE,SAAS,EAAE,OAAO,gBAAgB,MAAM,cAAc,MAAM,WAAW;AAAA,EACvE,cAAc,EAAE,OAAO,8BAA8B,MAAM,cAAc,MAAMJ,gBAAe;AAChG;AAOA,SAAS,QAAQ,EAAE,KAAK,GAAuB;AAC7C,QAAM,QAAQ,qBAAqB;AACnC,QAAM,EAAE,OAAO,MAAM,MAAM,KAAK,IAAI,UAAU,KAAK,MAAM;AACzD,SACE,gBAAAV,MAAC,SAAI,WAAW,GAAG,SAAS,oBAAoB,qBAAqB,GACnE,0BAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAD,MAAC,QAAK,WAAU,qBAAoB;AAAA,QACpC,gBAAAC,OAAC,UAAK,WAAU,YACb;AAAA;AAAA,UACA,KAAK,OAAO,KAAK,SAAS,KAAK,MAAM,EAAE,CAAC,KAAK;AAAA,WAChD;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;AAEA,SAAS,UAAU,EAAE,KAAK,GAAyB;AACjD,QAAM,QAAQ,qBAAqB;AACnC,QAAM,OACJ,KAAK,SAAS,WACV,4EACA,KAAK,SAAS,YACZ,+EACA;AACR,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAK;AAAA,MAEL;AAAA,wBAAAD;AAAA,UAACe;AAAA,UAAA;AAAA,YACC,WAAW,GAAG,0BAA0B,KAAK,SAAS,eAAe,YAAY;AAAA;AAAA,QACnF;AAAA,QACA,gBAAAd,OAAC,SAAI,WAAU,kBACb;AAAA,0BAAAD,MAAC,UAAK,WAAU,mCAAmC,eAAK,MAAK;AAAA,UAC5D,KAAK,UACJ,gBAAAC,OAAC,aAAQ,WAAU,gBACjB;AAAA,4BAAAD,MAAC,aAAQ,WAAU,8BAA8B,eAAK,QAAQ,OAAM;AAAA,YACpE,gBAAAA,MAAC,SAAI,WAAU,oHACZ,eAAK,UAAU,KAAK,QAAQ,OAAO,MAAM,CAAC,GAC7C;AAAA,aACF,IACE;AAAA,WACN;AAAA,QACC,KAAK,SACJ,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAM,KAAK,OAAO;AAAA,YAClB,KAAI;AAAA,YACJ,QAAO;AAAA,YAEN,eAAK,OAAO;AAAA;AAAA,QACf,IACE;AAAA;AAAA;AAAA,EACN;AAEJ;AAUA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,QAAQ,qBAAqB;AACnC,QAAM,CAAC,MAAM,OAAO,IAAII,WAAS,KAAK;AACtC,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAS,KAAK;AAC1C,QAAM,WAAW,cAAc,KAAK,cAAc;AAElD,QAAM,QAAQ,YAAY;AACxB,QAAI,CAAC,eAAe,MAAM;AACxB;AAAA,IACF;AACA,YAAQ,IAAI;AACZ,cAAU,KAAK;AACf,QAAI;AAGF,YAAM,YAAY,IAAI;AACtB,cAAQ,KAAK;AAAA,IACf,QAAQ;AACN,gBAAU,IAAI;AACd,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,gBAAAH,OAAC,SAAI,WAAW,GAAG,SAAS,oBAAoB,qBAAqB,GAAG,MAAK,UAC3E;AAAA,oBAAAA,OAAC,SAAI,WAAU,qHACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,0CACb;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,KAAK,sBAAsB,KAAK,cAAc,KAAK;AAAA,YACnD,OAAO;AAAA;AAAA,QACT;AAAA,QACA,gBAAAC,OAAC,SAAI,WAAU,WACb;AAAA,0BAAAA,OAAC,OAAE,WAAU,8CAA6C;AAAA;AAAA,YAAW;AAAA,aAAS;AAAA,UAC9E,gBAAAD,MAAC,OAAE,WAAU,yCAAyC,yBAAe,KAAK,MAAM,GAAE;AAAA,WACpF;AAAA,SACF;AAAA,MACC,cACC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,KAAK,MAAM;AAAA,UAC1B,UAAU;AAAA,UACV,WAAW;AAAA,YACT;AAAA,YACA;AAAA,UACF;AAAA,UAEA;AAAA,4BAAAD,MAAC,iBAAc,WAAW,GAAG,YAAY,QAAQ,iBAAiB,GAAG,eAAW,MAAC;AAAA,YAChF,OAAO,uBAAkB;AAAA;AAAA;AAAA,MAC5B,IACE,KAAK,mBACP,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,KAAK;AAAA,UACX,KAAI;AAAA,UACJ,QAAO;AAAA,UACP,WAAW;AAAA,YACT;AAAA,YACA;AAAA,UACF;AAAA,UAEA;AAAA,4BAAAD,MAAC,iBAAc,WAAU,YAAW,eAAW,MAAC;AAAA,YAAE;AAAA;AAAA;AAAA,MAEpD,IACE;AAAA,OACN;AAAA,IACC,SACC,gBAAAC,OAAC,OAAE,WAAU,yCAAwC;AAAA;AAAA,MACtB;AAAA,MAAS;AAAA,OACxC,IACE;AAAA,KACN;AAEJ;AASA,SAAS,iBAAiB,EAAE,KAAK,MAAM,GAA0C;AAC/E,QAAM,CAAC,QAAQ,SAAS,IAAIG,WAAS,KAAK;AAG1C,EAAAE,YAAU,MAAM,UAAU,KAAK,GAAG,CAAC,GAAG,CAAC;AACvC,QAAM,YAAY,OAAO,CAAC;AAC1B,SACE,gBAAAN;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,eAAW;AAAA,MAEV,sBACC,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,KAAI;AAAA,UACJ,SAAQ;AAAA,UACR,UAAS;AAAA,UACT,WAAU;AAAA,UACV,SAAS,MAAM,UAAU,IAAI;AAAA;AAAA,MAC/B,IAEA,gBAAAA,MAAC,UAAM,mBAAS,KAAK,GAAE;AAAA;AAAA,EAE3B;AAEJ;AAIA,SAAS,SAAS,OAAuB;AACvC,QAAM,QAAQ,MAAM,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AACtD,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AACA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,MAAM,CAAC,EAAG,MAAM,GAAG,CAAC,EAAE,YAAY;AAAA,EAC3C;AACA,UAAQ,MAAM,CAAC,EAAG,CAAC,IAAK,MAAM,CAAC,EAAG,CAAC,GAAI,YAAY;AACrD;AAIA,SAAS,cAAc,QAAwB;AAC7C,QAAM,OACJ,OACG,KAAK,EACL,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,UAAU,EAAE,EACpB,MAAM,GAAG,EAAE,CAAC,KAAK;AACtB,QAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK;AACpC,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,SAAO,MAAM,OAAO,CAAC,EAAE,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD;AAIA,SAAS,eAAe,QAA0C;AAChE,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;AGtlCM,gBAAAgB,OAWA,QAAAC,cAXA;AAvCC,SAAS,oBAAoB,SAA0B;AAG5D,MAAI,OAAO,QAAQ,UAAU,YAAY,QAAQ,MAAM,KAAK,EAAE,SAAS,GAAG;AACxE,WAAO,QAAQ;AAAA,EACjB;AACA,aAAW,OAAO,CAAC,SAAS,MAAM,GAAY;AAC5C,UAAM,QAAQ,QAAQ,SAAS,GAAG;AAClC,QAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG;AACxD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,SAAS,QAAQ,gBAAgB,GAAG,KAAK,QAAQ,GAAG,MAAM,GAAG,CAAC;AACvE;AAOO,SAAS,UAAU,EAAE,SAAS,OAAO,UAAU,QAAQ,UAAU,GAAmB;AACzF,QAAM,UAAU,QAAQ,WAAW,aAAa,QAAQ,WAAW;AACnE,QAAM,WAAW,QAAQ,WAAW;AACpC,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,eAAa,QAAQ;AAAA,MACrB,SAAS,SAAS,MAAM,OAAO,OAAO,IAAI;AAAA,MAC1C,UAAU,CAAC;AAAA,MACX,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA,UACE;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,eAAW;AAAA,YACX,WAAW;AAAA,cACT;AAAA,cACA,UACI,6BACA,WACE,qCACA;AAAA,YACR;AAAA;AAAA,QACF;AAAA,QACA,gBAAAC,OAAC,UAAK,WAAU,iDACd;AAAA,0BAAAD,MAAC,UAAK,WAAU,yEACb,mBAAS,oBAAoB,OAAO,GACvC;AAAA,UACA,gBAAAA,MAAC,iBAAc,QAAQ,QAAQ,QAAQ,MAAK,MAAK,WAAU,SAAQ;AAAA,WACrE;AAAA,QACC,WACC,gBAAAA,MAAC,UAAK,WAAU,4CAA4C,oBAAS,IACnE;AAAA,QACJ,gBAAAC,OAAC,UAAK,WAAU,uEACd;AAAA,0BAAAD,MAAC,UAAK,WAAU,gBAAgB,kBAAQ,GAAG,MAAM,GAAG,CAAC,GAAE;AAAA,UACvD,gBAAAA,MAAC,UAAK,eAAW,MAAC,kBAAC;AAAA,UACnB,gBAAAA,MAAC,UAAK,WAAU,YAAY,kBAAQ,OAAM;AAAA,UAC1C,gBAAAA,MAAC,UAAK,WAAU,oBAAmB,OAAO,QAAQ,WAC/C,6BAAmB,QAAQ,SAAS,GACvC;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACpFA,SAAyB,aAAAE,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;;;ACsD5D,IAAM,YAAyB;AAAA,EAC7B,OAAO;AAAA,EACP,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,6BAA6B;AAC/B;AAEA,IAAM,aAA0B;AAAA,EAC9B,OAAO;AAAA,EACP,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,aAAa;AAAA,EACb,WAAW;AAAA,EACX,aAAa;AAAA,EACb,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,qBAAqB;AAAA,EACrB,qBAAqB;AAAA,EACrB,6BAA6B;AAC/B;AAGO,SAAS,cAAc,MAA8B;AAC1D,SAAO,SAAS,UAAU,aAAa;AACzC;AAQO,SAAS,gBAAgB,MAAmB,MAA6B;AAC9E,QAAM,OAAO,cAAc,IAAI;AAC/B,QAAM,aAAa,SAAS,UAAU,2BAA2B;AACjE,QAAM,aAAa,SAAS,UAAU,0BAA0B;AAChE,QAAM,KAAK,KAAK,eAAe,KAAK;AACpC,QAAM,KAAK,KAAK,eAAe,KAAK;AACpC,QAAM,SAAS,KAAK,mBAAmB,KAAK,KAAK;AACjD,SAAO;AAAA;AAAA,IAEL,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,qBAAqB,KAAK;AAAA,IAC1B,qBAAqB,KAAK;AAAA,IAC1B,6BAA6B,KAAK;AAAA,IAClC,OAAO,KAAK;AAAA,IACZ,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,SAAS,KAAK;AAAA,IACd,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,aAAa,KAAK;AAAA,IAClB,WAAW,KAAK;AAAA,IAChB,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,IACnB,YAAY,KAAK;AAAA,IACjB,eAAe,KAAK;AAAA,IACpB,YAAY,KAAK;AAAA,IACjB,aAAa,KAAK;AAAA,EACpB;AACF;AAKA,SAAS,WAAW,IAAa,OAAuC;AACtE,QAAM,UAAU,GAAG,SAAS,KAAK,EAAE;AACnC,MAAI,SAAS;AACX,QAAI,QAAQ,yBAAyB,KAAK,QAAQ,WAAW,EAAG,QAAO;AACvE,UAAM,WAAW,QAAQ,iBAAiB;AAC1C,QAAI,SAAU,QAAO,SAAS,aAAa,eAAe,MAAM,UAAU,UAAU;AAAA,EACtF;AACA,QAAM,UACJ,MAAM,iBAAiB,cAAc,EAAE,KAAK,KAC5C,MAAM,eACN,IACA,YAAY;AACd,MAAI,OAAO,SAAS,OAAO,KAAK,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO;AACjE,SAAO;AACT;AAYO,SAAS,qBAAqB,MAAmD;AACtF,MAAI,OAAO,WAAW,eAAe,OAAO,qBAAqB,YAAa,QAAO;AACrF,QAAM,KACJ,SACC,OAAO,aAAa,cACf,SAAS,cAAc,iBAAiB,KAC1C,SAAS,kBACT;AACN,MAAI,CAAC,GAAI,QAAO;AAChB,QAAM,QAAQ,iBAAiB,EAAE;AACjC,QAAM,OAAoB,CAAC,SAAS;AAClC,UAAM,QAAQ,MAAM,iBAAiB,IAAI,EAAE,KAAK;AAChD,WAAO,SAAS;AAAA,EAClB;AACA,SAAO,gBAAgB,MAAM,WAAW,IAAI,KAAK,CAAC;AACpD;AAOA,IAAM,gBAAgB;AAWf,SAAS,8BACd,MACA,WACsB;AACtB,QAAM,YAAY,WAAW,cAAc,KAAK,gBAAgB;AAChE,QAAM,aACJ,aAAa,UAAU,KAAK,KAAK,CAAC,UAAU,SAAS,MAAM,IAAI,UAAU,KAAK,IAAI;AAEpF,MAAI,WAAW,WAAW;AAC1B,MAAI,YAAY,MAAM;AACpB,UAAM,MAAM,KAAK,qBAAqB;AACtC,UAAM,SAAS,MAAM,OAAO,WAAW,GAAG,IAAI,OAAO;AACrD,eAAW,OAAO,SAAS,MAAM,KAAK,SAAS,IAAI,SAAS;AAAA,EAC9D;AAEA,SAAO,EAAE,YAAY,UAAU,YAAY,IAAI;AACjD;AAGO,SAAS,oBACd,IACA,WACsB;AACtB,QAAM,QAAQ,iBAAiB,EAAE;AACjC,QAAM,OAAoB,CAAC,SAAS;AAClC,UAAM,QAAQ,MAAM,iBAAiB,IAAI,EAAE,KAAK;AAChD,WAAO,SAAS;AAAA,EAClB;AACA,SAAO,8BAA8B,MAAM,SAAS;AACtD;;;AClNA,IAAM,QAAwB,CAAC,SAAS,UAAU,KAAK;AAGhD,SAAS,iBAAiB,MAAyC;AACxE,QAAM,IAAI,MAAM,QAAQ,IAAI;AAC5B,SAAO,KAAK,KAAK,IAAI,MAAM,SAAS,IAAI,MAAM,IAAI,CAAC,IAAK;AAC1D;AAQA,eAAsB,eACpB,QACA,SACA,QACuB;AACvB,QAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,QAAQ,MAAM,CAAC;AAC/C,WAAS,IAAI,OAAO,IAAI,MAAM,QAAQ,KAAK;AACzC,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,SAAS,MAAO;AACpB,UAAM,SAAS,SAAS,UAAU,QAAQ,QAAQ,QAAQ;AAC1D,QAAI,CAAC,OAAQ;AACb,QAAI;AACF,YAAM,YAAY,iBAAiB,IAAI,KAAK;AAC5C,YAAM,OAAO,MAAM;AACjB,aAAK,eAAe,WAAW,SAAS,MAAM;AAAA,MAChD,CAAC;AACD,aAAO,IAAI;AACX,aAAO;AAAA,IACT,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,KAAK;AACZ,SAAO;AACT;;;AFmaY,gBAAAC,OAMA,QAAAC,cANA;AA5VZ,SAAS,yBAA4C;AACnD,QAAM,MAAM,OAAO,eAAe,cAAc,WAAW,6BAA6B;AACxF,QAAM,MAAM,oBAAI,IAAkB;AAClC,MAAI,OAAO,QAAQ,UAAU;AAC3B,eAAW,QAAQ,IAAI,MAAM,QAAQ,GAAG;AACtC,UAAI,SAAS,WAAW,SAAS,SAAU,KAAI,IAAI,IAAI;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AACT;AAsBO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,eAAeC,SAA8B,IAAI;AACvD,QAAM,UAAUA,SAAyB,IAAI;AAC7C,QAAM,SAASA,SAA4B,IAAI;AAC/C,QAAM,cAAcA,SAA4B,IAAI;AACpD,QAAM,aAAaA,SAAoB,oBAAI,IAAI,CAAC;AAChD,QAAM,mBAAmBA,SAAO,KAAK;AACrC,QAAM,gBAAgBA,SAAO,KAAK;AAClC,QAAM,CAAC,OAAO,QAAQ,IAAIC,WAAS,KAAK;AACxC,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,KAAK;AAGhD,QAAM,QAAQ,oBAAoB,cAAc,YAAY,QAAQ,oBAAoB,GAAG;AAE3F,QAAM,oBAAoBD,SAAiB,CAAC,CAAC;AAC7C,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,EACb,IAAI,kBAAkB;AAAA,IACpB,YAAY,QACR;AAAA,MACE,WAAW,mBAAoB;AAAA,MAC/B,KAAK,mBAAoB;AAAA,MACzB,OAAO,mBAAoB;AAAA,IAC7B,IACA;AAAA,IACJ,UAAU,CAAC,SAAS;AAClB,YAAM,OAAO,QAAQ;AACrB,UAAI,KAAM,MAAK,MAAM,IAAI;AAAA,UACpB,mBAAkB,QAAQ,KAAK,IAAI;AAAA,IAC1C;AAAA,EACF,CAAC;AAID,QAAM,UAAU,SAAS,cAAc;AACvC,QAAM,cAAc,CAAC,aAAa,WAAW,OAAO,UAAU;AAK9D,QAAM,OAAO,aAAa,UAAU,aAAa;AACjD,QAAM,UAAU,aAAa,CAAC,WAAW,CAAC,QAAQ,YAAY,QAAQ,OAAO,OAAO,WAAW;AAE/F,WAAS,iBAAiB;AACxB,QAAI,CAAC,UAAW,cAAa,IAAI;AACjC,iBAAa;AAAA,EACf;AAKA,EAAAE,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AACnC,UAAM,KAAK,aAAa;AACxB,QAAI,CAAC,GAAI;AACT,QAAI,WAAW;AAIf,UAAM,cAAc,CAAC,SACnB,IAAI,QAAc,CAAC,YAAY;AAC7B,UAAI,KAAK,cAAc,KAAK,KAAK,eAAe,EAAG,QAAO,QAAQ;AAClE,YAAM,KAAK,IAAI,eAAe,MAAM;AAClC,YAAI,KAAK,cAAc,KAAK,KAAK,eAAe,GAAG;AACjD,aAAG,WAAW;AACd,kBAAQ;AAAA,QACV;AAAA,MACF,CAAC;AACD,SAAG,QAAQ,IAAI;AACf,iBAAW,MAAM;AACf,WAAG,WAAW;AACd,gBAAQ;AAAA,MACV,GAAG,GAAI;AAAA,IACT,CAAC;AAEH,uBAAmB;AAEnB,UAAM,YAAY;AAChB,YAAM,CAAC,EAAE,SAAS,GAAG,EAAE,SAAS,GAAG,EAAE,cAAc,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,QACxE,OAAO,cAAc;AAAA,QACrB,OAAO,kBAAkB;AAAA,QACzB,OAAO,wBAAwB;AAAA,MACjC,CAAC;AACD,UAAI,SAAU;AACd,YAAM,YAAY,EAAE;AACpB,UAAI,SAAU;AAKd,YAAM,OAAO,oBAAoB,IAAI,EAAE,YAAY,SAAS,CAAC;AAC7D,YAAM,eAAe,SAAS,qBAAqB,EAAE;AAErD,YAAM,OAAO,IAAI,SAAS;AAAA,QACxB,YAAY;AAAA,QACZ,cAAc,CAAC;AAAA,QACf,aAAa;AAAA,QACb,YAAY,KAAK;AAAA,QACjB,UAAU,KAAK;AAAA,QACf,YAAY,KAAK;AAAA,QACjB,GAAI,eAAe,EAAE,OAAO,aAAa,IAAI,CAAC;AAAA,MAChD,CAAC;AACD,YAAM,MAAM,IAAI,SAAS;AACzB,WAAK,UAAU,GAAG;AAClB,WAAK;AAAA,QACH,IAAI;AAAA,UAAc,CAAC,IAAgB,QACjC,OAAO,KAAK,KAAK,UAAU,qBAAqB;AAAA,QAClD;AAAA,MACF;AACA,WAAK,KAAK,EAAE;AACZ,cAAQ,UAAU;AAClB,aAAO,UAAU;AAOjB,YAAM,UAAU,uBAAuB;AACvC,YAAM,UAA2B;AAAA,QAC/B,OAAO,OAAO,WAAW;AACvB,cAAI,QAAQ,IAAI,OAAO,EAAG,OAAM,IAAI,MAAM,sBAAsB;AAChE,gBAAM,EAAE,WAAW,IAAI,MAAM,OAAO,oBAAoB;AACxD,gBAAM,QAAQ,IAAI,WAAW;AAI7B,gBAAM,gBAAgB,MAAM;AAC1B,gBAAI;AACF,oBAAM,QAAQ;AAAA,YAChB,QAAQ;AAAA,YAER;AACA,mBAAO;AAAA,UACT,CAAC;AACD,eAAK,UAAU,KAAK;AACpB,iBAAO;AAAA,QACT;AAAA,MACF;AACA,YAAM,eAAe,SAAS,SAAS,CAAC,SAAS;AAC/C,oBAAY,UAAU;AACtB,WAAG,aAAa,yBAAyB,IAAI;AAAA,MAC/C,CAAC;AACD,UAAI,SAAU;AAKd,YAAM,SAAS,MAAM;AACnB,YAAI;AACF,cAAI,IAAI;AAAA,QACV,QAAQ;AAAA,QAER;AAAA,MACF;AACA,aAAO;AACP,4BAAsB,MAAM;AAC1B,YAAI,SAAU;AACd,eAAO;AACP,YAAI,kBAAkB,QAAQ,SAAS,GAAG;AACxC,qBAAW,QAAQ,kBAAkB,QAAS,MAAK,MAAM,IAAI;AAC7D,4BAAkB,UAAU,CAAC;AAAA,QAC/B;AACA,WAAG,aAAa,sBAAsB,MAAM;AAC5C,YAAI,OAAO,WAAW,0BAA0B,YAAY;AAC1D,qBAAW,sBAAsB;AAAA,YAC/B,UAAU,YAAY;AAAA,YACtB,YAAY,KAAK,QAAQ;AAAA,YACzB,UAAU,KAAK,QAAQ;AAAA,YACvB,cAAc,OAAO,KAAK,QAAQ,cAAc,EAAE,EAAE,SAAS,MAAM;AAAA,YACnE,OAAO,KAAK,QAAQ;AAAA,YACpB;AAAA,UACF,CAAC;AAAA,QACH;AACA,iBAAS,IAAI;AAAA,MACf,CAAC;AAAA,IACH,GAAG;AAEH,WAAO,MAAM;AACX,iBAAW;AACX,cAAQ,SAAS,QAAQ;AACzB,cAAQ,UAAU;AAClB,aAAO,UAAU;AACjB,kBAAY,UAAU;AACtB,iBAAW,UAAU,oBAAI,IAAI;AAC7B,uBAAiB,UAAU;AAC3B,oBAAc,UAAU;AACxB,eAAS,KAAK;AAAA,IAChB;AAAA,EAGF,GAAG,CAAC,CAAC;AAIL,EAAAA,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,SAAS,CAAC,KAAM;AACrB,SAAK,QAAQ,eAAe,CAAC;AAC7B,SAAK,QAAQ,cAAc;AAAA,EAC7B,GAAG,CAAC,OAAO,WAAW,CAAC;AAIvB,EAAAA,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,SAAS,CAAC,KAAM;AACrB,UAAM,OAAO,SAAS,qBAAqB,aAAa,OAAO;AAC/D,QAAI,KAAM,MAAK,QAAQ,QAAQ;AAAA,EACjC,GAAG,CAAC,OAAO,KAAK,CAAC;AAMjB,EAAAA,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,SAAS,CAAC,KAAM;AACrB,QAAI,CAAC,SAAS;AACZ,UAAI,cAAc,SAAS;AACzB,sBAAc,UAAU;AACxB,YAAI,CAAC,iBAAiB,QAAS,MAAK,MAAM;AAAA,MAC5C;AACA;AAAA,IACF;AACA,kBAAc,UAAU;AACxB,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,QAAQ,MAAM;AAClB,YAAM,IAAI,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,IAAI,IAAI,SAAS,GAAI,CAAC;AAG7D,WAAK,MAAM,+DAAqD,CAAC,gBAAW;AAAA,IAC9E;AACA,SAAK,MAAM,MAAM;AACjB,UAAM;AACN,UAAM,KAAK,YAAY,OAAO,GAAI;AAClC,WAAO,MAAM,cAAc,EAAE;AAAA,EAC/B,GAAG,CAAC,OAAO,OAAO,CAAC;AAKnB,EAAAA,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,SAAS,CAAC,QAAQ,QAAS;AAChC,eAAW,SAAS,OAAO,QAAQ;AACjC,UAAI,WAAW,QAAQ,IAAI,MAAM,EAAE,EAAG;AACtC,iBAAW,QAAQ,IAAI,MAAM,EAAE;AAC/B,uBAAiB,UAAU;AAC3B,WAAK,MAAM,MAAM,IAAI;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,OAAO,OAAO,QAAQ,OAAO,CAAC;AAIlC,EAAAA,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAa;AACrC,UAAM,OAAO,UAAU,WAAW,OAAO;AACzC,QAAI,CAAC,KAAM;AACX,UAAM,MAAM,KAAK,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC;AAC5C,WAAO,MAAM,IAAI,QAAQ;AAAA,EAC3B,GAAG,CAAC,OAAO,aAAa,SAAS,UAAU,OAAO,KAAK,CAAC;AAGxD,EAAAA,YAAU,MAAM;AACd,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAS;AACjC,cAAU,KAAK,MAAM,KAAK,IAAI;AAC9B,UAAM,MAAM,KAAK,SAAS,CAAC,EAAE,MAAM,KAAK,MAAM,UAAU,MAAM,IAAI,CAAC;AACnE,WAAO,MAAM,IAAI,QAAQ;AAAA,EAC3B,GAAG,CAAC,OAAO,SAAS,cAAc,SAAS,CAAC;AAG5C,EAAAA,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,YAAa;AACnC,UAAM,QAAQ,MAAM;AAClB,UAAI;AACF,eAAO,SAAS,IAAI;AAAA,MACtB,QAAQ;AAAA,MAER;AAAA,IACF;AACA,WAAO,iBAAiB,UAAU,KAAK;AACvC,QAAI,WAAkC;AACtC,UAAM,KAAK,aAAa;AACxB,QAAI,MAAM,OAAO,mBAAmB,aAAa;AAC/C,iBAAW,IAAI,eAAe,MAAM,MAAM,CAAC;AAC3C,eAAS,QAAQ,EAAE;AAAA,IACrB;AACA,WAAO,MAAM;AACX,aAAO,oBAAoB,UAAU,KAAK;AAC1C,gBAAU,WAAW;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,SACE,gBAAAH,OAAC,SAAI,WAAW,GAAG,wDAAwD,SAAS,GACjF;AAAA,kBACC,gBAAAA,OAAC,SAAI,WAAU,qHACb;AAAA,sBAAAA,OAAC,UAAK,WAAU,qCACd;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,OAAO,UAAU,yBAAyB;AAAA,YAC5C;AAAA;AAAA,QACF;AAAA,QACA,gBAAAC,OAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,UAAM,SAAS;AAAA,WAAQ;AAAA,SACjE;AAAA,MACA,gBAAAA,OAAC,UAAK,WAAU,oCACb;AAAA,SAAC,eACA,gBAAAD,MAAC,UAAK,WAAU,kFAAiF,uBAEjG;AAAA,QAEF,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM;AACb,sBAAQ,SAAS,MAAM;AACvB,yBAAW,UAAU,oBAAI,IAAI;AAC7B,+BAAiB,UAAU;AAAA,YAC7B;AAAA,YACA,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,SACF;AAAA,OACF;AAAA,IAMF,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,sBAAsB;AAAA,QACtB,gBAAgB;AAAA,QAEf;AAAA,WAAC,UAAU,eAAe,gBAAAD,MAAC,uBAAoB;AAAA,UAGhD,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,WAAU;AAAA,cACV,OAAO,EAAE,YAAY,QAAQ,YAAY,SAAS;AAAA,cAClD,0BAAsB;AAAA;AAAA,UACxB;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AASA,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCvB,SAAS,qBAA2B;AAClC,MAAI,OAAO,aAAa,YAAa;AACrC,MAAI,SAAS,eAAe,cAAc,EAAG;AAC7C,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,KAAK;AACX,QAAM,cAAc;AACpB,WAAS,KAAK,YAAY,KAAK;AACjC;AAEA,SAAS,sBAAsB;AAC7B,SACE,gBAAAA,MAAC,SAAI,WAAU,kFAAiF,oCAEhG;AAEJ;;;AG9kBA;AAAA,EACE,oBAAAK;AAAA,EACA,YAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,EACA,cAAAC;AAAA,OACK;AACP;AAAA,EAGE,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OACK;AACP,SAAS,aAA+B;AA0d3B,SA0LD,YAAAC,WA1LC,OAAAC,OAqDH,QAAAC,cArDG;AAzbb,IAAM,cAAmE;AAAA,EACvE,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,WAAW;AACb;AACA,IAAM,yBAAyB,OAAO,WAAW,cAAcC,cAAYC;AAG3E,SAASC,UAAS,MAAsB;AACtC,QAAM,IAAI,KAAK,YAAY,GAAG;AAC9B,SAAO,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG,CAAC;AACtC;AAGA,SAAS,SAAS,QAAgB,MAAsB;AACtD,SAAO,SAAS,GAAG,MAAM,IAAI,IAAI,KAAK;AACxC;AAGA,SAAS,QAAQ,MAA0B;AACzC,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,KAAK;AAAA,IACnB,KAAK;AACH,aAAO,UAAU,KAAK,MAAM;AAAA,IAC9B,KAAK;AACH,aAAO,YAAY,KAAK,IAAI;AAAA,IAC9B,KAAK;AACH,aAAO,WAAW,KAAK,IAAI;AAAA,EAC/B;AACF;AAGA,SAAS,SAAS,OAAuB,MAAwC;AAC/E,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,KAAM,QAAO;AAC/B,QAAI,KAAK,SAAS,SAAS,KAAK,YAAY,KAAK,WAAW,GAAG,KAAK,IAAI,GAAG,GAAG;AAC5E,YAAM,MAAM,SAAS,KAAK,UAAU,IAAI;AACxC,UAAI,IAAK,QAAO;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AACT;AA+BO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,CAAC,UAAU,WAAW,IAAIC,WAAsB,oBAAI,IAAI,CAAC;AAC/D,QAAM,CAAC,cAAc,eAAe,IAAIA,WAAsB,oBAAI,IAAI,CAAC;AACvE,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAwB,IAAI;AACxD,QAAM,CAAC,aAAa,cAAc,IAAIA,WAA6B,IAAI;AACvE,QAAM,CAAC,aAAa,cAAc,IAAIA,WAA6B,IAAI;AACvE,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAwB,IAAI;AAC5D,QAAM,CAAC,MAAM,OAAO,IAAIA,WAAkC,IAAI;AAC9D,QAAM,CAAC,MAAM,OAAO,IAAIA,WAAS,KAAK;AACtC,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAS,KAAK;AACxD,QAAM,eAAeC,SAA8B,IAAI;AACvD,QAAM,WAAWA,SAAoB,IAAI;AAEzC,yBAAuB,MAAM;AAC3B,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAAY;AAC9E,UAAM,QAAQ,OAAO,WAAW,mBAAmB;AACnD,UAAM,SAAS,MAAM,iBAAiB,MAAM,OAAO;AACnD,WAAO;AACP,QAAI,OAAO,MAAM,qBAAqB,YAAY;AAChD,YAAM,iBAAiB,UAAU,MAAM;AACvC,aAAO,MAAM,MAAM,oBAAoB,UAAU,MAAM;AAAA,IACzD;AACA,QAAI,OAAO,MAAM,gBAAgB,YAAY;AAC3C,YAAM,YAAY,MAAM;AACxB,aAAO,MAAM,MAAM,eAAe,MAAM;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,CAAC;AAIL,QAAM,SAAS,UAAU,gBAAgB;AAEzC,QAAM,SAASC;AAAA,IACb,OAAO,SAAiB;AACtB,YAAM,OAAO,SAAS,OAAO,MAAM,IAAI;AACvC,UAAI,QAAQ,KAAK,SAAS,SAAS,KAAK,aAAa,QAAW;AAC9D,wBAAgB,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,CAAC;AACjD,YAAI;AACF,gBAAM,OAAO,OAAO,IAAI;AAAA,QAC1B,UAAE;AACA,0BAAgB,CAAC,SAAS;AACxB,kBAAM,OAAO,IAAI,IAAI,IAAI;AACzB,iBAAK,OAAO,IAAI;AAChB,mBAAO;AAAA,UACT,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,OAAOA;AAAA,IACX,CAAC,SAAiB;AAChB,kBAAY,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,CAAC;AAC7C,WAAK,OAAO,IAAI;AAAA,IAClB;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,SAASA;AAAA,IACb,OAAO,SAAuB;AAC5B,UAAI,KAAK,SAAS,MAAO;AACzB,YAAM,SAAS,SAAS,IAAI,KAAK,IAAI;AACrC,kBAAY,CAAC,SAAS;AACpB,cAAM,OAAO,IAAI,IAAI,IAAI;AACzB,YAAI,OAAQ,MAAK,OAAO,KAAK,IAAI;AAAA,YAC5B,MAAK,IAAI,KAAK,IAAI;AACvB,eAAO;AAAA,MACT,CAAC;AACD,UAAI,CAAC,OAAQ,OAAM,OAAO,KAAK,IAAI;AAAA,IACrC;AAAA,IACA,CAAC,UAAU,MAAM;AAAA,EACnB;AAMA,QAAM,OAAO,OAAO,WAAW;AAC/B,QAAM,cAAcC,UAAQ,MAAM;AAChC,UAAM,QAAsB,CAAC;AAC7B,QAAI,eAAe,YAAY,WAAW,IAAI;AAC5C,YAAM,KAAK,EAAE,MAAM,UAAU,QAAQ,IAAI,MAAM,YAAY,MAAM,OAAO,EAAE,CAAC;AAAA,IAC7E;AACA,UAAM,OAAO,CAAC,OAAuB,UAAkB;AACrD,iBAAW,QAAQ,OAAO;AACxB,cAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,CAAC;AACxC,YAAI,KAAK,SAAS,SAAS,CAAC,SAAS,IAAI,KAAK,IAAI,EAAG;AACrD,YAAI,eAAe,YAAY,WAAW,KAAK,MAAM;AACnD,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,QAAQ,KAAK;AAAA,YACb,MAAM,YAAY;AAAA,YAClB,OAAO,QAAQ;AAAA,UACjB,CAAC;AAAA,QACH;AACA,cAAM,YAAY,KAAK,aAAa,UAAa,KAAK,SAAS,WAAW;AAC1E,cAAM,YAAY,aAAa,IAAI,KAAK,IAAI,KAAK,OAAO,eAAe,IAAI,KAAK,IAAI;AAGpF,YAAI,KAAK,aAAa,aAAa,QAAQ,CAAC,WAAW;AACrD,gBAAM,KAAK,EAAE,MAAM,WAAW,MAAM,KAAK,MAAM,OAAO,QAAQ,EAAE,CAAC;AAAA,QACnE,WAAW,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;AACpD,eAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,QAC/B,WAAW,aAAa,WAAW;AACjC,gBAAM,KAAK,EAAE,MAAM,YAAY,MAAM,KAAK,MAAM,OAAO,QAAQ,EAAE,CAAC;AAAA,QACpE;AAAA,MACF;AAAA,IACF;AACA,SAAK,OAAO,MAAM,CAAC;AACnB,WAAO;AAAA,EACT,GAAG,CAAC,OAAO,MAAM,UAAU,aAAa,cAAc,OAAO,gBAAgB,IAAI,CAAC;AAGlF,QAAM,WAAWA;AAAA,IACf,MACE,YAAY;AAAA,MAAQ,CAAC,SACnB,KAAK,SAAS,SAAS,CAAC,EAAE,MAAM,KAAK,MAAM,OAAO,KAAK,MAAM,CAAC,IAAI,CAAC;AAAA,IACrE;AAAA,IACF,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,mBAAmB;AAEzB,QAAM,YAAYD;AAAA,IAChB,OAAO,SAAuB;AAC5B,UAAI,CAAC,iBAAkB;AACvB,YAAM,YAAY,KAAK,SAAS;AAChC,YAAM,YACJ,kBACC,CAAC,MACA,OAAO,WAAW,eAAe,OAAO,OAAO,YAAY,aACvD,OAAO;AAAA,QACL,UAAU,EAAE,SAAS,QAAQ,WAAW,MAAM,KAAK,EAAE,IAAI,IAAI,YAAY,sBAAsB,EAAE;AAAA,MACnG,IACA;AACR,YAAM,KAAK,MAAM,UAAU,IAAI;AAC/B,UAAI,CAAC,GAAI;AACT,cAAQ,IAAI;AACZ,UAAI;AACF,cAAM,OAAO,YAAY,KAAK,MAAM,SAAS;AAAA,MAC/C,QAAQ;AAAA,MAER,UAAE;AACA,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,eAAe,MAAM;AAAA,EAC1C;AAEA,QAAM,eAAeA;AAAA,IACnB,OAAO,SAAiB;AACtB,YAAM,QAAQ;AACd,qBAAe,IAAI;AACnB,UAAI,CAAC,SAAS,CAAC,iBAAkB;AACjC,YAAM,UAAU,KAAK,KAAK,EAAE,QAAQ,QAAQ,EAAE;AAC9C,UAAI,CAAC,QAAS;AACd,YAAM,OAAO,SAAS,MAAM,QAAQ,OAAO;AAC3C,cAAQ,IAAI;AACZ,UAAI;AACF,YAAI,MAAM,SAAS,OAAO;AACxB,gBAAM,OAAO,UAAU,IAAI;AAC3B,eAAK,IAAI;AAAA,QACX,OAAO;AACL,gBAAM,OAAO,WAAW,IAAI;AAE5B,oBAAU,IAAI;AACd,yBAAe,IAAI;AAAA,QACrB;AAAA,MACF,QAAQ;AAAA,MAER,UAAE;AACA,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA,IACA,CAAC,aAAa,kBAAkB,QAAQ,MAAM,YAAY;AAAA,EAC5D;AAEA,QAAM,eAAeA;AAAA,IACnB,OAAO,SAAiB;AACtB,YAAM,QAAQ;AACd,qBAAe,IAAI;AACnB,UAAI,CAAC,SAAS,CAAC,iBAAkB;AACjC,YAAM,OAAO,SAAS,OAAO,MAAM,MAAM,IAAI;AAC7C,YAAM,UAAU,KAAK,KAAK,EAAE,QAAQ,QAAQ,EAAE;AAC9C,UAAI,CAAC,QAAQ,CAAC,WAAW,YAAY,KAAK,KAAM;AAChD,YAAM,UAAU,SAASH,UAAS,MAAM,IAAI,GAAG,OAAO;AACtD,cAAQ,IAAI;AACZ,UAAI;AACF,cAAM,OAAO,UAAU,MAAM,MAAM,OAAO;AAC1C,YAAI,KAAK,SAAS,WAAW,iBAAiB,MAAM,QAAQ,WAAW,MAAM,OAAO;AAClF,oBAAU,OAAO;AACjB,yBAAe,OAAO;AAAA,QACxB;AAAA,MACF,QAAQ;AAAA,MAER,UAAE;AACA,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA,IACA,CAAC,aAAa,kBAAkB,QAAQ,cAAc,QAAQ,YAAY;AAAA,EAC5E;AAGA,QAAM,cAAcG;AAAA,IAClB,CAAC,SAAyB;AACxB,UAAI,CAAC,iBAAkB;AACvB,YAAM,SAAS,SAAS,SAAS,OAAO,MAAM,MAAM,IAAI;AACxD,YAAM,SAAS,SAAU,OAAO,SAAS,QAAQ,OAAO,OAAOH,UAAS,OAAO,IAAI,IAAK;AACxF,UAAI,OAAQ,MAAK,MAAM;AACvB,qBAAe,IAAI;AACnB,cAAQ,IAAI;AACZ,qBAAe,EAAE,QAAQ,KAAK,CAAC;AAAA,IACjC;AAAA,IACA,CAAC,kBAAkB,QAAQ,OAAO,MAAM,IAAI;AAAA,EAC9C;AAEA,QAAM,cAAcG;AAAA,IAClB,CAAC,SAAuB;AACtB,UAAI,CAAC,iBAAkB;AACvB,qBAAe,IAAI;AACnB,cAAQ,IAAI;AACZ,qBAAe,EAAE,MAAM,KAAK,KAAK,CAAC;AAAA,IACpC;AAAA,IACA,CAAC,gBAAgB;AAAA,EACnB;AAGA,QAAM,aAAaA;AAAA,IACjB,OAAO,WAAmB,eAAuB;AAC/C,kBAAY,IAAI;AAChB,UAAI,CAAC,oBAAoB,CAAC,WAAY;AACtC,YAAM,MAAM,SAAS,OAAO,MAAM,UAAU;AAC5C,UAAI,CAAC,IAAK;AAEV,UAAIH,UAAS,UAAU,MAAM,UAAW;AACxC,UAAI,cAAc,cAAc,UAAU,WAAW,GAAG,UAAU,GAAG,EAAG;AACxE,YAAM,UAAU,SAAS,WAAW,IAAI,IAAI;AAC5C,UAAI,YAAY,WAAY;AAC5B,cAAQ,IAAI;AACZ,UAAI;AACF,cAAM,OAAO,UAAU,YAAY,OAAO;AAC1C,YAAI,IAAI,SAAS,WAAW,iBAAiB,cAAc,WAAW,aAAa;AACjF,oBAAU,OAAO;AACjB,yBAAe,OAAO;AAAA,QACxB;AAAA,MACF,QAAQ;AAAA,MAER,UAAE;AACA,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,QAAQ,cAAc,QAAQ,YAAY;AAAA,EAC/D;AAEA,QAAM,YAAYG;AAAA,IAChB,CAAC,MAA0C;AACzC,UAAI,eAAe,YAAa;AAChC,UAAI,SAAS,WAAW,EAAG;AAC3B,YAAM,MAAM,SAAS,UAAU,CAAC,MAAM,EAAE,KAAK,SAAS,MAAM;AAC5D,YAAM,OAAO,CAAC,SAAiB;AAC7B,cAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,SAAS,GAAG,IAAI,CAAC;AAC/D,cAAM,MAAM,SAAS,OAAO;AAC5B,YAAI,IAAK,WAAU,IAAI,KAAK,IAAI;AAChC,UAAE,eAAe;AAAA,MACnB;AACA,YAAM,MAAM,OAAO,IAAI,SAAS,GAAG,IAAI;AACvC,cAAQ,EAAE,KAAK;AAAA,QACb,KAAK;AACH,eAAK,MAAM,IAAI,IAAI,MAAM,CAAC;AAC1B;AAAA,QACF,KAAK;AACH,eAAK,MAAM,IAAI,IAAI,MAAM,CAAC;AAC1B;AAAA,QACF,KAAK;AACH,cAAI,KAAK,KAAK,SAAS,OAAO;AAC5B,gBAAI,CAAC,SAAS,IAAI,IAAI,KAAK,IAAI,EAAG,MAAK,IAAI,KAAK,IAAI;AAAA,gBAC/C,MAAK,MAAM,CAAC;AACjB,cAAE,eAAe;AAAA,UACnB;AACA;AAAA,QACF,KAAK;AACH,cAAI,KAAK;AACP,gBAAI,IAAI,KAAK,SAAS,SAAS,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG;AAC1D,0BAAY,CAAC,SAAS;AACpB,sBAAM,IAAI,IAAI,IAAI,IAAI;AACtB,kBAAE,OAAO,IAAI,KAAK,IAAI;AACtB,uBAAO;AAAA,cACT,CAAC;AAAA,YACH,OAAO;AACL,oBAAM,SAASH,UAAS,IAAI,KAAK,IAAI;AACrC,kBAAI,OAAQ,WAAU,MAAM;AAAA,YAC9B;AACA,cAAE,eAAe;AAAA,UACnB;AACA;AAAA,QACF,KAAK;AACH,cAAI,KAAK;AACP,gBAAI,IAAI,KAAK,SAAS,MAAO,MAAK,OAAO,IAAI,IAAI;AAAA,gBAC5C,gBAAe,IAAI,KAAK,IAAI;AACjC,cAAE,eAAe;AAAA,UACnB;AACA;AAAA,QACF,KAAK;AACH,cAAI,KAAK;AACP,wBAAY,IAAI,IAAI;AACpB,cAAE,eAAe;AAAA,UACnB;AACA;AAAA,QACF,KAAK;AAAA,QACL,KAAK;AACH,cAAI,OAAO,kBAAkB;AAC3B,iBAAK,UAAU,IAAI,IAAI;AACvB,cAAE,eAAe;AAAA,UACnB;AACA;AAAA,MACJ;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,EAAAF,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,MAAM,QAAQ,IAAI;AAChC,WAAO,iBAAiB,SAAS,KAAK;AACtC,WAAO,iBAAiB,UAAU,OAAO,IAAI;AAC7C,WAAO,iBAAiB,UAAU,KAAK;AACvC,WAAO,MAAM;AACX,aAAO,oBAAoB,SAAS,KAAK;AACzC,aAAO,oBAAoB,UAAU,OAAO,IAAI;AAChD,aAAO,oBAAoB,UAAU,KAAK;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,iBAAiB,OAAO,SAAS,OAAO,KAAK,WAAW,KAAK,CAAC;AACpE,QAAM,YAAY,CAAC,OAAO,WAAW,OAAO,KAAK,WAAW,KAAK,CAAC;AAClE,QAAM,cAAc,oBAAoB,QAAQ,OAAO,KAAK,KAAK,OAAO;AAIxE,QAAM,gBAAgB,CAAC,MAAoB,UAA6B;AACtE,UAAM,SAAS,SAAS,IAAI,KAAK,IAAI;AACrC,QAAI,YAAY;AACd,aAAO,gBAAAF,MAAC,SAAK,qBAAW,MAAM,OAAO,MAAM,GAAE;AAAA,IAC/C;AACA,UAAM,QAAQ,KAAK,SAAS;AAC5B,UAAM,aAAa,KAAK,SAAS,gBAAgB,KAAK,SAAS;AAC/D,UAAM,WAAW,KAAK,SAAS;AAC/B,UAAM,YAAY,aAAa,IAAI,KAAK,IAAI,KAAK,OAAO,eAAe,IAAI,KAAK,IAAI;AACpF,UAAM,aAAa,aAAa,SAAS,KAAK;AAC9C,UAAM,eAAe,cAAc,QAAQ,KAAK,OAAOI,UAAS,KAAK,IAAI;AACzE,UAAM,UAAU,QAAQ,KAAK,OAAOA,UAAS,KAAK,IAAI;AAEtD,WACE,gBAAAJ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAe,QAAQ,SAAS;AAAA,QAChC,iBAAe,YAAY;AAAA,QAC3B,aAAW,aAAa;AAAA,QACxB,YACE,mBACI,CAAC,MAAM;AACL,YAAE,eAAe;AACjB,YAAE,aAAa,aAAa;AAC5B,sBAAY,OAAO;AAAA,QACrB,IACA;AAAA,QAEN,aACE,mBACI,CAAC,MAAM;AACL,YAAE,gBAAgB;AAClB,sBAAY,CAAC,QAAS,QAAQ,UAAU,OAAO,GAAI;AAAA,QACrD,IACA;AAAA,QAEN,QACE,mBACI,CAAC,MAAM;AACL,YAAE,eAAe;AACjB,YAAE,gBAAgB;AAClB,gBAAM,MAAM,EAAE,aAAa,QAAQ,cAAc;AACjD,eAAK,WAAW,SAAS,GAAG;AAAA,QAC9B,IACA;AAAA,QAGL,uBACC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,MAAM,KAAK;AAAA,YACX,cAAc,KAAK;AAAA,YACnB,UAAU,CAAC,SAAS,KAAK,aAAa,IAAI;AAAA,YAC1C,UAAU,MAAM,eAAe,IAAI;AAAA;AAAA,QACrC,IAEA,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAW,oBAAoB;AAAA,YAC/B,aACE,mBACI,CAAC,MAAM;AACL,gBAAE,aAAa,QAAQ,gBAAgB,KAAK,IAAI;AAChD,gBAAE,aAAa,gBAAgB;AAAA,YACjC,IACA;AAAA,YAEN,SAAS,MAAM;AACb,wBAAU,KAAK,IAAI;AACnB,kBAAI,MAAO,MAAK,OAAO,IAAI;AAAA,kBACtB,gBAAe,KAAK,IAAI;AAAA,YAC/B;AAAA,YACA,eAAe,MAAM,oBAAoB,YAAY,IAAI;AAAA,YACzD,eAAe,CAAC,MAAM;AACpB,kBAAI,CAAC,iBAAkB;AACvB,gBAAE,eAAe;AACjB,wBAAU,KAAK,IAAI;AACnB,sBAAQ,EAAE,MAAM,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC;AAAA,YAC9C;AAAA,YACA,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,gBAAgB;AAAA;AAAA,cAEhB,aACE;AAAA,cACF,KAAK,SAAS,YAAY,KAAK,MAAM,IAAI;AAAA,YAC3C;AAAA,YACA,OAAO,EAAE,aAAa,GAAG,QAAQ,KAAK,CAAC,KAAK;AAAA,YAE3C;AAAA,sBACC,gBAAAD;AAAA,gBAACS;AAAA,gBAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACA,UAAU;AAAA,oBACV,aAAa;AAAA,kBACf;AAAA;AAAA,cACF,IAEA,gBAAAT,MAAC,UAAK,WAAU,6BAA4B;AAAA,cAE7C,QACC,gBAAAA,MAAC,cAAW,WAAU,qBAAoB,IAE1C,gBAAAA,MAACU,WAAA,EAAS,WAAU,qBAAoB;AAAA,cAE1C,gBAAAV,MAAC,UAAK,WAAU,YAAY,eAAK,MAAK;AAAA,cACrC,oBACC,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,UAAU;AAAA,kBACV,cAAW;AAAA,kBACX,SAAS,CAAC,MAAM;AACd,sBAAE,eAAe;AACjB,sBAAE,gBAAgB;AAClB,8BAAU,KAAK,IAAI;AACnB,0BAAM,OAAQ,EAAE,cAA8B,sBAAsB;AACpE,4BAAQ,EAAE,MAAM,GAAG,KAAK,OAAO,GAAG,KAAK,OAAO,CAAC;AAAA,kBACjD;AAAA,kBACA,WAAU;AAAA,kBACX;AAAA;AAAA,cAED;AAAA;AAAA;AAAA,QAEJ;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAGA,QAAM,aAAa,CAAC,SAAgC;AAClD,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO,cAAc,KAAK,MAAM,KAAK,KAAK;AAAA,MAC5C,KAAK;AACH,eACE,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,KAAK;AAAA,YACZ,MAAM,KAAK;AAAA,YACX,cAAa;AAAA,YACb,UAAU,CAAC,SAAS,KAAK,aAAa,IAAI;AAAA,YAC1C,UAAU,MAAM,eAAe,IAAI;AAAA;AAAA,QACrC;AAAA,MAEJ,KAAK;AACH,eACE,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,eAAW;AAAA,YACX,OAAO,EAAE,aAAa,GAAG,KAAK,QAAQ,KAAK,CAAC,KAAK;AAAA,YACjD,WAAU;AAAA,YAET,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MACd,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAU;AAAA,gBACV,OAAO,EAAE,OAAO,GAAG,KAAK,IAAI,EAAE,IAAI;AAAA;AAAA,cAF7B;AAAA,YAGP,CACD;AAAA;AAAA,QACH;AAAA,MAEJ,KAAK;AACH,eACE,gBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,EAAE,aAAa,GAAG,KAAK,QAAQ,KAAK,CAAC,KAAK;AAAA,YACjD,WAAU;AAAA,YAEV;AAAA,8BAAAD,MAAC,UAAK,WAAU,6BAA4B;AAAA,cAC5C,gBAAAA,MAAC,UAAK,WAAU,oBAAmB,uDAAoC;AAAA;AAAA;AAAA,QACzE;AAAA,IAEN;AAAA,EACF;AAGA,EAAAE,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,YAAY,UAAU,CAAC,OAAO,GAAG,SAAS,UAAU,GAAG,KAAK,SAAS,MAAM;AACzF,QAAI,SAAS,EAAG,UAAS,SAAS,cAAc,KAAK;AAAA,EACvD,GAAG,CAAC,QAAQ,WAAW,CAAC;AAExB,SACE,gBAAAD,OAAC,SAAI,WAAW,GAAG,iCAAiC,SAAS,GAC1D;AAAA,mBACC,gBAAAA,OAAC,SAAI,WAAU,oFACZ;AAAA,yBACC,gBAAAA,OAAAF,WAAA,EACE;AAAA,wBAAAC,MAAC,iBAAc,OAAM,YAAW,SAAS,MAAM,YAAY,MAAM,GAAG,UAAU,MAC5E,0BAAAA,MAAC,gBAAa,WAAU,YAAW,GACrC;AAAA,QACA,gBAAAA,MAAC,iBAAc,OAAM,cAAa,SAAS,MAAM,YAAY,KAAK,GAAG,UAAU,MAC7E,0BAAAA,MAAC,kBAAe,WAAU,YAAW,GACvC;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,SAAS,MAAM;AACb,oBAAM,OAAO,SAAS,SAAS,OAAO,MAAM,MAAM,IAAI;AACtD,kBAAI,KAAM,aAAY,IAAI;AAAA,YAC5B;AAAA,YACA,UAAU,QAAQ,CAAC;AAAA,YAEnB,0BAAAA,MAAC,cAAW,WAAU,YAAW;AAAA;AAAA,QACnC;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,SAAS,MAAM;AACb,oBAAM,OAAO,SAAS,SAAS,OAAO,MAAM,MAAM,IAAI;AACtD,kBAAI,KAAM,MAAK,UAAU,IAAI;AAAA,YAC/B;AAAA,YACA,UAAU,QAAQ,CAAC;AAAA,YAEnB,0BAAAA,MAACW,aAAA,EAAW,WAAU,YAAW;AAAA;AAAA,QACnC;AAAA,SACF,IACE;AAAA,MACJ,gBAAAX,MAAC,UAAK,WAAU,WAAU;AAAA,MAC1B,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,SAAS,MAAM,KAAK,OAAO,QAAQ;AAAA,UACnC,UAAU,QAAQ,OAAO;AAAA,UAEzB,0BAAAA,MAACY,gBAAA,EAAc,WAAW,GAAG,YAAY,OAAO,WAAW,cAAc,GAAG;AAAA;AAAA,MAC9E;AAAA,OACF;AAAA,IAKF,gBAAAZ;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,UAAU;AAAA,QACV,wBAAsB;AAAA,QACtB;AAAA,QACA,YACE,mBACI,CAAC,MAAM;AACL,YAAE,eAAe;AACjB,YAAE,aAAa,aAAa;AAC5B,sBAAY,EAAE;AAAA,QAChB,IACA;AAAA,QAEN,QACE,mBACI,CAAC,MAAM;AACL,YAAE,eAAe;AACjB,gBAAM,MAAM,EAAE,aAAa,QAAQ,cAAc;AACjD,eAAK,WAAW,IAAI,GAAG;AAAA,QACzB,IACA;AAAA,QAEN,WAAW;AAAA,UACT;AAAA,UACA,aAAa,MAAM;AAAA,QACrB;AAAA,QACA,2BAAuB;AAAA,QAEtB,2BACC,gBAAAC,OAAC,SAAI,WAAU,oEACb;AAAA,0BAAAD,MAAC,SACE,sBACC,yBAAyB,OAAO,OAAO,WAAW,oCAAoC,IAC1F;AAAA,UACA,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,KAAK,OAAO,QAAQ;AAAA,cACnC,UAAU,OAAO;AAAA,cACjB,WAAU;AAAA,cAEV;AAAA,gCAAAD;AAAA,kBAACY;AAAA,kBAAA;AAAA,oBACC,WAAW,GAAG,YAAY,OAAO,WAAW,cAAc;AAAA,oBAC1D,eAAW;AAAA;AAAA,gBACb;AAAA,gBAAE;AAAA;AAAA;AAAA,UAEJ;AAAA,WACF,IACE,YACF,gBAAAZ,MAAC,SAAI,WAAU,oCACZ,wBAAc,2BACjB;AAAA;AAAA;AAAA;AAAA,UAKA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,WAAU;AAAA,cACV,UAAU,gBAAgB,KAAK;AAAA,cAC/B,UAAU,KAAK,IAAI,IAAI,YAAY,MAAM;AAAA,cAExC,sBAAY,IAAI,CAAC,SAChB,gBAAAA,MAAC,SAAwB,WAAU,WAChC,qBAAW,IAAI,KADR,QAAQ,IAAI,CAEtB,CACD;AAAA;AAAA,UACH;AAAA;AAAA;AAAA,IAEJ;AAAA,IAEC,QAAQ,KAAK,QACZ,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,KAAK;AAAA,QACX,GAAG,KAAK;AAAA,QACR,GAAG,KAAK;AAAA,QACR,UAAU,MAAM,KAAK,QAAQ,YAAY,KAAK,IAAI;AAAA,QAClD,UAAU,MAAM,KAAK,QAAQ,KAAK,UAAU,KAAK,IAAI;AAAA,QACrD,WAAW,MAAM,YAAY,MAAM;AAAA,QACnC,aAAa,MAAM,YAAY,KAAK;AAAA;AAAA,IACtC;AAAA,KAEJ;AAEJ;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,OAAO;AAAA,MACP,cAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAGA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,CAAC,OAAO,QAAQ,IAAIK,WAAS,YAAY;AAC/C,QAAM,MAAMC,SAAgC,IAAI;AAEhD,QAAM,UAAUA,SAAO,KAAK;AAE5B,EAAAJ,YAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,OAAG,MAAM;AAET,UAAM,MAAM,aAAa,YAAY,GAAG;AACxC,QAAI,gBAAgB,MAAM,EAAG,IAAG,kBAAkB,GAAG,GAAG;AAAA,QACnD,IAAG,OAAO;AAAA,EACjB,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,SAAS,CAAC,WAAoB;AAClC,QAAI,QAAQ,QAAS;AACrB,YAAQ,UAAU;AAClB,QAAI,OAAQ,UAAS,KAAK;AAAA,QACrB,UAAS;AAAA,EAChB;AAEA,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO,EAAE,aAAa,GAAG,QAAQ,KAAK,CAAC,KAAK;AAAA,MAE5C;AAAA,wBAAAD,MAAC,UAAK,WAAU,6BAA4B;AAAA,QAC3C,SAAS,QACR,gBAAAA,MAAC,cAAW,WAAU,qBAAoB,IAE1C,gBAAAA,MAACU,WAAA,EAAS,WAAU,qBAAoB;AAAA,QAE1C,gBAAAV;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,YAAY;AAAA,YACZ,cAAa;AAAA,YACb,cAAY,SAAS,QAAQ,gBAAgB;AAAA,YAC7C,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,QAAQ,MAAM,OAAO,IAAI;AAAA,YACzB,WAAW,CAAC,MAAM;AAChB,kBAAI,EAAE,QAAQ,SAAS;AACrB,kBAAE,eAAe;AACjB,uBAAO,IAAI;AAAA,cACb,WAAW,EAAE,QAAQ,UAAU;AAC7B,kBAAE,eAAe;AACjB,uBAAO,KAAK;AAAA,cACd;AACA,gBAAE,gBAAgB;AAAA,YACpB;AAAA,YACA,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAGA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQG;AACD,QAAM,QAAQ,KAAK,SAAS;AAE5B,QAAM,KAAK,OAAO,WAAW,cAAc,OAAO,aAAa;AAC/D,QAAM,KAAK,OAAO,WAAW,cAAc,OAAO,cAAc;AAChE,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,GAAG;AACjC,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,GAAG;AAEhC,QAAM,OAAO,CAAC,OAAe,MAAiB,SAAqB,WACjE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,CAAC,MAAM;AACd,UAAE,gBAAgB;AAClB,gBAAQ;AAAA,MACV;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,SAAS,0BAA0B;AAAA,MACrC;AAAA,MAEC;AAAA;AAAA,QACA;AAAA;AAAA;AAAA,EACH;AAGF,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,CAAC,MAAM,EAAE,gBAAgB;AAAA,MAClC,OAAO,EAAE,MAAM,IAAI;AAAA,MACnB,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA,iBACC,gBAAAA,OAAAF,WAAA,EACG;AAAA,eAAK,YAAY,gBAAAC,MAAC,gBAAa,WAAU,YAAW,GAAI,SAAS;AAAA,UACjE,KAAK,cAAc,gBAAAA,MAAC,kBAAe,WAAU,YAAW,GAAI,WAAW;AAAA,UACxE,gBAAAA,MAAC,SAAI,WAAU,0BAAyB;AAAA,WAC1C;AAAA,QAED,KAAK,UAAU,gBAAAA,MAAC,cAAW,WAAU,YAAW,GAAI,QAAQ;AAAA,QAC5D,KAAK,UAAU,gBAAAA,MAACW,aAAA,EAAW,WAAU,YAAW,GAAI,UAAU,IAAI;AAAA;AAAA;AAAA,EACrE;AAEJ;;;AC75BM,gBAAAE,aAAA;AAXC,SAAS,SAAS;AAAA,EACvB;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AACF,GAAkB;AAChB,MAAI,KAAK,WAAW,GAAG;AACrB,WACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,oCAAoC,SAAS,GAC7D,yBAAe,SAAS,eAAe,0BAC1C;AAAA,EAEJ;AACA,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,MAC9C;AAAA;AAAA,EACF;AAEJ;;;ACnEA;AAAA,EAIE,QAAAC;AAAA,EACA,YAAAC;AAAA,EACA,aAAAC;AAAA,EACA,YAAAC;AAAA,OACK;AA4EuC,gBAAAC,aAAA;AAvC9C,IAAM,WAAWC,MAAK,YAAY;AAChC,QAAM,MAAO,MAAM,OAAO,qBAAqB;AAC/C,SAAO,EAAE,SAAS,IAAI,KAAK;AAC7B,CAAC;AAQM,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,CAAC,QAAQ,SAAS,IAAIC,WAAS,KAAK;AAI1C,EAAAC,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,SAAK,OAAO,qBAAqB,EAAE,MAAM,MAAM;AAC7C,UAAI,CAAC,UAAW,WAAU,IAAI;AAAA,IAChC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,OAAO,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAEtD,MAAI,QAAQ;AACV,WACE,gBAAAH,MAAC,SAAI,WAAuB,sBAAY,gBAAAA,MAAC,aAAU,MAAY,UAAoB,GAAG;AAAA,EAE1F;AAEA,QAAM,UAAU;AAAA,IACd,UAAU;AAAA,IACV,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,GAAI,QACA,EAAE,MAAM,IACR;AAAA,MACE,OAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACJ,WAAW,aAAa;AAAA,EAC1B;AAIA,QAAM,aAAa;AAAA,IACjB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,8BAA8B;AAAA,IAC9B,iCAAiC;AAAA,IACjC,qBAAqB;AAAA,IACrB,uBAAuB;AAAA,EACzB;AAEA,SACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,WAAW,SAAS,GAAG,6BAAyB,MAAC,OAAO,YACzE,0BAAAA,MAACI,WAAA,EAAS,UAAU,WAAW,gBAAAJ,MAAC,gBAAa,GAG3C,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB;AAAA,MACC,GAAI,sBAAsB,SAAY,EAAE,kBAAkB,IAAI,CAAC;AAAA;AAAA,EAClE,GACF,GACF;AAEJ;AAEA,SAAS,UAAU,EAAE,MAAM,SAAS,GAAuC;AACzE,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,aAAW;AAAA,MAEV;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,eAAe;AACtB,SAAO,gBAAAA,MAAC,SAAI,WAAU,oCAAmC,gCAAa;AACxE;;;AC9IA,SAAS,aAAa,gBAAgB;AACtC;AAAA,EAIE,QAAAK;AAAA,EACA,YAAAC;AAAA,EACA,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OACK;AA6Qc,gBAAAC,OAoBb,QAAAC,cApBa;AA1OrB,IAAM,mBAA2D;AAAA,EAC/D,YAAY,aACT,MAAM,OAAO,6BAA6B,GAAG,WAAW,EAAE,KAAK,MAAM,YAAY,KAAK,CAAC;AAAA,EAC1F,MAAM,aAAa,MAAM,OAAO,uBAAuB,GAAG,KAAK;AAAA,EAC/D,QAAQ,aAAa,MAAM,OAAO,yBAAyB,GAAG,OAAO;AAAA,EACrE,UAAU,aAAa,MAAM,OAAO,2BAA2B,GAAG,SAAS;AAAA,EAC3E,KAAK,aAAa,MAAM,OAAO,sBAAsB,GAAG,IAAI;AAAA,EAC5D,MAAM,aAAa,MAAM,OAAO,uBAAuB,GAAG,KAAK;AACjE;AAGO,SAAS,gBAAgB,MAAoD;AAClF,QAAM,OAAO,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AACtC,QAAM,MAAM,KAAK,SAAS,GAAG,KAAK,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI,YAAY,IAAI;AAC/E,UAAQ,KAAK;AAAA,IACX,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,IAAM,iBAAiBC,MAAK,YAAY;AACtC,QAAM,MAAO,MAAM,OAAO,uBAAuB;AAGjD,SAAO,EAAE,SAAS,IAAI,QAAQ;AAChC,CAAC;AAmCM,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,CAAC,QAAQ,SAAS,IAAIC,WAAS,KAAK;AAC1C,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAA8B,IAAI;AAK9D,QAAM,CAAC,OAAO,QAAQ,IAAIA,WAAS,eAAe;AAClD,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,eAAe;AACxD,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAAS,KAAK;AAC1C,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAuB,IAAI;AAC7D,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,KAAK;AAEhD,QAAM,QAAQ,UAAU;AAMxB,QAAM,qBAAqBC,SAAO,KAAK;AACvC,QAAM,WAAWA,SAA2C,EAAE,MAAM,UAAU,gBAAgB,CAAC;AAC/F,EAAAC,YAAU,MAAM;AACd,UAAM,cACJ,SAAS,QAAQ,SAAS,QAAQ,SAAS,QAAQ,aAAa;AAClE,QAAI,CAAC,YAAa;AAClB,aAAS,UAAU,EAAE,MAAM,UAAU,gBAAgB;AACrD,uBAAmB,UAAU;AAC7B,aAAS,eAAe;AACxB,gBAAY,eAAe;AAC3B,iBAAa,IAAI;AACjB,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAC,MAAM,eAAe,CAAC;AAI1B,QAAM,WAAWC;AAAA,IACf,CAAC,SAAiB;AAChB,eAAS,IAAI;AACb,mBAAa,KAAK;AAClB,UAAI,CAAC,mBAAmB,WAAW,SAAS,UAAU;AACpD,2BAAmB,UAAU;AAC7B,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,IACA,CAAC,UAAU,YAAY;AAAA,EACzB;AAIA,QAAM,UAAUC,UAAQ,MAAM,gBAAgB,IAAI,GAAG,CAAC,IAAI,CAAC;AAC3D,EAAAF,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,QAAS,MAAM,OAAO,uBAAuB;AAKnD,cAAM,oBAAoB,UAAU,MAAM,iBAAiB,OAAO,IAAI,IAAI;AAC1E,YAAI,UAAW;AAIf,cAAM,sBAAsB,CAAC,QAC3B,MAAM,KAAK;AAAA,UACT,MAAM,OAAO,GAAG;AAAA,YACd;AAAA,cACE,KAAK;AAAA,cACL,gBAAgB;AAAA,cAChB,KAAK,MAAM;AACT,oBAAI;AACJ,uBAAO;AAAA,cACT;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AACF,kBAAU;AAAA,UACR,QAAQ,MAAM;AAAA,UACd;AAAA,UACA,mBAAmB,qBAAqB;AAAA,QAC1C,CAAC;AAAA,MACH,QAAQ;AACN,YAAI,CAAC,UAAW,WAAU,IAAI;AAAA,MAChC;AAAA,IACF,GAAG;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAGZ,QAAM,UAAUD,SAAmB,MAAM;AAAA,EAAC,CAAC;AAE3C,QAAM,OAAOE,cAAY,YAAY;AACnC,QAAI,SAAU;AAEd,UAAM,WAAW;AACjB,QAAI,aAAa,SAAU;AAC3B,cAAU,IAAI;AACd,iBAAa,IAAI;AACjB,iBAAa,KAAK;AAClB,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,kBAAY,QAAQ;AACpB,eAAS,UAAU,EAAE,MAAM,UAAU,SAAS;AAC9C,mBAAa,IAAI;AAAA,IACnB,SAAS,OAAO;AACd,mBAAa,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,IACxE,UAAE;AACA,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,UAAU,OAAO,UAAU,QAAQ,IAAI,CAAC;AAE5C,UAAQ,UAAU,MAAM;AACtB,SAAK,KAAK;AAAA,EACZ;AAGA,EAAAD,YAAU,MAAM;AACd,QAAI,CAAC,UAAW;AAChB,UAAM,IAAI,WAAW,MAAM,aAAa,KAAK,GAAG,IAAI;AACpD,WAAO,MAAM,aAAa,CAAC;AAAA,EAC7B,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK;AAE1D,QAAM,eAAeE,UAAQ,MAAM;AACjC,QAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,UAAM,OAAkB,CAAC,OAAO,oBAAoB,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAC5E,QAAI,OAAO,kBAAmB,MAAK,KAAK,OAAO,iBAAiB;AAChE,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,QAAQ;AACV,WACE,gBAAAP,MAAC,SAAI,WAAW,GAAG,gCAAgC,SAAS,GACzD,sBAAY,gBAAAA,MAAC,iBAAc,OAAc,UAAoB,UAAU,UAAU,GACpF;AAAA,EAEJ;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,gCAAgC,SAAS;AAAA,MACvD,6BAAyB;AAAA,MACzB,OAAO;AAAA,MAGP;AAAA,wBAAAA,OAAC,SAAI,WAAU,wFACb;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,WAAW,mBAAmB,QAAQ,yBAAyB;AAAA,cACjE;AAAA,cACA,OAAO,WAAW,cAAc,QAAQ,oBAAoB;AAAA;AAAA,UAC9D;AAAA,UACA,gBAAAC,OAAC,UAAK,WAAU,qDACb;AAAA;AAAA,YACA,SAAS,CAAC,WAAW,YAAO;AAAA,aAC/B;AAAA,UACA,gBAAAA,OAAC,SAAI,WAAU,4CACZ;AAAA,yBACC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO,UAAU;AAAA,gBAEhB,oBAAU;AAAA;AAAA,YACb;AAAA,YAED,CAAC,aAAa,aAAa,gBAAAA,MAAC,UAAK,WAAU,kCAAiC,mBAAK;AAAA,YACjF,WACC,gBAAAA,MAAC,UAAK,WAAU,wDAAuD,uBAAS,IAEhF,gBAAAC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,KAAK,KAAK;AAAA,gBACzB,UAAU,UAAU,CAAC;AAAA,gBACrB,WAAW;AAAA,kBACT;AAAA,kBACA,UAAU,CAAC,QACP,gDACA;AAAA,gBACN;AAAA,gBACA,OAAM;AAAA,gBAEL;AAAA,2BACC,gBAAAD,MAAC,eAAY,WAAU,uBAAsB,IAE7C,gBAAAA,MAAC,YAAS,WAAU,UAAS;AAAA,kBAC7B;AAAA;AAAA;AAAA,YAEJ;AAAA,aAEJ;AAAA,WACF;AAAA,QAGA,gBAAAA,MAAC,SAAI,WAAU,gCACb,0BAAAA,MAACQ,WAAA,EAAS,UAAU,WAAW,gBAAAR,MAAC,kBAAe,GAC7C,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,OAAO,cAAc,UAAU,UAAU;AAAA,YACzC,UAAU,CAAC;AAAA,YACX;AAAA,YACA,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,QAAO;AAAA,YACP,WAAU;AAAA,YACV,UAAU,WAAW,SAAY;AAAA;AAAA,QACnC,GACF,GACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAGA,IAAM,aAAa;AAAA,EACjB,cAAc;AAAA,EACd,YAAY;AACd;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,MACxC,WAAU;AAAA;AAAA,EACZ;AAEJ;AAEA,SAAS,iBAAiB;AACxB,SAAO,gBAAAA,MAAC,SAAI,WAAU,oCAAmC,kCAAe;AAC1E;;;ACpYA,SAAyB,eAAAS,eAAa,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;AAsG9D,SA6EK,YAAAC,WA7EL,OAAAC,OAoCD,QAAAC,cApCC;AA/DJ,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA,sBAAsB;AAAA,EACtB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,CAAC,UAAU,WAAW,IAAIC,WAAwB,IAAI;AAG5D,QAAM,CAAC,UAAU,WAAW,IAAIA,WAAS,KAAK;AAK9C,QAAM,UAAUC,SAA8B,IAAI;AAClD,QAAM,CAAC,MAAM,OAAO,IAAID,WAAS,KAAK;AACtC,EAAAE,YAAU,MAAM;AACd,UAAM,KAAK,QAAQ;AACnB,QAAI,CAAC,MAAM,OAAO,mBAAmB,YAAa;AAClD,UAAM,WAAW,IAAI,eAAe,CAAC,YAAY;AAC/C,YAAM,IAAI,QAAQ,CAAC,GAAG,YAAY,SAAS;AAC3C,cAAQ,KAAK,GAAG;AAAA,IAClB,CAAC;AACD,aAAS,QAAQ,EAAE;AACnB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAIL,QAAM,gBAAgB,aAAa,SAAS;AAK5C,QAAM,WAAW;AACjB,QAAM,WAAW,YAAY,UAAU,MAAM,QAAQ;AAIrD,QAAM,aAAaC,cAAY,CAAC,SAAiB;AAC/C,gBAAY,IAAI;AAChB,gBAAY,KAAK;AAAA,EACnB,GAAG,CAAC,CAAC;AAML,QAAM,UACJ,YACA,aAAa,QACb,CAAC,SAAS,WACV,SAAS,UAAU,QACnB,CAAC,SAAS,YACV,CAAC,SAAS,aACV,SAAS,YAAY;AACvB,QAAM,aAAa,WAAW;AAE9B,MAAI,CAAC,qBAAqB;AACxB,WAAO,gBAAAL,MAAC,UAAO,WAAsB,yDAA2C;AAAA,EAClF;AAEA,SACE,gBAAAC,OAAC,SAAI,KAAK,SAAS,WAAW,GAAG,wCAAwC,SAAS,GAEhF;AAAA,oBAAAD,MAAC,aAAU,KAAU,YAAY,IAAI,KAAK,QAAQ;AAAA,IAElD,gBAAAC,OAAC,SAAI,WAAW,GAAG,uBAAuB,OAAO,aAAa,UAAU,GAGtE;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,OAAO,iDAAiD;AAAA,UAC1D;AAAA,UAEA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ;AAAA,cACR,cAAc,YAAY;AAAA,cAC1B,cAAc;AAAA,cACd;AAAA,cACA,YAAW;AAAA,cACX,WAAU;AAAA;AAAA,UACZ;AAAA;AAAA,MACF;AAAA,MAKA,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,OAAO,WAAW;AAAA,UACpB;AAAA,UAEA;AAAA,4BAAAA,OAAC,SAAI,WAAU,wGACb;AAAA,8BAAAD,MAAC,UAAK,WAAU,6DACb,sBAAY,oBACf;AAAA,cAIC,WACC,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAS;AAAA,oBACP,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,oBAC/B,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,kBACjC;AAAA,kBACA,OAAO,WAAW,SAAS;AAAA,kBAC3B,UAAU,CAAC,MAAM,YAAY,MAAM,MAAM;AAAA;AAAA,cAC3C;AAAA,eAEJ;AAAA,YACA,gBAAAA,MAAC,SAAI,WAAU,gCACZ,qBACC,cAAc,SAAS,YAAY,OACjC,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBAEC,MAAM;AAAA,gBACN,iBAAiB,SAAS;AAAA,gBAC1B,WAAW;AAAA,gBACX,QAAQ,CAAC,aAAa,MAAM,UAAU,UAAU,QAAQ;AAAA,gBACvD,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,gBACxC,WAAU;AAAA;AAAA,cANL;AAAA,YAOP,IACE,SAAS,QACX,gBAAAC,OAAC,UAAO;AAAA;AAAA,cACU;AAAA,cAAS;AAAA,cAAG,SAAS,MAAM;AAAA,eAC7C,IACE,SAAS,UACX,gBAAAA,OAAC,UAAO;AAAA;AAAA,cAAS;AAAA,cAAS;AAAA,eAAC,IACzB,SAAS,WACX,gBAAAA,OAAC,UACE;AAAA;AAAA,cAAS;AAAA,cAAoB,SAAS,aAAa;AAAA,cAAE;AAAA,eACxD,IACE,SAAS,YAAY,OACvB,gBAAAA,OAAAF,WAAA,EACG;AAAA,uBAAS,aACR,gBAAAE,OAAC,SAAI,WAAU,yFAAwF;AAAA;AAAA,gBAC1D,SAAS,aAAa;AAAA,gBAAE;AAAA,iBAErE;AAAA,cAED,YACC,gBAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAM;AAAA,kBACN,UAAU,SAAS;AAAA,kBACnB,WAAW;AAAA,kBACX,UACE,gBAAAA,MAAC,SAAI,WAAU,uEACZ,mBAAS,SACZ;AAAA,kBAEF,WAAU;AAAA;AAAA,cACZ,IAEA,gBAAAA,MAAC,SAAI,WAAU,uEACZ,mBAAS,SACZ;AAAA,eAEJ,IAEA,gBAAAC,OAAC,UAAO;AAAA;AAAA,cAAS;AAAA,cAAS;AAAA,eAAC;AAAA;AAAA,cAI7B,gBAAAD,MAAC,UAAO,mDAAqC;AAAA,eAEjD;AAAA;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,UAAU,EAAE,KAAK,WAAW,GAAqD;AACxF,QAAM,QAAQ,aAAa;AAC3B,SACE,gBAAAC,OAAC,SAAI,WAAU,mGACb;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,QAAQ,yBAAyB;AAAA,QACnC;AAAA,QACA,OAAO,QAAQ,GAAG,UAAU,aAAa;AAAA;AAAA,IAC3C;AAAA,IACA,gBAAAA,MAAC,UAAK,WAAU,oCACb,cAAI,WAAW,IAAI,SAAS,eAAe,YAC9C;AAAA,KACE,IAAI,QAAQ,KAAK,IAAI,SAAS,MAC9B,gBAAAC,OAAC,UAAK,WAAU,mEACb;AAAA,UAAI,QAAQ,KAAK,gBAAAA,OAAC,UAAK;AAAA;AAAA,QAAE,IAAI;AAAA,SAAM;AAAA,MACnC,IAAI,SAAS,KAAK,gBAAAA,OAAC,UAAK;AAAA;AAAA,QAAE,IAAI;AAAA,SAAO;AAAA,OACxC;AAAA,IAED,SACC,gBAAAA,OAAC,UAAK,WAAU,iDAAiD;AAAA;AAAA,MAAW;AAAA,OAAQ;AAAA,KAExF;AAEJ;AAEA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,gBAAAD,MAAC,SAAI,WAAU,2EACZ,kBAAQ,IAAI,CAAC,QACZ,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,SAAS,IAAI,KAAK;AAAA,MACjC,WAAW;AAAA,QACT;AAAA,QACA,IAAI,UAAU,QACV,iCACA;AAAA,MACN;AAAA,MAEC,cAAI;AAAA;AAAA,IAVA,IAAI;AAAA,EAWX,CACD,GACH;AAEJ;AAoBA,SAAS,YACP,MACA,UACe;AACf,QAAM,CAAC,OAAO,QAAQ,IAAIE,WAAwB;AAAA,IAChD,SAAS;AAAA,IACT,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO;AAAA,EACT,CAAC;AACD,EAAAE,YAAU,MAAM;AACd,QAAI,CAAC,MAAM;AACT,eAAS;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,QACX,WAAW;AAAA,QACX,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AACA,QAAI,YAAY;AAChB,aAAS;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,MACX,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA,IACT,CAAC;AACD,SAAK,SAAS,IAAI,EACf,KAAK,CAAC,QAAQ;AACb,UAAI,UAAW;AACf,YAAM,UAAU,IAAI,WAChB,OACA,IAAI,aAAa,WACf,iBAAiB,IAAI,OAAO,IAC5B,IAAI;AACV,eAAS;AAAA,QACP;AAAA,QACA,UAAU,IAAI;AAAA,QACd,WAAW,IAAI;AAAA,QACf,WAAW,IAAI;AAAA,QACf,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AAAA,IACH,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,UAAI,UAAW;AACf,eAAS;AAAA,QACP,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,QACX,WAAW;AAAA,QACX,SAAS;AAAA,QACT,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,MACjE,CAAC;AAAA,IACH,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,CAAC;AACnB,SAAO;AACT;AAGA,SAAS,iBAAiB,KAAqB;AAC7C,MAAI;AACF,QAAI,OAAO,SAAS,YAAY;AAC9B,YAAM,SAAS,KAAK,GAAG;AACvB,YAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,OAAM,CAAC,IAAI,OAAO,WAAW,CAAC;AACtE,aAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AAAA,IACvC;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,OAAO,EAAE,UAAU,UAAU,GAA4D;AAChG,SACE,gBAAAJ;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;;;AC/XA,SAAS,oBAAAM,mBAAkB,aAAa,uBAAuB,mBAAmB;AAClF,SAAyB,aAAAC,aAAW,UAAAC,UAAQ,YAAAC,kBAAgB;AAsWpD,gBAAAC,OA4DE,QAAAC,cA5DF;AAhRR,IAAM,2BAA2B;AAIjC,SAAS,kBAAkB,QAAqD;AAC9E,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AAEE,aAAO;AAAA,EACX;AACF;AAqBO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB;AACF,GAAuB;AACrB,QAAM,eAAeC,SAA8B,IAAI;AACvD,QAAM,CAAC,WAAW,YAAY,IAAIC,WAAS,KAAK;AAIhD,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAS,eAAe,KAAK;AACnE,QAAM,uBAAuB,gBAAgB;AAC7C,QAAM,sBAAsB,YAAY,SAAS;AACjD,QAAM,cAAc,uBAAuB,cAAc;AACzD,QAAM,YAAY,QAAQ,WAAW,KAAK;AAK1C,QAAM,aAAa,YAAY;AAG/B,QAAM,gBAAgB,CAAC,cAAc,WAAW,cAAc;AAC9D,QAAM,SAAS,YAAY,UAAU;AACrC,QAAM,WACJ,YAAY,2BAA2B,QAAQ,WAAW,iBAAiB,QAAQ,CAAC;AAEtF,QAAM,gBAAgB,QAAQ,UAAU,KAAK,CAAC,iBAAiB,CAAC,WAAY;AAI5E,QAAM,eACH,iBAAiB,WAAW,gBAAkB,CAAC,iBAAiB;AAEnE,QAAM,kBAAkB,iBAAiB,kBAAkB,MAAM;AAEjE,QAAM,SAAS,MAAM;AACnB,iBAAa,IAAI;AACjB,oBAAgB;AAAA,EAClB;AAcA,EAAAC,YAAU,MAAM;AACd,QAAI,CAAC,aAAa,qBAAsB;AACxC,UAAM,QAAQ,CAAC,UAAyB;AAGtC,UACE,MAAM,WACN,MAAM,UACN,MAAM,aACL,MAAM,QAAQ,aAAa,MAAM,QAAQ,SAAS,MAAM,QAAQ,UACjE;AACA,cAAM,eAAe;AACrB,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AACA,WAAO,iBAAiB,WAAW,KAAK;AACxC,WAAO,MAAM;AACX,aAAO,oBAAoB,WAAW,KAAK;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,WAAW,oBAAoB,CAAC;AAMpC,QAAM,oBAAoB,CAAC,iBAAiB,CAAC,YAAY,CAAC,mBAAmB,aAAa;AAC1F,QAAM,SAAS,iBAAiB;AAAA,IAC9B,YAAY;AAAA,IACZ;AAAA,IACA,aAAa;AAAA,IACb,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC;AAAA,IACvD,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACnC,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;AAAA,EACjD,CAAC;AAED,QAAM,YAAY,OAAO,UAAU;AACnC,QAAM,aAAa,QAAQ,mBAAmB,GAAG;AAIjD,QAAM,iBAAiBF,SAAO,OAAO,KAAK;AAC1C,iBAAe,UAAU,OAAO;AAUhC,QAAM,aAAaA,SAAsB,IAAI;AAC7C,EAAAE,YAAU,MAAM;AACd,QAAI,CAAC,cAAc,CAAC,gBAAgB,YAAY,kBAAkB;AAEhE,UAAI,CAAC,aAAc,YAAW,UAAU;AACxC;AAAA,IACF;AACA,UAAM,OAAO,UAAU;AACvB,QAAI,CAAC,KAAM;AAKX,UAAM,MAAM,GAAG,YAAY,UAAU,EAAE,IAAI,YAAY,OAAO,EAAE,IAAI,YAAY,aAAa,EAAE;AAC/F,QAAI,WAAW,YAAY,IAAK;AAChC,eAAW,UAAU;AACrB,SAAK;AAAA,EAGP,GAAG,CAAC,YAAY,cAAc,UAAU,kBAAkB,YAAY,QAAQ,aAAa,CAAC;AAQ5F,EAAAA,YAAU,MAAM;AACd,QAAI,CAAC,cAAc,OAAO,aAAa,YAAa;AACpD,UAAM,gBAAgB,MAAM;AAC1B,UAAI,SAAS,oBAAoB,UAAW;AAQ5C,UAAI,eAAe,YAAY,OAAQ,QAAO,UAAU;AAAA,IAC1D;AAMA,aAAS,iBAAiB,oBAAoB,aAAa;AAC3D,WAAO,MAAM,SAAS,oBAAoB,oBAAoB,aAAa;AAAA,EAG7E,GAAG,CAAC,YAAY,mBAAmB,GAAG,CAAC;AAMvC,QAAM,CAAC,iBAAiB,kBAAkB,IAAID,WAAS,KAAK;AAG5D,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,WAAS,CAAC;AACtD,EAAAC,YAAU,MAAM;AAKd,uBAAmB,KAAK;AACxB,QAAI,CAAC,cAAc,aAAa,OAAO,SAAS,oBAAoB,EAAG;AACvE,UAAM,QAAQ,WAAW,MAAM,mBAAmB,IAAI,GAAG,gBAAgB;AACzE,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB,OAAO;AAAA,IACP;AAAA,EACF,CAAC;AAED,QAAM,YAAY,MAAM;AACtB,uBAAmB,KAAK;AACxB,sBAAkB,CAAC,MAAM,IAAI,CAAC;AAC9B,WAAO,UAAU;AAAA,EACnB;AAGA,MAAI;AACJ,MAAI,iBAAkB,WAAU;AAAA,WACvB,gBAAiB,WAAU;AAAA,WAC3B,YAAY,CAAC,WAAY,WAAU;AAAA,WACnC,aAAc,WAAU;AAAA,WACxB,UAAW,WAAU;AAAA,WACrB,OAAO,MAAO,WAAU;AAAA,WACxB,gBAAiB,WAAU;AAAA,MAC/B,WAAU;AAIf,QAAM,eAAe,YAAY,eAAe,YAAY;AAC5D,QAAM,aAAa,qBAAqB,CAAC;AAEzC,MAAI,UAAqB;AACzB,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,gBACE,kBAAkB,KAClB;AAAA,QACE;AAAA,QACA;AAAA,MACF;AACF;AAAA,IACF,KAAK;AACH,gBACE,oBAAoB,MAAM,KAC1B,cAAc,uBAAuB,gBAAgB,MAAM,CAAC;AAC9D;AAAA,IACF,KAAK;AACH,gBAAU,oBACR,kBAAkB,QAAQ,YAAY,UAAU,KAAK,IAErD,gBAAAJ,MAAC,sBAAmB,QAAQ,YAAY,UAAU,OAAO,UAAU,QAAQ;AAE7E;AAAA,IACF,KAAK;AACH,gBAAU,gBAAgB,KAAK,gBAAAA,MAAC,iBAAc;AAC9C;AAAA,IACF,KAAK;AACH,gBAAU;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA;AAAA,IACF,KAAK;AACH,gBAAU;AAAA,QACR;AAAA,QACA,OAAO,OAAO,WAAW;AAAA,QACzB;AAAA,MACF;AACA;AAAA,IACF,KAAK;AAAA,IACL,KAAK;AACH,gBAAU;AACV;AAAA,EACJ;AAEA,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,aAAa;AAAA,QACb;AAAA,MACF;AAAA,MACA,OAAO,EAAE,iBAAiB,yBAAyB;AAAA,MACnD,yBAAqB;AAAA,MACrB,cAAY,OAAO;AAAA,MACnB,iBAAe;AAAA,MACf,mBAAiB,YAAY,SAAS;AAAA,MAStC;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,WAAU;AAAA,YACV,gCAA4B;AAAA,YAC5B,cAAY,OAAO;AAAA;AAAA,QACrB;AAAA,QAOC,YAAY,gBACX,gBAAAC,OAAC,SAAI,WAAU,0GACb;AAAA,0BAAAA,OAAC,UAAK,WAAU,6CACd;AAAA,4BAAAD,MAAC,eAAY,WAAU,qBAAoB,aAAa,KAAK;AAAA,YAC7D,gBAAAA;AAAA,cAACK;AAAA,cAAA;AAAA,gBACC,WAAU;AAAA,gBACV,aAAa;AAAA;AAAA,YACf;AAAA,aACF;AAAA,UACA,gBAAAL,MAAC,UAAK,WAAU,cAAa,6CAA0B;AAAA,WACzD;AAAA,QAYD,cAAc,CAAC,wBAAwB,aACtC,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ,YAAY,UAAU;AAAA,YAC9B,WAAW,MAAM,eAAe,KAAK;AAAA;AAAA,QACvC;AAAA,QAOD,cAAc,CAAC,wBAAwB,CAAC,aAAa,aACpD,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU,CAAC;AAAA,YACX,gBACE,CAAC,sBACG,YAAY,WAAW,WACrB,wEACA,mDACF;AAAA,YAEN,eAAe,MAAM,eAAe,IAAI;AAAA;AAAA,QAC1C;AAAA,QAGD,WACC,gBAAAA,MAAC,SAAI,WAAU,yDAAyD,mBAAQ;AAAA;AAAA;AAAA,EAEpF;AAEJ;AAWA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD;AAAA;AAAA;AAAA,IAGE,gBAAAA,MAAC,SAAI,WAAU,8EACb,0BAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL;AAAA,QACA,cAAW;AAAA,QACX,OAAO,WAAW,iBAAiB;AAAA,QACnC,SAAS;AAAA,QACT,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,WACI,kCACA;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACN;AAAA,QAEA;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,WAAW,KAAK;AAAA,cAClB;AAAA,cAEA,0BAAAA,MAAC,yBAAsB,WAAU,UAAS,aAAa,GAAG;AAAA;AAAA,UAC5D;AAAA,UACA,gBAAAC,OAAC,UAAK,WAAU,2CACd;AAAA,4BAAAD,MAAC,UAAK,WAAU,yCAAwC,0BAAY;AAAA,YACpE,gBAAAA,MAAC,UAAK,WAAU,gCACb,sBAAY,iBAAiB,iBAAiB,8BACjD;AAAA,aACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA;AAEJ;AAUA,SAAS,aAAa,EAAE,QAAQ,UAAU,GAA+C;AACvF,SACE,gBAAAC,OAAC,SAAI,WAAU,4FACb;AAAA,oBAAAA,OAAC,UAAK,WAAU,mJACd;AAAA,sBAAAD,MAAC,UAAK,WAAU,kDAAiD,eAAW,MAAC;AAAA,MAAE;AAAA,MAE/E,gBAAAA,MAAC,UAAK,WAAU,cAAa,2DAA0C;AAAA,OACzE;AAAA,IACA,gBAAAC,OAAC,SAAI,WAAU,iDACZ;AAAA,gBACC,gBAAAD,MAAC,UAAK,WAAU,iFAAgF,uDAEhG;AAAA,MAEF,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,OAAM;AAAA,UACN,WAAW;AAAA,YACT;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UAEA;AAAA,4BAAAD,MAAC,eAAY,WAAU,YAAW,aAAa,GAAG,eAAW,MAAC;AAAA,YAAE;AAAA;AAAA;AAAA,MAElE;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,gBAAgB,QAAoD;AAC3E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAGH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AASA,SAAS,cAAc,EAAE,QAAQ,GAA2C;AAC1E,SACE,gBAAAC,OAAC,SAAI,WAAU,wJACb;AAAA,oBAAAD,MAACK,mBAAA,EAAiB,WAAU,yCAAwC,aAAa,KAAK;AAAA,IACtF,gBAAAJ,OAAC,SAAI,WAAU,aACb;AAAA,sBAAAD,MAAC,SAAI,WAAU,eAAc,uCAAoB;AAAA,MACjD,gBAAAA,MAAC,OAAE,WAAU,gCAA+B,sEAE5C;AAAA,OACF;AAAA,IACC,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KAEJ;AAEJ;AAEA,SAAS,mBAAmB,EAAE,QAAQ,SAAS,GAA8C;AAC3F,SACE,gBAAAC,OAAC,SAAI,WAAU,mGACb;AAAA,oBAAAD,MAAC,SAAI,WAAU,oBAAmB,qCAAuB;AAAA,IACzD,gBAAAC,OAAC,OAAE,WAAU,qCAAoC;AAAA;AAAA,MACnB,gBAAAD,MAAC,YAAO,yBAAW;AAAA,MAAS;AAAA,MAEvD,SACG,wFACA;AAAA,OACN;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;AAEA,SAAS,cAAc,OAAe,MAAc,SAAiC;AACnF,SACE,gBAAAC,OAAC,SAAI,WAAU,mGACb;AAAA,oBAAAA,OAAC,SAAI,WAAU,6DACZ;AAAA,iBAAW,gBAAAD,MAAC,eAAY,WAAU,qBAAoB,aAAa,MAAM;AAAA,MACzE;AAAA,OACH;AAAA,IACA,gBAAAA,MAAC,OAAE,WAAU,gCAAgC,gBAAK;AAAA,IACjD,WACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KAEJ;AAEJ;;;ACjqBA;AAAA,EAGE,eAAAM;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAAC;AAAA,OACK;AACP,SAAS,OAAO,OAAO,WAAW,kBAAkB,mBAAmB;AAyLjE,SAsCE,YAAAC,WArCA,OAAAC,OADF,QAAAC,cAAA;AArIN,IAAM,sBAAsB,OAAO,WAAW,cAAcC,cAAYC;AAOxE,IAAM,0BAA0B;AAGhC,SAAS,YAAY,UAA2B;AAC9C,QAAM,CAAC,QAAQ,SAAS,IAAIC,WAAS,KAAK;AAC1C,sBAAoB,MAAM;AACxB,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E;AAAA,IACF;AACA,UAAM,MAAM,OAAO,WAAW,eAAe,WAAW,CAAC,KAAK;AAC9D,UAAM,SAAS,MAAM,UAAU,IAAI,OAAO;AAC1C,WAAO;AACP,QAAI,OAAO,IAAI,qBAAqB,YAAY;AAC9C,UAAI,iBAAiB,UAAU,MAAM;AACrC,aAAO,MAAM,IAAI,oBAAoB,UAAU,MAAM;AAAA,IACvD;AAEA,QAAI,YAAY,MAAM;AACtB,WAAO,MAAM,IAAI,eAAe,MAAM;AAAA,EACxC,GAAG,CAAC,QAAQ,CAAC;AACb,SAAO;AACT;AAEO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EACV,UAAU;AAAA,EACV;AACF,GAAuB;AACrB,QAAM,SAAS,YAAY,uBAAuB;AAClD,QAAM,eAAe,YAAY;AACjC,QAAM,CAAC,mBAAmB,oBAAoB,IAAIA,WAAS,KAAK;AAChE,QAAM,CAAC,WAAW,YAAY,IAAIA,WAAS,KAAK;AAChD,QAAM,CAAC,aAAa,cAAc,IAAIA,WAAS,KAAK,CAAC,GAAG,MAAM,EAAE;AAChE,QAAM,YAAY,iBAAiB;AAMnC,QAAM,iBAAiB,kBAAkB;AAGzC,QAAM,EAAE,eAAe,gBAAgB,IAAI,iBAAiB;AAAA,IAC1D,UAAU,CAAC,WAAW,MAAM;AAAA,IAC5B,SAAS,OAAO,WAAW,cAAc,OAAO,eAAe;AAAA,IAC/D,IAAI;AAAA,EACN,CAA2C;AAE3C,QAAM,eAAe,aAAa;AAClC,QAAM,SAAS,KAAK,IAAI,CAAC,QAAQ,IAAI,EAAE;AACvC,QAAM,aAAa,KAAK,CAAC,GAAG,MAAM;AAClC,QAAM,sBAAsB,OAAO,SAAS,YAAY;AACxD,QAAM,UAAU,sBAAsB,eAAe;AACrD,QAAM,SAASC;AAAA,IACb,CAAC,OAAe;AACd,qBAAe,EAAE;AACjB,0BAAoB,EAAE;AAAA,IACxB;AAAA,IACA,CAAC,iBAAiB;AAAA,EACpB;AACA,QAAM,eAAeA;AAAA,IACnB,CAAC,SAAkB;AACjB,2BAAqB,CAAC,aAAc,aAAa,OAAO,WAAW,IAAK;AACxE,0BAAoB,IAAI;AAAA,IAC1B;AAAA,IACA,CAAC,iBAAiB;AAAA,EACpB;AAEA,sBAAoB,MAAM;AACxB,QAAI,kBAAkB,QAAW;AAC/B;AAAA,IACF;AACA,QAAI,eAAe;AACjB,mBAAa,SAAS,SAAS;AAC/B,mBAAa,KAAK;AAAA,IACpB,OAAO;AACL,mBAAa,SAAS,OAAO;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,eAAe,YAAY,CAAC;AAGhC,EAAAH,YAAU,MAAM;AACd,QAAI,cAAc,CAAC,qBAAqB;AACtC,aAAO,UAAU;AAAA,IACnB;AAAA,EAGF,GAAG,CAAC,YAAY,qBAAqB,MAAM,CAAC;AAE5C,QAAM,WAAWG,cAAY,MAAM;AACjC,iBAAa,SAAS,SAAS;AAC/B,iBAAa,IAAI;AAAA,EACnB,GAAG,CAAC,cAAc,YAAY,CAAC;AAC/B,QAAM,SAASA,cAAY,MAAM;AAC/B,iBAAa,SAAS,OAAO;AAC7B,iBAAa,KAAK;AAAA,EACpB,GAAG,CAAC,cAAc,YAAY,CAAC;AAG/B,EAAAH,YAAU,MAAM;AACd,UAAM,cAAc,aAAc,UAAU,CAAC;AAC7C,QAAI,CAAC,YAAa;AAClB,UAAM,QAAQ,CAAC,UAAyB;AACtC,UAAI,MAAM,QAAQ,SAAU;AAC5B,UAAI,UAAW,cAAa,KAAK;AAAA,UAC5B,UAAS;AAAA,IAChB;AACA,WAAO,iBAAiB,WAAW,KAAK;AACxC,WAAO,MAAM,OAAO,oBAAoB,WAAW,KAAK;AAAA,EAC1D,GAAG,CAAC,WAAW,QAAQ,WAAW,QAAQ,CAAC;AAK3C,MAAI,QAAQ;AACV,WACE,gBAAAD,OAAC,SAAI,WAAW,GAAG,+CAA+C,SAAS,GACzE;AAAA,sBAAAD,MAAC,SAAI,WAAU,0BAA0B,mBAAQ;AAAA,MAChD,CAAC,aACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,cAAW;AAAA,UACX,cAAW;AAAA,UACX,WAAU;AAAA,UACV,OAAO;AAAA,YACL,YAAY;AAAA,YACZ,eAAe;AAAA,UACjB;AAAA,UAEA,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA,OAAO;AAAA,cACP,SAAS;AAAA,cACT,WAAW;AAAA,cACX,UACE,gBAAAA,MAAC,gBAAa,SAAS,UAAU,OAAM,mBAAkB,OAAM,mBAC7D,0BAAAA,MAACM,QAAA,EAAM,WAAU,UAAS,GAC5B;AAAA;AAAA,UAEJ;AAAA;AAAA,MACF;AAAA,OAEJ;AAAA,EAEJ;AAEA,QAAM,aACJ,gBAAAN;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP,WAAW;AAAA,MACX,UACE,gBAAAC,OAAAF,WAAA,EACE;AAAA,wBAAAC;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;AAAA,YACrC,OAAO,YAAY,kBAAkB;AAAA,YACrC,OAAO,YAAY,iBAAiB;AAAA,YAEnC,sBACC,gBAAAA,MAAC,iBAAc,WAAU,YAAW,IAEpC,gBAAAA,MAAC,iBAAc,WAAU,YAAW;AAAA;AAAA,QAExC;AAAA,QACC,iBAAiB,OAChB,gBAAAA,MAAC,gBAAa,SAAS,UAAU,OAAM,YAAW,OAAM,iBACtD,0BAAAA,MAAC,uBAAoB,WAAU,YAAW,GAC5C;AAAA,SAEJ;AAAA;AAAA,EAEJ;AAGF,SACE,gBAAAC,OAAC,SAAI,WAAW,GAAG,+CAA+C,SAAS,GACzE;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,aAAY;AAAA,QACZ,WAAU;AAAA,QACT,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;AAAA,QAC1C;AAAA,QAEA;AAAA,0BAAAD,MAAC,SAAM,IAAG,WAAU,SAAQ,OAAM,WAAU,mBACzC,mBACH;AAAA,UAEC,CAAC,aACA,gBAAAA,MAAC,aAAU,WAAU,8CACnB,0BAAAA,MAAC,UAAK,WAAU,gKAA+J,GACjL;AAAA,UAGF,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,UAAU;AAAA,cACV,aAAW;AAAA,cACX,eAAc;AAAA,cACd,aAAa,GAAG,WAAW;AAAA,cAC3B,SAAS,GAAG,OAAO;AAAA,cACnB,SAAS,GAAG,OAAO;AAAA,cACnB,UAAU,CAAC,MAAM,KAAK,iBAAiB;AAErC,sBAAM,cAAc,KAAK,gBAAgB;AACzC,sBAAM,mBAAmB,kBAAkB,UAAa,iBAAiB;AACzE,oBAAI,oBAAoB,gBAAgB,WAAW;AACjD,+BAAa,WAAW;AAAA,gBAC1B;AAAA,cACF;AAAA,cACA,WAAU;AAAA,cAIT,WAAC,aAAa,CAAC,aACd,gBAAAA,MAAC,SAAI,WAAU,2EACZ,sBACH;AAAA;AAAA,UAEJ;AAAA;AAAA;AAAA,IACF;AAAA,IAIC,aAAa,CAAC,aAAa,CAAC,kBAC3B,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,OAAM;AAAA,QACN,WAAU;AAAA,QAEV,0BAAAA,MAAC,yBAAsB,WAAU,YAAW;AAAA;AAAA,IAC9C;AAAA,IAID,aAAa,gBAAAA,MAAC,SAAI,WAAU,6CAA6C,sBAAW;AAAA,KACvF;AAEJ;AAGA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,cAAY;AAAA,MACZ,WAAU;AAAA,MAET;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AACD,QAAM,SAAS,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,KAAK,KAAK,CAAC;AAC3D,QAAM,cAAc,KAAK,UAAU,CAAC,QAAQ,IAAI,OAAO,QAAQ,EAAE;AACjE,QAAM,WAAWO,OAAM;AACvB,QAAM,UAAUC,SAAwC,CAAC,CAAC;AAC1D,QAAM,UAAU,GAAG,QAAQ;AAE3B,QAAM,cAAc,CAAC,UAAkB;AACrC,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,CAAC,IAAK;AACV,UAAM,IAAI,EAAE;AACZ,YAAQ,QAAQ,KAAK,GAAG,MAAM;AAAA,EAChC;AAEA,QAAM,eAAe,CAAC,OAA8C,UAAkB;AACpF,QAAI,KAAK,WAAW,EAAG;AACvB,QAAI,YAA2B;AAC/B,QAAI,MAAM,QAAQ,aAAc,cAAa,QAAQ,KAAK,KAAK;AAAA,aACtD,MAAM,QAAQ,YAAa,cAAa,QAAQ,IAAI,KAAK,UAAU,KAAK;AAAA,aACxE,MAAM,QAAQ,OAAQ,aAAY;AAAA,aAClC,MAAM,QAAQ,MAAO,aAAY,KAAK,SAAS;AACxD,QAAI,cAAc,KAAM;AACxB,UAAM,eAAe;AACrB,gBAAY,SAAS;AAAA,EACvB;AAEA,SACE,gBAAAP,OAAAF,WAAA,EACE;AAAA,oBAAAE,OAAC,SAAI,WAAU,0EACZ;AAAA,gBAAU,gBAAAD,MAAC,SAAI,WAAU,8BAA8B,mBAAQ,IAAS;AAAA,MAIzE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,MAAK;AAAA,UACL,oBAAiB;AAAA,UAEhB,eAAK,IAAI,CAAC,KAAK,UACd,gBAAAC;AAAA,YAAC;AAAA;AAAA,cAEC,KAAK,CAAC,SAAS;AACb,wBAAQ,QAAQ,KAAK,IAAI;AAAA,cAC3B;AAAA,cACA,IAAI,GAAG,QAAQ,QAAQ,KAAK;AAAA,cAC5B,MAAK;AAAA,cACL,MAAK;AAAA,cACL,iBAAe,IAAI,OAAO;AAAA,cAC1B,iBAAe;AAAA,cACf,UAAU,IAAI,OAAO,UAAU,IAAI;AAAA,cACnC,SAAS,MAAM,MAAM,IAAI,EAAE;AAAA,cAC3B,WAAW,CAAC,UAAU,aAAa,OAAO,KAAK;AAAA,cAC/C,WAAW;AAAA,gBACT;AAAA,gBACA,IAAI,OAAO,UACP,iCACA;AAAA,cACN;AAAA,cAEA;AAAA,gCAAAD,MAAC,UAAM,cAAI,OAAM;AAAA,gBAChB,IAAI;AAAA;AAAA;AAAA,YApBA,IAAI;AAAA,UAqBX,CACD;AAAA;AAAA,MACH;AAAA,MACC,YAAY,gBAAAA,MAAC,SAAI,WAAU,8BAA8B,qBAAU,IAAS;AAAA,MAC7E,gBAAAA,MAAC,SAAI,WAAU,wDAAwD,oBAAS;AAAA,OAClF;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,IAAI;AAAA,QACJ,cAAY,cAAc,IAAI,cAAc;AAAA,QAC5C,mBAAiB,eAAe,IAAI,GAAG,QAAQ,QAAQ,WAAW,KAAK;AAAA,QACvE,WAAU;AAAA,QACV,MAAK;AAAA,QAEJ,kBAAQ;AAAA;AAAA,IACX;AAAA,KACF;AAEJ;;;AChbA,SAAyB,eAAAS,eAAa,aAAAC,aAAW,WAAAC,WAAS,UAAAC,UAAQ,YAAAC,kBAAgB;AAClF,SAAS,eAAe;AAExB,SAAS,SAAS,YAAY,iBAAAC,sBAAqB;;;ACjBnD,SAAS,iBAAiB,mBAAmB;AAC7C;AAAA,EAEE,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OACK;AACP,SAAS,SAAAC,cAAa;;;ACZtB,SAAS,eAAAC,eAAa,aAAAC,aAAW,WAAAC,WAAS,UAAAC,UAAQ,YAAAC,kBAAgB;AAmC3D,SAAS,mBACd,SACA,WACA,UACA,UACa;AACb,QAAM,IAAI,QAAQ;AAClB,MAAI,MAAM,EAAG,QAAO,EAAE,OAAO,GAAG,KAAK,EAAE;AACvC,QAAM,MAAM,KAAK,IAAI,WAAW,CAAC;AACjC,QAAM,SAAS,MAAM,KAAK,IAAI,UAAU,CAAC;AAEzC,MAAI,eAAe;AACnB,MAAI,cAAc;AAClB,MAAI,MAAM;AACV,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,SAAS;AACf,UAAM,YAAY,SAAS,KAAK,IAAI,QAAQ,CAAC,KAAK,GAAG,CAAC;AACtD,QAAI,UAAU,IAAK,UAAS;AAG5B,QAAI,YAAY,OAAO,SAAS,QAAQ;AACtC,UAAI,iBAAiB,GAAI,gBAAe;AACxC,oBAAc;AAAA,IAChB;AACA,UAAM;AAAA,EACR;AAEA,MAAI,iBAAiB,IAAI;AACvB,mBAAe;AACf,kBAAc;AAAA,EAChB;AAEA,SAAO;AAAA,IACL,OAAO,KAAK,IAAI,GAAG,eAAe,QAAQ;AAAA,IAC1C,KAAK,KAAK,IAAI,GAAG,cAAc,IAAI,QAAQ;AAAA,EAC7C;AACF;AA0BO,SAAS,oBAAoB,MAIf;AACnB,QAAM,EAAE,OAAO,gBAAgB,WAAW,EAAE,IAAI;AAChD,QAAM,YAAYD,SAA8B,IAAI;AAEpD,QAAM,CAAC,SAAS,UAAU,IAAIC;AAAA,IAAmB,MAC/C,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM,eAAe,CAAC,CAAC;AAAA,EAC3D;AAIA,EAAAH,YAAU,MAAM;AACd,eAAW,CAAC,SAAS;AACnB,UAAI,KAAK,WAAW,MAAO,QAAO;AAClC,aAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,MAAM,KAAK,CAAC,KAAK,eAAe,CAAC,CAAC;AAAA,IAC7E,CAAC;AAAA,EAGH,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,aAAaE,SAAO,OAAO;AACjC,aAAW,UAAU;AAErB,QAAM,CAAC,OAAO,QAAQ,IAAIC,WAAsB,OAAO;AAAA,IACrD,OAAO;AAAA,IACP,KAAK,KAAK,IAAI,OAAO,WAAW,CAAC;AAAA,EACnC,EAAE;AAEF,QAAM,YAAYJ,cAAY,MAAM;AAClC,UAAM,KAAK,UAAU;AACrB,QAAI,CAAC,GAAI;AACT,UAAM,OAAO,mBAAmB,WAAW,SAAS,GAAG,WAAW,GAAG,cAAc,QAAQ;AAC3F,aAAS,CAAC,SAAU,KAAK,UAAU,KAAK,SAAS,KAAK,QAAQ,KAAK,MAAM,OAAO,IAAK;AAAA,EACvF,GAAG,CAAC,QAAQ,CAAC;AAGb,EAAAC,YAAU,MAAM;AACd,UAAM,KAAK,UAAU;AACrB,QAAI,CAAC,GAAI;AACT,QAAI,MAAM;AACV,UAAM,WAAW,MAAM;AACrB,UAAI,IAAK;AACT,YACE,OAAO,0BAA0B,aAC7B,sBAAsB,MAAM;AAC1B,cAAM;AACN,kBAAU;AAAA,MACZ,CAAC,KACA,UAAU,GAAG;AAAA,IACtB;AACA,OAAG,iBAAiB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;AACzD,UAAM,KAAK,OAAO,mBAAmB,cAAc,IAAI,eAAe,MAAM,UAAU,CAAC,IAAI;AAC3F,QAAI,QAAQ,EAAE;AACd,cAAU;AACV,WAAO,MAAM;AACX,SAAG,oBAAoB,UAAU,QAAQ;AACzC,UAAI,WAAW;AACf,UAAI,OAAO,OAAO,yBAAyB,WAAY,sBAAqB,GAAG;AAAA,IACjF;AAAA,EACF,GAAG,CAAC,WAAW,KAAK,CAAC;AAErB,QAAM,UAAUD,cAAY,CAAC,OAAe,WAAmB;AAC7D,QAAI,UAAU,EAAG;AACjB,eAAW,CAAC,SAAS;AACnB,UAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM,IAAI,EAAG,QAAO;AACtD,YAAM,OAAO,KAAK,MAAM;AACxB,WAAK,KAAK,IAAI;AACd,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,QAAM,UAAUE,UAAQ,MAAM;AAC5B,UAAM,MAAM,IAAI,MAAc,QAAQ,CAAC;AACvC,QAAI,CAAC,IAAI;AACT,aAAS,IAAI,GAAG,IAAI,OAAO,IAAK,KAAI,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,QAAQ,CAAC,KAAK,GAAG,CAAC;AACxF,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,KAAK,CAAC;AAInB,EAAAD,YAAU,MAAM;AACd,cAAU;AAAA,EACZ,GAAG,CAAC,SAAS,SAAS,CAAC;AAEvB,QAAM,gBAAgBD;AAAA,IACpB,CAAC,UAAkB;AACjB,YAAM,KAAK,UAAU;AACrB,UAAI,CAAC,GAAI;AACT,YAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,GAAG,KAAK,CAAC;AACtD,SAAG,YAAY,QAAQ,OAAO,KAAK;AAAA,IACrC;AAAA,IACA,CAAC,SAAS,KAAK;AAAA,EACjB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,QAAQ,KAAK,KAAK;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AACF;;;AD0CU,SAIkB,OAAAK,OAJlB,QAAAC,cAAA;AAjNV,IAAM,kBAAkB;AAExB,IAAM,WAAW;AACjB,IAAM,YAAY;AAClB,IAAM,UAAU;AAChB,IAAM,gBAAgB;AACtB,IAAM,qBAAqB;AAC3B,IAAM,yBAAyB,OAAO,WAAW,cAAcC,cAAYC;AAE3E,IAAMC,eAAqD;AAAA,EACzD,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,YAAY;AACd;AAEA,IAAM,gBAAuD;AAAA,EAC3D,OAAO;AAAA,EACP,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,YAAY;AACd;AAsBO,SAAS,UAAU,OAAwE;AAChG,MAAI,MAAM,UAAU,iBAAiB;AACnC,WAAO;AAAA,MACL,cAAc;AAAA,MACd,MAAM,MAAM,IAAI,CAAC,MAAM,WAAW,EAAE,MAAM,QAAQ,MAAM,MAAM,EAAE;AAAA,IAClE;AAAA,EACF;AACA,QAAM,SAAS,oBAAI,IAA2B;AAC9C,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,KAAK,QAAQ,GAAG;AACnC,UAAM,MAAM,QAAQ,IAAI,KAAK,KAAK,MAAM,GAAG,KAAK,IAAI;AACpD,UAAM,SAAS,OAAO,IAAI,GAAG;AAC7B,QAAI,OAAQ,QAAO,KAAK,IAAI;AAAA,QACvB,QAAO,IAAI,KAAK,CAAC,IAAI,CAAC;AAAA,EAC7B;AACA,QAAM,SAAS,CAAC,GAAG,OAAO,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AACnE,QAAM,eAA8B,CAAC;AACrC,QAAM,OAAkB,CAAC;AACzB,aAAW,SAAS,QAAQ;AAC1B,UAAM,UAAU,OAAO,IAAI,KAAK,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAC5F,SAAK,KAAK,EAAE,MAAM,SAAS,OAAO,OAAO,OAAO,OAAO,CAAC;AACxD,eAAW,QAAQ,QAAQ;AACzB,WAAK,KAAK,EAAE,MAAM,QAAQ,MAAM,OAAO,aAAa,OAAO,CAAC;AAC5D,mBAAa,KAAK,IAAI;AAAA,IACxB;AAAA,EACF;AACA,SAAO,EAAE,cAAc,KAAK;AAC9B;AAIA,SAAS,UAAU,MAA4B;AAC7C,SAAO,KAAK,YAAY,KAAK;AAC/B;AAIA,SAAS,sBAAsB,MAA2B;AACxD,MAAI,UAAU,IAAI,EAAG,QAAO,YAAY;AACxC,MAAI,QAAQ;AACZ,aAAW,QAAQ,KAAK,MAAO,UAAS,KAAK,MAAM,SAAS;AAC5D,SAAO,YAAY,KAAK,IAAI,OAAO,CAAC,IAAI,UAAU;AACpD;AAEO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,UAAUC,SAA8B,IAAI;AAClD,QAAM,CAAC,SAAS,UAAU,IAAIC,WAAS,KAAK;AAC5C,QAAM,CAAC,eAAe,gBAAgB,IAAIA,WAAS,KAAK;AACxD,QAAM,gBAAgB,aAAa,SAAS;AAC5C,QAAM,CAAC,QAAQ,SAAS,IAAIA,WAA8B,SAAS;AACnE,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAwB,IAAI;AAChE,QAAM,WAAWC,OAAM;AAEvB,QAAM,EAAE,cAAc,KAAK,IAAIC,UAAQ,MAAM,UAAU,IAAI,GAAG,CAAC,IAAI,CAAC;AACpE,QAAM,UAAU,KAAK,SAAS;AAC9B,QAAM,gBAAgB,aAAa,UAAU,CAAC,SAAS,KAAK,SAAS,UAAU;AAC/E,QAAM,cAAc,iBAAiB,IAAI,gBAAgB;AAEzD,yBAAuB,MAAM;AAC3B,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,QAAQ,OAAO,mBAAmB,YAAa;AACpD,UAAM,SAAS,CAAC,UAAkB;AAGhC,UAAI,QAAQ,EAAG,YAAW,QAAQ,kBAAkB;AAAA,IACtD;AACA,WAAO,KAAK,sBAAsB,EAAE,KAAK;AACzC,UAAM,WAAW,IAAI,eAAe,CAAC,YAAY;AAC/C,aAAO,QAAQ,CAAC,GAAG,YAAY,SAAS,KAAK,sBAAsB,EAAE,KAAK;AAAA,IAC5E,CAAC;AACD,aAAS,QAAQ,IAAI;AACrB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAEL,yBAAuB,MAAM;AAC3B,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,WAAY;AAC9E,UAAM,QAAQ,OAAO,WAAW,mBAAmB;AACnD,UAAM,SAAS,MAAM,iBAAiB,MAAM,OAAO;AACnD,WAAO;AACP,QAAI,OAAO,MAAM,qBAAqB,YAAY;AAChD,YAAM,iBAAiB,UAAU,MAAM;AACvC,aAAO,MAAM,MAAM,oBAAoB,UAAU,MAAM;AAAA,IACzD;AACA,QAAI,OAAO,MAAM,gBAAgB,YAAY;AAC3C,YAAM,YAAY,MAAM;AACxB,aAAO,MAAM,MAAM,eAAe,MAAM;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,YAAYA,UAAQ,MAAM,KAAK,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AACrF,QAAM,YAAYA,UAAQ,MAAM,KAAK,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAErF,QAAM,iBAAiBC;AAAA,IACrB,CAAC,UAAkB;AACjB,YAAM,OAAO,aAAa,KAAK;AAC/B,aAAO,OAAO,sBAAsB,IAAI,IAAI,YAAY;AAAA,IAC1D;AAAA,IACA,CAAC,YAAY;AAAA,EACf;AAEA,QAAM,WAAW,oBAAoB;AAAA,IACnC,OAAO,aAAa;AAAA,IACpB;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,SAASA;AAAA,IACb,CAAC,UAAkB;AACjB,oBAAc,aAAa,KAAK,GAAG,QAAQ,IAAI;AAC/C,eAAS,cAAc,KAAK;AAAA,IAC9B;AAAA,IACA,CAAC,cAAc,QAAQ;AAAA,EACzB;AAGA,QAAM,eAAeA,cAAY,MAAM;AACrC,UAAM,KAAK,SAAS,UAAU;AAC9B,QAAI,CAAC,GAAI;AACT,UAAM,MAAM,GAAG;AACf,UAAM,UAAU,SAAS;AACzB,QAAI,MAAM;AACV,aAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,WAAK,QAAQ,CAAC,KAAK,MAAM,MAAM,EAAG,OAAM;AAAA,UACnC;AAAA,IACP;AACA,UAAM,WAAW,aAAa,GAAG,GAAG,QAAQ;AAC5C,kBAAc,CAAC,aAAc,aAAa,WAAW,WAAW,QAAS;AAAA,EAC3E,GAAG,CAAC,UAAU,YAAY,CAAC;AAE3B,EAAAP,YAAU,MAAM;AACd,UAAM,KAAK,SAAS,UAAU;AAC9B,QAAI,CAAC,GAAI;AACT,OAAG,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;AAC7D,WAAO,MAAM,GAAG,oBAAoB,UAAU,YAAY;AAAA,EAC5D,GAAG,CAAC,SAAS,WAAW,YAAY,CAAC;AAErC,QAAM,cAAc,eAAe,QAAQ,YAAY,mBAAmB,IAAI;AAC9E,QAAM,aAAa,aAAa,WAAW,KAAK,aAAa,CAAC;AAE9D,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAW,GAAG,wCAAwC,SAAS;AAAA,MAC/D,iCAA+B,UAAU,YAAY;AAAA,MAGrD;AAAA,wBAAAA,OAAC,SAAI,WAAU,0FACb;AAAA,0BAAAA,OAAC,UAAK,WAAU,gDACb;AAAA,iBAAK;AAAA,YAAO;AAAA,YAAE,KAAK,WAAW,IAAI,SAAS;AAAA,YAAQ;AAAA,YACpD,gBAAAA,OAAC,UAAK,WAAU,4BAA2B;AAAA;AAAA,cAAE;AAAA,eAAU;AAAA,YACvD,gBAAAA,OAAC,UAAK,WAAU,8BAA6B;AAAA;AAAA,cAAE;AAAA,eAAU;AAAA,aAC3D;AAAA,UACA,gBAAAA,OAAC,SAAI,WAAU,oCACZ;AAAA,sBAAU,OAAO,gBAAAD,MAACU,eAAA,EAAa,QAAgB,UAAU,WAAW;AAAA,YACrE,gBAAAV,MAAC,eAAY,QAAgB,YAAwB,OAAO,aAAa;AAAA,aAC3E;AAAA,WACF;AAAA,QAEC,UACC,gBAAAC,OAAC,SAAI,WAAU,gCACb;AAAA,0BAAAA,OAAC,SAAI,WAAU,0DACb;AAAA,4BAAAD,MAAC,WAAM,WAAU,WAAU,SAAS,UAAU,0BAE9C;AAAA,YACA,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,IAAI;AAAA,gBACJ,cAAW;AAAA,gBACX,OAAO;AAAA,gBACP,UAAU,CAAC,UAAU;AACnB,wBAAM,QAAQ,OAAO,MAAM,cAAc,KAAK;AAC9C,gCAAc,aAAa,KAAK,GAAG,QAAQ,IAAI;AAAA,gBACjD;AAAA,gBACA,4BAAwB;AAAA,gBACxB,WAAU;AAAA,gBAET,uBAAa,IAAI,CAAC,MAAM,UACvB,gBAAAC,OAAC,YAAuB,OAAO,OAC5B;AAAA,gCAAc,KAAK,MAAM;AAAA,kBAAE;AAAA,kBAAI,KAAK;AAAA,kBAAK;AAAA,kBAAK,KAAK;AAAA,kBAAU;AAAA,kBAAG,KAAK;AAAA,qBAD3D,KAAK,IAElB,CACD;AAAA;AAAA,YACH;AAAA,aACF;AAAA,UACA,gBAAAD,MAAC,SAAI,WAAU,wCAAuC,8BAA0B,MAC7E,uBACC,gBAAAA,MAAC,eAAY,MAAM,YAAY,QAAO,WAAU,WAAW,eAAe,IACxE,MACN;AAAA,WACF,IAEA,gBAAAC,OAAC,SAAI,WAAU,uBAEb;AAAA,0BAAAD,MAAC,SAAI,WAAU,gDACb,0BAAAA;AAAA,YAACW;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,UAAU,gBAAgB,KAAK;AAAA,cAC/B,UAAU,KAAK,IAAI,IAAI,KAAK,MAAM;AAAA,cAEjC,eAAK;AAAA,gBAAI,CAAC,QACT,IAAI,SAAS,UACX,gBAAAV;AAAA,kBAAC;AAAA;AAAA,oBAEC,mBAAe;AAAA,oBACf,WAAU;AAAA,oBAEV;AAAA,sCAAAD,MAAC,UAAK,WAAU,oBAAoB,cAAI,OAAM;AAAA,sBAC9C,gBAAAA,MAAC,UAAK,WAAU,YAAY,cAAI,OAAM;AAAA;AAAA;AAAA,kBALjC,KAAK,IAAI,KAAK;AAAA,gBAMrB,IAEA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBAEC,MAAM,IAAI;AAAA,oBACV;AAAA,oBACA,QAAQ,IAAI,UAAU;AAAA,oBACtB,SAAS,MAAM,OAAO,IAAI,KAAK;AAAA;AAAA,kBAJ1B,IAAI,KAAK;AAAA,gBAKhB;AAAA,cAEJ;AAAA;AAAA,UACF,GACF;AAAA,UAKA,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK,SAAS;AAAA,cACd,WAAU;AAAA,cACV,8BAA0B;AAAA,cAE1B,0BAAAA,MAAC,SAAI,OAAO,EAAE,UAAU,YAAY,QAAQ,SAAS,YAAY,GAC9D,uBAAa,IAAI,CAAC,MAAM,UAAU;AACjC,oBAAI,QAAQ,SAAS,MAAM,SAAS,SAAS,SAAS,MAAM,IAAK,QAAO;AACxE,uBACE,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBAEC;AAAA,oBACA,KAAK,SAAS,QAAQ,KAAK,KAAK;AAAA,oBAChC,WAAW,SAAS;AAAA,oBAEpB,0BAAAA,MAAC,eAAY,MAAY,QAAgB,WAAW,eAAe;AAAA;AAAA,kBAL9D,KAAK;AAAA,gBAMZ;AAAA,cAEJ,CAAC,GACH;AAAA;AAAA,UACF;AAAA,WACF;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAQA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,WAAW,aAAa,YAAY;AACtC,WACE,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO,IAAI,KAAK,UAAU,EAAE,eAAe;AAAA,QAE3C;AAAA,0BAAAD,MAAC,eAAY,WAAU,0CAAyC,eAAW,MAAC;AAAA,UAC3E;AAAA;AAAA;AAAA,IACH;AAAA,EAEJ;AACA,SACE,gBAAAA,MAAC,UAAK,WAAU,yEACb,iBACH;AAEJ;AAGA,SAAS,eACP,QACA,YACA,UACQ;AACR,MAAI,WAAW,aAAa,CAAC,WAAY,QAAO;AAChD,QAAM,OAAO,WAAW,YAAY,KAAK,IAAI,CAAC;AAC9C,SAAO,aAAa,OAAO,cAAc,QAAQ,SAAM,IAAI,KAAK,SAAS,IAAI;AAC/E;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AAGD,QAAM,QAAQ,UAAU,KAAK,KAAK,MAAM,KAAK,KAAK,QAAQ,GAAG,IAAI,CAAC,KAAK,KAAK,OAAO,KAAK;AACxF,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,kBAAc;AAAA,MACd,WAAW;AAAA,QACT;AAAA,QACA,WAAW;AAAA,QACX,UAAU;AAAA,MACZ;AAAA,MAEA;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,GAAG,oDAAoDI,aAAY,KAAK,MAAM,CAAC;AAAA,YAEzF,wBAAc,KAAK,MAAM;AAAA;AAAA,QAC5B;AAAA,QACA,gBAAAJ,MAAC,UAAK,WAAU,2BAA2B,iBAAM;AAAA,QACjD,gBAAAC,OAAC,UAAK,WAAU,uEACd;AAAA,0BAAAA,OAAC,UAAK,WAAU,uBAAsB;AAAA;AAAA,YAAE,KAAK;AAAA,aAAU;AAAA,UACvD,gBAAAA,OAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,YAAE,KAAK;AAAA,aAAU;AAAA,WAC3D;AAAA;AAAA;AAAA,EACF;AAEJ;AAKA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,MAAMI,SAAuB,IAAI;AACvC,EAAAH,YAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,SAAS,MAAM,UAAU,OAAO,GAAG,YAAY;AACrD,WAAO;AACP,UAAM,KAAK,OAAO,mBAAmB,cAAc,IAAI,eAAe,MAAM,IAAI;AAChF,QAAI,QAAQ,EAAE;AACd,WAAO,MAAM,IAAI,WAAW;AAAA,EAC9B,GAAG,CAAC,OAAO,SAAS,CAAC;AACrB,SACE,gBAAAF;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,qBAAiB;AAAA,MACjB,mBAAiB;AAAA,MACjB,OAAO,EAAE,UAAU,YAAY,KAAK,MAAM,GAAG,OAAO,EAAE;AAAA,MAErD;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AAID,MAAI,UAAU,IAAI,GAAG;AACnB,UAAM,UAAU,KAAK,WAAW,KAAK,YAAY,KAAK;AACtD,WACE,gBAAAC,OAAC,aAAQ,WAAU,kCACjB;AAAA,sBAAAA,OAAC,YAAO,WAAU,kFAChB;AAAA,wBAAAD,MAAC,UAAK,WAAU,4CACb,oBAAU,GAAG,KAAK,OAAO,WAAM,KAAK,IAAI,KAAK,KAAK,MACrD;AAAA,QACA,gBAAAC,OAAC,UAAK,WAAU,0DACd;AAAA,0BAAAA,OAAC,UAAK,WAAU,uBAAsB;AAAA;AAAA,YAAE,KAAK;AAAA,aAAU;AAAA,UACvD,gBAAAA,OAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,YAAE,KAAK;AAAA,aAAU;AAAA,WAC3D;AAAA,SACF;AAAA,MACA,gBAAAD,MAAC,aAAU,MAAY;AAAA,OACzB;AAAA,EAEJ;AACA,SACE,gBAAAA,MAAC,aAAQ,WAAU,kCACjB,0BAAAA,MAAC,cAAW,MAAM,CAAC,IAAI,GAAG,QAAgB,WAAsB,WAAU,QAAO,GACnF;AAEJ;AAIA,SAAS,UAAU,EAAE,KAAK,GAA0B;AAClD,QAAM,SAAS,KAAK,WAAW,gBAAgB;AAC/C,SACE,gBAAAC,OAAC,SAAI,WAAU,kEACb;AAAA,oBAAAD,MAAC,mBAAgB,WAAU,qBAAoB;AAAA,IAC/C,gBAAAC,OAAC,UAAK,WAAU,WAAW;AAAA;AAAA,MAAO;AAAA,OAAkC;AAAA,KACtE;AAEJ;AAEA,SAASS,cAAa;AAAA,EACpB;AAAA,EACA;AACF,GAGG;AACD,SACE,gBAAAV,MAAC,SAAI,WAAU,wEACX,WAAC,WAAW,OAAO,EAAY,IAAI,CAAC,UACpC,gBAAAA;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,SAAS,KAAK;AAAA,MAC7B,WAAW;AAAA,QACT;AAAA,QACA,WAAW,QACP,iCACA;AAAA,MACN;AAAA,MAEC;AAAA;AAAA,IAVI;AAAA,EAWP,CACD,GACH;AAEJ;;;ADxI8B,gBAAAY,OA4QtB,QAAAC,cA5QsB;AAxWvB,IAAM,wBAAwB;AAC9B,IAAM,sBAAsB;AAEnC,SAAS,uBAAuB,QAAwB;AACtD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAcO,SAAS,oBACd,QACA,UACQ;AACR,MAAI,SAAU,QAAO;AACrB,MAAI,UAAU;AACd,MAAI,gBAAgB;AACpB,aAAW,SAAS,UAAU,CAAC,GAAG;AAChC,QAAI,MAAM,SAAS,8BAA+B;AAClD,QAAI,MAAM,YAAY,QAAS;AAC/B,UAAM,QAAS,MAAM,SAAuD;AAC5E,cAAU,MAAM;AAChB,oBAAgB,OAAO,OAAO,cAAc,WAAW,MAAM,YAAY;AAAA,EAC3E;AACA,SAAO,gBAAgB,IAAI,wBAAwB;AACrD;AAQA,SAAS,yBAAyB,QAAiC;AACjE,MAAI,WAAW;AACf,aAAW,SAAS,QAAQ;AAC1B,QACE,MAAM,SAAS,+BACf,MAAM,SAAS,iCACf,MAAM,SAAS,4BACf;AACA;AAAA,IACF;AACA,UAAM,UAAU,MAAM;AACtB,UAAM,OACJ,WAAW,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,IAC3D,QAAoC,OACrC;AACN,QAAI,SAAS,oBAAqB;AAClC,QAAI,MAAM,SAAS,6BAA6B;AAC9C,iBAAW;AAAA,IACb,OAAO;AACL,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AA6CA,SAAS,iBAAiB,WAAuC;AAC/D,SAAO;AAAA,IACL;AAAA,IACA,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,EACZ;AACF;AAOO,SAAS,wBACd,SAC+B;AAC/B,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,EAAE,WAAW,QAAQ,SAAS,IAAI;AACxC,QAAM,aAAa,QAAQ,cAAc;AAOzC,QAAM,CAAC,mBAAmB,oBAAoB,IAAIC;AAAA,IAA6B,MAC7E,iBAAiB,SAAS;AAAA,EAC5B;AACA,QAAM,cACJ,kBAAkB,cAAc,YAAY,oBAAoB,iBAAiB,SAAS;AAC5F,QAAM,EAAE,cAAc,cAAc,SAAS,IAAI;AACjD,QAAM,oBAAoBC;AAAA,IACxB,CAAC,WAA2D;AAC1D,2BAAqB,CAAC,aAAa;AACjC,cAAM,UAAU,SAAS,cAAc,YAAY,WAAW,iBAAiB,SAAS;AACxF,eAAO,QAAQ,MAAM,IAAI,UAAU,EAAE,GAAG,SAAS,CAAC,MAAM,GAAG,KAAK;AAAA,MAClE,CAAC;AAAA,IACH;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAIA,QAAM,WAAW,YAAY;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,EAClB,CAAC;AACD,QAAM,gBACJ,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,cAAc,SAAS,eAAe,KACtE,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,MAAM,KACtC;AAEF,QAAM,OAAO,uBAAuB,WAAW;AAAA,IAC7C;AAAA,IACA,eAAe;AAAA,IACf,gBAAgB;AAAA;AAAA;AAAA,IAGhB,aAAa;AAAA,EACf,CAAC;AACD,QAAM,eAAe,KAAK;AAC1B,QAAM,WAAW,cAAc;AAC/B,QAAM,eAAe,cAAc,WAAW,aAAa;AAO3D,QAAM,aAAa,cAAc,WAAW,YAAY;AACxD,QAAM,gBAAgB,gBAAgB,CAAC;AACvC,QAAM,QAAQ,cAAc,IAAI,aAAa;AAC7C,QAAM,cAAc,cAAc,SAAS,aAAa,UAAU;AAIlE,QAAM,YACJ,cAAc,SAAS,cAAc,YAAY,QAAQ,cAAc,SAAS,GAAG;AACrF,QAAM,cAAc,cAAc,SAAS,cAAc,UAAU,CAAC;AACpE,QAAM,WAAW,mBAAmB,WAAW;AAAA,IAC7C;AAAA,IACA,aAAa;AAAA,IACb;AAAA,EACF,CAAC;AACD,QAAM,qBACH,cAAc,cAAc,aAAa,UAAU,QACpD,cAAc,cAAc,WAAW;AAQzC,QAAM,eAAe,yBAAyB,MAAM;AACpD,QAAM,cAAc,KAAK;AACzB,QAAM,kBAAkBC,SAAO,EAAE,WAAW,aAAa,CAAC;AAC1D,EAAAC,YAAU,MAAM;AACd,UAAM,WAAW,gBAAgB;AACjC,QAAI,SAAS,cAAc,aAAa,SAAS,gBAAgB,CAAC,cAAc;AAC9E,kBAAY;AAAA,IACd;AACA,oBAAgB,UAAU,EAAE,WAAW,aAAa;AAAA,EACtD,GAAG,CAAC,WAAW,cAAc,WAAW,CAAC;AAKzC,QAAM,eAAe,oBAAoB,WAAW,EAAE,OAAO,CAAC;AAC9D,QAAM,mBAAmB,aAAa;AACtC,QAAM,gCAAgCD,SAGnC;AAAA,IACD;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AACD,MAAI,8BAA8B,QAAQ,cAAc,WAAW;AACjE,kCAA8B,UAAU,EAAE,WAAW,QAAQ,KAAK;AAAA,EACpE;AACA,EAAAC,YAAU,MAAM;AACd,UAAM,SAAS,aAAa;AAC5B,QAAI,CAAC,UAAU,8BAA8B,QAAQ,WAAW,OAAQ;AACxE,kCAA8B,UAAU,EAAE,WAAW,OAAO;AAC5D,eAAW,EAAE,MAAM,SAAS,SAAS,uBAAuB,MAAM,EAAE,CAAC;AAAA,EACvE,GAAG,CAAC,WAAW,aAAa,gBAAgB,QAAQ,CAAC;AAErD,QAAM,QAAQ,gBAAgB,WAAW;AAAA,IACvC;AAAA,IACA,SAAS,gBAAgB;AAAA,IACzB;AAAA,IACA,SAAS,aAAa;AAAA;AAAA;AAAA,IAGtB,iBAAiB,CAAC,OAAO,OACvB,WAAW;AAAA,MACT,MAAM;AAAA,MACN,SAAS,aAAa,EAAE,KAAK,MAAM,OAAO;AAAA,IAC5C,CAAC;AAAA,EACL,CAAC;AACD,QAAM,MAAM,cAAc,WAAW;AAAA,IACnC;AAAA,IACA,SAAS,SAAS;AAAA,IAClB;AAAA,IACA,SAAS,aAAa;AAAA,EACxB,CAAC;AACD,QAAM,YAAY,cAAc,WAAW;AAAA,IACzC;AAAA,IACA,SAAS;AAAA,IACT,QAAQ;AAAA,IACR;AAAA,IACA,SAAS,aAAa;AAAA,EACxB,CAAC;AAID,QAAM,CAAC,YAAY,aAAa,IAAIH,WAAiC,MAAS;AAC9E,EAAAG,YAAU,MAAM;AACd,QAAI,OAAO,aAAa,YAAa;AACrC,UAAM,SAAS,MAAM,cAAc,qBAAqB,CAAC;AACzD,WAAO;AACP,UAAM,WAAW,IAAI,iBAAiB,MAAM;AAC5C,aAAS,QAAQ,SAAS,iBAAiB;AAAA,MACzC,YAAY;AAAA,MACZ,iBAAiB,CAAC,iBAAiB,OAAO;AAAA,IAC5C,CAAC;AACD,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAEL,iBAAe,sBAAsB;AACnC,QAAI;AACF,YAAM,SAAS,cAAc,cAAc,UAAU;AACrD,YAAM,OAAO,kBAAkB,aAAa,WAAW;AAAA,QACrD,uBAAuB;AAAA,QACvB,mBAAmB;AAAA,MACrB,CAAC;AACD,wBAAkB,cAAc;AAChC,WAAK,YAAY;AAAA,IACnB,SAAS,OAAO;AACd,iBAAW;AAAA,QACT,MAAM;AAAA,QACN,SAAS,uCAAuC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACxG,CAAC;AAAA,IACH;AAAA,EACF;AAIA,WAAS,gBAAgB;AACvB,QAAI,CAAC,aAAc,mBAAkB,cAAc;AACnD,SAAK,YAAY;AAAA,EACnB;AAEA,QAAM,aAAa,IAAI,KAAK;AAI5B,QAAM,OAAO,eAAe;AAAA,IAC1B;AAAA,IACA,mBAAmB,KAAK;AAAA,IACxB,oBAAoB,eAAe,SAAS;AAAA,IAC5C,oBAAoB,eAAe,SAAS;AAAA,IAC5C,WAAW,gBAAgB,gBAAgB;AAAA,IAC3C,YAAY,aAAa;AAAA,EAC3B,CAAC;AAUD,QAAM,gBAAgBD,SAAoD;AAAA,IACxE;AAAA,IACA,OAAO;AAAA,EACT,CAAC;AACD,MAAI,cAAc,QAAQ,cAAc,WAAW;AACjD,kBAAc,UAAU,EAAE,WAAW,OAAO,KAAK;AAAA,EACnD;AACA,MAAI,cAAc,QAAQ,UAAU,MAAM;AACxC,QAAI,YAAY;AACd,oBAAc,QAAQ,QAAQ;AAAA,IAChC,WAAW,aAAa,cAAc,MAAM;AAC1C,oBAAc,QAAQ,QACpB,aAAa,YAAY,IAAI,wBAAwB;AAAA,IACzD;AAAA,EACF;AAEA,QAAM,aAAa,cAAc,QAAQ;AAEzC,QAAM,OAAOE,UAAQ,MAAM;AACzB,UAAM,OAAuB,CAAC;AAK9B,SAAK,KAAK;AAAA,MACR,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,OAAO,aAAa,IAAI,gBAAAN,MAAC,cAAW,OAAO,YAAY,IAAK;AAAA,MAC5D,SACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,iBAAiB,aAAa;AAAA,UAC9B,mBAAmB,KAAK;AAAA,UACxB,mBAAmB,KAAK;AAAA,UACxB,SAAS,KAAK;AAAA;AAAA,MAChB;AAAA,IAEJ,CAAC;AAGD,SAAK,KAAK;AAAA,MACR,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,SACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA,qBAAqB,gBAAgB;AAAA,UACrC,UAAU;AAAA,UAGV,cAAc,MAAM,kBAAkB,UAAU;AAAA,UAChD,WAAU;AAAA;AAAA,MACZ;AAAA,IAEJ,CAAC;AAGD,QAAI,YAAY;AACd,WAAK,KAAK;AAAA,QACR,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,SACE,gBAAAA,MAAC,SAAI,WAAU,uBACb,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC,QAAQ;AAAA,YACR,oBAAoB,cAAc,YAAY;AAAA,YAC9C,YAAY,MAAM,kBAAkB,cAAc;AAAA,YAClD,YAAU;AAAA,YACV,OAAO,cAAc,SAAS,SAAS;AAAA,YACvC;AAAA,YACC,GAAI,aAAa,EAAE,OAAO,WAAW,IAAI,CAAC;AAAA;AAAA,QAC7C,GACF;AAAA,MAEJ,CAAC;AAAA,IACH;AAGA,QAAI,mBAAmB;AACrB,WAAK,KAAK;AAAA,QACR,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,OAAO,eACL,gBAAAA,MAAC,UAAK,WAAU,8EAA6E,kBAE7F,IACE;AAAA,QACJ,SACE,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,YAAY,cAAc,iBAAiB;AAAA,YAC3C,kBAAkB,KAAK;AAAA,YACvB,UAAU;AAAA,YACV,eAAe,MAAM,KAAK,oBAAoB;AAAA,YAC9C,QAAQ;AAAA,YACR,WAAU;AAAA;AAAA,QACZ;AAAA,MAEJ,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EAET,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA,SAAS,SAAS;AAAA,MAClB,OAAO,SAAS;AAAA,MAChB,SAAS,SAAS;AAAA,IACpB;AAAA,EACF;AACF;AAoCO,SAAS,iBAAiB,OAAyC;AACxE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM;AAAA,IACJ,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,IAAI,wBAAwB;AAAA,IAC1B,GAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,IAC/C,GAAI,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;AAAA,IAC9D;AAAA,IACA;AAAA,IACA,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,IACnC,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,EACjC,CAAC;AAOD,QAAM,OAAuB,CAAC,GAAI,eAAe,CAAC,GAAI,GAAG,eAAe,GAAI,gBAAgB,CAAC,CAAE;AAC/F,QAAM,CAAC,iBAAiB,kBAAkB,IAAIE,WAGpC,IAAI;AACd,QAAM,cAAc,iBAAiB,cAAc,YAAY,gBAAgB,MAAM;AACrF,QAAM,YAAY,eAAe,cAAc,KAAK,CAAC,GAAG;AACxD,QAAM,YAAYC;AAAA,IAChB,CAAC,QAAgB,mBAAmB,EAAE,WAAW,IAAI,CAAC;AAAA,IACtD,CAAC,SAAS;AAAA,EACZ;AAEA,SACE,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACC,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MAChD,mBAAmB;AAAA,MACnB,iBACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,QAAQ;AAAA,UACd,eAAe,QAAQ;AAAA,UACvB,OAAO,QAAQ;AAAA,UACf,SAAS,MAAM,KAAK,QAAQ,QAAQ;AAAA;AAAA,MACtC;AAAA,MAED,GAAI,yBAAyB,SAAY,EAAE,qBAAqB,IAAI,CAAC;AAAA,MACrE,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MAC/C,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;AAAA,MACjD,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,MACjD,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,MACnD,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC3C,GAAI,YAAY,SAAY,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC3C,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;AAAA;AAAA,EAClD;AAEJ;AAKA,SAAS,WAAW,EAAE,MAAM,GAAsB;AAChD,SACE,gBAAAA,MAAC,UAAK,WAAU,kEAAkE,iBAAM;AAE5F;AAGA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AACF,GAGG;AACD,QAAM,OAAO,SAAS,eAAe,aAAa;AAClD,SAAO,gBAAAA,MAAC,QAAK,WAAW,GAAG,uCAAuC,SAAS,GAAG,eAAW,MAAC;AAC5F;AAEA,SAAS,aAAa,OAAqC;AACzD,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,SAAU,QAAO;AAC/B,SAAO;AACT;AASA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,gBAAAC,OAAC,QAAQ,MAAR,EACC;AAAA,oBAAAD,MAAC,QAAQ,SAAR,EAAgB,SAAO,MACtB,0BAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY,YAAY,KAAK,KAAK;AAAA,QAClC,WAAU;AAAA,QAEV;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,GAAG,kCAAkC,aAAa,KAAK,KAAK,CAAC;AAAA,cACxE,eAAW;AAAA;AAAA,UACb;AAAA,UACA,gBAAAA,MAAC,UAAK,WAAU,0BAA0B,eAAK,OAAM;AAAA;AAAA;AAAA,IACvD,GACF;AAAA,IACA,gBAAAA,MAAC,QAAQ,QAAR,EAAe,YAAU,MACxB,0BAAAC;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACC,YAAU;AAAA,QACV,OAAM;AAAA,QACN,YAAY;AAAA,QACZ,WAAU;AAAA,QAEV;AAAA,0BAAAA,OAAC,SAAI,WAAU,qCACb;AAAA,4BAAAD,MAAC,mBAAgB,MAAM,eAAe,MAAM;AAAA,YAC5C,gBAAAA,MAAC,UAAK,WAAU,gCAAgC,yBAAe,QAAQ,WAAU;AAAA,aACnF;AAAA,UACA,gBAAAC,OAAC,SAAI,WAAU,kDACb;AAAA,4BAAAD,MAAC,UAAK,WAAU,gCAA+B,wBAAU;AAAA,YACxD,gBACC,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,QAAQ,yBAAyB,cAAc,KAAK;AAAA,gBACpD,MAAK;AAAA;AAAA,YACP,IAEA,gBAAAA,MAAC,UAAK,WAAU,+BAA+B,eAAK,OAAM;AAAA,aAE9D;AAAA,UACC,KAAK,OACJ,gBAAAC,OAAC,OAAE,WAAU,iDAAgD;AAAA;AAAA,YACpC,WAAW,KAAK,MAAM,KAAK,IAAI,CAAC;AAAA,YAAE;AAAA,aAC3D,IACE;AAAA,UACH,iBAAiB,cAAc,qBAAqB,IACnD,gBAAAD,MAAC,SAAI,WAAU,UACb,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,oBAAoB,cAAc;AAAA,cAClC,SAAQ;AAAA;AAAA,UACV,GACF,IACE;AAAA,UACH,QACC,gBAAAC,OAAC,SAAI,WAAU,uDACb;AAAA,4BAAAD,MAAC,OAAE,WAAU,8CAA6C,0DAE1D;AAAA,YACA,gBAAAC,OAAC,oBAAiB,SAAS,SACzB;AAAA,8BAAAD,MAACO,gBAAA,EAAc,WAAU,UAAS;AAAA,cAAE;AAAA,eAEtC;AAAA,aACF,IACE;AAAA;AAAA;AAAA,IACN,GACF;AAAA,KACF;AAEJ;AAGA,SAAS,iBAAiB,EAAE,SAAS,SAAS,GAAiD;AAC7F,SACE,gBAAAP;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,WAAU;AAAA,MAET;AAAA;AAAA,EACH;AAEJ;AAQA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,OAAO,IAAI;AAEjB,MAAI,KAAK,SAAS,GAAG;AACnB,WACE,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,QAAQ,IAAI;AAAA,QACZ,YAAY,IAAI;AAAA,QAChB;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,MAAI,qBAAqB,CAAC,kBAAkB;AAC1C,WACE,gBAAAC,OAAC,iBACC;AAAA,sBAAAD,MAAC,OAAE,WAAU,qCAAoC,iCAAmB;AAAA,MACpE,gBAAAA,MAAC,OAAE,WAAU,yCACV,4BAAkB,WAAW,gDAChC;AAAA,MACA,gBAAAC,OAAC,oBAAiB,SAAS,SACzB;AAAA,wBAAAD,MAACO,gBAAA,EAAc,WAAU,UAAS;AAAA,QAAE;AAAA,SAEtC;AAAA,OACF;AAAA,EAEJ;AAEA,OAAK,sBAAsB,iBAAiB,sBAAsB,WAAW,CAAC,kBAAkB;AAC9F,WACE,gBAAAP,MAAC,iBACC,0BAAAA,MAAC,OAAE,WAAU,+BAA8B,sCAAmB,GAChE;AAAA,EAEJ;AAEA,SACE,gBAAAC,OAAC,iBACC;AAAA,oBAAAD,MAAC,OAAE,WAAU,qCAAoC,4BAAc;AAAA,IAC/D,gBAAAA,MAAC,OAAE,WAAU,0CAAyC,gEAEtD;AAAA,KACF;AAEJ;AAEA,SAAS,cAAc,EAAE,SAAS,GAA4B;AAC5D,SACE,gBAAAA,MAAC,SAAI,WAAU,kDACb,0BAAAA,MAAC,SAAI,WAAU,+CAA+C,UAAS,GACzE;AAEJ;;;AGtzBA,SAAS,eAAAQ,eAAa,YAAAC,kBAAgB;AAgB/B,SAAS,oBAAoB,OAA4C;AAC9E,SAAO,MAAM,SAAS,4BAA4B,MAAM,SAAS;AACnE;AA8DA,IAAM,iBAAwC;AAAA,EAC5C,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,oBAAoB;AACtB;AAUA,IAAM,cAAkC;AAAA,EACtC,UAAU,CAAC;AAAA,EACX,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,eAAe;AACjB;AASO,SAAS,iBAAiB,UAAmC,CAAC,GAA2B;AAC9F,QAAM,EAAE,QAAQ,YAAY,IAAI,YAAY,OAAO;AACnD,QAAM,cAAc,QAAQ,eAAgB;AAC5C,QAAM,YAAY,QAAQ;AAC1B,QAAM,eAAe,QAAQ;AAE7B,QAAM,OAAOC,cAAY,YAAyC;AAChE,UAAM,YAAY,YAAY,kBAAkB,WAAW;AAC3D,UAAM,WACJ,aAAa,YAAY,aACrB,YAAY,WAAW,aAAa,SAAS,EAAE,MAAM,MAAM,IAAI,IAC/D,QAAQ,QAAQ,IAAI;AAC1B,UAAM,CAAC,KAAK,OAAO,IAAI,MAAM,QAAQ,IAAI,CAAC,WAAW,QAAQ,CAAC;AAC9D,WAAO;AAAA,MACL,UAAU,IAAI;AAAA,MACd,iBAAiB,IAAI;AAAA,MACrB,UAAU,IAAI;AAAA,MACd,iBAAiB,SAAS,2BAA2B;AAAA,MACrD,eAAe,SAAS,yBAAyB;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,aAAa,aAAa,SAAS,CAAC;AAExC,QAAM;AAAA,IACJ,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF,IAAI,eAAe,MAAM;AAAA,IACvB,gBAAgB,QAAQ;AAAA,IACxB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,EAAE,KAAK,aAAa,UAAU,SAAS,cAAc,IAAI,kBAAkB;AACjF,QAAM,EAAE,KAAK,kBAAkB,UAAU,gBAAgB,IAAI,kBAAkB;AAC/E,QAAM,CAAC,eAAe,gBAAgB,IAAIC,WAAwB,IAAI;AAItE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,KAAK,QAAQ;AAAA,IACnB;AAAA,MACE,SAAS,QAAQ,WAAW;AAAA,MAC5B,GAAI,iBAAiB,SAAY,EAAE,QAAQ,aAAa,IAAI,CAAC;AAAA,IAC/D;AAAA,EACF;AAEA,QAAM,MAAMD;AAAA,IACV,OAAO,WAAqC;AAC1C,UAAI,CAAC,aAAa,CAAC,YAAY,wBAAwB;AACrD,eAAO;AAAA,MACT;AACA,uBAAiB,MAAM;AACvB,YAAM,SAAS,MAAM,YAAY,YAAY;AAC3C,cAAM,YAAY,uBAAwB,aAAa,WAAW,MAAM;AACxE,eAAO;AAAA,MACT,CAAC;AACD,uBAAiB,IAAI;AACrB,UAAI,OAAQ,OAAM,QAAQ;AAC1B,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,CAAC,aAAa,aAAa,WAAW,aAAa,OAAO;AAAA,EAC5D;AAKA,QAAM,eAAeA,cAAY,YAA8B;AAC7D,QAAI,CAAC,YAAY,mBAAmB;AAClC,aAAO;AAAA,IACT;AACA,UAAM,SAAS,MAAM,iBAAiB,YAAY;AAChD,YAAM,YAAY,kBAAmB,WAAW;AAChD,aAAO;AAAA,IACT,CAAC;AACD,QAAI,OAAQ,OAAM,QAAQ;AAC1B,WAAO,WAAW;AAAA,EACpB,GAAG,CAAC,aAAa,aAAa,kBAAkB,OAAO,CAAC;AAExD,QAAM,OAAO,cAAc;AAC3B,QAAM,qBAAqB,KAAK,mBAAmB,KAAK;AAExD,SAAO;AAAA,IACL,UAAU,KAAK;AAAA,IACf,iBAAiB,KAAK;AAAA,IACtB,iBAAiB,KAAK;AAAA,IACtB;AAAA,IACA,eAAe,KAAK;AAAA,IACpB,UAAU,KAAK;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["useCallback","useEffect","useMemo","useRef","useState","CameraIcon","CameraOffIcon","useState","createContext","useCallback","useContext","useState","jsx","createContext","useContext","useState","useCallback","Fragment","jsx","jsxs","useState","useState","useState","useEffect","useState","jsx","useState","useEffect","jsx","jsxs","useState","jsx","jsxs","file","CameraIcon","CameraOffIcon","createContext","useContext","Fragment","jsx","jsxs","ChevronRightIcon","useState","Collapsible","jsx","jsxs","useState","Collapsible","ChevronRightIcon","useState","useRef","useEffect","window","useCallback","useMemo","asRecord","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useCallback","useRef","useState","useState","useRef","useCallback","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useEffect","useRef","useCallback","useRef","useEffect","useCallback","useMemo","useCallback","useMemo","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","OpenGeniApiError","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","OpenGeniApiError","useEffect","useRef","useState","useEffect","useRef","useState","useState","useRef","useEffect","useEffect","useMemo","useRef","useState","OpenGeniApiError","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useEffect","useMemo","OpenGeniApiError","useCallback","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","isLive","useEffect","useCallback","useEffect","useRef","useState","isLive","useState","useRef","useCallback","useEffect","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useEffect","useRef","useState","useState","useRef","useEffect","useCallback","useMemo","useCallback","useMemo","useRef","useState","useState","useRef","useMemo","useCallback","errorMessage","AnimatePresence","motion","jsx","jsxs","AnimatePresence","motion","ImageIcon","XIcon","AnimatePresence","motion","useCallback","useEffect","useId","useMemo","useRef","useState","useMemo","jsx","jsxs","useMemo","Fragment","jsx","jsxs","useRef","useState","useCallback","useId","useEffect","useMemo","AnimatePresence","motion","ImageIcon","XIcon","ArrowRightIcon","BotIcon","CheckIcon","ChevronRightIcon","PlayIcon","TriangleAlertIcon","AnimatePresence","motion","Collapsible","useCallback","useEffect","useMemo","useRef","useState","jsx","jsx","jsxs","Fragment","jsx","jsxs","useMemo","useRef","useState","useCallback","useEffect","AnimatePresence","motion","BotIcon","ArrowRightIcon","Collapsible","ChevronRightIcon","CheckIcon","PlayIcon","TriangleAlertIcon","jsx","jsxs","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","ChevronRightIcon","FileIcon","RefreshCwIcon","Trash2Icon","useCallback","useEffect","useLayoutEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","useEffect","useLayoutEffect","parentOf","useState","useRef","useCallback","useMemo","ChevronRightIcon","FileIcon","Trash2Icon","RefreshCwIcon","jsx","lazy","Suspense","useEffect","useState","jsx","lazy","useState","useEffect","Suspense","lazy","Suspense","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","lazy","useState","useRef","useEffect","useCallback","useMemo","Suspense","useCallback","useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","LoaderCircleIcon","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","LoaderCircleIcon","useCallback","useEffect","useId","useLayoutEffect","useRef","useState","XIcon","Fragment","jsx","jsxs","useEffect","useLayoutEffect","useState","useCallback","XIcon","useId","useRef","useCallback","useEffect","useMemo","useRef","useState","RefreshCwIcon","useCallback","useEffect","useId","useLayoutEffect","useMemo","useRef","useState","VList","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useEffect","useLayoutEffect","STATUS_TINT","useRef","useState","useId","useMemo","useCallback","LayoutToggle","VList","jsx","jsxs","useState","useCallback","useRef","useEffect","useMemo","RefreshCwIcon","useCallback","useState","useCallback","useState"]}