@opengeni/react 3.7.0-canary.7 → 3.8.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/chat.js +1 -1
- package/dist/chunk-5M6VTFJ5.js +171 -0
- package/dist/chunk-5M6VTFJ5.js.map +1 -0
- package/dist/{chunk-IOLVN74D.js → chunk-6J56T3MG.js} +15 -1
- package/dist/chunk-6J56T3MG.js.map +1 -0
- package/dist/{chunk-BQGIXRKV.js → chunk-7BWFU6H4.js} +22 -4
- package/dist/chunk-7BWFU6H4.js.map +1 -0
- package/dist/{chunk-3HIF5IFC.js → chunk-7W6PVVTK.js} +63 -18
- package/dist/chunk-7W6PVVTK.js.map +1 -0
- package/dist/{chunk-ZFOFY5ST.js → chunk-NLTS7JHI.js} +16 -31
- package/dist/chunk-NLTS7JHI.js.map +1 -0
- package/dist/chunk-NOSYBS2D.js +208 -0
- package/dist/chunk-NOSYBS2D.js.map +1 -0
- package/dist/{chunk-F2CFHN3Y.js → chunk-YAIPFO5D.js} +2 -1
- package/dist/chunk-YAIPFO5D.js.map +1 -0
- package/dist/chunk-YBM6CQRU.js +292 -0
- package/dist/chunk-YBM6CQRU.js.map +1 -0
- package/dist/chunk-ZYRGEKWS.js +216 -0
- package/dist/chunk-ZYRGEKWS.js.map +1 -0
- package/dist/components/composer.d.ts +4 -2
- package/dist/components/message-timeline.d.ts +9 -2
- package/dist/components/timeline-annotation-chrome.d.ts +25 -0
- package/dist/components/timeline-annotation-layout.d.ts +42 -0
- package/dist/components/timeline-annotation-markers.d.ts +8 -0
- package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
- package/dist/components/timeline-annotation-shared.d.ts +31 -0
- package/dist/components/timeline-annotations-dialog.d.ts +1 -1
- package/dist/components/timeline-annotations.d.ts +8 -2
- package/dist/composer.js +2 -2
- package/dist/hooks/use-composer.d.ts +2 -0
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +6 -6
- package/dist/machines.js +1 -1
- package/dist/{queue-surface-implementation-XL2A6PBM.js → queue-surface-implementation-LK3S4BIW.js} +5 -2
- package/dist/{queue-surface-implementation-XL2A6PBM.js.map → queue-surface-implementation-LK3S4BIW.js.map} +1 -1
- package/dist/session-ui.js +8 -5
- package/dist/session.js +1 -1
- package/dist/timeline-annotation-markers-DRSTLEM6.js +165 -0
- package/dist/timeline-annotation-markers-DRSTLEM6.js.map +1 -0
- package/dist/timeline-annotation-selection-IHLUGVND.js +236 -0
- package/dist/timeline-annotation-selection-IHLUGVND.js.map +1 -0
- package/dist/timeline-annotations-dialog-6Q53N5FG.js +262 -0
- package/dist/timeline-annotations-dialog-6Q53N5FG.js.map +1 -0
- package/package.json +2 -2
- package/src/components/chat-composer.tsx +5 -2
- package/src/components/composer.tsx +40 -5
- package/src/components/copy-button.tsx +1 -0
- package/src/components/machines-dashboard.tsx +1 -16
- package/src/components/message-timeline.tsx +357 -297
- package/src/components/timeline-annotation-chrome.tsx +183 -0
- package/src/components/timeline-annotation-layout.ts +268 -0
- package/src/components/timeline-annotation-markers.tsx +185 -0
- package/src/components/timeline-annotation-reveal-context.ts +9 -0
- package/src/components/timeline-annotation-selection.tsx +99 -54
- package/src/components/timeline-annotation-shared.ts +245 -0
- package/src/components/timeline-annotations-dialog.tsx +172 -128
- package/src/components/timeline-annotations.tsx +178 -45
- package/src/hooks/use-composer.ts +17 -0
- package/styles/compiled.css +86 -22
- package/dist/chunk-3HIF5IFC.js.map +0 -1
- package/dist/chunk-BQGIXRKV.js.map +0 -1
- package/dist/chunk-F2CFHN3Y.js.map +0 -1
- package/dist/chunk-IOLVN74D.js.map +0 -1
- package/dist/chunk-W3OUAH6M.js +0 -170
- package/dist/chunk-W3OUAH6M.js.map +0 -1
- package/dist/chunk-ZFOFY5ST.js.map +0 -1
- package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
- package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
- package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
- package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/use-video-artifact-playback.ts","../src/file-node-visibility.ts","../src/hooks/use-last-started-turn-policy.ts","../src/hooks/use-scheduled-tasks.ts","../src/hooks/use-workspace-sessions.ts","../src/hooks/use-session-background-commands.ts","../src/hooks/use-environments.ts","../src/hooks/use-channels.ts","../src/hooks/channel-cache.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-session-capabilities.ts","../src/lib/sandbox-liveness.ts","../src/lib/terminal-capability.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/components/approval-surface.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/lib/use-unicode-fonts.ts","../src/components/workbench-changes.tsx","../src/hooks/use-windowed-sections.ts","../src/components/diff-view.tsx","../src/components/pierre-file.tsx","../src/components/code-editor.tsx","../src/components/sandbox-files.tsx","../src/components/workspace-dock.tsx","../src/components/sandbox-workspace.tsx","../src/hooks/use-codex-accounts.ts","../src/hooks/use-supergrok-accounts.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { VideoArtifactPlaybackLoader } from \"../timeline\";\nimport { useOpenGeni, type ClientOverride } from \"../session-context\";\n\n/**\n * Bind the current public SDK client/workspace to MessageTimeline's renewable\n * video-source boundary. Proxy hosts may omit the method until they support\n * retained video; the failure remains local to the player instead of loading\n * any video bytes through React.\n */\nexport function useVideoArtifactPlaybackLoader(\n options: ClientOverride = {},\n): VideoArtifactPlaybackLoader {\n const { client, workspaceId } = useOpenGeni(options);\n return useMemo(\n () => async (artifactId: string, signal?: AbortSignal) => {\n if (typeof client.createVideoArtifactPlaybackSource !== \"function\") {\n throw new Error(\"This OpenGeni host does not expose retained-video playback.\");\n }\n return await client.createVideoArtifactPlaybackSource(\n workspaceId,\n artifactId,\n signal ? { signal } : {},\n );\n },\n [client, workspaceId],\n );\n}\n","import type { FileTreeNode } from \"./hooks/use-sandbox-files\";\n\nexport type FileNodeVisibilityContext = {\n depth: number;\n parent: FileTreeNode | null;\n};\n\n/** Presentation-only predicate. It never changes filesystem authorization. */\nexport type FileNodeVisibilityPredicate = (\n node: FileTreeNode,\n context: FileNodeVisibilityContext,\n) => boolean;\n\nexport type FilePathVisibility = \"visible\" | \"hidden\" | \"unknown\";\n\nfunction pathIsInsideDirectory(path: string, directory: string): boolean {\n if (!path.startsWith(directory) || path === directory) return false;\n if (directory.endsWith(\"/\") || directory.endsWith(\"\\\\\")) return true;\n const boundary = path[directory.length];\n return boundary === \"/\" || boundary === \"\\\\\";\n}\n\n/**\n * Filter an authoritative tree without promoting children of a hidden parent.\n * Undefined children stay undefined so lazy-loading semantics are preserved.\n */\nexport function visibleFileTree(\n nodes: FileTreeNode[],\n predicate?: FileNodeVisibilityPredicate,\n parent: FileTreeNode | null = null,\n depth = 0,\n): FileTreeNode[] {\n if (!predicate) return nodes;\n const visible: FileTreeNode[] = [];\n for (const node of nodes) {\n if (!predicate(node, { depth, parent })) continue;\n visible.push(\n node.children === undefined\n ? node\n : {\n ...node,\n children: visibleFileTree(node.children, predicate, node, depth + 1),\n },\n );\n }\n return visible;\n}\n\n/** Resolve only what the currently loaded tree can prove. */\nexport function filePathVisibility(\n nodes: FileTreeNode[],\n path: string,\n predicate?: FileNodeVisibilityPredicate,\n parent: FileTreeNode | null = null,\n depth = 0,\n): FilePathVisibility {\n if (!predicate) return \"visible\";\n for (const node of nodes) {\n if (node.path !== path && !pathIsInsideDirectory(path, node.path)) continue;\n if (!predicate(node, { depth, parent })) return \"hidden\";\n if (node.path === path) return \"visible\";\n if (node.kind !== \"dir\" || node.children === undefined) return \"unknown\";\n return filePathVisibility(node.children, path, predicate, node, depth + 1);\n }\n return \"unknown\";\n}\n","import type { LatencyMode, ReasoningEffort, SessionEvent, SessionTurn } from \"@opengeni/sdk\";\nimport { useCallback, useEffect } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../session-context\";\nimport { usePolledValue, useSessionEventTrigger, type SessionEventFeedOptions } from \"./internal\";\n\n/** Refresh when a turn actually admits — not on composer picker / queue-only changes. */\nexport function isLastStartedTurnPolicyEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type === \"turn.started\";\n}\n\nexport type LastStartedTurnPolicy = {\n model: string;\n reasoningEffort: ReasoningEffort;\n latencyMode: LatencyMode;\n turnId: string;\n};\n\nexport type UseLastStartedTurnPolicyOptions = ClientOverride &\n SessionEventFeedOptions & {\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseLastStartedTurnPolicyResult = {\n /** Null until some turn has durably emitted `turn.started`. */\n policy: LastStartedTurnPolicy | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\nfunction policyFromTurn(turn: SessionTurn | null | undefined): LastStartedTurnPolicy | null {\n if (!turn) return null;\n return {\n model: turn.model,\n reasoningEffort: turn.reasoningEffort,\n latencyMode: turn.latencyMode,\n turnId: turn.id,\n };\n}\n\n/**\n * Model·effort·latency of the newest admitted turn (`turn.started`). This is\n * historical runtime truth for the session header — not the composer next-turn\n * picker and not the frozen session creation defaults.\n */\nexport function useLastStartedTurnPolicy(\n sessionId: string | null | undefined,\n options: UseLastStartedTurnPolicyOptions = {},\n): UseLastStartedTurnPolicyResult {\n const { client, workspaceId, workspaceControlEvent, registerSessionReconciler } =\n useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n\n const load = useCallback(\n async (signal?: AbortSignal): Promise<LastStartedTurnPolicy | null> => {\n if (!sessionId) return null;\n const turns = await client.listTurns(workspaceId, sessionId, {\n latestStarted: true,\n signal,\n });\n return policyFromTurn(turns[0]);\n },\n [client, workspaceId, sessionId],\n );\n\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled,\n });\n\n useEffect(() => {\n if (enabled && workspaceControlEvent) void refresh();\n }, [enabled, refresh, workspaceControlEvent]);\n\n useEffect(() => {\n if (!sessionId || !enabled) return;\n return registerSessionReconciler(sessionId, \"last-started-turn-policy\", refresh);\n }, [enabled, refresh, registerSessionReconciler, sessionId]);\n\n // Shared-feed only: the session header lives outside the route event log and\n // must not open a second SSE. Without `events`, rely on the initial fetch +\n // optional poll / workspace-control / reconciler.\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isLastStartedTurnPolicyEvent,\n () => void refresh(),\n {\n events: options.events,\n enabled: enabled && options.events !== undefined,\n },\n );\n\n return {\n policy: enabled ? data : null,\n loading,\n error,\n refresh,\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, useEffect, useRef } 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 /** Return only the complete personal pinned projection. */\n pinsOnly?: boolean | undefined;\n archivedOnly?: boolean | undefined;\n /** Refresh interval (ms) for fleet/manager views. Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n /** Optional shared causal clock invoked when each network read starts. */\n beginRead?: (() => number) | 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 /** True when the server omitted older pins from its bounded pinned section. */\n pinnedTruncated: boolean;\n nextCursor: string | null;\n loading: boolean;\n error: Error | null;\n /** Monotonic revision of accepted authoritative list-page reads. */\n readRevision: number;\n /** Causal generation captured when the accepted network read started. */\n readGeneration: number;\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 pinsOnly = options.pinsOnly;\n const archivedOnly = options.archivedOnly;\n const enabled = options.enabled ?? true;\n const nextReadRevision = useRef(0);\n const nextReadGeneration = useRef(0);\n const beginRead = options.beginRead;\n const queryKey = [\n workspaceId,\n limit ?? \"\",\n parentSessionId === null ? \"null\" : (parentSessionId ?? \"\"),\n cursor ?? \"\",\n search ?? \"\",\n pinsOnly ? \"1\" : \"\",\n archivedOnly ? \"archived\" : \"active\",\n ].join(\"\\u0000\");\n const previousQueryKey = useRef(queryKey);\n const queryKeyTransition = previousQueryKey.current !== queryKey;\n useEffect(() => {\n previousQueryKey.current = queryKey;\n }, [queryKey]);\n const load = useCallback(\n async (signal?: AbortSignal) => {\n const readGeneration = beginRead?.() ?? ++nextReadGeneration.current;\n const page = await client.listSessionPage(workspaceId, {\n ...(limit !== undefined ? { limit } : {}),\n ...(parentSessionId !== undefined ? { parentSessionId } : {}),\n ...(cursor !== undefined ? { cursor } : {}),\n ...(search !== undefined ? { search } : {}),\n ...(pinsOnly ? { pinsOnly: true } : {}),\n ...(archivedOnly ? { archivedOnly: true } : {}),\n signal,\n });\n return {\n queryKey,\n page,\n revision: ++nextReadRevision.current,\n readGeneration,\n };\n },\n [\n beginRead,\n client,\n workspaceId,\n limit,\n parentSessionId,\n cursor,\n search,\n pinsOnly,\n archivedOnly,\n queryKey,\n ],\n );\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n 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 pinnedTruncated: page?.pinnedTruncated ?? false,\n nextCursor: page?.nextCursor ?? null,\n // `usePolledValue` clears the old data and starts the new request in an\n // effect. During that query-key transition render, its old loading flag\n // can still be false; expose loading immediately so consumers do not\n // announce a transient false zero-match result.\n loading:\n enabled &&\n (state.loading ||\n queryKeyTransition ||\n (state.data !== null && state.data.queryKey !== queryKey)),\n error: state.error,\n readRevision: page ? (state.data?.revision ?? 0) : 0,\n readGeneration: page ? (state.data?.readGeneration ?? 0) : 0,\n refresh: state.refresh,\n };\n}\n","import type { SessionBackgroundCommand } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef } from \"react\";\n\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseSessionBackgroundCommandsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseSessionBackgroundCommandsResult = {\n commands: SessionBackgroundCommand[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n cancel: (commandId: string) => Promise<void>;\n};\n\nexport function useSessionBackgroundCommands(\n sessionId: string | null | undefined,\n options: UseSessionBackgroundCommandsOptions = {},\n): UseSessionBackgroundCommandsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const load = useCallback(\n async (signal?: AbortSignal) => {\n if (!sessionId) return { commands: [] };\n if (!client.listSessionBackgroundCommands) {\n throw new Error(\"The configured OpenGeni client does not support background commands\");\n }\n return await client.listSessionBackgroundCommands(workspaceId, sessionId, { signal });\n },\n [client, workspaceId, sessionId],\n );\n const state = usePolledValue(load, {\n enabled,\n pollIntervalMs: options.pollIntervalMs,\n });\n const refresh = state.refresh;\n const generation = useRef(0);\n useEffect(() => {\n generation.current += 1;\n return () => {\n generation.current += 1;\n };\n }, [client, workspaceId, sessionId, enabled]);\n const cancel = useCallback(\n async (commandId: string): Promise<void> => {\n if (!sessionId) return;\n if (!client.cancelSessionBackgroundCommand) {\n throw new Error(\"The configured OpenGeni client does not support background commands\");\n }\n const ticket = generation.current;\n await client.cancelSessionBackgroundCommand(workspaceId, sessionId, commandId);\n if (enabled && ticket === generation.current) await refresh();\n },\n [client, workspaceId, sessionId, refresh, enabled],\n );\n return {\n commands: state.data?.commands ?? [],\n loading: state.loading,\n error: state.error,\n refresh,\n cancel,\n };\n}\n","import type {\n CreateVariableSetRequest,\n UpdateVariableSetRequest,\n VariableSet,\n VariableSetSecret,\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 /**\n * Read one exact value through the dedicated permissioned API. The hook never\n * puts plaintext in its polled variable-set cache.\n */\n readVariable: (variableSetId: string, name: string) => Promise<VariableSetSecret | null>;\n /** Set/rotate a variable. Generic 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). Generic reads stay metadata-only. A dedicated,\n * permissioned method can retrieve one value and returns it directly without\n * adding plaintext to hook state or polling caches.\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 readVariable = useCallback(\n async (variableSetId: string, name: string): Promise<VariableSetSecret | null> =>\n await run(() => client.getVariableSetVariable(workspaceId, variableSetId, name)),\n [client, workspaceId, run],\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 readVariable,\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 & {\n environments: VariableSet[];\n};\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({\n ...options,\n ...(legacyClient ? { client: legacyClient } : {}),\n });\n return { ...result, environments: result.variableSets };\n}\n","import type { Channel, CreateChannelRequest, Session, UpdateChannelRequest } from \"@opengeni/sdk\";\nimport { useCallback, useMemo, useSyncExternalStore } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { channelCacheFor } from \"./channel-cache\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UseChannelsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseChannelsResult = {\n channels: Channel[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (request: CreateChannelRequest) => Promise<Channel | null>;\n update: (channelId: string, request: UpdateChannelRequest) => Promise<Channel | null>;\n reorder: (channelIds: string[]) => Promise<Channel[] | null>;\n remove: (channelId: string) => Promise<boolean>;\n /** Re-file a session into a channel; null moves it back to the inbox. */\n moveSession: (sessionId: string, channelId: string | null) => Promise<Session | null>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * Workspace-shared channels: rail organization for root sessions\n * (\"workstreams\") by work type. Pure metadata — filing a session into a\n * channel never affects execution.\n */\nexport function useChannels(options: UseChannelsOptions = {}): UseChannelsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const cache = useMemo(() => channelCacheFor(client, workspaceId), [client, workspaceId]);\n const snapshot = useSyncExternalStore(cache.subscribe, cache.getSnapshot, cache.getSnapshot);\n const load = useCallback(async () => {\n const ticket = cache.beginLoad();\n const channels = await client.listChannels(workspaceId);\n cache.acceptLoad(ticket, channels);\n return channels;\n }, [cache, client, workspaceId]);\n const { loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner(cache);\n\n const create = useCallback(\n async (request: CreateChannelRequest): Promise<Channel | null> => {\n const result = await run(() => client.createChannel(workspaceId, request));\n if (result) {\n // Publish the canonical write response before this promise can resolve.\n // The composer may create a session with this id immediately, while a\n // sibling rail hook could still have an older list request in flight.\n cache.publishCreated(result);\n await refresh();\n }\n return result;\n },\n [cache, client, workspaceId, run, refresh],\n );\n\n const update = useCallback(\n async (channelId: string, request: UpdateChannelRequest): Promise<Channel | null> => {\n const result = await run(() => client.updateChannel(workspaceId, channelId, 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 (channelId: string): Promise<boolean> => {\n const result = await run(async () => {\n await client.deleteChannel(workspaceId, channelId);\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 reorder = useCallback(\n async (channelIds: string[]): Promise<Channel[] | null> => {\n const result = await run(() => client.reorderChannels(workspaceId, { channelIds }));\n if (result) await refresh();\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const moveSession = useCallback(\n async (sessionId: string, channelId: string | null): Promise<Session | null> => {\n return await run(() => client.updateSessionChannel(workspaceId, sessionId, { channelId }));\n },\n [client, workspaceId, run],\n );\n\n return {\n // Cache snapshots replace arrays instead of mutating them, so preserve the\n // stable reference expected from the previous polled-value implementation.\n channels: snapshot.channels as Channel[],\n loading: loading && !snapshot.ready,\n error,\n refresh,\n create,\n update,\n reorder,\n remove,\n moveSession,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import type { Channel } from \"@opengeni/sdk\";\nimport type { SessionClientLike } from \"../client\";\n\ntype PendingChannel = { channel: Channel; committedAfterLoad: number };\n\nexport type ChannelCacheSnapshot = Readonly<{\n channels: readonly Channel[];\n ready: boolean;\n}>;\n\nexport type ChannelCacheStore = Readonly<{\n getSnapshot: () => ChannelCacheSnapshot;\n subscribe: (listener: () => void) => () => void;\n beginLoad: () => number;\n acceptLoad: (ticket: number, channels: readonly Channel[]) => void;\n publishCreated: (channel: Channel) => void;\n}>;\n\nconst EMPTY_CHANNELS: readonly Channel[] = [];\nconst EMPTY_SNAPSHOT: ChannelCacheSnapshot = {\n channels: EMPTY_CHANNELS,\n ready: false,\n};\nconst channelCaches = new WeakMap<object, Map<string, ChannelCacheStore>>();\n\nfunction compareChannels(left: Channel, right: Channel): number {\n return (\n Number(right.pinned) - Number(left.pinned) ||\n left.sortOrder - right.sortOrder ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction orderedChannels(channels: readonly Channel[]): Channel[] {\n return [...channels].sort(compareChannels);\n}\n\nfunction upsertChannel(channels: readonly Channel[], channel: Channel): Channel[] {\n const next = channels.filter((candidate) => candidate.id !== channel.id);\n next.push(channel);\n return orderedChannels(next);\n}\n\n/**\n * One client/workspace cache shared by every useChannels consumer.\n *\n * List reads are ticketed so an older request cannot erase a newer result.\n * A successful create remains layered over the latest server snapshot until a\n * list request that started after that success reconciles it. Requests already\n * in flight cannot make the project disappear between create and session start.\n */\nexport function createChannelCacheStore(): ChannelCacheStore {\n let base: readonly Channel[] | null = null;\n let snapshot = EMPTY_SNAPSHOT;\n let nextLoadTicket = 0;\n let acceptedLoadTicket = 0;\n const pending = new Map<string, PendingChannel>();\n const listeners = new Set<() => void>();\n\n const publish = () => {\n let channels = base ?? EMPTY_CHANNELS;\n for (const { channel } of pending.values()) {\n channels = upsertChannel(channels, channel);\n }\n snapshot = { channels, ready: base !== null || pending.size > 0 };\n for (const listener of listeners) listener();\n };\n\n return {\n getSnapshot: () => snapshot,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n beginLoad: () => ++nextLoadTicket,\n acceptLoad: (ticket, channels) => {\n if (ticket < acceptedLoadTicket) return;\n acceptedLoadTicket = ticket;\n base = orderedChannels(channels);\n for (const [id, created] of pending) {\n if (ticket > created.committedAfterLoad) pending.delete(id);\n }\n publish();\n },\n publishCreated: (channel) => {\n pending.set(channel.id, { channel, committedAfterLoad: nextLoadTicket });\n publish();\n },\n };\n}\n\nexport function channelCacheFor(client: SessionClientLike, workspaceId: string): ChannelCacheStore {\n let byWorkspace = channelCaches.get(client);\n if (!byWorkspace) {\n byWorkspace = new Map();\n channelCaches.set(client, byWorkspace);\n }\n let cache = byWorkspace.get(workspaceId);\n if (!cache) {\n cache = createChannelCacheStore();\n byWorkspace.set(workspaceId, cache);\n }\n return cache;\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 InstallPackRequest,\n PackInstallationPreview,\n PackInstallation,\n PackUninstallPreview,\n PreviewPackInstallationRequest,\n RegisterCapabilityPackRequest,\n UninstallPackRequest,\n UninstallPackResult,\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 /** @deprecated Use previewInstallation + install for component/Rig-aware Packs. */\n enable: (packId: string, request?: EnablePackRequest) => Promise<PackInstallation | null>;\n previewInstallation: (\n packId: string,\n request?: PreviewPackInstallationRequest,\n ) => Promise<PackInstallationPreview | null>;\n install: (packId: string, request: InstallPackRequest) => Promise<PackInstallation | null>;\n previewUninstall: (packId: string) => Promise<PackUninstallPreview | null>;\n uninstall: (packId: string, request: UninstallPackRequest) => Promise<UninstallPackResult | 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 previewInstallation = useCallback(\n async (\n packId: string,\n request: PreviewPackInstallationRequest = {},\n ): Promise<PackInstallationPreview | null> =>\n await run(() => client.previewPackInstallation(workspaceId, packId, request)),\n [client, workspaceId, run],\n );\n\n const install = useCallback(\n async (packId: string, request: InstallPackRequest): Promise<PackInstallation | null> => {\n const result = await run(() => client.installPack(workspaceId, packId, request));\n if (result) await refresh();\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const previewUninstall = useCallback(\n async (packId: string): Promise<PackUninstallPreview | null> =>\n await run(() => client.previewPackUninstall(workspaceId, packId)),\n [client, workspaceId, run],\n );\n\n const uninstall = useCallback(\n async (packId: string, request: UninstallPackRequest): Promise<UninstallPackResult | null> => {\n const result = await run(() => client.uninstallPack(workspaceId, packId, request));\n if (result) await refresh();\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 previewInstallation,\n install,\n previewUninstall,\n uninstall,\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 {\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\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport { terminalCanAcquirePty } from \"../lib/terminal-capability\";\nimport { usePageLiveActivity } from \"./internal\";\n\n// \"on-demand\" is the boxless-benign resting state: the lease is not currently\n// holder-backed and NOTHING asked to warm a box (no viewer/consent action, no\n// 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. The workbench uses this\n * to complete acknowledgment automatically while Desktop is opening.\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 * A real-PTY descriptor is attachable when already routed as `pty-ws`, or while\n * transiently cold. A firehose-only backend and policy/OS/backend degradation\n * cannot become interactive, so attaching there would only waste a holder.\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 (acknowledgment) and 429 (viewer cap) are\n * surfaced as 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 pageLive = usePageLiveActivity();\n const lifecycleEnabled = enabled && pageLive;\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 const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${enabled}`;\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 const [stateIdentity, setStateIdentity] = useState(identityKey);\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 const previousIdentityRef = useRef(identityKey);\n\n const renegotiate = useCallback(() => {\n setNonce((n) => n + 1);\n }, []);\n\n // ── Negotiation + viewer lifecycle ──────────────────────────────────────────\n useEffect(() => {\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged) {\n setStateIdentity(identityKey);\n setCapabilities(null);\n setState(\"idle\");\n setError(null);\n setAcknowledgmentRequired(null);\n setViewerCapReached(false);\n setViewerId(null);\n epochRef.current = 0;\n viewerIdRef.current = null;\n }\n if (!lifecycleEnabled || !sessionId) {\n setState(\"idle\");\n setCapabilities(null);\n viewerIdRef.current = null;\n setViewerId(null);\n return;\n }\n // The preceding effect cleanup released any old holder before this fresh\n // lifecycle starts. Never project that stale id while re-negotiating or if\n // the replacement grant degrades.\n viewerIdRef.current = null;\n setViewerId(null);\n let cancelled = false;\n let pollTimer: ReturnType<typeof setTimeout> | null = null;\n let heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\n let localViewerId: string | null = null;\n const requestAbort = new AbortController();\n const startedAt = Date.now();\n\n const clearTimers = () => {\n if (pollTimer !== null) clearTimeout(pollTimer);\n if (heartbeatTimer !== null) clearTimeout(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 const schedule = () => {\n if (cancelled || !localViewerId) return;\n heartbeatTimer = setTimeout(() => {\n heartbeatTimer = null;\n if (cancelled || !localViewerId) return;\n void client\n .heartbeatViewer(workspaceId, sessionId, localViewerId, {\n leaseEpoch: epochRef.current,\n })\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 .finally(schedule);\n }, intervalMs);\n };\n schedule();\n };\n\n const pollUntilWarm = () => {\n pollTimer = setTimeout(() => {\n if (cancelled) return;\n void client\n .getStreamCapabilities(workspaceId, sessionId, { signal: requestAbort.signal })\n .then((caps) => {\n if (cancelled) return;\n settle(caps);\n if (sandboxAcceptsLiveIo(caps.liveness)) {\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 if (isSandboxOwnershipDisabledError(cause)) {\n setState(\"on-demand\");\n setError(null);\n return;\n }\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 signal: requestAbort.signal,\n });\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 acknowledgment requirement (409) and viewer cap (429) surface as\n // typed signals 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 && terminalCanAcquirePty(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 terminal: wantTerminalAttach,\n files: wantFilesAttach,\n });\n if (cancelled) {\n // The attach crossed an identity/unmount boundary after the server\n // had already minted a holder. It is too late to publish the result,\n // but abandoning it would keep the old sandbox warm until the\n // reaper runs. Release that exact old-session holder immediately.\n void client.detachViewer(workspaceId, sessionId, holder.viewerId).catch(() => {});\n return;\n }\n if (\n (wantDesktopAttach &&\n (!holder.dataPlaneUrl || !holder.transport || !holder.client)) ||\n (wantTerminalAttach && (!holder.terminalUrl || !holder.terminalTransport))\n ) {\n // Nullable plane cells are valid graceful-degradation values at\n // the raw API boundary, but an explicit UI grant must not become\n // a successful holder that waits forever. Release it and surface\n // a retryable error instead of retaining stale credentials.\n await client.detachViewer(workspaceId, sessionId, holder.viewerId).catch(() => {});\n throw new Error(\"live plane unavailable\");\n }\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,\n token: holder.streamToken,\n expiresAt: holder.streamExpiresAt,\n resolution: holder.resolution ?? prev.DesktopStream.resolution,\n }\n : prev.DesktopStream,\n Terminal: wantTerminalAttach\n ? {\n ...prev.Terminal,\n transport: holder.terminalTransport ?? prev.Terminal.transport,\n url: holder.terminalUrl,\n token: holder.terminalToken,\n expiresAt: holder.terminalExpiresAt,\n // A live pty-ws means the box is pty-capable for real.\n ptyCapable: holder.terminalTransport ? true : prev.Terminal.ptyCapable,\n reason: holder.terminalTransport ? null : prev.Terminal.reason,\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 acknowledgment, so a 409 there\n // is not a desktop-open signal — the terminal 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 } else {\n throw cause;\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 // non-warm 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 (sandboxAcceptsLiveIo(caps.liveness) || 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 holder-confirmed warm yet — poll until it is, with the 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 (isSandboxOwnershipDisabledError(cause)) {\n setState(\"on-demand\");\n setError(null);\n return;\n }\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 requestAbort.abort();\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 lifecycleEnabled,\n attachDesktop,\n attachTerminal,\n attachFiles,\n warmingPollMs,\n warmingDeadlineMs,\n nonce,\n identityKey,\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 const identityMatches = enabled && stateIdentity === identityKey;\n return {\n capabilities: identityMatches ? capabilities : null,\n state: identityMatches ? state : \"idle\",\n error: identityMatches ? error : null,\n acknowledgmentRequired: identityMatches ? acknowledgmentRequired : null,\n viewerCapReached: identityMatches && viewerCapReached,\n viewerId: identityMatches ? viewerId : null,\n renegotiate,\n };\n}\n\nfunction isSandboxOwnershipDisabledError(error: unknown): boolean {\n return (\n error instanceof OpenGeniApiError &&\n error.status === 404 &&\n error.message.includes(\"sandbox ownership is not enabled\")\n );\n}\n","/**\n * A sandbox is available for new I/O only after a holder has observed `warm`.\n *\n * `draining` means the holder count is zero and teardown owns the provider\n * instance. The provider may disappear before the durable lease reaches `cold`,\n * so treating `draining` as live races capture/termination. Explicit user intent\n * reacquires a holder; only its subsequent `warm` state re-enables live I/O.\n */\nexport function sandboxAcceptsLiveIo(liveness: string | null | undefined): boolean {\n return liveness === \"warm\";\n}\n","import type { TerminalCapability } from \"@opengeni/sdk\";\n\n/** Whether an explicit viewer grant can upgrade this cell to a real PTY.\n * Keep acquisition feasibility separate from the current transport: a cold\n * real-PTY backend reports sse-events until the just-in-time grant warms it. */\nexport function terminalCanAcquirePty(cell: TerminalCapability | null | undefined): boolean {\n if (!cell?.ptyCapable) return false;\n if (cell.transport === \"pty-ws\" || cell.transport === \"relay-pty\") return true;\n return cell.reason === \"lease_cold\" || cell.reason === \"not_provisioned\";\n}\n","import {\n TTYD_SUBPROTOCOL,\n TerminalCapability,\n terminalSocketUrl,\n ttydAuthFrame,\n ttydInputFrame,\n ttydResizeFrame,\n TtydServerCommand,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n decodeStreamFrame,\n decodeStreamOpenAck,\n encodeStreamFrame,\n encodeStreamOpen,\n type RelayChannel,\n STREAM_KIND_PTY,\n STREAM_ROLE_CLIENT,\n} from \"../lib/relay-wire\";\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\" | \"expiresAt\"> | 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 /** Requests a fresh negotiated terminal grant after an unexpected transport\n * failure. Intentional disconnects and effect cleanup never call it. */\n onReconnectNeeded?: (() => 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 PTY stdin. Input during CONNECTING is bounded and\n * replayed only after ttyd authentication succeeds. */\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// Keystrokes entered during the websocket handshake are held until ttyd has\n// accepted its auth/resize frames. Bound the queue by UTF-16 code units (a hard\n// <=128 KiB string payload in current JS engines) so a paste cannot turn a slow\n// handshake into unbounded renderer memory. Overflow rejects the whole pending\n// input rather than ever executing a truncated shell command.\nexport const MAX_PENDING_TERMINAL_INPUT_CODE_UNITS = 64 * 1024;\nconst TERMINAL_CONNECT_EXPIRY_SKEW_MS = 5_000;\nconst TERMINAL_RECONNECT_INITIAL_MS = 100;\nconst TERMINAL_RECONNECT_MAX_MS = 3_000;\nconst RELAY_TAG_OPEN = 1;\nconst RELAY_TAG_OPEN_ACK = 2;\nconst RELAY_TAG_FRAME = 3;\n\nfunction relayDatagram(tag: number, body: Uint8Array): ArrayBuffer {\n const bytes = new Uint8Array(body.length + 1);\n bytes[0] = tag;\n bytes.set(body, 1);\n return bytes.buffer;\n}\n\nfunction relayChannelFromUrl(url: string): RelayChannel {\n const endpoint = new URL(url);\n const channel: RelayChannel = {\n channelId: endpoint.searchParams.get(\"channel\") ?? \"\",\n workspaceId: endpoint.searchParams.get(\"ws\") ?? \"\",\n agentId: endpoint.searchParams.get(\"agent\") ?? \"\",\n kind: STREAM_KIND_PTY,\n port: Number(endpoint.searchParams.get(\"port\") ?? \"0\"),\n };\n if (\n !channel.channelId ||\n !channel.workspaceId ||\n !channel.agentId ||\n !Number.isSafeInteger(channel.port) ||\n channel.port <= 0\n ) {\n throw new Error(\"terminal relay endpoint is incomplete\");\n }\n return channel;\n}\n\nfunction sendRelayInput(\n socket: WebSocket,\n channel: RelayChannel,\n sequence: bigint,\n data: string,\n): void {\n socket.send(\n relayDatagram(\n RELAY_TAG_FRAME,\n encodeStreamFrame({\n channelId: channel.channelId,\n seq: sequence.toString(),\n data: new TextEncoder().encode(data),\n producedAtMs: String(Date.now()),\n }),\n ),\n );\n}\n\n/** A bearer must remain valid long enough to finish a new websocket handshake.\n * Existing open sockets are unaffected: this is evaluated only when the\n * credential identity changes and the connection effect attempts a new socket. */\nexport function terminalStreamCredentialUsable(\n capability: Pick<TerminalCapability, \"transport\" | \"url\" | \"expiresAt\"> | null | undefined,\n nowMs = Date.now(),\n): boolean {\n if (\n (capability?.transport !== \"pty-ws\" && capability?.transport !== \"relay-pty\") ||\n !capability.url\n ) {\n return false;\n }\n if (!capability.expiresAt) return true;\n const expiresAt = Date.parse(capability.expiresAt);\n return Number.isFinite(expiresAt) && expiresAt > nowMs + TERMINAL_CONNECT_EXPIRY_SKEW_MS;\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\nfunction closeSocket(socket: WebSocket | null): void {\n try {\n socket?.close();\n } catch {\n // Already closed or rejected by the host WebSocket implementation.\n }\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, onReconnectNeeded, initialCols, initialRows } = options;\n const [status, setStatus] = useState<TerminalStreamStatus>(\"closed\");\n const [reconnectGeneration, setReconnectGeneration] = useState(0);\n const wsRef = useRef<WebSocket | null>(null);\n const pendingInputRef = useRef(\"\");\n const socketFailedRef = useRef(false);\n const socketAuthenticatedRef = useRef(false);\n const relayChannelRef = useRef<RelayChannel | null>(null);\n const relayIdentityRef = useRef<string | null>(null);\n const relayInputSequenceRef = useRef(0n);\n const relayOutputSequenceRef = useRef(0n);\n const reconnectAttemptRef = useRef(0);\n const credentialIdentityRef = useRef<string | null>(null);\n const refreshRequestedRef = useRef(false);\n const intentionalCloseRef = useRef<WeakSet<WebSocket>>(new WeakSet());\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 const onReconnectNeededRef = useRef(onReconnectNeeded);\n onOutputRef.current = onOutput;\n onTitleRef.current = onTitle;\n onReconnectNeededRef.current = onReconnectNeeded;\n\n const transport = capability?.transport ?? null;\n const url = capability?.url ?? null;\n const token = capability?.token ?? null;\n const expiresAt = capability?.expiresAt ?? null;\n const transportRef = useRef(transport);\n transportRef.current = transport;\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 const relay = transport === \"relay-pty\";\n if (transport !== \"pty-ws\" && !relay) {\n // A transport downgrade is a real semantic boundary. Do not replay input\n // captured for a PTY if this surface later changes back from firehose mode.\n pendingInputRef.current = \"\";\n socketAuthenticatedRef.current = false;\n relayIdentityRef.current = null;\n relayInputSequenceRef.current = 0n;\n relayOutputSequenceRef.current = 0n;\n reconnectAttemptRef.current = 0;\n credentialIdentityRef.current = null;\n refreshRequestedRef.current = false;\n setStatus(\"closed\");\n return;\n }\n const credentialIdentity = `${transport}\\u0000${url ?? \"\"}\\u0000${token ?? \"\"}\\u0000${expiresAt ?? \"\"}`;\n if (credentialIdentityRef.current !== credentialIdentity) {\n credentialIdentityRef.current = credentialIdentity;\n reconnectAttemptRef.current = 0;\n refreshRequestedRef.current = false;\n }\n // A changed/cleared credential is a new connection attempt boundary. It may\n // receive input while its exact grant is pending even if the prior socket\n // failed; the unchanged failed identity remains fenced because this effect\n // does not re-run for a status-only render.\n socketFailedRef.current = false;\n socketAuthenticatedRef.current = false;\n if (!url) {\n // Exact grants arrive asynchronously. Preserve the bounded first input\n // while the descriptor remains pty-ws, but never open without a credential.\n setStatus(\"closed\");\n return;\n }\n if (!terminalStreamCredentialUsable({ transport, url, expiresAt })) {\n // A descriptor from an older rolling server may still carry a bearer that\n // aged out before this surface mounted. Ask once for the exact fresh grant.\n setStatus(\"closed\");\n if (!refreshRequestedRef.current) {\n refreshRequestedRef.current = true;\n onReconnectNeededRef.current?.();\n }\n return;\n }\n\n let disposed = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let socket: WebSocket;\n let relayChannel: RelayChannel | null = null;\n const relayOutputDecoder = new TextDecoder();\n setStatus(\"connecting\");\n try {\n if (relay) {\n relayChannel = relayChannelFromUrl(url);\n const relayIdentity = [\n relayChannel.workspaceId,\n relayChannel.agentId,\n relayChannel.port,\n relayChannel.channelId,\n ].join(\"\\u0000\");\n if (relayIdentityRef.current !== relayIdentity) {\n relayIdentityRef.current = relayIdentity;\n relayInputSequenceRef.current = 0n;\n relayOutputSequenceRef.current = 0n;\n }\n relayChannelRef.current = relayChannel;\n socket = new WebSocket(url);\n } else {\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 }\n } catch {\n socketFailedRef.current = true;\n setStatus(\"error\");\n return;\n }\n socket.binaryType = \"arraybuffer\";\n wsRef.current = socket;\n\n const requestFreshGrant = () => {\n if (disposed || refreshRequestedRef.current || intentionalCloseRef.current.has(socket))\n return;\n refreshRequestedRef.current = true;\n onReconnectNeededRef.current?.();\n };\n\n const scheduleTransportReconnect = () => {\n if (disposed || reconnectTimer !== null || intentionalCloseRef.current.has(socket)) return;\n if (refreshRequestedRef.current) return;\n if (!terminalStreamCredentialUsable({ transport, url, expiresAt })) {\n requestFreshGrant();\n return;\n }\n const attempt = reconnectAttemptRef.current++;\n const delay = Math.min(\n TERMINAL_RECONNECT_INITIAL_MS * 2 ** Math.min(attempt, 8),\n TERMINAL_RECONNECT_MAX_MS,\n );\n setStatus(\"connecting\");\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n if (!disposed) setReconnectGeneration((generation) => generation + 1);\n }, delay);\n };\n\n socket.onopen = () => {\n if (disposed) return;\n if (relay && relayChannel) {\n try {\n socket.send(\n relayDatagram(\n RELAY_TAG_OPEN,\n encodeStreamOpen({\n channel: relayChannel,\n token: token ?? \"\",\n role: STREAM_ROLE_CLIENT,\n resumeFromSeq: relayOutputSequenceRef.current.toString(),\n }),\n ),\n );\n } catch {\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(socket);\n }\n return;\n }\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 if (pendingInputRef.current.length > 0) {\n // One websocket frame makes the pre-open queue all-or-nothing from this\n // client's perspective; never execute a prefix of a buffered command.\n socket.send(ttydInputFrame(pendingInputRef.current));\n pendingInputRef.current = \"\";\n }\n socketAuthenticatedRef.current = true;\n } catch {\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(socket);\n return;\n }\n setStatus(\"open\");\n reconnectAttemptRef.current = 0;\n refreshRequestedRef.current = false;\n };\n\n socket.onmessage = (ev: MessageEvent) => {\n if (disposed) return;\n if (relay) {\n if (!(ev.data instanceof ArrayBuffer) || !relayChannel) return;\n const bytes = new Uint8Array(ev.data);\n if (bytes.length < 1) return;\n const tag = bytes[0];\n const body = bytes.subarray(1);\n if (tag === RELAY_TAG_OPEN_ACK) {\n try {\n const ack = decodeStreamOpenAck(body);\n if (!ack.accepted) throw new Error(ack.error?.message ?? \"terminal relay rejected\");\n reconnectAttemptRef.current = 0;\n refreshRequestedRef.current = false;\n socketAuthenticatedRef.current = true;\n if (pendingInputRef.current.length > 0) {\n sendRelayInput(\n socket,\n relayChannel,\n relayInputSequenceRef.current++,\n pendingInputRef.current,\n );\n pendingInputRef.current = \"\";\n }\n setStatus(\"open\");\n } catch {\n socketFailedRef.current = true;\n setStatus(\"error\");\n requestFreshGrant();\n closeSocket(socket);\n }\n } else if (tag === RELAY_TAG_FRAME && socketAuthenticatedRef.current) {\n try {\n const frame = decodeStreamFrame(body);\n const sequence = BigInt(frame.seq);\n if (sequence < relayOutputSequenceRef.current) return;\n relayOutputSequenceRef.current = sequence + 1n;\n if (frame.data.length > 0) {\n onOutputRef.current?.(relayOutputDecoder.decode(frame.data, { stream: true }));\n }\n } catch {\n // Ignore one malformed frame; the live PTY remains usable.\n }\n }\n return;\n }\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) {\n // A network/relay outage is retryable with the same credential and PTY.\n // Keep accepting bounded input while the transport comes back.\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(socket);\n }\n };\n socket.onclose = () => {\n if (wsRef.current === socket) wsRef.current = null;\n socketAuthenticatedRef.current = false;\n if (!disposed) {\n if (socketFailedRef.current) setStatus(\"error\");\n else scheduleTransportReconnect();\n }\n };\n\n return () => {\n disposed = true;\n wsRef.current = null;\n socketAuthenticatedRef.current = false;\n relayChannelRef.current = null;\n if (reconnectTimer !== null) clearTimeout(reconnectTimer);\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 closeSocket(socket);\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, expiresAt, reconnectGeneration]);\n\n const write = useCallback((data: string) => {\n const currentTransport = transportRef.current;\n const ws = wsRef.current;\n if (ws && ws.readyState === WebSocket.OPEN && socketAuthenticatedRef.current) {\n try {\n const relayChannel = relayChannelRef.current;\n if (currentTransport === \"relay-pty\" && relayChannel) {\n sendRelayInput(ws, relayChannel, relayInputSequenceRef.current++, data);\n } else {\n ws.send(ttydInputFrame(data));\n }\n } catch {\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(ws);\n }\n } else if (\n (currentTransport === \"pty-ws\" || currentTransport === \"relay-pty\") &&\n !socketFailedRef.current\n ) {\n const nextSize = pendingInputRef.current.length + data.length;\n if (nextSize > MAX_PENDING_TERMINAL_INPUT_CODE_UNITS) {\n pendingInputRef.current = \"\";\n socketFailedRef.current = true;\n setStatus(\"error\");\n closeSocket(ws);\n return;\n }\n pendingInputRef.current += data;\n }\n }, []);\n const resize = useCallback((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 && socketAuthenticatedRef.current) {\n try {\n // Self-hosted relay PTYs carry raw input/output frames. Resize remains\n // an out-of-band control operation; do not send ttyd framing into them.\n if (transportRef.current === \"pty-ws\") ws.send(ttydResizeFrame(cols, rows));\n } catch {\n // socket raced closed — geometry is replayed on the next open.\n }\n }\n }, []);\n const disconnect = useCallback(() => {\n const ws = wsRef.current;\n wsRef.current = null;\n pendingInputRef.current = \"\";\n socketFailedRef.current = false;\n socketAuthenticatedRef.current = false;\n relayChannelRef.current = null;\n setStatus(\"closed\");\n if (ws) intentionalCloseRef.current.add(ws);\n closeSocket(ws);\n }, []);\n\n return useMemo<UseTerminalStreamResult>(() => {\n return { connected: status === \"open\", status, write, resize, disconnect };\n }, [status, write, resize, disconnect]);\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\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\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 identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${interactive}\\u0000${ptyFilter ?? \"\"}`;\n const [openedPtyId, setOpenedPtyId] = useState<string | null>(null);\n const [openError, setOpenError] = useState<Error | null>(null);\n const [stateIdentity, setStateIdentity] = useState(identityKey);\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 const currentIdentityRef = useRef(identityKey);\n currentIdentityRef.current = identityKey;\n\n // Async PTY state belongs to one workspace/session/mode identity. Hide it\n // synchronously on the switching render, then clear it durably in the effect.\n useEffect(() => {\n setStateIdentity(identityKey);\n setOpenedPtyId(null);\n setOpenError(null);\n }, [identityKey]);\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.\n const openInFlight = useRef(false);\n const boxWarm = liveness === undefined || sandboxAcceptsLiveIo(liveness);\n useEffect(() => {\n if (!interactive || !sessionId || ptyFilter || !boxWarm) {\n setOpenError(null);\n return;\n }\n let cancelled = false;\n setOpenError(null);\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 // The hook is session-scoped even if a host accidentally retains the old\n // event array for one render during navigation.\n if (event.workspaceId !== workspaceId || event.sessionId !== sessionId) continue;\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, workspaceId, sessionId]);\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 identityMatches = stateIdentity === identityKey;\n const activePtyId = identityMatches ? (openedPtyId ?? openPty) : null;\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 const writeIdentity = identityKey;\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 currentIdentityRef.current === writeIdentity\n ) {\n setOpenedPtyId(null);\n setReopenNonce((n) => n + 1);\n }\n });\n };\n }, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId, identityKey]);\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: identityMatches ? openError : null,\n };\n}\n","import type {\n FileSystemRouteIdentity,\n FsChangedPayload,\n FsReadResponse,\n FsTreeNode,\n FsWriteResponse,\n GitChangedPayload,\n GitFileStatusCode,\n GitStatusResponse,\n OpenGeniRequestOptions,\n SessionCapabilities,\n SessionEvent,\n WorkspaceCaptureManifest,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type ClientOverride, useOpenGeni } from \"../provider\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\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\nexport type CapturedFileUnavailableReason = \"not-captured\" | \"too-large\" | \"content-missing\";\n\n/** A cold capture can index a path without retaining its contents. Components\n * use this typed result to offer an explicit wake action instead of silently\n * turning passive review into a live sandbox read. */\nexport class CapturedFileUnavailableError extends Error {\n readonly code = \"captured_file_unavailable\";\n\n constructor(\n readonly path: string,\n readonly reason: CapturedFileUnavailableReason,\n ) {\n super(\n reason === \"too-large\"\n ? `${path} exceeds the captured preview limit.`\n : reason === \"content-missing\"\n ? `${path} is no longer available in this capture.`\n : `${path} was not changed in this captured turn.`,\n );\n this.name = \"CapturedFileUnavailableError\";\n }\n}\n\nexport class FileWriteConflictError extends Error {\n readonly code = \"file_write_conflict\";\n\n constructor(\n readonly path: string,\n readonly expectedContent: string,\n readonly liveContent: string,\n ) {\n super(`${path} changed on the machine. Reload it or explicitly overwrite the live version.`);\n this.name = \"FileWriteConflictError\";\n }\n}\n\nexport type SandboxWriteFileOptions = {\n /** Exact text loaded into the editor. The live file is re-read before write;\n * divergence fails closed with FileWriteConflictError. */\n expectedContent?: string | undefined;\n /** Deliberately bypass the expected-content guard after a visible conflict. */\n force?: boolean | undefined;\n};\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 /** Opaque path returned by the selected target's FileSystem boundary. */\n path: string;\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 /** Exact capability identity for the selected filesystem route. A route/root\n * change resets this hook and makes stale provider requests fail retryably. */\n route?: FileSystemRouteIdentity | undefined;\n /** Hold off the initial list (e.g. panel collapsed). Default true. */\n enabled?: boolean | undefined;\n /** Pause live reads/invalidation while preserving the last rendered result. */\n active?: boolean | undefined;\n /** Repository roots advertised by capabilities, relative to the workspace. */\n repoPaths?: readonly string[] | undefined;\n /** The lease liveness. `null` means capability negotiation has not produced\n * an authoritative lifecycle value yet and therefore blocks live I/O. Omitting\n * the option preserves the legacy direct-hook behavior. 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?: SessionCapabilities[\"liveness\"] | null | undefined;\n /** The latest turn-end workspace capture (from `useWorkspaceCapture`). The tree\n * paints immediately from this durable index, then a warm box reconciles live\n * in place. If that live read fails, the capture remains a truthful read-only\n * fallback instead of turning into an empty error surface. */\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, options?: OpenGeniRequestOptions) => 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: (\n path: string,\n content: string,\n options?: SandboxWriteFileOptions,\n ) => 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 /** Monotonic invalidation token for open file previews. Advances when an\n * external filesystem change or completed agent tool may have changed bytes. */\n contentRevision?: number | undefined;\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 /** Lightweight repository context loaded by the same status request that tints files. */\n gitSummary?: SandboxFilesGitSummary | null | undefined;\n /** True only while the initial repository-status overlay is still loading. */\n gitLoading?: boolean | undefined;\n loading: boolean;\n error: Error | null;\n};\n\nexport type SandboxFilesGitSummary = {\n branch: string | null;\n isRepo: boolean;\n repoCount: number;\n ahead: number;\n behind: number;\n dirtyCount: number;\n};\n\nfunction normalizeRoot(root: string): string {\n const slashNormalized = root.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\/+/, \"\");\n if (slashNormalized === \"/\") return \"/\";\n const normalized = slashNormalized.replace(/\\/+$/, \"\");\n return normalized === \".\" ? \"\" : normalized;\n}\n\nfunction isAbsoluteTreePath(path: string): boolean {\n return path.startsWith(\"/\") || /^[A-Za-z]:\\//u.test(path);\n}\n\nfunction joinTreeRoot(root: string, path: string): string {\n if (!root || isAbsoluteTreePath(path)) return path;\n return root === \"/\" ? `/${path}` : `${root}/${path}`;\n}\n\nfunction qualifyStatusPath(root: string, path: string, treeRoot: string): string {\n const normalized = normalizeRoot(root);\n const workspaceRelative = joinTreeRoot(normalized, path);\n return joinTreeRoot(normalizeRoot(treeRoot), workspaceRelative);\n}\n\nfunction summarizeStatuses(\n statuses: Array<{ root: string; status: GitStatusResponse }>,\n): SandboxFilesGitSummary {\n const repositories = statuses.filter(({ status }) => status.isRepo);\n return {\n branch: repositories.length === 1 ? (repositories[0]?.status.head ?? null) : null,\n isRepo: repositories.length > 0,\n repoCount: repositories.length,\n ahead: repositories.reduce((sum, { status }) => sum + status.ahead, 0),\n behind: repositories.reduce((sum, { status }) => sum + status.behind, 0),\n dirtyCount: repositories.reduce((sum, { status }) => sum + status.files.length, 0),\n };\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\nfunction parentWithinTree(path: string, rootPath: string): string {\n const parent = parentOf(path);\n return parent === \"\" && normalizeRoot(rootPath) === \"/\" && path.startsWith(\"/\") ? \"/\" : parent;\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, captureComplete = false): 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\n ? node.children.map((child) => fsNodeToTree(child, captureComplete))\n : captureComplete && kind === \"dir\"\n ? []\n : 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 {\n ...node,\n children: replaceChildren(node.children, targetPath, children),\n };\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\nconst FS_LIST_BATCH_REQUEST_LIMIT = 16;\n\n/** Repository paths are capability-advertised and therefore safe to use as a\n * bounded initial lazy-tree frontier. Listing their ancestors concurrently with\n * the root avoids a root → repositories → repo remote waterfall. */\nfunction initialDirectoryFrontier(rootPath: string, repoPaths: readonly string[]): string[] {\n const root = normalizeRoot(rootPath);\n const rootParts = root.split(\"/\").filter(Boolean);\n const rootPrefix = root.startsWith(\"//\") ? \"//\" : root.startsWith(\"/\") ? \"/\" : \"\";\n const paths = new Set<string>();\n for (const repoPath of repoPaths) {\n const canonicalRepoPath = joinTreeRoot(root, normalizeRoot(repoPath));\n const parts = canonicalRepoPath.split(\"/\").filter(Boolean);\n if (rootParts.some((part, index) => parts[index] !== part)) continue;\n for (let depth = rootParts.length + 1; depth <= parts.length; depth += 1) {\n const path = parts.slice(0, depth).join(\"/\");\n paths.add(`${rootPrefix}${path}`);\n }\n }\n // A workspace with hundreds of repositories should remain lazy. This still\n // preloads the shared repository container and the first visible roots.\n return [...paths]\n .sort((a, b) => a.split(\"/\").length - b.split(\"/\").length || a.localeCompare(b))\n .slice(0, 8);\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, rootPath = \"\"): boolean {\n if (parent === normalizeRoot(rootPath)) 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(\n nodes: FileTreeNode[],\n parent: string,\n child: FileTreeNode,\n rootPath = \"\",\n): FileTreeNode[] {\n if (parent === normalizeRoot(rootPath)) {\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, rootPath) };\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, rootPath = \"\"): FileTreeNode[] {\n const parent = parentWithinTree(path, rootPath);\n if (parent === normalizeRoot(rootPath)) {\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 {\n ...node,\n children: node.children.filter((n) => n.path !== path),\n };\n }\n if (node.kind === \"dir\" && node.children && parent.startsWith(`${node.path}/`)) {\n return { ...node, children: removeNode(node.children, path, rootPath) };\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\nfunction decodeBase64Bytes(value: string): Uint8Array {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n return bytes;\n}\n\nfunction decodeBase64Text(value: string): string {\n return new TextDecoder().decode(decodeBase64Bytes(value));\n}\n\nfunction encodeBase64Bytes(bytes: Uint8Array): string {\n let binary = \"\";\n const chunkSize = 0x8000;\n for (let offset = 0; offset < bytes.length; offset += chunkSize) {\n binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));\n }\n return btoa(binary);\n}\n\nasync function assertCapturedHash(bytes: Uint8Array, expected: string | null): Promise<void> {\n if (!expected) throw new Error(\"Captured file is missing its integrity hash.\");\n if (!globalThis.crypto?.subtle) {\n throw new Error(\"Captured file integrity verification is unavailable in this browser.\");\n }\n const buffer = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(buffer).set(bytes);\n const digest = new Uint8Array(await globalThis.crypto.subtle.digest(\"SHA-256\", buffer));\n const actual = [...digest].map((byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n if (actual !== expected) throw new Error(\"Captured file content failed its integrity check.\");\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 active = options.active ?? true;\n const rootPath = options.rootPath ?? \"\";\n const routeEpoch = options.route?.epoch ?? null;\n const routeRoot = options.route?.root ?? null;\n const route = useMemo<FileSystemRouteIdentity | undefined>(\n () =>\n routeEpoch !== null && routeRoot !== null\n ? { epoch: routeEpoch, root: routeRoot }\n : undefined,\n [routeEpoch, routeRoot],\n );\n const repoPathsKey = [\n ...new Set((options.repoPaths?.length ? options.repoPaths : [rootPath]).map(normalizeRoot)),\n ].join(\"\\u0000\");\n const repoPaths = useMemo(() => repoPathsKey.split(\"\\u0000\"), [repoPathsKey]);\n const capture = options.capture ?? null;\n const isLive = sandboxAcceptsLiveIo(options.liveness);\n // `liveness` predates this hook option. Preserve legacy embedders that omit it;\n // explicit `null` (negotiating) and lifecycle values require authoritative warm.\n const acceptsEventReads = options.liveness === undefined || isLive;\n const acceptsEventReadsRef = useRef(acceptsEventReads);\n acceptsEventReadsRef.current = acceptsEventReads;\n const hasLiveIoFence = options.liveness !== undefined;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${rootPath}\\u0000${repoPathsKey}\\u0000${routeEpoch ?? \"\"}\\u0000${routeRoot ?? \"\"}`;\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 [gitSummary, setGitSummary] = useState<SandboxFilesGitSummary | null>(null);\n const [gitLoading, setGitLoading] = useState(false);\n const [contentRevision, setContentRevision] = useState(0);\n const [stateIdentity, setStateIdentity] = useState(identityKey);\n // Which source the tree currently reflects — \"capture\" (cold paint) or \"live\".\n const [source, setSource] = useState<\"live\" | \"capture\" | null>(null);\n const sourceRef = useRef<\"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 refreshAbortRef = useRef<AbortController | null>(null);\n const identityAbortRef = useRef(new AbortController());\n const eventReadAbortRef = useRef(new AbortController());\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 eventReconcileInFlightRef = useRef<Promise<void> | null>(null);\n const eventReconcilePendingRef = 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. 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 refreshAbortRef.current?.abort();\n const refreshAbort = new AbortController();\n refreshAbortRef.current = refreshAbort;\n const generation = (refreshGenerationRef.current += 1);\n setLoading(true);\n setGitLoading(true);\n setError(null);\n try {\n // Paint the useful file tree before the optional Git tint. Separate remote\n // requests for one Modal box are deliberately serialized by the API; firing\n // both here only made the Git request contend with the file request during\n // cold starts.\n const frontierPaths = initialDirectoryFrontier(rootPath, repoPaths);\n const listRequests = [rootPath, ...frontierPaths].map((path) => ({\n path,\n depth: 1,\n ...(route ? { route } : {}),\n }));\n // Root plus the bounded repository frontier share one API request, one\n // direct holder, and one provider attach. The old per-directory fan-out\n // paid that fixed control-plane cost up to nine times on every Files open.\n const listedBatch = await client.fsListBatch(\n workspaceId,\n sessionId,\n { requests: listRequests },\n { signal: refreshAbort.signal },\n );\n if (refreshGenerationRef.current !== generation) return;\n const listed = listedBatch.results[0];\n if (!listed) throw new Error(\"Workspace list batch did not return the root result.\");\n const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));\n // Paint the root and already-returned frontier in one commit so preloaded\n // repository folders never flicker through a collapsed intermediate tree.\n setTree((prev) => {\n let hydrated = prev.length === 0 ? children : mergeRootChildren(prev, children);\n for (const [index, path] of frontierPaths.entries()) {\n const prefetched = listedBatch.results[index + 1];\n if (!prefetched) continue;\n hydrated = replaceChildren(\n hydrated,\n path,\n (prefetched.root.children ?? []).map((node) => fsNodeToTree(node)),\n );\n }\n return applyStatus(hydrated);\n });\n sourceRef.current = \"live\";\n setSource(\"live\");\n setLoading(false);\n\n const statuses =\n repoPaths.length > 0\n ? await client\n .gitReadBatch(\n workspaceId,\n sessionId,\n {\n requests: repoPaths.map((root) => ({\n status: { path: root },\n })),\n },\n { signal: refreshAbort.signal },\n )\n .then((batch) =>\n batch.results.map((result, index) => ({\n root: repoPaths[index] ?? \"\",\n status: result.status,\n })),\n )\n .catch(() => null)\n : [];\n if (refreshGenerationRef.current !== generation) return;\n if (statuses) {\n const overlay = new Map<string, FileTreeStatus>();\n for (const { root, status } of statuses) {\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(qualifyStatusPath(root, file.path, rootPath), mapped);\n }\n }\n statusRef.current = overlay;\n setGitSummary(summarizeStatuses(statuses));\n } else {\n statusRef.current = new Map();\n setGitSummary(null);\n }\n setGitLoading(false);\n setTree((prev) => applyStatus(prev));\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 if (refreshGenerationRef.current === generation) setGitLoading(false);\n if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;\n }\n }, [client, workspaceId, sessionId, rootPath, repoPaths, route, 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).\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 // The capture tree is a complete bounded index. Preserve an explicit empty\n // `children: []` as an actually empty directory; the live depth-1 mapper\n // intentionally treats that shape as an unexpanded boundary.\n const children = (manifest.treeIndex.children ?? []).map((node) => fsNodeToTree(node, true));\n setTree((prev) =>\n applyStatus(prev.length === 0 ? children : mergeRootChildren(prev, children)),\n );\n sourceRef.current = \"capture\";\n setSource(\"capture\");\n setGitSummary({\n branch: manifest.repos.length === 1 ? (manifest.repos[0]?.head ?? null) : null,\n isRepo: manifest.repos.length > 0,\n repoCount: manifest.repos.length,\n ahead: manifest.repos.reduce((sum, repo) => sum + repo.ahead, 0),\n behind: manifest.repos.reduce((sum, repo) => sum + repo.behind, 0),\n dirtyCount: manifest.files.length,\n });\n setGitLoading(false);\n setError(null);\n },\n [applyStatus],\n );\n\n const expand = useCallback(\n async (path: string) => {\n if (!sessionId) return;\n // Capture browsing is a durable server-side read surface. Never turn a\n // folder click into a Channel-A list while cold; truncated residue already\n // renders a truthful \"contents on machine\" row.\n if (source === \"capture\" && capture) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\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(\n workspaceId,\n sessionId,\n { path, depth: 1, ...(route ? { route } : {}) },\n { signal: identitySignal },\n );\n if (identityGenerationRef.current !== identityGeneration) return;\n const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));\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, capture, source, route, applyStatus],\n );\n\n const readFile = useCallback(\n async (path: string, requestOptions: OpenGeniRequestOptions = {}) => {\n if (!sessionId) throw new Error(\"no session\");\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestOptions.signal\n ? AbortSignal.any([identitySignal, requestOptions.signal])\n : identitySignal;\n const captured = capture?.files.find((file) => file.path === path && !file.deleted);\n if (source === \"capture\" && capture) {\n if (!captured) {\n throw new CapturedFileUnavailableError(path, \"not-captured\");\n }\n // A passive review of a turn-touched file must stay entirely server-side:\n // mint/read its captured after-image, verify the content hash, and never\n // wake the sandbox. A URL may expire between mint and GET, so retry once\n // through the authenticated API to obtain a fresh scoped URL.\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const result = await client.getWorkspaceCaptureFile(\n workspaceId,\n sessionId,\n path,\n capture.revision,\n { signal },\n );\n if (result.path !== path || result.revision !== capture.revision) {\n throw new Error(\n \"Captured file identity did not match the requested workspace revision.\",\n );\n }\n if (\n result.hash !== captured.hash ||\n result.sizeBytes !== captured.sizeBytes ||\n result.isBinary !== captured.isBinary ||\n result.tooLarge !== captured.tooLarge\n ) {\n throw new Error(\"Captured file metadata did not match its manifest.\");\n }\n if (result.tooLarge) {\n throw new CapturedFileUnavailableError(path, \"too-large\");\n }\n\n let bytes: Uint8Array;\n let encoding: \"utf8\" | \"base64\";\n let content: string;\n if (result.content !== null && result.encoding !== null) {\n encoding = result.encoding;\n content = result.content;\n bytes =\n encoding === \"base64\"\n ? decodeBase64Bytes(content)\n : new TextEncoder().encode(content);\n } else if (result.contentUrl) {\n const response = await fetch(result.contentUrl.url, {\n credentials: \"omit\",\n cache: \"no-store\",\n referrerPolicy: \"no-referrer\",\n signal: AbortSignal.any([signal, AbortSignal.timeout(30_000)]),\n }).catch(() => null);\n if (!response?.ok) {\n if (\n attempt === 0 &&\n (response === null || response.status === 401 || response.status === 403)\n ) {\n continue;\n }\n throw new Error(\"Captured file download failed.\");\n }\n bytes = new Uint8Array(await response.arrayBuffer());\n encoding = result.isBinary ? \"base64\" : \"utf8\";\n content = result.isBinary ? encodeBase64Bytes(bytes) : new TextDecoder().decode(bytes);\n } else {\n throw new CapturedFileUnavailableError(path, \"content-missing\");\n }\n\n if (bytes.byteLength !== result.sizeBytes) {\n throw new Error(\"Captured file size did not match its manifest.\");\n }\n await assertCapturedHash(bytes, result.hash);\n return {\n path,\n encoding,\n content,\n sizeBytes: result.sizeBytes,\n truncated: false,\n isBinary: result.isBinary,\n revision: result.revision,\n };\n }\n throw new Error(\"Captured file download failed after refreshing its URL.\");\n }\n return await client.fsRead(\n workspaceId,\n sessionId,\n { path, ...(route ? { route } : {}) },\n { signal },\n );\n },\n [client, workspaceId, sessionId, capture, source, route],\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, requestSignal?: AbortSignal) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestSignal\n ? AbortSignal.any([identitySignal, requestSignal])\n : identitySignal;\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, rootPath)) return;\n try {\n const listed = await client.fsList(\n workspaceId,\n sessionId,\n { path, depth: 1, ...(route ? { route } : {}) },\n { signal },\n );\n if (identityGenerationRef.current !== identityGeneration) return;\n const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));\n if (path === normalizeRoot(rootPath)) {\n 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, rootPath, route, applyStatus],\n );\n\n // Reconcile the visible directory frontier through bounded batch requests.\n // One tool completion can affect several expanded directories; issuing one\n // provider request per directory created a self-inflicted lock convoy.\n const reconcilePaths = useCallback(\n async (requestedPaths: readonly string[], requestSignal?: AbortSignal) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestSignal\n ? AbortSignal.any([identitySignal, requestSignal])\n : identitySignal;\n const paths = [...new Set(requestedPaths)].filter((path) =>\n parentIsLoaded(treeRef.current, path, rootPath),\n );\n for (let offset = 0; offset < paths.length; offset += FS_LIST_BATCH_REQUEST_LIMIT) {\n const chunk = paths.slice(offset, offset + FS_LIST_BATCH_REQUEST_LIMIT);\n try {\n const listed = await client.fsListBatch(\n workspaceId,\n sessionId,\n {\n requests: chunk.map((path) => ({\n path,\n depth: 1,\n ...(route ? { route } : {}),\n })),\n },\n { signal },\n );\n if (identityGenerationRef.current !== identityGeneration) return;\n setTree((previous) => {\n let next = previous;\n for (const [index, path] of chunk.entries()) {\n const result = listed.results[index];\n if (!result) continue;\n const children = (result.root.children ?? []).map((node) => fsNodeToTree(node));\n if (path === normalizeRoot(rootPath)) {\n next = mergeRootChildren(next, children);\n } else {\n const existing = findNodeByPath(next, path);\n const merged = existing?.children\n ? mergeChildren(existing.children, children)\n : children;\n next = replaceChildren(next, path, merged);\n }\n }\n return applyStatus(next);\n });\n } catch {\n // Reconciliation is best-effort. Preserve the current visible tree and\n // let the next real event or explicit refresh reconcile it.\n }\n }\n },\n [client, workspaceId, sessionId, rootPath, route, 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 setError(null);\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 // An expected-content conflict belongs to the editor's explicit\n // Reload/Overwrite decision surface. Treating it as a broken file tree\n // would also raise a duplicate host toast and leave a stale global error\n // after the user successfully resolves the conflict.\n if (err instanceof FileWriteConflictError) throw err;\n setError(err);\n onMutationError?.(err, opName);\n throw err;\n }\n },\n [applyStatus, reconcilePath, onMutationError],\n );\n\n const writeFile = useCallback(\n async (\n path: string,\n content: string,\n writeOptions: SandboxWriteFileOptions = {},\n ): Promise<FsWriteResponse> => {\n if (!sessionId) throw new Error(\"no session\");\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const parent = parentWithinTree(path, rootPath);\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 = {\n path,\n name: leafOf(path),\n kind: \"file\",\n size: content.length,\n };\n return await runOptimistic(\n \"write\",\n (nodes) => (exists ? nodes : insertNode(nodes, parent, node, rootPath)),\n async () => {\n if (!writeOptions.force && writeOptions.expectedContent !== undefined) {\n const live = await client.fsRead(\n workspaceId,\n sessionId,\n { path, ...(route ? { route } : {}) },\n { signal: identitySignal },\n );\n if (identityGenerationRef.current !== identityGeneration) {\n throw new Error(\"File save cancelled because the workspace changed.\");\n }\n const liveContent =\n live.encoding === \"base64\" ? decodeBase64Text(live.content) : live.content;\n if (live.truncated || live.isBinary || liveContent !== writeOptions.expectedContent) {\n throw new FileWriteConflictError(path, writeOptions.expectedContent, liveContent);\n }\n }\n if (identityGenerationRef.current !== identityGeneration) {\n throw new Error(\"File save cancelled because the workspace changed.\");\n }\n return await client.fsWrite(workspaceId, sessionId, {\n path,\n content,\n overwrite: true,\n ...(route ? { route } : {}),\n });\n },\n exists ? [] : [parent],\n );\n },\n [client, workspaceId, sessionId, tree, rootPath, route, runOptimistic],\n );\n\n const createFile = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentWithinTree(path, rootPath);\n const node: FileTreeNode = {\n path,\n name: leafOf(path),\n kind: \"file\",\n size: 0,\n };\n await runOptimistic(\n \"create file\",\n (nodes) => insertNode(nodes, parent, node, rootPath),\n () =>\n client.fsWrite(workspaceId, sessionId, {\n path,\n content: \"\",\n overwrite: false,\n ...(route ? { route } : {}),\n }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, runOptimistic],\n );\n\n const createDir = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentWithinTree(path, rootPath);\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 = {\n path,\n name: leafOf(path),\n kind: \"dir\",\n children: [],\n };\n await runOptimistic(\n \"create folder\",\n (nodes) => insertNode(nodes, parent, node, rootPath),\n () =>\n client.fsMkdir(workspaceId, sessionId, {\n path,\n recursive: true,\n ...(route ? { route } : {}),\n }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, 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, rootPath),\n () =>\n client.fsDelete(workspaceId, sessionId, {\n path,\n recursive,\n ...(route ? { route } : {}),\n }),\n [parentWithinTree(path, rootPath)],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, 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 = parentWithinTree(path, rootPath);\n const to = parentWithinTree(newPath, rootPath);\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, rootPath), to, moved, rootPath);\n },\n () =>\n client.fsMove(workspaceId, sessionId, {\n path,\n newPath,\n overwrite: opts?.overwrite ?? false,\n ...(route ? { route } : {}),\n }),\n to === from ? [from] : [from, to],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, runOptimistic],\n );\n\n // Initial paint + reset on identity change. Source selection:\n // • any box WITH a capture → paint instantly from the durable capture index;\n // a holder-confirmed warm box then reconciles live in place.\n // • if that live reconciliation fails, keep the capture visible and read-only.\n // • legacy callers that omit liveness and have no capture retain their live\n // fallback; an explicitly cold/draining lease never wakes from a passive mount.\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 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 refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshGenerationRef.current += 1;\n eventReadAbortRef.current.abort();\n eventReadAbortRef.current = new AbortController();\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged || !enabled) {\n if (identityChanged) eventReconcileInFlightRef.current = null;\n identityAbortRef.current.abort();\n identityAbortRef.current = new AbortController();\n identityGenerationRef.current += 1;\n lastSeqRef.current = 0;\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n eventReconcilePendingRef.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 setStateIdentity(identityKey);\n setExpandingPaths(new Set());\n sourceRef.current = null;\n setSource(null);\n setLoading(false);\n setError(null);\n setGitSummary(null);\n setGitLoading(false);\n setContentRevision(0);\n }\n if (!enabled) {\n return;\n }\n const currentCapture = captureRevision !== null ? captureRef.current : null;\n if (currentCapture && (identityChanged || !isLive || sourceRef.current !== \"live\")) {\n seedFromCapture(currentCapture);\n }\n if (!active) {\n if (!active) {\n setLoading(false);\n setGitLoading(false);\n }\n return;\n }\n if (isLive || (!hasLiveIoFence && !currentCapture)) {\n void refresh();\n }\n return () => {\n refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshGenerationRef.current += 1;\n eventReadAbortRef.current.abort();\n eventReconcilePendingRef.current = false;\n };\n }, [\n enabled,\n active,\n isLive,\n hasLiveIoFence,\n captureRevision,\n identityKey,\n refresh,\n seedFromCapture,\n ]);\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(\n async (requestSignal?: AbortSignal) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestSignal\n ? AbortSignal.any([identitySignal, requestSignal])\n : identitySignal;\n setGitLoading(true);\n try {\n const batch = await client.gitReadBatch(\n workspaceId,\n sessionId,\n { requests: repoPaths.map((root) => ({ status: { path: root } })) },\n { signal },\n );\n const statuses = batch.results.map((result, index) => ({\n root: repoPaths[index] ?? \"\",\n status: result.status,\n }));\n if (identityGenerationRef.current !== identityGeneration) return;\n const overlay = new Map<string, FileTreeStatus>();\n for (const { root, status } of statuses) {\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(qualifyStatusPath(root, file.path, rootPath), mapped);\n }\n }\n statusRef.current = overlay;\n setGitSummary(summarizeStatuses(statuses));\n setTree((prev) => applyStatus(prev));\n } catch {\n /* a non-repo box has no overlay — leave the tree untinted */\n } finally {\n if (identityGenerationRef.current === identityGeneration) setGitLoading(false);\n }\n },\n [client, workspaceId, sessionId, repoPaths, rootPath, applyStatus],\n );\n\n const performEventReconcile = useCallback(async () => {\n const parents = pendingParentsRef.current;\n pendingParentsRef.current = new Set();\n const wantGit = pendingGitRef.current;\n pendingGitRef.current = false;\n const signal = eventReadAbortRef.current.signal;\n const paths = [...parents];\n\n // File content is the primary Files-tab result. Reconcile it first, then add\n // the optional Git tint through a second serial request. This matches the\n // API's exact-provider serialization instead of making the two reads contend.\n await reconcilePaths(paths, signal);\n if (wantGit) await refreshGitOverlay(signal);\n }, [reconcilePaths, refreshGitOverlay]);\n const performEventReconcileRef = useRef(performEventReconcile);\n performEventReconcileRef.current = performEventReconcile;\n const reconcilePendingEvents = useCallback(async () => {\n eventReconcilePendingRef.current = true;\n const existing = eventReconcileInFlightRef.current;\n if (existing) return await existing;\n const identityGeneration = identityGenerationRef.current;\n const run = (async () => {\n while (\n eventReconcilePendingRef.current &&\n identityGenerationRef.current === identityGeneration\n ) {\n eventReconcilePendingRef.current = false;\n await performEventReconcileRef.current();\n }\n })();\n eventReconcileInFlightRef.current = run;\n try {\n await run;\n } finally {\n if (eventReconcileInFlightRef.current === run) eventReconcileInFlightRef.current = null;\n }\n }, []);\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 // • Generic command/tool output performs no provider reads. The canonical\n // turn-end capture refreshes the root once after the command burst settles.\n const events = options.events;\n\n useEffect(() => {\n if (!enabled || !events) return;\n // An inactive tab or holderless draining/cold lease must not replay the\n // historical log into live provider reads. The capture already includes\n // those events; a later warm transition performs one authoritative refresh.\n if (!active || !acceptsEventReads) {\n for (const event of events) {\n if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;\n }\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n debounceRef.current = null;\n }\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n eventReconcilePendingRef.current = false;\n return;\n }\n let sawNew = false;\n let contentChanged = 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 contentChanged = true;\n for (const change of payload.changes ?? []) {\n pendingParentsRef.current.add(parentWithinTree(change.path, rootPath));\n if (change.oldPath) {\n pendingParentsRef.current.add(parentWithinTree(change.oldPath, rootPath));\n }\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 if (contentChanged) setContentRevision((revision) => revision + 1);\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 if (!acceptsEventReadsRef.current) {\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n return;\n }\n void reconcilePendingEvents();\n }, 150);\n }, [enabled, active, acceptsEventReads, events, rootPath, reconcilePendingEvents]);\n\n useEffect(() => {\n if (active && acceptsEventReads) return;\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n debounceRef.current = null;\n }\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n eventReconcilePendingRef.current = false;\n }, [active, acceptsEventReads]);\n\n useEffect(\n () => () => {\n refreshAbortRef.current?.abort();\n identityAbortRef.current.abort();\n eventReadAbortRef.current.abort();\n eventReconcilePendingRef.current = false;\n identityGenerationRef.current += 1;\n if (debounceRef.current) clearTimeout(debounceRef.current);\n },\n [],\n );\n\n const identityMatches = enabled && stateIdentity === identityKey;\n return {\n tree: identityMatches ? tree : [],\n expand,\n expandingPaths: identityMatches ? expandingPaths : new Set<string>(),\n readFile,\n writeFile,\n createFile,\n createDir,\n deleteEntry,\n moveEntry,\n refresh,\n contentRevision: identityMatches ? contentRevision : 0,\n source: identityMatches ? source : null,\n capturedAt: identityMatches && source === \"capture\" ? (capture?.capturedAt ?? null) : null,\n gitSummary: identityMatches ? gitSummary : null,\n gitLoading: identityMatches && gitLoading,\n loading: identityMatches && loading,\n error: identityMatches ? error : null,\n };\n}\n","import type {\n GitFileDiff,\n SessionCapabilities,\n SessionEvent,\n WorkspaceCaptureManifest,\n WorkspaceCaptureRepo,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type ClientOverride, useOpenGeni } from \"../provider\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\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 /** All repository roots in the workspace. When supplied, status and diff are\n * aggregated into one workspace-wide result and paths are workspace-relative. */\n repoPaths?: readonly string[] | undefined;\n /** Diff the staged index vs HEAD (`--cached`) instead of the working tree. */\n staged?: boolean | undefined;\n /** Review scope. `branch` compares the current branch with the remote default\n * branch, `working` shows uncommitted edits, and `staged` shows the index.\n * `staged` above remains as a compatibility alias. */\n comparison?: SandboxGitComparison | undefined;\n /** Hold off the initial fetch. Default true. */\n enabled?: boolean | undefined;\n /** Pause live reads/invalidation while preserving the last rendered result. */\n active?: boolean | undefined;\n /** Lease liveness. `null` means capability negotiation is still pending and\n * blocks live I/O. When not warm, the diff is served from the capture instead\n * of a live `gitDiff` RPC. Omission preserves legacy direct-hook behavior. */\n liveness?: SessionCapabilities[\"liveness\"] | null | undefined;\n /** The latest turn-end capture (from `useWorkspaceCapture`). Seeds the diff\n * immediately; a warm box reconciles live and leaves this durable review\n * surface in place if the live request is temporarily unavailable. */\n capture?: WorkspaceCaptureManifest | null | undefined;\n};\n\nexport type SandboxGitComparison = \"branch\" | \"working\" | \"staged\";\n\n/** A Git diff qualified into workspace scope. `repoRoot` is present for the\n * workspace-wide path and lets review UI group real repositories without\n * guessing from the first path segment. */\nexport type SandboxGitFileDiff = GitFileDiff & {\n repoRoot?: string | 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: SandboxGitFileDiff[];\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 /** Number and workspace-relative roots of repositories represented here. */\n repoCount: number;\n repoRoots: string[];\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 const normalized = root\n .replaceAll(\"\\\\\", \"/\")\n .replace(/^\\.\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n return normalized === \".\" ? \"\" : normalized;\n}\n\nfunction qualifyPath(repoRoot: string, path: string): string {\n const root = normalizeRoot(repoRoot);\n return root ? `${root}/${path}` : path;\n}\n\nfunction qualifyDiff(repoRoot: string, file: GitFileDiff): SandboxGitFileDiff {\n const root = normalizeRoot(repoRoot);\n return {\n ...file,\n path: qualifyPath(root, file.path),\n oldPath: file.oldPath === null ? null : qualifyPath(root, file.oldPath),\n repoRoot: root,\n };\n}\n\nfunction uniqueRoots(roots: readonly string[]): string[] {\n return [...new Set(roots.map(normalizeRoot))].sort((a, b) => a.localeCompare(b));\n}\n\n// GitReadBatchRequest is contract-bounded to 32 items. Keep workspace-wide\n// reads bounded without changing the wire limit; sequential chunks preserve\n// deterministic root/result mapping and cap Channel-A lease concurrency at one.\nconst GIT_READ_BATCH_REQUEST_LIMIT = 32;\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: SandboxGitFileDiff, b: SandboxGitFileDiff): boolean {\n if (\n a.path !== b.path ||\n a.oldPath !== b.oldPath ||\n a.repoRoot !== b.repoRoot ||\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(\n current: SandboxGitFileDiff[],\n next: SandboxGitFileDiff[],\n): SandboxGitFileDiff[] {\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. 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 active = options.active ?? true;\n const repoPath = options.repoPath ?? \"\";\n const workspaceWide = options.repoPaths !== undefined;\n // Serialize the caller's array so inline values do not retrigger effects. An\n // explicitly empty advertised list falls back to the legacy repoPath probe.\n const repoPathsKey = uniqueRoots(\n options.repoPaths && options.repoPaths.length > 0 ? options.repoPaths : [repoPath],\n ).join(\"\\u0000\");\n const repoPaths = useMemo(() => repoPathsKey.split(\"\\u0000\"), [repoPathsKey]);\n const comparison: SandboxGitComparison =\n options.comparison ?? (options.staged ? \"staged\" : \"working\");\n const hasAdvertisedRepoPaths = (options.repoPaths?.length ?? 0) > 0;\n // New captures retain both working-tree and branch comparisons. Staged state\n // remains live-only; legacy captures simply lack branchDiff and fall back via\n // the workspace controller without inventing an empty branch comparison.\n const capture = comparison === \"staged\" ? null : (options.capture ?? null);\n const isLive = sandboxAcceptsLiveIo(options.liveness);\n // `liveness` is optional for compatibility with direct hook consumers. Explicit\n // `null` (negotiating) and lifecycle values require authoritative warm.\n const acceptsEventReads = options.liveness === undefined || isLive;\n const acceptsEventReadsRef = useRef(acceptsEventReads);\n acceptsEventReadsRef.current = acceptsEventReads;\n const hasLiveIoFence = options.liveness !== undefined;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${repoPathsKey}\\u0000${workspaceWide}\\u0000${comparison}`;\n\n const [diff, setDiff] = useState<SandboxGitFileDiff[]>([]);\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 [repoRoots, setRepoRoots] = useState<string[]>([]);\n const [source, setSource] = useState<\"live\" | \"capture\" | null>(null);\n const sourceRef = useRef<\"live\" | \"capture\" | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [stateIdentity, setStateIdentity] = useState(identityKey);\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 refreshAbortRef = useRef<AbortController | null>(null);\n const refreshInFlightRef = useRef<Promise<void> | null>(null);\n const refreshPendingRef = useRef(false);\n const refreshWorkerEpochRef = useRef(0);\n const lastChangeRef = useRef(0);\n const eventRefreshTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const performRefresh = useCallback(async () => {\n if (!sessionId) return;\n const refreshAbort = new AbortController();\n refreshAbortRef.current = refreshAbort;\n const generation = (refreshGenerationRef.current += 1);\n setLoading(true);\n setError(null);\n try {\n const diffRequest = (root: string) =>\n client.gitDiff(\n workspaceId,\n sessionId,\n {\n path: root,\n ...(comparison === \"branch\"\n ? { fromRef: \"origin/HEAD\", includeUntracked: true }\n : comparison === \"working\"\n ? { fromRef: \"HEAD\", includeUntracked: true }\n : { staged: true, includeUntracked: false }),\n },\n { signal: refreshAbort.signal },\n );\n\n // Capability-advertised roots are known repositories. Fetch status metadata\n // and diff hunks together: both are independent Channel-A reads and each can\n // take several seconds on a remote sandbox. The legacy root probe remains\n // serial so a non-repository workspace never receives a failing git diff.\n const prefetched = hasAdvertisedRepoPaths\n ? await (async () => {\n const prefetchedRepos: Array<{\n root: string;\n status: Awaited<ReturnType<typeof client.gitStatus>>;\n result: Awaited<ReturnType<typeof client.gitDiff>>;\n }> = [];\n for (\n let offset = 0;\n offset < repoPaths.length;\n offset += GIT_READ_BATCH_REQUEST_LIMIT\n ) {\n const roots = repoPaths.slice(offset, offset + GIT_READ_BATCH_REQUEST_LIMIT);\n const batch = await client.gitReadBatch(\n workspaceId,\n sessionId,\n {\n requests: roots.map((root) => ({\n status: { path: root },\n diff: {\n path: root,\n ...(comparison === \"branch\"\n ? { fromRef: \"origin/HEAD\", includeUntracked: true }\n : comparison === \"working\"\n ? { fromRef: \"HEAD\", includeUntracked: true }\n : { staged: true, includeUntracked: false }),\n },\n })),\n },\n { signal: refreshAbort.signal },\n );\n if (batch.results.length !== roots.length) {\n throw new Error(\n `Workspace Git batch returned ${batch.results.length} results for ${roots.length} repositories.`,\n );\n }\n batch.results.forEach((item, index) => {\n prefetchedRepos.push({\n root: roots[index]!,\n status: item.status,\n result: item.diff ?? {\n files: [],\n revision: item.status.revision,\n },\n });\n });\n }\n return prefetchedRepos;\n })()\n : null;\n const statuses =\n prefetched ??\n (await Promise.all(\n repoPaths.map(async (root) => ({\n root,\n status: await client.gitStatus(\n workspaceId,\n sessionId,\n { path: root },\n { signal: refreshAbort.signal },\n ),\n })),\n ));\n if (refreshGenerationRef.current !== generation) return;\n const repositories = statuses.filter(({ status }) => status.isRepo);\n const roots = repositories.map(({ root }) => root);\n setRepoRoots(roots);\n setIsRepo(repositories.length > 0);\n setBranch(repositories.length === 1 ? (repositories[0]?.status.head ?? null) : null);\n setAhead(repositories.reduce((sum, { status }) => sum + status.ahead, 0));\n setBehind(repositories.reduce((sum, { status }) => sum + status.behind, 0));\n if (repositories.length === 0) {\n setDiff([]);\n sourceRef.current = \"live\";\n setSource(\"live\");\n return;\n }\n const prefetchedByRoot = new Map(prefetched?.map(({ root, result }) => [root, result]));\n const results = await Promise.all(\n repositories.map(async ({ root }) => ({\n root,\n result: prefetchedByRoot.get(root) ?? (await diffRequest(root)),\n })),\n );\n if (refreshGenerationRef.current !== generation) return;\n // Merge in place so the cold→warm swap keeps unchanged file sections mounted.\n setDiff((prev) =>\n mergeDiffs(\n prev,\n results.flatMap(({ root, result }) =>\n workspaceWide ? result.files.map((file) => qualifyDiff(root, file)) : result.files,\n ),\n ),\n );\n sourceRef.current = \"live\";\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 if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;\n }\n }, [\n client,\n workspaceId,\n sessionId,\n repoPaths,\n hasAdvertisedRepoPaths,\n workspaceWide,\n comparison,\n ]);\n\n // Provider reads cannot be undispatched after they reach a remote sandbox.\n // Keep exactly one refresh in flight and collapse any burst of invalidations\n // into one trailing read. Aborting and replacing every tool-output refresh\n // used to leave several Modal reads contending for the same provider lock.\n const performRefreshRef = useRef(performRefresh);\n performRefreshRef.current = performRefresh;\n const refresh = useCallback(async () => {\n refreshPendingRef.current = true;\n const existing = refreshInFlightRef.current;\n if (existing) return await existing;\n\n const workerEpoch = refreshWorkerEpochRef.current;\n const run = (async () => {\n while (refreshPendingRef.current && refreshWorkerEpochRef.current === workerEpoch) {\n refreshPendingRef.current = false;\n await performRefreshRef.current();\n }\n })();\n refreshInFlightRef.current = run;\n try {\n await run;\n } finally {\n if (refreshInFlightRef.current === run) refreshInFlightRef.current = null;\n }\n }, []);\n\n // Serve the requested review scope from a capture when that scope exists.\n const seedFromCapture = useCallback(\n (manifest: WorkspaceCaptureManifest) => {\n const repositories = workspaceWide\n ? manifest.repos\n : ([repoForPath(manifest, repoPath)].filter(Boolean) as WorkspaceCaptureRepo[]);\n if (comparison === \"branch\" && repositories.some((repo) => repo.branchDiff === undefined)) {\n return;\n }\n if (repositories.length === 0) {\n setIsRepo(false);\n setBranch(null);\n setAhead(0);\n setBehind(0);\n setRepoRoots([]);\n setDiff((prev) => (prev.length === 0 ? prev : []));\n sourceRef.current = \"capture\";\n setSource(\"capture\");\n return;\n }\n setIsRepo(true);\n setBranch(repositories.length === 1 ? (repositories[0]?.head ?? null) : null);\n setAhead(repositories.reduce((sum, repo) => sum + repo.ahead, 0));\n setBehind(repositories.reduce((sum, repo) => sum + repo.behind, 0));\n setRepoRoots(repositories.map((repo) => normalizeRoot(repo.root)));\n setDiff((prev) =>\n mergeDiffs(\n prev,\n repositories.flatMap((repo) => {\n const capturedDiff = comparison === \"branch\" ? (repo.branchDiff ?? []) : repo.diff;\n return workspaceWide\n ? capturedDiff.map((file) => qualifyDiff(repo.root, file))\n : capturedDiff;\n }),\n ),\n );\n sourceRef.current = \"capture\";\n setSource(\"capture\");\n setError(null);\n },\n [comparison, repoPath, workspaceWide],\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 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 refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshPendingRef.current = false;\n refreshGenerationRef.current += 1;\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged) {\n // Different sessions target different provider identities. Fence the old\n // worker and let the new session load immediately instead of waiting for a\n // stuck request that has already been aborted.\n refreshWorkerEpochRef.current += 1;\n refreshInFlightRef.current = null;\n }\n if (identityChanged || !enabled) {\n lastChangeRef.current = 0;\n setDiff([]);\n setStateIdentity(identityKey);\n setIsRepo(false);\n setBranch(null);\n setAhead(0);\n setBehind(0);\n setRepoRoots([]);\n sourceRef.current = null;\n setSource(null);\n setLoading(false);\n setError(null);\n }\n if (!enabled) {\n return;\n }\n const currentCapture = captureRevision !== null ? captureRef.current : null;\n if (currentCapture && (identityChanged || !isLive || sourceRef.current !== \"live\")) {\n seedFromCapture(currentCapture);\n }\n if (!active) {\n if (!active) setLoading(false);\n return;\n }\n if (isLive || (!hasLiveIoFence && !currentCapture)) {\n void refresh();\n }\n return () => {\n refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshPendingRef.current = false;\n refreshGenerationRef.current += 1;\n };\n }, [\n enabled,\n active,\n isLive,\n hasLiveIoFence,\n captureRevision,\n identityKey,\n refresh,\n seedFromCapture,\n ]);\n\n // Structured Git changes are debounced into one live reconcile. Generic\n // command/tool output performs no provider reads: the canonical turn-end\n // capture advances `captureRevision`, which refreshes after the burst settles.\n const events = options.events;\n useEffect(() => {\n if (!enabled || !events) {\n if (eventRefreshTimerRef.current) {\n clearTimeout(eventRefreshTimerRef.current);\n eventRefreshTimerRef.current = null;\n }\n return;\n }\n // Historical events describe the capture we already loaded. Inactive tabs\n // and holderless draining/cold leases advance the cursor without issuing\n // provider I/O; becoming warm performs one authoritative reconcile above.\n if (!active || !acceptsEventReads) {\n for (const event of events) {\n if (event.sequence > lastChangeRef.current) lastChangeRef.current = event.sequence;\n }\n if (eventRefreshTimerRef.current) {\n clearTimeout(eventRefreshTimerRef.current);\n eventRefreshTimerRef.current = null;\n }\n return;\n }\n let latest = lastChangeRef.current;\n let changed = false;\n for (const event of events) {\n if (event.sequence <= latest) continue;\n if (event.type === \"git.changed\") {\n latest = event.sequence;\n changed = true;\n }\n }\n if (latest > lastChangeRef.current) {\n lastChangeRef.current = latest;\n if (!changed) return;\n if (eventRefreshTimerRef.current) clearTimeout(eventRefreshTimerRef.current);\n eventRefreshTimerRef.current = setTimeout(() => {\n eventRefreshTimerRef.current = null;\n if (acceptsEventReadsRef.current) void refresh();\n }, 150);\n }\n }, [enabled, active, acceptsEventReads, events, refresh]);\n\n useEffect(\n () => () => {\n if (eventRefreshTimerRef.current) clearTimeout(eventRefreshTimerRef.current);\n },\n [],\n );\n\n const identityMatches = enabled && stateIdentity === identityKey;\n const visibleRepoRoots = identityMatches ? repoRoots : [];\n return {\n diff: identityMatches ? diff : [],\n branch: identityMatches ? branch : null,\n isRepo: identityMatches && isRepo,\n ahead: identityMatches ? ahead : 0,\n behind: identityMatches ? behind : 0,\n repoCount: visibleRepoRoots.length,\n repoRoots: visibleRepoRoots,\n refresh,\n source: identityMatches ? source : null,\n capturedAt: identityMatches && source === \"capture\" ? (capture?.capturedAt ?? null) : null,\n loading: identityMatches && loading,\n error: identityMatches ? error : null,\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\ntype AvailableCaptureResponse = Extract<GetWorkspaceCaptureResponse, { available: true }>;\n\nconst CAPTURE_STATS_NUMBER_FIELDS = [\n \"repoCount\",\n \"fileCount\",\n \"additions\",\n \"deletions\",\n \"totalBytes\",\n \"tooLargeCount\",\n \"binaryCount\",\n \"treeEntryCount\",\n \"durationMs\",\n] as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Signed manifests bypass the authenticated JSON client's wire decoder. Treat\n * the blob as untrusted until its outer schema and exact revision identity match\n * the metadata response that minted the URL. The API performs the full contract\n * parse; this client-side boundary prevents a corrupt/mis-keyed response from\n * being presented as a different authoritative capture.\n */\nfunction captureManifestForResponse(\n value: unknown,\n response: AvailableCaptureResponse,\n): WorkspaceCaptureManifest {\n if (\n !isRecord(value) ||\n value.version !== 1 ||\n !Number.isSafeInteger(value.revision) ||\n typeof value.capturedAt !== \"string\" ||\n !(value.turnId === null || typeof value.turnId === \"string\") ||\n !Number.isSafeInteger(value.leaseEpoch) ||\n !isRecord(value.treeIndex) ||\n typeof value.treeTruncated !== \"boolean\" ||\n !Array.isArray(value.repos) ||\n !Array.isArray(value.files) ||\n !isRecord(value.stats)\n ) {\n throw new Error(\"Workspace capture manifest failed validation.\");\n }\n\n if (\n value.revision !== response.revision ||\n value.capturedAt !== response.capturedAt ||\n value.turnId !== response.turnId ||\n value.leaseEpoch !== response.leaseEpoch\n ) {\n throw new Error(\"Workspace capture manifest identity did not match its response.\");\n }\n\n for (const field of CAPTURE_STATS_NUMBER_FIELDS) {\n if (!Number.isSafeInteger(value.stats[field]) || value.stats[field] !== response.stats[field]) {\n throw new Error(\"Workspace capture manifest statistics did not match its response.\");\n }\n }\n if (\n typeof value.stats.treeTruncated !== \"boolean\" ||\n value.stats.treeTruncated !== response.stats.treeTruncated ||\n (value.stats.fingerprint ?? null) !== (response.stats.fingerprint ?? null) ||\n value.repos.length !== response.stats.repoCount ||\n value.files.length !== response.stats.fileCount ||\n value.treeTruncated !== response.stats.treeTruncated\n ) {\n throw new Error(\"Workspace capture manifest statistics did not match its response.\");\n }\n\n return value as WorkspaceCaptureManifest;\n}\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). 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 const requestAbortRef = useRef<AbortController | null>(null);\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 requestAbortRef.current?.abort();\n const requestAbort = new AbortController();\n requestAbortRef.current = requestAbort;\n const generation = (generationRef.current += 1);\n setStateIdentity(identityKey);\n setLoading(true);\n setError(null);\n try {\n // A signed URL can expire between mint and GET. Re-enter the authenticated\n // endpoint once to mint a fresh URL; never replay or log the old credential.\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const res: GetWorkspaceCaptureResponse = await client.getWorkspaceCapture(\n workspaceId,\n sessionId,\n { signal: requestAbort.signal },\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 manifestValue: unknown = res.manifest;\n if (!manifestValue && res.manifestUrl) {\n const response = await fetch(res.manifestUrl.url, {\n signal: AbortSignal.any([\n requestAbort.signal,\n AbortSignal.timeout(MANIFEST_FETCH_TIMEOUT_MS),\n ]),\n credentials: \"omit\",\n cache: \"no-store\",\n referrerPolicy: \"no-referrer\",\n }).catch(() => null);\n if (generationRef.current !== generation) return;\n if (!response?.ok) {\n if (\n attempt === 0 &&\n (response === null || response.status === 401 || response.status === 403)\n ) {\n continue;\n }\n throw new Error(\n `Workspace capture manifest download failed${response ? ` (${response.status})` : \"\"}.`,\n );\n }\n try {\n manifestValue = await response.json();\n } catch {\n throw new Error(\"Workspace capture manifest was not valid JSON.\");\n }\n if (generationRef.current !== generation) return;\n }\n if (!manifestValue) {\n throw new Error(\"Workspace capture response did not include a manifest.\");\n }\n const manifest = captureManifestForResponse(manifestValue, res);\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 return;\n }\n throw new Error(\"Workspace capture manifest download failed after refreshing its URL.\");\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 if (requestAbortRef.current === requestAbort) requestAbortRef.current = null;\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 requestAbortRef.current?.abort();\n requestAbortRef.current = null;\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 requestAbortRef.current?.abort();\n requestAbortRef.current = null;\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 // The mount request is already resolving the latest revision. Do not abort\n // and replace that exact identity-equivalent read merely because the event\n // tail announced a revision before the response arrived. When the request\n // settles, its state update re-runs this effect and a genuinely newer\n // announcement still refreshes immediately.\n if (requestAbortRef.current) 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 type { FileSystemRouteIdentity } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\n\n/**\n * The wake-on-edit state machine. This hook owns the logic and the UI renders\n * its result. 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 /** Exact capability identity for the selected filesystem route. A route/root\n * change discards the buffered edit and makes stale flushes fail retryably. */\n route?: FileSystemRouteIdentity | 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 sandboxAcceptsLiveIo(liveness);\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.\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 design specifies — 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 routeEpoch = options.route?.epoch;\n const routeRoot = options.route?.root;\n const route = useMemo<FileSystemRouteIdentity | undefined>(\n () =>\n routeEpoch !== undefined && routeRoot !== undefined\n ? { epoch: routeEpoch, root: routeRoot }\n : undefined,\n [routeEpoch, routeRoot],\n );\n const live = isLive(options.liveness);\n const offline = options.offline === true;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${path ?? \"\"}\\u0000${routeEpoch ?? \"\"}\\u0000${routeRoot ?? \"\"}`;\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 const [stateIdentity, setStateIdentity] = useState(identityKey);\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 const identityGenerationRef = useRef(0);\n const flushAttemptRef = useRef(0);\n const readAbortRef = useRef<AbortController | null>(null);\n\n // Reset the machine when the edited file (or session) changes.\n useEffect(() => {\n identityGenerationRef.current += 1;\n flushAttemptRef.current += 1;\n readAbortRef.current?.abort();\n readAbortRef.current = null;\n setStateIdentity(identityKey);\n setBuffer(null);\n setWantsWarm(false);\n setFlush(\"idle\");\n setConflict(null);\n setError(null);\n flushingRef.current = false;\n return () => {\n identityGenerationRef.current += 1;\n flushAttemptRef.current += 1;\n readAbortRef.current?.abort();\n readAbortRef.current = null;\n };\n }, [identityKey]);\n\n const edit = useCallback(\n (content: string) => {\n if (stateIdentity !== identityKey) return;\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, stateIdentity, identityKey],\n );\n\n const doFlush = useCallback(\n async (force: boolean) => {\n if (stateIdentity !== identityKey) return;\n if (!sessionId || !path) return;\n const content = bufferRef.current;\n if (content === null) return;\n if (flushingRef.current) return;\n const identityGeneration = identityGenerationRef.current;\n const flushAttempt = (flushAttemptRef.current += 1);\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 readAbort = new AbortController();\n readAbortRef.current?.abort();\n readAbortRef.current = readAbort;\n const liveRead = await client.fsRead(\n workspaceId,\n sessionId,\n { path, ...(route ? { route } : {}) },\n { signal: readAbort.signal },\n );\n if (readAbortRef.current === readAbort) readAbortRef.current = null;\n if (identityGenerationRef.current !== identityGeneration) return;\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, {\n path,\n content,\n overwrite: true,\n ...(route ? { route } : {}),\n });\n if (identityGenerationRef.current !== identityGeneration) return;\n setConflict(null);\n setFlush(\"flushed\");\n setWantsWarm(false);\n } catch (cause) {\n if (identityGenerationRef.current !== identityGeneration) return;\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 if (flushAttemptRef.current === flushAttempt) {\n flushingRef.current = false;\n readAbortRef.current = null;\n }\n }\n },\n [client, workspaceId, sessionId, path, baseContent, route, stateIdentity, identityKey],\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 const identityMatches = stateIdentity === identityKey;\n return {\n state: identityMatches ? state : offline ? \"readonly-offline\" : \"viewing-cold\",\n readOnly: offline,\n buffer: identityMatches ? buffer : null,\n wantsWarm: identityMatches && wantsWarm,\n edit,\n conflict: identityMatches ? conflict : null,\n overwrite,\n discard,\n error: identityMatches ? error : null,\n };\n}\n","import { useMemo } from \"react\";\nimport type { MachineState } from \"@opengeni/sdk\";\nimport type { SessionCapabilitiesState } from \"./use-session-capabilities\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport { connectionStatusForState } from \"../types/machines\";\n\n/** The one truthful machine indicator. Managed cold compute is sleeping; a\n * Connected Machine that is genuinely unreachable remains offline. */\nexport type MachineChipState = \"live\" | \"waking\" | \"offline\";\n\nexport type MachineChip = {\n state: MachineChipState;\n /** A ready-to-render label (\"Live\" / \"Waking…\" / \"Sleeping · saved 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 lease → **live** (a holder-confirmed 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 managedRestingLabel = asOf ? `Sleeping · saved ${formatAsOf(asOf, now)}` : \"Sleeping\";\n const offlineLabel = \"Offline\";\n\n // A connected machine has no Modal group lease, so capability negotiation\n // legitimately reports `cold` until a stream holder is minted. Its fleet\n // probe is the authoritative reachability signal; do not label an online Mac\n // \"Offline\" merely because there is no unrelated Modal lease.\n const selfhostedOnline =\n input.activeIsSelfhosted === true &&\n input.activeMachineState != null &&\n connectionStatusForState(input.activeMachineState) === \"online\";\n\n // 1. A holder-confirmed warm provider or online connected machine is live.\n // Draining remains teardown-owned and may already have lost its instance.\n if (sandboxAcceptsLiveIo(input.liveness) || selfhostedOnline) {\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\".\n const selfhostedOffline =\n input.activeIsSelfhosted === true && input.activeMachineState === \"offline\";\n\n // Capability negotiation has definitively failed. A retained warm intent\n // must not turn that error into the optimistic Waking state.\n if (input.capabilitiesState === \"error\") {\n return {\n state: \"offline\",\n label: input.activeIsSelfhosted === true ? offlineLabel : managedRestingLabel,\n asOf,\n };\n }\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. Managed cold compute is sleeping with saved-workspace freshness. A\n // Connected Machine is only described as Offline when its reachability is\n // genuinely unavailable; capture time is not a heartbeat.\n return {\n state: \"offline\",\n label: input.activeIsSelfhosted === true ? offlineLabel : managedRestingLabel,\n asOf,\n };\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 { CheckIcon, ShieldCheckIcon, XIcon } from \"lucide-react\";\nimport { useEffect, useId, useRef, useState, type ReactNode } from \"react\";\nimport type { PendingApproval } from \"../approvals\";\nimport { cn } from \"../lib/cn\";\n\nexport type ApprovalSurfaceMessages = {\n title: string;\n description: string;\n approve: string;\n reject: string;\n approving: string;\n rejecting: string;\n formatToolName: (name: string) => string;\n};\n\nexport const defaultApprovalSurfaceMessages: ApprovalSurfaceMessages = {\n title: \"Approval required\",\n description: \"Review the requested action before the agent continues.\",\n approve: \"Approve\",\n reject: \"Reject\",\n approving: \"Approving…\",\n rejecting: \"Rejecting…\",\n formatToolName: (name) => name.replaceAll(\"_\", \" \").replaceAll(\".\", \" › \"),\n};\n\nexport type ApprovalSurfaceProps = {\n approvals: PendingApproval[];\n onApprove: (approval: PendingApproval) => void | Promise<void>;\n onReject: (approval: PendingApproval) => void | Promise<void>;\n responding?: boolean | undefined;\n error?: string | Error | null | undefined;\n messages?: Partial<ApprovalSurfaceMessages> | undefined;\n renderApproval?: ((approval: PendingApproval) => ReactNode) | undefined;\n className?: string | undefined;\n};\n\nconst APPROVAL_ARGUMENT_PREVIEW_CHARACTERS = 4_000;\n\nfunction approvalArgumentsPreview(value: unknown): string | null {\n if (value === undefined) return null;\n let serialized: string;\n try {\n serialized =\n typeof value === \"string\" ? value : (JSON.stringify(value, null, 2) ?? String(value));\n } catch {\n serialized = \"[Arguments unavailable]\";\n }\n const characters = Array.from(serialized);\n if (characters.length <= APPROVAL_ARGUMENT_PREVIEW_CHARACTERS) return serialized;\n return `${characters.slice(0, APPROVAL_ARGUMENT_PREVIEW_CHARACTERS).join(\"\")}\\n… ${characters.length - APPROVAL_ARGUMENT_PREVIEW_CHARACTERS} characters omitted`;\n}\n\nfunction approvalOwnershipKey(approval: PendingApproval): string {\n return `${approval.id}\\u0000${approval.name}\\u0000${approvalArgumentsPreview(approval.arguments) ?? \"\"}`;\n}\n\n/**\n * Host-neutral approval presentation backed by the native pending-approval\n * projection and control callbacks. It owns only presentation and duplicate\n * click fencing; OpenGeni remains the authority for approval state.\n */\nexport function ApprovalSurface({\n approvals,\n onApprove,\n onReject,\n responding = false,\n error,\n messages: overrides,\n renderApproval,\n className,\n}: ApprovalSurfaceProps) {\n const titleId = useId();\n const messages = { ...defaultApprovalSurfaceMessages, ...overrides };\n const [pending, setPending] = useState<{\n approvalKey: string;\n decision: \"approve\" | \"reject\";\n token: symbol;\n } | null>(null);\n const pendingRef = useRef<{ approvalKey: string; token: symbol } | null>(null);\n const [decisionError, setDecisionError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (\n pending &&\n !approvals.some((approval) => approvalOwnershipKey(approval) === pending.approvalKey)\n ) {\n if (pendingRef.current?.token === pending.token) {\n pendingRef.current = null;\n }\n setPending((current) => (current?.token === pending.token ? null : current));\n }\n }, [approvals, pending]);\n\n if (approvals.length === 0) return null;\n const busy = responding || pendingRef.current !== null;\n const decide = async (\n approval: PendingApproval,\n decision: \"approve\" | \"reject\",\n ): Promise<void> => {\n if (responding || pendingRef.current !== null) return;\n const approvalKey = approvalOwnershipKey(approval);\n const token = Symbol(approvalKey);\n pendingRef.current = { approvalKey, token };\n setPending({ approvalKey, decision, token });\n setDecisionError(null);\n try {\n await (decision === \"approve\" ? onApprove(approval) : onReject(approval));\n // Keep the decision fenced until the authoritative projection removes or\n // replaces this exact approval. A successful callback is transport\n // acceptance, not settlement.\n } catch (cause) {\n if (pendingRef.current?.token === token) {\n pendingRef.current = null;\n setPending((current) => (current?.token === token ? null : current));\n setDecisionError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n }\n };\n const errorMessage = decisionError?.message ?? (error instanceof Error ? error.message : error);\n\n return (\n <section\n className={cn(\n \"og-root flex w-full flex-col gap-3 rounded-og-lg border border-og-status-waiting/35 bg-og-status-waiting/5 p-4 shadow-og-sm\",\n className,\n )}\n aria-labelledby={titleId}\n >\n <header className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 inline-flex size-8 shrink-0 items-center justify-center rounded-og-md bg-og-status-waiting/12 text-og-status-waiting\">\n <ShieldCheckIcon aria-hidden=\"true\" className=\"size-4\" />\n </span>\n <div className=\"min-w-0\">\n <h2 id={titleId} className=\"text-og-md font-semibold text-og-fg\">\n {messages.title}\n </h2>\n <p className=\"mt-0.5 text-og-sm text-og-fg-muted\">{messages.description}</p>\n </div>\n </header>\n\n <div className=\"flex flex-col gap-2\">\n {approvals.map((approval) => {\n const approvalKey = approvalOwnershipKey(approval);\n const active = pending?.approvalKey === approvalKey ? pending.decision : null;\n const argumentsPreview = approvalArgumentsPreview(approval.arguments);\n return (\n <article\n key={approval.id}\n data-approval-id={approval.id}\n className=\"rounded-og-md border border-og-border bg-og-surface-1 p-3\"\n >\n {renderApproval ? (\n renderApproval(approval)\n ) : (\n <>\n <p className=\"text-og-sm font-medium text-og-fg\">\n {messages.formatToolName(approval.name)}\n </p>\n {argumentsPreview !== null ? (\n <pre className=\"mt-2 max-h-48 overflow-auto whitespace-pre-wrap break-words rounded-og-sm bg-og-surface-2 p-2 font-mono text-og-xs text-og-fg-muted\">\n {argumentsPreview}\n </pre>\n ) : null}\n </>\n )}\n <div className=\"mt-3 flex flex-wrap justify-end gap-2\">\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => void decide(approval, \"reject\")}\n className=\"inline-flex min-h-9 items-center gap-1.5 rounded-og-md border border-og-border px-3 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50\"\n >\n <XIcon aria-hidden=\"true\" className=\"size-3.5\" />\n {active === \"reject\" ? messages.rejecting : messages.reject}\n </button>\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => void decide(approval, \"approve\")}\n className=\"inline-flex min-h-9 items-center gap-1.5 rounded-og-md bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg transition-colors hover:bg-og-accent-strong disabled:opacity-50\"\n >\n <CheckIcon aria-hidden=\"true\" className=\"size-3.5\" />\n {active === \"approve\" ? messages.approving : messages.approve}\n </button>\n </div>\n </article>\n );\n })}\n </div>\n\n {errorMessage ? (\n <p role=\"alert\" className=\"text-og-sm text-og-status-failed\">\n {errorMessage}\n </p>\n ) : null}\n </section>\n );\n}\n","import { deriveSessionDisplayTitle, type Session } from \"@opengeni/sdk\";\nimport { cn } from \"../lib/cn\";\nimport { formatRelativeTime } from \"../lib/format\";\nimport { SessionStatus } from \"./session-status\";\n\nconst SESSION_METADATA_TITLE_KEYS = [\"title\", \"name\"] as const;\n\nexport type FleetTileProps = {\n session: Session;\n /** Overrides the derived title (durable title, metadata, prompt preview, or safe fallback). */\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 return deriveSessionDisplayTitle(session, { metadataKeys: SESSION_METADATA_TITLE_KEYS });\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, useLayoutEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { type TerminalStreamStatus, useTerminalStream } from \"../hooks/use-terminal-stream\";\nimport type { UseSandboxTerminalResult } from \"../hooks/use-sandbox-terminal\";\nimport { resolveTerminalFont, xtermThemeFromTokens } from \"../lib/xterm-theme\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport { terminalCanAcquirePty } from \"../lib/terminal-capability\";\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 engaged 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 /** Re-negotiate the terminal capability after an unexpected socket failure. */\n onReconnectNeeded?: (() => 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 focus: () => 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\nexport type TerminalSurfaceState =\n | \"loading\"\n | \"connecting\"\n | \"error\"\n | \"waking\"\n | \"output-only\"\n | \"interactive\";\n\n/**\n * Stable semantic state for hosts and browser acceptance. The xterm helper\n * textarea exists before the live PTY socket is ready, so its presence alone\n * must never be treated as proof that keystrokes can reach the sandbox.\n */\nexport function terminalSurfaceState(input: {\n ready: boolean;\n acceptsInput: boolean;\n inputPending: boolean;\n ptyStatus: TerminalStreamStatus;\n booting: boolean;\n}): TerminalSurfaceState {\n if (!input.ready) return \"loading\";\n if (input.acceptsInput) return \"interactive\";\n if (input.inputPending) return \"connecting\";\n if (input.ptyStatus === \"connecting\") return \"connecting\";\n if (input.ptyStatus === \"error\") return \"error\";\n if (input.booting) return \"waking\";\n return \"output-only\";\n}\n\nexport function subscribeTerminalInput(\n term: Pick<XtermLike, \"onData\"> | null,\n sink: ((data: string) => void) | null,\n enabled: boolean,\n): { dispose: () => void } | null {\n if (!enabled || !term || !sink) return null;\n return term.onData(sink);\n}\n\n/** Clear the transient wake line and put the first live prompt at cell 1,1.\n * `Terminal.clear()` removes scrollback but deliberately preserves the cursor,\n * which lets the first PTY frame append to the old wake message. */\nexport function clearTerminalBootStatus(term: Pick<XtermLike, \"write\">): void {\n term.write(\"\\r\\x1b[2K\\x1b[2J\\x1b[H\");\n}\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 onReconnectNeeded,\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 [inputReady, setInputReady] = useState(false);\n const [activated, setActivated] = useState(false);\n\n // ── Interactive transport switch ─────────────────────────────────────────────\n const ptyDescriptor =\n terminalCapability?.transport === \"pty-ws\" || terminalCapability?.transport === \"relay-pty\";\n const ptyAttachable = terminalCanAcquirePty(terminalCapability);\n const {\n status: ptyStatus,\n write: ptyWrite,\n resize: resizePty,\n connected: ptyConnected,\n } = useTerminalStream({\n // Connect only after xterm exists. This makes the renderer the sole output\n // owner from the first websocket frame and removes an otherwise unbounded\n // pre-mount output queue during large command bursts.\n capability:\n ptyAttachable && ready\n ? {\n transport: terminalCapability!.transport,\n url: ptyDescriptor ? terminalCapability!.url : null,\n token: ptyDescriptor ? terminalCapability!.token : null,\n expiresAt: ptyDescriptor ? terminalCapability!.expiresAt : null,\n }\n : null,\n onOutput: (data) => {\n termRef.current?.write(data);\n },\n onReconnectNeeded,\n });\n\n // A pty-ws capability exclusively owns the screen even while connecting or\n // after a visible connection failure; never silently switch one terminal UI\n // between two PTYs. Input is enabled during the handshake because the stream\n // hook buffers it strictly and flushes only after ttyd auth succeeds.\n const ptyMode = ptyDescriptor;\n // Keep xterm stdin live for an attachable descriptor even before its URL has\n // arrived. Focus/click triggers the grant; any immediately following input is\n // bounded in the stream hook instead of disappearing in that HTTP interval.\n const ptyCapturesInput = ptyAttachable && ptyStatus !== \"error\";\n const interactive = !readOnly && (ptyAttachable ? ptyCapturesInput : result.write !== null);\n // Public \"interactive\" means the mounted input subscription can reach a live\n // PTY now. Before that point xterm still captures into the bounded queue, but\n // acceptance and embedders see an explicit connecting state.\n const acceptsInput = inputReady && (!ptyAttachable || ptyConnected);\n const inputPending = inputReady && ptyAttachable && !ptyConnected && activated;\n let terminalModeLabel: string | null;\n if (readOnly) terminalModeLabel = \"read-only\";\n else if (!ptyAttachable) terminalModeLabel = acceptsInput ? null : \"output only\";\n else if (ptyStatus === \"error\") terminalModeLabel = \"connection error\";\n else if (acceptsInput) terminalModeLabel = null;\n else terminalModeLabel = activated ? \"connecting\" : \"connect on input\";\n\n // Boot-in-terminal: after the user engages 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 = sandboxAcceptsLiveIo(liveness);\n const booting =\n activated &&\n !ptyMode &&\n !warm &&\n liveness !== null &&\n liveness !== undefined &&\n result.chunks.length === 0;\n const surfaceState = terminalSurfaceState({\n ready,\n acceptsInput,\n inputPending,\n ptyStatus,\n booting,\n });\n\n function handleActivate() {\n // Capture-phase activation may synchronously negotiate a fresh terminal\n // capability and rerender the shell. Focus xterm before that state change so\n // the user's first keystroke or paste reaches its already-bounded input\n // queue instead of landing on the surrounding dock.\n const term = termRef.current;\n if (term && !readOnly && (ptyAttachable || result.write !== null)) {\n term.options.disableStdin = false;\n term.options.cursorBlink = true;\n }\n term?.focus();\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 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 useLayoutEffect(() => {\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) clearTerminalBootStatus(term);\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. `ptyWrite` is stable across socket\n // status changes, so this subscription does not tear down while a grant opens\n // or rotates and cannot create a first-keystroke gap.\n useLayoutEffect(() => {\n const term = termRef.current;\n if (!ready || !term || !interactive) {\n setInputReady(false);\n return;\n }\n const sink = ptyAttachable ? ptyWrite : result.write;\n if (!sink) {\n setInputReady(false);\n return;\n }\n const sub = subscribeTerminalInput(term, sink, true);\n setInputReady(sub !== null);\n return () => sub?.dispose();\n }, [ready, interactive, ptyAttachable, 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 {terminalModeLabel && (\n <span\n className=\"rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-xs uppercase tracking-wide\"\n role=\"status\"\n >\n {terminalModeLabel}\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-11\"\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 data-opengeni-terminal-ready={ready ? \"true\" : \"false\"}\n data-opengeni-terminal-interactive={surfaceState === \"interactive\" ? \"true\" : \"false\"}\n data-opengeni-terminal-state={surfaceState}\n data-opengeni-terminal-status={ptyAttachable ? ptyStatus : \"firehose\"}\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 TriangleAlertIcon,\n Trash2Icon,\n} from \"lucide-react\";\nimport {\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { AlertDialog } from \"radix-ui\";\nimport { VList, type VListHandle } from \"virtua\";\nimport { cn } from \"../lib/cn\";\nimport {\n type PortalTokenStyle,\n usePortalTokenSource,\n usePortalTokenStyle,\n} from \"../lib/use-portal-token-style\";\nimport { useUnicodeFallbackFonts } from \"../lib/use-unicode-fonts\";\nimport type { FileTreeNode, UseSandboxFilesResult } from \"../hooks/use-sandbox-files\";\nimport { visibleFileTree, type FileNodeVisibilityPredicate } from \"../file-node-visibility\";\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 /** Presentation-only node filter. Hidden parents never expose their children. */\n isNodeVisible?: FileNodeVisibilityPredicate | undefined;\n /** Deliberately reveal this selected path by lazily opening every loaded\n * ancestor and scrolling its row into view. The path is opaque and is never\n * normalized or re-rooted here. */\n revealPath?: string | undefined;\n /** Increment/change to reveal the same path again after a user collapses it. */\n revealPathRequestId?: string | number | 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 * The default is an accessible, non-blocking confirmation dialog. Supply this\n * callback to delegate confirmation to a host-owned dialog.\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\nfunction pathIsInsideDirectory(path: string, directory: string): boolean {\n if (!path.startsWith(directory) || path === directory) return false;\n if (directory.endsWith(\"/\") || directory.endsWith(\"\\\\\")) return true;\n const boundary = path[directory.length];\n return boundary === \"/\" || boundary === \"\\\\\";\n}\n\n/** Walk the authoritative tree without assuming its target-owned separator. */\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 && pathIsInsideDirectory(path, node.path)) {\n const hit = findNode(node.children, path);\n if (hit) return hit;\n }\n }\n return undefined;\n}\n\ntype RevealTrace = {\n directories: string[];\n frontier: string | null;\n};\n\n/** Follow only paths already named by the authoritative tree. This deliberately\n * avoids manufacturing ancestors from a platform-specific path string. */\nfunction traceRevealPath(nodes: FileTreeNode[], targetPath: string): RevealTrace {\n for (const node of nodes) {\n if (node.path === targetPath) {\n return {\n directories: node.kind === \"dir\" ? [node.path] : [],\n frontier: node.kind === \"dir\" && node.children === undefined ? node.path : null,\n };\n }\n if (node.kind !== \"dir\" || !pathIsInsideDirectory(targetPath, node.path)) continue;\n if (node.children === undefined) {\n return { directories: [node.path], frontier: node.path };\n }\n const child = traceRevealPath(node.children, targetPath);\n return {\n directories: [node.path, ...child.directories],\n frontier: child.frontier,\n };\n }\n return { directories: [], frontier: null };\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 isNodeVisible,\n revealPath,\n revealPathRequestId,\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 [pendingDelete, setPendingDelete] = useState<FileTreeNode | null>(null);\n const [busy, setBusy] = useState(false);\n const [coarsePointer, setCoarsePointer] = useState(false);\n const [revealRequest, setRevealRequest] = useState<{\n path: string;\n requestId: string | number;\n } | null>(null);\n const handledRevealRequestRef = useRef<{\n path: string;\n requestId: string | number;\n } | null>(null);\n const attemptedRevealPathsRef = useRef<Set<string>>(new Set());\n const treeId = useId();\n const container = usePortalTokenSource<HTMLDivElement>();\n const containerRef = container.currentRef;\n const deleteReturnFocusRef = useRef<HTMLElement | null>(null);\n const vlistRef = useRef<VListHandle>(null);\n const portalTokenStyle = usePortalTokenStyle(container.source);\n const getTreeElement = useCallback(\n () => (typeof document === \"undefined\" ? null : document.getElementById(treeId)),\n [treeId],\n );\n const visibleTree = useMemo(\n () => visibleFileTree(result.tree, isNodeVisible),\n [isNodeVisible, result.tree],\n );\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 const effectiveRevealRequestId = revealPath ? (revealPathRequestId ?? revealPath) : null;\n useEffect(() => {\n if (!revealPath || effectiveRevealRequestId === null) {\n setRevealRequest(null);\n return;\n }\n const handled = handledRevealRequestRef.current;\n if (handled?.path === revealPath && handled.requestId === effectiveRevealRequestId) return;\n handledRevealRequestRef.current = {\n path: revealPath,\n requestId: effectiveRevealRequestId,\n };\n attemptedRevealPathsRef.current = new Set();\n setActive(null);\n setRevealRequest({ path: revealPath, requestId: effectiveRevealRequestId });\n }, [effectiveRevealRequestId, revealPath]);\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 visibleActive = active && findNode(visibleTree, active) ? active : null;\n const cursor =\n visibleActive ?? (selectedPath && findNode(visibleTree, selectedPath) ? selectedPath : null);\n useEffect(() => {\n if (active !== null && visibleActive === null) setActive(null);\n }, [active, visibleActive]);\n\n const expand = useCallback(\n async (path: string) => {\n const node = findNode(visibleTree, 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, visibleTree],\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 useEffect(() => {\n if (!revealRequest) return;\n const trace = traceRevealPath(visibleTree, revealRequest.path);\n if (trace.directories.length > 0) {\n setExpanded((previous) => {\n const next = new Set(previous);\n let changed = false;\n for (const path of trace.directories) {\n if (next.has(path)) continue;\n next.add(path);\n changed = true;\n }\n return changed ? next : previous;\n });\n }\n const frontier = trace.frontier;\n if (\n !frontier ||\n attemptedRevealPathsRef.current.has(frontier) ||\n loadingPaths.has(frontier) ||\n result.expandingPaths.has(frontier)\n ) {\n return;\n }\n attemptedRevealPathsRef.current.add(frontier);\n void expand(frontier);\n }, [expand, loadingPaths, result.expandingPaths, revealRequest, visibleTree]);\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(visibleTree, 0);\n return items;\n }, [visibleTree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);\n const unicodeFontPaths = useMemo(\n () => renderItems.flatMap((item) => (item.type === \"node\" ? [item.node.path] : [])),\n [renderItems],\n );\n useUnicodeFallbackFonts(unicodeFontPaths);\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 const rowIndexByPath = useMemo(\n () => new Map(flatRows.map((row, index) => [row.node.path, index] as const)),\n [flatRows],\n );\n const treePositionByPath = useMemo(() => {\n const positions = new Map<string, { position: number; setSize: number }>();\n const visit = (nodes: FileTreeNode[]) => {\n nodes.forEach((node, index) => {\n positions.set(node.path, { position: index + 1, setSize: nodes.length });\n if (node.children) visit(node.children);\n });\n };\n visit(visibleTree);\n return positions;\n }, [visibleTree]);\n const cursorIndex = cursor ? (rowIndexByPath.get(cursor) ?? -1) : -1;\n const activeDescendantId = cursorIndex >= 0 ? `${treeId}-item-${cursorIndex}` : undefined;\n\n // A capture is immutable review data even if a stale capability document still\n // says the machine is writable. Mutations become available only after a live\n // reconciliation has actually succeeded.\n const supportsMutation =\n editable && result.source === \"live\" && result.error === null && !result.loading;\n\n const performDelete = useCallback(\n async (node: FileTreeNode) => {\n if (!supportsMutation) return;\n const recursive = node.kind === \"dir\";\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, result],\n );\n\n const runDelete = useCallback(\n async (node: FileTreeNode, returnFocus?: HTMLElement) => {\n if (!supportsMutation) return;\n setMenu(null);\n if (!confirmDelete) {\n deleteReturnFocusRef.current =\n returnFocus ??\n (typeof document !== \"undefined\" && document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null);\n setPendingDelete(node);\n return;\n }\n if (await confirmDelete(node)) await performDelete(node);\n },\n [supportsMutation, confirmDelete, performDelete],\n );\n\n const closePendingDelete = useCallback(\n (restoreTrigger: boolean) => {\n const returnTarget = restoreTrigger ? deleteReturnFocusRef.current : getTreeElement();\n deleteReturnFocusRef.current = null;\n setPendingDelete(null);\n if (typeof window !== \"undefined\") {\n window.requestAnimationFrame(() => {\n const target = returnTarget?.isConnected ? returnTarget : getTreeElement();\n target?.focus();\n });\n }\n },\n [getTreeElement],\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(visibleTree, 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, visibleTree],\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(visibleTree, 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, open, visibleTree],\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(visibleTree, 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, visibleTree],\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 \"Home\":\n move(0);\n break;\n case \"End\":\n move(flatRows.length - 1);\n break;\n case \"PageDown\": {\n const pageSize = Math.max(\n 1,\n Math.floor((containerRef.current?.clientHeight || 280) / (coarsePointer ? 44 : 28)) - 1,\n );\n move((idx < 0 ? 0 : idx) + pageSize);\n break;\n }\n case \"PageUp\": {\n const pageSize = Math.max(\n 1,\n Math.floor((containerRef.current?.clientHeight || 280) / (coarsePointer ? 44 : 28)) - 1,\n );\n move((idx < 0 ? 0 : idx) - pageSize);\n break;\n }\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 \"ContextMenu\":\n case \"F10\":\n if (cur && supportsMutation && (e.key === \"ContextMenu\" || e.shiftKey)) {\n const rowIndex = rowIndexByPath.get(cur.node.path) ?? 0;\n const row = document.getElementById(`${treeId}-item-${rowIndex}`);\n const rect = row?.getBoundingClientRect();\n setMenu({\n node: cur.node,\n x: rect ? rect.left + Math.min(32, rect.width / 2) : 8,\n y: rect ? rect.bottom : 8,\n });\n e.preventDefault();\n } else if (e.key === \"F10\") {\n break;\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 coarsePointer,\n containerRef,\n rowIndexByPath,\n treeId,\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 && visibleTree.length === 0 && !draftCreate;\n const showDegradedTree = result.error && visibleTree.length > 0;\n const showEmpty = !result.loading && visibleTree.length === 0 && !draftCreate;\n // Retry lives next to the state it explains (the degraded/empty notice), so do\n // not render a second toolbar retry for the same failure.\n const showToolbar = supportsMutation || result.loading;\n // Virtua caches the previous visible range when a lazy-expanded subtree is\n // inserted in the middle of a short list. The spacer grows but later root\n // siblings can remain unmounted until a scroll/resize (for example,\n // `.bash_history` vanished after expanding `repositories/<repo>`). Small\n // trees do not benefit from virtualization, so render them directly and keep\n // Virtua only for genuinely large workspaces.\n const usesVirtualTree = !showErrorEmpty && !showEmpty && renderItems.length > 500;\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 const treePosition = treePositionByPath.get(node.path);\n\n return (\n <div\n id={`${treeId}-item-${rowIndexByPath.get(node.path) ?? 0}`}\n role=\"treeitem\"\n aria-level={depth + 1}\n aria-posinset={treePosition?.position}\n aria-setsize={treePosition?.setSize}\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 tabIndex={-1}\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 useEffect(() => {\n if (!revealRequest) return;\n const index = renderItems.findIndex(\n (item) => item.type === \"node\" && item.node.path === revealRequest.path,\n );\n if (index < 0) return;\n if (usesVirtualTree) {\n vlistRef.current?.scrollToIndex(index);\n } else {\n document.getElementById(`${treeId}-item-${index}`)?.scrollIntoView?.({ block: \"nearest\" });\n }\n setRevealRequest((current) =>\n current?.path === revealRequest.path && current.requestId === revealRequest.requestId\n ? null\n : current,\n );\n }, [renderItems, revealRequest, treeId, usesVirtualTree]);\n\n return (\n <div className={cn(\"flex min-h-0 min-w-0 flex-col\", className)}>\n {showToolbar && (\n <div\n role=\"toolbar\"\n aria-label=\"File actions\"\n className=\"flex shrink-0 flex-wrap items-center gap-0.5 border-b border-og-border px-1 py-1\"\n >\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(visibleTree, 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={(event) => {\n const node = cursor ? findNode(visibleTree, cursor) : undefined;\n if (node) void runDelete(node, event.currentTarget);\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 {showDegradedTree ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n data-opengeni-files-degraded\n className=\"flex shrink-0 items-center gap-2 border-b border-og-status-running/30 bg-og-status-running/10 px-2 py-1.5 text-og-xs text-og-fg-muted\"\n >\n <TriangleAlertIcon className=\"size-3.5 shrink-0 text-og-status-running\" aria-hidden />\n <span className=\"min-w-0 flex-1\">\n {result.source === \"capture\"\n ? \"Live files are temporarily unavailable. Showing the latest captured revision.\"\n : \"Live refresh failed. Showing the last loaded files.\"}\n </span>\n <button\n type=\"button\"\n onClick={() => void result.refresh()}\n disabled={result.loading}\n className=\"inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n <RefreshCwIcon\n className={cn(\"size-3\", result.loading && \"animate-spin motion-reduce:animate-none\")}\n aria-hidden\n />\n Retry\n </button>\n </div>\n ) : null}\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={container.ref}\n onFocus={(event) => {\n if ((event.target as HTMLElement).id === treeId && cursorIndex < 0) {\n const first = flatRows[0];\n if (first) setActive(first.node.path);\n }\n }}\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\",\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-11\"\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 ) : !usesVirtualTree ? (\n <div\n id={treeId}\n role=\"tree\"\n aria-label=\"Workspace files\"\n aria-activedescendant={activeDescendantId}\n aria-multiselectable={false}\n tabIndex={0}\n className=\"min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\n >\n {renderItems.map((item) => (\n <div key={itemKey(item)} className=\"min-w-0\">\n {renderItem(item)}\n </div>\n ))}\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 id={treeId}\n role=\"tree\"\n aria-label=\"Workspace files\"\n aria-activedescendant={activeDescendantId}\n aria-multiselectable={false}\n tabIndex={0}\n className=\"min-h-0 flex-1 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\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 onClose={() => {\n setMenu(null);\n window.requestAnimationFrame(() => getTreeElement()?.focus());\n }}\n />\n )}\n {pendingDelete ? (\n <DeleteDialog\n node={pendingDelete}\n busy={busy}\n portalTokenStyle={portalTokenStyle}\n onCancel={() => closePendingDelete(true)}\n onConfirm={() => {\n const node = pendingDelete;\n closePendingDelete(false);\n void performDelete(node);\n }}\n />\n ) : null}\n </div>\n );\n}\n\nfunction DeleteDialog({\n node,\n busy,\n portalTokenStyle,\n onCancel,\n onConfirm,\n}: {\n node: FileTreeNode;\n busy: boolean;\n portalTokenStyle: PortalTokenStyle;\n onCancel: () => void;\n onConfirm: () => void;\n}) {\n const cancelRef = useRef<HTMLButtonElement | null>(null);\n const [open, setOpen] = useState(true);\n const closeIntentRef = useRef<\"cancel\" | \"confirm\">(\"cancel\");\n const settledRef = useRef(false);\n const settleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const settle = () => {\n if (settledRef.current) return;\n settledRef.current = true;\n if (closeIntentRef.current === \"confirm\") {\n onConfirm();\n } else {\n onCancel();\n }\n };\n\n const scheduleSettle = () => {\n if (settleTimerRef.current !== null) return;\n settleTimerRef.current = setTimeout(() => {\n settleTimerRef.current = null;\n settle();\n }, 0);\n };\n\n useEffect(\n () => () => {\n if (settleTimerRef.current !== null) clearTimeout(settleTimerRef.current);\n },\n [],\n );\n\n return (\n <AlertDialog.Root\n open={open}\n onOpenChange={(nextOpen) => {\n if (!nextOpen && !busy) {\n setOpen(false);\n scheduleSettle();\n }\n }}\n >\n <AlertDialog.Portal container={typeof document === \"undefined\" ? null : document.body}>\n <AlertDialog.Overlay className=\"og-root fixed inset-0 z-[100] bg-black/45 backdrop-blur-[2px]\" />\n <AlertDialog.Content\n className=\"og-root fixed left-1/2 top-1/2 z-[101] max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-sm -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-og-lg border border-og-border-strong bg-og-surface-1 p-4 text-og-fg shadow-2xl outline-hidden\"\n style={portalTokenStyle}\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n cancelRef.current?.focus();\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n scheduleSettle();\n }}\n onEscapeKeyDown={(event) => {\n event.stopPropagation();\n if (busy) {\n event.preventDefault();\n } else {\n closeIntentRef.current = \"cancel\";\n }\n }}\n >\n <div className=\"flex items-start gap-3\">\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-full bg-og-status-failed/12 text-og-status-failed\">\n <Trash2Icon className=\"size-4\" aria-hidden />\n </span>\n <div className=\"min-w-0\">\n <AlertDialog.Title className=\"text-og-sm font-semibold\">\n Delete {node.kind === \"dir\" ? \"folder\" : \"file\"}?\n </AlertDialog.Title>\n <AlertDialog.Description className=\"mt-1 text-og-sm leading-relaxed text-og-fg-muted\">\n <span className=\"break-all font-og-mono text-og-fg\">{node.path}</span>\n {node.kind === \"dir\"\n ? \" and everything inside it will be permanently removed.\"\n : \" will be permanently removed.\"}\n </AlertDialog.Description>\n </div>\n </div>\n <div className=\"mt-4 flex justify-end gap-2\">\n <AlertDialog.Cancel asChild>\n <button\n ref={cancelRef}\n type=\"button\"\n onClick={() => {\n closeIntentRef.current = \"cancel\";\n }}\n disabled={busy}\n className=\"min-h-9 rounded-og-md border border-og-border px-3 text-og-sm font-medium text-og-fg hover:bg-og-surface-2 disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n Cancel\n </button>\n </AlertDialog.Cancel>\n <AlertDialog.Action asChild>\n <button\n type=\"button\"\n onClick={() => {\n closeIntentRef.current = \"confirm\";\n }}\n disabled={busy}\n className=\"min-h-9 rounded-og-md bg-og-status-failed px-3 text-og-sm font-semibold text-white shadow-sm hover:brightness-110 disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n Delete permanently\n </button>\n </AlertDialog.Action>\n </div>\n </AlertDialog.Content>\n </AlertDialog.Portal>\n </AlertDialog.Root>\n );\n}\n\nfunction ToolbarButton({\n label,\n onClick,\n disabled,\n children,\n}: {\n label: string;\n onClick: (event: ReactMouseEvent<HTMLButtonElement>) => 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-hidden\",\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 onClose,\n}: {\n node: FileTreeNode;\n x: number;\n y: number;\n onRename: () => void;\n onDelete: () => void;\n onNewFile: () => void;\n onNewFolder: () => void;\n onClose: () => void;\n}) {\n const isDir = node.kind === \"dir\";\n const menuRef = useRef<HTMLDivElement | null>(null);\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.max(4, Math.min(x, vw - 180));\n const top = Math.max(4, Math.min(y, vh - 160));\n\n useEffect(() => {\n menuRef.current?.querySelector<HTMLButtonElement>('[role=\"menuitem\"]')?.focus();\n }, []);\n\n const onKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const items = Array.from(\n menuRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"menuitem\"]') ?? [],\n );\n if (items.length === 0) return;\n const current = items.findIndex((item) => item === document.activeElement);\n let next: number | null = null;\n if (event.key === \"ArrowDown\") next = (current + 1 + items.length) % items.length;\n else if (event.key === \"ArrowUp\") next = (current - 1 + items.length) % items.length;\n else if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n onClose();\n return;\n }\n if (next === null) return;\n event.preventDefault();\n event.stopPropagation();\n items[next]?.focus();\n };\n\n const item = (label: string, icon: ReactNode, onClick: () => void, danger?: boolean) => (\n <button\n type=\"button\"\n role=\"menuitem\"\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-11\",\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 ref={menuRef}\n role=\"menu\"\n aria-label={`Actions for ${node.name}`}\n onKeyDown={onKeyDown}\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 role=\"separator\" 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 { useEffect, useMemo } from \"react\";\n\nexport type UnicodeFontNeeds = {\n japanese: boolean;\n arabic: boolean;\n};\n\nconst japaneseScript = /[\\u3040-\\u30ff\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff]/u;\nconst arabicScript = /[\\u0600-\\u06ff\\u0750-\\u077f\\u0870-\\u08ff\\ufb50-\\ufdff\\ufe70-\\ufefc]/u;\n\nexport function detectUnicodeFontNeeds(values: Iterable<string>): UnicodeFontNeeds {\n let japanese = false;\n let arabic = false;\n for (const value of values) {\n japanese ||= japaneseScript.test(value);\n arabic ||= arabicScript.test(value);\n if (japanese && arabic) break;\n }\n return { japanese, arabic };\n}\n\n/**\n * Load large script-specific font manifests only when visible workspace content\n * needs them. Fontsource splits the actual glyphs by unicode-range, so Chromium\n * then fetches only the small shards used by the path instead of charging every\n * Latin-only session for the complete font.\n */\nexport function useUnicodeFallbackFonts(values: readonly string[]): void {\n const content = useMemo(() => collectUnicodeContent(values), [values]);\n useEffect(() => {\n if (content.japanese) {\n void import(\"./noto-sans-jp-loader.generated\")\n .then(({ loadNotoSansJp }) => loadNotoSansJp(content.japanese))\n .catch(() => undefined);\n }\n if (content.arabic) {\n void import(\"./noto-sans-arabic-loader\")\n .then(({ loadNotoSansArabic }) => loadNotoSansArabic())\n .catch(() => undefined);\n }\n }, [content.arabic, content.japanese]);\n}\n\nfunction collectUnicodeContent(values: Iterable<string>): {\n japanese: string;\n arabic: string;\n} {\n const japanese = new Set<string>();\n const arabic = new Set<string>();\n for (const value of values) {\n for (const character of value) {\n if (japaneseScript.test(character)) japanese.add(character);\n if (arabicScript.test(character)) arabic.add(character);\n }\n }\n return { japanese: [...japanese].join(\"\"), arabic: [...arabic].join(\"\") };\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { ArrowUpRightIcon, FileWarningIcon, HistoryIcon } from \"lucide-react\";\nimport {\n Component,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { VList, type VListHandle } from \"virtua\";\nimport { cn } from \"../lib/cn\";\nimport { useUnicodeFallbackFonts } from \"../lib/use-unicode-fonts\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport { formatAsOf } from \"../hooks/use-machine-chip\";\nimport type { SandboxGitFileDiff } from \"../hooks/use-sandbox-git\";\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 repository when metadata is\n available, otherwise by top-level directory for a large legacy input) on the\n 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 (D2). A per-file size guard (binary / diff too\n large) degrades to an \"open live\" affordance instead of a diff body.\n\n Workspace-wide Git results carry an explicit `repoRoot`, so grouping never\n guesses repository ownership from a directory name. Multi-repo results group\n at every size; legacy unscoped inputs group by top-level directory only past\n the threshold.\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\nfunction compactFileLabel(file: SandboxGitFileDiff): string {\n const slash = file.path.lastIndexOf(\"/\");\n const basename = slash >= 0 ? file.path.slice(slash + 1) : file.path;\n const parent = slash >= 0 ? file.path.slice(0, slash + 1) : \"\";\n return `${STATUS_LETTER[file.status]} · ${basename}${parent ? ` — ${parent}` : \"\"}`;\n}\n\nexport type WorkbenchChangesProps = {\n /** The changed files (`useSandboxGit().diff`). Assumed non-empty by the caller. */\n diff: SandboxGitFileDiff[];\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 /** Route a guarded binary/oversize file into the live Files surface. */\n onOpenFile?: ((path: string) => void) | undefined;\n className?: string | undefined;\n};\n\ntype RailRow =\n | { kind: \"group\"; label: string; count: number }\n | { kind: \"file\"; file: SandboxGitFileDiff; index: number };\n\ntype ChangesRailVListProps = {\n children: ReactNode;\n className: string;\n coarsePointer: boolean;\n files: readonly SandboxGitFileDiff[];\n rowCount: number;\n};\n\ntype ChangesRailVListState = {\n renderedRowCount: number;\n resetVersion: number;\n};\n\ntype ChangesRailSnapshot = {\n focusedPath: string | null;\n scrollOffset: number;\n};\n\n/** Virtua must reset its cached range when the rail shrinks. Keep that remount\n * scoped to shrink transitions and preserve the reader's focus/scroll context. */\nclass ChangesRailVList extends Component<\n ChangesRailVListProps,\n ChangesRailVListState,\n ChangesRailSnapshot | null\n> {\n state: ChangesRailVListState = {\n renderedRowCount: this.props.rowCount,\n resetVersion: 0,\n };\n\n private host: HTMLDivElement | null = null;\n private listHandle: VListHandle | null = null;\n private pendingFocusedPath: string | null = null;\n private restoreFrame: number | null = null;\n\n static getDerivedStateFromProps(\n props: ChangesRailVListProps,\n state: ChangesRailVListState,\n ): ChangesRailVListState | null {\n if (props.rowCount === state.renderedRowCount) return null;\n return {\n renderedRowCount: props.rowCount,\n resetVersion:\n props.rowCount < state.renderedRowCount ? state.resetVersion + 1 : state.resetVersion,\n };\n }\n\n getSnapshotBeforeUpdate(\n _previousProps: ChangesRailVListProps,\n previousState: ChangesRailVListState,\n ): ChangesRailSnapshot | null {\n if (previousState.resetVersion === this.state.resetVersion) return null;\n const scroller = this.host?.firstElementChild;\n if (!(scroller instanceof HTMLElement)) return null;\n const active = document.activeElement;\n const focusedRow =\n active instanceof HTMLElement && scroller.contains(active)\n ? active.closest<HTMLElement>(\"[data-rail-file-path]\")\n : null;\n return {\n focusedPath: focusedRow?.dataset.railFilePath ?? this.pendingFocusedPath,\n scrollOffset: scroller.scrollTop,\n };\n }\n\n componentDidUpdate(\n _previousProps: ChangesRailVListProps,\n _previousState: ChangesRailVListState,\n snapshot: ChangesRailSnapshot | null,\n ): void {\n if (!snapshot || !this.listHandle) return;\n this.cancelRestoreFrame();\n const maxOffset = Math.max(0, this.listHandle.scrollSize - this.listHandle.viewportSize);\n this.listHandle.scrollTo(Math.min(Math.max(snapshot.scrollOffset, 0), maxOffset));\n const focusedPath = snapshot.focusedPath;\n if (!focusedPath) return;\n this.pendingFocusedPath = focusedPath;\n this.continueFocusRestore();\n }\n\n componentWillUnmount(): void {\n this.cancelRestoreFrame();\n this.pendingFocusedPath = null;\n }\n\n private cancelRestoreFrame(): void {\n if (this.restoreFrame === null) return;\n if (typeof cancelAnimationFrame === \"function\") cancelAnimationFrame(this.restoreFrame);\n this.restoreFrame = null;\n }\n\n private continueFocusRestore = (): void => {\n const path = this.pendingFocusedPath;\n if (!path) return;\n if (this.restoreFocusedPath(path)) {\n this.pendingFocusedPath = null;\n return;\n }\n if (this.restoreFrame === null && typeof requestAnimationFrame === \"function\") {\n this.restoreFrame = requestAnimationFrame(() => {\n this.restoreFrame = null;\n this.continueFocusRestore();\n });\n }\n };\n\n private restoreFocusedPath(path: string): boolean {\n const host = this.host;\n if (!host) return true;\n const active = document.activeElement;\n if (active instanceof HTMLElement && active.isConnected && active !== document.body) {\n return true;\n }\n if (!this.props.files.some((file) => file.path === path)) return true;\n const row = Array.from(host.querySelectorAll<HTMLButtonElement>(\"[data-rail-file-path]\")).find(\n (candidate) => candidate.dataset.railFilePath === path,\n );\n if (!row) return false;\n row.focus({ preventScroll: true });\n return true;\n }\n\n private setHost = (host: HTMLDivElement | null): void => {\n this.host = host;\n };\n\n private setListHandle = (handle: VListHandle | null): void => {\n this.listHandle = handle;\n };\n\n render() {\n return (\n <div ref={this.setHost} data-opengeni-changes-rail className={this.props.className}>\n <VList\n key={this.state.resetVersion}\n ref={this.setListHandle}\n className=\"h-full\"\n itemSize={this.props.coarsePointer ? 44 : 28}\n ssrCount={Math.min(30, this.props.rowCount)}\n >\n {this.props.children}\n </VList>\n </div>\n );\n }\n}\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: SandboxGitFileDiff[]): {\n orderedFiles: SandboxGitFileDiff[];\n rows: RailRow[];\n grouped: boolean;\n} {\n const roots = new Set(\n files.flatMap((file) => (file.repoRoot === undefined ? [] : [file.repoRoot])),\n );\n const groupByRepo = roots.size > 1;\n if (!groupByRepo && files.length <= GROUP_THRESHOLD) {\n return {\n orderedFiles: files,\n rows: files.map((file, index) => ({ kind: \"file\", file, index })),\n grouped: false,\n };\n }\n const groups = new Map<string, SandboxGitFileDiff[]>();\n for (const file of files) {\n const slash = file.path.indexOf(\"/\");\n const key = groupByRepo\n ? file.repoRoot || \"(workspace)\"\n : slash > 0\n ? file.path.slice(0, slash)\n : \"(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: SandboxGitFileDiff[] = [];\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, grouped: true };\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 onOpenFile,\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 unicodeFontPaths = useMemo(\n () => diff.flatMap((file) => (file.oldPath ? [file.path, file.oldPath] : [file.path])),\n [diff],\n );\n useUnicodeFallbackFonts(unicodeFontPaths);\n\n const { orderedFiles, rows, grouped } = useMemo(() => buildRail(diff), [diff]);\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) {\n return;\n }\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\n className={cn(\n \"flex shrink-0 items-center justify-between gap-2 border-b border-og-border px-3 py-1.5\",\n compact && source === \"capture\" && \"flex-col items-stretch gap-1.5 py-2\",\n )}\n >\n <span\n role=\"status\"\n aria-atomic=\"true\"\n aria-live=\"polite\"\n data-contrast-audited\n className=\"min-w-0 text-og-xs text-og-fg-muted\"\n >\n {diff.length} {diff.length === 1 ? \"file\" : \"files\"} changed\n <span data-contrast-audited className=\"ml-2 text-og-status-idle\">\n +{additions}\n </span>\n <span data-contrast-audited className=\"ml-1 text-og-status-failed\">\n −{deletions}\n </span>\n </span>\n <div\n className={cn(\n \"flex shrink-0 items-center gap-2\",\n compact && source === \"capture\" && \"self-start\",\n )}\n >\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 title={activeFile?.path}\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-hidden 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 {compactFileLabel(file)}\n </option>\n ))}\n </select>\n </div>\n <div\n aria-label=\"Changed file diff\"\n className=\"min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\n data-opengeni-changes-pane\n role=\"region\"\n tabIndex={0}\n >\n {activeFile ? (\n <DiffSection\n file={activeFile}\n layout=\"unified\"\n themeType={resolvedTheme}\n {...(onOpenFile ? { onOpenFile } : {})}\n />\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 <ChangesRailVList\n rowCount={rows.length}\n coarsePointer={coarsePointer}\n files={orderedFiles}\n className=\"w-[clamp(12rem,28%,15rem)] shrink-0 border-r border-og-border bg-og-surface-1/35\"\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-og-xs 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 </ChangesRailVList>\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 aria-label=\"Changed files diff\"\n className=\"min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\n data-opengeni-changes-pane\n role=\"region\"\n tabIndex={0}\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\n file={file}\n layout={layout}\n themeType={resolvedTheme}\n {...(onOpenFile ? { onOpenFile } : {})}\n />\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-og-xs 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-og-xs text-og-fg-subtle\">\n {label}\n </span>\n );\n}\n\n/** \"Live diff\" · \"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 diff\";\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: SandboxGitFileDiff;\n grouped: boolean;\n active: boolean;\n onClick: () => void;\n}) {\n // A real repository group strips the exact repo root. Legacy top-directory\n // grouping strips only that first segment.\n const repoPrefix = file.repoRoot ? `${file.repoRoot}/` : null;\n const shown = grouped\n ? file.repoRoot !== undefined\n ? repoPrefix && file.path.startsWith(repoPrefix)\n ? file.path.slice(repoPrefix.length)\n : file.path\n : file.path.slice(file.path.indexOf(\"/\") + 1) || file.path\n : file.path;\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={file.path}\n data-rail-file\n data-rail-file-path={file.path}\n className={cn(\n \"relative flex min-h-7 w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-og-sm transition-colors hover:bg-og-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent pointer-coarse:min-h-11\",\n grouped && \"pl-3\",\n active &&\n \"bg-og-accent-soft text-og-fg before:absolute before:inset-y-1 before:left-0 before:w-0.5 before:rounded-r-full before:bg-og-accent\",\n )}\n >\n <span\n data-contrast-audited\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-og-xs\">\n <span data-contrast-audited className=\"text-og-status-idle\">\n +{file.additions}\n </span>\n <span data-contrast-audited className=\"text-og-status-failed\">\n −{file.deletions}\n </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 onOpenFile,\n}: {\n file: GitFileDiff;\n layout: \"unified\" | \"split\";\n themeType: \"dark\" | \"light\";\n onOpenFile?: ((path: string) => void) | undefined;\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-og-xs\">\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} {...(onOpenFile ? { onOpenFile } : {})} />\n </section>\n );\n }\n return (\n <section data-pierre-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({\n file,\n onOpenFile,\n}: {\n file: GitFileDiff;\n onOpenFile?: ((path: string) => void) | undefined;\n}) {\n const reason = file.isBinary ? \"Binary file\" : \"Diff too large to show here\";\n return (\n <div className=\"flex flex-wrap items-center gap-2 px-3 py-3 text-og-sm text-og-fg-subtle\">\n <FileWarningIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"min-w-0 flex-1\">{reason}.</span>\n {onOpenFile ? (\n <button\n type=\"button\"\n onClick={() => onOpenFile(file.path)}\n className=\"inline-flex min-h-8 shrink-0 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:bg-og-surface-2 hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-11\"\n >\n Open in Files\n <ArrowUpRightIcon className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\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-og-xs capitalize focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-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 (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 (known layout risk). 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 when the estimate function changes as well as when the count changes.\n // A replacement diff can contain the same number of files but radically\n // different section sizes; retaining measurements by index would then place\n // every unvisited section at an offset belonging to the previous diff.\n useEffect(() => {\n setHeights((prev) => {\n const next = Array.from({ length: count }, (_, i) => estimateHeight(i));\n return prev.length === next.length && prev.every((height, index) => height === next[index])\n ? prev\n : next;\n });\n }, [count, estimateHeight]);\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 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 /** Target 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 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\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 /**\n * Persist the current buffer against the exact contents it was edited from.\n * The second argument is the immutable compare-and-swap baseline; hosts must\n * not replace it with a newer remote snapshot or concurrent writes can be\n * silently overwritten.\n */\n onSave: (contents: string, expectedContents: string) => Promise<unknown>;\n /** Explicitly overwrite after a visible expected-content conflict. */\n onOverwrite?: ((contents: string) => Promise<unknown>) | undefined;\n /** Re-read the selected file after a visible save conflict. */\n onReload?: (() => void) | undefined;\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\nexport type EditorBufferState = {\n path: string;\n value: string;\n baseline: string;\n};\n\n/**\n * Reconcile a remote file snapshot without destroying unsaved local work.\n *\n * A different path is a new document and always resets. For the same path, a\n * clean editor follows the remote snapshot while a dirty editor retains both\n * its local value and the original CAS baseline. The eventual save will then\n * either succeed against that baseline or surface a typed conflict.\n */\nexport function reconcileEditorBuffer(\n current: EditorBufferState,\n incoming: { path: string; contents: string },\n): EditorBufferState {\n if (current.path === incoming.path && current.value !== current.baseline) {\n return current;\n }\n if (\n current.path === incoming.path &&\n current.value === incoming.contents &&\n current.baseline === incoming.contents\n ) {\n return current;\n }\n return {\n path: incoming.path,\n value: incoming.contents,\n baseline: incoming.contents,\n };\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 onOverwrite,\n onReload,\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 and its compare-and-swap baseline are one state value so a\n // remote refresh cannot update one without the other.\n const [buffer, setBuffer] = useState<EditorBufferState>(() => ({\n path,\n value: initialContents,\n baseline: initialContents,\n }));\n const { value, baseline } = buffer;\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<Error | null>(null);\n const [savedTick, setSavedTick] = useState(false);\n const saveInFlightRef = useRef(false);\n\n const dirty = value !== baseline;\n const saveConflict =\n saveError !== null && (saveError as Error & { code?: unknown }).code === \"file_write_conflict\";\n\n // Follow path changes and clean same-file refreshes. Dirty same-file buffers\n // intentionally ignore remote snapshots: the original baseline must survive\n // until guarded save, explicit reload, or navigation.\n const editIntentFiredRef = useRef(false);\n useEffect(() => {\n setBuffer((current) => reconcileEditorBuffer(current, { path, contents: initialContents }));\n }, [path, initialContents]);\n\n // A new document is a new edit-intent/error lifecycle. The normal\n // SandboxFiles host also keys the component by path; this keeps standalone\n // consumers correct without relying on that implementation detail.\n useEffect(() => {\n editIntentFiredRef.current = false;\n setSaveError(null);\n setSavedTick(false);\n }, [path]);\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 setBuffer((current) => ({ ...current, value: 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 // Language peers are optional. A missing grammar must degrade to a plain\n // CodeMirror document, not throw the entire editor down to textarea.\n let languageExtension: unknown | null = null;\n if (langKey) {\n try {\n languageExtension = (await LANGUAGE_LOADERS[langKey]?.()) ?? null;\n } catch {\n languageExtension = null;\n }\n }\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,\n });\n setFailed(false);\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 || saveInFlightRef.current) 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 saveInFlightRef.current = true;\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onSave(snapshot, baseline);\n setBuffer((current) =>\n current.path === path ? { ...current, baseline: snapshot } : current,\n );\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n saveInFlightRef.current = false;\n setSaving(false);\n }\n }, [readOnly, value, baseline, onSave, path]);\n\n const overwrite = useCallback(async () => {\n if (readOnly || !onOverwrite || saveInFlightRef.current) return;\n const snapshot = value;\n if (snapshot === baseline) return;\n saveInFlightRef.current = true;\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onOverwrite(snapshot);\n setBuffer((current) =>\n current.path === path ? { ...current, baseline: snapshot } : current,\n );\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n saveInFlightRef.current = false;\n setSaving(false);\n }\n }, [readOnly, onOverwrite, value, baseline, 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 const Editor = bundle?.Editor;\n\n const reload = useCallback(() => {\n setBuffer({ path, value: initialContents, baseline: initialContents });\n editIntentFiredRef.current = false;\n setSaveError(null);\n setSavedTick(false);\n onReload?.();\n }, [initialContents, onReload, path]);\n\n return (\n <div\n className={cn(\"flex h-full min-h-0 flex-col\", className)}\n data-opengeni-code-editor\n data-opengeni-editor-dirty={dirty ? \"true\" : \"false\"}\n style={editorVars}\n >\n {/* Save bar: dirty indicator + status + the explicit Save button. */}\n <div className=\"flex min-h-9 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 && !saveConflict && (\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 && !dirty && (\n <span className=\"text-og-xs text-og-status-idle\">Saved</span>\n )}\n {readOnly ? (\n <span className=\"text-og-xs uppercase tracking-wide text-og-fg-subtle\">Read-only</span>\n ) : !saveConflict ? (\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-11\",\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 ) : null}\n </div>\n </div>\n\n {saveConflict ? (\n <div\n className=\"flex shrink-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-og-status-failed/25 bg-og-status-failed/8 px-2 py-2\"\n role=\"alert\"\n >\n <div className=\"min-w-[12rem] flex-1 text-og-xs text-og-fg-muted\">\n <span className=\"font-medium text-og-status-failed\">File changed on machine.</span>{\" \"}\n Reloading discards your edits; overwriting replaces the live version.\n </div>\n <div className=\"ml-auto flex shrink-0 items-center gap-1.5\">\n {onReload ? (\n <button\n type=\"button\"\n onClick={() => {\n reload();\n }}\n className=\"min-h-8 rounded-og-sm border border-og-border bg-og-surface-1 px-2 text-og-xs font-medium text-og-fg hover:bg-og-surface-2 pointer-coarse:min-h-11\"\n >\n Reload live\n </button>\n ) : null}\n {onOverwrite ? (\n <button\n type=\"button\"\n onClick={() => void overwrite()}\n disabled={saving}\n className=\"min-h-8 rounded-og-sm border border-og-status-failed/40 px-2 text-og-xs font-medium text-og-status-failed hover:bg-og-status-failed/10 disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n Overwrite\n </button>\n ) : null}\n </div>\n </div>\n ) : null}\n\n {/* The editor surface. */}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {failed ? (\n (fallback ?? (\n <PlainTextarea\n value={value}\n readOnly={readOnly}\n onChange={noteEdit}\n onSave={() => void save()}\n />\n ))\n ) : Editor ? (\n <Editor\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 ) : (\n (loading ?? <EditorSkeleton />)\n )}\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 onSave,\n}: {\n value: string;\n readOnly: boolean;\n onChange: (value: string) => void;\n onSave: () => void;\n}) {\n return (\n <textarea\n value={value}\n readOnly={readOnly}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"s\") {\n event.preventDefault();\n onSave();\n }\n }}\n aria-label=\"Plain text file editor\"\n className=\"h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-hidden\"\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 { FileCode2Icon, FileWarningIcon, LoaderCircleIcon } from \"lucide-react\";\nimport { type ReactNode, useCallback, useEffect, useRef, useState } from \"react\";\nimport { Group, Panel, Separator } from \"react-resizable-panels\";\nimport { cn } from \"../lib/cn\";\nimport { prefersReducedMotion } from \"../lib/motion\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport {\n CapturedFileUnavailableError,\n type SandboxFilesGitSummary,\n type UseSandboxFilesResult,\n} from \"../hooks/use-sandbox-files\";\nimport type { UseSandboxGitResult } from \"../hooks/use-sandbox-git\";\nimport { filePathVisibility, type FileNodeVisibilityPredicate } from \"../file-node-visibility\";\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 /** Compatibility fallback for callers that have not yet adopted `files.gitSummary`. */\n git?: UseSandboxGitResult | undefined;\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 /** Restore the file last viewed in this task. Invalid/missing paths still\n * surface the ordinary file-view error instead of changing files silently. */\n initialSelectedPath?: string | null | undefined;\n onSelectedPathChange?: ((path: string | null) => void) | undefined;\n /** Presentation-only node filter shared with the tree and selected-file view. */\n isNodeVisible?: FileNodeVisibilityPredicate | undefined;\n /** A deliberate file-open path routed here by the parent workspace. */\n requestedPath?: string | undefined;\n /** 1-based line to reveal after `requestedPath` opens. */\n requestedLine?: number | null | undefined;\n /** Identity for one guarded-file request. Increment this when the same path is\n * deliberately requested again; it also lets a pending request be consumed\n * without overriding later manual tree navigation. Defaults to the path. */\n requestedPathRequestId?: string | number | undefined;\n /** False while the parent is waking a cold sandbox for `requestedPath`. */\n requestedPathReady?: boolean | undefined;\n /** The machine is cold and no durable capture exists yet. Render an explicit\n * wake gate instead of an empty-tree lie or an implicit Channel-A read. */\n workspaceResting?: boolean | undefined;\n /** A deliberate wake has started but the live file surface is not ready yet. */\n workspaceWaking?: boolean | undefined;\n /** Whether live reads are currently authoritative. */\n liveWorkspaceReady?: boolean | undefined;\n /** Failed live negotiation; never present a failure as an ongoing wake. */\n workspaceError?: Error | null | undefined;\n /** Deliberately wake the machine to read content absent from the capture. */\n onWakeWorkspace?: (() => 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 initialSelectedPath,\n onSelectedPathChange,\n isNodeVisible,\n requestedPath,\n requestedLine,\n requestedPathRequestId,\n requestedPathReady = true,\n workspaceResting = false,\n workspaceWaking = false,\n liveWorkspaceReady = true,\n workspaceError = null,\n onWakeWorkspace,\n themeType,\n className,\n}: SandboxFilesProps) {\n const [selected, setSelected] = useState<string | null>(() => initialSelectedPath ?? 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 const [focusLine, setFocusLine] = useState<number | null>(null);\n const [treeRevealRequest, setTreeRevealRequest] = useState<{\n path: string;\n requestId: string | number;\n } | null>(null);\n const [liveRequestedPath, setLiveRequestedPath] = useState<string | null>(null);\n const [viewReloadRevision, setViewReloadRevision] = useState(0);\n const viewerScrollRef = useRef<HTMLDivElement | null>(null);\n const pendingRequestRef = useRef<string | number | null>(null);\n const handledRequestRef = useRef<string | number | null>(null);\n const requestKey = requestedPath ? (requestedPathRequestId ?? requestedPath) : null;\n\n useEffect(() => {\n if (!requestedPath || requestKey === null) {\n pendingRequestRef.current = null;\n handledRequestRef.current = null;\n setTreeRevealRequest(null);\n return;\n }\n if (handledRequestRef.current === requestKey) {\n return;\n }\n if (!requestedPathReady) {\n pendingRequestRef.current = requestKey;\n setTreeRevealRequest(null);\n return;\n }\n if (isNodeVisible && files.loading && files.tree.length === 0) return;\n if (isNodeVisible && !files.loading && files.tree.length === 0) {\n handledRequestRef.current = requestKey;\n pendingRequestRef.current = null;\n setTreeRevealRequest(null);\n return;\n }\n if (filePathVisibility(files.tree, requestedPath, isNodeVisible) === \"hidden\") {\n handledRequestRef.current = requestKey;\n pendingRequestRef.current = null;\n setTreeRevealRequest(null);\n return;\n }\n handledRequestRef.current = requestKey;\n pendingRequestRef.current = null;\n setSelected(requestedPath);\n onSelectedPathChange?.(requestedPath);\n setEditMode(false);\n setFocusLine(requestedLine != null && requestedLine > 0 ? requestedLine : null);\n setTreeRevealRequest({ path: requestedPath, requestId: requestKey });\n setViewReloadRevision((revision) => revision + 1);\n }, [\n files.loading,\n files.tree,\n isNodeVisible,\n onSelectedPathChange,\n requestKey,\n requestedLine,\n requestedPath,\n requestedPathReady,\n ]);\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) return;\n const update = () => setWide(el.getBoundingClientRect().width >= 720);\n update();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(update);\n observer.observe(el);\n // WorkspaceDock maximization changes its persistent surface from a sized\n // panel child to `fixed inset-0`. Chromium can retain the child's observer\n // size across that containing-block change even though its visible bounding\n // box is now viewport-wide. Follow the surface mode as a deterministic\n // second signal so the tree/viewer orientation matches what is painted.\n const surface = el.closest(\"[data-workspace-surface]\");\n const surfaceObserver =\n surface && typeof MutationObserver !== \"undefined\" ? new MutationObserver(update) : null;\n surfaceObserver?.observe(surface!, {\n attributes: true,\n attributeFilter: [\"class\", \"style\"],\n });\n return () => {\n observer.disconnect();\n surfaceObserver?.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 selectedVisibility = selected\n ? filePathVisibility(files.tree, selected, isNodeVisible)\n : \"unknown\";\n const visibilityPending = Boolean(isNodeVisible && files.loading && files.tree.length === 0);\n const viewPath = selectedVisibility === \"hidden\" || visibilityPending ? null : selected;\n useEffect(() => {\n if (selected === null || selectedVisibility !== \"hidden\") return;\n setSelected(null);\n onSelectedPathChange?.(null);\n setEditMode(false);\n setFocusLine(null);\n setTreeRevealRequest(null);\n setLiveRequestedPath(null);\n }, [onSelectedPathChange, selected, selectedVisibility]);\n const fileView = useFileView(\n viewPath,\n files.readFile,\n `${files.contentRevision ?? 0}:${viewReloadRevision}`,\n );\n\n useEffect(() => {\n if (focusLine === null && viewReloadRevision > 0 && viewerScrollRef.current) {\n viewerScrollRef.current.scrollTop = 0;\n }\n }, [focusLine, viewReloadRevision]);\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. Manual\n // navigation also consumes a pending guarded-file request: a late cold→warm\n // transition must never pull the user away from the file they chose meanwhile.\n const selectFile = useCallback(\n (path: string) => {\n if (pendingRequestRef.current !== null) {\n handledRequestRef.current = pendingRequestRef.current;\n pendingRequestRef.current = null;\n }\n setSelected(path);\n onSelectedPathChange?.(path);\n setEditMode(false);\n setFocusLine(null);\n setTreeRevealRequest(null);\n setLiveRequestedPath(null);\n setViewReloadRevision(0);\n },\n [onSelectedPathChange],\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 const captureFileUnavailable =\n fileView.error instanceof CapturedFileUnavailableError ? fileView.error : null;\n const waitingForSelectedFile =\n !workspaceError &&\n liveRequestedPath === viewPath &&\n (!liveWorkspaceReady || files.loading) &&\n captureFileUnavailable !== null;\n\n if (workspaceError && !liveWorkspaceReady && files.source !== \"capture\") {\n return (\n <Notice className={className} title=\"Could not open live workspace\" announce=\"alert\">\n <p>{workspaceError.message}</p>\n {onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Retry live workspace</WakeButton>\n ) : null}\n </Notice>\n );\n }\n\n if (workspaceResting || workspaceWaking) {\n return (\n <div className={cn(\"h-full\", className)} data-opengeni-workspace-resting>\n <Notice\n icon={\n workspaceWaking ? (\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n ) : (\n <FileCode2Icon className=\"size-5\" aria-hidden />\n )\n }\n title={workspaceWaking ? \"Waking workspace\" : \"Workspace is resting\"}\n announce=\"status\"\n >\n <p>\n {workspaceWaking\n ? \"Connecting to the live file system…\"\n : \"No captured revision is available yet. Wake the sandbox to browse its current files.\"}\n </p>\n {!workspaceWaking && onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Open live workspace</WakeButton>\n ) : null}\n </Notice>\n </div>\n );\n }\n\n if (!fileSystemAvailable) {\n return (\n <Notice\n className={className}\n icon={<FileWarningIcon className=\"size-5\" aria-hidden />}\n title=\"Files unavailable\"\n announce=\"alert\"\n >\n This sandbox does not expose a file system.\n </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 (context; NOT the changed-files list). */}\n <GitHeader\n loading={\n Boolean(files.loading || files.gitLoading || files.source === null || git?.loading) &&\n files.gitSummary === null\n }\n git={\n files.gitSummary ?? {\n branch: git?.branch ?? null,\n isRepo: git?.isRepo ?? false,\n repoCount: git?.repoCount ?? 0,\n ahead: git?.ahead ?? 0,\n behind: git?.behind ?? 0,\n dirtyCount: git?.diff.length ?? 0,\n }\n }\n />\n\n <Group\n orientation={wide ? \"horizontal\" : \"vertical\"}\n className={cn(\"min-h-0 flex-1\", wide ? \"flex-row\" : \"flex-col\")}\n >\n {/* Tree pane: the full lazy file tree. A fixed left column when wide, a top\n band when narrow. */}\n <Panel\n id=\"sandbox-files-tree\"\n defaultSize={wide ? \"280px\" : \"40%\"}\n minSize={wide ? \"180px\" : \"120px\"}\n maxSize={wide ? \"60%\" : \"70%\"}\n className=\"flex min-h-0 min-w-0 flex-col\"\n >\n <FileBrowser\n result={files}\n isNodeVisible={isNodeVisible}\n selectedPath={selected ?? undefined}\n {...(treeRevealRequest\n ? {\n revealPath: treeRevealRequest.path,\n revealPathRequestId: treeRevealRequest.requestId,\n }\n : {})}\n onSelectFile={selectFile}\n editable={editable}\n emptyState=\"This directory is empty\"\n className=\"min-w-0 flex-1\"\n />\n </Panel>\n\n <Separator\n aria-label=\"Resize file tree\"\n className={cn(\n \"group relative z-10 shrink-0 cursor-col-resize outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\",\n \"w-px bg-og-border after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2\",\n \"hover:bg-og-accent focus-visible:bg-og-accent data-[separator-state=dragging]:bg-og-accent\",\n !wide &&\n \"h-px w-full cursor-row-resize after:inset-x-0 after:inset-y-auto after:top-1/2 after:h-3 after:w-full after:-translate-x-0 after:-translate-y-1/2\",\n )}\n />\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 <Panel\n id=\"sandbox-files-viewer\"\n minSize={wide ? \"240px\" : \"160px\"}\n className={cn(\"flex min-h-0 min-w-0 flex-col\", !wide && \"border-t border-og-border\")}\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\n data-opengeni-selected-file\n className=\"min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted\"\n >\n {selected\n ? focusLine !== null\n ? `${selected}:${focusLine}`\n : selected\n : \"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\n ref={viewerScrollRef}\n className=\"min-h-0 flex-1 overflow-auto\"\n data-opengeni-file-viewer-scroll\n >\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, expectedContents) =>\n files.writeFile(viewPath, contents, { expectedContent: expectedContents })\n }\n onOverwrite={(contents) => files.writeFile(viewPath, contents, { force: true })}\n onReload={() => setViewReloadRevision((revision) => revision + 1)}\n {...(onEditIntent ? { onEditIntent } : {})}\n className=\"h-full\"\n />\n ) : workspaceError &&\n (liveRequestedPath === viewPath || requestedPath === viewPath) &&\n !liveWorkspaceReady ? (\n <Notice title=\"Could not open live file\" announce=\"alert\">\n <p>{workspaceError.message}</p>\n {onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Retry live file</WakeButton>\n ) : null}\n </Notice>\n ) : waitingForSelectedFile ? (\n <Notice\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n title=\"Waking workspace\"\n announce=\"status\"\n >\n Opening {viewPath} when the live file system is ready…\n </Notice>\n ) : captureFileUnavailable ? (\n <Notice icon={<FileCode2Icon className=\"size-5\" aria-hidden />} title=\"On machine\">\n <p>\n {captureFileUnavailable.reason === \"too-large\"\n ? \"This file is larger than the captured preview limit.\"\n : captureFileUnavailable.reason === \"content-missing\"\n ? \"The captured copy is no longer available.\"\n : \"This file was indexed, but it was not changed in the captured turn.\"}\n </p>\n {onWakeWorkspace ? (\n <WakeButton\n onClick={() => {\n setLiveRequestedPath(viewPath);\n if (liveWorkspaceReady) void files.refresh();\n else onWakeWorkspace();\n }}\n >\n {liveWorkspaceReady ? \"Retry live file\" : \"Open live file\"}\n </WakeButton>\n ) : null}\n </Notice>\n ) : fileView.error ? (\n <Notice announce=\"alert\">\n Could not open {viewPath}: {fileView.error.message}\n </Notice>\n ) : fileView.loading ? (\n <Notice announce=\"status\">Loading {viewPath}…</Notice>\n ) : fileView.imageUrl ? (\n <RasterFilePreview\n key={fileView.imageUrl}\n src={fileView.imageUrl}\n path={viewPath}\n />\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 && focusLine === null ? (\n <PierreFile\n key={`${viewPath}:${viewReloadRevision}`}\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 ) : focusLine !== null ? (\n <LineNumberedFile\n path={viewPath}\n contents={fileView.content}\n focusLine={focusLine}\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 announce=\"status\">Loading {viewPath}…</Notice>\n )\n ) : // Nothing selected — the tree shows the whole workspace; pick a file.\n requestedPath && !requestedPathReady ? (\n workspaceError ? (\n <Notice title=\"Could not open live file\" announce=\"alert\">\n <p>{workspaceError.message}</p>\n {onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Retry live file</WakeButton>\n ) : null}\n </Notice>\n ) : (\n <Notice\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n title=\"Waking sandbox\"\n announce=\"status\"\n >\n Opening {requestedPath} when the live workspace is ready…\n </Notice>\n )\n ) : (\n <Notice icon={<FileCode2Icon className=\"size-5\" aria-hidden />} title=\"Choose a file\">\n Select a file in the tree to preview it.\n </Notice>\n )}\n </div>\n </Panel>\n </Group>\n </div>\n );\n}\n\nfunction WakeButton({ children, onClick }: { children: ReactNode; onClick: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"mt-1 inline-flex min-h-11 items-center justify-center rounded-og-md bg-og-accent-deep px-3 py-2 text-og-sm font-medium text-og-accent-fg shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg\"\n >\n {children}\n </button>\n );\n}\n\nfunction LineNumberedFile({\n path,\n contents,\n focusLine,\n}: {\n path: string;\n contents: string;\n focusLine: number;\n}) {\n const lines = contents.split(\"\\n\");\n const inRange = focusLine >= 1 && focusLine <= lines.length;\n const targetRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n targetRef.current?.scrollIntoView({\n block: \"center\",\n behavior: prefersReducedMotion() ? \"auto\" : \"smooth\",\n });\n }, [path, focusLine, contents]);\n\n return (\n <div\n className=\"h-full min-h-0 overflow-auto font-og-mono text-og-sm text-og-fg\"\n role=\"region\"\n aria-label={inRange ? `${path} at line ${focusLine}` : path}\n >\n {!inRange ? (\n <p\n className=\"border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-fg-muted\"\n role=\"status\"\n >\n Line {focusLine} is past the end of this file.\n </p>\n ) : null}\n <div>\n {lines.map((text, index) => {\n const lineNumber = index + 1;\n const focused = inRange && lineNumber === focusLine;\n return (\n <div\n key={lineNumber}\n ref={focused ? targetRef : undefined}\n data-opengeni-file-line={lineNumber}\n {...(focused ? { \"data-opengeni-focus-line\": \"\" } : {})}\n aria-current={focused ? \"location\" : undefined}\n className={cn(\"flex gap-3 px-2 py-0.5 leading-6\", focused && \"bg-og-accent-soft\")}\n >\n <span className=\"w-11 shrink-0 select-none text-right tabular-nums text-og-fg-subtle\">\n {lineNumber}\n </span>\n <pre className=\"min-w-0 flex-1 whitespace-pre-wrap break-words\">{text || \" \"}</pre>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction GitHeader({ git, loading }: { git: SandboxFilesGitSummary; loading: boolean }) {\n if (loading) {\n return (\n <div\n className=\"flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm text-og-fg-muted\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <LoaderCircleIcon\n className=\"size-3.5 shrink-0 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n <span>Loading repository…</span>\n </div>\n );\n }\n const dirty = git.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 aria-hidden=\"true\"\n className={cn(\n \"size-2 shrink-0 rounded-full\",\n dirty ? \"bg-og-status-running\" : \"bg-og-status-idle\",\n )}\n />\n <span className=\"sr-only\">\n {dirty ? `Uncommitted changes in ${git.dirtyCount} files` : \"No uncommitted changes\"}\n </span>\n <span className=\"truncate font-og-mono text-og-fg\">\n {git.repoCount > 1\n ? `${git.repoCount} repositories`\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 {/* Small arrow glyphs can make axe's pixel overlap heuristic inconclusive.\n Keep both counters in the same computed-contrast audit as the dirty count. */}\n {git.ahead > 0 && <span data-contrast-audited>↑{git.ahead}</span>}\n {git.behind > 0 && <span data-contrast-audited>↓{git.behind}</span>}\n </span>\n )}\n {dirty && (\n <span\n aria-hidden=\"true\"\n data-contrast-audited\n className=\"ml-auto shrink-0 text-og-xs text-og-fg-subtle\"\n >\n {git.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 \"min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-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 imageUrl?: 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: UseSandboxFilesResult[\"readFile\"],\n reloadRevision: string | number = 0,\n): FileViewState {\n const previousPathRef = useRef<string | null>(null);\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 previousPathRef.current = null;\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 const pathChanged = previousPathRef.current !== path;\n previousPathRef.current = path;\n let cancelled = false;\n const abort = new AbortController();\n if (pathChanged) {\n setState({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: true,\n error: null,\n });\n } else {\n // Keep the last successful preview visible while a remote Modal read\n // revalidates it. Replacing useful content with a multi-second spinner\n // makes a live workspace feel slower and hides the state being refreshed.\n setState((previous) => ({ ...previous, error: null }));\n }\n void readFile(path, { signal: abort.signal })\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 imageUrl:\n !res.truncated && res.encoding === \"base64\" ? rasterImageUrl(path, res.content) : null,\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 const error = cause instanceof Error ? cause : new Error(String(cause));\n setState((previous) =>\n pathChanged\n ? {\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: false,\n error,\n }\n : { ...previous, loading: false, error },\n );\n });\n return () => {\n cancelled = true;\n abort.abort();\n };\n }, [path, readFile, reloadRevision]);\n return state;\n}\n\n/** Only raster formats belong in this preview; never interpret SVG/HTML as a document. */\nfunction rasterImageUrl(path: string, content: string): string | null {\n const extension = path.split(\".\").pop()?.toLowerCase();\n const mime =\n extension === \"png\"\n ? \"image/png\"\n : extension === \"jpg\" || extension === \"jpeg\"\n ? \"image/jpeg\"\n : extension === \"gif\"\n ? \"image/gif\"\n : extension === \"webp\"\n ? \"image/webp\"\n : null;\n return mime ? `data:${mime};base64,${content}` : null;\n}\n\nfunction RasterFilePreview({ src, path }: { src: string; path: string }) {\n const [failed, setFailed] = useState(false);\n return failed ? (\n <Notice title=\"Image preview unavailable\" announce=\"alert\">\n Could not decode {path} as an image.\n </Notice>\n ) : (\n <img\n src={src}\n alt={path}\n onError={() => setFailed(true)}\n className=\"max-w-full object-contain\"\n />\n );\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({\n children,\n className,\n icon,\n title,\n announce,\n}: {\n children: ReactNode;\n className?: string | undefined;\n icon?: ReactNode | undefined;\n title?: string | undefined;\n announce?: \"status\" | \"alert\" | undefined;\n}) {\n return (\n <div\n role={announce}\n aria-atomic={announce ? \"true\" : undefined}\n aria-live={announce === \"alert\" ? \"assertive\" : announce === \"status\" ? \"polite\" : undefined}\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 <div className=\"flex max-w-sm flex-col items-center gap-2.5\">\n {icon ? (\n <span className=\"grid size-10 place-items-center rounded-og-lg border border-og-border bg-og-surface-1 text-og-fg-muted shadow-sm\">\n {icon}\n </span>\n ) : null}\n {title ? <p className=\"font-medium text-og-fg\">{title}</p> : null}\n <div data-contrast-audited className=\"leading-5\">\n {children}\n </div>\n </div>\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 {\n Group,\n Panel,\n Separator,\n useDefaultLayout,\n usePanelRef,\n type Layout,\n type LayoutChangedMeta,\n type LayoutStorage,\n} from \"react-resizable-panels\";\nimport { cn } from \"../lib/cn\";\n\nexport type WorkspaceTab = {\n id: string;\n label: ReactNode;\n /** Optional icon used by the compact activity rail. */\n icon?: ReactNode | undefined;\n /** Accessible name when `label` is not plain text. */\n ariaLabel?: string | undefined;\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 /** Keep the panel-local Hide workspace control when the host controls collapsed state. */\n showCollapseControl?: boolean | undefined;\n /** A status accessory pinned to the right of the workspace header, 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\nconst SERVER_LAYOUT_STORAGE: LayoutStorage = {\n getItem: () => null,\n setItem: () => {},\n};\n\n/** `useDefaultLayout` defaults to the ambient `localStorage` identifier when\n * storage is undefined, which throws during SSR. Access can also throw in a\n * browser that blocks storage (sandboxed frames/private policy), so both cases\n * use a stable, non-persisting implementation instead. */\nfunction getLayoutStorage(): LayoutStorage {\n if (typeof window === \"undefined\") return SERVER_LAYOUT_STORAGE;\n try {\n return window.localStorage;\n } catch {\n return SERVER_LAYOUT_STORAGE;\n }\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 showCollapseControl = true,\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 rootRef = useRef<HTMLDivElement | null>(null);\n const reopenRef = useRef<HTMLButtonElement | null>(null);\n const returnFocusRef = useRef<HTMLElement | null>(null);\n const initialNarrowFocusRef = useRef(false);\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 // The host header remains the stable reopen action. The open panel also owns\n // a local Hide workspace action so a user never has to hunt elsewhere to\n // dismiss it; standalone usage keeps the thin reopen rail as well.\n const hostControlled = collapsedProp !== undefined;\n const previousCollapsedRef = useRef(collapsed);\n\n // Persisted layout (width split) keyed by autoSaveId.\n const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n panelIds: [\"primary\", \"dock\"],\n storage: getLayoutStorage(),\n id: autoSaveId,\n });\n const expandedDefaultLayout =\n defaultLayout && (defaultLayout.dock ?? 0) > 1 ? defaultLayout : undefined;\n const lastExpandedSizeRef = useRef(expandedDefaultLayout?.dock ?? defaultSize);\n const layoutIdentityRef = useRef(autoSaveId);\n if (layoutIdentityRef.current !== autoSaveId) {\n layoutIdentityRef.current = autoSaveId;\n lastExpandedSizeRef.current = expandedDefaultLayout?.dock ?? defaultSize;\n }\n const persistExpandedLayout = useCallback(\n (layout: Layout, meta: LayoutChangedMeta) => {\n // Both supported panel-library versions report 100/0 when the host\n // collapses the dock. Do not replace the last user-selected width with it.\n const dockSize = layout.dock ?? 0;\n if (dockSize <= 1) return;\n lastExpandedSizeRef.current = dockSize;\n onLayoutChanged(layout, meta);\n },\n [onLayoutChanged],\n );\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?.resize(`${lastExpandedSizeRef.current}%`);\n }\n }, [collapsedProp, dockPanelRef]);\n\n // Treat the narrow overlay like a real modal: remember the external opener,\n // move focus into the selected tab, and restore it on close. The standalone\n // desktop dock instead focuses its newly-visible reopen rail after collapse.\n useEffect(() => {\n const previous = previousCollapsedRef.current;\n previousCollapsedRef.current = collapsed;\n if (previous === collapsed) return;\n\n if (!collapsed) {\n const active = document.activeElement;\n const workspaceSurface = rootRef.current?.querySelector<HTMLElement>(\n narrow ? '[role=\"dialog\"]' : \"[data-workspace-surface]\",\n );\n if (active instanceof HTMLElement && !workspaceSurface?.contains(active)) {\n returnFocusRef.current = active;\n }\n if (narrow) {\n const frame = requestAnimationFrame(() => {\n rootRef.current\n ?.querySelector<HTMLElement>('[role=\"dialog\"] [role=\"tab\"][aria-selected=\"true\"]')\n ?.focus();\n });\n return () => cancelAnimationFrame(frame);\n }\n return;\n }\n\n const frame = requestAnimationFrame(() => {\n if (!hostControlled) {\n reopenRef.current?.focus();\n return;\n }\n const target = returnFocusRef.current;\n if (target?.isConnected) {\n target.focus();\n return;\n }\n // A controlled desktop dock can be restored open on the initial render,\n // so there may be no opener to remember. Never leave focus parked on the\n // now-hidden workspace chrome; fall back to the host's primary surface.\n rootRef.current\n ?.querySelector<HTMLElement>(\n '[data-workspace-primary] button:not([disabled]), [data-workspace-primary] a[href], [data-workspace-primary] input:not([disabled]), [data-workspace-primary] textarea:not([disabled]), [data-workspace-primary] select:not([disabled]), [data-workspace-primary] [tabindex]:not([tabindex=\"-1\"])',\n )\n ?.focus();\n });\n return () => cancelAnimationFrame(frame);\n }, [collapsed, hostControlled, narrow]);\n\n // On the first narrow render there is no collapsed-state transition to drive\n // focus into the modal: the overlay can already be open at mount. Place focus\n // on its selected tab once, just as we do when an existing overlay is opened.\n useEffect(() => {\n if (!narrow || collapsed || initialNarrowFocusRef.current) return;\n initialNarrowFocusRef.current = true;\n const active = document.activeElement;\n const workspaceSurface = rootRef.current?.querySelector<HTMLElement>('[role=\"dialog\"]');\n if (active instanceof HTMLElement && !workspaceSurface?.contains(active)) {\n returnFocusRef.current = active;\n }\n const frame = requestAnimationFrame(() => {\n workspaceSurface?.querySelector<HTMLElement>('[role=\"tab\"][aria-selected=\"true\"]')?.focus();\n });\n return () => cancelAnimationFrame(frame);\n }, [collapsed, narrow]);\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. Tab is\n // fenced inside either full-screen surface: both visually cover the host, so\n // keyboard focus must never move into invisible content behind them.\n useEffect(() => {\n const overlayOpen = maximized || (narrow && !collapsed);\n if (!overlayOpen) return;\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n if (maximized) setMaximized(false);\n else collapse();\n return;\n }\n if (event.key !== \"Tab\") return;\n const surface = rootRef.current?.querySelector<HTMLElement>(\n narrow ? '[role=\"dialog\"]' : \"[data-workspace-surface]\",\n );\n if (!surface) return;\n const focusable = Array.from(surface.querySelectorAll<HTMLElement>(\"*\")).filter(\n (element) =>\n element.tabIndex >= 0 &&\n !element.hasAttribute(\"disabled\") &&\n element.getClientRects().length > 0 &&\n getComputedStyle(element).visibility !== \"hidden\",\n );\n const first = focusable[0];\n const last = focusable.at(-1);\n const active = document.activeElement;\n if (!first || !last) {\n event.preventDefault();\n surface.focus();\n return;\n }\n if (!surface.contains(active)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n return;\n }\n if ((event.shiftKey && active === first) || (!event.shiftKey && active === last)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n return;\n }\n // Focus can emerge from a shadow-DOM editor/highlighter host at a point\n // the light-DOM order cannot predict. Repair any escape after the browser\n // performs its default Tab move.\n requestAnimationFrame(() => {\n const next = document.activeElement;\n if (!surface.contains(next)) (event.shiftKey ? last : first).focus();\n });\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 ref={rootRef} className={cn(\"relative flex h-full min-h-0 w-full min-w-0\", className)}>\n <div\n data-workspace-primary\n aria-hidden={!collapsed ? true : undefined}\n className=\"min-h-0 min-w-0 flex-1\"\n inert={!collapsed ? true : undefined}\n >\n {primary}\n </div>\n <div\n data-workspace-surface\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 hidden={collapsed}\n style={{\n // Author utility classes can override the user-agent `[hidden]`\n // rule (for example this surface's `flex` class). Keep an inline\n // display guard so a collapsed mobile workspace is actually gone\n // visually as well as from the accessibility tree.\n display: collapsed ? \"none\" : undefined,\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=\"Hide workspace\" label=\"Hide workspace\">\n <XIcon className=\"size-4\" />\n </ChromeButton>\n }\n />\n </div>\n {collapsed && !hostControlled ? (\n <button\n ref={reopenRef}\n type=\"button\"\n onClick={expand}\n title=\"Open workspace\"\n aria-label=\"Open workspace\"\n className=\"absolute right-3 top-3 z-30 inline-flex size-11 items-center justify-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted shadow-lg transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent\"\n style={{ marginTop: \"env(safe-area-inset-top)\" }}\n >\n <ChevronsLeftRightIcon className=\"size-4\" aria-hidden />\n </button>\n ) : null}\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 && !showCollapseControl ? null : (\n <ChromeButton onClick={collapse} title=\"Hide workspace\" label=\"Hide workspace\">\n <PanelRightCloseIcon className=\"size-3.5\" />\n </ChromeButton>\n )}\n </>\n }\n />\n );\n\n return (\n <div ref={rootRef} 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 {...(expandedDefaultLayout ? { defaultLayout: expandedDefaultLayout } : {})}\n onLayoutChanged={persistExpandedLayout}\n >\n <Panel id=\"primary\" minSize=\"30%\" className=\"min-h-0 min-w-0\">\n <div\n data-workspace-primary\n aria-hidden={maximized ? true : undefined}\n className=\"h-full min-h-0 min-w-0\"\n inert={maximized ? true : undefined}\n >\n {primary}\n </div>\n </Panel>\n\n {!collapsed && (\n <Separator className=\"group relative z-10 w-1.5 shrink-0 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent max-[1023px]:-mx-[19px] max-[1023px]:w-11 pointer-coarse:-mx-[19px] pointer-coarse:w-11\">\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-focus-visible: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 {/* One persistent mount across normal, collapsed, and maximized modes:\n layout changes must never destroy an editor buffer or terminal view. */}\n <div\n data-workspace-surface\n role={maximized ? \"dialog\" : undefined}\n aria-modal={maximized ? true : undefined}\n aria-label={maximized ? \"Workspace\" : undefined}\n aria-hidden={collapsed ? true : undefined}\n className={cn(\n \"flex h-full min-h-0 min-w-0 flex-col bg-og-bg\",\n maximized ? \"fixed inset-0 z-40\" : \"border-l border-og-border\",\n collapsed && \"invisible pointer-events-none\",\n )}\n >\n {dockChrome}\n </div>\n </Panel>\n </Group>\n\n {/* Collapsed rail: the standalone fallback re-open affordance. Hidden\n when the host controls collapse — its header remains the stable way in. */}\n {collapsed && !maximized && !hostControlled && (\n <button\n ref={reopenRef}\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 </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 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent 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 chromeRef = useRef<HTMLDivElement | null>(null);\n const [compact, setCompact] = useState(false);\n const active = tabs.find((t) => t.id === current) ?? tabs[0];\n const tabsetId = useId();\n const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);\n const [visitedTabs, setVisitedTabs] = useState<Set<string>>(() => new Set());\n const activeId = active?.id ?? \"\";\n\n // Dock width, not viewport width, chooses rail density. A narrow split keeps\n // the icon-first activity rail usable without stealing the panel's content\n // width; overlays and maximized views retain readable labels.\n useDockLayoutEffect(() => {\n const node = chromeRef.current;\n if (!node) return;\n const update = () => {\n const desktop =\n typeof window.matchMedia !== \"function\" || window.matchMedia(\"(min-width: 1024px)\").matches;\n const next = desktop && node.getBoundingClientRect().width < 440;\n setCompact((previous) => (previous === next ? previous : next));\n };\n update();\n if (typeof ResizeObserver === \"undefined\") {\n window.addEventListener(\"resize\", update);\n return () => window.removeEventListener(\"resize\", update);\n }\n const observer = new ResizeObserver(update);\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (!activeId) return;\n setVisitedTabs((previous) => {\n if (previous.has(activeId)) return previous;\n const next = new Set(previous);\n next.add(activeId);\n return next;\n });\n }, [activeId]);\n\n const activateTab = (index: number) => {\n const tab = tabs[index];\n if (!tab) {\n return;\n }\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 === \"ArrowDown\") nextIndex = (index + 1) % tabs.length;\n else if (event.key === \"ArrowUp\") 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 <div\n ref={chromeRef}\n data-dock-chrome\n data-compact={compact ? \"true\" : undefined}\n className=\"flex h-full min-h-0 min-w-0 flex-col\"\n >\n <div className=\"flex min-h-10 shrink-0 items-center gap-2 border-b border-og-border px-2 max-[1023px]:min-h-12\">\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n {leading ?? (\n <span className=\"hidden truncate text-og-sm font-semibold text-og-fg max-[1023px]:inline\">\n Workspace\n </span>\n )}\n </div>\n <div className=\"min-w-0 shrink text-og-fg-muted\">{accessory}</div>\n <div className=\"flex shrink-0 items-center gap-0.5 text-og-fg-subtle\">{controls}</div>\n </div>\n <div className=\"flex min-h-0 min-w-0 flex-1\">\n <div\n className={cn(\n \"flex shrink-0 flex-col gap-1 overflow-x-hidden overflow-y-auto border-r border-og-border bg-og-surface-1/45 p-1.5\",\n compact ? \"w-12\" : \"w-32 max-[1023px]:w-36\",\n )}\n role=\"tablist\"\n aria-label=\"Workspace panels\"\n aria-orientation=\"vertical\"\n >\n {tabs.map((tab, index) => {\n const tabName = tab.ariaLabel ?? (typeof tab.label === \"string\" ? tab.label : tab.id);\n return (\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-label={compact && tab.icon ? tabName : undefined}\n title={compact && tab.icon ? tabName : undefined}\n aria-selected={tab.id === current}\n aria-controls={`${tabsetId}-panel-${index}`}\n tabIndex={tab.id === current ? 0 : -1}\n onClick={() => onTab(tab.id)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n className={cn(\n \"group relative flex min-h-9 w-full items-center gap-2 rounded-og-md px-2 text-left text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11\",\n compact && \"justify-center px-1\",\n tab.id === current\n ? \"bg-og-accent-soft text-og-fg shadow-[inset_2px_0_0_var(--og-color-accent)]\"\n : \"text-og-fg-subtle hover:bg-og-surface-2 hover:text-og-fg\",\n )}\n >\n {tab.icon ? (\n <span\n className=\"flex size-4 shrink-0 items-center justify-center [&>svg]:size-4\"\n aria-hidden\n >\n {tab.icon}\n </span>\n ) : null}\n {!compact || !tab.icon ? (\n <span data-contrast-audited className=\"min-w-0 flex-1 truncate\">\n {tab.label}\n </span>\n ) : null}\n {tab.badge ? (\n <span\n className={cn(\"shrink-0\", compact && \"absolute -right-0.5 -top-0.5 scale-90\")}\n >\n {tab.badge}\n </span>\n ) : null}\n </button>\n );\n })}\n </div>\n <div className=\"min-h-0 min-w-0 flex-1 overflow-hidden\">\n {tabs.length > 0 ? (\n tabs.map((tab, index) => {\n const selected = tab.id === activeId;\n const shouldMount = selected || visitedTabs.has(tab.id);\n return (\n <div\n key={tab.id}\n id={`${tabsetId}-panel-${index}`}\n aria-labelledby={`${tabsetId}-tab-${index}`}\n className=\"h-full min-h-0 min-w-0 overflow-hidden\"\n hidden={!selected}\n role=\"tabpanel\"\n >\n {shouldMount ? tab.content : null}\n </div>\n );\n })\n ) : (\n <div className=\"h-full min-h-0 min-w-0\" aria-label=\"Workspace\" role=\"tabpanel\" />\n )}\n </div>\n </div>\n </div>\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// Browser — workspace-wide BrowserSessions, tabs, live frames, and input\n// Computer — workspace ComputerSessions: native targets, frames, and input\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 uses — that is criterion F1.\nimport {\n lazy,\n type ReactNode,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { SessionEvent } from \"@opengeni/sdk\";\nimport type { InteractionPlacement } from \"@opengeni/sdk/interaction\";\nimport {\n CircleCheckIcon,\n CpuIcon,\n FileCode2Icon,\n GitCompareArrowsIcon,\n Globe2Icon,\n LoaderCircleIcon,\n MonitorIcon,\n RefreshCwIcon,\n SquareTerminalIcon,\n TriangleAlertIcon,\n} from \"lucide-react\";\n\nimport { type ClientOverride, useOpenGeni } from \"../provider\";\nimport { cn } from \"../lib/cn\";\nimport { xtermThemeFromTokens } from \"../lib/xterm-theme\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport type { BrowserFrameWebSocketFactory } from \"../hooks/use-browser-frame-stream\";\nimport type { ComputerFrameWebSocketFactory } from \"../hooks/use-computer-frame-stream\";\nimport type { FileNodeVisibilityPredicate } from \"../file-node-visibility\";\nimport { useSessionCapabilities } from \"../hooks/use-session-capabilities\";\nimport { useSandboxFiles } from \"../hooks/use-sandbox-files\";\nimport {\n useSandboxGit,\n type SandboxGitComparison,\n type UseSandboxGitResult,\n} from \"../hooks/use-sandbox-git\";\nimport { useSandboxTerminal } from \"../hooks/use-sandbox-terminal\";\nimport { useWorkspaceCapture } from \"../hooks/use-workspace-capture\";\nimport { useMachineChip, type MachineChip } from \"../hooks/use-machine-chip\";\nimport { MACHINES_SESSION_POLL_MS, useMachines } from \"../hooks/use-machines\";\nimport type { MachineView } from \"../types/machines\";\nimport { SandboxFiles } from \"./sandbox-files\";\nimport { WorkbenchChanges } from \"./workbench-changes\";\nimport { SandboxTerminal, type XtermTheme } from \"./sandbox-terminal\";\nimport { WorkspaceDock, type WorkspaceDockProps, type WorkspaceTab } from \"./workspace-dock\";\n\nconst LazyBrowserViewer = lazy(async () => {\n const { BrowserViewer } = await import(\"./browser-viewer\");\n return { default: BrowserViewer };\n});\n\nconst LazyComputerViewer = lazy(async () => {\n const { ComputerViewer } = await import(\"./computer-viewer\");\n return { default: ComputerViewer };\n});\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\";\nexport const WORKBENCH_TAB_TERMINAL = \"terminal\";\nexport const WORKBENCH_TAB_BROWSER = \"browser\";\nexport const WORKBENCH_TAB_DESKTOP = \"desktop\";\n\n/**\n * The built-in workbench surfaces in their canonical display order. Hosts can\n * pass a subset through `surfaces`; omission preserves the complete standalone\n * workbench.\n */\nexport const WORKBENCH_SURFACES = [\n WORKBENCH_TAB_CHANGES,\n WORKBENCH_TAB_FILES,\n WORKBENCH_TAB_TERMINAL,\n WORKBENCH_TAB_BROWSER,\n WORKBENCH_TAB_DESKTOP,\n] as const;\n\nexport type SandboxWorkspaceSurface = (typeof WORKBENCH_SURFACES)[number];\n\nfunction isWorkbenchSurface(value: string): value is SandboxWorkspaceSurface {\n return (WORKBENCH_SURFACES as readonly string[]).includes(value);\n}\n\nfunction isCanonicalAbsoluteSandboxPath(value: string | null | undefined): boolean {\n if (!value) return false;\n const portable = value.replaceAll(\"\\\\\", \"/\");\n return portable.startsWith(\"/\") || /^[A-Za-z]:\\//u.test(portable);\n}\n\nfunction sourceDrivenDefaultTab(\n hasChanges: boolean,\n changesEnabled: boolean,\n filesEnabled: boolean,\n): string | null {\n if (hasChanges && changesEnabled) return WORKBENCH_TAB_CHANGES;\n if (filesEnabled) return WORKBENCH_TAB_FILES;\n if (changesEnabled) return WORKBENCH_TAB_CHANGES;\n return null;\n}\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 case \"repository_read_unavailable\":\n return \"Workspace capture is incomplete because repository changes could not be read. Live files remain authoritative.\";\n default:\n return \"Workspace capture is incomplete because repository discovery failed. Live files remain authoritative.\";\n }\n}\n\nfunction WorkbenchSurfaceLoading({ name }: { name: \"Browser\" | \"Desktop\" }) {\n return (\n <CenteredState\n icon={\n <LoaderCircleIcon className=\"size-5 animate-spin motion-reduce:animate-none\" aria-hidden />\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">Opening {name}</p>\n </CenteredState>\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 * `<SandboxWorkspace>` uses this only as an optional early hint after its own\n * capture GET reports no durable capture. A pure embedder needs no events-at-mount\n * contract: it falls through to authoritative live Git instead.\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 if (bestFileCount > 0) return WORKBENCH_TAB_CHANGES;\n\n let latestGitSeq = -1;\n let committedOnly = false;\n for (const event of events ?? []) {\n if (event.type !== \"git.changed\" || event.sequence > bestSeq) continue;\n if (event.sequence <= latestGitSeq) continue;\n const payload = event.payload as { ahead?: number; reason?: string } | null;\n latestGitSeq = event.sequence;\n committedOnly =\n (typeof payload?.ahead === \"number\" && payload.ahead > 0) || payload?.reason === \"commit\";\n }\n return committedOnly ? 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\n/**\n * Whether this session currently owns an admitted agent turn. Automatic live\n * Files/Git reads pause across the whole turn: command boundaries are not a safe\n * gap because the next tool can dispatch before a remote provider read releases\n * its sandbox holder. Existing/captured content remains usable, and the terminal\n * turn event resumes one authoritative refresh.\n */\nfunction workspaceTurnInFlight(events: SessionEvent[]): boolean {\n const activeTurnIds = new Set<string>();\n let anonymousTurnInFlight = false;\n let sessionOwnsWorkspace = false;\n for (const event of events) {\n if (event.type === \"session.status.changed\") {\n const status =\n event.payload && typeof event.payload === \"object\" && !Array.isArray(event.payload)\n ? (event.payload as Record<string, unknown>).status\n : null;\n sessionOwnsWorkspace = status === \"running\" || status === \"recovering\";\n continue;\n }\n if (event.type === \"turn.started\") {\n if (event.turnId) activeTurnIds.add(event.turnId);\n else anonymousTurnInFlight = true;\n continue;\n }\n if (\n event.type !== \"turn.completed\" &&\n event.type !== \"turn.failed\" &&\n event.type !== \"turn.cancelled\" &&\n event.type !== \"turn.superseded\"\n ) {\n continue;\n }\n if (event.turnId) activeTurnIds.delete(event.turnId);\n else anonymousTurnInFlight = false;\n }\n // The retained event window preserves the latest status even after a very\n // long turn has evicted its original turn.started event.\n return sessionOwnsWorkspace || anonymousTurnInFlight || activeTurnIds.size > 0;\n}\n\nexport type WorkspaceMachine = {\n /** Whether at least one built-in workbench surface is enabled. */\n enabled: boolean;\n /** The derived live/waking/sleeping-or-offline chip model. */\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 /**\n * Built-in surfaces this host wants to expose. Omit for all five. A disabled\n * surface is behaviorally dormant: its data hooks, warm intents, stream\n * attachment, and navigation callbacks are not activated.\n */\n surfaces?: readonly SandboxWorkspaceSurface[] | undefined;\n /** Override the source-driven default tab (e.g. a host landing tab id). When\n * omitted the workbench picks Changes-vs-Files from capture or live Git. */\n initialTab?: string | null | undefined;\n /** Actually selected dock tab. Inactive data surfaces retain cache but issue no live reads. */\n activeTab?: string | null | undefined;\n /** Whether the dock is visible. Hidden docks retain UI state but must not keep\n * expensive browser/computer media streams alive. */\n workspaceVisible?: boolean | 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 /** Alternate frame transport for non-browser runtimes and deterministic tests. */\n browserWebSocketFactory?: BrowserFrameWebSocketFactory | undefined;\n /** Alternate Computer frame transport for non-browser runtimes and deterministic tests. */\n computerWebSocketFactory?: ComputerFrameWebSocketFactory | undefined;\n /** Host-owned setup page or store listing for attaching an existing Chrome profile. */\n browserExtensionSetupUrl?: string | undefined;\n /** File requested by a Changes guard. The Files surface defers the read until\n * the sandbox is live, then reveals this path. */\n requestedFilePath?: string | null | undefined;\n /** Unique identity for `requestedFilePath`, including repeated requests for the\n * same path. */\n requestedFileRequestId?: string | number | null | undefined;\n /** 1-based line to reveal after `requestedFilePath` opens. */\n requestedFileLine?: number | null | undefined;\n /** Route a guarded diff into the host's Files tab. */\n onOpenFile?: ((path: string) => void) | undefined;\n /** Restore and report navigation inside the built-in workbench surfaces. */\n initialFilePath?: string | null | undefined;\n onFilePathChange?: ((path: string | null) => void) | undefined;\n /** Presentation-only filter for Files tree nodes and selected-file viewing. */\n isFileNodeVisible?: FileNodeVisibilityPredicate | undefined;\n initialBrowserSessionId?: string | null | undefined;\n onBrowserSessionIdChange?: ((browserSessionId: string | null) => void) | undefined;\n initialComputerSessionId?: string | null | undefined;\n onComputerSessionIdChange?: ((computerSessionId: string | null) => void) | undefined;\n /** Navigate the host dock to one exact linked ComputerSession. */\n onOpenComputerSession?: ((computerSessionId: string) => void) | undefined;\n requestedComputerSessionId?: string | null | undefined;\n requestedComputerRequestId?: string | number | null | undefined;\n};\n\nexport type UseSandboxWorkspaceTabsResult = {\n /** Changes | Files | Terminal | Browser | Desktop (capability-gated where noted). */\n tabs: WorkspaceTab[];\n /** The source-driven default tab: Changes when the first authoritative capture\n * has changes, else Files (a host `initialTab` overrides). Choosing a tab\n * never performs hidden live workspace I/O.\n * null while that source resolves, or permanently when neither Changes nor\n * Files is enabled; the choice latches once. */\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 warmTerminal: boolean;\n warmFiles: boolean;\n};\n\nfunction emptyWarmIntents(sessionId: string): SessionWarmIntents {\n return {\n sessionId,\n warmTerminal: false,\n warmFiles: 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, automatic desktop acknowledgment, and the xterm theme observer — all\n * package-local.\n */\nexport function useSandboxWorkspaceTabs(\n options: UseSandboxWorkspaceTabsOptions,\n): UseSandboxWorkspaceTabsResult {\n const { client, workspaceId, workspaceInteractionEvent } = useOpenGeni(options);\n const {\n sessionId,\n events,\n onNotify,\n browserWebSocketFactory,\n computerWebSocketFactory,\n browserExtensionSetupUrl,\n requestedFilePath,\n requestedFileRequestId,\n requestedFileLine,\n onOpenFile,\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n onOpenComputerSession,\n requestedComputerSessionId,\n requestedComputerRequestId,\n } = options;\n const initialTab = options.initialTab ?? null;\n const activeTab = options.activeTab ?? initialTab;\n const workspaceVisible = options.workspaceVisible ?? true;\n const requestedSurfaces = options.surfaces ?? WORKBENCH_SURFACES;\n const surfaceSet = new Set<SandboxWorkspaceSurface>(requestedSurfaces);\n const changesEnabled = surfaceSet.has(WORKBENCH_TAB_CHANGES);\n const filesEnabled = surfaceSet.has(WORKBENCH_TAB_FILES);\n const terminalEnabled = surfaceSet.has(WORKBENCH_TAB_TERMINAL);\n const browserEnabled = surfaceSet.has(WORKBENCH_TAB_BROWSER);\n const desktopEnabled = surfaceSet.has(WORKBENCH_TAB_DESKTOP);\n const createLinkedComputer = useCallback(\n async (name: string, placement?: InteractionPlacement) => {\n const response = await client.createComputerSession(workspaceId, {\n operationId: crypto.randomUUID(),\n sessionId,\n name,\n ...(placement ? { placement } : {}),\n });\n if (response.operation.state !== \"completed\" || response.session.lifecycle !== \"active\") {\n throw new Error(response.operation.error?.message ?? \"The desktop could not be opened.\");\n }\n return {\n id: response.session.id,\n placement: response.session.placement,\n };\n },\n [client, sessionId, workspaceId],\n );\n const workspaceDataEnabled = changesEnabled || filesEnabled;\n const machineSurfaceEnabled = workspaceDataEnabled || terminalEnabled || desktopEnabled;\n // Do not speculatively activate both remote workspace surfaces while the dock\n // is still resolving its selected tab. Modal calls cannot be cancelled after\n // dispatch, so that transient state otherwise creates an aborted duplicate\n // batch immediately before the real selected-tab request.\n const resolvedActiveTab = activeTab ?? initialTab;\n const changesActive = resolvedActiveTab === WORKBENCH_TAB_CHANGES;\n const filesActive = resolvedActiveTab === WORKBENCH_TAB_FILES;\n const turnInFlight = workspaceTurnInFlight(events);\n const surfaceIdentity = WORKBENCH_SURFACES.filter((surface) => surfaceSet.has(surface)).join(\",\");\n\n // The two 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): terminal engagement (`onActivate`) and a deliberate\n // live-file open/edit in Files. 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 { warmTerminal, warmFiles } = warmIntents;\n // A host-requested file is itself explicit live-file intent. Derive the wake\n // directly from the request instead of relying on a follow-up effect to copy\n // it into local state; otherwise a missing or delayed effect leaves the file\n // waiting for a sandbox that this hook never asks to start.\n const filesWarmRequested = warmFiles || Boolean(requestedFilePath);\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 // The session's machine fleet + the active-sandbox pointer. Drives the header\n // chip (which machine + its connection state). Shares the session list poll.\n const machines = useMachines({\n workspaceId,\n sessionId,\n pollIntervalMs: MACHINES_SESSION_POLL_MS,\n enabled: machineSurfaceEnabled,\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 enabled: machineSurfaceEnabled,\n attachDesktop: false,\n attachTerminal: terminalEnabled && warmTerminal,\n // Explicit live-file intent only — NOT \"the Files tab is open\". A cold edit\n // or guarded-file open wakes the box; a glance at the tree/diff does not.\n attachFiles: workspaceDataEnabled && filesWarmRequested,\n });\n const capabilities = caps.capabilities;\n const liveness = capabilities?.liveness;\n // A missing capability document is not evidence that the sandbox is live.\n // Pass explicit null to live-I/O hooks so fast capture/event hydration cannot\n // exploit their legacy \"liveness omitted\" compatibility path while negotiation\n // is still pending.\n const liveIoLiveness = liveness ?? null;\n const fileSystemOn = capabilities?.FileSystem.available ?? false;\n const fileSystemRoute = capabilities\n ? { epoch: capabilities.leaseEpoch, root: capabilities.FileSystem.root }\n : undefined;\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 (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 // Mutations are live-only. A capture is a review artifact, never a writable\n // surrogate for a sleeping machine; the user must deliberately open the live\n // workspace before create/rename/delete/edit controls appear.\n const filesEditable = fileSystemOn && !fsReadOnly && sandboxAcceptsLiveIo(liveness);\n const gitOn = capabilities?.Git.available ?? false;\n const terminalOn = terminalEnabled && (capabilities?.Terminal.transport ?? null) !== null;\n // A descriptor-only pty-ws cell intentionally has no short-lived URL until\n // terminal intent acquires one. Do not mistake that grant boundary for a\n // legacy HTTP PTY and eagerly open a second terminal. The fallback exists only\n // for a genuinely firehose-transport backend with no typed degradation.\n const ptyCapable =\n warmTerminal &&\n (capabilities?.Terminal.ptyCapable ?? false) &&\n capabilities?.Terminal.transport === \"sse-events\" &&\n capabilities?.Terminal.reason === null;\n const terminal = useSandboxTerminal(sessionId, {\n events: terminalEnabled ? events : [],\n interactive: terminalEnabled && ptyCapable,\n liveness,\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 // BrowserSession and ComputerSession lifecycles use the same placement lease\n // as files/terminal/desktop, but are workspace resources rather than session\n // events. Re-read the capability document on their canonical workspace\n // invalidation so the one machine chip cannot remain \"Offline\" beside a live\n // browser/computer (or remain \"Live\" after the final interaction holder ends).\n // This is a read-only negotiation: it never acquires a holder or wakes a box.\n useEffect(() => {\n if (workspaceInteractionEvent?.workspaceId !== workspaceId) return;\n renegotiate();\n }, [workspaceId, workspaceInteractionEvent, 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 immediately; a warm box reconciles live without discarding the capture\n // when that provider read is temporarily unavailable.\n const captureState = useWorkspaceCapture(sessionId, {\n events,\n enabled: workspaceDataEnabled,\n });\n const captureAvailable = captureState.available;\n const liveWorkspaceExpected = sandboxAcceptsLiveIo(liveness);\n // Capability negotiation and capture resolution are independent requests. A\n // cold capability document can win that race by a few milliseconds; enabling\n // the leaf hooks in that window would make them interpret `capture: null` as a\n // real miss and issue Channel-A reads, waking the very box the capture exists\n // to avoid. Wait until the capture request has conclusively resolved. A warm\n // workspace never waits on this server-side snapshot.\n const capturePending =\n !liveWorkspaceExpected && (captureState.fileCount === null || captureState.loading);\n const repoPaths = useMemo(() => {\n const advertised = capabilities?.Git.repos ?? [];\n if (advertised.length > 0) return advertised;\n return captureState.capture?.repos.map((repo) => repo.root) ?? [];\n }, [capabilities?.Git.repos, captureState.capture]);\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 // No passive Channel-A reads while cold, even after a conclusive capture\n // miss. A missing capture gets an explicit \"Open live workspace\" gate.\n enabled: filesEnabled && (captureAvailable || (fileSystemOn && liveWorkspaceExpected)),\n // A cold sandbox can become warm while the first agent command still owns\n // startup. Do not race that command with an automatic Files read. Keeping\n // this fence at turn scope also avoids unsafe millisecond gaps between\n // sequential tool calls; rendered state and explicit user actions remain.\n active: filesActive && !turnInFlight,\n // A deliberate canonical absolute-path open browses in the selected target's\n // advertised namespace, so the authoritative tree and link share exact paths.\n ...(isCanonicalAbsoluteSandboxPath(requestedFilePath) && capabilities?.FileSystem.root\n ? { rootPath: capabilities.FileSystem.root }\n : {}),\n ...(fileSystemRoute ? { route: fileSystemRoute } : {}),\n repoPaths,\n liveness: liveIoLiveness,\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 [storedChangesComparison, setStoredChangesComparison] = useState<{\n sessionId: string;\n value: SandboxGitComparison;\n } | null>(null);\n const captureSupportsBranch =\n captureState.capture !== null &&\n captureState.capture.repos.length > 0 &&\n captureState.capture.repos.every((repo) => repo.branchDiff !== undefined);\n // A sleeping workspace can truthfully serve only the captured working-tree\n // comparison. A live workspace defaults to the branch comparison so committed\n // agent work remains visible. Explicit user selection is scoped per session.\n const changesComparison =\n storedChangesComparison?.sessionId === sessionId\n ? storedChangesComparison.value\n : liveWorkspaceExpected || captureSupportsBranch\n ? \"branch\"\n : \"working\";\n const setChangesComparison = useCallback(\n (value: SandboxGitComparison) => setStoredChangesComparison({ sessionId, value }),\n [sessionId],\n );\n const git = useSandboxGit(sessionId, {\n events,\n enabled:\n changesComparison === \"working\"\n ? workspaceDataEnabled && (captureAvailable || (gitOn && liveWorkspaceExpected))\n : changesComparison === \"branch\"\n ? workspaceDataEnabled && (captureSupportsBranch || (gitOn && liveWorkspaceExpected))\n : workspaceDataEnabled && gitOn && liveWorkspaceExpected,\n // Live Git belongs to the visible Changes surface. In particular, do not\n // turn an unresolved/default tab into a hidden provider read: that races the\n // agent's own sandbox commands and used to refresh after every tool output\n // even while Files was visibly selected.\n active: changesActive && !turnInFlight,\n repoPaths,\n liveness: liveIoLiveness,\n comparison: changesComparison,\n capture: changesComparison === \"staged\" ? null : captureState.capture,\n });\n useEffect(() => {\n if (\n changesComparison === \"branch\" &&\n git.error &&\n storedChangesComparison?.sessionId !== sessionId\n ) {\n // `origin/HEAD` is not guaranteed on a newly initialized repository, a\n // connected machine, or a clone whose remote was renamed. The implicit\n // live default must not strand the whole Changes surface when its ordinary\n // working-tree comparison is still valid. Fall back once; an explicit\n // user-selected Branch view remains selected and surfaces its real error.\n setStoredChangesComparison({ sessionId, value: \"working\" });\n }\n }, [changesComparison, git.error, sessionId, storedChangesComparison?.sessionId]);\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 (!terminalEnabled || 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 }, [terminalEnabled]);\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: (terminalEnabled && warmTerminal) || (workspaceDataEnabled && filesWarmRequested),\n capturedAt: captureState.capturedAt,\n });\n const workspaceWaking = chip.state === \"waking\";\n\n // The pre-paint default comes only from the durable capture. Default selection\n // must never dispatch live provider work: a live Git probe can overlap the\n // agent's first command, and an uncontrolled dock used to keep that probe\n // active forever after it visibly selected Files. A capture with reviewable\n // changes opens Changes; no capture (or an empty one) opens Files. The choice\n // latches once so later edits never steal the user's current tab.\n const defaultIdentity = `${sessionId}\\u0000${surfaceIdentity}`;\n const defaultTabRef = useRef<{ identity: string; value: string | null }>({\n identity: defaultIdentity,\n value: null,\n });\n if (defaultTabRef.current.identity !== defaultIdentity) {\n defaultTabRef.current = { identity: defaultIdentity, value: null };\n }\n const captureHasChanges =\n (captureState.fileCount ?? 0) > 0 ||\n (captureState.capture?.repos.some((repo) => (repo.branchDiff?.length ?? 0) > 0) ?? false);\n const captureUnavailable =\n (captureState.fileCount === 0 && !captureHasChanges) || captureState.error !== null;\n if (defaultTabRef.current.value === null) {\n if (initialTab && (!isWorkbenchSurface(initialTab) || surfaceSet.has(initialTab))) {\n defaultTabRef.current.value = initialTab;\n } else if (captureState.fileCount !== null && captureState.available) {\n defaultTabRef.current.value = sourceDrivenDefaultTab(\n captureHasChanges,\n changesEnabled,\n filesEnabled,\n );\n } else if (captureUnavailable && initialWorkspaceTab(events) === WORKBENCH_TAB_CHANGES) {\n defaultTabRef.current.value = sourceDrivenDefaultTab(true, changesEnabled, filesEnabled);\n } else if (captureState.fileCount !== null || captureState.error !== null) {\n // No durable review surface exists. Files owns the explicit live-workspace\n // gate; a user can open Changes deliberately if they need a fresh Git read.\n defaultTabRef.current.value = sourceDrivenDefaultTab(false, changesEnabled, filesEnabled);\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 — capture-backed and usable cold/offline when the host enables it.\n if (changesEnabled)\n list.push({\n id: WORKBENCH_TAB_CHANGES,\n label: \"Changes\",\n icon: <GitCompareArrowsIcon />,\n badge: dirtyCount > 0 ? <DirtyBadge count={dirtyCount} /> : undefined,\n content: (\n <ChangesTabBody\n git={git}\n comparison={changesComparison}\n onComparisonChange={setChangesComparison}\n captureAvailable={captureAvailable}\n captureRevision={captureState.revision}\n capturePending={capturePending}\n liveWorkspaceExpected={liveWorkspaceExpected}\n workspaceWaking={workspaceWaking}\n capabilitiesState={caps.state}\n capabilitiesError={caps.error}\n onRetry={caps.renegotiate}\n onWake={() => requestWarmIntent(\"warmFiles\")}\n {...(filesEnabled && onOpenFile\n ? {\n onOpenFile: (path: string) => {\n requestWarmIntent(\"warmFiles\");\n onOpenFile(path);\n },\n }\n : {})}\n />\n ),\n });\n\n // Files — capture-backed cold tree; live warm when the host enables it.\n if (filesEnabled)\n list.push({\n id: WORKBENCH_TAB_FILES,\n label: \"Files\",\n icon: <FileCode2Icon />,\n content: (\n <SandboxFiles\n key={sessionId}\n files={files}\n git={git}\n isNodeVisible={isFileNodeVisible}\n fileSystemAvailable={fileSystemOn || captureAvailable}\n editable={\n filesEditable && files.source === \"live\" && files.error === null && !files.loading\n }\n workspaceResting={\n !liveWorkspaceExpected &&\n liveness !== undefined &&\n !capturePending &&\n !captureAvailable &&\n !workspaceWaking\n }\n workspaceWaking={!liveWorkspaceExpected && !captureAvailable && workspaceWaking}\n liveWorkspaceReady={liveWorkspaceExpected}\n workspaceError={\n caps.error ??\n (caps.viewerCapReached\n ? new Error(\n \"The live workspace viewer limit has been reached. Close another viewer and retry.\",\n )\n : filesWarmRequested && caps.state === \"on-demand\" && !fileSystemOn\n ? new Error(\"This machine does not currently expose a live file system.\")\n : null)\n }\n onWakeWorkspace={() => {\n if (filesWarmRequested) caps.renegotiate();\n else requestWarmIntent(\"warmFiles\");\n }}\n {...(requestedFilePath\n ? {\n requestedPath: requestedFilePath,\n ...(requestedFileRequestId !== null && requestedFileRequestId !== undefined\n ? { requestedPathRequestId: requestedFileRequestId }\n : {}),\n requestedPathReady: sandboxAcceptsLiveIo(liveness),\n ...(requestedFileLine != null && requestedFileLine > 0\n ? { requestedLine: requestedFileLine }\n : {}),\n }\n : {})}\n // Ordinary capture browsing does not warm a box. The first edit — or an\n // explicit guarded-file open from Changes — is deliberate live-file intent.\n onEditIntent={() => requestWarmIntent(\"warmFiles\")}\n initialSelectedPath={initialFilePath}\n onSelectedPathChange={onFilePathChange}\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: WORKBENCH_TAB_TERMINAL,\n label: \"Terminal\",\n icon: <SquareTerminalIcon />,\n content: (\n <div className=\"h-full bg-og-bg p-1\">\n <SandboxTerminal\n key={sessionId}\n result={terminal}\n terminalCapability={capabilities?.Terminal ?? null}\n onActivate={() => requestWarmIntent(\"warmTerminal\")}\n onReconnectNeeded={caps.renegotiate}\n showHeader\n shell={capabilities?.Terminal.shell ?? undefined}\n liveness={liveness}\n {...(xtermTheme ? { theme: xtermTheme } : {})}\n />\n </div>\n ),\n });\n }\n\n // Browser — independent from sandbox capability negotiation. BrowserSessions\n // are workspace resources and may live in this agent's sandbox, a peer's\n // sandbox, a connected machine, or an external browser placement.\n if (browserEnabled) {\n list.push({\n id: WORKBENCH_TAB_BROWSER,\n label: \"Browser\",\n icon: <Globe2Icon />,\n content: (\n <Suspense fallback={<WorkbenchSurfaceLoading name=\"Browser\" />}>\n <LazyBrowserViewer\n key={sessionId}\n client={client}\n workspaceId={workspaceId}\n sessionId={sessionId}\n // WorkspaceDock mounts a heavy surface only after its first visit,\n // then keeps it mounted behind `hidden` when another tab is\n // selected. Keep that already-visited surface enabled while the\n // dock itself remains open: tearing down its controller + media\n // socket on every Browser↔Computer tab switch turned an ordinary\n // click into a multi-second cold reconnect. This does not eagerly\n // start BrowserViewer—the lazy panel is still unmounted until the\n // user/agent first visits it.\n enabled={workspaceVisible}\n onNotify={onNotify}\n initialBrowserSessionId={initialBrowserSessionId}\n onBrowserSessionIdChange={onBrowserSessionIdChange}\n {...(desktopEnabled ? { createLinkedComputer } : {})}\n {...(onOpenComputerSession ? { onOpenComputer: onOpenComputerSession } : {})}\n {...(browserWebSocketFactory ? { webSocketFactory: browserWebSocketFactory } : {})}\n {...(browserExtensionSetupUrl ? { browserExtensionSetupUrl } : {})}\n className=\"h-full\"\n />\n </Suspense>\n ),\n });\n }\n\n // Computer — stable legacy tab id, new workspace resource body. Like Browser,\n // it is independent from the selected agent's sandbox capability document.\n if (desktopEnabled) {\n list.push({\n id: WORKBENCH_TAB_DESKTOP,\n label: \"Desktop\",\n icon: <MonitorIcon />,\n content: (\n <Suspense fallback={<WorkbenchSurfaceLoading name=\"Desktop\" />}>\n <LazyComputerViewer\n key={sessionId}\n client={client}\n workspaceId={workspaceId}\n sessionId={sessionId}\n // Same visited-surface lifetime as Browser above. A live noVNC\n // connection survives tab switches and ResizeObserver re-fits its\n // canvas when this hidden panel becomes visible again, making the\n // second and later Computer opens local-machine fast.\n enabled={workspaceVisible}\n onNotify={onNotify}\n initialComputerSessionId={initialComputerSessionId}\n onComputerSessionIdChange={onComputerSessionIdChange}\n requestedComputerSessionId={requestedComputerSessionId}\n requestedComputerRequestId={requestedComputerRequestId}\n {...(computerWebSocketFactory ? { webSocketFactory: computerWebSocketFactory } : {})}\n className=\"h-full\"\n />\n </Suspense>\n ),\n });\n }\n\n return list;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n fileSystemOn,\n changesEnabled,\n filesEnabled,\n terminalOn,\n browserEnabled,\n desktopEnabled,\n captureAvailable,\n dirtyCount,\n warmTerminal,\n requestedFilePath,\n requestedFileRequestId,\n requestedFileLine,\n onOpenFile,\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n onOpenComputerSession,\n requestedComputerSessionId,\n requestedComputerRequestId,\n onNotify,\n browserWebSocketFactory,\n computerWebSocketFactory,\n workspaceVisible,\n resolvedActiveTab,\n client,\n workspaceId,\n liveness,\n sessionId,\n files,\n git,\n changesComparison,\n terminal,\n xtermTheme,\n capabilities,\n workspaceWaking,\n caps.state,\n caps.error,\n caps.viewerCapReached,\n caps.renegotiate,\n filesWarmRequested,\n requestWarmIntent,\n createLinkedComputer,\n ]);\n\n return {\n tabs,\n defaultTab,\n machine: {\n enabled: machineSurfaceEnabled,\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 /**\n * Built-in surfaces this host wants to expose. Omit for Changes, Files,\n * Terminal, Browser, and Desktop. Disabled surfaces remain behaviorally dormant.\n */\n surfaces?: readonly SandboxWorkspaceSurface[] | undefined;\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 from the durable workspace capture. */\n initialTab?: string | undefined;\n onActiveTabChange?: ((activeTab: string) => void) | undefined;\n initialFilePath?: string | null | undefined;\n onFilePathChange?: ((path: string | null) => void) | undefined;\n /** Presentation-only filter for Files tree nodes and selected-file viewing. */\n isFileNodeVisible?: FileNodeVisibilityPredicate | undefined;\n /**\n * Host request to open a workspace file (and optional line) in Files. A new\n * `requestId` re-opens even the same path.\n */\n openFileRequest?:\n | {\n path: string;\n line?: number | null;\n requestId: number;\n }\n | null\n | undefined;\n initialBrowserSessionId?: string | null | undefined;\n onBrowserSessionIdChange?: ((browserSessionId: string | null) => void) | undefined;\n initialComputerSessionId?: string | null | undefined;\n onComputerSessionIdChange?: ((computerSessionId: string | null) => void) | undefined;\n /** Host-routed notifications (no toast dependency in the package). */\n onNotify?: ((notification: WorkspaceNotification) => void) | undefined;\n /** Alternate Browser frame transport for non-browser runtimes and deterministic tests. */\n browserWebSocketFactory?: BrowserFrameWebSocketFactory | undefined;\n /** Alternate Computer frame transport for non-browser runtimes and deterministic tests. */\n computerWebSocketFactory?: ComputerFrameWebSocketFactory | undefined;\n /** Host-owned setup page or store listing for attaching an existing Chrome profile. */\n browserExtensionSetupUrl?: string | undefined;\n /** Controlled collapsed state for hosts with their own dock toggle. */\n collapsed?: boolean | undefined;\n onCollapsedChange?: ((collapsed: boolean) => void) | undefined;\n /** Keep the dock's built-in collapse control with controlled collapsed state. */\n showCollapseControl?: boolean | 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/compiled.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 surfaces,\n leadingTabs,\n trailingTabs,\n initialTab,\n onActiveTabChange,\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n openFileRequest,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n onNotify,\n browserWebSocketFactory,\n computerWebSocketFactory,\n browserExtensionSetupUrl,\n collapsed,\n onCollapsedChange,\n showCollapseControl,\n mobileLeadingControl,\n autoSaveId,\n defaultSize,\n minSize,\n maxSize,\n className,\n } = props;\n\n const [storedSelection, setStoredSelection] = useState<{\n sessionId: string;\n tab: string;\n } | null>(null);\n const [requestedFile, setRequestedFile] = useState<{\n sessionId: string;\n path: string;\n line: number | null;\n requestId: number;\n } | null>(null);\n const [requestedComputer, setRequestedComputer] = useState<{\n sessionId: string;\n computerSessionId: string;\n requestId: number;\n } | null>(null);\n const nextFileRequestId = useRef(0);\n const nextComputerRequestId = useRef(0);\n const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;\n const activeTabHint = selectedTab ?? initialTab ?? leadingTabs?.[0]?.id ?? null;\n const openFile = useCallback(\n (path: string, line?: number | null) => {\n setRequestedFile({\n sessionId,\n path,\n line: line != null && line > 0 ? line : null,\n requestId: ++nextFileRequestId.current,\n });\n setStoredSelection({ sessionId, tab: WORKBENCH_TAB_FILES });\n onActiveTabChange?.(WORKBENCH_TAB_FILES);\n onFilePathChange?.(path);\n onCollapsedChange?.(false);\n },\n [onActiveTabChange, onCollapsedChange, onFilePathChange, sessionId],\n );\n const handledOpenFileRequestId = useRef<number | null>(null);\n useEffect(() => {\n if (!openFileRequest) return;\n if (handledOpenFileRequestId.current === openFileRequest.requestId) return;\n handledOpenFileRequestId.current = openFileRequest.requestId;\n openFile(openFileRequest.path, openFileRequest.line);\n }, [openFile, openFileRequest]);\n const openComputer = useCallback(\n (computerSessionId: string) => {\n nextComputerRequestId.current += 1;\n setRequestedComputer({\n sessionId,\n computerSessionId,\n requestId: nextComputerRequestId.current,\n });\n setStoredSelection({ sessionId, tab: WORKBENCH_TAB_DESKTOP });\n onActiveTabChange?.(WORKBENCH_TAB_DESKTOP);\n onComputerSessionIdChange?.(computerSessionId);\n },\n [onActiveTabChange, onComputerSessionIdChange, sessionId],\n );\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 ...(surfaces ? { surfaces } : {}),\n ...(initialTab ? { initialTab } : {}),\n activeTab: activeTabHint,\n workspaceVisible: collapsed !== true,\n ...(onNotify ? { onNotify } : {}),\n ...(browserWebSocketFactory ? { browserWebSocketFactory } : {}),\n ...(computerWebSocketFactory ? { computerWebSocketFactory } : {}),\n ...(browserExtensionSetupUrl ? { browserExtensionSetupUrl } : {}),\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n requestedFilePath: requestedFile?.sessionId === sessionId ? requestedFile.path : null,\n requestedFileRequestId: requestedFile?.sessionId === sessionId ? requestedFile.requestId : null,\n requestedFileLine: requestedFile?.sessionId === sessionId ? requestedFile.line : null,\n onOpenFile: openFile,\n onOpenComputerSession: openComputer,\n requestedComputerSessionId:\n requestedComputer?.sessionId === sessionId ? requestedComputer.computerSessionId : null,\n requestedComputerRequestId:\n requestedComputer?.sessionId === sessionId ? requestedComputer.requestId : null,\n });\n\n // A user's tab click wins forever; before that we follow the source-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 preferredTab = selectedTab ?? defaultTab;\n const activeTab =\n preferredTab && tabs.some((tab) => tab.id === preferredTab) ? preferredTab : tabs[0]?.id;\n const selectTab = useCallback(\n (tab: string) => {\n setStoredSelection({ sessionId, tab });\n onActiveTabChange?.(tab);\n },\n [onActiveTabChange, sessionId],\n );\n useEffect(() => {\n if (selectedTab !== null || defaultTab === null) return;\n // Once the source-driven choice resolves, make it the real controlled\n // selection. Without this handoff the dock could visibly show Files while\n // the data hooks continued treating the selection as unresolved.\n setStoredSelection({ sessionId, tab: defaultTab });\n }, [defaultTab, selectedTab, sessionId]);\n\n return (\n <WorkspaceDock\n primary={primary}\n tabs={tabs}\n {...(activeTab !== undefined ? { activeTab } : {})}\n onActiveTabChange={selectTab}\n {...(machine.enabled\n ? {\n headerAccessory: <MachineStateChip chip={machine.chip} />,\n }\n : {})}\n {...(mobileLeadingControl !== undefined ? { mobileLeadingControl } : {})}\n {...(collapsed !== undefined ? { collapsed } : {})}\n {...(onCollapsedChange ? { onCollapsedChange } : {})}\n {...(showCollapseControl !== undefined ? { showCollapseControl } : {})}\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-og-xs text-og-fg-muted\">\n {count}\n </span>\n );\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 motion-reduce:animate-none\";\n return \"bg-og-fg-subtle\";\n}\n\n/**\n * The dock-header machine status: one quiet, truthful live/waking/resting\n * indicator. It is intentionally not interactive; detailed machine controls do\n * not belong in a transient popover above the workspace tabs.\n */\nfunction MachineStateChip({ chip }: { chip: MachineChip }) {\n return (\n <div\n role=\"status\"\n aria-label={`Machine: ${chip.label}`}\n className=\"inline-flex min-h-7 min-w-0 items-center gap-1.5 px-2 py-1 text-og-xs font-medium text-og-fg-muted 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=\"min-w-0 max-w-[11rem] truncate\">{chip.label}</span>\n </div>\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 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11\"\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 comparison,\n onComparisonChange,\n ...props\n}: {\n comparison: SandboxGitComparison;\n onComparisonChange: (comparison: SandboxGitComparison) => void;\n} & Parameters<typeof ChangesTabContent>[0]) {\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <div className=\"flex shrink-0 items-center gap-1 border-b border-og-border bg-og-surface-1 px-2 py-1.5\">\n {(\n [\n [\"branch\", \"Branch\"],\n [\"working\", \"Uncommitted\"],\n [\"staged\", \"Staged\"],\n ] as const\n ).map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n aria-pressed={comparison === value}\n onClick={() => onComparisonChange(value)}\n className={cn(\n \"rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11\",\n comparison === value\n ? \"bg-og-surface-2 text-og-fg shadow-sm\"\n : \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\",\n )}\n >\n {label}\n </button>\n ))}\n </div>\n <div className=\"min-h-0 flex-1\">\n <ChangesTabContent comparison={comparison} {...props} />\n </div>\n </div>\n );\n}\n\nfunction ChangesTabContent({\n git,\n comparison,\n captureAvailable,\n captureRevision,\n capturePending,\n liveWorkspaceExpected,\n workspaceWaking,\n capabilitiesState,\n capabilitiesError,\n onRetry,\n onWake,\n onOpenFile,\n}: {\n git: UseSandboxGitResult;\n comparison: SandboxGitComparison;\n captureAvailable: boolean;\n captureRevision: number | null;\n capturePending: boolean;\n liveWorkspaceExpected: boolean;\n workspaceWaking: boolean;\n capabilitiesState: string;\n capabilitiesError: Error | null;\n onRetry: () => void;\n onWake: () => void;\n onOpenFile?: ((path: string) => void) | undefined;\n}) {\n const diff = git.diff;\n\n if (diff.length > 0) {\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n {git.error ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n data-opengeni-changes-degraded\n className=\"flex shrink-0 items-center gap-2 border-b border-og-status-running/30 bg-og-status-running/10 px-2 py-1.5 text-og-xs text-og-fg-muted\"\n >\n <TriangleAlertIcon className=\"size-3.5 shrink-0 text-og-status-running\" aria-hidden />\n <span className=\"min-w-0 flex-1\">\n {git.source === \"capture\"\n ? \"Live changes are temporarily unavailable. Showing the latest captured revision.\"\n : \"Live refresh failed. Showing the last loaded changes.\"}\n </span>\n <button\n type=\"button\"\n onClick={() => void git.refresh()}\n disabled={git.loading}\n className=\"inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n <RefreshCwIcon\n className={cn(\"size-3\", git.loading && \"animate-spin motion-reduce:animate-none\")}\n aria-hidden\n />\n Retry\n </button>\n </div>\n ) : null}\n <div className=\"min-h-0 flex-1\">\n <WorkbenchChanges\n diff={diff}\n source={git.source}\n capturedAt={git.capturedAt}\n captureRevision={captureRevision}\n {...(onOpenFile ? { onOpenFile } : {})}\n />\n </div>\n </div>\n );\n }\n\n if (capabilitiesError && !captureAvailable) {\n return (\n <CenteredState icon={<TriangleAlertIcon className=\"size-5\" aria-hidden />} tone=\"danger\">\n <p className=\"text-og-sm font-medium text-og-fg\">Sandbox unavailable</p>\n <p data-contrast-audited 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 (\n (capturePending || capabilitiesState === \"negotiating\") &&\n !captureAvailable &&\n !workspaceWaking\n ) {\n return (\n <CenteredState\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">Connecting workspace</p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">\n Looking for the latest files and changes…\n </p>\n </CenteredState>\n );\n }\n\n if (!liveWorkspaceExpected && (comparison !== \"working\" || !captureAvailable)) {\n return (\n <CenteredState\n icon={\n workspaceWaking ? (\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n ) : (\n <CpuIcon className=\"size-5\" aria-hidden />\n )\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">\n {workspaceWaking ? \"Waking workspace\" : \"Workspace is resting\"}\n </p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">\n {workspaceWaking\n ? \"Connecting to the live working tree…\"\n : comparison === \"branch\"\n ? \"Wake the sandbox to compare this branch with the remote default branch.\"\n : comparison === \"staged\"\n ? \"Wake the sandbox to inspect staged changes.\"\n : \"No captured revision is available yet. Wake the sandbox to inspect uncommitted changes.\"}\n </p>\n {!workspaceWaking ? (\n <DockActionButton onClick={onWake}>\n <CpuIcon className=\"size-3\" />\n Open live workspace\n </DockActionButton>\n ) : null}\n </CenteredState>\n );\n }\n\n if (git.loading && git.source === null) {\n return (\n <CenteredState\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">Loading workspace</p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">Reading the current working tree…</p>\n </CenteredState>\n );\n }\n\n return (\n <CenteredState icon={<CircleCheckIcon className=\"size-5\" aria-hidden />} tone=\"success\">\n <p className=\"text-og-sm font-medium text-og-fg\">\n {comparison === \"branch\"\n ? \"No branch changes\"\n : comparison === \"staged\"\n ? \"No staged changes\"\n : \"No uncommitted changes\"}\n </p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">\n {comparison === \"branch\"\n ? \"This branch matches the remote default branch.\"\n : comparison === \"staged\"\n ? \"Stage files to review the next commit here.\"\n : \"Local edits not yet committed will appear here.\"}\n </p>\n </CenteredState>\n );\n}\n\nfunction CenteredState({\n children,\n icon,\n tone = \"neutral\",\n}: {\n children: ReactNode;\n icon?: ReactNode | undefined;\n tone?: \"neutral\" | \"success\" | \"danger\";\n}) {\n return (\n <div\n role={tone === \"danger\" ? \"alert\" : \"status\"}\n aria-atomic=\"true\"\n aria-live={tone === \"danger\" ? \"assertive\" : \"polite\"}\n className=\"grid h-full place-items-center p-6 text-center\"\n >\n <div className=\"flex max-w-sm flex-col items-center gap-2.5\">\n {icon ? (\n <span\n className={cn(\n \"grid size-10 place-items-center rounded-og-lg border bg-og-surface-1 shadow-sm\",\n tone === \"success\" && \"border-og-status-idle/30 text-og-status-idle\",\n tone === \"danger\" && \"border-og-status-failed/30 text-og-status-failed\",\n tone === \"neutral\" && \"border-og-border text-og-fg-muted\",\n )}\n >\n {icon}\n </span>\n ) : null}\n {children}\n </div>\n </div>\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\";\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: \"sharded\",\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` 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 // Refresh only after the durable post-selection event. `turn.started` is\n // emitted before account selection settles and races this authoritative read.\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","import type { SuperGrokAccount, SuperGrokAccountsResponse } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\n\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type SuperGrokAccountsClientLike = {\n listSuperGrokAccounts: (workspaceId: string) => Promise<SuperGrokAccountsResponse>;\n activateSuperGrokAccount?: (\n workspaceId: string,\n accountId: string,\n ) => Promise<{ activated: boolean; accountId: string }>;\n};\n\nexport type UseSuperGrokAccountsOptions = ClientOverride & {\n enabled?: boolean | undefined;\n pollIntervalMs?: number | undefined;\n supergrokClient?: SuperGrokAccountsClientLike | undefined;\n};\n\nexport type UseSuperGrokAccountsResult = {\n accounts: SuperGrokAccount[];\n activeAccountId: string | null;\n settings: SuperGrokAccountsResponse[\"settings\"];\n loading: boolean;\n refresh: () => Promise<void>;\n activate: (accountId: string) => Promise<boolean>;\n activating: boolean;\n mutationError: Error | null;\n};\n\nconst EMPTY: SuperGrokAccountsResponse = {\n accounts: [],\n activeAccountId: null,\n settings: {\n rotationEnabled: false,\n rotationStrategy: \"sharded\",\n activeCredentialId: null,\n },\n};\n\n/** Workspace-visible xAI accounts. Workspace scope is the connection default. */\nexport function useSuperGrokAccounts(\n options: UseSuperGrokAccountsOptions = {},\n): UseSuperGrokAccountsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const supergrokClient =\n options.supergrokClient ?? (client as unknown as SuperGrokAccountsClientLike);\n const load = useCallback(\n async () => await supergrokClient.listSuperGrokAccounts(workspaceId),\n [supergrokClient, workspaceId],\n );\n const { data, loading, refresh } = usePolledValue(load, {\n enabled: options.enabled,\n pollIntervalMs: options.pollIntervalMs,\n });\n const { run, mutating: activating, mutationError } = useMutationRunner();\n const activate = useCallback(\n async (accountId: string): Promise<boolean> => {\n if (!supergrokClient.activateSuperGrokAccount) return false;\n const result = await run(async () => {\n await supergrokClient.activateSuperGrokAccount!(workspaceId, accountId);\n return true;\n });\n if (result) await refresh();\n return result === true;\n },\n [refresh, run, supergrokClient, workspaceId],\n );\n const state = data ?? EMPTY;\n return {\n accounts: state.accounts,\n activeAccountId: state.activeAccountId,\n settings: state.settings,\n loading,\n refresh,\n activate,\n activating,\n mutationError,\n };\n}\n"],"mappings":"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","names":["useCallback","useCallback","useCallback","useEffect","useEffect","useCallback","page","useCallback","useEffect","useRef","useCallback","useRef","useEffect","useCallback","useMemo","useCallback","useMemo","useCallback","useMemo","useMemo","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useEffect","useRef","useRef","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useEffect","useCallback","useMemo","OpenGeniApiError","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useEffect","useMemo","OpenGeniApiError","useCallback","useCallback","useEffect","useMemo","useRef","useState","useMemo","isLive","useRef","useState","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","normalizeRoot","useMemo","isLive","useRef","useState","useCallback","roots","useEffect","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","useMemo","useState","useRef","useEffect","useCallback","useMemo","useMemo","useEffect","useRef","useState","useState","useRef","useEffect","jsx","jsxs","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useCallback","useEffect","useId","useLayoutEffect","useMemo","useRef","useState","useEffect","useMemo","useMemo","useEffect","Fragment","jsx","jsxs","useEffect","useLayoutEffect","parentOf","pathIsInsideDirectory","useState","useRef","useId","useCallback","useMemo","item","useCallback","useEffect","useId","useLayoutEffect","useMemo","useRef","useState","VList","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useEffect","useLayoutEffect","STATUS_TINT","VList","useRef","useState","useId","useMemo","useCallback","jsx","useEffect","useState","jsx","useState","useEffect","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useCallback","useMemo","FileWarningIcon","useCallback","useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","FileWarningIcon","useCallback","useEffect","useId","useLayoutEffect","useRef","useState","XIcon","Group","Panel","Separator","Fragment","jsx","jsxs","useEffect","useLayoutEffect","useState","useRef","useCallback","frame","XIcon","Group","Panel","Separator","useId","lazy","Suspense","useCallback","useEffect","useMemo","useRef","useState","FileCode2Icon","LoaderCircleIcon","RefreshCwIcon","TriangleAlertIcon","jsx","jsxs","lazy","LoaderCircleIcon","useCallback","useState","useRef","useEffect","useMemo","FileCode2Icon","Suspense","TriangleAlertIcon","RefreshCwIcon","useCallback","useState","useCallback","useState","useCallback","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-video-artifact-playback.ts","../src/file-node-visibility.ts","../src/hooks/use-last-started-turn-policy.ts","../src/hooks/use-scheduled-tasks.ts","../src/hooks/use-workspace-sessions.ts","../src/hooks/use-session-background-commands.ts","../src/hooks/use-environments.ts","../src/hooks/use-channels.ts","../src/hooks/channel-cache.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-session-capabilities.ts","../src/lib/sandbox-liveness.ts","../src/lib/terminal-capability.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/components/approval-surface.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/lib/use-unicode-fonts.ts","../src/components/workbench-changes.tsx","../src/hooks/use-windowed-sections.ts","../src/components/diff-view.tsx","../src/components/pierre-file.tsx","../src/components/code-editor.tsx","../src/components/sandbox-files.tsx","../src/components/workspace-dock.tsx","../src/components/sandbox-workspace.tsx","../src/hooks/use-codex-accounts.ts","../src/hooks/use-supergrok-accounts.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { VideoArtifactPlaybackLoader } from \"../timeline\";\nimport { useOpenGeni, type ClientOverride } from \"../session-context\";\n\n/**\n * Bind the current public SDK client/workspace to MessageTimeline's renewable\n * video-source boundary. Proxy hosts may omit the method until they support\n * retained video; the failure remains local to the player instead of loading\n * any video bytes through React.\n */\nexport function useVideoArtifactPlaybackLoader(\n options: ClientOverride = {},\n): VideoArtifactPlaybackLoader {\n const { client, workspaceId } = useOpenGeni(options);\n return useMemo(\n () => async (artifactId: string, signal?: AbortSignal) => {\n if (typeof client.createVideoArtifactPlaybackSource !== \"function\") {\n throw new Error(\"This OpenGeni host does not expose retained-video playback.\");\n }\n return await client.createVideoArtifactPlaybackSource(\n workspaceId,\n artifactId,\n signal ? { signal } : {},\n );\n },\n [client, workspaceId],\n );\n}\n","import type { FileTreeNode } from \"./hooks/use-sandbox-files\";\n\nexport type FileNodeVisibilityContext = {\n depth: number;\n parent: FileTreeNode | null;\n};\n\n/** Presentation-only predicate. It never changes filesystem authorization. */\nexport type FileNodeVisibilityPredicate = (\n node: FileTreeNode,\n context: FileNodeVisibilityContext,\n) => boolean;\n\nexport type FilePathVisibility = \"visible\" | \"hidden\" | \"unknown\";\n\nfunction pathIsInsideDirectory(path: string, directory: string): boolean {\n if (!path.startsWith(directory) || path === directory) return false;\n if (directory.endsWith(\"/\") || directory.endsWith(\"\\\\\")) return true;\n const boundary = path[directory.length];\n return boundary === \"/\" || boundary === \"\\\\\";\n}\n\n/**\n * Filter an authoritative tree without promoting children of a hidden parent.\n * Undefined children stay undefined so lazy-loading semantics are preserved.\n */\nexport function visibleFileTree(\n nodes: FileTreeNode[],\n predicate?: FileNodeVisibilityPredicate,\n parent: FileTreeNode | null = null,\n depth = 0,\n): FileTreeNode[] {\n if (!predicate) return nodes;\n const visible: FileTreeNode[] = [];\n for (const node of nodes) {\n if (!predicate(node, { depth, parent })) continue;\n visible.push(\n node.children === undefined\n ? node\n : {\n ...node,\n children: visibleFileTree(node.children, predicate, node, depth + 1),\n },\n );\n }\n return visible;\n}\n\n/** Resolve only what the currently loaded tree can prove. */\nexport function filePathVisibility(\n nodes: FileTreeNode[],\n path: string,\n predicate?: FileNodeVisibilityPredicate,\n parent: FileTreeNode | null = null,\n depth = 0,\n): FilePathVisibility {\n if (!predicate) return \"visible\";\n for (const node of nodes) {\n if (node.path !== path && !pathIsInsideDirectory(path, node.path)) continue;\n if (!predicate(node, { depth, parent })) return \"hidden\";\n if (node.path === path) return \"visible\";\n if (node.kind !== \"dir\" || node.children === undefined) return \"unknown\";\n return filePathVisibility(node.children, path, predicate, node, depth + 1);\n }\n return \"unknown\";\n}\n","import type { LatencyMode, ReasoningEffort, SessionEvent, SessionTurn } from \"@opengeni/sdk\";\nimport { useCallback, useEffect } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../session-context\";\nimport { usePolledValue, useSessionEventTrigger, type SessionEventFeedOptions } from \"./internal\";\n\n/** Refresh when a turn actually admits — not on composer picker / queue-only changes. */\nexport function isLastStartedTurnPolicyEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type === \"turn.started\";\n}\n\nexport type LastStartedTurnPolicy = {\n model: string;\n reasoningEffort: ReasoningEffort;\n latencyMode: LatencyMode;\n turnId: string;\n};\n\nexport type UseLastStartedTurnPolicyOptions = ClientOverride &\n SessionEventFeedOptions & {\n pollIntervalMs?: number | undefined;\n };\n\nexport type UseLastStartedTurnPolicyResult = {\n /** Null until some turn has durably emitted `turn.started`. */\n policy: LastStartedTurnPolicy | null;\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n};\n\nfunction policyFromTurn(turn: SessionTurn | null | undefined): LastStartedTurnPolicy | null {\n if (!turn) return null;\n return {\n model: turn.model,\n reasoningEffort: turn.reasoningEffort,\n latencyMode: turn.latencyMode,\n turnId: turn.id,\n };\n}\n\n/**\n * Model·effort·latency of the newest admitted turn (`turn.started`). This is\n * historical runtime truth for the session header — not the composer next-turn\n * picker and not the frozen session creation defaults.\n */\nexport function useLastStartedTurnPolicy(\n sessionId: string | null | undefined,\n options: UseLastStartedTurnPolicyOptions = {},\n): UseLastStartedTurnPolicyResult {\n const { client, workspaceId, workspaceControlEvent, registerSessionReconciler } =\n useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n\n const load = useCallback(\n async (signal?: AbortSignal): Promise<LastStartedTurnPolicy | null> => {\n if (!sessionId) return null;\n const turns = await client.listTurns(workspaceId, sessionId, {\n latestStarted: true,\n signal,\n });\n return policyFromTurn(turns[0]);\n },\n [client, workspaceId, sessionId],\n );\n\n const { data, loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled,\n });\n\n useEffect(() => {\n if (enabled && workspaceControlEvent) void refresh();\n }, [enabled, refresh, workspaceControlEvent]);\n\n useEffect(() => {\n if (!sessionId || !enabled) return;\n return registerSessionReconciler(sessionId, \"last-started-turn-policy\", refresh);\n }, [enabled, refresh, registerSessionReconciler, sessionId]);\n\n // Shared-feed only: the session header lives outside the route event log and\n // must not open a second SSE. Without `events`, rely on the initial fetch +\n // optional poll / workspace-control / reconciler.\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isLastStartedTurnPolicyEvent,\n () => void refresh(),\n {\n events: options.events,\n enabled: enabled && options.events !== undefined,\n },\n );\n\n return {\n policy: enabled ? data : null,\n loading,\n error,\n refresh,\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, useEffect, useRef } 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 /** Return only the complete personal pinned projection. */\n pinsOnly?: boolean | undefined;\n archivedOnly?: boolean | undefined;\n /** Refresh interval (ms) for fleet/manager views. Off by default. */\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n /** Optional shared causal clock invoked when each network read starts. */\n beginRead?: (() => number) | 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 /** True when the server omitted older pins from its bounded pinned section. */\n pinnedTruncated: boolean;\n nextCursor: string | null;\n loading: boolean;\n error: Error | null;\n /** Monotonic revision of accepted authoritative list-page reads. */\n readRevision: number;\n /** Causal generation captured when the accepted network read started. */\n readGeneration: number;\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 pinsOnly = options.pinsOnly;\n const archivedOnly = options.archivedOnly;\n const enabled = options.enabled ?? true;\n const nextReadRevision = useRef(0);\n const nextReadGeneration = useRef(0);\n const beginRead = options.beginRead;\n const queryKey = [\n workspaceId,\n limit ?? \"\",\n parentSessionId === null ? \"null\" : (parentSessionId ?? \"\"),\n cursor ?? \"\",\n search ?? \"\",\n pinsOnly ? \"1\" : \"\",\n archivedOnly ? \"archived\" : \"active\",\n ].join(\"\\u0000\");\n const previousQueryKey = useRef(queryKey);\n const queryKeyTransition = previousQueryKey.current !== queryKey;\n useEffect(() => {\n previousQueryKey.current = queryKey;\n }, [queryKey]);\n const load = useCallback(\n async (signal?: AbortSignal) => {\n const readGeneration = beginRead?.() ?? ++nextReadGeneration.current;\n const page = await client.listSessionPage(workspaceId, {\n ...(limit !== undefined ? { limit } : {}),\n ...(parentSessionId !== undefined ? { parentSessionId } : {}),\n ...(cursor !== undefined ? { cursor } : {}),\n ...(search !== undefined ? { search } : {}),\n ...(pinsOnly ? { pinsOnly: true } : {}),\n ...(archivedOnly ? { archivedOnly: true } : {}),\n signal,\n });\n return {\n queryKey,\n page,\n revision: ++nextReadRevision.current,\n readGeneration,\n };\n },\n [\n beginRead,\n client,\n workspaceId,\n limit,\n parentSessionId,\n cursor,\n search,\n pinsOnly,\n archivedOnly,\n queryKey,\n ],\n );\n const state = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n 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 pinnedTruncated: page?.pinnedTruncated ?? false,\n nextCursor: page?.nextCursor ?? null,\n // `usePolledValue` clears the old data and starts the new request in an\n // effect. During that query-key transition render, its old loading flag\n // can still be false; expose loading immediately so consumers do not\n // announce a transient false zero-match result.\n loading:\n enabled &&\n (state.loading ||\n queryKeyTransition ||\n (state.data !== null && state.data.queryKey !== queryKey)),\n error: state.error,\n readRevision: page ? (state.data?.revision ?? 0) : 0,\n readGeneration: page ? (state.data?.readGeneration ?? 0) : 0,\n refresh: state.refresh,\n };\n}\n","import type { SessionBackgroundCommand } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useRef } from \"react\";\n\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { usePolledValue } from \"./internal\";\n\nexport type UseSessionBackgroundCommandsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseSessionBackgroundCommandsResult = {\n commands: SessionBackgroundCommand[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n cancel: (commandId: string) => Promise<void>;\n};\n\nexport function useSessionBackgroundCommands(\n sessionId: string | null | undefined,\n options: UseSessionBackgroundCommandsOptions = {},\n): UseSessionBackgroundCommandsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const enabled = (options.enabled ?? true) && Boolean(sessionId);\n const load = useCallback(\n async (signal?: AbortSignal) => {\n if (!sessionId) return { commands: [] };\n if (!client.listSessionBackgroundCommands) {\n throw new Error(\"The configured OpenGeni client does not support background commands\");\n }\n return await client.listSessionBackgroundCommands(workspaceId, sessionId, { signal });\n },\n [client, workspaceId, sessionId],\n );\n const state = usePolledValue(load, {\n enabled,\n pollIntervalMs: options.pollIntervalMs,\n });\n const refresh = state.refresh;\n const generation = useRef(0);\n useEffect(() => {\n generation.current += 1;\n return () => {\n generation.current += 1;\n };\n }, [client, workspaceId, sessionId, enabled]);\n const cancel = useCallback(\n async (commandId: string): Promise<void> => {\n if (!sessionId) return;\n if (!client.cancelSessionBackgroundCommand) {\n throw new Error(\"The configured OpenGeni client does not support background commands\");\n }\n const ticket = generation.current;\n await client.cancelSessionBackgroundCommand(workspaceId, sessionId, commandId);\n if (enabled && ticket === generation.current) await refresh();\n },\n [client, workspaceId, sessionId, refresh, enabled],\n );\n return {\n commands: state.data?.commands ?? [],\n loading: state.loading,\n error: state.error,\n refresh,\n cancel,\n };\n}\n","import type {\n CreateVariableSetRequest,\n UpdateVariableSetRequest,\n VariableSet,\n VariableSetSecret,\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 /**\n * Read one exact value through the dedicated permissioned API. The hook never\n * puts plaintext in its polled variable-set cache.\n */\n readVariable: (variableSetId: string, name: string) => Promise<VariableSetSecret | null>;\n /** Set/rotate a variable. Generic 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). Generic reads stay metadata-only. A dedicated,\n * permissioned method can retrieve one value and returns it directly without\n * adding plaintext to hook state or polling caches.\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 readVariable = useCallback(\n async (variableSetId: string, name: string): Promise<VariableSetSecret | null> =>\n await run(() => client.getVariableSetVariable(workspaceId, variableSetId, name)),\n [client, workspaceId, run],\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 readVariable,\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 & {\n environments: VariableSet[];\n};\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({\n ...options,\n ...(legacyClient ? { client: legacyClient } : {}),\n });\n return { ...result, environments: result.variableSets };\n}\n","import type { Channel, CreateChannelRequest, Session, UpdateChannelRequest } from \"@opengeni/sdk\";\nimport { useCallback, useMemo, useSyncExternalStore } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { channelCacheFor } from \"./channel-cache\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type UseChannelsOptions = ClientOverride & {\n pollIntervalMs?: number | undefined;\n enabled?: boolean | undefined;\n};\n\nexport type UseChannelsResult = {\n channels: Channel[];\n loading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n create: (request: CreateChannelRequest) => Promise<Channel | null>;\n update: (channelId: string, request: UpdateChannelRequest) => Promise<Channel | null>;\n reorder: (channelIds: string[]) => Promise<Channel[] | null>;\n remove: (channelId: string) => Promise<boolean>;\n /** Re-file a session into a channel; null moves it back to the inbox. */\n moveSession: (sessionId: string, channelId: string | null) => Promise<Session | null>;\n mutating: boolean;\n mutationError: Error | null;\n clearMutationError: () => void;\n};\n\n/**\n * Workspace-shared channels: rail organization for root sessions\n * (\"workstreams\") by work type. Pure metadata — filing a session into a\n * channel never affects execution.\n */\nexport function useChannels(options: UseChannelsOptions = {}): UseChannelsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const cache = useMemo(() => channelCacheFor(client, workspaceId), [client, workspaceId]);\n const snapshot = useSyncExternalStore(cache.subscribe, cache.getSnapshot, cache.getSnapshot);\n const load = useCallback(async () => {\n const ticket = cache.beginLoad();\n const channels = await client.listChannels(workspaceId);\n cache.acceptLoad(ticket, channels);\n return channels;\n }, [cache, client, workspaceId]);\n const { loading, error, refresh } = usePolledValue(load, {\n pollIntervalMs: options.pollIntervalMs,\n enabled: options.enabled,\n });\n const { run, mutating, mutationError, clearMutationError } = useMutationRunner(cache);\n\n const create = useCallback(\n async (request: CreateChannelRequest): Promise<Channel | null> => {\n const result = await run(() => client.createChannel(workspaceId, request));\n if (result) {\n // Publish the canonical write response before this promise can resolve.\n // The composer may create a session with this id immediately, while a\n // sibling rail hook could still have an older list request in flight.\n cache.publishCreated(result);\n await refresh();\n }\n return result;\n },\n [cache, client, workspaceId, run, refresh],\n );\n\n const update = useCallback(\n async (channelId: string, request: UpdateChannelRequest): Promise<Channel | null> => {\n const result = await run(() => client.updateChannel(workspaceId, channelId, 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 (channelId: string): Promise<boolean> => {\n const result = await run(async () => {\n await client.deleteChannel(workspaceId, channelId);\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 reorder = useCallback(\n async (channelIds: string[]): Promise<Channel[] | null> => {\n const result = await run(() => client.reorderChannels(workspaceId, { channelIds }));\n if (result) await refresh();\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const moveSession = useCallback(\n async (sessionId: string, channelId: string | null): Promise<Session | null> => {\n return await run(() => client.updateSessionChannel(workspaceId, sessionId, { channelId }));\n },\n [client, workspaceId, run],\n );\n\n return {\n // Cache snapshots replace arrays instead of mutating them, so preserve the\n // stable reference expected from the previous polled-value implementation.\n channels: snapshot.channels as Channel[],\n loading: loading && !snapshot.ready,\n error,\n refresh,\n create,\n update,\n reorder,\n remove,\n moveSession,\n mutating,\n mutationError,\n clearMutationError,\n };\n}\n","import type { Channel } from \"@opengeni/sdk\";\nimport type { SessionClientLike } from \"../client\";\n\ntype PendingChannel = { channel: Channel; committedAfterLoad: number };\n\nexport type ChannelCacheSnapshot = Readonly<{\n channels: readonly Channel[];\n ready: boolean;\n}>;\n\nexport type ChannelCacheStore = Readonly<{\n getSnapshot: () => ChannelCacheSnapshot;\n subscribe: (listener: () => void) => () => void;\n beginLoad: () => number;\n acceptLoad: (ticket: number, channels: readonly Channel[]) => void;\n publishCreated: (channel: Channel) => void;\n}>;\n\nconst EMPTY_CHANNELS: readonly Channel[] = [];\nconst EMPTY_SNAPSHOT: ChannelCacheSnapshot = {\n channels: EMPTY_CHANNELS,\n ready: false,\n};\nconst channelCaches = new WeakMap<object, Map<string, ChannelCacheStore>>();\n\nfunction compareChannels(left: Channel, right: Channel): number {\n return (\n Number(right.pinned) - Number(left.pinned) ||\n left.sortOrder - right.sortOrder ||\n left.id.localeCompare(right.id)\n );\n}\n\nfunction orderedChannels(channels: readonly Channel[]): Channel[] {\n return [...channels].sort(compareChannels);\n}\n\nfunction upsertChannel(channels: readonly Channel[], channel: Channel): Channel[] {\n const next = channels.filter((candidate) => candidate.id !== channel.id);\n next.push(channel);\n return orderedChannels(next);\n}\n\n/**\n * One client/workspace cache shared by every useChannels consumer.\n *\n * List reads are ticketed so an older request cannot erase a newer result.\n * A successful create remains layered over the latest server snapshot until a\n * list request that started after that success reconciles it. Requests already\n * in flight cannot make the project disappear between create and session start.\n */\nexport function createChannelCacheStore(): ChannelCacheStore {\n let base: readonly Channel[] | null = null;\n let snapshot = EMPTY_SNAPSHOT;\n let nextLoadTicket = 0;\n let acceptedLoadTicket = 0;\n const pending = new Map<string, PendingChannel>();\n const listeners = new Set<() => void>();\n\n const publish = () => {\n let channels = base ?? EMPTY_CHANNELS;\n for (const { channel } of pending.values()) {\n channels = upsertChannel(channels, channel);\n }\n snapshot = { channels, ready: base !== null || pending.size > 0 };\n for (const listener of listeners) listener();\n };\n\n return {\n getSnapshot: () => snapshot,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n beginLoad: () => ++nextLoadTicket,\n acceptLoad: (ticket, channels) => {\n if (ticket < acceptedLoadTicket) return;\n acceptedLoadTicket = ticket;\n base = orderedChannels(channels);\n for (const [id, created] of pending) {\n if (ticket > created.committedAfterLoad) pending.delete(id);\n }\n publish();\n },\n publishCreated: (channel) => {\n pending.set(channel.id, { channel, committedAfterLoad: nextLoadTicket });\n publish();\n },\n };\n}\n\nexport function channelCacheFor(client: SessionClientLike, workspaceId: string): ChannelCacheStore {\n let byWorkspace = channelCaches.get(client);\n if (!byWorkspace) {\n byWorkspace = new Map();\n channelCaches.set(client, byWorkspace);\n }\n let cache = byWorkspace.get(workspaceId);\n if (!cache) {\n cache = createChannelCacheStore();\n byWorkspace.set(workspaceId, cache);\n }\n return cache;\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 InstallPackRequest,\n PackInstallationPreview,\n PackInstallation,\n PackUninstallPreview,\n PreviewPackInstallationRequest,\n RegisterCapabilityPackRequest,\n UninstallPackRequest,\n UninstallPackResult,\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 /** @deprecated Use previewInstallation + install for component/Rig-aware Packs. */\n enable: (packId: string, request?: EnablePackRequest) => Promise<PackInstallation | null>;\n previewInstallation: (\n packId: string,\n request?: PreviewPackInstallationRequest,\n ) => Promise<PackInstallationPreview | null>;\n install: (packId: string, request: InstallPackRequest) => Promise<PackInstallation | null>;\n previewUninstall: (packId: string) => Promise<PackUninstallPreview | null>;\n uninstall: (packId: string, request: UninstallPackRequest) => Promise<UninstallPackResult | 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 previewInstallation = useCallback(\n async (\n packId: string,\n request: PreviewPackInstallationRequest = {},\n ): Promise<PackInstallationPreview | null> =>\n await run(() => client.previewPackInstallation(workspaceId, packId, request)),\n [client, workspaceId, run],\n );\n\n const install = useCallback(\n async (packId: string, request: InstallPackRequest): Promise<PackInstallation | null> => {\n const result = await run(() => client.installPack(workspaceId, packId, request));\n if (result) await refresh();\n return result;\n },\n [client, workspaceId, run, refresh],\n );\n\n const previewUninstall = useCallback(\n async (packId: string): Promise<PackUninstallPreview | null> =>\n await run(() => client.previewPackUninstall(workspaceId, packId)),\n [client, workspaceId, run],\n );\n\n const uninstall = useCallback(\n async (packId: string, request: UninstallPackRequest): Promise<UninstallPackResult | null> => {\n const result = await run(() => client.uninstallPack(workspaceId, packId, request));\n if (result) await refresh();\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 previewInstallation,\n install,\n previewUninstall,\n uninstall,\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 {\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\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport { terminalCanAcquirePty } from \"../lib/terminal-capability\";\nimport { usePageLiveActivity } from \"./internal\";\n\n// \"on-demand\" is the boxless-benign resting state: the lease is not currently\n// holder-backed and NOTHING asked to warm a box (no viewer/consent action, no\n// 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. The workbench uses this\n * to complete acknowledgment automatically while Desktop is opening.\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 * A real-PTY descriptor is attachable when already routed as `pty-ws`, or while\n * transiently cold. A firehose-only backend and policy/OS/backend degradation\n * cannot become interactive, so attaching there would only waste a holder.\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 (acknowledgment) and 429 (viewer cap) are\n * surfaced as 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 pageLive = usePageLiveActivity();\n const lifecycleEnabled = enabled && pageLive;\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 const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${enabled}`;\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 const [stateIdentity, setStateIdentity] = useState(identityKey);\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 const previousIdentityRef = useRef(identityKey);\n\n const renegotiate = useCallback(() => {\n setNonce((n) => n + 1);\n }, []);\n\n // ── Negotiation + viewer lifecycle ──────────────────────────────────────────\n useEffect(() => {\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged) {\n setStateIdentity(identityKey);\n setCapabilities(null);\n setState(\"idle\");\n setError(null);\n setAcknowledgmentRequired(null);\n setViewerCapReached(false);\n setViewerId(null);\n epochRef.current = 0;\n viewerIdRef.current = null;\n }\n if (!lifecycleEnabled || !sessionId) {\n setState(\"idle\");\n setCapabilities(null);\n viewerIdRef.current = null;\n setViewerId(null);\n return;\n }\n // The preceding effect cleanup released any old holder before this fresh\n // lifecycle starts. Never project that stale id while re-negotiating or if\n // the replacement grant degrades.\n viewerIdRef.current = null;\n setViewerId(null);\n let cancelled = false;\n let pollTimer: ReturnType<typeof setTimeout> | null = null;\n let heartbeatTimer: ReturnType<typeof setTimeout> | null = null;\n let localViewerId: string | null = null;\n const requestAbort = new AbortController();\n const startedAt = Date.now();\n\n const clearTimers = () => {\n if (pollTimer !== null) clearTimeout(pollTimer);\n if (heartbeatTimer !== null) clearTimeout(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 const schedule = () => {\n if (cancelled || !localViewerId) return;\n heartbeatTimer = setTimeout(() => {\n heartbeatTimer = null;\n if (cancelled || !localViewerId) return;\n void client\n .heartbeatViewer(workspaceId, sessionId, localViewerId, {\n leaseEpoch: epochRef.current,\n })\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 .finally(schedule);\n }, intervalMs);\n };\n schedule();\n };\n\n const pollUntilWarm = () => {\n pollTimer = setTimeout(() => {\n if (cancelled) return;\n void client\n .getStreamCapabilities(workspaceId, sessionId, { signal: requestAbort.signal })\n .then((caps) => {\n if (cancelled) return;\n settle(caps);\n if (sandboxAcceptsLiveIo(caps.liveness)) {\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 if (isSandboxOwnershipDisabledError(cause)) {\n setState(\"on-demand\");\n setError(null);\n return;\n }\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 signal: requestAbort.signal,\n });\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 acknowledgment requirement (409) and viewer cap (429) surface as\n // typed signals 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 && terminalCanAcquirePty(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 terminal: wantTerminalAttach,\n files: wantFilesAttach,\n });\n if (cancelled) {\n // The attach crossed an identity/unmount boundary after the server\n // had already minted a holder. It is too late to publish the result,\n // but abandoning it would keep the old sandbox warm until the\n // reaper runs. Release that exact old-session holder immediately.\n void client.detachViewer(workspaceId, sessionId, holder.viewerId).catch(() => {});\n return;\n }\n if (\n (wantDesktopAttach &&\n (!holder.dataPlaneUrl || !holder.transport || !holder.client)) ||\n (wantTerminalAttach && (!holder.terminalUrl || !holder.terminalTransport))\n ) {\n // Nullable plane cells are valid graceful-degradation values at\n // the raw API boundary, but an explicit UI grant must not become\n // a successful holder that waits forever. Release it and surface\n // a retryable error instead of retaining stale credentials.\n await client.detachViewer(workspaceId, sessionId, holder.viewerId).catch(() => {});\n throw new Error(\"live plane unavailable\");\n }\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,\n token: holder.streamToken,\n expiresAt: holder.streamExpiresAt,\n resolution: holder.resolution ?? prev.DesktopStream.resolution,\n }\n : prev.DesktopStream,\n Terminal: wantTerminalAttach\n ? {\n ...prev.Terminal,\n transport: holder.terminalTransport ?? prev.Terminal.transport,\n url: holder.terminalUrl,\n token: holder.terminalToken,\n expiresAt: holder.terminalExpiresAt,\n // A live pty-ws means the box is pty-capable for real.\n ptyCapable: holder.terminalTransport ? true : prev.Terminal.ptyCapable,\n reason: holder.terminalTransport ? null : prev.Terminal.reason,\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 acknowledgment, so a 409 there\n // is not a desktop-open signal — the terminal 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 } else {\n throw cause;\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 // non-warm 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 (sandboxAcceptsLiveIo(caps.liveness) || 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 holder-confirmed warm yet — poll until it is, with the 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 (isSandboxOwnershipDisabledError(cause)) {\n setState(\"on-demand\");\n setError(null);\n return;\n }\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 requestAbort.abort();\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 lifecycleEnabled,\n attachDesktop,\n attachTerminal,\n attachFiles,\n warmingPollMs,\n warmingDeadlineMs,\n nonce,\n identityKey,\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 const identityMatches = enabled && stateIdentity === identityKey;\n return {\n capabilities: identityMatches ? capabilities : null,\n state: identityMatches ? state : \"idle\",\n error: identityMatches ? error : null,\n acknowledgmentRequired: identityMatches ? acknowledgmentRequired : null,\n viewerCapReached: identityMatches && viewerCapReached,\n viewerId: identityMatches ? viewerId : null,\n renegotiate,\n };\n}\n\nfunction isSandboxOwnershipDisabledError(error: unknown): boolean {\n return (\n error instanceof OpenGeniApiError &&\n error.status === 404 &&\n error.message.includes(\"sandbox ownership is not enabled\")\n );\n}\n","/**\n * A sandbox is available for new I/O only after a holder has observed `warm`.\n *\n * `draining` means the holder count is zero and teardown owns the provider\n * instance. The provider may disappear before the durable lease reaches `cold`,\n * so treating `draining` as live races capture/termination. Explicit user intent\n * reacquires a holder; only its subsequent `warm` state re-enables live I/O.\n */\nexport function sandboxAcceptsLiveIo(liveness: string | null | undefined): boolean {\n return liveness === \"warm\";\n}\n","import type { TerminalCapability } from \"@opengeni/sdk\";\n\n/** Whether an explicit viewer grant can upgrade this cell to a real PTY.\n * Keep acquisition feasibility separate from the current transport: a cold\n * real-PTY backend reports sse-events until the just-in-time grant warms it. */\nexport function terminalCanAcquirePty(cell: TerminalCapability | null | undefined): boolean {\n if (!cell?.ptyCapable) return false;\n if (cell.transport === \"pty-ws\" || cell.transport === \"relay-pty\") return true;\n return cell.reason === \"lease_cold\" || cell.reason === \"not_provisioned\";\n}\n","import {\n TTYD_SUBPROTOCOL,\n TerminalCapability,\n terminalSocketUrl,\n ttydAuthFrame,\n ttydInputFrame,\n ttydResizeFrame,\n TtydServerCommand,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n decodeStreamFrame,\n decodeStreamOpenAck,\n encodeStreamFrame,\n encodeStreamOpen,\n type RelayChannel,\n STREAM_KIND_PTY,\n STREAM_ROLE_CLIENT,\n} from \"../lib/relay-wire\";\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\" | \"expiresAt\"> | 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 /** Requests a fresh negotiated terminal grant after an unexpected transport\n * failure. Intentional disconnects and effect cleanup never call it. */\n onReconnectNeeded?: (() => 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 PTY stdin. Input during CONNECTING is bounded and\n * replayed only after ttyd authentication succeeds. */\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// Keystrokes entered during the websocket handshake are held until ttyd has\n// accepted its auth/resize frames. Bound the queue by UTF-16 code units (a hard\n// <=128 KiB string payload in current JS engines) so a paste cannot turn a slow\n// handshake into unbounded renderer memory. Overflow rejects the whole pending\n// input rather than ever executing a truncated shell command.\nexport const MAX_PENDING_TERMINAL_INPUT_CODE_UNITS = 64 * 1024;\nconst TERMINAL_CONNECT_EXPIRY_SKEW_MS = 5_000;\nconst TERMINAL_RECONNECT_INITIAL_MS = 100;\nconst TERMINAL_RECONNECT_MAX_MS = 3_000;\nconst RELAY_TAG_OPEN = 1;\nconst RELAY_TAG_OPEN_ACK = 2;\nconst RELAY_TAG_FRAME = 3;\n\nfunction relayDatagram(tag: number, body: Uint8Array): ArrayBuffer {\n const bytes = new Uint8Array(body.length + 1);\n bytes[0] = tag;\n bytes.set(body, 1);\n return bytes.buffer;\n}\n\nfunction relayChannelFromUrl(url: string): RelayChannel {\n const endpoint = new URL(url);\n const channel: RelayChannel = {\n channelId: endpoint.searchParams.get(\"channel\") ?? \"\",\n workspaceId: endpoint.searchParams.get(\"ws\") ?? \"\",\n agentId: endpoint.searchParams.get(\"agent\") ?? \"\",\n kind: STREAM_KIND_PTY,\n port: Number(endpoint.searchParams.get(\"port\") ?? \"0\"),\n };\n if (\n !channel.channelId ||\n !channel.workspaceId ||\n !channel.agentId ||\n !Number.isSafeInteger(channel.port) ||\n channel.port <= 0\n ) {\n throw new Error(\"terminal relay endpoint is incomplete\");\n }\n return channel;\n}\n\nfunction sendRelayInput(\n socket: WebSocket,\n channel: RelayChannel,\n sequence: bigint,\n data: string,\n): void {\n socket.send(\n relayDatagram(\n RELAY_TAG_FRAME,\n encodeStreamFrame({\n channelId: channel.channelId,\n seq: sequence.toString(),\n data: new TextEncoder().encode(data),\n producedAtMs: String(Date.now()),\n }),\n ),\n );\n}\n\n/** A bearer must remain valid long enough to finish a new websocket handshake.\n * Existing open sockets are unaffected: this is evaluated only when the\n * credential identity changes and the connection effect attempts a new socket. */\nexport function terminalStreamCredentialUsable(\n capability: Pick<TerminalCapability, \"transport\" | \"url\" | \"expiresAt\"> | null | undefined,\n nowMs = Date.now(),\n): boolean {\n if (\n (capability?.transport !== \"pty-ws\" && capability?.transport !== \"relay-pty\") ||\n !capability.url\n ) {\n return false;\n }\n if (!capability.expiresAt) return true;\n const expiresAt = Date.parse(capability.expiresAt);\n return Number.isFinite(expiresAt) && expiresAt > nowMs + TERMINAL_CONNECT_EXPIRY_SKEW_MS;\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\nfunction closeSocket(socket: WebSocket | null): void {\n try {\n socket?.close();\n } catch {\n // Already closed or rejected by the host WebSocket implementation.\n }\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, onReconnectNeeded, initialCols, initialRows } = options;\n const [status, setStatus] = useState<TerminalStreamStatus>(\"closed\");\n const [reconnectGeneration, setReconnectGeneration] = useState(0);\n const wsRef = useRef<WebSocket | null>(null);\n const pendingInputRef = useRef(\"\");\n const socketFailedRef = useRef(false);\n const socketAuthenticatedRef = useRef(false);\n const relayChannelRef = useRef<RelayChannel | null>(null);\n const relayIdentityRef = useRef<string | null>(null);\n const relayInputSequenceRef = useRef(0n);\n const relayOutputSequenceRef = useRef(0n);\n const reconnectAttemptRef = useRef(0);\n const credentialIdentityRef = useRef<string | null>(null);\n const refreshRequestedRef = useRef(false);\n const intentionalCloseRef = useRef<WeakSet<WebSocket>>(new WeakSet());\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 const onReconnectNeededRef = useRef(onReconnectNeeded);\n onOutputRef.current = onOutput;\n onTitleRef.current = onTitle;\n onReconnectNeededRef.current = onReconnectNeeded;\n\n const transport = capability?.transport ?? null;\n const url = capability?.url ?? null;\n const token = capability?.token ?? null;\n const expiresAt = capability?.expiresAt ?? null;\n const transportRef = useRef(transport);\n transportRef.current = transport;\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 const relay = transport === \"relay-pty\";\n if (transport !== \"pty-ws\" && !relay) {\n // A transport downgrade is a real semantic boundary. Do not replay input\n // captured for a PTY if this surface later changes back from firehose mode.\n pendingInputRef.current = \"\";\n socketAuthenticatedRef.current = false;\n relayIdentityRef.current = null;\n relayInputSequenceRef.current = 0n;\n relayOutputSequenceRef.current = 0n;\n reconnectAttemptRef.current = 0;\n credentialIdentityRef.current = null;\n refreshRequestedRef.current = false;\n setStatus(\"closed\");\n return;\n }\n const credentialIdentity = `${transport}\\u0000${url ?? \"\"}\\u0000${token ?? \"\"}\\u0000${expiresAt ?? \"\"}`;\n if (credentialIdentityRef.current !== credentialIdentity) {\n credentialIdentityRef.current = credentialIdentity;\n reconnectAttemptRef.current = 0;\n refreshRequestedRef.current = false;\n }\n // A changed/cleared credential is a new connection attempt boundary. It may\n // receive input while its exact grant is pending even if the prior socket\n // failed; the unchanged failed identity remains fenced because this effect\n // does not re-run for a status-only render.\n socketFailedRef.current = false;\n socketAuthenticatedRef.current = false;\n if (!url) {\n // Exact grants arrive asynchronously. Preserve the bounded first input\n // while the descriptor remains pty-ws, but never open without a credential.\n setStatus(\"closed\");\n return;\n }\n if (!terminalStreamCredentialUsable({ transport, url, expiresAt })) {\n // A descriptor from an older rolling server may still carry a bearer that\n // aged out before this surface mounted. Ask once for the exact fresh grant.\n setStatus(\"closed\");\n if (!refreshRequestedRef.current) {\n refreshRequestedRef.current = true;\n onReconnectNeededRef.current?.();\n }\n return;\n }\n\n let disposed = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let socket: WebSocket;\n let relayChannel: RelayChannel | null = null;\n const relayOutputDecoder = new TextDecoder();\n setStatus(\"connecting\");\n try {\n if (relay) {\n relayChannel = relayChannelFromUrl(url);\n const relayIdentity = [\n relayChannel.workspaceId,\n relayChannel.agentId,\n relayChannel.port,\n relayChannel.channelId,\n ].join(\"\\u0000\");\n if (relayIdentityRef.current !== relayIdentity) {\n relayIdentityRef.current = relayIdentity;\n relayInputSequenceRef.current = 0n;\n relayOutputSequenceRef.current = 0n;\n }\n relayChannelRef.current = relayChannel;\n socket = new WebSocket(url);\n } else {\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 }\n } catch {\n socketFailedRef.current = true;\n setStatus(\"error\");\n return;\n }\n socket.binaryType = \"arraybuffer\";\n wsRef.current = socket;\n\n const requestFreshGrant = () => {\n if (disposed || refreshRequestedRef.current || intentionalCloseRef.current.has(socket))\n return;\n refreshRequestedRef.current = true;\n onReconnectNeededRef.current?.();\n };\n\n const scheduleTransportReconnect = () => {\n if (disposed || reconnectTimer !== null || intentionalCloseRef.current.has(socket)) return;\n if (refreshRequestedRef.current) return;\n if (!terminalStreamCredentialUsable({ transport, url, expiresAt })) {\n requestFreshGrant();\n return;\n }\n const attempt = reconnectAttemptRef.current++;\n const delay = Math.min(\n TERMINAL_RECONNECT_INITIAL_MS * 2 ** Math.min(attempt, 8),\n TERMINAL_RECONNECT_MAX_MS,\n );\n setStatus(\"connecting\");\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n if (!disposed) setReconnectGeneration((generation) => generation + 1);\n }, delay);\n };\n\n socket.onopen = () => {\n if (disposed) return;\n if (relay && relayChannel) {\n try {\n socket.send(\n relayDatagram(\n RELAY_TAG_OPEN,\n encodeStreamOpen({\n channel: relayChannel,\n token: token ?? \"\",\n role: STREAM_ROLE_CLIENT,\n resumeFromSeq: relayOutputSequenceRef.current.toString(),\n }),\n ),\n );\n } catch {\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(socket);\n }\n return;\n }\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 if (pendingInputRef.current.length > 0) {\n // One websocket frame makes the pre-open queue all-or-nothing from this\n // client's perspective; never execute a prefix of a buffered command.\n socket.send(ttydInputFrame(pendingInputRef.current));\n pendingInputRef.current = \"\";\n }\n socketAuthenticatedRef.current = true;\n } catch {\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(socket);\n return;\n }\n setStatus(\"open\");\n reconnectAttemptRef.current = 0;\n refreshRequestedRef.current = false;\n };\n\n socket.onmessage = (ev: MessageEvent) => {\n if (disposed) return;\n if (relay) {\n if (!(ev.data instanceof ArrayBuffer) || !relayChannel) return;\n const bytes = new Uint8Array(ev.data);\n if (bytes.length < 1) return;\n const tag = bytes[0];\n const body = bytes.subarray(1);\n if (tag === RELAY_TAG_OPEN_ACK) {\n try {\n const ack = decodeStreamOpenAck(body);\n if (!ack.accepted) throw new Error(ack.error?.message ?? \"terminal relay rejected\");\n reconnectAttemptRef.current = 0;\n refreshRequestedRef.current = false;\n socketAuthenticatedRef.current = true;\n if (pendingInputRef.current.length > 0) {\n sendRelayInput(\n socket,\n relayChannel,\n relayInputSequenceRef.current++,\n pendingInputRef.current,\n );\n pendingInputRef.current = \"\";\n }\n setStatus(\"open\");\n } catch {\n socketFailedRef.current = true;\n setStatus(\"error\");\n requestFreshGrant();\n closeSocket(socket);\n }\n } else if (tag === RELAY_TAG_FRAME && socketAuthenticatedRef.current) {\n try {\n const frame = decodeStreamFrame(body);\n const sequence = BigInt(frame.seq);\n if (sequence < relayOutputSequenceRef.current) return;\n relayOutputSequenceRef.current = sequence + 1n;\n if (frame.data.length > 0) {\n onOutputRef.current?.(relayOutputDecoder.decode(frame.data, { stream: true }));\n }\n } catch {\n // Ignore one malformed frame; the live PTY remains usable.\n }\n }\n return;\n }\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) {\n // A network/relay outage is retryable with the same credential and PTY.\n // Keep accepting bounded input while the transport comes back.\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(socket);\n }\n };\n socket.onclose = () => {\n if (wsRef.current === socket) wsRef.current = null;\n socketAuthenticatedRef.current = false;\n if (!disposed) {\n if (socketFailedRef.current) setStatus(\"error\");\n else scheduleTransportReconnect();\n }\n };\n\n return () => {\n disposed = true;\n wsRef.current = null;\n socketAuthenticatedRef.current = false;\n relayChannelRef.current = null;\n if (reconnectTimer !== null) clearTimeout(reconnectTimer);\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 closeSocket(socket);\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, expiresAt, reconnectGeneration]);\n\n const write = useCallback((data: string) => {\n const currentTransport = transportRef.current;\n const ws = wsRef.current;\n if (ws && ws.readyState === WebSocket.OPEN && socketAuthenticatedRef.current) {\n try {\n const relayChannel = relayChannelRef.current;\n if (currentTransport === \"relay-pty\" && relayChannel) {\n sendRelayInput(ws, relayChannel, relayInputSequenceRef.current++, data);\n } else {\n ws.send(ttydInputFrame(data));\n }\n } catch {\n socketFailedRef.current = false;\n setStatus(\"connecting\");\n closeSocket(ws);\n }\n } else if (\n (currentTransport === \"pty-ws\" || currentTransport === \"relay-pty\") &&\n !socketFailedRef.current\n ) {\n const nextSize = pendingInputRef.current.length + data.length;\n if (nextSize > MAX_PENDING_TERMINAL_INPUT_CODE_UNITS) {\n pendingInputRef.current = \"\";\n socketFailedRef.current = true;\n setStatus(\"error\");\n closeSocket(ws);\n return;\n }\n pendingInputRef.current += data;\n }\n }, []);\n const resize = useCallback((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 && socketAuthenticatedRef.current) {\n try {\n // Self-hosted relay PTYs carry raw input/output frames. Resize remains\n // an out-of-band control operation; do not send ttyd framing into them.\n if (transportRef.current === \"pty-ws\") ws.send(ttydResizeFrame(cols, rows));\n } catch {\n // socket raced closed — geometry is replayed on the next open.\n }\n }\n }, []);\n const disconnect = useCallback(() => {\n const ws = wsRef.current;\n wsRef.current = null;\n pendingInputRef.current = \"\";\n socketFailedRef.current = false;\n socketAuthenticatedRef.current = false;\n relayChannelRef.current = null;\n setStatus(\"closed\");\n if (ws) intentionalCloseRef.current.add(ws);\n closeSocket(ws);\n }, []);\n\n return useMemo<UseTerminalStreamResult>(() => {\n return { connected: status === \"open\", status, write, resize, disconnect };\n }, [status, write, resize, disconnect]);\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\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\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 identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${interactive}\\u0000${ptyFilter ?? \"\"}`;\n const [openedPtyId, setOpenedPtyId] = useState<string | null>(null);\n const [openError, setOpenError] = useState<Error | null>(null);\n const [stateIdentity, setStateIdentity] = useState(identityKey);\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 const currentIdentityRef = useRef(identityKey);\n currentIdentityRef.current = identityKey;\n\n // Async PTY state belongs to one workspace/session/mode identity. Hide it\n // synchronously on the switching render, then clear it durably in the effect.\n useEffect(() => {\n setStateIdentity(identityKey);\n setOpenedPtyId(null);\n setOpenError(null);\n }, [identityKey]);\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.\n const openInFlight = useRef(false);\n const boxWarm = liveness === undefined || sandboxAcceptsLiveIo(liveness);\n useEffect(() => {\n if (!interactive || !sessionId || ptyFilter || !boxWarm) {\n setOpenError(null);\n return;\n }\n let cancelled = false;\n setOpenError(null);\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 // The hook is session-scoped even if a host accidentally retains the old\n // event array for one render during navigation.\n if (event.workspaceId !== workspaceId || event.sessionId !== sessionId) continue;\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, workspaceId, sessionId]);\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 identityMatches = stateIdentity === identityKey;\n const activePtyId = identityMatches ? (openedPtyId ?? openPty) : null;\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 const writeIdentity = identityKey;\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 currentIdentityRef.current === writeIdentity\n ) {\n setOpenedPtyId(null);\n setReopenNonce((n) => n + 1);\n }\n });\n };\n }, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId, identityKey]);\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: identityMatches ? openError : null,\n };\n}\n","import type {\n FileSystemRouteIdentity,\n FsChangedPayload,\n FsReadResponse,\n FsTreeNode,\n FsWriteResponse,\n GitChangedPayload,\n GitFileStatusCode,\n GitStatusResponse,\n OpenGeniRequestOptions,\n SessionCapabilities,\n SessionEvent,\n WorkspaceCaptureManifest,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type ClientOverride, useOpenGeni } from \"../provider\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\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\nexport type CapturedFileUnavailableReason = \"not-captured\" | \"too-large\" | \"content-missing\";\n\n/** A cold capture can index a path without retaining its contents. Components\n * use this typed result to offer an explicit wake action instead of silently\n * turning passive review into a live sandbox read. */\nexport class CapturedFileUnavailableError extends Error {\n readonly code = \"captured_file_unavailable\";\n\n constructor(\n readonly path: string,\n readonly reason: CapturedFileUnavailableReason,\n ) {\n super(\n reason === \"too-large\"\n ? `${path} exceeds the captured preview limit.`\n : reason === \"content-missing\"\n ? `${path} is no longer available in this capture.`\n : `${path} was not changed in this captured turn.`,\n );\n this.name = \"CapturedFileUnavailableError\";\n }\n}\n\nexport class FileWriteConflictError extends Error {\n readonly code = \"file_write_conflict\";\n\n constructor(\n readonly path: string,\n readonly expectedContent: string,\n readonly liveContent: string,\n ) {\n super(`${path} changed on the machine. Reload it or explicitly overwrite the live version.`);\n this.name = \"FileWriteConflictError\";\n }\n}\n\nexport type SandboxWriteFileOptions = {\n /** Exact text loaded into the editor. The live file is re-read before write;\n * divergence fails closed with FileWriteConflictError. */\n expectedContent?: string | undefined;\n /** Deliberately bypass the expected-content guard after a visible conflict. */\n force?: boolean | undefined;\n};\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 /** Opaque path returned by the selected target's FileSystem boundary. */\n path: string;\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 /** Exact capability identity for the selected filesystem route. A route/root\n * change resets this hook and makes stale provider requests fail retryably. */\n route?: FileSystemRouteIdentity | undefined;\n /** Hold off the initial list (e.g. panel collapsed). Default true. */\n enabled?: boolean | undefined;\n /** Pause live reads/invalidation while preserving the last rendered result. */\n active?: boolean | undefined;\n /** Repository roots advertised by capabilities, relative to the workspace. */\n repoPaths?: readonly string[] | undefined;\n /** The lease liveness. `null` means capability negotiation has not produced\n * an authoritative lifecycle value yet and therefore blocks live I/O. Omitting\n * the option preserves the legacy direct-hook behavior. 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?: SessionCapabilities[\"liveness\"] | null | undefined;\n /** The latest turn-end workspace capture (from `useWorkspaceCapture`). The tree\n * paints immediately from this durable index, then a warm box reconciles live\n * in place. If that live read fails, the capture remains a truthful read-only\n * fallback instead of turning into an empty error surface. */\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, options?: OpenGeniRequestOptions) => 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: (\n path: string,\n content: string,\n options?: SandboxWriteFileOptions,\n ) => 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 /** Monotonic invalidation token for open file previews. Advances when an\n * external filesystem change or completed agent tool may have changed bytes. */\n contentRevision?: number | undefined;\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 /** Lightweight repository context loaded by the same status request that tints files. */\n gitSummary?: SandboxFilesGitSummary | null | undefined;\n /** True only while the initial repository-status overlay is still loading. */\n gitLoading?: boolean | undefined;\n loading: boolean;\n error: Error | null;\n};\n\nexport type SandboxFilesGitSummary = {\n branch: string | null;\n isRepo: boolean;\n repoCount: number;\n ahead: number;\n behind: number;\n dirtyCount: number;\n};\n\nfunction normalizeRoot(root: string): string {\n const slashNormalized = root.replaceAll(\"\\\\\", \"/\").replace(/^\\.\\/+/, \"\");\n if (slashNormalized === \"/\") return \"/\";\n const normalized = slashNormalized.replace(/\\/+$/, \"\");\n return normalized === \".\" ? \"\" : normalized;\n}\n\nfunction isAbsoluteTreePath(path: string): boolean {\n return path.startsWith(\"/\") || /^[A-Za-z]:\\//u.test(path);\n}\n\nfunction joinTreeRoot(root: string, path: string): string {\n if (!root || isAbsoluteTreePath(path)) return path;\n return root === \"/\" ? `/${path}` : `${root}/${path}`;\n}\n\nfunction qualifyStatusPath(root: string, path: string, treeRoot: string): string {\n const normalized = normalizeRoot(root);\n const workspaceRelative = joinTreeRoot(normalized, path);\n return joinTreeRoot(normalizeRoot(treeRoot), workspaceRelative);\n}\n\nfunction summarizeStatuses(\n statuses: Array<{ root: string; status: GitStatusResponse }>,\n): SandboxFilesGitSummary {\n const repositories = statuses.filter(({ status }) => status.isRepo);\n return {\n branch: repositories.length === 1 ? (repositories[0]?.status.head ?? null) : null,\n isRepo: repositories.length > 0,\n repoCount: repositories.length,\n ahead: repositories.reduce((sum, { status }) => sum + status.ahead, 0),\n behind: repositories.reduce((sum, { status }) => sum + status.behind, 0),\n dirtyCount: repositories.reduce((sum, { status }) => sum + status.files.length, 0),\n };\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\nfunction parentWithinTree(path: string, rootPath: string): string {\n const parent = parentOf(path);\n return parent === \"\" && normalizeRoot(rootPath) === \"/\" && path.startsWith(\"/\") ? \"/\" : parent;\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, captureComplete = false): 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\n ? node.children.map((child) => fsNodeToTree(child, captureComplete))\n : captureComplete && kind === \"dir\"\n ? []\n : 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 {\n ...node,\n children: replaceChildren(node.children, targetPath, children),\n };\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\nconst FS_LIST_BATCH_REQUEST_LIMIT = 16;\n\n/** Repository paths are capability-advertised and therefore safe to use as a\n * bounded initial lazy-tree frontier. Listing their ancestors concurrently with\n * the root avoids a root → repositories → repo remote waterfall. */\nfunction initialDirectoryFrontier(rootPath: string, repoPaths: readonly string[]): string[] {\n const root = normalizeRoot(rootPath);\n const rootParts = root.split(\"/\").filter(Boolean);\n const rootPrefix = root.startsWith(\"//\") ? \"//\" : root.startsWith(\"/\") ? \"/\" : \"\";\n const paths = new Set<string>();\n for (const repoPath of repoPaths) {\n const canonicalRepoPath = joinTreeRoot(root, normalizeRoot(repoPath));\n const parts = canonicalRepoPath.split(\"/\").filter(Boolean);\n if (rootParts.some((part, index) => parts[index] !== part)) continue;\n for (let depth = rootParts.length + 1; depth <= parts.length; depth += 1) {\n const path = parts.slice(0, depth).join(\"/\");\n paths.add(`${rootPrefix}${path}`);\n }\n }\n // A workspace with hundreds of repositories should remain lazy. This still\n // preloads the shared repository container and the first visible roots.\n return [...paths]\n .sort((a, b) => a.split(\"/\").length - b.split(\"/\").length || a.localeCompare(b))\n .slice(0, 8);\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, rootPath = \"\"): boolean {\n if (parent === normalizeRoot(rootPath)) 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(\n nodes: FileTreeNode[],\n parent: string,\n child: FileTreeNode,\n rootPath = \"\",\n): FileTreeNode[] {\n if (parent === normalizeRoot(rootPath)) {\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, rootPath) };\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, rootPath = \"\"): FileTreeNode[] {\n const parent = parentWithinTree(path, rootPath);\n if (parent === normalizeRoot(rootPath)) {\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 {\n ...node,\n children: node.children.filter((n) => n.path !== path),\n };\n }\n if (node.kind === \"dir\" && node.children && parent.startsWith(`${node.path}/`)) {\n return { ...node, children: removeNode(node.children, path, rootPath) };\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\nfunction decodeBase64Bytes(value: string): Uint8Array {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n return bytes;\n}\n\nfunction decodeBase64Text(value: string): string {\n return new TextDecoder().decode(decodeBase64Bytes(value));\n}\n\nfunction encodeBase64Bytes(bytes: Uint8Array): string {\n let binary = \"\";\n const chunkSize = 0x8000;\n for (let offset = 0; offset < bytes.length; offset += chunkSize) {\n binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));\n }\n return btoa(binary);\n}\n\nasync function assertCapturedHash(bytes: Uint8Array, expected: string | null): Promise<void> {\n if (!expected) throw new Error(\"Captured file is missing its integrity hash.\");\n if (!globalThis.crypto?.subtle) {\n throw new Error(\"Captured file integrity verification is unavailable in this browser.\");\n }\n const buffer = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(buffer).set(bytes);\n const digest = new Uint8Array(await globalThis.crypto.subtle.digest(\"SHA-256\", buffer));\n const actual = [...digest].map((byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n if (actual !== expected) throw new Error(\"Captured file content failed its integrity check.\");\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 active = options.active ?? true;\n const rootPath = options.rootPath ?? \"\";\n const routeEpoch = options.route?.epoch ?? null;\n const routeRoot = options.route?.root ?? null;\n const route = useMemo<FileSystemRouteIdentity | undefined>(\n () =>\n routeEpoch !== null && routeRoot !== null\n ? { epoch: routeEpoch, root: routeRoot }\n : undefined,\n [routeEpoch, routeRoot],\n );\n const repoPathsKey = [\n ...new Set((options.repoPaths?.length ? options.repoPaths : [rootPath]).map(normalizeRoot)),\n ].join(\"\\u0000\");\n const repoPaths = useMemo(() => repoPathsKey.split(\"\\u0000\"), [repoPathsKey]);\n const capture = options.capture ?? null;\n const isLive = sandboxAcceptsLiveIo(options.liveness);\n // `liveness` predates this hook option. Preserve legacy embedders that omit it;\n // explicit `null` (negotiating) and lifecycle values require authoritative warm.\n const acceptsEventReads = options.liveness === undefined || isLive;\n const acceptsEventReadsRef = useRef(acceptsEventReads);\n acceptsEventReadsRef.current = acceptsEventReads;\n const hasLiveIoFence = options.liveness !== undefined;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${rootPath}\\u0000${repoPathsKey}\\u0000${routeEpoch ?? \"\"}\\u0000${routeRoot ?? \"\"}`;\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 [gitSummary, setGitSummary] = useState<SandboxFilesGitSummary | null>(null);\n const [gitLoading, setGitLoading] = useState(false);\n const [contentRevision, setContentRevision] = useState(0);\n const [stateIdentity, setStateIdentity] = useState(identityKey);\n // Which source the tree currently reflects — \"capture\" (cold paint) or \"live\".\n const [source, setSource] = useState<\"live\" | \"capture\" | null>(null);\n const sourceRef = useRef<\"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 refreshAbortRef = useRef<AbortController | null>(null);\n const identityAbortRef = useRef(new AbortController());\n const eventReadAbortRef = useRef(new AbortController());\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 eventReconcileInFlightRef = useRef<Promise<void> | null>(null);\n const eventReconcilePendingRef = 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. 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 refreshAbortRef.current?.abort();\n const refreshAbort = new AbortController();\n refreshAbortRef.current = refreshAbort;\n const generation = (refreshGenerationRef.current += 1);\n setLoading(true);\n setGitLoading(true);\n setError(null);\n try {\n // Paint the useful file tree before the optional Git tint. Separate remote\n // requests for one Modal box are deliberately serialized by the API; firing\n // both here only made the Git request contend with the file request during\n // cold starts.\n const frontierPaths = initialDirectoryFrontier(rootPath, repoPaths);\n const listRequests = [rootPath, ...frontierPaths].map((path) => ({\n path,\n depth: 1,\n ...(route ? { route } : {}),\n }));\n // Root plus the bounded repository frontier share one API request, one\n // direct holder, and one provider attach. The old per-directory fan-out\n // paid that fixed control-plane cost up to nine times on every Files open.\n const listedBatch = await client.fsListBatch(\n workspaceId,\n sessionId,\n { requests: listRequests },\n { signal: refreshAbort.signal },\n );\n if (refreshGenerationRef.current !== generation) return;\n const listed = listedBatch.results[0];\n if (!listed) throw new Error(\"Workspace list batch did not return the root result.\");\n const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));\n // Paint the root and already-returned frontier in one commit so preloaded\n // repository folders never flicker through a collapsed intermediate tree.\n setTree((prev) => {\n let hydrated = prev.length === 0 ? children : mergeRootChildren(prev, children);\n for (const [index, path] of frontierPaths.entries()) {\n const prefetched = listedBatch.results[index + 1];\n if (!prefetched) continue;\n hydrated = replaceChildren(\n hydrated,\n path,\n (prefetched.root.children ?? []).map((node) => fsNodeToTree(node)),\n );\n }\n return applyStatus(hydrated);\n });\n sourceRef.current = \"live\";\n setSource(\"live\");\n setLoading(false);\n\n const statuses =\n repoPaths.length > 0\n ? await client\n .gitReadBatch(\n workspaceId,\n sessionId,\n {\n requests: repoPaths.map((root) => ({\n status: { path: root },\n })),\n },\n { signal: refreshAbort.signal },\n )\n .then((batch) =>\n batch.results.map((result, index) => ({\n root: repoPaths[index] ?? \"\",\n status: result.status,\n })),\n )\n .catch(() => null)\n : [];\n if (refreshGenerationRef.current !== generation) return;\n if (statuses) {\n const overlay = new Map<string, FileTreeStatus>();\n for (const { root, status } of statuses) {\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(qualifyStatusPath(root, file.path, rootPath), mapped);\n }\n }\n statusRef.current = overlay;\n setGitSummary(summarizeStatuses(statuses));\n } else {\n statusRef.current = new Map();\n setGitSummary(null);\n }\n setGitLoading(false);\n setTree((prev) => applyStatus(prev));\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 if (refreshGenerationRef.current === generation) setGitLoading(false);\n if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;\n }\n }, [client, workspaceId, sessionId, rootPath, repoPaths, route, 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).\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 // The capture tree is a complete bounded index. Preserve an explicit empty\n // `children: []` as an actually empty directory; the live depth-1 mapper\n // intentionally treats that shape as an unexpanded boundary.\n const children = (manifest.treeIndex.children ?? []).map((node) => fsNodeToTree(node, true));\n setTree((prev) =>\n applyStatus(prev.length === 0 ? children : mergeRootChildren(prev, children)),\n );\n sourceRef.current = \"capture\";\n setSource(\"capture\");\n setGitSummary({\n branch: manifest.repos.length === 1 ? (manifest.repos[0]?.head ?? null) : null,\n isRepo: manifest.repos.length > 0,\n repoCount: manifest.repos.length,\n ahead: manifest.repos.reduce((sum, repo) => sum + repo.ahead, 0),\n behind: manifest.repos.reduce((sum, repo) => sum + repo.behind, 0),\n dirtyCount: manifest.files.length,\n });\n setGitLoading(false);\n setError(null);\n },\n [applyStatus],\n );\n\n const expand = useCallback(\n async (path: string) => {\n if (!sessionId) return;\n // Capture browsing is a durable server-side read surface. Never turn a\n // folder click into a Channel-A list while cold; truncated residue already\n // renders a truthful \"contents on machine\" row.\n if (source === \"capture\" && capture) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\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(\n workspaceId,\n sessionId,\n { path, depth: 1, ...(route ? { route } : {}) },\n { signal: identitySignal },\n );\n if (identityGenerationRef.current !== identityGeneration) return;\n const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));\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, capture, source, route, applyStatus],\n );\n\n const readFile = useCallback(\n async (path: string, requestOptions: OpenGeniRequestOptions = {}) => {\n if (!sessionId) throw new Error(\"no session\");\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestOptions.signal\n ? AbortSignal.any([identitySignal, requestOptions.signal])\n : identitySignal;\n const captured = capture?.files.find((file) => file.path === path && !file.deleted);\n if (source === \"capture\" && capture) {\n if (!captured) {\n throw new CapturedFileUnavailableError(path, \"not-captured\");\n }\n // A passive review of a turn-touched file must stay entirely server-side:\n // mint/read its captured after-image, verify the content hash, and never\n // wake the sandbox. A URL may expire between mint and GET, so retry once\n // through the authenticated API to obtain a fresh scoped URL.\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const result = await client.getWorkspaceCaptureFile(\n workspaceId,\n sessionId,\n path,\n capture.revision,\n { signal },\n );\n if (result.path !== path || result.revision !== capture.revision) {\n throw new Error(\n \"Captured file identity did not match the requested workspace revision.\",\n );\n }\n if (\n result.hash !== captured.hash ||\n result.sizeBytes !== captured.sizeBytes ||\n result.isBinary !== captured.isBinary ||\n result.tooLarge !== captured.tooLarge\n ) {\n throw new Error(\"Captured file metadata did not match its manifest.\");\n }\n if (result.tooLarge) {\n throw new CapturedFileUnavailableError(path, \"too-large\");\n }\n\n let bytes: Uint8Array;\n let encoding: \"utf8\" | \"base64\";\n let content: string;\n if (result.content !== null && result.encoding !== null) {\n encoding = result.encoding;\n content = result.content;\n bytes =\n encoding === \"base64\"\n ? decodeBase64Bytes(content)\n : new TextEncoder().encode(content);\n } else if (result.contentUrl) {\n const response = await fetch(result.contentUrl.url, {\n credentials: \"omit\",\n cache: \"no-store\",\n referrerPolicy: \"no-referrer\",\n signal: AbortSignal.any([signal, AbortSignal.timeout(30_000)]),\n }).catch(() => null);\n if (!response?.ok) {\n if (\n attempt === 0 &&\n (response === null || response.status === 401 || response.status === 403)\n ) {\n continue;\n }\n throw new Error(\"Captured file download failed.\");\n }\n bytes = new Uint8Array(await response.arrayBuffer());\n encoding = result.isBinary ? \"base64\" : \"utf8\";\n content = result.isBinary ? encodeBase64Bytes(bytes) : new TextDecoder().decode(bytes);\n } else {\n throw new CapturedFileUnavailableError(path, \"content-missing\");\n }\n\n if (bytes.byteLength !== result.sizeBytes) {\n throw new Error(\"Captured file size did not match its manifest.\");\n }\n await assertCapturedHash(bytes, result.hash);\n return {\n path,\n encoding,\n content,\n sizeBytes: result.sizeBytes,\n truncated: false,\n isBinary: result.isBinary,\n revision: result.revision,\n };\n }\n throw new Error(\"Captured file download failed after refreshing its URL.\");\n }\n return await client.fsRead(\n workspaceId,\n sessionId,\n { path, ...(route ? { route } : {}) },\n { signal },\n );\n },\n [client, workspaceId, sessionId, capture, source, route],\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, requestSignal?: AbortSignal) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestSignal\n ? AbortSignal.any([identitySignal, requestSignal])\n : identitySignal;\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, rootPath)) return;\n try {\n const listed = await client.fsList(\n workspaceId,\n sessionId,\n { path, depth: 1, ...(route ? { route } : {}) },\n { signal },\n );\n if (identityGenerationRef.current !== identityGeneration) return;\n const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));\n if (path === normalizeRoot(rootPath)) {\n 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, rootPath, route, applyStatus],\n );\n\n // Reconcile the visible directory frontier through bounded batch requests.\n // One tool completion can affect several expanded directories; issuing one\n // provider request per directory created a self-inflicted lock convoy.\n const reconcilePaths = useCallback(\n async (requestedPaths: readonly string[], requestSignal?: AbortSignal) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestSignal\n ? AbortSignal.any([identitySignal, requestSignal])\n : identitySignal;\n const paths = [...new Set(requestedPaths)].filter((path) =>\n parentIsLoaded(treeRef.current, path, rootPath),\n );\n for (let offset = 0; offset < paths.length; offset += FS_LIST_BATCH_REQUEST_LIMIT) {\n const chunk = paths.slice(offset, offset + FS_LIST_BATCH_REQUEST_LIMIT);\n try {\n const listed = await client.fsListBatch(\n workspaceId,\n sessionId,\n {\n requests: chunk.map((path) => ({\n path,\n depth: 1,\n ...(route ? { route } : {}),\n })),\n },\n { signal },\n );\n if (identityGenerationRef.current !== identityGeneration) return;\n setTree((previous) => {\n let next = previous;\n for (const [index, path] of chunk.entries()) {\n const result = listed.results[index];\n if (!result) continue;\n const children = (result.root.children ?? []).map((node) => fsNodeToTree(node));\n if (path === normalizeRoot(rootPath)) {\n next = mergeRootChildren(next, children);\n } else {\n const existing = findNodeByPath(next, path);\n const merged = existing?.children\n ? mergeChildren(existing.children, children)\n : children;\n next = replaceChildren(next, path, merged);\n }\n }\n return applyStatus(next);\n });\n } catch {\n // Reconciliation is best-effort. Preserve the current visible tree and\n // let the next real event or explicit refresh reconcile it.\n }\n }\n },\n [client, workspaceId, sessionId, rootPath, route, 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 setError(null);\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 // An expected-content conflict belongs to the editor's explicit\n // Reload/Overwrite decision surface. Treating it as a broken file tree\n // would also raise a duplicate host toast and leave a stale global error\n // after the user successfully resolves the conflict.\n if (err instanceof FileWriteConflictError) throw err;\n setError(err);\n onMutationError?.(err, opName);\n throw err;\n }\n },\n [applyStatus, reconcilePath, onMutationError],\n );\n\n const writeFile = useCallback(\n async (\n path: string,\n content: string,\n writeOptions: SandboxWriteFileOptions = {},\n ): Promise<FsWriteResponse> => {\n if (!sessionId) throw new Error(\"no session\");\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const parent = parentWithinTree(path, rootPath);\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 = {\n path,\n name: leafOf(path),\n kind: \"file\",\n size: content.length,\n };\n return await runOptimistic(\n \"write\",\n (nodes) => (exists ? nodes : insertNode(nodes, parent, node, rootPath)),\n async () => {\n if (!writeOptions.force && writeOptions.expectedContent !== undefined) {\n const live = await client.fsRead(\n workspaceId,\n sessionId,\n { path, ...(route ? { route } : {}) },\n { signal: identitySignal },\n );\n if (identityGenerationRef.current !== identityGeneration) {\n throw new Error(\"File save cancelled because the workspace changed.\");\n }\n const liveContent =\n live.encoding === \"base64\" ? decodeBase64Text(live.content) : live.content;\n if (live.truncated || live.isBinary || liveContent !== writeOptions.expectedContent) {\n throw new FileWriteConflictError(path, writeOptions.expectedContent, liveContent);\n }\n }\n if (identityGenerationRef.current !== identityGeneration) {\n throw new Error(\"File save cancelled because the workspace changed.\");\n }\n return await client.fsWrite(workspaceId, sessionId, {\n path,\n content,\n overwrite: true,\n ...(route ? { route } : {}),\n });\n },\n exists ? [] : [parent],\n );\n },\n [client, workspaceId, sessionId, tree, rootPath, route, runOptimistic],\n );\n\n const createFile = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentWithinTree(path, rootPath);\n const node: FileTreeNode = {\n path,\n name: leafOf(path),\n kind: \"file\",\n size: 0,\n };\n await runOptimistic(\n \"create file\",\n (nodes) => insertNode(nodes, parent, node, rootPath),\n () =>\n client.fsWrite(workspaceId, sessionId, {\n path,\n content: \"\",\n overwrite: false,\n ...(route ? { route } : {}),\n }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, runOptimistic],\n );\n\n const createDir = useCallback(\n async (path: string): Promise<void> => {\n if (!sessionId) throw new Error(\"no session\");\n const parent = parentWithinTree(path, rootPath);\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 = {\n path,\n name: leafOf(path),\n kind: \"dir\",\n children: [],\n };\n await runOptimistic(\n \"create folder\",\n (nodes) => insertNode(nodes, parent, node, rootPath),\n () =>\n client.fsMkdir(workspaceId, sessionId, {\n path,\n recursive: true,\n ...(route ? { route } : {}),\n }),\n [parent],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, 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, rootPath),\n () =>\n client.fsDelete(workspaceId, sessionId, {\n path,\n recursive,\n ...(route ? { route } : {}),\n }),\n [parentWithinTree(path, rootPath)],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, 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 = parentWithinTree(path, rootPath);\n const to = parentWithinTree(newPath, rootPath);\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, rootPath), to, moved, rootPath);\n },\n () =>\n client.fsMove(workspaceId, sessionId, {\n path,\n newPath,\n overwrite: opts?.overwrite ?? false,\n ...(route ? { route } : {}),\n }),\n to === from ? [from] : [from, to],\n );\n },\n [client, workspaceId, sessionId, rootPath, route, runOptimistic],\n );\n\n // Initial paint + reset on identity change. Source selection:\n // • any box WITH a capture → paint instantly from the durable capture index;\n // a holder-confirmed warm box then reconciles live in place.\n // • if that live reconciliation fails, keep the capture visible and read-only.\n // • legacy callers that omit liveness and have no capture retain their live\n // fallback; an explicitly cold/draining lease never wakes from a passive mount.\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 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 refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshGenerationRef.current += 1;\n eventReadAbortRef.current.abort();\n eventReadAbortRef.current = new AbortController();\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged || !enabled) {\n if (identityChanged) eventReconcileInFlightRef.current = null;\n identityAbortRef.current.abort();\n identityAbortRef.current = new AbortController();\n identityGenerationRef.current += 1;\n lastSeqRef.current = 0;\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n eventReconcilePendingRef.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 setStateIdentity(identityKey);\n setExpandingPaths(new Set());\n sourceRef.current = null;\n setSource(null);\n setLoading(false);\n setError(null);\n setGitSummary(null);\n setGitLoading(false);\n setContentRevision(0);\n }\n if (!enabled) {\n return;\n }\n const currentCapture = captureRevision !== null ? captureRef.current : null;\n if (currentCapture && (identityChanged || !isLive || sourceRef.current !== \"live\")) {\n seedFromCapture(currentCapture);\n }\n if (!active) {\n if (!active) {\n setLoading(false);\n setGitLoading(false);\n }\n return;\n }\n if (isLive || (!hasLiveIoFence && !currentCapture)) {\n void refresh();\n }\n return () => {\n refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshGenerationRef.current += 1;\n eventReadAbortRef.current.abort();\n eventReconcilePendingRef.current = false;\n };\n }, [\n enabled,\n active,\n isLive,\n hasLiveIoFence,\n captureRevision,\n identityKey,\n refresh,\n seedFromCapture,\n ]);\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(\n async (requestSignal?: AbortSignal) => {\n if (!sessionId) return;\n const identityGeneration = identityGenerationRef.current;\n const identitySignal = identityAbortRef.current.signal;\n const signal = requestSignal\n ? AbortSignal.any([identitySignal, requestSignal])\n : identitySignal;\n setGitLoading(true);\n try {\n const batch = await client.gitReadBatch(\n workspaceId,\n sessionId,\n { requests: repoPaths.map((root) => ({ status: { path: root } })) },\n { signal },\n );\n const statuses = batch.results.map((result, index) => ({\n root: repoPaths[index] ?? \"\",\n status: result.status,\n }));\n if (identityGenerationRef.current !== identityGeneration) return;\n const overlay = new Map<string, FileTreeStatus>();\n for (const { root, status } of statuses) {\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(qualifyStatusPath(root, file.path, rootPath), mapped);\n }\n }\n statusRef.current = overlay;\n setGitSummary(summarizeStatuses(statuses));\n setTree((prev) => applyStatus(prev));\n } catch {\n /* a non-repo box has no overlay — leave the tree untinted */\n } finally {\n if (identityGenerationRef.current === identityGeneration) setGitLoading(false);\n }\n },\n [client, workspaceId, sessionId, repoPaths, rootPath, applyStatus],\n );\n\n const performEventReconcile = useCallback(async () => {\n const parents = pendingParentsRef.current;\n pendingParentsRef.current = new Set();\n const wantGit = pendingGitRef.current;\n pendingGitRef.current = false;\n const signal = eventReadAbortRef.current.signal;\n const paths = [...parents];\n\n // File content is the primary Files-tab result. Reconcile it first, then add\n // the optional Git tint through a second serial request. This matches the\n // API's exact-provider serialization instead of making the two reads contend.\n await reconcilePaths(paths, signal);\n if (wantGit) await refreshGitOverlay(signal);\n }, [reconcilePaths, refreshGitOverlay]);\n const performEventReconcileRef = useRef(performEventReconcile);\n performEventReconcileRef.current = performEventReconcile;\n const reconcilePendingEvents = useCallback(async () => {\n eventReconcilePendingRef.current = true;\n const existing = eventReconcileInFlightRef.current;\n if (existing) return await existing;\n const identityGeneration = identityGenerationRef.current;\n const run = (async () => {\n while (\n eventReconcilePendingRef.current &&\n identityGenerationRef.current === identityGeneration\n ) {\n eventReconcilePendingRef.current = false;\n await performEventReconcileRef.current();\n }\n })();\n eventReconcileInFlightRef.current = run;\n try {\n await run;\n } finally {\n if (eventReconcileInFlightRef.current === run) eventReconcileInFlightRef.current = null;\n }\n }, []);\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 // • Generic command/tool output performs no provider reads. The canonical\n // turn-end capture refreshes the root once after the command burst settles.\n const events = options.events;\n\n useEffect(() => {\n if (!enabled || !events) return;\n // An inactive tab or holderless draining/cold lease must not replay the\n // historical log into live provider reads. The capture already includes\n // those events; a later warm transition performs one authoritative refresh.\n if (!active || !acceptsEventReads) {\n for (const event of events) {\n if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;\n }\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n debounceRef.current = null;\n }\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n eventReconcilePendingRef.current = false;\n return;\n }\n let sawNew = false;\n let contentChanged = 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 contentChanged = true;\n for (const change of payload.changes ?? []) {\n pendingParentsRef.current.add(parentWithinTree(change.path, rootPath));\n if (change.oldPath) {\n pendingParentsRef.current.add(parentWithinTree(change.oldPath, rootPath));\n }\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 if (contentChanged) setContentRevision((revision) => revision + 1);\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 if (!acceptsEventReadsRef.current) {\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n return;\n }\n void reconcilePendingEvents();\n }, 150);\n }, [enabled, active, acceptsEventReads, events, rootPath, reconcilePendingEvents]);\n\n useEffect(() => {\n if (active && acceptsEventReads) return;\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n debounceRef.current = null;\n }\n pendingParentsRef.current = new Set();\n pendingGitRef.current = false;\n eventReconcilePendingRef.current = false;\n }, [active, acceptsEventReads]);\n\n useEffect(\n () => () => {\n refreshAbortRef.current?.abort();\n identityAbortRef.current.abort();\n eventReadAbortRef.current.abort();\n eventReconcilePendingRef.current = false;\n identityGenerationRef.current += 1;\n if (debounceRef.current) clearTimeout(debounceRef.current);\n },\n [],\n );\n\n const identityMatches = enabled && stateIdentity === identityKey;\n return {\n tree: identityMatches ? tree : [],\n expand,\n expandingPaths: identityMatches ? expandingPaths : new Set<string>(),\n readFile,\n writeFile,\n createFile,\n createDir,\n deleteEntry,\n moveEntry,\n refresh,\n contentRevision: identityMatches ? contentRevision : 0,\n source: identityMatches ? source : null,\n capturedAt: identityMatches && source === \"capture\" ? (capture?.capturedAt ?? null) : null,\n gitSummary: identityMatches ? gitSummary : null,\n gitLoading: identityMatches && gitLoading,\n loading: identityMatches && loading,\n error: identityMatches ? error : null,\n };\n}\n","import type {\n GitFileDiff,\n SessionCapabilities,\n SessionEvent,\n WorkspaceCaptureManifest,\n WorkspaceCaptureRepo,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { type ClientOverride, useOpenGeni } from \"../provider\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\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 /** All repository roots in the workspace. When supplied, status and diff are\n * aggregated into one workspace-wide result and paths are workspace-relative. */\n repoPaths?: readonly string[] | undefined;\n /** Diff the staged index vs HEAD (`--cached`) instead of the working tree. */\n staged?: boolean | undefined;\n /** Review scope. `branch` compares the current branch with the remote default\n * branch, `working` shows uncommitted edits, and `staged` shows the index.\n * `staged` above remains as a compatibility alias. */\n comparison?: SandboxGitComparison | undefined;\n /** Hold off the initial fetch. Default true. */\n enabled?: boolean | undefined;\n /** Pause live reads/invalidation while preserving the last rendered result. */\n active?: boolean | undefined;\n /** Lease liveness. `null` means capability negotiation is still pending and\n * blocks live I/O. When not warm, the diff is served from the capture instead\n * of a live `gitDiff` RPC. Omission preserves legacy direct-hook behavior. */\n liveness?: SessionCapabilities[\"liveness\"] | null | undefined;\n /** The latest turn-end capture (from `useWorkspaceCapture`). Seeds the diff\n * immediately; a warm box reconciles live and leaves this durable review\n * surface in place if the live request is temporarily unavailable. */\n capture?: WorkspaceCaptureManifest | null | undefined;\n};\n\nexport type SandboxGitComparison = \"branch\" | \"working\" | \"staged\";\n\n/** A Git diff qualified into workspace scope. `repoRoot` is present for the\n * workspace-wide path and lets review UI group real repositories without\n * guessing from the first path segment. */\nexport type SandboxGitFileDiff = GitFileDiff & {\n repoRoot?: string | 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: SandboxGitFileDiff[];\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 /** Number and workspace-relative roots of repositories represented here. */\n repoCount: number;\n repoRoots: string[];\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 const normalized = root\n .replaceAll(\"\\\\\", \"/\")\n .replace(/^\\.\\/+/, \"\")\n .replace(/\\/+$/, \"\");\n return normalized === \".\" ? \"\" : normalized;\n}\n\nfunction qualifyPath(repoRoot: string, path: string): string {\n const root = normalizeRoot(repoRoot);\n return root ? `${root}/${path}` : path;\n}\n\nfunction qualifyDiff(repoRoot: string, file: GitFileDiff): SandboxGitFileDiff {\n const root = normalizeRoot(repoRoot);\n return {\n ...file,\n path: qualifyPath(root, file.path),\n oldPath: file.oldPath === null ? null : qualifyPath(root, file.oldPath),\n repoRoot: root,\n };\n}\n\nfunction uniqueRoots(roots: readonly string[]): string[] {\n return [...new Set(roots.map(normalizeRoot))].sort((a, b) => a.localeCompare(b));\n}\n\n// GitReadBatchRequest is contract-bounded to 32 items. Keep workspace-wide\n// reads bounded without changing the wire limit; sequential chunks preserve\n// deterministic root/result mapping and cap Channel-A lease concurrency at one.\nconst GIT_READ_BATCH_REQUEST_LIMIT = 32;\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: SandboxGitFileDiff, b: SandboxGitFileDiff): boolean {\n if (\n a.path !== b.path ||\n a.oldPath !== b.oldPath ||\n a.repoRoot !== b.repoRoot ||\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(\n current: SandboxGitFileDiff[],\n next: SandboxGitFileDiff[],\n): SandboxGitFileDiff[] {\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. 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 active = options.active ?? true;\n const repoPath = options.repoPath ?? \"\";\n const workspaceWide = options.repoPaths !== undefined;\n // Serialize the caller's array so inline values do not retrigger effects. An\n // explicitly empty advertised list falls back to the legacy repoPath probe.\n const repoPathsKey = uniqueRoots(\n options.repoPaths && options.repoPaths.length > 0 ? options.repoPaths : [repoPath],\n ).join(\"\\u0000\");\n const repoPaths = useMemo(() => repoPathsKey.split(\"\\u0000\"), [repoPathsKey]);\n const comparison: SandboxGitComparison =\n options.comparison ?? (options.staged ? \"staged\" : \"working\");\n const hasAdvertisedRepoPaths = (options.repoPaths?.length ?? 0) > 0;\n // New captures retain both working-tree and branch comparisons. Staged state\n // remains live-only; legacy captures simply lack branchDiff and fall back via\n // the workspace controller without inventing an empty branch comparison.\n const capture = comparison === \"staged\" ? null : (options.capture ?? null);\n const isLive = sandboxAcceptsLiveIo(options.liveness);\n // `liveness` is optional for compatibility with direct hook consumers. Explicit\n // `null` (negotiating) and lifecycle values require authoritative warm.\n const acceptsEventReads = options.liveness === undefined || isLive;\n const acceptsEventReadsRef = useRef(acceptsEventReads);\n acceptsEventReadsRef.current = acceptsEventReads;\n const hasLiveIoFence = options.liveness !== undefined;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${repoPathsKey}\\u0000${workspaceWide}\\u0000${comparison}`;\n\n const [diff, setDiff] = useState<SandboxGitFileDiff[]>([]);\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 [repoRoots, setRepoRoots] = useState<string[]>([]);\n const [source, setSource] = useState<\"live\" | \"capture\" | null>(null);\n const sourceRef = useRef<\"live\" | \"capture\" | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [stateIdentity, setStateIdentity] = useState(identityKey);\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 refreshAbortRef = useRef<AbortController | null>(null);\n const refreshInFlightRef = useRef<Promise<void> | null>(null);\n const refreshPendingRef = useRef(false);\n const refreshWorkerEpochRef = useRef(0);\n const lastChangeRef = useRef(0);\n const eventRefreshTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const performRefresh = useCallback(async () => {\n if (!sessionId) return;\n const refreshAbort = new AbortController();\n refreshAbortRef.current = refreshAbort;\n const generation = (refreshGenerationRef.current += 1);\n setLoading(true);\n setError(null);\n try {\n const diffRequest = (root: string) =>\n client.gitDiff(\n workspaceId,\n sessionId,\n {\n path: root,\n ...(comparison === \"branch\"\n ? { fromRef: \"origin/HEAD\", includeUntracked: true }\n : comparison === \"working\"\n ? { fromRef: \"HEAD\", includeUntracked: true }\n : { staged: true, includeUntracked: false }),\n },\n { signal: refreshAbort.signal },\n );\n\n // Capability-advertised roots are known repositories. Fetch status metadata\n // and diff hunks together: both are independent Channel-A reads and each can\n // take several seconds on a remote sandbox. The legacy root probe remains\n // serial so a non-repository workspace never receives a failing git diff.\n const prefetched = hasAdvertisedRepoPaths\n ? await (async () => {\n const prefetchedRepos: Array<{\n root: string;\n status: Awaited<ReturnType<typeof client.gitStatus>>;\n result: Awaited<ReturnType<typeof client.gitDiff>>;\n }> = [];\n for (\n let offset = 0;\n offset < repoPaths.length;\n offset += GIT_READ_BATCH_REQUEST_LIMIT\n ) {\n const roots = repoPaths.slice(offset, offset + GIT_READ_BATCH_REQUEST_LIMIT);\n const batch = await client.gitReadBatch(\n workspaceId,\n sessionId,\n {\n requests: roots.map((root) => ({\n status: { path: root },\n diff: {\n path: root,\n ...(comparison === \"branch\"\n ? { fromRef: \"origin/HEAD\", includeUntracked: true }\n : comparison === \"working\"\n ? { fromRef: \"HEAD\", includeUntracked: true }\n : { staged: true, includeUntracked: false }),\n },\n })),\n },\n { signal: refreshAbort.signal },\n );\n if (batch.results.length !== roots.length) {\n throw new Error(\n `Workspace Git batch returned ${batch.results.length} results for ${roots.length} repositories.`,\n );\n }\n batch.results.forEach((item, index) => {\n prefetchedRepos.push({\n root: roots[index]!,\n status: item.status,\n result: item.diff ?? {\n files: [],\n revision: item.status.revision,\n },\n });\n });\n }\n return prefetchedRepos;\n })()\n : null;\n const statuses =\n prefetched ??\n (await Promise.all(\n repoPaths.map(async (root) => ({\n root,\n status: await client.gitStatus(\n workspaceId,\n sessionId,\n { path: root },\n { signal: refreshAbort.signal },\n ),\n })),\n ));\n if (refreshGenerationRef.current !== generation) return;\n const repositories = statuses.filter(({ status }) => status.isRepo);\n const roots = repositories.map(({ root }) => root);\n setRepoRoots(roots);\n setIsRepo(repositories.length > 0);\n setBranch(repositories.length === 1 ? (repositories[0]?.status.head ?? null) : null);\n setAhead(repositories.reduce((sum, { status }) => sum + status.ahead, 0));\n setBehind(repositories.reduce((sum, { status }) => sum + status.behind, 0));\n if (repositories.length === 0) {\n setDiff([]);\n sourceRef.current = \"live\";\n setSource(\"live\");\n return;\n }\n const prefetchedByRoot = new Map(prefetched?.map(({ root, result }) => [root, result]));\n const results = await Promise.all(\n repositories.map(async ({ root }) => ({\n root,\n result: prefetchedByRoot.get(root) ?? (await diffRequest(root)),\n })),\n );\n if (refreshGenerationRef.current !== generation) return;\n // Merge in place so the cold→warm swap keeps unchanged file sections mounted.\n setDiff((prev) =>\n mergeDiffs(\n prev,\n results.flatMap(({ root, result }) =>\n workspaceWide ? result.files.map((file) => qualifyDiff(root, file)) : result.files,\n ),\n ),\n );\n sourceRef.current = \"live\";\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 if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;\n }\n }, [\n client,\n workspaceId,\n sessionId,\n repoPaths,\n hasAdvertisedRepoPaths,\n workspaceWide,\n comparison,\n ]);\n\n // Provider reads cannot be undispatched after they reach a remote sandbox.\n // Keep exactly one refresh in flight and collapse any burst of invalidations\n // into one trailing read. Aborting and replacing every tool-output refresh\n // used to leave several Modal reads contending for the same provider lock.\n const performRefreshRef = useRef(performRefresh);\n performRefreshRef.current = performRefresh;\n const refresh = useCallback(async () => {\n refreshPendingRef.current = true;\n const existing = refreshInFlightRef.current;\n if (existing) return await existing;\n\n const workerEpoch = refreshWorkerEpochRef.current;\n const run = (async () => {\n while (refreshPendingRef.current && refreshWorkerEpochRef.current === workerEpoch) {\n refreshPendingRef.current = false;\n await performRefreshRef.current();\n }\n })();\n refreshInFlightRef.current = run;\n try {\n await run;\n } finally {\n if (refreshInFlightRef.current === run) refreshInFlightRef.current = null;\n }\n }, []);\n\n // Serve the requested review scope from a capture when that scope exists.\n const seedFromCapture = useCallback(\n (manifest: WorkspaceCaptureManifest) => {\n const repositories = workspaceWide\n ? manifest.repos\n : ([repoForPath(manifest, repoPath)].filter(Boolean) as WorkspaceCaptureRepo[]);\n if (comparison === \"branch\" && repositories.some((repo) => repo.branchDiff === undefined)) {\n return;\n }\n if (repositories.length === 0) {\n setIsRepo(false);\n setBranch(null);\n setAhead(0);\n setBehind(0);\n setRepoRoots([]);\n setDiff((prev) => (prev.length === 0 ? prev : []));\n sourceRef.current = \"capture\";\n setSource(\"capture\");\n return;\n }\n setIsRepo(true);\n setBranch(repositories.length === 1 ? (repositories[0]?.head ?? null) : null);\n setAhead(repositories.reduce((sum, repo) => sum + repo.ahead, 0));\n setBehind(repositories.reduce((sum, repo) => sum + repo.behind, 0));\n setRepoRoots(repositories.map((repo) => normalizeRoot(repo.root)));\n setDiff((prev) =>\n mergeDiffs(\n prev,\n repositories.flatMap((repo) => {\n const capturedDiff = comparison === \"branch\" ? (repo.branchDiff ?? []) : repo.diff;\n return workspaceWide\n ? capturedDiff.map((file) => qualifyDiff(repo.root, file))\n : capturedDiff;\n }),\n ),\n );\n sourceRef.current = \"capture\";\n setSource(\"capture\");\n setError(null);\n },\n [comparison, repoPath, workspaceWide],\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 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 refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshPendingRef.current = false;\n refreshGenerationRef.current += 1;\n const identityChanged = previousIdentityRef.current !== identityKey;\n previousIdentityRef.current = identityKey;\n if (identityChanged) {\n // Different sessions target different provider identities. Fence the old\n // worker and let the new session load immediately instead of waiting for a\n // stuck request that has already been aborted.\n refreshWorkerEpochRef.current += 1;\n refreshInFlightRef.current = null;\n }\n if (identityChanged || !enabled) {\n lastChangeRef.current = 0;\n setDiff([]);\n setStateIdentity(identityKey);\n setIsRepo(false);\n setBranch(null);\n setAhead(0);\n setBehind(0);\n setRepoRoots([]);\n sourceRef.current = null;\n setSource(null);\n setLoading(false);\n setError(null);\n }\n if (!enabled) {\n return;\n }\n const currentCapture = captureRevision !== null ? captureRef.current : null;\n if (currentCapture && (identityChanged || !isLive || sourceRef.current !== \"live\")) {\n seedFromCapture(currentCapture);\n }\n if (!active) {\n if (!active) setLoading(false);\n return;\n }\n if (isLive || (!hasLiveIoFence && !currentCapture)) {\n void refresh();\n }\n return () => {\n refreshAbortRef.current?.abort();\n refreshAbortRef.current = null;\n refreshPendingRef.current = false;\n refreshGenerationRef.current += 1;\n };\n }, [\n enabled,\n active,\n isLive,\n hasLiveIoFence,\n captureRevision,\n identityKey,\n refresh,\n seedFromCapture,\n ]);\n\n // Structured Git changes are debounced into one live reconcile. Generic\n // command/tool output performs no provider reads: the canonical turn-end\n // capture advances `captureRevision`, which refreshes after the burst settles.\n const events = options.events;\n useEffect(() => {\n if (!enabled || !events) {\n if (eventRefreshTimerRef.current) {\n clearTimeout(eventRefreshTimerRef.current);\n eventRefreshTimerRef.current = null;\n }\n return;\n }\n // Historical events describe the capture we already loaded. Inactive tabs\n // and holderless draining/cold leases advance the cursor without issuing\n // provider I/O; becoming warm performs one authoritative reconcile above.\n if (!active || !acceptsEventReads) {\n for (const event of events) {\n if (event.sequence > lastChangeRef.current) lastChangeRef.current = event.sequence;\n }\n if (eventRefreshTimerRef.current) {\n clearTimeout(eventRefreshTimerRef.current);\n eventRefreshTimerRef.current = null;\n }\n return;\n }\n let latest = lastChangeRef.current;\n let changed = false;\n for (const event of events) {\n if (event.sequence <= latest) continue;\n if (event.type === \"git.changed\") {\n latest = event.sequence;\n changed = true;\n }\n }\n if (latest > lastChangeRef.current) {\n lastChangeRef.current = latest;\n if (!changed) return;\n if (eventRefreshTimerRef.current) clearTimeout(eventRefreshTimerRef.current);\n eventRefreshTimerRef.current = setTimeout(() => {\n eventRefreshTimerRef.current = null;\n if (acceptsEventReadsRef.current) void refresh();\n }, 150);\n }\n }, [enabled, active, acceptsEventReads, events, refresh]);\n\n useEffect(\n () => () => {\n if (eventRefreshTimerRef.current) clearTimeout(eventRefreshTimerRef.current);\n },\n [],\n );\n\n const identityMatches = enabled && stateIdentity === identityKey;\n const visibleRepoRoots = identityMatches ? repoRoots : [];\n return {\n diff: identityMatches ? diff : [],\n branch: identityMatches ? branch : null,\n isRepo: identityMatches && isRepo,\n ahead: identityMatches ? ahead : 0,\n behind: identityMatches ? behind : 0,\n repoCount: visibleRepoRoots.length,\n repoRoots: visibleRepoRoots,\n refresh,\n source: identityMatches ? source : null,\n capturedAt: identityMatches && source === \"capture\" ? (capture?.capturedAt ?? null) : null,\n loading: identityMatches && loading,\n error: identityMatches ? error : null,\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\ntype AvailableCaptureResponse = Extract<GetWorkspaceCaptureResponse, { available: true }>;\n\nconst CAPTURE_STATS_NUMBER_FIELDS = [\n \"repoCount\",\n \"fileCount\",\n \"additions\",\n \"deletions\",\n \"totalBytes\",\n \"tooLargeCount\",\n \"binaryCount\",\n \"treeEntryCount\",\n \"durationMs\",\n] as const;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Signed manifests bypass the authenticated JSON client's wire decoder. Treat\n * the blob as untrusted until its outer schema and exact revision identity match\n * the metadata response that minted the URL. The API performs the full contract\n * parse; this client-side boundary prevents a corrupt/mis-keyed response from\n * being presented as a different authoritative capture.\n */\nfunction captureManifestForResponse(\n value: unknown,\n response: AvailableCaptureResponse,\n): WorkspaceCaptureManifest {\n if (\n !isRecord(value) ||\n value.version !== 1 ||\n !Number.isSafeInteger(value.revision) ||\n typeof value.capturedAt !== \"string\" ||\n !(value.turnId === null || typeof value.turnId === \"string\") ||\n !Number.isSafeInteger(value.leaseEpoch) ||\n !isRecord(value.treeIndex) ||\n typeof value.treeTruncated !== \"boolean\" ||\n !Array.isArray(value.repos) ||\n !Array.isArray(value.files) ||\n !isRecord(value.stats)\n ) {\n throw new Error(\"Workspace capture manifest failed validation.\");\n }\n\n if (\n value.revision !== response.revision ||\n value.capturedAt !== response.capturedAt ||\n value.turnId !== response.turnId ||\n value.leaseEpoch !== response.leaseEpoch\n ) {\n throw new Error(\"Workspace capture manifest identity did not match its response.\");\n }\n\n for (const field of CAPTURE_STATS_NUMBER_FIELDS) {\n if (!Number.isSafeInteger(value.stats[field]) || value.stats[field] !== response.stats[field]) {\n throw new Error(\"Workspace capture manifest statistics did not match its response.\");\n }\n }\n if (\n typeof value.stats.treeTruncated !== \"boolean\" ||\n value.stats.treeTruncated !== response.stats.treeTruncated ||\n (value.stats.fingerprint ?? null) !== (response.stats.fingerprint ?? null) ||\n value.repos.length !== response.stats.repoCount ||\n value.files.length !== response.stats.fileCount ||\n value.treeTruncated !== response.stats.treeTruncated\n ) {\n throw new Error(\"Workspace capture manifest statistics did not match its response.\");\n }\n\n return value as WorkspaceCaptureManifest;\n}\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). 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 const requestAbortRef = useRef<AbortController | null>(null);\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 requestAbortRef.current?.abort();\n const requestAbort = new AbortController();\n requestAbortRef.current = requestAbort;\n const generation = (generationRef.current += 1);\n setStateIdentity(identityKey);\n setLoading(true);\n setError(null);\n try {\n // A signed URL can expire between mint and GET. Re-enter the authenticated\n // endpoint once to mint a fresh URL; never replay or log the old credential.\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const res: GetWorkspaceCaptureResponse = await client.getWorkspaceCapture(\n workspaceId,\n sessionId,\n { signal: requestAbort.signal },\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 manifestValue: unknown = res.manifest;\n if (!manifestValue && res.manifestUrl) {\n const response = await fetch(res.manifestUrl.url, {\n signal: AbortSignal.any([\n requestAbort.signal,\n AbortSignal.timeout(MANIFEST_FETCH_TIMEOUT_MS),\n ]),\n credentials: \"omit\",\n cache: \"no-store\",\n referrerPolicy: \"no-referrer\",\n }).catch(() => null);\n if (generationRef.current !== generation) return;\n if (!response?.ok) {\n if (\n attempt === 0 &&\n (response === null || response.status === 401 || response.status === 403)\n ) {\n continue;\n }\n throw new Error(\n `Workspace capture manifest download failed${response ? ` (${response.status})` : \"\"}.`,\n );\n }\n try {\n manifestValue = await response.json();\n } catch {\n throw new Error(\"Workspace capture manifest was not valid JSON.\");\n }\n if (generationRef.current !== generation) return;\n }\n if (!manifestValue) {\n throw new Error(\"Workspace capture response did not include a manifest.\");\n }\n const manifest = captureManifestForResponse(manifestValue, res);\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 return;\n }\n throw new Error(\"Workspace capture manifest download failed after refreshing its URL.\");\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 if (requestAbortRef.current === requestAbort) requestAbortRef.current = null;\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 requestAbortRef.current?.abort();\n requestAbortRef.current = null;\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 requestAbortRef.current?.abort();\n requestAbortRef.current = null;\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 // The mount request is already resolving the latest revision. Do not abort\n // and replace that exact identity-equivalent read merely because the event\n // tail announced a revision before the response arrived. When the request\n // settles, its state update re-runs this effect and a genuinely newer\n // announcement still refreshes immediately.\n if (requestAbortRef.current) 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 type { FileSystemRouteIdentity } from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\n\n/**\n * The wake-on-edit state machine. This hook owns the logic and the UI renders\n * its result. 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 /** Exact capability identity for the selected filesystem route. A route/root\n * change discards the buffered edit and makes stale flushes fail retryably. */\n route?: FileSystemRouteIdentity | 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 sandboxAcceptsLiveIo(liveness);\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.\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 design specifies — 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 routeEpoch = options.route?.epoch;\n const routeRoot = options.route?.root;\n const route = useMemo<FileSystemRouteIdentity | undefined>(\n () =>\n routeEpoch !== undefined && routeRoot !== undefined\n ? { epoch: routeEpoch, root: routeRoot }\n : undefined,\n [routeEpoch, routeRoot],\n );\n const live = isLive(options.liveness);\n const offline = options.offline === true;\n const identityKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${path ?? \"\"}\\u0000${routeEpoch ?? \"\"}\\u0000${routeRoot ?? \"\"}`;\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 const [stateIdentity, setStateIdentity] = useState(identityKey);\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 const identityGenerationRef = useRef(0);\n const flushAttemptRef = useRef(0);\n const readAbortRef = useRef<AbortController | null>(null);\n\n // Reset the machine when the edited file (or session) changes.\n useEffect(() => {\n identityGenerationRef.current += 1;\n flushAttemptRef.current += 1;\n readAbortRef.current?.abort();\n readAbortRef.current = null;\n setStateIdentity(identityKey);\n setBuffer(null);\n setWantsWarm(false);\n setFlush(\"idle\");\n setConflict(null);\n setError(null);\n flushingRef.current = false;\n return () => {\n identityGenerationRef.current += 1;\n flushAttemptRef.current += 1;\n readAbortRef.current?.abort();\n readAbortRef.current = null;\n };\n }, [identityKey]);\n\n const edit = useCallback(\n (content: string) => {\n if (stateIdentity !== identityKey) return;\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, stateIdentity, identityKey],\n );\n\n const doFlush = useCallback(\n async (force: boolean) => {\n if (stateIdentity !== identityKey) return;\n if (!sessionId || !path) return;\n const content = bufferRef.current;\n if (content === null) return;\n if (flushingRef.current) return;\n const identityGeneration = identityGenerationRef.current;\n const flushAttempt = (flushAttemptRef.current += 1);\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 readAbort = new AbortController();\n readAbortRef.current?.abort();\n readAbortRef.current = readAbort;\n const liveRead = await client.fsRead(\n workspaceId,\n sessionId,\n { path, ...(route ? { route } : {}) },\n { signal: readAbort.signal },\n );\n if (readAbortRef.current === readAbort) readAbortRef.current = null;\n if (identityGenerationRef.current !== identityGeneration) return;\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, {\n path,\n content,\n overwrite: true,\n ...(route ? { route } : {}),\n });\n if (identityGenerationRef.current !== identityGeneration) return;\n setConflict(null);\n setFlush(\"flushed\");\n setWantsWarm(false);\n } catch (cause) {\n if (identityGenerationRef.current !== identityGeneration) return;\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 if (flushAttemptRef.current === flushAttempt) {\n flushingRef.current = false;\n readAbortRef.current = null;\n }\n }\n },\n [client, workspaceId, sessionId, path, baseContent, route, stateIdentity, identityKey],\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 const identityMatches = stateIdentity === identityKey;\n return {\n state: identityMatches ? state : offline ? \"readonly-offline\" : \"viewing-cold\",\n readOnly: offline,\n buffer: identityMatches ? buffer : null,\n wantsWarm: identityMatches && wantsWarm,\n edit,\n conflict: identityMatches ? conflict : null,\n overwrite,\n discard,\n error: identityMatches ? error : null,\n };\n}\n","import { useMemo } from \"react\";\nimport type { MachineState } from \"@opengeni/sdk\";\nimport type { SessionCapabilitiesState } from \"./use-session-capabilities\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport { connectionStatusForState } from \"../types/machines\";\n\n/** The one truthful machine indicator. Managed cold compute is sleeping; a\n * Connected Machine that is genuinely unreachable remains offline. */\nexport type MachineChipState = \"live\" | \"waking\" | \"offline\";\n\nexport type MachineChip = {\n state: MachineChipState;\n /** A ready-to-render label (\"Live\" / \"Waking…\" / \"Sleeping · saved 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 lease → **live** (a holder-confirmed 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 managedRestingLabel = asOf ? `Sleeping · saved ${formatAsOf(asOf, now)}` : \"Sleeping\";\n const offlineLabel = \"Offline\";\n\n // A connected machine has no Modal group lease, so capability negotiation\n // legitimately reports `cold` until a stream holder is minted. Its fleet\n // probe is the authoritative reachability signal; do not label an online Mac\n // \"Offline\" merely because there is no unrelated Modal lease.\n const selfhostedOnline =\n input.activeIsSelfhosted === true &&\n input.activeMachineState != null &&\n connectionStatusForState(input.activeMachineState) === \"online\";\n\n // 1. A holder-confirmed warm provider or online connected machine is live.\n // Draining remains teardown-owned and may already have lost its instance.\n if (sandboxAcceptsLiveIo(input.liveness) || selfhostedOnline) {\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\".\n const selfhostedOffline =\n input.activeIsSelfhosted === true && input.activeMachineState === \"offline\";\n\n // Capability negotiation has definitively failed. A retained warm intent\n // must not turn that error into the optimistic Waking state.\n if (input.capabilitiesState === \"error\") {\n return {\n state: \"offline\",\n label: input.activeIsSelfhosted === true ? offlineLabel : managedRestingLabel,\n asOf,\n };\n }\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. Managed cold compute is sleeping with saved-workspace freshness. A\n // Connected Machine is only described as Offline when its reachability is\n // genuinely unavailable; capture time is not a heartbeat.\n return {\n state: \"offline\",\n label: input.activeIsSelfhosted === true ? offlineLabel : managedRestingLabel,\n asOf,\n };\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 { CheckIcon, ShieldCheckIcon, XIcon } from \"lucide-react\";\nimport { useEffect, useId, useRef, useState, type ReactNode } from \"react\";\nimport type { PendingApproval } from \"../approvals\";\nimport { cn } from \"../lib/cn\";\n\nexport type ApprovalSurfaceMessages = {\n title: string;\n description: string;\n approve: string;\n reject: string;\n approving: string;\n rejecting: string;\n formatToolName: (name: string) => string;\n};\n\nexport const defaultApprovalSurfaceMessages: ApprovalSurfaceMessages = {\n title: \"Approval required\",\n description: \"Review the requested action before the agent continues.\",\n approve: \"Approve\",\n reject: \"Reject\",\n approving: \"Approving…\",\n rejecting: \"Rejecting…\",\n formatToolName: (name) => name.replaceAll(\"_\", \" \").replaceAll(\".\", \" › \"),\n};\n\nexport type ApprovalSurfaceProps = {\n approvals: PendingApproval[];\n onApprove: (approval: PendingApproval) => void | Promise<void>;\n onReject: (approval: PendingApproval) => void | Promise<void>;\n responding?: boolean | undefined;\n error?: string | Error | null | undefined;\n messages?: Partial<ApprovalSurfaceMessages> | undefined;\n renderApproval?: ((approval: PendingApproval) => ReactNode) | undefined;\n className?: string | undefined;\n};\n\nconst APPROVAL_ARGUMENT_PREVIEW_CHARACTERS = 4_000;\n\nfunction approvalArgumentsPreview(value: unknown): string | null {\n if (value === undefined) return null;\n let serialized: string;\n try {\n serialized =\n typeof value === \"string\" ? value : (JSON.stringify(value, null, 2) ?? String(value));\n } catch {\n serialized = \"[Arguments unavailable]\";\n }\n const characters = Array.from(serialized);\n if (characters.length <= APPROVAL_ARGUMENT_PREVIEW_CHARACTERS) return serialized;\n return `${characters.slice(0, APPROVAL_ARGUMENT_PREVIEW_CHARACTERS).join(\"\")}\\n… ${characters.length - APPROVAL_ARGUMENT_PREVIEW_CHARACTERS} characters omitted`;\n}\n\nfunction approvalOwnershipKey(approval: PendingApproval): string {\n return `${approval.id}\\u0000${approval.name}\\u0000${approvalArgumentsPreview(approval.arguments) ?? \"\"}`;\n}\n\n/**\n * Host-neutral approval presentation backed by the native pending-approval\n * projection and control callbacks. It owns only presentation and duplicate\n * click fencing; OpenGeni remains the authority for approval state.\n */\nexport function ApprovalSurface({\n approvals,\n onApprove,\n onReject,\n responding = false,\n error,\n messages: overrides,\n renderApproval,\n className,\n}: ApprovalSurfaceProps) {\n const titleId = useId();\n const messages = { ...defaultApprovalSurfaceMessages, ...overrides };\n const [pending, setPending] = useState<{\n approvalKey: string;\n decision: \"approve\" | \"reject\";\n token: symbol;\n } | null>(null);\n const pendingRef = useRef<{ approvalKey: string; token: symbol } | null>(null);\n const [decisionError, setDecisionError] = useState<Error | null>(null);\n\n useEffect(() => {\n if (\n pending &&\n !approvals.some((approval) => approvalOwnershipKey(approval) === pending.approvalKey)\n ) {\n if (pendingRef.current?.token === pending.token) {\n pendingRef.current = null;\n }\n setPending((current) => (current?.token === pending.token ? null : current));\n }\n }, [approvals, pending]);\n\n if (approvals.length === 0) return null;\n const busy = responding || pendingRef.current !== null;\n const decide = async (\n approval: PendingApproval,\n decision: \"approve\" | \"reject\",\n ): Promise<void> => {\n if (responding || pendingRef.current !== null) return;\n const approvalKey = approvalOwnershipKey(approval);\n const token = Symbol(approvalKey);\n pendingRef.current = { approvalKey, token };\n setPending({ approvalKey, decision, token });\n setDecisionError(null);\n try {\n await (decision === \"approve\" ? onApprove(approval) : onReject(approval));\n // Keep the decision fenced until the authoritative projection removes or\n // replaces this exact approval. A successful callback is transport\n // acceptance, not settlement.\n } catch (cause) {\n if (pendingRef.current?.token === token) {\n pendingRef.current = null;\n setPending((current) => (current?.token === token ? null : current));\n setDecisionError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n }\n };\n const errorMessage = decisionError?.message ?? (error instanceof Error ? error.message : error);\n\n return (\n <section\n className={cn(\n \"og-root flex w-full flex-col gap-3 rounded-og-lg border border-og-status-waiting/35 bg-og-status-waiting/5 p-4 shadow-og-sm\",\n className,\n )}\n aria-labelledby={titleId}\n >\n <header className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 inline-flex size-8 shrink-0 items-center justify-center rounded-og-md bg-og-status-waiting/12 text-og-status-waiting\">\n <ShieldCheckIcon aria-hidden=\"true\" className=\"size-4\" />\n </span>\n <div className=\"min-w-0\">\n <h2 id={titleId} className=\"text-og-md font-semibold text-og-fg\">\n {messages.title}\n </h2>\n <p className=\"mt-0.5 text-og-sm text-og-fg-muted\">{messages.description}</p>\n </div>\n </header>\n\n <div className=\"flex flex-col gap-2\">\n {approvals.map((approval) => {\n const approvalKey = approvalOwnershipKey(approval);\n const active = pending?.approvalKey === approvalKey ? pending.decision : null;\n const argumentsPreview = approvalArgumentsPreview(approval.arguments);\n return (\n <article\n key={approval.id}\n data-approval-id={approval.id}\n className=\"rounded-og-md border border-og-border bg-og-surface-1 p-3\"\n >\n {renderApproval ? (\n renderApproval(approval)\n ) : (\n <>\n <p className=\"text-og-sm font-medium text-og-fg\">\n {messages.formatToolName(approval.name)}\n </p>\n {argumentsPreview !== null ? (\n <pre className=\"mt-2 max-h-48 overflow-auto whitespace-pre-wrap break-words rounded-og-sm bg-og-surface-2 p-2 font-mono text-og-xs text-og-fg-muted\">\n {argumentsPreview}\n </pre>\n ) : null}\n </>\n )}\n <div className=\"mt-3 flex flex-wrap justify-end gap-2\">\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => void decide(approval, \"reject\")}\n className=\"inline-flex min-h-9 items-center gap-1.5 rounded-og-md border border-og-border px-3 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-surface-2 hover:text-og-fg disabled:opacity-50\"\n >\n <XIcon aria-hidden=\"true\" className=\"size-3.5\" />\n {active === \"reject\" ? messages.rejecting : messages.reject}\n </button>\n <button\n type=\"button\"\n disabled={busy}\n onClick={() => void decide(approval, \"approve\")}\n className=\"inline-flex min-h-9 items-center gap-1.5 rounded-og-md bg-og-accent px-3 py-1.5 text-og-sm font-medium text-og-accent-fg transition-colors hover:bg-og-accent-strong disabled:opacity-50\"\n >\n <CheckIcon aria-hidden=\"true\" className=\"size-3.5\" />\n {active === \"approve\" ? messages.approving : messages.approve}\n </button>\n </div>\n </article>\n );\n })}\n </div>\n\n {errorMessage ? (\n <p role=\"alert\" className=\"text-og-sm text-og-status-failed\">\n {errorMessage}\n </p>\n ) : null}\n </section>\n );\n}\n","import { deriveSessionDisplayTitle, type Session } from \"@opengeni/sdk\";\nimport { cn } from \"../lib/cn\";\nimport { formatRelativeTime } from \"../lib/format\";\nimport { SessionStatus } from \"./session-status\";\n\nconst SESSION_METADATA_TITLE_KEYS = [\"title\", \"name\"] as const;\n\nexport type FleetTileProps = {\n session: Session;\n /** Overrides the derived title (durable title, metadata, prompt preview, or safe fallback). */\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 return deriveSessionDisplayTitle(session, { metadataKeys: SESSION_METADATA_TITLE_KEYS });\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, useLayoutEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { type TerminalStreamStatus, useTerminalStream } from \"../hooks/use-terminal-stream\";\nimport type { UseSandboxTerminalResult } from \"../hooks/use-sandbox-terminal\";\nimport { resolveTerminalFont, xtermThemeFromTokens } from \"../lib/xterm-theme\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport { terminalCanAcquirePty } from \"../lib/terminal-capability\";\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 engaged 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 /** Re-negotiate the terminal capability after an unexpected socket failure. */\n onReconnectNeeded?: (() => 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 focus: () => 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\nexport type TerminalSurfaceState =\n | \"loading\"\n | \"connecting\"\n | \"error\"\n | \"waking\"\n | \"output-only\"\n | \"interactive\";\n\n/**\n * Stable semantic state for hosts and browser acceptance. The xterm helper\n * textarea exists before the live PTY socket is ready, so its presence alone\n * must never be treated as proof that keystrokes can reach the sandbox.\n */\nexport function terminalSurfaceState(input: {\n ready: boolean;\n acceptsInput: boolean;\n inputPending: boolean;\n ptyStatus: TerminalStreamStatus;\n booting: boolean;\n}): TerminalSurfaceState {\n if (!input.ready) return \"loading\";\n if (input.acceptsInput) return \"interactive\";\n if (input.inputPending) return \"connecting\";\n if (input.ptyStatus === \"connecting\") return \"connecting\";\n if (input.ptyStatus === \"error\") return \"error\";\n if (input.booting) return \"waking\";\n return \"output-only\";\n}\n\nexport function subscribeTerminalInput(\n term: Pick<XtermLike, \"onData\"> | null,\n sink: ((data: string) => void) | null,\n enabled: boolean,\n): { dispose: () => void } | null {\n if (!enabled || !term || !sink) return null;\n return term.onData(sink);\n}\n\n/** Clear the transient wake line and put the first live prompt at cell 1,1.\n * `Terminal.clear()` removes scrollback but deliberately preserves the cursor,\n * which lets the first PTY frame append to the old wake message. */\nexport function clearTerminalBootStatus(term: Pick<XtermLike, \"write\">): void {\n term.write(\"\\r\\x1b[2K\\x1b[2J\\x1b[H\");\n}\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 onReconnectNeeded,\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 [inputReady, setInputReady] = useState(false);\n const [activated, setActivated] = useState(false);\n\n // ── Interactive transport switch ─────────────────────────────────────────────\n const ptyDescriptor =\n terminalCapability?.transport === \"pty-ws\" || terminalCapability?.transport === \"relay-pty\";\n const ptyAttachable = terminalCanAcquirePty(terminalCapability);\n const {\n status: ptyStatus,\n write: ptyWrite,\n resize: resizePty,\n connected: ptyConnected,\n } = useTerminalStream({\n // Connect only after xterm exists. This makes the renderer the sole output\n // owner from the first websocket frame and removes an otherwise unbounded\n // pre-mount output queue during large command bursts.\n capability:\n ptyAttachable && ready\n ? {\n transport: terminalCapability!.transport,\n url: ptyDescriptor ? terminalCapability!.url : null,\n token: ptyDescriptor ? terminalCapability!.token : null,\n expiresAt: ptyDescriptor ? terminalCapability!.expiresAt : null,\n }\n : null,\n onOutput: (data) => {\n termRef.current?.write(data);\n },\n onReconnectNeeded,\n });\n\n // A pty-ws capability exclusively owns the screen even while connecting or\n // after a visible connection failure; never silently switch one terminal UI\n // between two PTYs. Input is enabled during the handshake because the stream\n // hook buffers it strictly and flushes only after ttyd auth succeeds.\n const ptyMode = ptyDescriptor;\n // Keep xterm stdin live for an attachable descriptor even before its URL has\n // arrived. Focus/click triggers the grant; any immediately following input is\n // bounded in the stream hook instead of disappearing in that HTTP interval.\n const ptyCapturesInput = ptyAttachable && ptyStatus !== \"error\";\n const interactive = !readOnly && (ptyAttachable ? ptyCapturesInput : result.write !== null);\n // Public \"interactive\" means the mounted input subscription can reach a live\n // PTY now. Before that point xterm still captures into the bounded queue, but\n // acceptance and embedders see an explicit connecting state.\n const acceptsInput = inputReady && (!ptyAttachable || ptyConnected);\n const inputPending = inputReady && ptyAttachable && !ptyConnected && activated;\n let terminalModeLabel: string | null;\n if (readOnly) terminalModeLabel = \"read-only\";\n else if (!ptyAttachable) terminalModeLabel = acceptsInput ? null : \"output only\";\n else if (ptyStatus === \"error\") terminalModeLabel = \"connection error\";\n else if (acceptsInput) terminalModeLabel = null;\n else terminalModeLabel = activated ? \"connecting\" : \"connect on input\";\n\n // Boot-in-terminal: after the user engages 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 = sandboxAcceptsLiveIo(liveness);\n const booting =\n activated &&\n !ptyMode &&\n !warm &&\n liveness !== null &&\n liveness !== undefined &&\n result.chunks.length === 0;\n const surfaceState = terminalSurfaceState({\n ready,\n acceptsInput,\n inputPending,\n ptyStatus,\n booting,\n });\n\n function handleActivate() {\n // Capture-phase activation may synchronously negotiate a fresh terminal\n // capability and rerender the shell. Focus xterm before that state change so\n // the user's first keystroke or paste reaches its already-bounded input\n // queue instead of landing on the surrounding dock.\n const term = termRef.current;\n if (term && !readOnly && (ptyAttachable || result.write !== null)) {\n term.options.disableStdin = false;\n term.options.cursorBlink = true;\n }\n term?.focus();\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 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 useLayoutEffect(() => {\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) clearTerminalBootStatus(term);\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. `ptyWrite` is stable across socket\n // status changes, so this subscription does not tear down while a grant opens\n // or rotates and cannot create a first-keystroke gap.\n useLayoutEffect(() => {\n const term = termRef.current;\n if (!ready || !term || !interactive) {\n setInputReady(false);\n return;\n }\n const sink = ptyAttachable ? ptyWrite : result.write;\n if (!sink) {\n setInputReady(false);\n return;\n }\n const sub = subscribeTerminalInput(term, sink, true);\n setInputReady(sub !== null);\n return () => sub?.dispose();\n }, [ready, interactive, ptyAttachable, 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 {terminalModeLabel && (\n <span\n className=\"rounded-og-sm bg-og-surface-2 px-1.5 py-0.5 text-og-xs uppercase tracking-wide\"\n role=\"status\"\n >\n {terminalModeLabel}\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-11\"\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 data-opengeni-terminal-ready={ready ? \"true\" : \"false\"}\n data-opengeni-terminal-interactive={surfaceState === \"interactive\" ? \"true\" : \"false\"}\n data-opengeni-terminal-state={surfaceState}\n data-opengeni-terminal-status={ptyAttachable ? ptyStatus : \"firehose\"}\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 TriangleAlertIcon,\n Trash2Icon,\n} from \"lucide-react\";\nimport {\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { AlertDialog } from \"radix-ui\";\nimport { VList, type VListHandle } from \"virtua\";\nimport { cn } from \"../lib/cn\";\nimport {\n type PortalTokenStyle,\n usePortalTokenSource,\n usePortalTokenStyle,\n} from \"../lib/use-portal-token-style\";\nimport { useUnicodeFallbackFonts } from \"../lib/use-unicode-fonts\";\nimport type { FileTreeNode, UseSandboxFilesResult } from \"../hooks/use-sandbox-files\";\nimport { visibleFileTree, type FileNodeVisibilityPredicate } from \"../file-node-visibility\";\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 /** Presentation-only node filter. Hidden parents never expose their children. */\n isNodeVisible?: FileNodeVisibilityPredicate | undefined;\n /** Deliberately reveal this selected path by lazily opening every loaded\n * ancestor and scrolling its row into view. The path is opaque and is never\n * normalized or re-rooted here. */\n revealPath?: string | undefined;\n /** Increment/change to reveal the same path again after a user collapses it. */\n revealPathRequestId?: string | number | 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 * The default is an accessible, non-blocking confirmation dialog. Supply this\n * callback to delegate confirmation to a host-owned dialog.\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\nfunction pathIsInsideDirectory(path: string, directory: string): boolean {\n if (!path.startsWith(directory) || path === directory) return false;\n if (directory.endsWith(\"/\") || directory.endsWith(\"\\\\\")) return true;\n const boundary = path[directory.length];\n return boundary === \"/\" || boundary === \"\\\\\";\n}\n\n/** Walk the authoritative tree without assuming its target-owned separator. */\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 && pathIsInsideDirectory(path, node.path)) {\n const hit = findNode(node.children, path);\n if (hit) return hit;\n }\n }\n return undefined;\n}\n\ntype RevealTrace = {\n directories: string[];\n frontier: string | null;\n};\n\n/** Follow only paths already named by the authoritative tree. This deliberately\n * avoids manufacturing ancestors from a platform-specific path string. */\nfunction traceRevealPath(nodes: FileTreeNode[], targetPath: string): RevealTrace {\n for (const node of nodes) {\n if (node.path === targetPath) {\n return {\n directories: node.kind === \"dir\" ? [node.path] : [],\n frontier: node.kind === \"dir\" && node.children === undefined ? node.path : null,\n };\n }\n if (node.kind !== \"dir\" || !pathIsInsideDirectory(targetPath, node.path)) continue;\n if (node.children === undefined) {\n return { directories: [node.path], frontier: node.path };\n }\n const child = traceRevealPath(node.children, targetPath);\n return {\n directories: [node.path, ...child.directories],\n frontier: child.frontier,\n };\n }\n return { directories: [], frontier: null };\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 isNodeVisible,\n revealPath,\n revealPathRequestId,\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 [pendingDelete, setPendingDelete] = useState<FileTreeNode | null>(null);\n const [busy, setBusy] = useState(false);\n const [coarsePointer, setCoarsePointer] = useState(false);\n const [revealRequest, setRevealRequest] = useState<{\n path: string;\n requestId: string | number;\n } | null>(null);\n const handledRevealRequestRef = useRef<{\n path: string;\n requestId: string | number;\n } | null>(null);\n const attemptedRevealPathsRef = useRef<Set<string>>(new Set());\n const treeId = useId();\n const container = usePortalTokenSource<HTMLDivElement>();\n const containerRef = container.currentRef;\n const deleteReturnFocusRef = useRef<HTMLElement | null>(null);\n const vlistRef = useRef<VListHandle>(null);\n const portalTokenStyle = usePortalTokenStyle(container.source);\n const getTreeElement = useCallback(\n () => (typeof document === \"undefined\" ? null : document.getElementById(treeId)),\n [treeId],\n );\n const visibleTree = useMemo(\n () => visibleFileTree(result.tree, isNodeVisible),\n [isNodeVisible, result.tree],\n );\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 const effectiveRevealRequestId = revealPath ? (revealPathRequestId ?? revealPath) : null;\n useEffect(() => {\n if (!revealPath || effectiveRevealRequestId === null) {\n setRevealRequest(null);\n return;\n }\n const handled = handledRevealRequestRef.current;\n if (handled?.path === revealPath && handled.requestId === effectiveRevealRequestId) return;\n handledRevealRequestRef.current = {\n path: revealPath,\n requestId: effectiveRevealRequestId,\n };\n attemptedRevealPathsRef.current = new Set();\n setActive(null);\n setRevealRequest({ path: revealPath, requestId: effectiveRevealRequestId });\n }, [effectiveRevealRequestId, revealPath]);\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 visibleActive = active && findNode(visibleTree, active) ? active : null;\n const cursor =\n visibleActive ?? (selectedPath && findNode(visibleTree, selectedPath) ? selectedPath : null);\n useEffect(() => {\n if (active !== null && visibleActive === null) setActive(null);\n }, [active, visibleActive]);\n\n const expand = useCallback(\n async (path: string) => {\n const node = findNode(visibleTree, 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, visibleTree],\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 useEffect(() => {\n if (!revealRequest) return;\n const trace = traceRevealPath(visibleTree, revealRequest.path);\n if (trace.directories.length > 0) {\n setExpanded((previous) => {\n const next = new Set(previous);\n let changed = false;\n for (const path of trace.directories) {\n if (next.has(path)) continue;\n next.add(path);\n changed = true;\n }\n return changed ? next : previous;\n });\n }\n const frontier = trace.frontier;\n if (\n !frontier ||\n attemptedRevealPathsRef.current.has(frontier) ||\n loadingPaths.has(frontier) ||\n result.expandingPaths.has(frontier)\n ) {\n return;\n }\n attemptedRevealPathsRef.current.add(frontier);\n void expand(frontier);\n }, [expand, loadingPaths, result.expandingPaths, revealRequest, visibleTree]);\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(visibleTree, 0);\n return items;\n }, [visibleTree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);\n const unicodeFontPaths = useMemo(\n () => renderItems.flatMap((item) => (item.type === \"node\" ? [item.node.path] : [])),\n [renderItems],\n );\n useUnicodeFallbackFonts(unicodeFontPaths);\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 const rowIndexByPath = useMemo(\n () => new Map(flatRows.map((row, index) => [row.node.path, index] as const)),\n [flatRows],\n );\n const treePositionByPath = useMemo(() => {\n const positions = new Map<string, { position: number; setSize: number }>();\n const visit = (nodes: FileTreeNode[]) => {\n nodes.forEach((node, index) => {\n positions.set(node.path, { position: index + 1, setSize: nodes.length });\n if (node.children) visit(node.children);\n });\n };\n visit(visibleTree);\n return positions;\n }, [visibleTree]);\n const cursorIndex = cursor ? (rowIndexByPath.get(cursor) ?? -1) : -1;\n const activeDescendantId = cursorIndex >= 0 ? `${treeId}-item-${cursorIndex}` : undefined;\n\n // A capture is immutable review data even if a stale capability document still\n // says the machine is writable. Mutations become available only after a live\n // reconciliation has actually succeeded.\n const supportsMutation =\n editable && result.source === \"live\" && result.error === null && !result.loading;\n\n const performDelete = useCallback(\n async (node: FileTreeNode) => {\n if (!supportsMutation) return;\n const recursive = node.kind === \"dir\";\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, result],\n );\n\n const runDelete = useCallback(\n async (node: FileTreeNode, returnFocus?: HTMLElement) => {\n if (!supportsMutation) return;\n setMenu(null);\n if (!confirmDelete) {\n deleteReturnFocusRef.current =\n returnFocus ??\n (typeof document !== \"undefined\" && document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null);\n setPendingDelete(node);\n return;\n }\n if (await confirmDelete(node)) await performDelete(node);\n },\n [supportsMutation, confirmDelete, performDelete],\n );\n\n const closePendingDelete = useCallback(\n (restoreTrigger: boolean) => {\n const returnTarget = restoreTrigger ? deleteReturnFocusRef.current : getTreeElement();\n deleteReturnFocusRef.current = null;\n setPendingDelete(null);\n if (typeof window !== \"undefined\") {\n window.requestAnimationFrame(() => {\n const target = returnTarget?.isConnected ? returnTarget : getTreeElement();\n target?.focus();\n });\n }\n },\n [getTreeElement],\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(visibleTree, 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, visibleTree],\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(visibleTree, 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, open, visibleTree],\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(visibleTree, 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, visibleTree],\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 \"Home\":\n move(0);\n break;\n case \"End\":\n move(flatRows.length - 1);\n break;\n case \"PageDown\": {\n const pageSize = Math.max(\n 1,\n Math.floor((containerRef.current?.clientHeight || 280) / (coarsePointer ? 44 : 28)) - 1,\n );\n move((idx < 0 ? 0 : idx) + pageSize);\n break;\n }\n case \"PageUp\": {\n const pageSize = Math.max(\n 1,\n Math.floor((containerRef.current?.clientHeight || 280) / (coarsePointer ? 44 : 28)) - 1,\n );\n move((idx < 0 ? 0 : idx) - pageSize);\n break;\n }\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 \"ContextMenu\":\n case \"F10\":\n if (cur && supportsMutation && (e.key === \"ContextMenu\" || e.shiftKey)) {\n const rowIndex = rowIndexByPath.get(cur.node.path) ?? 0;\n const row = document.getElementById(`${treeId}-item-${rowIndex}`);\n const rect = row?.getBoundingClientRect();\n setMenu({\n node: cur.node,\n x: rect ? rect.left + Math.min(32, rect.width / 2) : 8,\n y: rect ? rect.bottom : 8,\n });\n e.preventDefault();\n } else if (e.key === \"F10\") {\n break;\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 coarsePointer,\n containerRef,\n rowIndexByPath,\n treeId,\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 && visibleTree.length === 0 && !draftCreate;\n const showDegradedTree = result.error && visibleTree.length > 0;\n const showEmpty = !result.loading && visibleTree.length === 0 && !draftCreate;\n // Retry lives next to the state it explains (the degraded/empty notice), so do\n // not render a second toolbar retry for the same failure.\n const showToolbar = supportsMutation || result.loading;\n // Virtua caches the previous visible range when a lazy-expanded subtree is\n // inserted in the middle of a short list. The spacer grows but later root\n // siblings can remain unmounted until a scroll/resize (for example,\n // `.bash_history` vanished after expanding `repositories/<repo>`). Small\n // trees do not benefit from virtualization, so render them directly and keep\n // Virtua only for genuinely large workspaces.\n const usesVirtualTree = !showErrorEmpty && !showEmpty && renderItems.length > 500;\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 const treePosition = treePositionByPath.get(node.path);\n\n return (\n <div\n id={`${treeId}-item-${rowIndexByPath.get(node.path) ?? 0}`}\n role=\"treeitem\"\n aria-level={depth + 1}\n aria-posinset={treePosition?.position}\n aria-setsize={treePosition?.setSize}\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 tabIndex={-1}\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 useEffect(() => {\n if (!revealRequest) return;\n const index = renderItems.findIndex(\n (item) => item.type === \"node\" && item.node.path === revealRequest.path,\n );\n if (index < 0) return;\n if (usesVirtualTree) {\n vlistRef.current?.scrollToIndex(index);\n } else {\n document.getElementById(`${treeId}-item-${index}`)?.scrollIntoView?.({ block: \"nearest\" });\n }\n setRevealRequest((current) =>\n current?.path === revealRequest.path && current.requestId === revealRequest.requestId\n ? null\n : current,\n );\n }, [renderItems, revealRequest, treeId, usesVirtualTree]);\n\n return (\n <div className={cn(\"flex min-h-0 min-w-0 flex-col\", className)}>\n {showToolbar && (\n <div\n role=\"toolbar\"\n aria-label=\"File actions\"\n className=\"flex shrink-0 flex-wrap items-center gap-0.5 border-b border-og-border px-1 py-1\"\n >\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(visibleTree, 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={(event) => {\n const node = cursor ? findNode(visibleTree, cursor) : undefined;\n if (node) void runDelete(node, event.currentTarget);\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 {showDegradedTree ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n data-opengeni-files-degraded\n className=\"flex shrink-0 items-center gap-2 border-b border-og-status-running/30 bg-og-status-running/10 px-2 py-1.5 text-og-xs text-og-fg-muted\"\n >\n <TriangleAlertIcon className=\"size-3.5 shrink-0 text-og-status-running\" aria-hidden />\n <span className=\"min-w-0 flex-1\">\n {result.source === \"capture\"\n ? \"Live files are temporarily unavailable. Showing the latest captured revision.\"\n : \"Live refresh failed. Showing the last loaded files.\"}\n </span>\n <button\n type=\"button\"\n onClick={() => void result.refresh()}\n disabled={result.loading}\n className=\"inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n <RefreshCwIcon\n className={cn(\"size-3\", result.loading && \"animate-spin motion-reduce:animate-none\")}\n aria-hidden\n />\n Retry\n </button>\n </div>\n ) : null}\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={container.ref}\n onFocus={(event) => {\n if ((event.target as HTMLElement).id === treeId && cursorIndex < 0) {\n const first = flatRows[0];\n if (first) setActive(first.node.path);\n }\n }}\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\",\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-11\"\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 ) : !usesVirtualTree ? (\n <div\n id={treeId}\n role=\"tree\"\n aria-label=\"Workspace files\"\n aria-activedescendant={activeDescendantId}\n aria-multiselectable={false}\n tabIndex={0}\n className=\"min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\n >\n {renderItems.map((item) => (\n <div key={itemKey(item)} className=\"min-w-0\">\n {renderItem(item)}\n </div>\n ))}\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 id={treeId}\n role=\"tree\"\n aria-label=\"Workspace files\"\n aria-activedescendant={activeDescendantId}\n aria-multiselectable={false}\n tabIndex={0}\n className=\"min-h-0 flex-1 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\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 onClose={() => {\n setMenu(null);\n window.requestAnimationFrame(() => getTreeElement()?.focus());\n }}\n />\n )}\n {pendingDelete ? (\n <DeleteDialog\n node={pendingDelete}\n busy={busy}\n portalTokenStyle={portalTokenStyle}\n onCancel={() => closePendingDelete(true)}\n onConfirm={() => {\n const node = pendingDelete;\n closePendingDelete(false);\n void performDelete(node);\n }}\n />\n ) : null}\n </div>\n );\n}\n\nfunction DeleteDialog({\n node,\n busy,\n portalTokenStyle,\n onCancel,\n onConfirm,\n}: {\n node: FileTreeNode;\n busy: boolean;\n portalTokenStyle: PortalTokenStyle;\n onCancel: () => void;\n onConfirm: () => void;\n}) {\n const cancelRef = useRef<HTMLButtonElement | null>(null);\n const [open, setOpen] = useState(true);\n const closeIntentRef = useRef<\"cancel\" | \"confirm\">(\"cancel\");\n const settledRef = useRef(false);\n const settleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const settle = () => {\n if (settledRef.current) return;\n settledRef.current = true;\n if (closeIntentRef.current === \"confirm\") {\n onConfirm();\n } else {\n onCancel();\n }\n };\n\n const scheduleSettle = () => {\n if (settleTimerRef.current !== null) return;\n settleTimerRef.current = setTimeout(() => {\n settleTimerRef.current = null;\n settle();\n }, 0);\n };\n\n useEffect(\n () => () => {\n if (settleTimerRef.current !== null) clearTimeout(settleTimerRef.current);\n },\n [],\n );\n\n return (\n <AlertDialog.Root\n open={open}\n onOpenChange={(nextOpen) => {\n if (!nextOpen && !busy) {\n setOpen(false);\n scheduleSettle();\n }\n }}\n >\n <AlertDialog.Portal container={typeof document === \"undefined\" ? null : document.body}>\n <AlertDialog.Overlay className=\"og-root fixed inset-0 z-[100] bg-black/45 backdrop-blur-[2px]\" />\n <AlertDialog.Content\n className=\"og-root fixed left-1/2 top-1/2 z-[101] max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-sm -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-og-lg border border-og-border-strong bg-og-surface-1 p-4 text-og-fg shadow-2xl outline-hidden\"\n style={portalTokenStyle}\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n cancelRef.current?.focus();\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n scheduleSettle();\n }}\n onEscapeKeyDown={(event) => {\n event.stopPropagation();\n if (busy) {\n event.preventDefault();\n } else {\n closeIntentRef.current = \"cancel\";\n }\n }}\n >\n <div className=\"flex items-start gap-3\">\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-full bg-og-status-failed/12 text-og-status-failed\">\n <Trash2Icon className=\"size-4\" aria-hidden />\n </span>\n <div className=\"min-w-0\">\n <AlertDialog.Title className=\"text-og-sm font-semibold\">\n Delete {node.kind === \"dir\" ? \"folder\" : \"file\"}?\n </AlertDialog.Title>\n <AlertDialog.Description className=\"mt-1 text-og-sm leading-relaxed text-og-fg-muted\">\n <span className=\"break-all font-og-mono text-og-fg\">{node.path}</span>\n {node.kind === \"dir\"\n ? \" and everything inside it will be permanently removed.\"\n : \" will be permanently removed.\"}\n </AlertDialog.Description>\n </div>\n </div>\n <div className=\"mt-4 flex justify-end gap-2\">\n <AlertDialog.Cancel asChild>\n <button\n ref={cancelRef}\n type=\"button\"\n onClick={() => {\n closeIntentRef.current = \"cancel\";\n }}\n disabled={busy}\n className=\"min-h-9 rounded-og-md border border-og-border px-3 text-og-sm font-medium text-og-fg hover:bg-og-surface-2 disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n Cancel\n </button>\n </AlertDialog.Cancel>\n <AlertDialog.Action asChild>\n <button\n type=\"button\"\n onClick={() => {\n closeIntentRef.current = \"confirm\";\n }}\n disabled={busy}\n className=\"min-h-9 rounded-og-md bg-og-status-failed px-3 text-og-sm font-semibold text-white shadow-sm hover:brightness-110 disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n Delete permanently\n </button>\n </AlertDialog.Action>\n </div>\n </AlertDialog.Content>\n </AlertDialog.Portal>\n </AlertDialog.Root>\n );\n}\n\nfunction ToolbarButton({\n label,\n onClick,\n disabled,\n children,\n}: {\n label: string;\n onClick: (event: ReactMouseEvent<HTMLButtonElement>) => 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-hidden\",\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 onClose,\n}: {\n node: FileTreeNode;\n x: number;\n y: number;\n onRename: () => void;\n onDelete: () => void;\n onNewFile: () => void;\n onNewFolder: () => void;\n onClose: () => void;\n}) {\n const isDir = node.kind === \"dir\";\n const menuRef = useRef<HTMLDivElement | null>(null);\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.max(4, Math.min(x, vw - 180));\n const top = Math.max(4, Math.min(y, vh - 160));\n\n useEffect(() => {\n menuRef.current?.querySelector<HTMLButtonElement>('[role=\"menuitem\"]')?.focus();\n }, []);\n\n const onKeyDown = (event: ReactKeyboardEvent<HTMLDivElement>) => {\n const items = Array.from(\n menuRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"menuitem\"]') ?? [],\n );\n if (items.length === 0) return;\n const current = items.findIndex((item) => item === document.activeElement);\n let next: number | null = null;\n if (event.key === \"ArrowDown\") next = (current + 1 + items.length) % items.length;\n else if (event.key === \"ArrowUp\") next = (current - 1 + items.length) % items.length;\n else if (event.key === \"Home\") next = 0;\n else if (event.key === \"End\") next = items.length - 1;\n else if (event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n onClose();\n return;\n }\n if (next === null) return;\n event.preventDefault();\n event.stopPropagation();\n items[next]?.focus();\n };\n\n const item = (label: string, icon: ReactNode, onClick: () => void, danger?: boolean) => (\n <button\n type=\"button\"\n role=\"menuitem\"\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-11\",\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 ref={menuRef}\n role=\"menu\"\n aria-label={`Actions for ${node.name}`}\n onKeyDown={onKeyDown}\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 role=\"separator\" 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 { useEffect, useMemo } from \"react\";\n\nexport type UnicodeFontNeeds = {\n japanese: boolean;\n arabic: boolean;\n};\n\nconst japaneseScript = /[\\u3040-\\u30ff\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff]/u;\nconst arabicScript = /[\\u0600-\\u06ff\\u0750-\\u077f\\u0870-\\u08ff\\ufb50-\\ufdff\\ufe70-\\ufefc]/u;\n\nexport function detectUnicodeFontNeeds(values: Iterable<string>): UnicodeFontNeeds {\n let japanese = false;\n let arabic = false;\n for (const value of values) {\n japanese ||= japaneseScript.test(value);\n arabic ||= arabicScript.test(value);\n if (japanese && arabic) break;\n }\n return { japanese, arabic };\n}\n\n/**\n * Load large script-specific font manifests only when visible workspace content\n * needs them. Fontsource splits the actual glyphs by unicode-range, so Chromium\n * then fetches only the small shards used by the path instead of charging every\n * Latin-only session for the complete font.\n */\nexport function useUnicodeFallbackFonts(values: readonly string[]): void {\n const content = useMemo(() => collectUnicodeContent(values), [values]);\n useEffect(() => {\n if (content.japanese) {\n void import(\"./noto-sans-jp-loader.generated\")\n .then(({ loadNotoSansJp }) => loadNotoSansJp(content.japanese))\n .catch(() => undefined);\n }\n if (content.arabic) {\n void import(\"./noto-sans-arabic-loader\")\n .then(({ loadNotoSansArabic }) => loadNotoSansArabic())\n .catch(() => undefined);\n }\n }, [content.arabic, content.japanese]);\n}\n\nfunction collectUnicodeContent(values: Iterable<string>): {\n japanese: string;\n arabic: string;\n} {\n const japanese = new Set<string>();\n const arabic = new Set<string>();\n for (const value of values) {\n for (const character of value) {\n if (japaneseScript.test(character)) japanese.add(character);\n if (arabicScript.test(character)) arabic.add(character);\n }\n }\n return { japanese: [...japanese].join(\"\"), arabic: [...arabic].join(\"\") };\n}\n","import type { GitFileDiff } from \"@opengeni/sdk\";\nimport { ArrowUpRightIcon, FileWarningIcon, HistoryIcon } from \"lucide-react\";\nimport {\n Component,\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { VList, type VListHandle } from \"virtua\";\nimport { cn } from \"../lib/cn\";\nimport { useUnicodeFallbackFonts } from \"../lib/use-unicode-fonts\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport { formatAsOf } from \"../hooks/use-machine-chip\";\nimport type { SandboxGitFileDiff } from \"../hooks/use-sandbox-git\";\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 repository when metadata is\n available, otherwise by top-level directory for a large legacy input) on the\n 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 (D2). A per-file size guard (binary / diff too\n large) degrades to an \"open live\" affordance instead of a diff body.\n\n Workspace-wide Git results carry an explicit `repoRoot`, so grouping never\n guesses repository ownership from a directory name. Multi-repo results group\n at every size; legacy unscoped inputs group by top-level directory only past\n the threshold.\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\nfunction compactFileLabel(file: SandboxGitFileDiff): string {\n const slash = file.path.lastIndexOf(\"/\");\n const basename = slash >= 0 ? file.path.slice(slash + 1) : file.path;\n const parent = slash >= 0 ? file.path.slice(0, slash + 1) : \"\";\n return `${STATUS_LETTER[file.status]} · ${basename}${parent ? ` — ${parent}` : \"\"}`;\n}\n\nexport type WorkbenchChangesProps = {\n /** The changed files (`useSandboxGit().diff`). Assumed non-empty by the caller. */\n diff: SandboxGitFileDiff[];\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 /** Route a guarded binary/oversize file into the live Files surface. */\n onOpenFile?: ((path: string) => void) | undefined;\n className?: string | undefined;\n};\n\ntype RailRow =\n | { kind: \"group\"; label: string; count: number }\n | { kind: \"file\"; file: SandboxGitFileDiff; index: number };\n\ntype ChangesRailVListProps = {\n children: ReactNode;\n className: string;\n coarsePointer: boolean;\n files: readonly SandboxGitFileDiff[];\n rowCount: number;\n};\n\ntype ChangesRailVListState = {\n renderedRowCount: number;\n resetVersion: number;\n};\n\ntype ChangesRailSnapshot = {\n focusedPath: string | null;\n scrollOffset: number;\n};\n\n/** Virtua must reset its cached range when the rail shrinks. Keep that remount\n * scoped to shrink transitions and preserve the reader's focus/scroll context. */\nclass ChangesRailVList extends Component<\n ChangesRailVListProps,\n ChangesRailVListState,\n ChangesRailSnapshot | null\n> {\n state: ChangesRailVListState = {\n renderedRowCount: this.props.rowCount,\n resetVersion: 0,\n };\n\n private host: HTMLDivElement | null = null;\n private listHandle: VListHandle | null = null;\n private pendingFocusedPath: string | null = null;\n private restoreFrame: number | null = null;\n\n static getDerivedStateFromProps(\n props: ChangesRailVListProps,\n state: ChangesRailVListState,\n ): ChangesRailVListState | null {\n if (props.rowCount === state.renderedRowCount) return null;\n return {\n renderedRowCount: props.rowCount,\n resetVersion:\n props.rowCount < state.renderedRowCount ? state.resetVersion + 1 : state.resetVersion,\n };\n }\n\n getSnapshotBeforeUpdate(\n _previousProps: ChangesRailVListProps,\n previousState: ChangesRailVListState,\n ): ChangesRailSnapshot | null {\n if (previousState.resetVersion === this.state.resetVersion) return null;\n const scroller = this.host?.firstElementChild;\n if (!(scroller instanceof HTMLElement)) return null;\n const active = document.activeElement;\n const focusedRow =\n active instanceof HTMLElement && scroller.contains(active)\n ? active.closest<HTMLElement>(\"[data-rail-file-path]\")\n : null;\n return {\n focusedPath: focusedRow?.dataset.railFilePath ?? this.pendingFocusedPath,\n scrollOffset: scroller.scrollTop,\n };\n }\n\n componentDidUpdate(\n _previousProps: ChangesRailVListProps,\n _previousState: ChangesRailVListState,\n snapshot: ChangesRailSnapshot | null,\n ): void {\n if (!snapshot || !this.listHandle) return;\n this.cancelRestoreFrame();\n const maxOffset = Math.max(0, this.listHandle.scrollSize - this.listHandle.viewportSize);\n this.listHandle.scrollTo(Math.min(Math.max(snapshot.scrollOffset, 0), maxOffset));\n const focusedPath = snapshot.focusedPath;\n if (!focusedPath) return;\n this.pendingFocusedPath = focusedPath;\n this.continueFocusRestore();\n }\n\n componentWillUnmount(): void {\n this.cancelRestoreFrame();\n this.pendingFocusedPath = null;\n }\n\n private cancelRestoreFrame(): void {\n if (this.restoreFrame === null) return;\n if (typeof cancelAnimationFrame === \"function\") cancelAnimationFrame(this.restoreFrame);\n this.restoreFrame = null;\n }\n\n private continueFocusRestore = (): void => {\n const path = this.pendingFocusedPath;\n if (!path) return;\n if (this.restoreFocusedPath(path)) {\n this.pendingFocusedPath = null;\n return;\n }\n if (this.restoreFrame === null && typeof requestAnimationFrame === \"function\") {\n this.restoreFrame = requestAnimationFrame(() => {\n this.restoreFrame = null;\n this.continueFocusRestore();\n });\n }\n };\n\n private restoreFocusedPath(path: string): boolean {\n const host = this.host;\n if (!host) return true;\n const active = document.activeElement;\n if (active instanceof HTMLElement && active.isConnected && active !== document.body) {\n return true;\n }\n if (!this.props.files.some((file) => file.path === path)) return true;\n const row = Array.from(host.querySelectorAll<HTMLButtonElement>(\"[data-rail-file-path]\")).find(\n (candidate) => candidate.dataset.railFilePath === path,\n );\n if (!row) return false;\n row.focus({ preventScroll: true });\n return true;\n }\n\n private setHost = (host: HTMLDivElement | null): void => {\n this.host = host;\n };\n\n private setListHandle = (handle: VListHandle | null): void => {\n this.listHandle = handle;\n };\n\n render() {\n return (\n <div ref={this.setHost} data-opengeni-changes-rail className={this.props.className}>\n <VList\n key={this.state.resetVersion}\n ref={this.setListHandle}\n className=\"h-full\"\n itemSize={this.props.coarsePointer ? 44 : 28}\n ssrCount={Math.min(30, this.props.rowCount)}\n >\n {this.props.children}\n </VList>\n </div>\n );\n }\n}\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: SandboxGitFileDiff[]): {\n orderedFiles: SandboxGitFileDiff[];\n rows: RailRow[];\n grouped: boolean;\n} {\n const roots = new Set(\n files.flatMap((file) => (file.repoRoot === undefined ? [] : [file.repoRoot])),\n );\n const groupByRepo = roots.size > 1;\n if (!groupByRepo && files.length <= GROUP_THRESHOLD) {\n return {\n orderedFiles: files,\n rows: files.map((file, index) => ({ kind: \"file\", file, index })),\n grouped: false,\n };\n }\n const groups = new Map<string, SandboxGitFileDiff[]>();\n for (const file of files) {\n const slash = file.path.indexOf(\"/\");\n const key = groupByRepo\n ? file.repoRoot || \"(workspace)\"\n : slash > 0\n ? file.path.slice(0, slash)\n : \"(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: SandboxGitFileDiff[] = [];\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, grouped: true };\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 onOpenFile,\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 unicodeFontPaths = useMemo(\n () => diff.flatMap((file) => (file.oldPath ? [file.path, file.oldPath] : [file.path])),\n [diff],\n );\n useUnicodeFallbackFonts(unicodeFontPaths);\n\n const { orderedFiles, rows, grouped } = useMemo(() => buildRail(diff), [diff]);\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) {\n return;\n }\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\n className={cn(\n \"flex shrink-0 items-center justify-between gap-2 border-b border-og-border px-3 py-1.5\",\n compact && source === \"capture\" && \"flex-col items-stretch gap-1.5 py-2\",\n )}\n >\n <span\n role=\"status\"\n aria-atomic=\"true\"\n aria-live=\"polite\"\n data-contrast-audited\n className=\"min-w-0 text-og-xs text-og-fg-muted\"\n >\n {diff.length} {diff.length === 1 ? \"file\" : \"files\"} changed\n <span data-contrast-audited className=\"ml-2 text-og-status-idle\">\n +{additions}\n </span>\n <span data-contrast-audited className=\"ml-1 text-og-status-failed\">\n −{deletions}\n </span>\n </span>\n <div\n className={cn(\n \"flex shrink-0 items-center gap-2\",\n compact && source === \"capture\" && \"self-start\",\n )}\n >\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 title={activeFile?.path}\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-hidden 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 {compactFileLabel(file)}\n </option>\n ))}\n </select>\n </div>\n <div\n aria-label=\"Changed file diff\"\n className=\"min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\n data-opengeni-changes-pane\n role=\"region\"\n tabIndex={0}\n >\n {activeFile ? (\n <DiffSection\n file={activeFile}\n layout=\"unified\"\n themeType={resolvedTheme}\n {...(onOpenFile ? { onOpenFile } : {})}\n />\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 <ChangesRailVList\n rowCount={rows.length}\n coarsePointer={coarsePointer}\n files={orderedFiles}\n className=\"w-[clamp(12rem,28%,15rem)] shrink-0 border-r border-og-border bg-og-surface-1/35\"\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-og-xs 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 </ChangesRailVList>\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 aria-label=\"Changed files diff\"\n className=\"min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\"\n data-opengeni-changes-pane\n role=\"region\"\n tabIndex={0}\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\n file={file}\n layout={layout}\n themeType={resolvedTheme}\n {...(onOpenFile ? { onOpenFile } : {})}\n />\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-og-xs 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-og-xs text-og-fg-subtle\">\n {label}\n </span>\n );\n}\n\n/** \"Live diff\" · \"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 diff\";\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: SandboxGitFileDiff;\n grouped: boolean;\n active: boolean;\n onClick: () => void;\n}) {\n // A real repository group strips the exact repo root. Legacy top-directory\n // grouping strips only that first segment.\n const repoPrefix = file.repoRoot ? `${file.repoRoot}/` : null;\n const shown = grouped\n ? file.repoRoot !== undefined\n ? repoPrefix && file.path.startsWith(repoPrefix)\n ? file.path.slice(repoPrefix.length)\n : file.path\n : file.path.slice(file.path.indexOf(\"/\") + 1) || file.path\n : file.path;\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={file.path}\n data-rail-file\n data-rail-file-path={file.path}\n className={cn(\n \"relative flex min-h-7 w-full items-center gap-1.5 truncate px-2 py-0.5 text-left text-og-sm transition-colors hover:bg-og-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent pointer-coarse:min-h-11\",\n grouped && \"pl-3\",\n active &&\n \"bg-og-accent-soft text-og-fg before:absolute before:inset-y-1 before:left-0 before:w-0.5 before:rounded-r-full before:bg-og-accent\",\n )}\n >\n <span\n data-contrast-audited\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-og-xs\">\n <span data-contrast-audited className=\"text-og-status-idle\">\n +{file.additions}\n </span>\n <span data-contrast-audited className=\"text-og-status-failed\">\n −{file.deletions}\n </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 onOpenFile,\n}: {\n file: GitFileDiff;\n layout: \"unified\" | \"split\";\n themeType: \"dark\" | \"light\";\n onOpenFile?: ((path: string) => void) | undefined;\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-og-xs\">\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} {...(onOpenFile ? { onOpenFile } : {})} />\n </section>\n );\n }\n return (\n <section data-pierre-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({\n file,\n onOpenFile,\n}: {\n file: GitFileDiff;\n onOpenFile?: ((path: string) => void) | undefined;\n}) {\n const reason = file.isBinary ? \"Binary file\" : \"Diff too large to show here\";\n return (\n <div className=\"flex flex-wrap items-center gap-2 px-3 py-3 text-og-sm text-og-fg-subtle\">\n <FileWarningIcon className=\"size-3.5 shrink-0\" aria-hidden />\n <span className=\"min-w-0 flex-1\">{reason}.</span>\n {onOpenFile ? (\n <button\n type=\"button\"\n onClick={() => onOpenFile(file.path)}\n className=\"inline-flex min-h-8 shrink-0 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:bg-og-surface-2 hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-11\"\n >\n Open in Files\n <ArrowUpRightIcon className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\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-og-xs capitalize focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-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 (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 (known layout risk). 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 when the estimate function changes as well as when the count changes.\n // A replacement diff can contain the same number of files but radically\n // different section sizes; retaining measurements by index would then place\n // every unvisited section at an offset belonging to the previous diff.\n useEffect(() => {\n setHeights((prev) => {\n const next = Array.from({ length: count }, (_, i) => estimateHeight(i));\n return prev.length === next.length && prev.every((height, index) => height === next[index])\n ? prev\n : next;\n });\n }, [count, estimateHeight]);\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 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 /** Target 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 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\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 /**\n * Persist the current buffer against the exact contents it was edited from.\n * The second argument is the immutable compare-and-swap baseline; hosts must\n * not replace it with a newer remote snapshot or concurrent writes can be\n * silently overwritten.\n */\n onSave: (contents: string, expectedContents: string) => Promise<unknown>;\n /** Explicitly overwrite after a visible expected-content conflict. */\n onOverwrite?: ((contents: string) => Promise<unknown>) | undefined;\n /** Re-read the selected file after a visible save conflict. */\n onReload?: (() => void) | undefined;\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\nexport type EditorBufferState = {\n path: string;\n value: string;\n baseline: string;\n};\n\n/**\n * Reconcile a remote file snapshot without destroying unsaved local work.\n *\n * A different path is a new document and always resets. For the same path, a\n * clean editor follows the remote snapshot while a dirty editor retains both\n * its local value and the original CAS baseline. The eventual save will then\n * either succeed against that baseline or surface a typed conflict.\n */\nexport function reconcileEditorBuffer(\n current: EditorBufferState,\n incoming: { path: string; contents: string },\n): EditorBufferState {\n if (current.path === incoming.path && current.value !== current.baseline) {\n return current;\n }\n if (\n current.path === incoming.path &&\n current.value === incoming.contents &&\n current.baseline === incoming.contents\n ) {\n return current;\n }\n return {\n path: incoming.path,\n value: incoming.contents,\n baseline: incoming.contents,\n };\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 onOverwrite,\n onReload,\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 and its compare-and-swap baseline are one state value so a\n // remote refresh cannot update one without the other.\n const [buffer, setBuffer] = useState<EditorBufferState>(() => ({\n path,\n value: initialContents,\n baseline: initialContents,\n }));\n const { value, baseline } = buffer;\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<Error | null>(null);\n const [savedTick, setSavedTick] = useState(false);\n const saveInFlightRef = useRef(false);\n\n const dirty = value !== baseline;\n const saveConflict =\n saveError !== null && (saveError as Error & { code?: unknown }).code === \"file_write_conflict\";\n\n // Follow path changes and clean same-file refreshes. Dirty same-file buffers\n // intentionally ignore remote snapshots: the original baseline must survive\n // until guarded save, explicit reload, or navigation.\n const editIntentFiredRef = useRef(false);\n useEffect(() => {\n setBuffer((current) => reconcileEditorBuffer(current, { path, contents: initialContents }));\n }, [path, initialContents]);\n\n // A new document is a new edit-intent/error lifecycle. The normal\n // SandboxFiles host also keys the component by path; this keeps standalone\n // consumers correct without relying on that implementation detail.\n useEffect(() => {\n editIntentFiredRef.current = false;\n setSaveError(null);\n setSavedTick(false);\n }, [path]);\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 setBuffer((current) => ({ ...current, value: 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 // Language peers are optional. A missing grammar must degrade to a plain\n // CodeMirror document, not throw the entire editor down to textarea.\n let languageExtension: unknown | null = null;\n if (langKey) {\n try {\n languageExtension = (await LANGUAGE_LOADERS[langKey]?.()) ?? null;\n } catch {\n languageExtension = null;\n }\n }\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,\n });\n setFailed(false);\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 || saveInFlightRef.current) 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 saveInFlightRef.current = true;\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onSave(snapshot, baseline);\n setBuffer((current) =>\n current.path === path ? { ...current, baseline: snapshot } : current,\n );\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n saveInFlightRef.current = false;\n setSaving(false);\n }\n }, [readOnly, value, baseline, onSave, path]);\n\n const overwrite = useCallback(async () => {\n if (readOnly || !onOverwrite || saveInFlightRef.current) return;\n const snapshot = value;\n if (snapshot === baseline) return;\n saveInFlightRef.current = true;\n setSaving(true);\n setSaveError(null);\n setSavedTick(false);\n try {\n await onOverwrite(snapshot);\n setBuffer((current) =>\n current.path === path ? { ...current, baseline: snapshot } : current,\n );\n setSavedTick(true);\n } catch (cause) {\n setSaveError(cause instanceof Error ? cause : new Error(String(cause)));\n } finally {\n saveInFlightRef.current = false;\n setSaving(false);\n }\n }, [readOnly, onOverwrite, value, baseline, 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 const Editor = bundle?.Editor;\n\n const reload = useCallback(() => {\n setBuffer({ path, value: initialContents, baseline: initialContents });\n editIntentFiredRef.current = false;\n setSaveError(null);\n setSavedTick(false);\n onReload?.();\n }, [initialContents, onReload, path]);\n\n return (\n <div\n className={cn(\"flex h-full min-h-0 flex-col\", className)}\n data-opengeni-code-editor\n data-opengeni-editor-dirty={dirty ? \"true\" : \"false\"}\n style={editorVars}\n >\n {/* Save bar: dirty indicator + status + the explicit Save button. */}\n <div className=\"flex min-h-9 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 && !saveConflict && (\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 && !dirty && (\n <span className=\"text-og-xs text-og-status-idle\">Saved</span>\n )}\n {readOnly ? (\n <span className=\"text-og-xs uppercase tracking-wide text-og-fg-subtle\">Read-only</span>\n ) : !saveConflict ? (\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-11\",\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 ) : null}\n </div>\n </div>\n\n {saveConflict ? (\n <div\n className=\"flex shrink-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-og-status-failed/25 bg-og-status-failed/8 px-2 py-2\"\n role=\"alert\"\n >\n <div className=\"min-w-[12rem] flex-1 text-og-xs text-og-fg-muted\">\n <span className=\"font-medium text-og-status-failed\">File changed on machine.</span>{\" \"}\n Reloading discards your edits; overwriting replaces the live version.\n </div>\n <div className=\"ml-auto flex shrink-0 items-center gap-1.5\">\n {onReload ? (\n <button\n type=\"button\"\n onClick={() => {\n reload();\n }}\n className=\"min-h-8 rounded-og-sm border border-og-border bg-og-surface-1 px-2 text-og-xs font-medium text-og-fg hover:bg-og-surface-2 pointer-coarse:min-h-11\"\n >\n Reload live\n </button>\n ) : null}\n {onOverwrite ? (\n <button\n type=\"button\"\n onClick={() => void overwrite()}\n disabled={saving}\n className=\"min-h-8 rounded-og-sm border border-og-status-failed/40 px-2 text-og-xs font-medium text-og-status-failed hover:bg-og-status-failed/10 disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n Overwrite\n </button>\n ) : null}\n </div>\n </div>\n ) : null}\n\n {/* The editor surface. */}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {failed ? (\n (fallback ?? (\n <PlainTextarea\n value={value}\n readOnly={readOnly}\n onChange={noteEdit}\n onSave={() => void save()}\n />\n ))\n ) : Editor ? (\n <Editor\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 ) : (\n (loading ?? <EditorSkeleton />)\n )}\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 onSave,\n}: {\n value: string;\n readOnly: boolean;\n onChange: (value: string) => void;\n onSave: () => void;\n}) {\n return (\n <textarea\n value={value}\n readOnly={readOnly}\n spellCheck={false}\n onChange={(e) => onChange(e.target.value)}\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"s\") {\n event.preventDefault();\n onSave();\n }\n }}\n aria-label=\"Plain text file editor\"\n className=\"h-full w-full resize-none bg-transparent p-2 font-og-mono text-og-sm text-og-fg outline-hidden\"\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 { FileCode2Icon, FileWarningIcon, LoaderCircleIcon } from \"lucide-react\";\nimport { type ReactNode, useCallback, useEffect, useRef, useState } from \"react\";\nimport { Group, Panel, Separator } from \"react-resizable-panels\";\nimport { cn } from \"../lib/cn\";\nimport { prefersReducedMotion } from \"../lib/motion\";\nimport { useThemeType } from \"../lib/use-theme-type\";\nimport {\n CapturedFileUnavailableError,\n type SandboxFilesGitSummary,\n type UseSandboxFilesResult,\n} from \"../hooks/use-sandbox-files\";\nimport type { UseSandboxGitResult } from \"../hooks/use-sandbox-git\";\nimport { filePathVisibility, type FileNodeVisibilityPredicate } from \"../file-node-visibility\";\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 /** Compatibility fallback for callers that have not yet adopted `files.gitSummary`. */\n git?: UseSandboxGitResult | undefined;\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 /** Restore the file last viewed in this task. Invalid/missing paths still\n * surface the ordinary file-view error instead of changing files silently. */\n initialSelectedPath?: string | null | undefined;\n onSelectedPathChange?: ((path: string | null) => void) | undefined;\n /** Presentation-only node filter shared with the tree and selected-file view. */\n isNodeVisible?: FileNodeVisibilityPredicate | undefined;\n /** A deliberate file-open path routed here by the parent workspace. */\n requestedPath?: string | undefined;\n /** 1-based line to reveal after `requestedPath` opens. */\n requestedLine?: number | null | undefined;\n /** Identity for one guarded-file request. Increment this when the same path is\n * deliberately requested again; it also lets a pending request be consumed\n * without overriding later manual tree navigation. Defaults to the path. */\n requestedPathRequestId?: string | number | undefined;\n /** False while the parent is waking a cold sandbox for `requestedPath`. */\n requestedPathReady?: boolean | undefined;\n /** The machine is cold and no durable capture exists yet. Render an explicit\n * wake gate instead of an empty-tree lie or an implicit Channel-A read. */\n workspaceResting?: boolean | undefined;\n /** A deliberate wake has started but the live file surface is not ready yet. */\n workspaceWaking?: boolean | undefined;\n /** Whether live reads are currently authoritative. */\n liveWorkspaceReady?: boolean | undefined;\n /** Failed live negotiation; never present a failure as an ongoing wake. */\n workspaceError?: Error | null | undefined;\n /** Deliberately wake the machine to read content absent from the capture. */\n onWakeWorkspace?: (() => 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 initialSelectedPath,\n onSelectedPathChange,\n isNodeVisible,\n requestedPath,\n requestedLine,\n requestedPathRequestId,\n requestedPathReady = true,\n workspaceResting = false,\n workspaceWaking = false,\n liveWorkspaceReady = true,\n workspaceError = null,\n onWakeWorkspace,\n themeType,\n className,\n}: SandboxFilesProps) {\n const [selected, setSelected] = useState<string | null>(() => initialSelectedPath ?? 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 const [focusLine, setFocusLine] = useState<number | null>(null);\n const [treeRevealRequest, setTreeRevealRequest] = useState<{\n path: string;\n requestId: string | number;\n } | null>(null);\n const [liveRequestedPath, setLiveRequestedPath] = useState<string | null>(null);\n const [viewReloadRevision, setViewReloadRevision] = useState(0);\n const viewerScrollRef = useRef<HTMLDivElement | null>(null);\n const pendingRequestRef = useRef<string | number | null>(null);\n const handledRequestRef = useRef<string | number | null>(null);\n const requestKey = requestedPath ? (requestedPathRequestId ?? requestedPath) : null;\n\n useEffect(() => {\n if (!requestedPath || requestKey === null) {\n pendingRequestRef.current = null;\n handledRequestRef.current = null;\n setTreeRevealRequest(null);\n return;\n }\n if (handledRequestRef.current === requestKey) {\n return;\n }\n if (!requestedPathReady) {\n pendingRequestRef.current = requestKey;\n setTreeRevealRequest(null);\n return;\n }\n if (isNodeVisible && files.loading && files.tree.length === 0) return;\n if (isNodeVisible && !files.loading && files.tree.length === 0) {\n handledRequestRef.current = requestKey;\n pendingRequestRef.current = null;\n setTreeRevealRequest(null);\n return;\n }\n if (filePathVisibility(files.tree, requestedPath, isNodeVisible) === \"hidden\") {\n handledRequestRef.current = requestKey;\n pendingRequestRef.current = null;\n setTreeRevealRequest(null);\n return;\n }\n handledRequestRef.current = requestKey;\n pendingRequestRef.current = null;\n setSelected(requestedPath);\n onSelectedPathChange?.(requestedPath);\n setEditMode(false);\n setFocusLine(requestedLine != null && requestedLine > 0 ? requestedLine : null);\n setTreeRevealRequest({ path: requestedPath, requestId: requestKey });\n setViewReloadRevision((revision) => revision + 1);\n }, [\n files.loading,\n files.tree,\n isNodeVisible,\n onSelectedPathChange,\n requestKey,\n requestedLine,\n requestedPath,\n requestedPathReady,\n ]);\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) return;\n const update = () => setWide(el.getBoundingClientRect().width >= 720);\n update();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(update);\n observer.observe(el);\n // WorkspaceDock maximization changes its persistent surface from a sized\n // panel child to `fixed inset-0`. Chromium can retain the child's observer\n // size across that containing-block change even though its visible bounding\n // box is now viewport-wide. Follow the surface mode as a deterministic\n // second signal so the tree/viewer orientation matches what is painted.\n const surface = el.closest(\"[data-workspace-surface]\");\n const surfaceObserver =\n surface && typeof MutationObserver !== \"undefined\" ? new MutationObserver(update) : null;\n surfaceObserver?.observe(surface!, {\n attributes: true,\n attributeFilter: [\"class\", \"style\"],\n });\n return () => {\n observer.disconnect();\n surfaceObserver?.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 selectedVisibility = selected\n ? filePathVisibility(files.tree, selected, isNodeVisible)\n : \"unknown\";\n const visibilityPending = Boolean(isNodeVisible && files.loading && files.tree.length === 0);\n const viewPath = selectedVisibility === \"hidden\" || visibilityPending ? null : selected;\n useEffect(() => {\n if (selected === null || selectedVisibility !== \"hidden\") return;\n setSelected(null);\n onSelectedPathChange?.(null);\n setEditMode(false);\n setFocusLine(null);\n setTreeRevealRequest(null);\n setLiveRequestedPath(null);\n }, [onSelectedPathChange, selected, selectedVisibility]);\n const fileView = useFileView(\n viewPath,\n files.readFile,\n `${files.contentRevision ?? 0}:${viewReloadRevision}`,\n );\n\n useEffect(() => {\n if (focusLine === null && viewReloadRevision > 0 && viewerScrollRef.current) {\n viewerScrollRef.current.scrollTop = 0;\n }\n }, [focusLine, viewReloadRevision]);\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. Manual\n // navigation also consumes a pending guarded-file request: a late cold→warm\n // transition must never pull the user away from the file they chose meanwhile.\n const selectFile = useCallback(\n (path: string) => {\n if (pendingRequestRef.current !== null) {\n handledRequestRef.current = pendingRequestRef.current;\n pendingRequestRef.current = null;\n }\n setSelected(path);\n onSelectedPathChange?.(path);\n setEditMode(false);\n setFocusLine(null);\n setTreeRevealRequest(null);\n setLiveRequestedPath(null);\n setViewReloadRevision(0);\n },\n [onSelectedPathChange],\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 const captureFileUnavailable =\n fileView.error instanceof CapturedFileUnavailableError ? fileView.error : null;\n const waitingForSelectedFile =\n !workspaceError &&\n liveRequestedPath === viewPath &&\n (!liveWorkspaceReady || files.loading) &&\n captureFileUnavailable !== null;\n\n if (workspaceError && !liveWorkspaceReady && files.source !== \"capture\") {\n return (\n <Notice className={className} title=\"Could not open live workspace\" announce=\"alert\">\n <p>{workspaceError.message}</p>\n {onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Retry live workspace</WakeButton>\n ) : null}\n </Notice>\n );\n }\n\n if (workspaceResting || workspaceWaking) {\n return (\n <div className={cn(\"h-full\", className)} data-opengeni-workspace-resting>\n <Notice\n icon={\n workspaceWaking ? (\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n ) : (\n <FileCode2Icon className=\"size-5\" aria-hidden />\n )\n }\n title={workspaceWaking ? \"Waking workspace\" : \"Workspace is resting\"}\n announce=\"status\"\n >\n <p>\n {workspaceWaking\n ? \"Connecting to the live file system…\"\n : \"No captured revision is available yet. Wake the sandbox to browse its current files.\"}\n </p>\n {!workspaceWaking && onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Open live workspace</WakeButton>\n ) : null}\n </Notice>\n </div>\n );\n }\n\n if (!fileSystemAvailable) {\n return (\n <Notice\n className={className}\n icon={<FileWarningIcon className=\"size-5\" aria-hidden />}\n title=\"Files unavailable\"\n announce=\"alert\"\n >\n This sandbox does not expose a file system.\n </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 (context; NOT the changed-files list). */}\n <GitHeader\n loading={\n Boolean(files.loading || files.gitLoading || files.source === null || git?.loading) &&\n files.gitSummary === null\n }\n git={\n files.gitSummary ?? {\n branch: git?.branch ?? null,\n isRepo: git?.isRepo ?? false,\n repoCount: git?.repoCount ?? 0,\n ahead: git?.ahead ?? 0,\n behind: git?.behind ?? 0,\n dirtyCount: git?.diff.length ?? 0,\n }\n }\n />\n\n <Group\n orientation={wide ? \"horizontal\" : \"vertical\"}\n className={cn(\"min-h-0 flex-1\", wide ? \"flex-row\" : \"flex-col\")}\n >\n {/* Tree pane: the full lazy file tree. A fixed left column when wide, a top\n band when narrow. */}\n <Panel\n id=\"sandbox-files-tree\"\n defaultSize={wide ? \"280px\" : \"40%\"}\n minSize={wide ? \"180px\" : \"120px\"}\n maxSize={wide ? \"60%\" : \"70%\"}\n className=\"flex min-h-0 min-w-0 flex-col\"\n >\n <FileBrowser\n result={files}\n isNodeVisible={isNodeVisible}\n selectedPath={selected ?? undefined}\n {...(treeRevealRequest\n ? {\n revealPath: treeRevealRequest.path,\n revealPathRequestId: treeRevealRequest.requestId,\n }\n : {})}\n onSelectFile={selectFile}\n editable={editable}\n emptyState=\"This directory is empty\"\n className=\"min-w-0 flex-1\"\n />\n </Panel>\n\n <Separator\n aria-label=\"Resize file tree\"\n className={cn(\n \"group relative z-10 shrink-0 cursor-col-resize outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent\",\n \"w-px bg-og-border after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2\",\n \"hover:bg-og-accent focus-visible:bg-og-accent data-[separator-state=dragging]:bg-og-accent\",\n !wide &&\n \"h-px w-full cursor-row-resize after:inset-x-0 after:inset-y-auto after:top-1/2 after:h-3 after:w-full after:-translate-x-0 after:-translate-y-1/2\",\n )}\n />\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 <Panel\n id=\"sandbox-files-viewer\"\n minSize={wide ? \"240px\" : \"160px\"}\n className={cn(\"flex min-h-0 min-w-0 flex-col\", !wide && \"border-t border-og-border\")}\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\n data-opengeni-selected-file\n className=\"min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted\"\n >\n {selected\n ? focusLine !== null\n ? `${selected}:${focusLine}`\n : selected\n : \"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\n ref={viewerScrollRef}\n className=\"min-h-0 flex-1 overflow-auto\"\n data-opengeni-file-viewer-scroll\n >\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, expectedContents) =>\n files.writeFile(viewPath, contents, { expectedContent: expectedContents })\n }\n onOverwrite={(contents) => files.writeFile(viewPath, contents, { force: true })}\n onReload={() => setViewReloadRevision((revision) => revision + 1)}\n {...(onEditIntent ? { onEditIntent } : {})}\n className=\"h-full\"\n />\n ) : workspaceError &&\n (liveRequestedPath === viewPath || requestedPath === viewPath) &&\n !liveWorkspaceReady ? (\n <Notice title=\"Could not open live file\" announce=\"alert\">\n <p>{workspaceError.message}</p>\n {onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Retry live file</WakeButton>\n ) : null}\n </Notice>\n ) : waitingForSelectedFile ? (\n <Notice\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n title=\"Waking workspace\"\n announce=\"status\"\n >\n Opening {viewPath} when the live file system is ready…\n </Notice>\n ) : captureFileUnavailable ? (\n <Notice icon={<FileCode2Icon className=\"size-5\" aria-hidden />} title=\"On machine\">\n <p>\n {captureFileUnavailable.reason === \"too-large\"\n ? \"This file is larger than the captured preview limit.\"\n : captureFileUnavailable.reason === \"content-missing\"\n ? \"The captured copy is no longer available.\"\n : \"This file was indexed, but it was not changed in the captured turn.\"}\n </p>\n {onWakeWorkspace ? (\n <WakeButton\n onClick={() => {\n setLiveRequestedPath(viewPath);\n if (liveWorkspaceReady) void files.refresh();\n else onWakeWorkspace();\n }}\n >\n {liveWorkspaceReady ? \"Retry live file\" : \"Open live file\"}\n </WakeButton>\n ) : null}\n </Notice>\n ) : fileView.error ? (\n <Notice announce=\"alert\">\n Could not open {viewPath}: {fileView.error.message}\n </Notice>\n ) : fileView.loading ? (\n <Notice announce=\"status\">Loading {viewPath}…</Notice>\n ) : fileView.imageUrl ? (\n <RasterFilePreview\n key={fileView.imageUrl}\n src={fileView.imageUrl}\n path={viewPath}\n />\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 && focusLine === null ? (\n <PierreFile\n key={`${viewPath}:${viewReloadRevision}`}\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 ) : focusLine !== null ? (\n <LineNumberedFile\n path={viewPath}\n contents={fileView.content}\n focusLine={focusLine}\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 announce=\"status\">Loading {viewPath}…</Notice>\n )\n ) : // Nothing selected — the tree shows the whole workspace; pick a file.\n requestedPath && !requestedPathReady ? (\n workspaceError ? (\n <Notice title=\"Could not open live file\" announce=\"alert\">\n <p>{workspaceError.message}</p>\n {onWakeWorkspace ? (\n <WakeButton onClick={onWakeWorkspace}>Retry live file</WakeButton>\n ) : null}\n </Notice>\n ) : (\n <Notice\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n title=\"Waking sandbox\"\n announce=\"status\"\n >\n Opening {requestedPath} when the live workspace is ready…\n </Notice>\n )\n ) : (\n <Notice icon={<FileCode2Icon className=\"size-5\" aria-hidden />} title=\"Choose a file\">\n Select a file in the tree to preview it.\n </Notice>\n )}\n </div>\n </Panel>\n </Group>\n </div>\n );\n}\n\nfunction WakeButton({ children, onClick }: { children: ReactNode; onClick: () => void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"mt-1 inline-flex min-h-11 items-center justify-center rounded-og-md bg-og-accent-deep px-3 py-2 text-og-sm font-medium text-og-accent-fg shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg\"\n >\n {children}\n </button>\n );\n}\n\nfunction LineNumberedFile({\n path,\n contents,\n focusLine,\n}: {\n path: string;\n contents: string;\n focusLine: number;\n}) {\n const lines = contents.split(\"\\n\");\n const inRange = focusLine >= 1 && focusLine <= lines.length;\n const targetRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n targetRef.current?.scrollIntoView({\n block: \"center\",\n behavior: prefersReducedMotion() ? \"auto\" : \"smooth\",\n });\n }, [path, focusLine, contents]);\n\n return (\n <div\n className=\"h-full min-h-0 overflow-auto font-og-mono text-og-sm text-og-fg\"\n role=\"region\"\n aria-label={inRange ? `${path} at line ${focusLine}` : path}\n >\n {!inRange ? (\n <p\n className=\"border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-fg-muted\"\n role=\"status\"\n >\n Line {focusLine} is past the end of this file.\n </p>\n ) : null}\n <div>\n {lines.map((text, index) => {\n const lineNumber = index + 1;\n const focused = inRange && lineNumber === focusLine;\n return (\n <div\n key={lineNumber}\n ref={focused ? targetRef : undefined}\n data-opengeni-file-line={lineNumber}\n {...(focused ? { \"data-opengeni-focus-line\": \"\" } : {})}\n aria-current={focused ? \"location\" : undefined}\n className={cn(\"flex gap-3 px-2 py-0.5 leading-6\", focused && \"bg-og-accent-soft\")}\n >\n <span className=\"w-11 shrink-0 select-none text-right tabular-nums text-og-fg-subtle\">\n {lineNumber}\n </span>\n <pre className=\"min-w-0 flex-1 whitespace-pre-wrap break-words\">{text || \" \"}</pre>\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction GitHeader({ git, loading }: { git: SandboxFilesGitSummary; loading: boolean }) {\n if (loading) {\n return (\n <div\n className=\"flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm text-og-fg-muted\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <LoaderCircleIcon\n className=\"size-3.5 shrink-0 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n <span>Loading repository…</span>\n </div>\n );\n }\n const dirty = git.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 aria-hidden=\"true\"\n className={cn(\n \"size-2 shrink-0 rounded-full\",\n dirty ? \"bg-og-status-running\" : \"bg-og-status-idle\",\n )}\n />\n <span className=\"sr-only\">\n {dirty ? `Uncommitted changes in ${git.dirtyCount} files` : \"No uncommitted changes\"}\n </span>\n <span className=\"truncate font-og-mono text-og-fg\">\n {git.repoCount > 1\n ? `${git.repoCount} repositories`\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 {/* Small arrow glyphs can make axe's pixel overlap heuristic inconclusive.\n Keep both counters in the same computed-contrast audit as the dirty count. */}\n {git.ahead > 0 && <span data-contrast-audited>↑{git.ahead}</span>}\n {git.behind > 0 && <span data-contrast-audited>↓{git.behind}</span>}\n </span>\n )}\n {dirty && (\n <span\n aria-hidden=\"true\"\n data-contrast-audited\n className=\"ml-auto shrink-0 text-og-xs text-og-fg-subtle\"\n >\n {git.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 \"min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-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 imageUrl?: 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: UseSandboxFilesResult[\"readFile\"],\n reloadRevision: string | number = 0,\n): FileViewState {\n const previousPathRef = useRef<string | null>(null);\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 previousPathRef.current = null;\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 const pathChanged = previousPathRef.current !== path;\n previousPathRef.current = path;\n let cancelled = false;\n const abort = new AbortController();\n if (pathChanged) {\n setState({\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: true,\n error: null,\n });\n } else {\n // Keep the last successful preview visible while a remote Modal read\n // revalidates it. Replacing useful content with a multi-second spinner\n // makes a live workspace feel slower and hides the state being refreshed.\n setState((previous) => ({ ...previous, error: null }));\n }\n void readFile(path, { signal: abort.signal })\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 imageUrl:\n !res.truncated && res.encoding === \"base64\" ? rasterImageUrl(path, res.content) : null,\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 const error = cause instanceof Error ? cause : new Error(String(cause));\n setState((previous) =>\n pathChanged\n ? {\n content: null,\n isBinary: false,\n truncated: false,\n sizeBytes: null,\n loading: false,\n error,\n }\n : { ...previous, loading: false, error },\n );\n });\n return () => {\n cancelled = true;\n abort.abort();\n };\n }, [path, readFile, reloadRevision]);\n return state;\n}\n\n/** Only raster formats belong in this preview; never interpret SVG/HTML as a document. */\nfunction rasterImageUrl(path: string, content: string): string | null {\n const extension = path.split(\".\").pop()?.toLowerCase();\n const mime =\n extension === \"png\"\n ? \"image/png\"\n : extension === \"jpg\" || extension === \"jpeg\"\n ? \"image/jpeg\"\n : extension === \"gif\"\n ? \"image/gif\"\n : extension === \"webp\"\n ? \"image/webp\"\n : null;\n return mime ? `data:${mime};base64,${content}` : null;\n}\n\nfunction RasterFilePreview({ src, path }: { src: string; path: string }) {\n const [failed, setFailed] = useState(false);\n return failed ? (\n <Notice title=\"Image preview unavailable\" announce=\"alert\">\n Could not decode {path} as an image.\n </Notice>\n ) : (\n <img\n src={src}\n alt={path}\n onError={() => setFailed(true)}\n className=\"max-w-full object-contain\"\n />\n );\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({\n children,\n className,\n icon,\n title,\n announce,\n}: {\n children: ReactNode;\n className?: string | undefined;\n icon?: ReactNode | undefined;\n title?: string | undefined;\n announce?: \"status\" | \"alert\" | undefined;\n}) {\n return (\n <div\n role={announce}\n aria-atomic={announce ? \"true\" : undefined}\n aria-live={announce === \"alert\" ? \"assertive\" : announce === \"status\" ? \"polite\" : undefined}\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 <div className=\"flex max-w-sm flex-col items-center gap-2.5\">\n {icon ? (\n <span className=\"grid size-10 place-items-center rounded-og-lg border border-og-border bg-og-surface-1 text-og-fg-muted shadow-sm\">\n {icon}\n </span>\n ) : null}\n {title ? <p className=\"font-medium text-og-fg\">{title}</p> : null}\n <div data-contrast-audited className=\"leading-5\">\n {children}\n </div>\n </div>\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 {\n Group,\n Panel,\n Separator,\n useDefaultLayout,\n usePanelRef,\n type Layout,\n type LayoutChangedMeta,\n type LayoutStorage,\n} from \"react-resizable-panels\";\nimport { cn } from \"../lib/cn\";\n\nexport type WorkspaceTab = {\n id: string;\n label: ReactNode;\n /** Optional icon used by the compact activity rail. */\n icon?: ReactNode | undefined;\n /** Accessible name when `label` is not plain text. */\n ariaLabel?: string | undefined;\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 /** Keep the panel-local Hide workspace control when the host controls collapsed state. */\n showCollapseControl?: boolean | undefined;\n /** A status accessory pinned to the right of the workspace header, 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\nconst SERVER_LAYOUT_STORAGE: LayoutStorage = {\n getItem: () => null,\n setItem: () => {},\n};\n\n/** `useDefaultLayout` defaults to the ambient `localStorage` identifier when\n * storage is undefined, which throws during SSR. Access can also throw in a\n * browser that blocks storage (sandboxed frames/private policy), so both cases\n * use a stable, non-persisting implementation instead. */\nfunction getLayoutStorage(): LayoutStorage {\n if (typeof window === \"undefined\") return SERVER_LAYOUT_STORAGE;\n try {\n return window.localStorage;\n } catch {\n return SERVER_LAYOUT_STORAGE;\n }\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 showCollapseControl = true,\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 rootRef = useRef<HTMLDivElement | null>(null);\n const reopenRef = useRef<HTMLButtonElement | null>(null);\n const returnFocusRef = useRef<HTMLElement | null>(null);\n const initialNarrowFocusRef = useRef(false);\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 // The host header remains the stable reopen action. The open panel also owns\n // a local Hide workspace action so a user never has to hunt elsewhere to\n // dismiss it; standalone usage keeps the thin reopen rail as well.\n const hostControlled = collapsedProp !== undefined;\n const previousCollapsedRef = useRef(collapsed);\n\n // Persisted layout (width split) keyed by autoSaveId.\n const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n panelIds: [\"primary\", \"dock\"],\n storage: getLayoutStorage(),\n id: autoSaveId,\n });\n const expandedDefaultLayout =\n defaultLayout && (defaultLayout.dock ?? 0) > 1 ? defaultLayout : undefined;\n const lastExpandedSizeRef = useRef(expandedDefaultLayout?.dock ?? defaultSize);\n const layoutIdentityRef = useRef(autoSaveId);\n if (layoutIdentityRef.current !== autoSaveId) {\n layoutIdentityRef.current = autoSaveId;\n lastExpandedSizeRef.current = expandedDefaultLayout?.dock ?? defaultSize;\n }\n const persistExpandedLayout = useCallback(\n (layout: Layout, meta: LayoutChangedMeta) => {\n // Both supported panel-library versions report 100/0 when the host\n // collapses the dock. Do not replace the last user-selected width with it.\n const dockSize = layout.dock ?? 0;\n if (dockSize <= 1) return;\n lastExpandedSizeRef.current = dockSize;\n onLayoutChanged(layout, meta);\n },\n [onLayoutChanged],\n );\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?.resize(`${lastExpandedSizeRef.current}%`);\n }\n }, [collapsedProp, dockPanelRef]);\n\n // Treat the narrow overlay like a real modal: remember the external opener,\n // move focus into the selected tab, and restore it on close. The standalone\n // desktop dock instead focuses its newly-visible reopen rail after collapse.\n useEffect(() => {\n const previous = previousCollapsedRef.current;\n previousCollapsedRef.current = collapsed;\n if (previous === collapsed) return;\n\n if (!collapsed) {\n const active = document.activeElement;\n const workspaceSurface = rootRef.current?.querySelector<HTMLElement>(\n narrow ? '[role=\"dialog\"]' : \"[data-workspace-surface]\",\n );\n if (active instanceof HTMLElement && !workspaceSurface?.contains(active)) {\n returnFocusRef.current = active;\n }\n if (narrow) {\n const frame = requestAnimationFrame(() => {\n rootRef.current\n ?.querySelector<HTMLElement>('[role=\"dialog\"] [role=\"tab\"][aria-selected=\"true\"]')\n ?.focus();\n });\n return () => cancelAnimationFrame(frame);\n }\n return;\n }\n\n const frame = requestAnimationFrame(() => {\n if (!hostControlled) {\n reopenRef.current?.focus();\n return;\n }\n const target = returnFocusRef.current;\n if (target?.isConnected) {\n target.focus();\n return;\n }\n // A controlled desktop dock can be restored open on the initial render,\n // so there may be no opener to remember. Never leave focus parked on the\n // now-hidden workspace chrome; fall back to the host's primary surface.\n rootRef.current\n ?.querySelector<HTMLElement>(\n '[data-workspace-primary] button:not([disabled]), [data-workspace-primary] a[href], [data-workspace-primary] input:not([disabled]), [data-workspace-primary] textarea:not([disabled]), [data-workspace-primary] select:not([disabled]), [data-workspace-primary] [tabindex]:not([tabindex=\"-1\"])',\n )\n ?.focus();\n });\n return () => cancelAnimationFrame(frame);\n }, [collapsed, hostControlled, narrow]);\n\n // On the first narrow render there is no collapsed-state transition to drive\n // focus into the modal: the overlay can already be open at mount. Place focus\n // on its selected tab once, just as we do when an existing overlay is opened.\n useEffect(() => {\n if (!narrow || collapsed || initialNarrowFocusRef.current) return;\n initialNarrowFocusRef.current = true;\n const active = document.activeElement;\n const workspaceSurface = rootRef.current?.querySelector<HTMLElement>('[role=\"dialog\"]');\n if (active instanceof HTMLElement && !workspaceSurface?.contains(active)) {\n returnFocusRef.current = active;\n }\n const frame = requestAnimationFrame(() => {\n workspaceSurface?.querySelector<HTMLElement>('[role=\"tab\"][aria-selected=\"true\"]')?.focus();\n });\n return () => cancelAnimationFrame(frame);\n }, [collapsed, narrow]);\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. Tab is\n // fenced inside either full-screen surface: both visually cover the host, so\n // keyboard focus must never move into invisible content behind them.\n useEffect(() => {\n const overlayOpen = maximized || (narrow && !collapsed);\n if (!overlayOpen) return;\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n if (maximized) setMaximized(false);\n else collapse();\n return;\n }\n if (event.key !== \"Tab\") return;\n const surface = rootRef.current?.querySelector<HTMLElement>(\n narrow ? '[role=\"dialog\"]' : \"[data-workspace-surface]\",\n );\n if (!surface) return;\n const focusable = Array.from(surface.querySelectorAll<HTMLElement>(\"*\")).filter(\n (element) =>\n element.tabIndex >= 0 &&\n !element.hasAttribute(\"disabled\") &&\n element.getClientRects().length > 0 &&\n getComputedStyle(element).visibility !== \"hidden\",\n );\n const first = focusable[0];\n const last = focusable.at(-1);\n const active = document.activeElement;\n if (!first || !last) {\n event.preventDefault();\n surface.focus();\n return;\n }\n if (!surface.contains(active)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n return;\n }\n if ((event.shiftKey && active === first) || (!event.shiftKey && active === last)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n return;\n }\n // Focus can emerge from a shadow-DOM editor/highlighter host at a point\n // the light-DOM order cannot predict. Repair any escape after the browser\n // performs its default Tab move.\n requestAnimationFrame(() => {\n const next = document.activeElement;\n if (!surface.contains(next)) (event.shiftKey ? last : first).focus();\n });\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 ref={rootRef} className={cn(\"relative flex h-full min-h-0 w-full min-w-0\", className)}>\n <div\n data-workspace-primary\n aria-hidden={!collapsed ? true : undefined}\n className=\"min-h-0 min-w-0 flex-1\"\n inert={!collapsed ? true : undefined}\n >\n {primary}\n </div>\n <div\n data-workspace-surface\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 hidden={collapsed}\n style={{\n // Author utility classes can override the user-agent `[hidden]`\n // rule (for example this surface's `flex` class). Keep an inline\n // display guard so a collapsed mobile workspace is actually gone\n // visually as well as from the accessibility tree.\n display: collapsed ? \"none\" : undefined,\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=\"Hide workspace\" label=\"Hide workspace\">\n <XIcon className=\"size-4\" />\n </ChromeButton>\n }\n />\n </div>\n {collapsed && !hostControlled ? (\n <button\n ref={reopenRef}\n type=\"button\"\n onClick={expand}\n title=\"Open workspace\"\n aria-label=\"Open workspace\"\n className=\"absolute right-3 top-3 z-30 inline-flex size-11 items-center justify-center rounded-og-md border border-og-border bg-og-surface-1 text-og-fg-muted shadow-lg transition-colors hover:border-og-border-strong hover:text-og-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent\"\n style={{ marginTop: \"env(safe-area-inset-top)\" }}\n >\n <ChevronsLeftRightIcon className=\"size-4\" aria-hidden />\n </button>\n ) : null}\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 && !showCollapseControl ? null : (\n <ChromeButton onClick={collapse} title=\"Hide workspace\" label=\"Hide workspace\">\n <PanelRightCloseIcon className=\"size-3.5\" />\n </ChromeButton>\n )}\n </>\n }\n />\n );\n\n return (\n <div ref={rootRef} 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 {...(expandedDefaultLayout ? { defaultLayout: expandedDefaultLayout } : {})}\n onLayoutChanged={persistExpandedLayout}\n >\n <Panel id=\"primary\" minSize=\"30%\" className=\"min-h-0 min-w-0\">\n <div\n data-workspace-primary\n aria-hidden={maximized ? true : undefined}\n className=\"h-full min-h-0 min-w-0\"\n inert={maximized ? true : undefined}\n >\n {primary}\n </div>\n </Panel>\n\n {!collapsed && (\n <Separator className=\"group relative z-10 w-1.5 shrink-0 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent max-[1023px]:-mx-[19px] max-[1023px]:w-11 pointer-coarse:-mx-[19px] pointer-coarse:w-11\">\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-focus-visible: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 {/* One persistent mount across normal, collapsed, and maximized modes:\n layout changes must never destroy an editor buffer or terminal view. */}\n <div\n data-workspace-surface\n role={maximized ? \"dialog\" : undefined}\n aria-modal={maximized ? true : undefined}\n aria-label={maximized ? \"Workspace\" : undefined}\n aria-hidden={collapsed ? true : undefined}\n className={cn(\n \"flex h-full min-h-0 min-w-0 flex-col bg-og-bg\",\n maximized ? \"fixed inset-0 z-40\" : \"border-l border-og-border\",\n collapsed && \"invisible pointer-events-none\",\n )}\n >\n {dockChrome}\n </div>\n </Panel>\n </Group>\n\n {/* Collapsed rail: the standalone fallback re-open affordance. Hidden\n when the host controls collapse — its header remains the stable way in. */}\n {collapsed && !maximized && !hostControlled && (\n <button\n ref={reopenRef}\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 </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 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent 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 chromeRef = useRef<HTMLDivElement | null>(null);\n const [compact, setCompact] = useState(false);\n const active = tabs.find((t) => t.id === current) ?? tabs[0];\n const tabsetId = useId();\n const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);\n const [visitedTabs, setVisitedTabs] = useState<Set<string>>(() => new Set());\n const activeId = active?.id ?? \"\";\n\n // Dock width, not viewport width, chooses rail density. A narrow split keeps\n // the icon-first activity rail usable without stealing the panel's content\n // width; overlays and maximized views retain readable labels.\n useDockLayoutEffect(() => {\n const node = chromeRef.current;\n if (!node) return;\n const update = () => {\n const desktop =\n typeof window.matchMedia !== \"function\" || window.matchMedia(\"(min-width: 1024px)\").matches;\n const next = desktop && node.getBoundingClientRect().width < 440;\n setCompact((previous) => (previous === next ? previous : next));\n };\n update();\n if (typeof ResizeObserver === \"undefined\") {\n window.addEventListener(\"resize\", update);\n return () => window.removeEventListener(\"resize\", update);\n }\n const observer = new ResizeObserver(update);\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n if (!activeId) return;\n setVisitedTabs((previous) => {\n if (previous.has(activeId)) return previous;\n const next = new Set(previous);\n next.add(activeId);\n return next;\n });\n }, [activeId]);\n\n const activateTab = (index: number) => {\n const tab = tabs[index];\n if (!tab) {\n return;\n }\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 === \"ArrowDown\") nextIndex = (index + 1) % tabs.length;\n else if (event.key === \"ArrowUp\") 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 <div\n ref={chromeRef}\n data-dock-chrome\n data-compact={compact ? \"true\" : undefined}\n className=\"flex h-full min-h-0 min-w-0 flex-col\"\n >\n <div className=\"flex min-h-10 shrink-0 items-center gap-2 border-b border-og-border px-2 max-[1023px]:min-h-12\">\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n {leading ?? (\n <span className=\"hidden truncate text-og-sm font-semibold text-og-fg max-[1023px]:inline\">\n Workspace\n </span>\n )}\n </div>\n <div className=\"min-w-0 shrink text-og-fg-muted\">{accessory}</div>\n <div className=\"flex shrink-0 items-center gap-0.5 text-og-fg-subtle\">{controls}</div>\n </div>\n <div className=\"flex min-h-0 min-w-0 flex-1\">\n <div\n className={cn(\n \"flex shrink-0 flex-col gap-1 overflow-x-hidden overflow-y-auto border-r border-og-border bg-og-surface-1/45 p-1.5\",\n compact ? \"w-12\" : \"w-32 max-[1023px]:w-36\",\n )}\n role=\"tablist\"\n aria-label=\"Workspace panels\"\n aria-orientation=\"vertical\"\n >\n {tabs.map((tab, index) => {\n const tabName = tab.ariaLabel ?? (typeof tab.label === \"string\" ? tab.label : tab.id);\n return (\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-label={compact && tab.icon ? tabName : undefined}\n title={compact && tab.icon ? tabName : undefined}\n aria-selected={tab.id === current}\n aria-controls={`${tabsetId}-panel-${index}`}\n tabIndex={tab.id === current ? 0 : -1}\n onClick={() => onTab(tab.id)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n className={cn(\n \"group relative flex min-h-9 w-full items-center gap-2 rounded-og-md px-2 text-left text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11\",\n compact && \"justify-center px-1\",\n tab.id === current\n ? \"bg-og-accent-soft text-og-fg shadow-[inset_2px_0_0_var(--og-color-accent)]\"\n : \"text-og-fg-subtle hover:bg-og-surface-2 hover:text-og-fg\",\n )}\n >\n {tab.icon ? (\n <span\n className=\"flex size-4 shrink-0 items-center justify-center [&>svg]:size-4\"\n aria-hidden\n >\n {tab.icon}\n </span>\n ) : null}\n {!compact || !tab.icon ? (\n <span data-contrast-audited className=\"min-w-0 flex-1 truncate\">\n {tab.label}\n </span>\n ) : null}\n {tab.badge ? (\n <span\n className={cn(\"shrink-0\", compact && \"absolute -right-0.5 -top-0.5 scale-90\")}\n >\n {tab.badge}\n </span>\n ) : null}\n </button>\n );\n })}\n </div>\n <div className=\"min-h-0 min-w-0 flex-1 overflow-hidden\">\n {tabs.length > 0 ? (\n tabs.map((tab, index) => {\n const selected = tab.id === activeId;\n const shouldMount = selected || visitedTabs.has(tab.id);\n return (\n <div\n key={tab.id}\n id={`${tabsetId}-panel-${index}`}\n aria-labelledby={`${tabsetId}-tab-${index}`}\n className=\"h-full min-h-0 min-w-0 overflow-hidden\"\n hidden={!selected}\n role=\"tabpanel\"\n >\n {shouldMount ? tab.content : null}\n </div>\n );\n })\n ) : (\n <div className=\"h-full min-h-0 min-w-0\" aria-label=\"Workspace\" role=\"tabpanel\" />\n )}\n </div>\n </div>\n </div>\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// Browser — workspace-wide BrowserSessions, tabs, live frames, and input\n// Computer — workspace ComputerSessions: native targets, frames, and input\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 uses — that is criterion F1.\nimport {\n lazy,\n type ReactNode,\n Suspense,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { SessionEvent } from \"@opengeni/sdk\";\nimport type { InteractionPlacement } from \"@opengeni/sdk/interaction\";\nimport {\n CircleCheckIcon,\n CpuIcon,\n FileCode2Icon,\n GitCompareArrowsIcon,\n Globe2Icon,\n LoaderCircleIcon,\n MonitorIcon,\n RefreshCwIcon,\n SquareTerminalIcon,\n TriangleAlertIcon,\n} from \"lucide-react\";\n\nimport { type ClientOverride, useOpenGeni } from \"../provider\";\nimport { cn } from \"../lib/cn\";\nimport { xtermThemeFromTokens } from \"../lib/xterm-theme\";\nimport { sandboxAcceptsLiveIo } from \"../lib/sandbox-liveness\";\nimport type { BrowserFrameWebSocketFactory } from \"../hooks/use-browser-frame-stream\";\nimport type { ComputerFrameWebSocketFactory } from \"../hooks/use-computer-frame-stream\";\nimport type { FileNodeVisibilityPredicate } from \"../file-node-visibility\";\nimport { useSessionCapabilities } from \"../hooks/use-session-capabilities\";\nimport { useSandboxFiles } from \"../hooks/use-sandbox-files\";\nimport {\n useSandboxGit,\n type SandboxGitComparison,\n type UseSandboxGitResult,\n} from \"../hooks/use-sandbox-git\";\nimport { useSandboxTerminal } from \"../hooks/use-sandbox-terminal\";\nimport { useWorkspaceCapture } from \"../hooks/use-workspace-capture\";\nimport { useMachineChip, type MachineChip } from \"../hooks/use-machine-chip\";\nimport { MACHINES_SESSION_POLL_MS, useMachines } from \"../hooks/use-machines\";\nimport type { MachineView } from \"../types/machines\";\nimport { SandboxFiles } from \"./sandbox-files\";\nimport { WorkbenchChanges } from \"./workbench-changes\";\nimport { SandboxTerminal, type XtermTheme } from \"./sandbox-terminal\";\nimport { WorkspaceDock, type WorkspaceDockProps, type WorkspaceTab } from \"./workspace-dock\";\n\nconst LazyBrowserViewer = lazy(async () => {\n const { BrowserViewer } = await import(\"./browser-viewer\");\n return { default: BrowserViewer };\n});\n\nconst LazyComputerViewer = lazy(async () => {\n const { ComputerViewer } = await import(\"./computer-viewer\");\n return { default: ComputerViewer };\n});\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\";\nexport const WORKBENCH_TAB_TERMINAL = \"terminal\";\nexport const WORKBENCH_TAB_BROWSER = \"browser\";\nexport const WORKBENCH_TAB_DESKTOP = \"desktop\";\n\n/**\n * The built-in workbench surfaces in their canonical display order. Hosts can\n * pass a subset through `surfaces`; omission preserves the complete standalone\n * workbench.\n */\nexport const WORKBENCH_SURFACES = [\n WORKBENCH_TAB_CHANGES,\n WORKBENCH_TAB_FILES,\n WORKBENCH_TAB_TERMINAL,\n WORKBENCH_TAB_BROWSER,\n WORKBENCH_TAB_DESKTOP,\n] as const;\n\nexport type SandboxWorkspaceSurface = (typeof WORKBENCH_SURFACES)[number];\n\nfunction isWorkbenchSurface(value: string): value is SandboxWorkspaceSurface {\n return (WORKBENCH_SURFACES as readonly string[]).includes(value);\n}\n\nfunction isCanonicalAbsoluteSandboxPath(value: string | null | undefined): boolean {\n if (!value) return false;\n const portable = value.replaceAll(\"\\\\\", \"/\");\n return portable.startsWith(\"/\") || /^[A-Za-z]:\\//u.test(portable);\n}\n\nfunction sourceDrivenDefaultTab(\n hasChanges: boolean,\n changesEnabled: boolean,\n filesEnabled: boolean,\n): string | null {\n if (hasChanges && changesEnabled) return WORKBENCH_TAB_CHANGES;\n if (filesEnabled) return WORKBENCH_TAB_FILES;\n if (changesEnabled) return WORKBENCH_TAB_CHANGES;\n return null;\n}\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 case \"repository_read_unavailable\":\n return \"Workspace capture is incomplete because repository changes could not be read. Live files remain authoritative.\";\n default:\n return \"Workspace capture is incomplete because repository discovery failed. Live files remain authoritative.\";\n }\n}\n\nfunction WorkbenchSurfaceLoading({ name }: { name: \"Browser\" | \"Desktop\" }) {\n return (\n <CenteredState\n icon={\n <LoaderCircleIcon className=\"size-5 animate-spin motion-reduce:animate-none\" aria-hidden />\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">Opening {name}</p>\n </CenteredState>\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 * `<SandboxWorkspace>` uses this only as an optional early hint after its own\n * capture GET reports no durable capture. A pure embedder needs no events-at-mount\n * contract: it falls through to authoritative live Git instead.\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 if (bestFileCount > 0) return WORKBENCH_TAB_CHANGES;\n\n let latestGitSeq = -1;\n let committedOnly = false;\n for (const event of events ?? []) {\n if (event.type !== \"git.changed\" || event.sequence > bestSeq) continue;\n if (event.sequence <= latestGitSeq) continue;\n const payload = event.payload as { ahead?: number; reason?: string } | null;\n latestGitSeq = event.sequence;\n committedOnly =\n (typeof payload?.ahead === \"number\" && payload.ahead > 0) || payload?.reason === \"commit\";\n }\n return committedOnly ? 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\n/**\n * Whether this session currently owns an admitted agent turn. Automatic live\n * Files/Git reads pause across the whole turn: command boundaries are not a safe\n * gap because the next tool can dispatch before a remote provider read releases\n * its sandbox holder. Existing/captured content remains usable, and the terminal\n * turn event resumes one authoritative refresh.\n */\nfunction workspaceTurnInFlight(events: SessionEvent[]): boolean {\n const activeTurnIds = new Set<string>();\n let anonymousTurnInFlight = false;\n let sessionOwnsWorkspace = false;\n for (const event of events) {\n if (event.type === \"session.status.changed\") {\n const status =\n event.payload && typeof event.payload === \"object\" && !Array.isArray(event.payload)\n ? (event.payload as Record<string, unknown>).status\n : null;\n sessionOwnsWorkspace = status === \"running\" || status === \"recovering\";\n continue;\n }\n if (event.type === \"turn.started\") {\n if (event.turnId) activeTurnIds.add(event.turnId);\n else anonymousTurnInFlight = true;\n continue;\n }\n if (\n event.type !== \"turn.completed\" &&\n event.type !== \"turn.failed\" &&\n event.type !== \"turn.cancelled\" &&\n event.type !== \"turn.superseded\"\n ) {\n continue;\n }\n if (event.turnId) activeTurnIds.delete(event.turnId);\n else anonymousTurnInFlight = false;\n }\n // The retained event window preserves the latest status even after a very\n // long turn has evicted its original turn.started event.\n return sessionOwnsWorkspace || anonymousTurnInFlight || activeTurnIds.size > 0;\n}\n\nexport type WorkspaceMachine = {\n /** Whether at least one built-in workbench surface is enabled. */\n enabled: boolean;\n /** The derived live/waking/sleeping-or-offline chip model. */\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 /**\n * Built-in surfaces this host wants to expose. Omit for all five. A disabled\n * surface is behaviorally dormant: its data hooks, warm intents, stream\n * attachment, and navigation callbacks are not activated.\n */\n surfaces?: readonly SandboxWorkspaceSurface[] | undefined;\n /** Override the source-driven default tab (e.g. a host landing tab id). When\n * omitted the workbench picks Changes-vs-Files from capture or live Git. */\n initialTab?: string | null | undefined;\n /** Actually selected dock tab. Inactive data surfaces retain cache but issue no live reads. */\n activeTab?: string | null | undefined;\n /** Whether the dock is visible. Hidden docks retain UI state but must not keep\n * expensive browser/computer media streams alive. */\n workspaceVisible?: boolean | 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 /** Alternate frame transport for non-browser runtimes and deterministic tests. */\n browserWebSocketFactory?: BrowserFrameWebSocketFactory | undefined;\n /** Alternate Computer frame transport for non-browser runtimes and deterministic tests. */\n computerWebSocketFactory?: ComputerFrameWebSocketFactory | undefined;\n /** Host-owned setup page or store listing for attaching an existing Chrome profile. */\n browserExtensionSetupUrl?: string | undefined;\n /** File requested by a Changes guard. The Files surface defers the read until\n * the sandbox is live, then reveals this path. */\n requestedFilePath?: string | null | undefined;\n /** Unique identity for `requestedFilePath`, including repeated requests for the\n * same path. */\n requestedFileRequestId?: string | number | null | undefined;\n /** 1-based line to reveal after `requestedFilePath` opens. */\n requestedFileLine?: number | null | undefined;\n /** Route a guarded diff into the host's Files tab. */\n onOpenFile?: ((path: string) => void) | undefined;\n /** Restore and report navigation inside the built-in workbench surfaces. */\n initialFilePath?: string | null | undefined;\n onFilePathChange?: ((path: string | null) => void) | undefined;\n /** Presentation-only filter for Files tree nodes and selected-file viewing. */\n isFileNodeVisible?: FileNodeVisibilityPredicate | undefined;\n initialBrowserSessionId?: string | null | undefined;\n onBrowserSessionIdChange?: ((browserSessionId: string | null) => void) | undefined;\n initialComputerSessionId?: string | null | undefined;\n onComputerSessionIdChange?: ((computerSessionId: string | null) => void) | undefined;\n /** Navigate the host dock to one exact linked ComputerSession. */\n onOpenComputerSession?: ((computerSessionId: string) => void) | undefined;\n requestedComputerSessionId?: string | null | undefined;\n requestedComputerRequestId?: string | number | null | undefined;\n};\n\nexport type UseSandboxWorkspaceTabsResult = {\n /** Changes | Files | Terminal | Browser | Desktop (capability-gated where noted). */\n tabs: WorkspaceTab[];\n /** The source-driven default tab: Changes when the first authoritative capture\n * has changes, else Files (a host `initialTab` overrides). Choosing a tab\n * never performs hidden live workspace I/O.\n * null while that source resolves, or permanently when neither Changes nor\n * Files is enabled; the choice latches once. */\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 warmTerminal: boolean;\n warmFiles: boolean;\n};\n\nfunction emptyWarmIntents(sessionId: string): SessionWarmIntents {\n return {\n sessionId,\n warmTerminal: false,\n warmFiles: 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, automatic desktop acknowledgment, and the xterm theme observer — all\n * package-local.\n */\nexport function useSandboxWorkspaceTabs(\n options: UseSandboxWorkspaceTabsOptions,\n): UseSandboxWorkspaceTabsResult {\n const { client, workspaceId, workspaceInteractionEvent } = useOpenGeni(options);\n const {\n sessionId,\n events,\n onNotify,\n browserWebSocketFactory,\n computerWebSocketFactory,\n browserExtensionSetupUrl,\n requestedFilePath,\n requestedFileRequestId,\n requestedFileLine,\n onOpenFile,\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n onOpenComputerSession,\n requestedComputerSessionId,\n requestedComputerRequestId,\n } = options;\n const initialTab = options.initialTab ?? null;\n const activeTab = options.activeTab ?? initialTab;\n const workspaceVisible = options.workspaceVisible ?? true;\n const requestedSurfaces = options.surfaces ?? WORKBENCH_SURFACES;\n const surfaceSet = new Set<SandboxWorkspaceSurface>(requestedSurfaces);\n const changesEnabled = surfaceSet.has(WORKBENCH_TAB_CHANGES);\n const filesEnabled = surfaceSet.has(WORKBENCH_TAB_FILES);\n const terminalEnabled = surfaceSet.has(WORKBENCH_TAB_TERMINAL);\n const browserEnabled = surfaceSet.has(WORKBENCH_TAB_BROWSER);\n const desktopEnabled = surfaceSet.has(WORKBENCH_TAB_DESKTOP);\n const createLinkedComputer = useCallback(\n async (name: string, placement?: InteractionPlacement) => {\n const response = await client.createComputerSession(workspaceId, {\n operationId: crypto.randomUUID(),\n sessionId,\n name,\n ...(placement ? { placement } : {}),\n });\n if (response.operation.state !== \"completed\" || response.session.lifecycle !== \"active\") {\n throw new Error(response.operation.error?.message ?? \"The desktop could not be opened.\");\n }\n return {\n id: response.session.id,\n placement: response.session.placement,\n };\n },\n [client, sessionId, workspaceId],\n );\n const workspaceDataEnabled = changesEnabled || filesEnabled;\n const machineSurfaceEnabled = workspaceDataEnabled || terminalEnabled || desktopEnabled;\n // Do not speculatively activate both remote workspace surfaces while the dock\n // is still resolving its selected tab. Modal calls cannot be cancelled after\n // dispatch, so that transient state otherwise creates an aborted duplicate\n // batch immediately before the real selected-tab request.\n const resolvedActiveTab = activeTab ?? initialTab;\n const changesActive = resolvedActiveTab === WORKBENCH_TAB_CHANGES;\n const filesActive = resolvedActiveTab === WORKBENCH_TAB_FILES;\n const turnInFlight = workspaceTurnInFlight(events);\n const surfaceIdentity = WORKBENCH_SURFACES.filter((surface) => surfaceSet.has(surface)).join(\",\");\n\n // The two 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): terminal engagement (`onActivate`) and a deliberate\n // live-file open/edit in Files. 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 { warmTerminal, warmFiles } = warmIntents;\n // A host-requested file is itself explicit live-file intent. Derive the wake\n // directly from the request instead of relying on a follow-up effect to copy\n // it into local state; otherwise a missing or delayed effect leaves the file\n // waiting for a sandbox that this hook never asks to start.\n const filesWarmRequested = warmFiles || Boolean(requestedFilePath);\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 // The session's machine fleet + the active-sandbox pointer. Drives the header\n // chip (which machine + its connection state). Shares the session list poll.\n const machines = useMachines({\n workspaceId,\n sessionId,\n pollIntervalMs: MACHINES_SESSION_POLL_MS,\n enabled: machineSurfaceEnabled,\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 enabled: machineSurfaceEnabled,\n attachDesktop: false,\n attachTerminal: terminalEnabled && warmTerminal,\n // Explicit live-file intent only — NOT \"the Files tab is open\". A cold edit\n // or guarded-file open wakes the box; a glance at the tree/diff does not.\n attachFiles: workspaceDataEnabled && filesWarmRequested,\n });\n const capabilities = caps.capabilities;\n const liveness = capabilities?.liveness;\n // A missing capability document is not evidence that the sandbox is live.\n // Pass explicit null to live-I/O hooks so fast capture/event hydration cannot\n // exploit their legacy \"liveness omitted\" compatibility path while negotiation\n // is still pending.\n const liveIoLiveness = liveness ?? null;\n const fileSystemOn = capabilities?.FileSystem.available ?? false;\n const fileSystemRoute = capabilities\n ? { epoch: capabilities.leaseEpoch, root: capabilities.FileSystem.root }\n : undefined;\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 (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 // Mutations are live-only. A capture is a review artifact, never a writable\n // surrogate for a sleeping machine; the user must deliberately open the live\n // workspace before create/rename/delete/edit controls appear.\n const filesEditable = fileSystemOn && !fsReadOnly && sandboxAcceptsLiveIo(liveness);\n const gitOn = capabilities?.Git.available ?? false;\n const terminalOn = terminalEnabled && (capabilities?.Terminal.transport ?? null) !== null;\n // A descriptor-only pty-ws cell intentionally has no short-lived URL until\n // terminal intent acquires one. Do not mistake that grant boundary for a\n // legacy HTTP PTY and eagerly open a second terminal. The fallback exists only\n // for a genuinely firehose-transport backend with no typed degradation.\n const ptyCapable =\n warmTerminal &&\n (capabilities?.Terminal.ptyCapable ?? false) &&\n capabilities?.Terminal.transport === \"sse-events\" &&\n capabilities?.Terminal.reason === null;\n const terminal = useSandboxTerminal(sessionId, {\n events: terminalEnabled ? events : [],\n interactive: terminalEnabled && ptyCapable,\n liveness,\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 // BrowserSession and ComputerSession lifecycles use the same placement lease\n // as files/terminal/desktop, but are workspace resources rather than session\n // events. Re-read the capability document on their canonical workspace\n // invalidation so the one machine chip cannot remain \"Offline\" beside a live\n // browser/computer (or remain \"Live\" after the final interaction holder ends).\n // This is a read-only negotiation: it never acquires a holder or wakes a box.\n useEffect(() => {\n if (workspaceInteractionEvent?.workspaceId !== workspaceId) return;\n renegotiate();\n }, [workspaceId, workspaceInteractionEvent, 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 immediately; a warm box reconciles live without discarding the capture\n // when that provider read is temporarily unavailable.\n const captureState = useWorkspaceCapture(sessionId, {\n events,\n enabled: workspaceDataEnabled,\n });\n const captureAvailable = captureState.available;\n const liveWorkspaceExpected = sandboxAcceptsLiveIo(liveness);\n // Capability negotiation and capture resolution are independent requests. A\n // cold capability document can win that race by a few milliseconds; enabling\n // the leaf hooks in that window would make them interpret `capture: null` as a\n // real miss and issue Channel-A reads, waking the very box the capture exists\n // to avoid. Wait until the capture request has conclusively resolved. A warm\n // workspace never waits on this server-side snapshot.\n const capturePending =\n !liveWorkspaceExpected && (captureState.fileCount === null || captureState.loading);\n const repoPaths = useMemo(() => {\n const advertised = capabilities?.Git.repos ?? [];\n if (advertised.length > 0) return advertised;\n return captureState.capture?.repos.map((repo) => repo.root) ?? [];\n }, [capabilities?.Git.repos, captureState.capture]);\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 // No passive Channel-A reads while cold, even after a conclusive capture\n // miss. A missing capture gets an explicit \"Open live workspace\" gate.\n enabled: filesEnabled && (captureAvailable || (fileSystemOn && liveWorkspaceExpected)),\n // A cold sandbox can become warm while the first agent command still owns\n // startup. Do not race that command with an automatic Files read. Keeping\n // this fence at turn scope also avoids unsafe millisecond gaps between\n // sequential tool calls; rendered state and explicit user actions remain.\n active: filesActive && !turnInFlight,\n // A deliberate canonical absolute-path open browses in the selected target's\n // advertised namespace, so the authoritative tree and link share exact paths.\n ...(isCanonicalAbsoluteSandboxPath(requestedFilePath) && capabilities?.FileSystem.root\n ? { rootPath: capabilities.FileSystem.root }\n : {}),\n ...(fileSystemRoute ? { route: fileSystemRoute } : {}),\n repoPaths,\n liveness: liveIoLiveness,\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 [storedChangesComparison, setStoredChangesComparison] = useState<{\n sessionId: string;\n value: SandboxGitComparison;\n } | null>(null);\n const captureSupportsBranch =\n captureState.capture !== null &&\n captureState.capture.repos.length > 0 &&\n captureState.capture.repos.every((repo) => repo.branchDiff !== undefined);\n // A sleeping workspace can truthfully serve only the captured working-tree\n // comparison. A live workspace defaults to the branch comparison so committed\n // agent work remains visible. Explicit user selection is scoped per session.\n const changesComparison =\n storedChangesComparison?.sessionId === sessionId\n ? storedChangesComparison.value\n : liveWorkspaceExpected || captureSupportsBranch\n ? \"branch\"\n : \"working\";\n const setChangesComparison = useCallback(\n (value: SandboxGitComparison) => setStoredChangesComparison({ sessionId, value }),\n [sessionId],\n );\n const git = useSandboxGit(sessionId, {\n events,\n enabled:\n changesComparison === \"working\"\n ? workspaceDataEnabled && (captureAvailable || (gitOn && liveWorkspaceExpected))\n : changesComparison === \"branch\"\n ? workspaceDataEnabled && (captureSupportsBranch || (gitOn && liveWorkspaceExpected))\n : workspaceDataEnabled && gitOn && liveWorkspaceExpected,\n // Live Git belongs to the visible Changes surface. In particular, do not\n // turn an unresolved/default tab into a hidden provider read: that races the\n // agent's own sandbox commands and used to refresh after every tool output\n // even while Files was visibly selected.\n active: changesActive && !turnInFlight,\n repoPaths,\n liveness: liveIoLiveness,\n comparison: changesComparison,\n capture: changesComparison === \"staged\" ? null : captureState.capture,\n });\n useEffect(() => {\n if (\n changesComparison === \"branch\" &&\n git.error &&\n storedChangesComparison?.sessionId !== sessionId\n ) {\n // `origin/HEAD` is not guaranteed on a newly initialized repository, a\n // connected machine, or a clone whose remote was renamed. The implicit\n // live default must not strand the whole Changes surface when its ordinary\n // working-tree comparison is still valid. Fall back once; an explicit\n // user-selected Branch view remains selected and surfaces its real error.\n setStoredChangesComparison({ sessionId, value: \"working\" });\n }\n }, [changesComparison, git.error, sessionId, storedChangesComparison?.sessionId]);\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 (!terminalEnabled || 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 }, [terminalEnabled]);\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: (terminalEnabled && warmTerminal) || (workspaceDataEnabled && filesWarmRequested),\n capturedAt: captureState.capturedAt,\n });\n const workspaceWaking = chip.state === \"waking\";\n\n // The pre-paint default comes only from the durable capture. Default selection\n // must never dispatch live provider work: a live Git probe can overlap the\n // agent's first command, and an uncontrolled dock used to keep that probe\n // active forever after it visibly selected Files. A capture with reviewable\n // changes opens Changes; no capture (or an empty one) opens Files. The choice\n // latches once so later edits never steal the user's current tab.\n const defaultIdentity = `${sessionId}\\u0000${surfaceIdentity}`;\n const defaultTabRef = useRef<{ identity: string; value: string | null }>({\n identity: defaultIdentity,\n value: null,\n });\n if (defaultTabRef.current.identity !== defaultIdentity) {\n defaultTabRef.current = { identity: defaultIdentity, value: null };\n }\n const captureHasChanges =\n (captureState.fileCount ?? 0) > 0 ||\n (captureState.capture?.repos.some((repo) => (repo.branchDiff?.length ?? 0) > 0) ?? false);\n const captureUnavailable =\n (captureState.fileCount === 0 && !captureHasChanges) || captureState.error !== null;\n if (defaultTabRef.current.value === null) {\n if (initialTab && (!isWorkbenchSurface(initialTab) || surfaceSet.has(initialTab))) {\n defaultTabRef.current.value = initialTab;\n } else if (captureState.fileCount !== null && captureState.available) {\n defaultTabRef.current.value = sourceDrivenDefaultTab(\n captureHasChanges,\n changesEnabled,\n filesEnabled,\n );\n } else if (captureUnavailable && initialWorkspaceTab(events) === WORKBENCH_TAB_CHANGES) {\n defaultTabRef.current.value = sourceDrivenDefaultTab(true, changesEnabled, filesEnabled);\n } else if (captureState.fileCount !== null || captureState.error !== null) {\n // No durable review surface exists. Files owns the explicit live-workspace\n // gate; a user can open Changes deliberately if they need a fresh Git read.\n defaultTabRef.current.value = sourceDrivenDefaultTab(false, changesEnabled, filesEnabled);\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 — capture-backed and usable cold/offline when the host enables it.\n if (changesEnabled)\n list.push({\n id: WORKBENCH_TAB_CHANGES,\n label: \"Changes\",\n icon: <GitCompareArrowsIcon />,\n badge: dirtyCount > 0 ? <DirtyBadge count={dirtyCount} /> : undefined,\n content: (\n <ChangesTabBody\n git={git}\n comparison={changesComparison}\n onComparisonChange={setChangesComparison}\n captureAvailable={captureAvailable}\n captureRevision={captureState.revision}\n capturePending={capturePending}\n liveWorkspaceExpected={liveWorkspaceExpected}\n workspaceWaking={workspaceWaking}\n capabilitiesState={caps.state}\n capabilitiesError={caps.error}\n onRetry={caps.renegotiate}\n onWake={() => requestWarmIntent(\"warmFiles\")}\n {...(filesEnabled && onOpenFile\n ? {\n onOpenFile: (path: string) => {\n requestWarmIntent(\"warmFiles\");\n onOpenFile(path);\n },\n }\n : {})}\n />\n ),\n });\n\n // Files — capture-backed cold tree; live warm when the host enables it.\n if (filesEnabled)\n list.push({\n id: WORKBENCH_TAB_FILES,\n label: \"Files\",\n icon: <FileCode2Icon />,\n content: (\n <SandboxFiles\n key={sessionId}\n files={files}\n git={git}\n isNodeVisible={isFileNodeVisible}\n fileSystemAvailable={fileSystemOn || captureAvailable}\n editable={\n filesEditable && files.source === \"live\" && files.error === null && !files.loading\n }\n workspaceResting={\n !liveWorkspaceExpected &&\n liveness !== undefined &&\n !capturePending &&\n !captureAvailable &&\n !workspaceWaking\n }\n workspaceWaking={!liveWorkspaceExpected && !captureAvailable && workspaceWaking}\n liveWorkspaceReady={liveWorkspaceExpected}\n workspaceError={\n caps.error ??\n (caps.viewerCapReached\n ? new Error(\n \"The live workspace viewer limit has been reached. Close another viewer and retry.\",\n )\n : filesWarmRequested && caps.state === \"on-demand\" && !fileSystemOn\n ? new Error(\"This machine does not currently expose a live file system.\")\n : null)\n }\n onWakeWorkspace={() => {\n if (filesWarmRequested) caps.renegotiate();\n else requestWarmIntent(\"warmFiles\");\n }}\n {...(requestedFilePath\n ? {\n requestedPath: requestedFilePath,\n ...(requestedFileRequestId !== null && requestedFileRequestId !== undefined\n ? { requestedPathRequestId: requestedFileRequestId }\n : {}),\n requestedPathReady: sandboxAcceptsLiveIo(liveness),\n ...(requestedFileLine != null && requestedFileLine > 0\n ? { requestedLine: requestedFileLine }\n : {}),\n }\n : {})}\n // Ordinary capture browsing does not warm a box. The first edit — or an\n // explicit guarded-file open from Changes — is deliberate live-file intent.\n onEditIntent={() => requestWarmIntent(\"warmFiles\")}\n initialSelectedPath={initialFilePath}\n onSelectedPathChange={onFilePathChange}\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: WORKBENCH_TAB_TERMINAL,\n label: \"Terminal\",\n icon: <SquareTerminalIcon />,\n content: (\n <div className=\"h-full bg-og-bg p-1\">\n <SandboxTerminal\n key={sessionId}\n result={terminal}\n terminalCapability={capabilities?.Terminal ?? null}\n onActivate={() => requestWarmIntent(\"warmTerminal\")}\n onReconnectNeeded={caps.renegotiate}\n showHeader\n shell={capabilities?.Terminal.shell ?? undefined}\n liveness={liveness}\n {...(xtermTheme ? { theme: xtermTheme } : {})}\n />\n </div>\n ),\n });\n }\n\n // Browser — independent from sandbox capability negotiation. BrowserSessions\n // are workspace resources and may live in this agent's sandbox, a peer's\n // sandbox, a connected machine, or an external browser placement.\n if (browserEnabled) {\n list.push({\n id: WORKBENCH_TAB_BROWSER,\n label: \"Browser\",\n icon: <Globe2Icon />,\n content: (\n <Suspense fallback={<WorkbenchSurfaceLoading name=\"Browser\" />}>\n <LazyBrowserViewer\n key={sessionId}\n client={client}\n workspaceId={workspaceId}\n sessionId={sessionId}\n // WorkspaceDock mounts a heavy surface only after its first visit,\n // then keeps it mounted behind `hidden` when another tab is\n // selected. Keep that already-visited surface enabled while the\n // dock itself remains open: tearing down its controller + media\n // socket on every Browser↔Computer tab switch turned an ordinary\n // click into a multi-second cold reconnect. This does not eagerly\n // start BrowserViewer—the lazy panel is still unmounted until the\n // user/agent first visits it.\n enabled={workspaceVisible}\n onNotify={onNotify}\n initialBrowserSessionId={initialBrowserSessionId}\n onBrowserSessionIdChange={onBrowserSessionIdChange}\n {...(desktopEnabled ? { createLinkedComputer } : {})}\n {...(onOpenComputerSession ? { onOpenComputer: onOpenComputerSession } : {})}\n {...(browserWebSocketFactory ? { webSocketFactory: browserWebSocketFactory } : {})}\n {...(browserExtensionSetupUrl ? { browserExtensionSetupUrl } : {})}\n className=\"h-full\"\n />\n </Suspense>\n ),\n });\n }\n\n // Computer — stable legacy tab id, new workspace resource body. Like Browser,\n // it is independent from the selected agent's sandbox capability document.\n if (desktopEnabled) {\n list.push({\n id: WORKBENCH_TAB_DESKTOP,\n label: \"Desktop\",\n icon: <MonitorIcon />,\n content: (\n <Suspense fallback={<WorkbenchSurfaceLoading name=\"Desktop\" />}>\n <LazyComputerViewer\n key={sessionId}\n client={client}\n workspaceId={workspaceId}\n sessionId={sessionId}\n // Same visited-surface lifetime as Browser above. A live noVNC\n // connection survives tab switches and ResizeObserver re-fits its\n // canvas when this hidden panel becomes visible again, making the\n // second and later Computer opens local-machine fast.\n enabled={workspaceVisible}\n onNotify={onNotify}\n initialComputerSessionId={initialComputerSessionId}\n onComputerSessionIdChange={onComputerSessionIdChange}\n requestedComputerSessionId={requestedComputerSessionId}\n requestedComputerRequestId={requestedComputerRequestId}\n {...(computerWebSocketFactory ? { webSocketFactory: computerWebSocketFactory } : {})}\n className=\"h-full\"\n />\n </Suspense>\n ),\n });\n }\n\n return list;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n fileSystemOn,\n changesEnabled,\n filesEnabled,\n terminalOn,\n browserEnabled,\n desktopEnabled,\n captureAvailable,\n dirtyCount,\n warmTerminal,\n requestedFilePath,\n requestedFileRequestId,\n requestedFileLine,\n onOpenFile,\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n onOpenComputerSession,\n requestedComputerSessionId,\n requestedComputerRequestId,\n onNotify,\n browserWebSocketFactory,\n computerWebSocketFactory,\n workspaceVisible,\n resolvedActiveTab,\n client,\n workspaceId,\n liveness,\n sessionId,\n files,\n git,\n changesComparison,\n terminal,\n xtermTheme,\n capabilities,\n workspaceWaking,\n caps.state,\n caps.error,\n caps.viewerCapReached,\n caps.renegotiate,\n filesWarmRequested,\n requestWarmIntent,\n createLinkedComputer,\n ]);\n\n return {\n tabs,\n defaultTab,\n machine: {\n enabled: machineSurfaceEnabled,\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 /**\n * Built-in surfaces this host wants to expose. Omit for Changes, Files,\n * Terminal, Browser, and Desktop. Disabled surfaces remain behaviorally dormant.\n */\n surfaces?: readonly SandboxWorkspaceSurface[] | undefined;\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 from the durable workspace capture. */\n initialTab?: string | undefined;\n onActiveTabChange?: ((activeTab: string) => void) | undefined;\n initialFilePath?: string | null | undefined;\n onFilePathChange?: ((path: string | null) => void) | undefined;\n /** Presentation-only filter for Files tree nodes and selected-file viewing. */\n isFileNodeVisible?: FileNodeVisibilityPredicate | undefined;\n /**\n * Host request to open a workspace file (and optional line) in Files. A new\n * `requestId` re-opens even the same path.\n */\n openFileRequest?:\n | {\n path: string;\n line?: number | null;\n requestId: number;\n }\n | null\n | undefined;\n initialBrowserSessionId?: string | null | undefined;\n onBrowserSessionIdChange?: ((browserSessionId: string | null) => void) | undefined;\n initialComputerSessionId?: string | null | undefined;\n onComputerSessionIdChange?: ((computerSessionId: string | null) => void) | undefined;\n /** Host-routed notifications (no toast dependency in the package). */\n onNotify?: ((notification: WorkspaceNotification) => void) | undefined;\n /** Alternate Browser frame transport for non-browser runtimes and deterministic tests. */\n browserWebSocketFactory?: BrowserFrameWebSocketFactory | undefined;\n /** Alternate Computer frame transport for non-browser runtimes and deterministic tests. */\n computerWebSocketFactory?: ComputerFrameWebSocketFactory | undefined;\n /** Host-owned setup page or store listing for attaching an existing Chrome profile. */\n browserExtensionSetupUrl?: string | undefined;\n /** Controlled collapsed state for hosts with their own dock toggle. */\n collapsed?: boolean | undefined;\n onCollapsedChange?: ((collapsed: boolean) => void) | undefined;\n /** Keep the dock's built-in collapse control with controlled collapsed state. */\n showCollapseControl?: boolean | 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/compiled.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 surfaces,\n leadingTabs,\n trailingTabs,\n initialTab,\n onActiveTabChange,\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n openFileRequest,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n onNotify,\n browserWebSocketFactory,\n computerWebSocketFactory,\n browserExtensionSetupUrl,\n collapsed,\n onCollapsedChange,\n showCollapseControl,\n mobileLeadingControl,\n autoSaveId,\n defaultSize,\n minSize,\n maxSize,\n className,\n } = props;\n\n const [storedSelection, setStoredSelection] = useState<{\n sessionId: string;\n tab: string;\n } | null>(null);\n const [requestedFile, setRequestedFile] = useState<{\n sessionId: string;\n path: string;\n line: number | null;\n requestId: number;\n } | null>(null);\n const [requestedComputer, setRequestedComputer] = useState<{\n sessionId: string;\n computerSessionId: string;\n requestId: number;\n } | null>(null);\n const nextFileRequestId = useRef(0);\n const nextComputerRequestId = useRef(0);\n const selectedTab = storedSelection?.sessionId === sessionId ? storedSelection.tab : null;\n const activeTabHint = selectedTab ?? initialTab ?? leadingTabs?.[0]?.id ?? null;\n const openFile = useCallback(\n (path: string, line?: number | null) => {\n setRequestedFile({\n sessionId,\n path,\n line: line != null && line > 0 ? line : null,\n requestId: ++nextFileRequestId.current,\n });\n setStoredSelection({ sessionId, tab: WORKBENCH_TAB_FILES });\n onActiveTabChange?.(WORKBENCH_TAB_FILES);\n onFilePathChange?.(path);\n onCollapsedChange?.(false);\n },\n [onActiveTabChange, onCollapsedChange, onFilePathChange, sessionId],\n );\n const handledOpenFileRequestId = useRef<number | null>(null);\n useEffect(() => {\n if (!openFileRequest) return;\n if (handledOpenFileRequestId.current === openFileRequest.requestId) return;\n handledOpenFileRequestId.current = openFileRequest.requestId;\n openFile(openFileRequest.path, openFileRequest.line);\n }, [openFile, openFileRequest]);\n const openComputer = useCallback(\n (computerSessionId: string) => {\n nextComputerRequestId.current += 1;\n setRequestedComputer({\n sessionId,\n computerSessionId,\n requestId: nextComputerRequestId.current,\n });\n setStoredSelection({ sessionId, tab: WORKBENCH_TAB_DESKTOP });\n onActiveTabChange?.(WORKBENCH_TAB_DESKTOP);\n onComputerSessionIdChange?.(computerSessionId);\n },\n [onActiveTabChange, onComputerSessionIdChange, sessionId],\n );\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 ...(surfaces ? { surfaces } : {}),\n ...(initialTab ? { initialTab } : {}),\n activeTab: activeTabHint,\n workspaceVisible: collapsed !== true,\n ...(onNotify ? { onNotify } : {}),\n ...(browserWebSocketFactory ? { browserWebSocketFactory } : {}),\n ...(computerWebSocketFactory ? { computerWebSocketFactory } : {}),\n ...(browserExtensionSetupUrl ? { browserExtensionSetupUrl } : {}),\n initialFilePath,\n onFilePathChange,\n isFileNodeVisible,\n initialBrowserSessionId,\n onBrowserSessionIdChange,\n initialComputerSessionId,\n onComputerSessionIdChange,\n requestedFilePath: requestedFile?.sessionId === sessionId ? requestedFile.path : null,\n requestedFileRequestId: requestedFile?.sessionId === sessionId ? requestedFile.requestId : null,\n requestedFileLine: requestedFile?.sessionId === sessionId ? requestedFile.line : null,\n onOpenFile: openFile,\n onOpenComputerSession: openComputer,\n requestedComputerSessionId:\n requestedComputer?.sessionId === sessionId ? requestedComputer.computerSessionId : null,\n requestedComputerRequestId:\n requestedComputer?.sessionId === sessionId ? requestedComputer.requestId : null,\n });\n\n // A user's tab click wins forever; before that we follow the source-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 preferredTab = selectedTab ?? defaultTab;\n const activeTab =\n preferredTab && tabs.some((tab) => tab.id === preferredTab) ? preferredTab : tabs[0]?.id;\n const selectTab = useCallback(\n (tab: string) => {\n setStoredSelection({ sessionId, tab });\n onActiveTabChange?.(tab);\n },\n [onActiveTabChange, sessionId],\n );\n useEffect(() => {\n if (selectedTab !== null || defaultTab === null) return;\n // Once the source-driven choice resolves, make it the real controlled\n // selection. Without this handoff the dock could visibly show Files while\n // the data hooks continued treating the selection as unresolved.\n setStoredSelection({ sessionId, tab: defaultTab });\n }, [defaultTab, selectedTab, sessionId]);\n\n return (\n <WorkspaceDock\n primary={primary}\n tabs={tabs}\n {...(activeTab !== undefined ? { activeTab } : {})}\n onActiveTabChange={selectTab}\n {...(machine.enabled\n ? {\n headerAccessory: <MachineStateChip chip={machine.chip} />,\n }\n : {})}\n {...(mobileLeadingControl !== undefined ? { mobileLeadingControl } : {})}\n {...(collapsed !== undefined ? { collapsed } : {})}\n {...(onCollapsedChange ? { onCollapsedChange } : {})}\n {...(showCollapseControl !== undefined ? { showCollapseControl } : {})}\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-og-xs text-og-fg-muted\">\n {count}\n </span>\n );\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 motion-reduce:animate-none\";\n return \"bg-og-fg-subtle\";\n}\n\n/**\n * The dock-header machine status: one quiet, truthful live/waking/resting\n * indicator. It is intentionally not interactive; detailed machine controls do\n * not belong in a transient popover above the workspace tabs.\n */\nfunction MachineStateChip({ chip }: { chip: MachineChip }) {\n return (\n <div\n role=\"status\"\n aria-label={`Machine: ${chip.label}`}\n className=\"inline-flex min-h-7 min-w-0 items-center gap-1.5 px-2 py-1 text-og-xs font-medium text-og-fg-muted 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=\"min-w-0 max-w-[11rem] truncate\">{chip.label}</span>\n </div>\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 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11\"\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 comparison,\n onComparisonChange,\n ...props\n}: {\n comparison: SandboxGitComparison;\n onComparisonChange: (comparison: SandboxGitComparison) => void;\n} & Parameters<typeof ChangesTabContent>[0]) {\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <div className=\"flex shrink-0 items-center gap-1 border-b border-og-border bg-og-surface-1 px-2 py-1.5\">\n {(\n [\n [\"branch\", \"Branch\"],\n [\"working\", \"Uncommitted\"],\n [\"staged\", \"Staged\"],\n ] as const\n ).map(([value, label]) => (\n <button\n key={value}\n type=\"button\"\n aria-pressed={comparison === value}\n onClick={() => onComparisonChange(value)}\n className={cn(\n \"rounded-og-sm px-2 py-1 text-og-xs font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 pointer-coarse:min-h-11\",\n comparison === value\n ? \"bg-og-surface-2 text-og-fg shadow-sm\"\n : \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\",\n )}\n >\n {label}\n </button>\n ))}\n </div>\n <div className=\"min-h-0 flex-1\">\n <ChangesTabContent comparison={comparison} {...props} />\n </div>\n </div>\n );\n}\n\nfunction ChangesTabContent({\n git,\n comparison,\n captureAvailable,\n captureRevision,\n capturePending,\n liveWorkspaceExpected,\n workspaceWaking,\n capabilitiesState,\n capabilitiesError,\n onRetry,\n onWake,\n onOpenFile,\n}: {\n git: UseSandboxGitResult;\n comparison: SandboxGitComparison;\n captureAvailable: boolean;\n captureRevision: number | null;\n capturePending: boolean;\n liveWorkspaceExpected: boolean;\n workspaceWaking: boolean;\n capabilitiesState: string;\n capabilitiesError: Error | null;\n onRetry: () => void;\n onWake: () => void;\n onOpenFile?: ((path: string) => void) | undefined;\n}) {\n const diff = git.diff;\n\n if (diff.length > 0) {\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n {git.error ? (\n <div\n role=\"status\"\n aria-live=\"polite\"\n data-opengeni-changes-degraded\n className=\"flex shrink-0 items-center gap-2 border-b border-og-status-running/30 bg-og-status-running/10 px-2 py-1.5 text-og-xs text-og-fg-muted\"\n >\n <TriangleAlertIcon className=\"size-3.5 shrink-0 text-og-status-running\" aria-hidden />\n <span className=\"min-w-0 flex-1\">\n {git.source === \"capture\"\n ? \"Live changes are temporarily unavailable. Showing the latest captured revision.\"\n : \"Live refresh failed. Showing the last loaded changes.\"}\n </span>\n <button\n type=\"button\"\n onClick={() => void git.refresh()}\n disabled={git.loading}\n className=\"inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11\"\n >\n <RefreshCwIcon\n className={cn(\"size-3\", git.loading && \"animate-spin motion-reduce:animate-none\")}\n aria-hidden\n />\n Retry\n </button>\n </div>\n ) : null}\n <div className=\"min-h-0 flex-1\">\n <WorkbenchChanges\n diff={diff}\n source={git.source}\n capturedAt={git.capturedAt}\n captureRevision={captureRevision}\n {...(onOpenFile ? { onOpenFile } : {})}\n />\n </div>\n </div>\n );\n }\n\n if (capabilitiesError && !captureAvailable) {\n return (\n <CenteredState icon={<TriangleAlertIcon className=\"size-5\" aria-hidden />} tone=\"danger\">\n <p className=\"text-og-sm font-medium text-og-fg\">Sandbox unavailable</p>\n <p data-contrast-audited 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 (\n (capturePending || capabilitiesState === \"negotiating\") &&\n !captureAvailable &&\n !workspaceWaking\n ) {\n return (\n <CenteredState\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">Connecting workspace</p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">\n Looking for the latest files and changes…\n </p>\n </CenteredState>\n );\n }\n\n if (!liveWorkspaceExpected && (comparison !== \"working\" || !captureAvailable)) {\n return (\n <CenteredState\n icon={\n workspaceWaking ? (\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n ) : (\n <CpuIcon className=\"size-5\" aria-hidden />\n )\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">\n {workspaceWaking ? \"Waking workspace\" : \"Workspace is resting\"}\n </p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">\n {workspaceWaking\n ? \"Connecting to the live working tree…\"\n : comparison === \"branch\"\n ? \"Wake the sandbox to compare this branch with the remote default branch.\"\n : comparison === \"staged\"\n ? \"Wake the sandbox to inspect staged changes.\"\n : \"No captured revision is available yet. Wake the sandbox to inspect uncommitted changes.\"}\n </p>\n {!workspaceWaking ? (\n <DockActionButton onClick={onWake}>\n <CpuIcon className=\"size-3\" />\n Open live workspace\n </DockActionButton>\n ) : null}\n </CenteredState>\n );\n }\n\n if (git.loading && git.source === null) {\n return (\n <CenteredState\n icon={\n <LoaderCircleIcon\n className=\"size-5 animate-spin motion-reduce:animate-none\"\n aria-hidden\n />\n }\n >\n <p className=\"text-og-sm font-medium text-og-fg\">Loading workspace</p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">Reading the current working tree…</p>\n </CenteredState>\n );\n }\n\n return (\n <CenteredState icon={<CircleCheckIcon className=\"size-5\" aria-hidden />} tone=\"success\">\n <p className=\"text-og-sm font-medium text-og-fg\">\n {comparison === \"branch\"\n ? \"No branch changes\"\n : comparison === \"staged\"\n ? \"No staged changes\"\n : \"No uncommitted changes\"}\n </p>\n <p className=\"text-og-sm leading-5 text-og-fg-subtle\">\n {comparison === \"branch\"\n ? \"This branch matches the remote default branch.\"\n : comparison === \"staged\"\n ? \"Stage files to review the next commit here.\"\n : \"Local edits not yet committed will appear here.\"}\n </p>\n </CenteredState>\n );\n}\n\nfunction CenteredState({\n children,\n icon,\n tone = \"neutral\",\n}: {\n children: ReactNode;\n icon?: ReactNode | undefined;\n tone?: \"neutral\" | \"success\" | \"danger\";\n}) {\n return (\n <div\n role={tone === \"danger\" ? \"alert\" : \"status\"}\n aria-atomic=\"true\"\n aria-live={tone === \"danger\" ? \"assertive\" : \"polite\"}\n className=\"grid h-full place-items-center p-6 text-center\"\n >\n <div className=\"flex max-w-sm flex-col items-center gap-2.5\">\n {icon ? (\n <span\n className={cn(\n \"grid size-10 place-items-center rounded-og-lg border bg-og-surface-1 shadow-sm\",\n tone === \"success\" && \"border-og-status-idle/30 text-og-status-idle\",\n tone === \"danger\" && \"border-og-status-failed/30 text-og-status-failed\",\n tone === \"neutral\" && \"border-og-border text-og-fg-muted\",\n )}\n >\n {icon}\n </span>\n ) : null}\n {children}\n </div>\n </div>\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\";\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: \"sharded\",\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` 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 // Refresh only after the durable post-selection event. `turn.started` is\n // emitted before account selection settles and races this authoritative read.\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","import type { SuperGrokAccount, SuperGrokAccountsResponse } from \"@opengeni/sdk\";\nimport { useCallback } from \"react\";\n\nimport { useOpenGeni, type ClientOverride } from \"../provider\";\nimport { useMutationRunner, usePolledValue } from \"./internal\";\n\nexport type SuperGrokAccountsClientLike = {\n listSuperGrokAccounts: (workspaceId: string) => Promise<SuperGrokAccountsResponse>;\n activateSuperGrokAccount?: (\n workspaceId: string,\n accountId: string,\n ) => Promise<{ activated: boolean; accountId: string }>;\n};\n\nexport type UseSuperGrokAccountsOptions = ClientOverride & {\n enabled?: boolean | undefined;\n pollIntervalMs?: number | undefined;\n supergrokClient?: SuperGrokAccountsClientLike | undefined;\n};\n\nexport type UseSuperGrokAccountsResult = {\n accounts: SuperGrokAccount[];\n activeAccountId: string | null;\n settings: SuperGrokAccountsResponse[\"settings\"];\n loading: boolean;\n refresh: () => Promise<void>;\n activate: (accountId: string) => Promise<boolean>;\n activating: boolean;\n mutationError: Error | null;\n};\n\nconst EMPTY: SuperGrokAccountsResponse = {\n accounts: [],\n activeAccountId: null,\n settings: {\n rotationEnabled: false,\n rotationStrategy: \"sharded\",\n activeCredentialId: null,\n },\n};\n\n/** Workspace-visible xAI accounts. Workspace scope is the connection default. */\nexport function useSuperGrokAccounts(\n options: UseSuperGrokAccountsOptions = {},\n): UseSuperGrokAccountsResult {\n const { client, workspaceId } = useOpenGeni(options);\n const supergrokClient =\n options.supergrokClient ?? (client as unknown as SuperGrokAccountsClientLike);\n const load = useCallback(\n async () => await supergrokClient.listSuperGrokAccounts(workspaceId),\n [supergrokClient, workspaceId],\n );\n const { data, loading, refresh } = usePolledValue(load, {\n enabled: options.enabled,\n pollIntervalMs: options.pollIntervalMs,\n });\n const { run, mutating: activating, mutationError } = useMutationRunner();\n const activate = useCallback(\n async (accountId: string): Promise<boolean> => {\n if (!supergrokClient.activateSuperGrokAccount) return false;\n const result = await run(async () => {\n await supergrokClient.activateSuperGrokAccount!(workspaceId, accountId);\n return true;\n });\n if (result) await refresh();\n return result === true;\n },\n [refresh, run, supergrokClient, workspaceId],\n );\n const state = data ?? EMPTY;\n return {\n accounts: state.accounts,\n activeAccountId: state.activeAccountId,\n settings: state.settings,\n loading,\n refresh,\n activate,\n activating,\n mutationError,\n };\n}\n"],"mappings":"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","names":["useCallback","useCallback","useCallback","useEffect","useEffect","useCallback","page","useCallback","useEffect","useRef","useCallback","useRef","useEffect","useCallback","useMemo","useCallback","useMemo","useCallback","useMemo","useMemo","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useCallback","useEffect","useRef","useRef","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useEffect","useCallback","useMemo","OpenGeniApiError","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","useEffect","useMemo","OpenGeniApiError","useCallback","useCallback","useEffect","useMemo","useRef","useState","useMemo","isLive","useRef","useState","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","normalizeRoot","useMemo","isLive","useRef","useState","useCallback","roots","useEffect","useCallback","useEffect","useRef","useState","useState","useRef","useCallback","useEffect","useCallback","useEffect","useMemo","useRef","useState","useMemo","useState","useRef","useEffect","useCallback","useMemo","useMemo","useEffect","useRef","useState","useState","useRef","useEffect","jsx","jsxs","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useCallback","useEffect","useId","useLayoutEffect","useMemo","useRef","useState","useEffect","useMemo","useMemo","useEffect","Fragment","jsx","jsxs","useEffect","useLayoutEffect","parentOf","pathIsInsideDirectory","useState","useRef","useId","useCallback","useMemo","item","useCallback","useEffect","useId","useLayoutEffect","useMemo","useRef","useState","VList","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useEffect","useLayoutEffect","STATUS_TINT","VList","useRef","useState","useId","useMemo","useCallback","jsx","useEffect","useState","jsx","useState","useEffect","useCallback","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useCallback","useMemo","FileWarningIcon","useCallback","useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","FileWarningIcon","useCallback","useEffect","useId","useLayoutEffect","useRef","useState","XIcon","Group","Panel","Separator","Fragment","jsx","jsxs","useEffect","useLayoutEffect","useState","useRef","useCallback","frame","XIcon","Group","Panel","Separator","useId","lazy","Suspense","useCallback","useEffect","useMemo","useRef","useState","FileCode2Icon","LoaderCircleIcon","RefreshCwIcon","TriangleAlertIcon","jsx","jsxs","lazy","LoaderCircleIcon","useCallback","useState","useRef","useEffect","useMemo","FileCode2Icon","Suspense","TriangleAlertIcon","RefreshCwIcon","useCallback","useState","useCallback","useState","useCallback","useCallback"]}
|