@opengeni/react 0.6.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -98,7 +98,7 @@ function useSession(sessionId, options = {}) {
98
98
  }
99
99
 
100
100
  // src/hooks/use-session-events.ts
101
- import { useEffect as useEffect3, useMemo as useMemo2, useRef, useState as useState8 } from "react";
101
+ import { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState8 } from "react";
102
102
 
103
103
  // src/timeline/projection.ts
104
104
  var WORKER_SPAWN_TOOL = "session_create";
@@ -352,7 +352,7 @@ ${message}` : message;
352
352
  case "turn.failed": {
353
353
  const hadActivity = hasTurnActivity(items, turnId);
354
354
  const failureText = failureMessage(payload);
355
- finalizeOpen(turnId, "failed");
355
+ finalizeOpen(turnId, "cancelled");
356
356
  items.push(turnEndItem(event, "failed", failureText));
357
357
  if (!hadActivity) {
358
358
  items.push({
@@ -594,8 +594,14 @@ function stampTurnOutcome(groups, turnEnd) {
594
594
  }
595
595
  }
596
596
  function applyTurnOutcome(group, turnEnd) {
597
- group.outcome = turnEnd.outcome;
598
- if (turnEnd.failureText) {
597
+ if (turnEnd.outcome === "complete") {
598
+ group.outcome = "complete";
599
+ return;
600
+ }
601
+ const hasFailed = group.items.some((item) => "status" in item && item.status === "failed");
602
+ const hasInterrupted = group.items.some((item) => "status" in item && item.status === "cancelled");
603
+ group.outcome = hasFailed ? "failed" : hasInterrupted ? "cancelled" : "complete";
604
+ if (turnEnd.failureText && hasFailed) {
599
605
  group.failureText = turnEnd.failureText;
600
606
  }
601
607
  }
@@ -2492,6 +2498,18 @@ function createDefaultToolRegistry(options = {}) {
2492
2498
 
2493
2499
  // src/timeline/activity-rail.tsx
2494
2500
  import { BotIcon, BrainIcon, SquareTerminalIcon } from "lucide-react";
2501
+
2502
+ // src/timeline/entrance.tsx
2503
+ import { createContext as createContext3, useContext as useContext3, useRef } from "react";
2504
+ var EntranceAnimationContext = createContext3(true);
2505
+ var EntranceAnimationProvider = EntranceAnimationContext.Provider;
2506
+ function useEntranceAnimation() {
2507
+ const enabled = useContext3(EntranceAnimationContext);
2508
+ const captured = useRef(enabled);
2509
+ return captured.current;
2510
+ }
2511
+
2512
+ // src/timeline/activity-rail.tsx
2495
2513
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2496
2514
  function familyOf(item) {
2497
2515
  if (item.kind === "tool-call") {
@@ -2500,6 +2518,7 @@ function familyOf(item) {
2500
2518
  return item.kind;
2501
2519
  }
2502
2520
  function ActivityRail({ items, toolRegistry = defaultToolRegistry, onOpenSession, bare, className }) {
2521
+ const enter = useEntranceAnimation();
2503
2522
  return /* @__PURE__ */ jsx8(
2504
2523
  "div",
2505
2524
  {
@@ -2508,7 +2527,8 @@ function ActivityRail({ items, toolRegistry = defaultToolRegistry, onOpenSession
2508
2527
  // calm cluster; a family change opens real breathing room (mt-3) below,
2509
2528
  // so a long rail reads as a few clusters, not a metronome of rows.
2510
2529
  "flex flex-col gap-0.5",
2511
- !bare && "animate-og-enter border-l-2 border-og-border pl-3 sm:pl-4",
2530
+ !bare && "border-l-2 border-og-border pl-3 sm:pl-4",
2531
+ !bare && enter && "animate-og-enter",
2512
2532
  className
2513
2533
  ),
2514
2534
  children: items.map((item, index) => {
@@ -2630,8 +2650,9 @@ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2630
2650
  function TurnSummary({ items, outcome, failureText, durationMs, defaultOpen, children }) {
2631
2651
  const forcedDefaultOpen = useForcedDefaultOpen();
2632
2652
  const [open, setOpen] = useState7(defaultOpen ?? forcedDefaultOpen ?? false);
2653
+ const enter = useEntranceAnimation();
2633
2654
  const facets = summarizeTurn(items, durationMs);
2634
- return /* @__PURE__ */ jsxs7(Collapsible2.Root, { open, onOpenChange: setOpen, className: "animate-og-enter", children: [
2655
+ return /* @__PURE__ */ jsxs7(Collapsible2.Root, { open, onOpenChange: setOpen, className: enter ? "animate-og-enter" : void 0, children: [
2635
2656
  /* @__PURE__ */ jsxs7(
2636
2657
  Collapsible2.Trigger,
2637
2658
  {
@@ -2734,22 +2755,42 @@ function formatDurationFacet(durationMs) {
2734
2755
  }
2735
2756
 
2736
2757
  // src/hooks/use-session-events.ts
2758
+ var TAIL_PAGE_SIZE = 5e3;
2759
+ var INITIAL_GROUP_TARGET = 48;
2760
+ var INITIAL_FETCH_CAP = 3;
2761
+ var OLDER_GROUP_TARGET = 32;
2762
+ var OLDER_FETCH_CAP = 2;
2763
+ var BOUNDARY_PAGE_CAP = 4;
2737
2764
  function useSessionEvents(sessionId, options = {}) {
2738
2765
  const { client, workspaceId } = useOpenGeni(options);
2739
2766
  const enabled = options.enabled ?? true;
2740
2767
  const after = options.after ?? 0;
2768
+ const replay = options.replay ?? "windowed";
2769
+ const fullReplay = replay === "full" || after !== 0;
2741
2770
  const [events, setEvents] = useState8([]);
2742
2771
  const [connectionState, setConnectionState] = useState8("idle");
2743
2772
  const [error, setError] = useState8(null);
2744
- const lastSequenceRef = useRef(after);
2745
- const streamKeyRef = useRef(null);
2773
+ const [hasOlder, setHasOlder] = useState8(false);
2774
+ const [loadingOlder, setLoadingOlder] = useState8(false);
2775
+ const lastSequenceRef = useRef2(after);
2776
+ const oldestSequenceRef = useRef2(null);
2777
+ const hasOlderRef = useRef2(false);
2778
+ const loadingOlderRef = useRef2(false);
2779
+ const streamKeyRef = useRef2(null);
2780
+ const generationRef = useRef2(0);
2746
2781
  useEffect3(() => {
2747
- const streamKey = `${workspaceId}\0${sessionId ?? ""}\0${after}`;
2782
+ const streamKey = `${workspaceId}\0${sessionId ?? ""}\0${after}\0${fullReplay ? "full" : "windowed"}`;
2748
2783
  if (streamKeyRef.current !== streamKey) {
2749
2784
  streamKeyRef.current = streamKey;
2785
+ generationRef.current += 1;
2750
2786
  setEvents([]);
2751
2787
  setError(null);
2788
+ setHasOlder(false);
2789
+ setLoadingOlder(false);
2752
2790
  lastSequenceRef.current = after;
2791
+ oldestSequenceRef.current = null;
2792
+ hasOlderRef.current = false;
2793
+ loadingOlderRef.current = false;
2753
2794
  }
2754
2795
  if (!sessionId || !enabled) {
2755
2796
  setConnectionState("idle");
@@ -2767,7 +2808,7 @@ function useSessionEvents(sessionId, options = {}) {
2767
2808
  pending = [];
2768
2809
  const lastInBatch = batch[batch.length - 1];
2769
2810
  if (lastInBatch) {
2770
- lastSequenceRef.current = lastInBatch.sequence;
2811
+ lastSequenceRef.current = Math.max(lastSequenceRef.current, ...batch.map(eventResumeSequence));
2771
2812
  }
2772
2813
  setEvents((existing) => [...existing, ...batch]);
2773
2814
  };
@@ -2776,6 +2817,24 @@ function useSessionEvents(sessionId, options = {}) {
2776
2817
  };
2777
2818
  void (async () => {
2778
2819
  try {
2820
+ if (!fullReplay) {
2821
+ setConnectionState("connecting");
2822
+ const window2 = await loadEventWindow(client, workspaceId, sessionId, {
2823
+ before: Number.MAX_SAFE_INTEGER,
2824
+ pageSize: TAIL_PAGE_SIZE,
2825
+ targetGroups: INITIAL_GROUP_TARGET,
2826
+ maxFetches: INITIAL_FETCH_CAP,
2827
+ signal: controller.signal
2828
+ });
2829
+ if (controller.signal.aborted) {
2830
+ return;
2831
+ }
2832
+ oldestSequenceRef.current = window2.oldestSequence;
2833
+ hasOlderRef.current = window2.hasOlder;
2834
+ lastSequenceRef.current = window2.newestSequence;
2835
+ setHasOlder(window2.hasOlder);
2836
+ setEvents(window2.events);
2837
+ }
2779
2838
  const stream = client.streamEvents(workspaceId, sessionId, {
2780
2839
  after: lastSequenceRef.current,
2781
2840
  signal: controller.signal,
@@ -2807,7 +2866,51 @@ function useSessionEvents(sessionId, options = {}) {
2807
2866
  clearTimeout(flushTimer);
2808
2867
  }
2809
2868
  };
2810
- }, [client, workspaceId, sessionId, after, enabled]);
2869
+ }, [client, workspaceId, sessionId, after, enabled, fullReplay]);
2870
+ const loadOlder = useCallback3(async () => {
2871
+ if (!sessionId || fullReplay || loadingOlderRef.current || !hasOlderRef.current) {
2872
+ return false;
2873
+ }
2874
+ const before = oldestSequenceRef.current;
2875
+ if (before === null) {
2876
+ hasOlderRef.current = false;
2877
+ setHasOlder(false);
2878
+ return false;
2879
+ }
2880
+ const generation = generationRef.current;
2881
+ loadingOlderRef.current = true;
2882
+ setLoadingOlder(true);
2883
+ try {
2884
+ const window2 = await loadEventWindow(client, workspaceId, sessionId, {
2885
+ before,
2886
+ pageSize: TAIL_PAGE_SIZE,
2887
+ targetGroups: OLDER_GROUP_TARGET,
2888
+ maxFetches: OLDER_FETCH_CAP
2889
+ });
2890
+ if (generationRef.current !== generation) {
2891
+ return false;
2892
+ }
2893
+ if (window2.events.length === 0) {
2894
+ oldestSequenceRef.current = null;
2895
+ hasOlderRef.current = false;
2896
+ setHasOlder(false);
2897
+ return false;
2898
+ }
2899
+ oldestSequenceRef.current = window2.oldestSequence;
2900
+ hasOlderRef.current = window2.hasOlder;
2901
+ setHasOlder(window2.hasOlder);
2902
+ setEvents((existing) => {
2903
+ assertPrependOrder(existing, window2.events);
2904
+ return [...window2.events, ...existing];
2905
+ });
2906
+ return window2.hasOlder;
2907
+ } finally {
2908
+ if (generationRef.current === generation) {
2909
+ loadingOlderRef.current = false;
2910
+ setLoadingOlder(false);
2911
+ }
2912
+ }
2913
+ }, [client, workspaceId, sessionId, fullReplay]);
2811
2914
  const timeline = useMemo2(() => buildTimeline(events), [events]);
2812
2915
  const sessionStatus = useMemo2(() => sessionStatusFromEvents(events), [events]);
2813
2916
  return {
@@ -2816,12 +2919,143 @@ function useSessionEvents(sessionId, options = {}) {
2816
2919
  sessionStatus,
2817
2920
  connectionState,
2818
2921
  lastSequence: lastSequenceRef.current,
2922
+ hasOlder: fullReplay ? false : hasOlder,
2923
+ loadingOlder: fullReplay ? false : loadingOlder,
2924
+ loadOlder,
2819
2925
  error
2820
2926
  };
2821
2927
  }
2928
+ async function loadEventWindow(client, workspaceId, sessionId, options) {
2929
+ let cursor = options.before;
2930
+ let buffer = [];
2931
+ let reachedStart = false;
2932
+ let fetches = 0;
2933
+ while (fetches < options.maxFetches) {
2934
+ if (buffer.length > 0 && groupCount(buffer) >= options.targetGroups) {
2935
+ break;
2936
+ }
2937
+ const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {
2938
+ pageSize: options.pageSize,
2939
+ ...options.signal ? { signal: options.signal } : {}
2940
+ });
2941
+ fetches += 1;
2942
+ if (page.length === 0) {
2943
+ reachedStart = true;
2944
+ break;
2945
+ }
2946
+ assertAscending(page);
2947
+ buffer = [...page, ...buffer];
2948
+ cursor = page[0].sequence;
2949
+ if (isLogStart(page[0])) {
2950
+ reachedStart = true;
2951
+ break;
2952
+ }
2953
+ }
2954
+ let snapPages = 0;
2955
+ while (!reachedStart && findBoundaryIndex(buffer) === -1 && snapPages < BOUNDARY_PAGE_CAP && fetches < options.maxFetches) {
2956
+ const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {
2957
+ pageSize: options.pageSize,
2958
+ ...options.signal ? { signal: options.signal } : {}
2959
+ });
2960
+ fetches += 1;
2961
+ snapPages += 1;
2962
+ if (page.length === 0) {
2963
+ reachedStart = true;
2964
+ break;
2965
+ }
2966
+ assertAscending(page);
2967
+ buffer = [...page, ...buffer];
2968
+ cursor = page[0].sequence;
2969
+ if (isLogStart(page[0])) {
2970
+ reachedStart = true;
2971
+ break;
2972
+ }
2973
+ }
2974
+ if (!reachedStart) {
2975
+ const boundary = findBoundaryIndex(buffer);
2976
+ if (boundary > 0) {
2977
+ buffer = buffer.slice(boundary);
2978
+ }
2979
+ }
2980
+ const oldest = buffer[0] ?? null;
2981
+ const newest = buffer[buffer.length - 1] ?? null;
2982
+ return {
2983
+ events: buffer,
2984
+ oldestSequence: oldest?.sequence ?? null,
2985
+ newestSequence: newest ? maxResumeSequence(buffer) : 0,
2986
+ hasOlder: buffer.length > 0 && !reachedStart && oldest?.type !== "session.created"
2987
+ };
2988
+ }
2989
+ function findBoundaryIndex(events) {
2990
+ for (let index = 0; index < events.length; index += 1) {
2991
+ const type = events[index].type;
2992
+ if (type === "session.created" || type === "user.message") {
2993
+ return index;
2994
+ }
2995
+ }
2996
+ return -1;
2997
+ }
2998
+ async function loadPreviousPage(client, workspaceId, sessionId, before, options) {
2999
+ if (options.signal?.aborted) {
3000
+ throw abortError();
3001
+ }
3002
+ const requested = options.pageSize;
3003
+ if (requested === 0) {
3004
+ return Object.assign([], { requested });
3005
+ }
3006
+ const page = await client.listEvents(workspaceId, sessionId, { before, limit: requested, compact: true });
3007
+ if (options.signal?.aborted) {
3008
+ throw abortError();
3009
+ }
3010
+ return Object.assign(page, { requested });
3011
+ }
3012
+ function groupCount(events) {
3013
+ if (events.length === 0) {
3014
+ return 0;
3015
+ }
3016
+ return groupTimeline(buildTimeline(events)).length;
3017
+ }
3018
+ function isLogStart(event) {
3019
+ return event.type === "session.created" || event.sequence <= 1;
3020
+ }
3021
+ function maxResumeSequence(events) {
3022
+ return events.reduce((max, event) => Math.max(max, eventResumeSequence(event)), 0);
3023
+ }
3024
+ function eventResumeSequence(event) {
3025
+ const payload = asRecord2(event.payload);
3026
+ const coalescedUntil = Number(payload.coalescedUntil);
3027
+ return Math.max(event.sequence, Number.isFinite(coalescedUntil) ? Math.floor(coalescedUntil) : 0);
3028
+ }
3029
+ function asRecord2(value) {
3030
+ return value && typeof value === "object" ? value : {};
3031
+ }
3032
+ function assertAscending(events) {
3033
+ for (let index = 1; index < events.length; index += 1) {
3034
+ if (events[index - 1].sequence >= events[index].sequence) {
3035
+ throw new Error("@opengeni/react: session events must be ordered by ascending sequence");
3036
+ }
3037
+ }
3038
+ }
3039
+ function assertPrependOrder(existing, older) {
3040
+ if (!shouldAssertDevelopment() || existing.length === 0 || older.length === 0) {
3041
+ return;
3042
+ }
3043
+ if (older[older.length - 1].sequence >= existing[0].sequence) {
3044
+ throw new Error("@opengeni/react: loadOlder returned overlapping session events");
3045
+ }
3046
+ }
3047
+ function shouldAssertDevelopment() {
3048
+ const processEnv = globalThis.process?.env;
3049
+ return processEnv !== void 0 && processEnv.NODE_ENV !== "production";
3050
+ }
3051
+ function abortError() {
3052
+ const error = new Error("The operation was aborted.");
3053
+ error.name = "AbortError";
3054
+ return error;
3055
+ }
2822
3056
 
2823
3057
  // src/hooks/use-composer.ts
2824
- import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef2, useState as useState9 } from "react";
3058
+ import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef3, useState as useState9 } from "react";
2825
3059
  function useComposer(sessionId, options = {}) {
2826
3060
  const { client, workspaceId } = useOpenGeni(options);
2827
3061
  const defaultMode = options.defaultMode ?? "queue";
@@ -2830,14 +3064,14 @@ function useComposer(sessionId, options = {}) {
2830
3064
  const [sending, setSending] = useState9(false);
2831
3065
  const [interrupting, setInterrupting] = useState9(false);
2832
3066
  const [error, setError] = useState9(null);
2833
- const pendingClientEventId = useRef2(null);
3067
+ const pendingClientEventId = useRef3(null);
2834
3068
  const onSent = options.onSent;
2835
- const modeRef = useRef2(mode);
3069
+ const modeRef = useRef3(mode);
2836
3070
  modeRef.current = mode;
2837
- const sendExtrasRef = useRef2(options.sendExtras);
3071
+ const sendExtrasRef = useRef3(options.sendExtras);
2838
3072
  sendExtrasRef.current = options.sendExtras;
2839
3073
  const targetKey = `${workspaceId}\0${sessionId ?? ""}`;
2840
- const targetKeyRef = useRef2(targetKey);
3074
+ const targetKeyRef = useRef3(targetKey);
2841
3075
  useEffect4(() => {
2842
3076
  if (targetKeyRef.current !== targetKey) {
2843
3077
  targetKeyRef.current = targetKey;
@@ -2847,7 +3081,7 @@ function useComposer(sessionId, options = {}) {
2847
3081
  setMode(defaultMode);
2848
3082
  }
2849
3083
  }, [targetKey, defaultMode]);
2850
- const send = useCallback3(
3084
+ const send = useCallback4(
2851
3085
  async (explicit) => {
2852
3086
  const draftAtSend = value;
2853
3087
  const text = (explicit ?? draftAtSend).trim();
@@ -2883,7 +3117,7 @@ function useComposer(sessionId, options = {}) {
2883
3117
  [client, workspaceId, sessionId, value, sending, onSent]
2884
3118
  );
2885
3119
  const hasReadyResources = (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;
2886
- const interrupt = useCallback3(
3120
+ const interrupt = useCallback4(
2887
3121
  async (reason) => {
2888
3122
  if (!sessionId || interrupting) {
2889
3123
  return;
@@ -2900,7 +3134,7 @@ function useComposer(sessionId, options = {}) {
2900
3134
  },
2901
3135
  [client, workspaceId, sessionId, interrupting]
2902
3136
  );
2903
- const updateValue = useCallback3((next) => {
3137
+ const updateValue = useCallback4((next) => {
2904
3138
  pendingClientEventId.current = null;
2905
3139
  setValue(next);
2906
3140
  }, []);
@@ -2915,7 +3149,7 @@ function useComposer(sessionId, options = {}) {
2915
3149
  interrupt,
2916
3150
  interrupting,
2917
3151
  error,
2918
- clearError: useCallback3(() => setError(null), [])
3152
+ clearError: useCallback4(() => setError(null), [])
2919
3153
  };
2920
3154
  }
2921
3155
  var FILE_ONLY_MESSAGE_TEXT = "(see attached files)";
@@ -2940,14 +3174,14 @@ function generateClientEventId() {
2940
3174
  }
2941
3175
 
2942
3176
  // src/hooks/use-file-attachments.ts
2943
- import { useCallback as useCallback4, useRef as useRef3, useState as useState10 } from "react";
3177
+ import { useCallback as useCallback5, useRef as useRef4, useState as useState10 } from "react";
2944
3178
  var isImage = (file) => file.type.startsWith("image/");
2945
3179
  function useFileAttachments(options = {}) {
2946
3180
  const { client, workspaceId } = useOpenGeni(options);
2947
3181
  const pasteFilter = options.pasteFilter ?? isImage;
2948
3182
  const [attachments, setAttachments] = useState10([]);
2949
- const sources = useRef3(/* @__PURE__ */ new Map());
2950
- const startUpload = useCallback4((id, file) => {
3183
+ const sources = useRef4(/* @__PURE__ */ new Map());
3184
+ const startUpload = useCallback5((id, file) => {
2951
3185
  void client.uploadFile(workspaceId, {
2952
3186
  filename: file.name || "file",
2953
3187
  contentType: file.type || "application/octet-stream",
@@ -2958,7 +3192,7 @@ function useFileAttachments(options = {}) {
2958
3192
  setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "failed", error: error instanceof Error ? error.message : String(error) } : attachment));
2959
3193
  });
2960
3194
  }, [client, workspaceId]);
2961
- const addFiles = useCallback4((files) => {
3195
+ const addFiles = useCallback5((files) => {
2962
3196
  for (const file of files) {
2963
3197
  const id = crypto.randomUUID();
2964
3198
  sources.current.set(id, file);
@@ -2974,7 +3208,7 @@ function useFileAttachments(options = {}) {
2974
3208
  startUpload(id, file);
2975
3209
  }
2976
3210
  }, [startUpload]);
2977
- const retry = useCallback4((id) => {
3211
+ const retry = useCallback5((id) => {
2978
3212
  const file = sources.current.get(id);
2979
3213
  if (!file) {
2980
3214
  return;
@@ -2982,7 +3216,7 @@ function useFileAttachments(options = {}) {
2982
3216
  setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "uploading", error: void 0 } : attachment));
2983
3217
  startUpload(id, file);
2984
3218
  }, [startUpload]);
2985
- const addFromPaste = useCallback4((event) => {
3219
+ const addFromPaste = useCallback5((event) => {
2986
3220
  const clipboardFiles = event.clipboardData?.files;
2987
3221
  if (!clipboardFiles) {
2988
3222
  return;
@@ -2992,7 +3226,7 @@ function useFileAttachments(options = {}) {
2992
3226
  addFiles(files);
2993
3227
  }
2994
3228
  }, [addFiles, pasteFilter]);
2995
- const remove = useCallback4((id) => {
3229
+ const remove = useCallback5((id) => {
2996
3230
  sources.current.delete(id);
2997
3231
  setAttachments((current) => {
2998
3232
  const removed = current.find((attachment) => attachment.id === id);
@@ -3002,7 +3236,7 @@ function useFileAttachments(options = {}) {
3002
3236
  return current.filter((attachment) => attachment.id !== id);
3003
3237
  });
3004
3238
  }, []);
3005
- const clear = useCallback4(() => {
3239
+ const clear = useCallback5(() => {
3006
3240
  sources.current.clear();
3007
3241
  setAttachments((current) => {
3008
3242
  for (const attachment of current) {
@@ -3026,7 +3260,7 @@ function useFileAttachments(options = {}) {
3026
3260
  }
3027
3261
 
3028
3262
  // src/hooks/use-turn-queue.ts
3029
- import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef4, useState as useState11 } from "react";
3263
+ import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef5, useState as useState11 } from "react";
3030
3264
  function isTurnQueueEvent(event) {
3031
3265
  return event.type.startsWith("turn.");
3032
3266
  }
@@ -3070,9 +3304,9 @@ function useTurnQueue(sessionId, options = {}) {
3070
3304
  const [loading, setLoading] = useState11(enabled);
3071
3305
  const [error, setError] = useState11(null);
3072
3306
  const mutation = useMutationRunner();
3073
- const generation = useRef4(0);
3074
- const targetKeyRef = useRef4(null);
3075
- const load = useCallback5(async () => {
3307
+ const generation = useRef5(0);
3308
+ const targetKeyRef = useRef5(null);
3309
+ const load = useCallback6(async () => {
3076
3310
  if (!sessionId) {
3077
3311
  return;
3078
3312
  }
@@ -3121,7 +3355,7 @@ function useTurnQueue(sessionId, options = {}) {
3121
3355
  enabled,
3122
3356
  ...options.events !== void 0 ? { events: options.events } : {}
3123
3357
  });
3124
- const editTurn = useCallback5(
3358
+ const editTurn = useCallback6(
3125
3359
  async (turnId, update) => {
3126
3360
  if (!sessionId) {
3127
3361
  return null;
@@ -3137,7 +3371,7 @@ function useTurnQueue(sessionId, options = {}) {
3137
3371
  },
3138
3372
  [client, workspaceId, sessionId, mutation.run, load]
3139
3373
  );
3140
- const reorderTurns = useCallback5(
3374
+ const reorderTurns = useCallback6(
3141
3375
  async (turnIds) => {
3142
3376
  if (!sessionId || turnIds.length === 0) {
3143
3377
  return null;
@@ -3156,7 +3390,7 @@ function useTurnQueue(sessionId, options = {}) {
3156
3390
  },
3157
3391
  [client, workspaceId, sessionId, mutation.run, load]
3158
3392
  );
3159
- const removeTurn = useCallback5(
3393
+ const removeTurn = useCallback6(
3160
3394
  async (turnId) => {
3161
3395
  if (!sessionId) {
3162
3396
  return null;
@@ -3190,7 +3424,7 @@ function useTurnQueue(sessionId, options = {}) {
3190
3424
 
3191
3425
  // src/hooks/use-goal.ts
3192
3426
  import { OpenGeniApiError } from "@opengeni/sdk";
3193
- import { useCallback as useCallback6, useEffect as useEffect6, useRef as useRef5, useState as useState12 } from "react";
3427
+ import { useCallback as useCallback7, useEffect as useEffect6, useRef as useRef6, useState as useState12 } from "react";
3194
3428
  function isGoalEvent(event) {
3195
3429
  return event.type.startsWith("goal.");
3196
3430
  }
@@ -3203,9 +3437,9 @@ function useGoal(sessionId, options = {}) {
3203
3437
  const [loading, setLoading] = useState12(enabled);
3204
3438
  const [error, setError] = useState12(null);
3205
3439
  const mutation = useMutationRunner();
3206
- const generation = useRef5(0);
3207
- const targetKeyRef = useRef5(null);
3208
- const load = useCallback6(async () => {
3440
+ const generation = useRef6(0);
3441
+ const targetKeyRef = useRef6(null);
3442
+ const load = useCallback7(async () => {
3209
3443
  if (!sessionId) {
3210
3444
  return;
3211
3445
  }
@@ -3266,7 +3500,7 @@ function useGoal(sessionId, options = {}) {
3266
3500
  enabled,
3267
3501
  ...sharedEvents !== void 0 ? { events: sharedEvents } : {}
3268
3502
  });
3269
- const pause = useCallback6(
3503
+ const pause = useCallback7(
3270
3504
  async (rationale) => {
3271
3505
  if (!sessionId) {
3272
3506
  return null;
@@ -3282,7 +3516,7 @@ function useGoal(sessionId, options = {}) {
3282
3516
  },
3283
3517
  [client, workspaceId, sessionId, mutation.run]
3284
3518
  );
3285
- const resume = useCallback6(async () => {
3519
+ const resume = useCallback7(async () => {
3286
3520
  if (!sessionId) {
3287
3521
  return null;
3288
3522
  }
@@ -3309,12 +3543,12 @@ function useGoal(sessionId, options = {}) {
3309
3543
  }
3310
3544
 
3311
3545
  // src/hooks/use-session-control.ts
3312
- import { useCallback as useCallback7 } from "react";
3546
+ import { useCallback as useCallback8 } from "react";
3313
3547
  function useSessionControl(sessionId, options = {}) {
3314
3548
  const { client, workspaceId } = useOpenGeni(options);
3315
3549
  const interruptMutation = useMutationRunner();
3316
3550
  const approvalMutation = useMutationRunner();
3317
- const interrupt = useCallback7(
3551
+ const interrupt = useCallback8(
3318
3552
  async (reason) => {
3319
3553
  if (!sessionId) {
3320
3554
  return null;
@@ -3323,7 +3557,7 @@ function useSessionControl(sessionId, options = {}) {
3323
3557
  },
3324
3558
  [client, workspaceId, sessionId, interruptMutation.run]
3325
3559
  );
3326
- const decide = useCallback7(
3560
+ const decide = useCallback8(
3327
3561
  async (approvalId, decision, message) => {
3328
3562
  if (!sessionId) {
3329
3563
  return null;
@@ -3336,16 +3570,16 @@ function useSessionControl(sessionId, options = {}) {
3336
3570
  },
3337
3571
  [client, workspaceId, sessionId, approvalMutation.run]
3338
3572
  );
3339
- const approve = useCallback7(
3573
+ const approve = useCallback8(
3340
3574
  async (approvalId, message) => await decide(approvalId, "approve", message),
3341
3575
  [decide]
3342
3576
  );
3343
- const reject = useCallback7(
3577
+ const reject = useCallback8(
3344
3578
  async (approvalId, message) => await decide(approvalId, "reject", message),
3345
3579
  [decide]
3346
3580
  );
3347
3581
  const error = approvalMutation.mutationError ?? interruptMutation.mutationError;
3348
- const clearError = useCallback7(() => {
3582
+ const clearError = useCallback8(() => {
3349
3583
  interruptMutation.clearMutationError();
3350
3584
  approvalMutation.clearMutationError();
3351
3585
  }, [interruptMutation.clearMutationError, approvalMutation.clearMutationError]);
@@ -3361,11 +3595,11 @@ function useSessionControl(sessionId, options = {}) {
3361
3595
  }
3362
3596
 
3363
3597
  // src/hooks/use-scheduled-tasks.ts
3364
- import { useCallback as useCallback8 } from "react";
3598
+ import { useCallback as useCallback9 } from "react";
3365
3599
  function useScheduledTasks(options = {}) {
3366
3600
  const { client, workspaceId } = useOpenGeni(options);
3367
3601
  const limit = options.limit;
3368
- const load = useCallback8(
3602
+ const load = useCallback9(
3369
3603
  async () => await client.listScheduledTasks(workspaceId, limit !== void 0 ? { limit } : {}),
3370
3604
  [client, workspaceId, limit]
3371
3605
  );
@@ -3374,11 +3608,11 @@ function useScheduledTasks(options = {}) {
3374
3608
  }
3375
3609
 
3376
3610
  // src/hooks/use-workspace-sessions.ts
3377
- import { useCallback as useCallback9 } from "react";
3611
+ import { useCallback as useCallback10 } from "react";
3378
3612
  function useWorkspaceSessions(options = {}) {
3379
3613
  const { client, workspaceId } = useOpenGeni(options);
3380
3614
  const limit = options.limit;
3381
- const load = useCallback9(
3615
+ const load = useCallback10(
3382
3616
  async () => await client.listSessions(workspaceId, limit !== void 0 ? { limit } : {}),
3383
3617
  [client, workspaceId, limit]
3384
3618
  );
@@ -3387,13 +3621,13 @@ function useWorkspaceSessions(options = {}) {
3387
3621
  }
3388
3622
 
3389
3623
  // src/hooks/use-environments.ts
3390
- import { useCallback as useCallback10 } from "react";
3624
+ import { useCallback as useCallback11 } from "react";
3391
3625
  function useEnvironments(options = {}) {
3392
3626
  const { client, workspaceId } = useOpenGeni(options);
3393
- const load = useCallback10(async () => await client.listEnvironments(workspaceId), [client, workspaceId]);
3627
+ const load = useCallback11(async () => await client.listEnvironments(workspaceId), [client, workspaceId]);
3394
3628
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3395
3629
  const mutation = useMutationRunner();
3396
- const create = useCallback10(
3630
+ const create = useCallback11(
3397
3631
  async (request) => {
3398
3632
  const result = await mutation.run(() => client.createEnvironment(workspaceId, request));
3399
3633
  if (result) {
@@ -3403,7 +3637,7 @@ function useEnvironments(options = {}) {
3403
3637
  },
3404
3638
  [client, workspaceId, mutation.run, state.refresh]
3405
3639
  );
3406
- const update = useCallback10(
3640
+ const update = useCallback11(
3407
3641
  async (environmentId, request) => {
3408
3642
  const result = await mutation.run(() => client.updateEnvironment(workspaceId, environmentId, request));
3409
3643
  if (result) {
@@ -3413,7 +3647,7 @@ function useEnvironments(options = {}) {
3413
3647
  },
3414
3648
  [client, workspaceId, mutation.run, state.refresh]
3415
3649
  );
3416
- const remove = useCallback10(
3650
+ const remove = useCallback11(
3417
3651
  async (environmentId) => {
3418
3652
  const result = await mutation.run(async () => {
3419
3653
  await client.deleteEnvironment(workspaceId, environmentId);
@@ -3426,7 +3660,7 @@ function useEnvironments(options = {}) {
3426
3660
  },
3427
3661
  [client, workspaceId, mutation.run, state.refresh]
3428
3662
  );
3429
- const setVariable = useCallback10(
3663
+ const setVariable = useCallback11(
3430
3664
  async (environmentId, name, value) => {
3431
3665
  const result = await mutation.run(() => client.setEnvironmentVariable(workspaceId, environmentId, name, value));
3432
3666
  if (result) {
@@ -3436,7 +3670,7 @@ function useEnvironments(options = {}) {
3436
3670
  },
3437
3671
  [client, workspaceId, mutation.run, state.refresh]
3438
3672
  );
3439
- const deleteVariable = useCallback10(
3673
+ const deleteVariable = useCallback11(
3440
3674
  async (environmentId, name) => {
3441
3675
  const result = await mutation.run(async () => {
3442
3676
  await client.deleteEnvironmentVariable(workspaceId, environmentId, name);
@@ -3466,13 +3700,13 @@ function useEnvironments(options = {}) {
3466
3700
  }
3467
3701
 
3468
3702
  // src/hooks/use-packs.ts
3469
- import { useCallback as useCallback11 } from "react";
3703
+ import { useCallback as useCallback12 } from "react";
3470
3704
  function usePacks(options = {}) {
3471
3705
  const { client, workspaceId } = useOpenGeni(options);
3472
- const load = useCallback11(async () => await client.listPacks(workspaceId), [client, workspaceId]);
3706
+ const load = useCallback12(async () => await client.listPacks(workspaceId), [client, workspaceId]);
3473
3707
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3474
3708
  const mutation = useMutationRunner();
3475
- const register = useCallback11(
3709
+ const register = useCallback12(
3476
3710
  async (manifest) => {
3477
3711
  const result = await mutation.run(() => client.registerPack(workspaceId, manifest));
3478
3712
  if (result) {
@@ -3482,7 +3716,7 @@ function usePacks(options = {}) {
3482
3716
  },
3483
3717
  [client, workspaceId, mutation.run, state.refresh]
3484
3718
  );
3485
- const enable = useCallback11(
3719
+ const enable = useCallback12(
3486
3720
  async (packId, request = {}) => {
3487
3721
  const result = await mutation.run(() => client.enablePack(workspaceId, packId, request));
3488
3722
  if (result) {
@@ -3492,7 +3726,7 @@ function usePacks(options = {}) {
3492
3726
  },
3493
3727
  [client, workspaceId, mutation.run, state.refresh]
3494
3728
  );
3495
- const remove = useCallback11(
3729
+ const remove = useCallback12(
3496
3730
  async (packId) => {
3497
3731
  const result = await mutation.run(async () => {
3498
3732
  await client.deletePack(workspaceId, packId);
@@ -3506,7 +3740,7 @@ function usePacks(options = {}) {
3506
3740
  [client, workspaceId, mutation.run, state.refresh]
3507
3741
  );
3508
3742
  const installations = state.data?.installations ?? [];
3509
- const installationFor = useCallback11(
3743
+ const installationFor = useCallback12(
3510
3744
  (packId) => installations.find((installation) => installation.packId === packId) ?? null,
3511
3745
  [installations]
3512
3746
  );
@@ -3527,13 +3761,13 @@ function usePacks(options = {}) {
3527
3761
  }
3528
3762
 
3529
3763
  // src/hooks/use-workspaces.ts
3530
- import { useCallback as useCallback12 } from "react";
3764
+ import { useCallback as useCallback13 } from "react";
3531
3765
  function useWorkspaces(options = {}) {
3532
3766
  const client = useOpenGeniClient(options);
3533
- const load = useCallback12(async () => await client.listWorkspaces(), [client]);
3767
+ const load = useCallback13(async () => await client.listWorkspaces(), [client]);
3534
3768
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3535
3769
  const mutation = useMutationRunner();
3536
- const create = useCallback12(
3770
+ const create = useCallback13(
3537
3771
  async (request) => {
3538
3772
  const result = await mutation.run(() => client.createWorkspace(request));
3539
3773
  if (result) {
@@ -3543,7 +3777,7 @@ function useWorkspaces(options = {}) {
3543
3777
  },
3544
3778
  [client, mutation.run, state.refresh]
3545
3779
  );
3546
- const update = useCallback12(
3780
+ const update = useCallback13(
3547
3781
  async (workspaceId, request) => {
3548
3782
  const result = await mutation.run(() => client.updateWorkspace(workspaceId, request));
3549
3783
  if (result) {
@@ -3567,12 +3801,12 @@ function useWorkspaces(options = {}) {
3567
3801
  }
3568
3802
 
3569
3803
  // src/hooks/use-billing-usage.ts
3570
- import { useCallback as useCallback13 } from "react";
3804
+ import { useCallback as useCallback14 } from "react";
3571
3805
  function useBillingUsage(options = {}) {
3572
3806
  const client = useOpenGeniClient(options);
3573
3807
  const accountId = options.accountId;
3574
3808
  const workspaceId = options.workspaceId;
3575
- const load = useCallback13(
3809
+ const load = useCallback14(
3576
3810
  async () => await client.getBillingUsage({
3577
3811
  ...accountId !== void 0 ? { accountId } : {},
3578
3812
  ...workspaceId !== void 0 ? { workspaceId } : {}
@@ -3590,10 +3824,10 @@ function useBillingUsage(options = {}) {
3590
3824
  }
3591
3825
 
3592
3826
  // src/hooks/use-available-models.ts
3593
- import { useCallback as useCallback14 } from "react";
3827
+ import { useCallback as useCallback15 } from "react";
3594
3828
  function useAvailableModels(options = {}) {
3595
3829
  const client = useOpenGeniClient(options);
3596
- const load = useCallback14(async () => await client.getClientConfig(), [client]);
3830
+ const load = useCallback15(async () => await client.getClientConfig(), [client]);
3597
3831
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3598
3832
  return {
3599
3833
  models: state.data?.models ?? [],
@@ -3609,7 +3843,7 @@ import {
3609
3843
  OpenGeniApiError as OpenGeniApiError2,
3610
3844
  applyUrlRotation
3611
3845
  } from "@opengeni/sdk";
3612
- import { useCallback as useCallback15, useEffect as useEffect7, useRef as useRef6, useState as useState13 } from "react";
3846
+ import { useCallback as useCallback16, useEffect as useEffect7, useRef as useRef7, useState as useState13 } from "react";
3613
3847
  function desktopAttachable(cell) {
3614
3848
  if (cell.transport !== null) return true;
3615
3849
  return cell.reason === "lease_cold" || cell.reason === "not_provisioned" || cell.reason === null;
@@ -3644,9 +3878,9 @@ function useSessionCapabilities(sessionId, options = {}) {
3644
3878
  const [viewerCapReached, setViewerCapReached] = useState13(false);
3645
3879
  const [viewerId, setViewerId] = useState13(null);
3646
3880
  const [nonce, setNonce] = useState13(0);
3647
- const epochRef = useRef6(0);
3648
- const viewerIdRef = useRef6(null);
3649
- const renegotiate = useCallback15(() => {
3881
+ const epochRef = useRef7(0);
3882
+ const viewerIdRef = useRef7(null);
3883
+ const renegotiate = useCallback16(() => {
3650
3884
  setNonce((n) => n + 1);
3651
3885
  }, []);
3652
3886
  useEffect7(() => {
@@ -3844,7 +4078,7 @@ import {
3844
4078
  desktopSocketUrl,
3845
4079
  nextDesktopState
3846
4080
  } from "@opengeni/sdk";
3847
- import { useEffect as useEffect9, useRef as useRef8, useState as useState15 } from "react";
4081
+ import { useEffect as useEffect9, useRef as useRef9, useState as useState15 } from "react";
3848
4082
 
3849
4083
  // src/lib/relay-wire.ts
3850
4084
  import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -3917,7 +4151,7 @@ function decodeStreamFrame(bytes) {
3917
4151
  }
3918
4152
 
3919
4153
  // src/hooks/use-relay-frame-stream.ts
3920
- import { useEffect as useEffect8, useRef as useRef7, useState as useState14 } from "react";
4154
+ import { useEffect as useEffect8, useRef as useRef8, useState as useState14 } from "react";
3921
4155
  var TAG_OPEN = 1;
3922
4156
  var TAG_OPENACK = 2;
3923
4157
  var TAG_FRAME = 3;
@@ -3935,7 +4169,7 @@ function useRelayFrameStream(options) {
3935
4169
  const [state, setState] = useState14("idle");
3936
4170
  const [error, setError] = useState14(null);
3937
4171
  const [nonce, setNonce] = useState14(0);
3938
- const stateRef = useRef7("idle");
4172
+ const stateRef = useRef8("idle");
3939
4173
  const setBoth = (next) => {
3940
4174
  stateRef.current = next;
3941
4175
  setState(next);
@@ -3944,7 +4178,7 @@ function useRelayFrameStream(options) {
3944
4178
  const transport = capability?.transport ?? null;
3945
4179
  const url = capability?.url ?? null;
3946
4180
  const token = capability?.token ?? null;
3947
- const factoryRef = useRef7(webSocketFactory);
4181
+ const factoryRef = useRef8(webSocketFactory);
3948
4182
  factoryRef.current = webSocketFactory;
3949
4183
  useEffect8(() => {
3950
4184
  if (typeof window === "undefined") return;
@@ -4138,7 +4372,7 @@ function useDesktopStream(options) {
4138
4372
  const [state, setState] = useState15("idle");
4139
4373
  const [error, setError] = useState15(null);
4140
4374
  const [nonce, setNonce] = useState15(0);
4141
- const stateRef = useRef8("idle");
4375
+ const stateRef = useRef9("idle");
4142
4376
  const setBoth = (next) => {
4143
4377
  stateRef.current = next;
4144
4378
  setState(next);
@@ -4148,11 +4382,11 @@ function useDesktopStream(options) {
4148
4382
  const token = capability?.token ?? null;
4149
4383
  const transport = capability?.transport ?? null;
4150
4384
  const mode = capability?.mode ?? "read-only";
4151
- const rfbRef = useRef8(null);
4152
- const interactiveRef = useRef8(interactive);
4153
- const scaleViewportRef = useRef8(scaleViewport);
4154
- const modeRef = useRef8(mode);
4155
- const rfbFactoryRef = useRef8(rfbFactory);
4385
+ const rfbRef = useRef9(null);
4386
+ const interactiveRef = useRef9(interactive);
4387
+ const scaleViewportRef = useRef9(scaleViewport);
4388
+ const modeRef = useRef9(mode);
4389
+ const rfbFactoryRef = useRef9(rfbFactory);
4156
4390
  interactiveRef.current = interactive;
4157
4391
  scaleViewportRef.current = scaleViewport;
4158
4392
  modeRef.current = mode;
@@ -4245,7 +4479,7 @@ import {
4245
4479
  ttydResizeFrame,
4246
4480
  TtydServerCommand
4247
4481
  } from "@opengeni/sdk";
4248
- import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef9, useState as useState16 } from "react";
4482
+ import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef10, useState as useState16 } from "react";
4249
4483
  function decodeFrame(data) {
4250
4484
  if (typeof data === "string") {
4251
4485
  return { command: data.charAt(0), payload: data.slice(1) };
@@ -4258,13 +4492,13 @@ function decodeFrame(data) {
4258
4492
  function useTerminalStream(options) {
4259
4493
  const { capability, onOutput, onTitle, initialCols, initialRows } = options;
4260
4494
  const [status, setStatus] = useState16("closed");
4261
- const wsRef = useRef9(null);
4262
- const sizeRef = useRef9({
4495
+ const wsRef = useRef10(null);
4496
+ const sizeRef = useRef10({
4263
4497
  cols: initialCols ?? 80,
4264
4498
  rows: initialRows ?? 24
4265
4499
  });
4266
- const onOutputRef = useRef9(onOutput);
4267
- const onTitleRef = useRef9(onTitle);
4500
+ const onOutputRef = useRef10(onOutput);
4501
+ const onTitleRef = useRef10(onTitle);
4268
4502
  onOutputRef.current = onOutput;
4269
4503
  onTitleRef.current = onTitle;
4270
4504
  const transport = capability?.transport ?? null;
@@ -4367,7 +4601,7 @@ function useTerminalStream(options) {
4367
4601
 
4368
4602
  // src/hooks/use-sandbox-terminal.ts
4369
4603
  import { OpenGeniApiError as OpenGeniApiError3 } from "@opengeni/sdk";
4370
- import { useCallback as useCallback16, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef10, useState as useState17 } from "react";
4604
+ import { useCallback as useCallback17, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef11, useState as useState17 } from "react";
4371
4605
  function useSandboxTerminal(sessionId, options) {
4372
4606
  const { client, workspaceId } = useOpenGeni(options);
4373
4607
  const includeAgentFirehose = options.includeAgentFirehose ?? true;
@@ -4377,7 +4611,7 @@ function useSandboxTerminal(sessionId, options) {
4377
4611
  const [openedPtyId, setOpenedPtyId] = useState17(null);
4378
4612
  const [openError, setOpenError] = useState17(null);
4379
4613
  const [reopenNonce, setReopenNonce] = useState17(0);
4380
- const openInFlight = useRef10(false);
4614
+ const openInFlight = useRef11(false);
4381
4615
  const boxWarm = liveness === void 0 || liveness === "warm" || liveness === "draining";
4382
4616
  useEffect11(() => {
4383
4617
  if (!interactive || !sessionId || ptyFilter || !boxWarm) return;
@@ -4467,7 +4701,7 @@ function useSandboxTerminal(sessionId, options) {
4467
4701
  });
4468
4702
  };
4469
4703
  }, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId]);
4470
- const close = useCallback16(() => {
4704
+ const close = useCallback17(() => {
4471
4705
  if (!activePtyId || !sessionId) return;
4472
4706
  void client.terminalPtyClose(workspaceId, sessionId, { ptyId: activePtyId }).catch(() => {
4473
4707
  });
@@ -4483,7 +4717,7 @@ function useSandboxTerminal(sessionId, options) {
4483
4717
  }
4484
4718
 
4485
4719
  // src/hooks/use-sandbox-files.ts
4486
- import { useCallback as useCallback17, useEffect as useEffect12, useRef as useRef11, useState as useState18 } from "react";
4720
+ import { useCallback as useCallback18, useEffect as useEffect12, useRef as useRef12, useState as useState18 } from "react";
4487
4721
  function parentOf(path) {
4488
4722
  const i = path.lastIndexOf("/");
4489
4723
  return i <= 0 ? "" : path.slice(0, i);
@@ -4603,15 +4837,15 @@ function useSandboxFiles(sessionId, options = {}) {
4603
4837
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
4604
4838
  const rootPath = options.rootPath ?? "";
4605
4839
  const [tree, setTree] = useState18([]);
4606
- const treeRef = useRef11([]);
4840
+ const treeRef = useRef12([]);
4607
4841
  const [loading, setLoading] = useState18(false);
4608
4842
  const [expandingPaths, setExpandingPaths] = useState18(/* @__PURE__ */ new Set());
4609
4843
  const [error, setError] = useState18(null);
4610
- const statusRef = useRef11(/* @__PURE__ */ new Map());
4611
- const ownRevisionsRef = useRef11(/* @__PURE__ */ new Set());
4844
+ const statusRef = useRef12(/* @__PURE__ */ new Map());
4845
+ const ownRevisionsRef = useRef12(/* @__PURE__ */ new Set());
4612
4846
  const onMutationError = options.onMutationError;
4613
4847
  treeRef.current = tree;
4614
- const applyStatus = useCallback17((nodes) => {
4848
+ const applyStatus = useCallback18((nodes) => {
4615
4849
  const overlay = statusRef.current;
4616
4850
  if (overlay.size === 0) return nodes;
4617
4851
  const walk = (list) => list.map((node) => {
@@ -4623,7 +4857,7 @@ function useSandboxFiles(sessionId, options = {}) {
4623
4857
  });
4624
4858
  return walk(nodes);
4625
4859
  }, []);
4626
- const refresh = useCallback17(async () => {
4860
+ const refresh = useCallback18(async () => {
4627
4861
  if (!sessionId) return;
4628
4862
  setLoading(true);
4629
4863
  setError(null);
@@ -4649,7 +4883,7 @@ function useSandboxFiles(sessionId, options = {}) {
4649
4883
  setLoading(false);
4650
4884
  }
4651
4885
  }, [client, workspaceId, sessionId, rootPath, applyStatus]);
4652
- const expand = useCallback17(
4886
+ const expand = useCallback18(
4653
4887
  async (path) => {
4654
4888
  if (!sessionId) return;
4655
4889
  setExpandingPaths((prev) => {
@@ -4674,14 +4908,14 @@ function useSandboxFiles(sessionId, options = {}) {
4674
4908
  },
4675
4909
  [client, workspaceId, sessionId, applyStatus]
4676
4910
  );
4677
- const readFile = useCallback17(
4911
+ const readFile = useCallback18(
4678
4912
  async (path) => {
4679
4913
  if (!sessionId) throw new Error("no session");
4680
4914
  return await client.fsRead(workspaceId, sessionId, { path });
4681
4915
  },
4682
4916
  [client, workspaceId, sessionId]
4683
4917
  );
4684
- const reconcilePath = useCallback17(
4918
+ const reconcilePath = useCallback18(
4685
4919
  async (path) => {
4686
4920
  if (!sessionId) return;
4687
4921
  if (!parentIsLoaded(treeRef.current, path)) return;
@@ -4700,7 +4934,7 @@ function useSandboxFiles(sessionId, options = {}) {
4700
4934
  },
4701
4935
  [client, workspaceId, sessionId, applyStatus]
4702
4936
  );
4703
- const runOptimistic = useCallback17(
4937
+ const runOptimistic = useCallback18(
4704
4938
  async (opName, apply, op, reconcileParents) => {
4705
4939
  const snapshot = treeRef.current;
4706
4940
  setTree(applyStatus(apply(snapshot)));
@@ -4722,7 +4956,7 @@ function useSandboxFiles(sessionId, options = {}) {
4722
4956
  },
4723
4957
  [applyStatus, reconcilePath, onMutationError]
4724
4958
  );
4725
- const writeFile = useCallback17(
4959
+ const writeFile = useCallback18(
4726
4960
  async (path, content) => {
4727
4961
  if (!sessionId) throw new Error("no session");
4728
4962
  const parent = parentOf(path);
@@ -4737,7 +4971,7 @@ function useSandboxFiles(sessionId, options = {}) {
4737
4971
  },
4738
4972
  [client, workspaceId, sessionId, tree, runOptimistic]
4739
4973
  );
4740
- const createFile = useCallback17(
4974
+ const createFile = useCallback18(
4741
4975
  async (path) => {
4742
4976
  if (!sessionId) throw new Error("no session");
4743
4977
  const parent = parentOf(path);
@@ -4751,7 +4985,7 @@ function useSandboxFiles(sessionId, options = {}) {
4751
4985
  },
4752
4986
  [client, workspaceId, sessionId, runOptimistic]
4753
4987
  );
4754
- const createDir = useCallback17(
4988
+ const createDir = useCallback18(
4755
4989
  async (path) => {
4756
4990
  if (!sessionId) throw new Error("no session");
4757
4991
  const parent = parentOf(path);
@@ -4765,7 +4999,7 @@ function useSandboxFiles(sessionId, options = {}) {
4765
4999
  },
4766
5000
  [client, workspaceId, sessionId, runOptimistic]
4767
5001
  );
4768
- const deleteEntry = useCallback17(
5002
+ const deleteEntry = useCallback18(
4769
5003
  async (path, recursive = false) => {
4770
5004
  if (!sessionId) throw new Error("no session");
4771
5005
  await runOptimistic(
@@ -4777,7 +5011,7 @@ function useSandboxFiles(sessionId, options = {}) {
4777
5011
  },
4778
5012
  [client, workspaceId, sessionId, runOptimistic]
4779
5013
  );
4780
- const moveEntry = useCallback17(
5014
+ const moveEntry = useCallback18(
4781
5015
  async (path, newPath, opts) => {
4782
5016
  if (!sessionId) throw new Error("no session");
4783
5017
  const from = parentOf(path);
@@ -4807,7 +5041,7 @@ function useSandboxFiles(sessionId, options = {}) {
4807
5041
  }
4808
5042
  void refresh();
4809
5043
  }, [enabled, refresh]);
4810
- const refreshGitOverlay = useCallback17(async () => {
5044
+ const refreshGitOverlay = useCallback18(async () => {
4811
5045
  if (!sessionId) return;
4812
5046
  try {
4813
5047
  const status = await client.gitStatus(workspaceId, sessionId, { path: rootPath });
@@ -4823,10 +5057,10 @@ function useSandboxFiles(sessionId, options = {}) {
4823
5057
  }
4824
5058
  }, [client, workspaceId, sessionId, rootPath, applyStatus]);
4825
5059
  const events = options.events;
4826
- const lastSeqRef = useRef11(0);
4827
- const pendingParentsRef = useRef11(/* @__PURE__ */ new Set());
4828
- const pendingGitRef = useRef11(false);
4829
- const debounceRef = useRef11(null);
5060
+ const lastSeqRef = useRef12(0);
5061
+ const pendingParentsRef = useRef12(/* @__PURE__ */ new Set());
5062
+ const pendingGitRef = useRef12(false);
5063
+ const debounceRef = useRef12(null);
4830
5064
  useEffect12(() => {
4831
5065
  if (!enabled || !events) return;
4832
5066
  let sawNew = false;
@@ -4870,7 +5104,7 @@ function useSandboxFiles(sessionId, options = {}) {
4870
5104
  },
4871
5105
  []
4872
5106
  );
4873
- const wasLiveRef = useRef11(false);
5107
+ const wasLiveRef = useRef12(false);
4874
5108
  const liveness = options.liveness;
4875
5109
  useEffect12(() => {
4876
5110
  const live = liveness === "warm" || liveness === "draining";
@@ -4898,7 +5132,7 @@ function useSandboxFiles(sessionId, options = {}) {
4898
5132
  }
4899
5133
 
4900
5134
  // src/hooks/use-sandbox-git.ts
4901
- import { useCallback as useCallback18, useEffect as useEffect13, useRef as useRef12, useState as useState19 } from "react";
5135
+ import { useCallback as useCallback19, useEffect as useEffect13, useRef as useRef13, useState as useState19 } from "react";
4902
5136
  function useSandboxGit(sessionId, options = {}) {
4903
5137
  const { client, workspaceId } = useOpenGeni(options);
4904
5138
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
@@ -4911,7 +5145,7 @@ function useSandboxGit(sessionId, options = {}) {
4911
5145
  const [behind, setBehind] = useState19(0);
4912
5146
  const [loading, setLoading] = useState19(false);
4913
5147
  const [error, setError] = useState19(null);
4914
- const refresh = useCallback18(async () => {
5148
+ const refresh = useCallback19(async () => {
4915
5149
  if (!sessionId) return;
4916
5150
  setLoading(true);
4917
5151
  setError(null);
@@ -4943,7 +5177,7 @@ function useSandboxGit(sessionId, options = {}) {
4943
5177
  void refresh();
4944
5178
  }, [enabled, refresh]);
4945
5179
  const events = options.events;
4946
- const lastChangeRef = useRef12(0);
5180
+ const lastChangeRef = useRef13(0);
4947
5181
  useEffect13(() => {
4948
5182
  if (!enabled || !events) return;
4949
5183
  let latest = lastChangeRef.current;
@@ -5192,14 +5426,14 @@ function clearErrorMessage(cause) {
5192
5426
  }
5193
5427
 
5194
5428
  // src/hooks/use-slash-commands.ts
5195
- import { useCallback as useCallback19, useMemo as useMemo5, useRef as useRef13, useState as useState20 } from "react";
5429
+ import { useCallback as useCallback20, useMemo as useMemo5, useRef as useRef14, useState as useState20 } from "react";
5196
5430
  function useSlashCommands(options) {
5197
5431
  const { commands, context, handlers, value, setValue } = options;
5198
5432
  const [highlight, setHighlight] = useState20(0);
5199
5433
  const [dismissedValue, setDismissedValue] = useState20(null);
5200
5434
  const dismissed = dismissedValue !== null && dismissedValue === value;
5201
- const navigatedRef = useRef13(false);
5202
- const navTokenRef = useRef13(value);
5435
+ const navigatedRef = useRef14(false);
5436
+ const navTokenRef = useRef14(value);
5203
5437
  if (navTokenRef.current !== value) {
5204
5438
  navTokenRef.current = value;
5205
5439
  navigatedRef.current = false;
@@ -5232,7 +5466,7 @@ function useSlashCommands(options) {
5232
5466
  const isCommandDraft = parsed !== null && items.length > 0;
5233
5467
  const clampedHighlight = items.length === 0 ? 0 : Math.min(highlight, items.length - 1);
5234
5468
  const activeArgHint = activeCommand ? argHint(activeCommand.args) : "";
5235
- const buildContext = useCallback19(
5469
+ const buildContext = useCallback20(
5236
5470
  (command) => {
5237
5471
  if (!context) {
5238
5472
  return null;
@@ -5241,7 +5475,7 @@ function useSlashCommands(options) {
5241
5475
  },
5242
5476
  [context, handlers]
5243
5477
  );
5244
- const execute = useCallback19(
5478
+ const execute = useCallback20(
5245
5479
  async (command, args) => {
5246
5480
  const ctx = buildContext(command);
5247
5481
  if (!ctx) {
@@ -5261,20 +5495,20 @@ function useSlashCommands(options) {
5261
5495
  },
5262
5496
  [buildContext, setValue]
5263
5497
  );
5264
- const autocomplete = useCallback19(
5498
+ const autocomplete = useCallback20(
5265
5499
  (command) => {
5266
5500
  setValue(`/${command.name} `);
5267
5501
  setHighlight(0);
5268
5502
  },
5269
5503
  [setValue]
5270
5504
  );
5271
- const autocompleteHighlighted = useCallback19(() => {
5505
+ const autocompleteHighlighted = useCallback20(() => {
5272
5506
  const command = items[clampedHighlight];
5273
5507
  if (command) {
5274
5508
  autocomplete(command);
5275
5509
  }
5276
5510
  }, [items, clampedHighlight, autocomplete]);
5277
- const runResolved = useCallback19(
5511
+ const runResolved = useCallback20(
5278
5512
  async (command, options2) => {
5279
5513
  if (!parsed) {
5280
5514
  return;
@@ -5297,7 +5531,7 @@ function useSlashCommands(options) {
5297
5531
  },
5298
5532
  [parsed, activeCommand, autocomplete, execute]
5299
5533
  );
5300
- const runHighlighted = useCallback19(async () => {
5534
+ const runHighlighted = useCallback20(async () => {
5301
5535
  if (!parsed) {
5302
5536
  return;
5303
5537
  }
@@ -5316,7 +5550,7 @@ function useSlashCommands(options) {
5316
5550
  }
5317
5551
  await runResolved(command);
5318
5552
  }, [parsed, activeCommand, items, clampedHighlight, runResolved]);
5319
- const runAt = useCallback19(
5553
+ const runAt = useCallback20(
5320
5554
  async (index) => {
5321
5555
  const command = items[index];
5322
5556
  if (!command) {
@@ -5326,8 +5560,8 @@ function useSlashCommands(options) {
5326
5560
  },
5327
5561
  [items, runResolved]
5328
5562
  );
5329
- const runningRef = useRef13(false);
5330
- const onKeyDown = useCallback19(
5563
+ const runningRef = useRef14(false);
5564
+ const onKeyDown = useCallback20(
5331
5565
  (event) => {
5332
5566
  if (!open) {
5333
5567
  return false;
@@ -5469,7 +5703,7 @@ function CommandPalette({ open, items, highlight, onHighlight, onRun, argHintTex
5469
5703
  // src/components/chat-composer.tsx
5470
5704
  import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, RotateCwIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
5471
5705
  import { AnimatePresence as AnimatePresence3, motion as motion3 } from "motion/react";
5472
- import { useCallback as useCallback20, useEffect as useEffect14, useId as useId2, useMemo as useMemo7, useRef as useRef14, useState as useState21 } from "react";
5706
+ import { useCallback as useCallback21, useEffect as useEffect14, useId as useId2, useMemo as useMemo7, useRef as useRef15, useState as useState21 } from "react";
5473
5707
 
5474
5708
  // src/components/model-picker.tsx
5475
5709
  import { ChevronDownIcon } from "lucide-react";
@@ -5546,15 +5780,15 @@ function ChatComposer({
5546
5780
  commandContext,
5547
5781
  onClearView
5548
5782
  }) {
5549
- const textareaRef = useRef14(null);
5550
- const fileInputRef = useRef14(null);
5783
+ const textareaRef = useRef15(null);
5784
+ const fileInputRef = useRef15(null);
5551
5785
  const active = status != null && ACTIVE_STATUSES.has(status);
5552
5786
  const blockedByUpload = attachments?.uploading === true;
5553
5787
  const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;
5554
5788
  const canSend = (composer.canSend || hasReadyAttachment) && !blockedByUpload && !composer.sending;
5555
5789
  const [dragging, setDragging] = useState21(false);
5556
5790
  const dragCarriesFiles = (event) => event.dataTransfer != null && [...event.dataTransfer.types].includes("Files");
5557
- const handleDragOver = useCallback20(
5791
+ const handleDragOver = useCallback21(
5558
5792
  (event) => {
5559
5793
  if (!attachments || !dragCarriesFiles(event)) {
5560
5794
  return;
@@ -5564,7 +5798,7 @@ function ChatComposer({
5564
5798
  },
5565
5799
  [attachments]
5566
5800
  );
5567
- const handleDragLeave = useCallback20(
5801
+ const handleDragLeave = useCallback21(
5568
5802
  (event) => {
5569
5803
  if (!attachments) {
5570
5804
  return;
@@ -5576,7 +5810,7 @@ function ChatComposer({
5576
5810
  },
5577
5811
  [attachments]
5578
5812
  );
5579
- const handleDrop = useCallback20(
5813
+ const handleDrop = useCallback21(
5580
5814
  (event) => {
5581
5815
  if (!attachments || !dragCarriesFiles(event)) {
5582
5816
  return;
@@ -5593,7 +5827,7 @@ function ChatComposer({
5593
5827
  const [helpOpen, setHelpOpen] = useState21(false);
5594
5828
  const [confirmState, setConfirmState] = useState21(null);
5595
5829
  const listboxId = useId2();
5596
- const resize = useCallback20(() => {
5830
+ const resize = useCallback21(() => {
5597
5831
  const textarea = textareaRef.current;
5598
5832
  if (!textarea) {
5599
5833
  return;
@@ -5662,14 +5896,14 @@ function ChatComposer({
5662
5896
  void composer.send();
5663
5897
  }
5664
5898
  };
5665
- const handlePaste = useCallback20(
5899
+ const handlePaste = useCallback21(
5666
5900
  (event) => {
5667
5901
  onPaste?.(event);
5668
5902
  attachments?.addFromPaste(event);
5669
5903
  },
5670
5904
  [onPaste, attachments]
5671
5905
  );
5672
- const handleFileChange = useCallback20(
5906
+ const handleFileChange = useCallback21(
5673
5907
  (event) => {
5674
5908
  if (event.target.files) {
5675
5909
  attachments?.addFiles(event.target.files);
@@ -5915,7 +6149,7 @@ function ConfirmBar({
5915
6149
  onConfirm,
5916
6150
  returnFocusRef
5917
6151
  }) {
5918
- const confirmRef = useRef14(null);
6152
+ const confirmRef = useRef15(null);
5919
6153
  const descriptionId = useId2();
5920
6154
  useEffect14(() => {
5921
6155
  const returnTo = returnFocusRef?.current ?? null;
@@ -6071,7 +6305,7 @@ import {
6071
6305
  TriangleAlertIcon as TriangleAlertIcon2
6072
6306
  } from "lucide-react";
6073
6307
  import { AnimatePresence as AnimatePresence4, motion as motion4 } from "motion/react";
6074
- import { useCallback as useCallback21, useEffect as useEffect15, useMemo as useMemo8, useRef as useRef15, useState as useState22 } from "react";
6308
+ import { useCallback as useCallback22, useEffect as useEffect15, useLayoutEffect, useMemo as useMemo8, useRef as useRef16, useState as useState22 } from "react";
6075
6309
 
6076
6310
  // src/components/markdown.tsx
6077
6311
  import { memo } from "react";
@@ -6230,19 +6464,38 @@ function MessageTimeline({
6230
6464
  onOpenSession,
6231
6465
  toolRegistry = defaultToolRegistry,
6232
6466
  autoFollow = true,
6467
+ hasOlder = false,
6468
+ loadingOlder = false,
6469
+ onLoadOlder,
6233
6470
  emptyState,
6234
6471
  className
6235
6472
  }) {
6236
6473
  const resolvedItems = useMemo8(() => items ?? buildTimeline(events ?? []), [items, events]);
6237
6474
  const groups = useMemo8(() => groupTimeline(resolvedItems), [resolvedItems]);
6238
- const scrollRef = useRef15(null);
6475
+ const firstGroupKey = groups[0] ? timelineGroupKey(groups[0]) : null;
6476
+ const scrollRef = useRef16(null);
6477
+ const topSentinelRef = useRef16(null);
6478
+ const previousBulkFirstKeyRef = useRef16(void 0);
6239
6479
  const [pinned, setPinned] = useState22(true);
6240
- const pinnedRef = useRef15(true);
6241
- const anchorRef = useRef15(null);
6480
+ const [bulkActive, setBulkActive] = useState22(true);
6481
+ const [revealed, setRevealed] = useState22(false);
6482
+ const programmaticScrollRef = useRef16(false);
6483
+ const assignScrollTop = useCallback22((node, value) => {
6484
+ const previous = node.scrollTop;
6485
+ programmaticScrollRef.current = true;
6486
+ node.scrollTop = value;
6487
+ if (node.scrollTop === previous) {
6488
+ programmaticScrollRef.current = false;
6489
+ }
6490
+ }, []);
6491
+ const pinnedRef = useRef16(true);
6492
+ const anchorRef = useRef16(null);
6242
6493
  const lastItem = resolvedItems[resolvedItems.length - 1];
6243
6494
  const streaming = lastItem !== void 0 && (lastItem.kind === "agent-message" || lastItem.kind === "reasoning") && lastItem.streaming;
6244
6495
  const working = status === "running" && !streaming;
6245
- const captureAnchor = useCallback21(() => {
6496
+ const firstKeyChangedForBulk = previousBulkFirstKeyRef.current !== void 0 && previousBulkFirstKeyRef.current !== firstGroupKey;
6497
+ const bulkRender = groups.length > 0 && (bulkActive || firstKeyChangedForBulk);
6498
+ const captureAnchor = useCallback22(() => {
6246
6499
  const node = scrollRef.current;
6247
6500
  const inner = node?.firstElementChild;
6248
6501
  if (!node || !inner) {
@@ -6251,6 +6504,9 @@ function MessageTimeline({
6251
6504
  }
6252
6505
  const containerTop = node.getBoundingClientRect().top;
6253
6506
  for (const child of Array.from(inner.children)) {
6507
+ if (child instanceof HTMLElement && child.dataset.ogTimelineChrome !== void 0) {
6508
+ continue;
6509
+ }
6254
6510
  const rect = child.getBoundingClientRect();
6255
6511
  if (rect.bottom > containerTop + 1) {
6256
6512
  anchorRef.current = { el: child, top: rect.top - containerTop };
@@ -6259,12 +6515,43 @@ function MessageTimeline({
6259
6515
  }
6260
6516
  anchorRef.current = null;
6261
6517
  }, []);
6262
- useEffect15(() => {
6518
+ useLayoutEffect(() => {
6263
6519
  const node = scrollRef.current;
6264
6520
  if (node && autoFollow && pinned) {
6265
- node.scrollTop = node.scrollHeight;
6521
+ assignScrollTop(node, node.scrollHeight);
6522
+ }
6523
+ if (!revealed && groups.length > 0) {
6524
+ setRevealed(true);
6266
6525
  }
6267
- }, [resolvedItems, working, autoFollow, pinned]);
6526
+ }, [resolvedItems, working, autoFollow, pinned, revealed, groups.length, assignScrollTop]);
6527
+ useLayoutEffect(() => {
6528
+ if (groups.length === 0 && revealed) {
6529
+ setRevealed(false);
6530
+ }
6531
+ }, [groups.length, revealed]);
6532
+ useLayoutEffect(() => {
6533
+ previousBulkFirstKeyRef.current = firstGroupKey;
6534
+ if (!bulkRender) {
6535
+ return;
6536
+ }
6537
+ setBulkActive(true);
6538
+ const frame = requestFrame(() => setBulkActive(false));
6539
+ return () => cancelFrame(frame);
6540
+ }, [bulkRender, firstGroupKey]);
6541
+ useEffect15(() => {
6542
+ const root = scrollRef.current;
6543
+ const target = topSentinelRef.current;
6544
+ if (!root || !target || !hasOlder || loadingOlder || !onLoadOlder || typeof IntersectionObserver === "undefined") {
6545
+ return;
6546
+ }
6547
+ const observer = new IntersectionObserver((entries) => {
6548
+ if (entries.some((entry) => entry.isIntersecting)) {
6549
+ onLoadOlder();
6550
+ }
6551
+ }, { root, rootMargin: "1600px 0px 0px 0px" });
6552
+ observer.observe(target);
6553
+ return () => observer.disconnect();
6554
+ }, [hasOlder, loadingOlder, onLoadOlder, firstGroupKey]);
6268
6555
  useEffect15(() => {
6269
6556
  const node = scrollRef.current;
6270
6557
  const inner = node?.firstElementChild;
@@ -6277,7 +6564,7 @@ function MessageTimeline({
6277
6564
  return;
6278
6565
  }
6279
6566
  if (autoFollow && pinnedRef.current) {
6280
- current.scrollTop = current.scrollHeight;
6567
+ assignScrollTop(current, current.scrollHeight);
6281
6568
  } else {
6282
6569
  const anchor = anchorRef.current;
6283
6570
  if (anchor && anchor.el.isConnected) {
@@ -6285,7 +6572,7 @@ function MessageTimeline({
6285
6572
  const now = anchor.el.getBoundingClientRect().top - containerTop;
6286
6573
  const diff = now - anchor.top;
6287
6574
  if (diff !== 0) {
6288
- current.scrollTop += diff;
6575
+ assignScrollTop(current, current.scrollTop + diff);
6289
6576
  }
6290
6577
  }
6291
6578
  }
@@ -6293,32 +6580,47 @@ function MessageTimeline({
6293
6580
  });
6294
6581
  observer.observe(inner);
6295
6582
  return () => observer.disconnect();
6296
- }, [autoFollow, captureAnchor]);
6583
+ }, [autoFollow, captureAnchor, assignScrollTop]);
6297
6584
  const onScroll = () => {
6298
6585
  const node = scrollRef.current;
6299
6586
  if (!node) {
6300
6587
  return;
6301
6588
  }
6589
+ const programmatic = programmaticScrollRef.current;
6590
+ programmaticScrollRef.current = false;
6302
6591
  const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;
6303
- pinnedRef.current = nextPinned;
6304
- setPinned(nextPinned);
6592
+ if (nextPinned || !programmatic) {
6593
+ pinnedRef.current = nextPinned;
6594
+ setPinned(nextPinned);
6595
+ }
6305
6596
  captureAnchor();
6306
6597
  };
6307
- return /* @__PURE__ */ jsx15(LightboxProvider, { children: /* @__PURE__ */ jsxs12("div", { className: cn("og-root relative flex min-h-0 flex-col", className), children: [
6308
- /* @__PURE__ */ jsx15("div", { ref: scrollRef, onScroll, className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 sm:px-6", children: /* @__PURE__ */ jsxs12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
6309
- groups.length === 0 && !working ? emptyState ?? /* @__PURE__ */ jsx15("p", { className: "py-10 text-center text-sm text-og-fg-subtle", children: "No activity yet." }) : null,
6310
- groups.map((group) => /* @__PURE__ */ jsx15(
6311
- TimelineGroupView,
6312
- {
6313
- group,
6314
- renderMessageText,
6315
- onOpenSession,
6316
- toolRegistry
6317
- },
6318
- timelineGroupKey(group)
6319
- )),
6320
- working ? /* @__PURE__ */ jsx15("div", { className: "animate-og-enter flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx15("span", { className: "og-shimmer-text font-medium", children: "Working\u2026" }) }) : null
6321
- ] }) }),
6598
+ return /* @__PURE__ */ jsx15(LightboxProvider, { children: /* @__PURE__ */ jsx15(EntranceAnimationProvider, { value: !bulkRender, children: /* @__PURE__ */ jsxs12("div", { className: cn("og-root relative flex min-h-0 flex-col", className), children: [
6599
+ /* @__PURE__ */ jsx15(
6600
+ "div",
6601
+ {
6602
+ ref: scrollRef,
6603
+ onScroll,
6604
+ style: groups.length > 0 && !revealed ? { visibility: "hidden" } : void 0,
6605
+ className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 [overflow-anchor:none] sm:px-6",
6606
+ children: /* @__PURE__ */ jsxs12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
6607
+ groups.length === 0 && !working ? emptyState ?? /* @__PURE__ */ jsx15("p", { className: "py-10 text-center text-sm text-og-fg-subtle", children: "No activity yet." }) : null,
6608
+ hasOlder ? /* @__PURE__ */ jsx15("div", { ref: topSentinelRef, "data-og-top-sentinel": "", "data-og-timeline-chrome": "", "aria-hidden": "true", className: "h-px w-full shrink-0" }) : null,
6609
+ loadingOlder ? /* @__PURE__ */ jsx15("div", { "data-og-timeline-chrome": "", className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx15("span", { className: "og-shimmer-text font-medium", children: "Loading earlier activity\u2026" }) }) : null,
6610
+ groups.map((group) => /* @__PURE__ */ jsx15(
6611
+ TimelineGroupView,
6612
+ {
6613
+ group,
6614
+ renderMessageText,
6615
+ onOpenSession,
6616
+ toolRegistry
6617
+ },
6618
+ timelineGroupKey(group)
6619
+ )),
6620
+ working ? /* @__PURE__ */ jsx15("div", { className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx15("span", { className: "og-shimmer-text font-medium", children: "Working\u2026" }) }) : null
6621
+ ] })
6622
+ }
6623
+ ),
6322
6624
  /* @__PURE__ */ jsx15(AnimatePresence4, { children: !pinned && autoFollow ? /* @__PURE__ */ jsxs12(
6323
6625
  motion4.button,
6324
6626
  {
@@ -6347,7 +6649,20 @@ function MessageTimeline({
6347
6649
  ]
6348
6650
  }
6349
6651
  ) : null })
6350
- ] }) });
6652
+ ] }) }) });
6653
+ }
6654
+ function requestFrame(callback) {
6655
+ if (typeof requestAnimationFrame === "function") {
6656
+ return requestAnimationFrame(callback);
6657
+ }
6658
+ return window.setTimeout(() => callback(performance.now()), 16);
6659
+ }
6660
+ function cancelFrame(id) {
6661
+ if (typeof cancelAnimationFrame === "function") {
6662
+ cancelAnimationFrame(id);
6663
+ return;
6664
+ }
6665
+ window.clearTimeout(id);
6351
6666
  }
6352
6667
  function TimelineGroupView({
6353
6668
  group,
@@ -6448,7 +6763,8 @@ function UserMessageRow({
6448
6763
  item,
6449
6764
  renderMessageText
6450
6765
  }) {
6451
- return /* @__PURE__ */ jsx15("div", { className: "animate-og-enter flex justify-end", children: /* @__PURE__ */ jsxs12("div", { className: "flex max-w-[85%] min-w-0 flex-col items-end gap-1", children: [
6766
+ const enter = useEntranceAnimation();
6767
+ return /* @__PURE__ */ jsx15("div", { className: cn(enter && "animate-og-enter", "flex justify-end"), children: /* @__PURE__ */ jsxs12("div", { className: "flex max-w-[85%] min-w-0 flex-col items-end gap-1", children: [
6452
6768
  item.pending ? /* @__PURE__ */ jsx15("span", { className: "px-1 text-og-xs text-og-fg-subtle", children: "queued" }) : null,
6453
6769
  /* @__PURE__ */ jsx15("div", { className: "w-fit max-w-full min-w-0 rounded-og-lg rounded-br-og-xs border border-og-border bg-og-surface-2 px-4 py-2.5 text-og-md leading-6 text-og-fg", children: renderMessageText ? renderMessageText(item.text, item) : /* @__PURE__ */ jsx15(Markdown, { children: item.text }) })
6454
6770
  ] }) });
@@ -6457,8 +6773,9 @@ function AgentMessageRow({
6457
6773
  item,
6458
6774
  renderMessageText
6459
6775
  }) {
6776
+ const enter = useEntranceAnimation();
6460
6777
  const caret = item.streaming ? /* @__PURE__ */ jsx15("span", { className: "ml-0.5 inline-block h-[1.1em] w-[2px] translate-y-[3px] animate-og-blink rounded-full bg-og-accent", "aria-hidden": true }) : null;
6461
- return /* @__PURE__ */ jsx15("div", { className: "animate-og-enter min-w-0 text-og-md leading-7 text-og-fg", children: renderMessageText ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
6778
+ return /* @__PURE__ */ jsx15("div", { className: cn(enter && "animate-og-enter", "min-w-0 text-og-md leading-7 text-og-fg"), children: renderMessageText ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
6462
6779
  renderMessageText(item.text, item),
6463
6780
  caret
6464
6781
  ] }) : (
@@ -6472,8 +6789,9 @@ function AgentMessageRow({
6472
6789
  ) });
6473
6790
  }
6474
6791
  function SessionStatusRow({ item }) {
6792
+ const enter = useEntranceAnimation();
6475
6793
  const meta = SESSION_STATUS_META[item.status];
6476
- return /* @__PURE__ */ jsxs12("div", { className: "animate-og-enter flex items-center gap-3 text-og-xs text-og-fg-subtle", role: "status", children: [
6794
+ return /* @__PURE__ */ jsxs12("div", { className: cn(enter && "animate-og-enter", "flex items-center gap-3 text-og-xs text-og-fg-subtle"), role: "status", children: [
6477
6795
  /* @__PURE__ */ jsx15("span", { className: "h-px flex-1 bg-og-border" }),
6478
6796
  /* @__PURE__ */ jsxs12("span", { className: "inline-flex items-center gap-1.5", children: [
6479
6797
  /* @__PURE__ */ jsx15(StatusDot, { status: item.status, className: "size-1" }),
@@ -6494,8 +6812,9 @@ var GOAL_META = {
6494
6812
  continuation: { label: "Continuing toward the goal", pill: NEUTRAL_PILL, icon: ArrowRightIcon }
6495
6813
  };
6496
6814
  function GoalRow({ item }) {
6815
+ const enter = useEntranceAnimation();
6497
6816
  const { label, pill, icon: Icon } = GOAL_META[item.action];
6498
- return /* @__PURE__ */ jsx15("div", { className: "animate-og-enter flex justify-center", children: /* @__PURE__ */ jsxs12("span", { className: cn("inline-flex max-w-full items-center gap-1.5 rounded-full border px-3 py-1 text-og-sm", pill), children: [
6817
+ return /* @__PURE__ */ jsx15("div", { className: cn(enter && "animate-og-enter", "flex justify-center"), children: /* @__PURE__ */ jsxs12("span", { className: cn("inline-flex max-w-full items-center gap-1.5 rounded-full border px-3 py-1 text-og-sm", pill), children: [
6499
6818
  /* @__PURE__ */ jsx15(Icon, { className: "size-3.5 shrink-0" }),
6500
6819
  /* @__PURE__ */ jsxs12("span", { className: "truncate", children: [
6501
6820
  label,
@@ -6504,8 +6823,9 @@ function GoalRow({ item }) {
6504
6823
  ] }) });
6505
6824
  }
6506
6825
  function NoticeRow({ item }) {
6826
+ const enter = useEntranceAnimation();
6507
6827
  const tone = item.tone === "failed" ? "border-og-status-failed/35 bg-og-status-failed/10 text-og-status-failed" : item.tone === "waiting" ? "border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting" : "border-og-border bg-og-surface-1 text-og-fg-muted";
6508
- return /* @__PURE__ */ jsxs12("div", { className: cn("animate-og-enter flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm", tone), role: "status", children: [
6828
+ return /* @__PURE__ */ jsxs12("div", { className: cn(enter && "animate-og-enter", "flex items-start gap-2.5 rounded-og-md border px-3.5 py-2.5 text-sm", tone), role: "status", children: [
6509
6829
  /* @__PURE__ */ jsx15(TriangleAlertIcon2, { className: cn("mt-0.5 size-4 shrink-0", item.tone === "cancelled" && "opacity-60") }),
6510
6830
  /* @__PURE__ */ jsx15("span", { className: "min-w-0 whitespace-pre-wrap break-words", children: item.text })
6511
6831
  ] });
@@ -6571,7 +6891,7 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
6571
6891
  }
6572
6892
 
6573
6893
  // src/components/sandbox-terminal.tsx
6574
- import { useEffect as useEffect16, useRef as useRef16, useState as useState23 } from "react";
6894
+ import { useEffect as useEffect16, useRef as useRef17, useState as useState23 } from "react";
6575
6895
  import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
6576
6896
  function SandboxTerminal({
6577
6897
  result,
@@ -6586,13 +6906,13 @@ function SandboxTerminal({
6586
6906
  onActivate,
6587
6907
  className
6588
6908
  }) {
6589
- const containerRef = useRef16(null);
6590
- const termRef = useRef16(null);
6591
- const fitRef = useRef16(null);
6592
- const writtenRef = useRef16(/* @__PURE__ */ new Set());
6909
+ const containerRef = useRef17(null);
6910
+ const termRef = useRef17(null);
6911
+ const fitRef = useRef17(null);
6912
+ const writtenRef = useRef17(/* @__PURE__ */ new Set());
6593
6913
  const [ready, setReady] = useState23(false);
6594
6914
  const ptyWs = terminalCapability?.transport === "pty-ws" && Boolean(terminalCapability?.url);
6595
- const ptyOutputQueueRef = useRef16([]);
6915
+ const ptyOutputQueueRef = useRef17([]);
6596
6916
  const ptyStream = useTerminalStream({
6597
6917
  capability: ptyWs ? {
6598
6918
  transport: terminalCapability.transport,
@@ -6687,7 +7007,7 @@ function SandboxTerminal({
6687
7007
  if (!ready || !term || !theme) return;
6688
7008
  term.options.theme = theme;
6689
7009
  }, [ready, theme]);
6690
- const enteredPtyRef = useRef16(false);
7010
+ const enteredPtyRef = useRef17(false);
6691
7011
  useEffect16(() => {
6692
7012
  const term = termRef.current;
6693
7013
  if (!ready || !term) return;
@@ -6847,10 +7167,10 @@ import {
6847
7167
  Trash2Icon
6848
7168
  } from "lucide-react";
6849
7169
  import {
6850
- useCallback as useCallback22,
7170
+ useCallback as useCallback23,
6851
7171
  useEffect as useEffect17,
6852
7172
  useMemo as useMemo9,
6853
- useRef as useRef17,
7173
+ useRef as useRef18,
6854
7174
  useState as useState24
6855
7175
  } from "react";
6856
7176
  import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
@@ -6897,9 +7217,9 @@ function FileBrowser({
6897
7217
  const [dragOver, setDragOver] = useState24(null);
6898
7218
  const [menu, setMenu] = useState24(null);
6899
7219
  const [busy, setBusy] = useState24(false);
6900
- const containerRef = useRef17(null);
7220
+ const containerRef = useRef18(null);
6901
7221
  const cursor = active ?? selectedPath ?? null;
6902
- const expand = useCallback22(
7222
+ const expand = useCallback23(
6903
7223
  async (path) => {
6904
7224
  const node = findNode(result.tree, path);
6905
7225
  if (node && node.kind === "dir" && node.children === void 0) {
@@ -6917,14 +7237,14 @@ function FileBrowser({
6917
7237
  },
6918
7238
  [result]
6919
7239
  );
6920
- const open = useCallback22(
7240
+ const open = useCallback23(
6921
7241
  (path) => {
6922
7242
  setExpanded((prev) => new Set(prev).add(path));
6923
7243
  void expand(path);
6924
7244
  },
6925
7245
  [expand]
6926
7246
  );
6927
- const toggle = useCallback22(
7247
+ const toggle = useCallback23(
6928
7248
  async (node) => {
6929
7249
  if (node.kind !== "dir") return;
6930
7250
  const isOpen = expanded.has(node.path);
@@ -6952,7 +7272,7 @@ function FileBrowser({
6952
7272
  return rows;
6953
7273
  }, [result.tree, expanded]);
6954
7274
  const supportsMutation = editable;
6955
- const runDelete = useCallback22(
7275
+ const runDelete = useCallback23(
6956
7276
  async (node) => {
6957
7277
  if (!supportsMutation) return;
6958
7278
  const recursive = node.kind === "dir";
@@ -6971,7 +7291,7 @@ function FileBrowser({
6971
7291
  },
6972
7292
  [supportsMutation, confirmDelete, result]
6973
7293
  );
6974
- const commitCreate = useCallback22(
7294
+ const commitCreate = useCallback23(
6975
7295
  async (name) => {
6976
7296
  const draft = draftCreate;
6977
7297
  setDraftCreate(null);
@@ -6996,7 +7316,7 @@ function FileBrowser({
6996
7316
  },
6997
7317
  [draftCreate, supportsMutation, result, open, onSelectFile]
6998
7318
  );
6999
- const commitRename = useCallback22(
7319
+ const commitRename = useCallback23(
7000
7320
  async (name) => {
7001
7321
  const draft = draftRename;
7002
7322
  setDraftRename(null);
@@ -7019,7 +7339,7 @@ function FileBrowser({
7019
7339
  },
7020
7340
  [draftRename, supportsMutation, result, selectedPath, active, onSelectFile]
7021
7341
  );
7022
- const startCreate = useCallback22(
7342
+ const startCreate = useCallback23(
7023
7343
  (kind) => {
7024
7344
  if (!supportsMutation) return;
7025
7345
  const anchor = cursor ? findNode(result.tree, cursor) : void 0;
@@ -7031,7 +7351,7 @@ function FileBrowser({
7031
7351
  },
7032
7352
  [supportsMutation, cursor, result.tree, open]
7033
7353
  );
7034
- const startRename = useCallback22(
7354
+ const startRename = useCallback23(
7035
7355
  (node) => {
7036
7356
  if (!supportsMutation) return;
7037
7357
  setDraftCreate(null);
@@ -7040,7 +7360,7 @@ function FileBrowser({
7040
7360
  },
7041
7361
  [supportsMutation]
7042
7362
  );
7043
- const onDropOnto = useCallback22(
7363
+ const onDropOnto = useCallback23(
7044
7364
  async (targetDir, sourcePath) => {
7045
7365
  setDragOver(null);
7046
7366
  if (!supportsMutation || !sourcePath) return;
@@ -7064,7 +7384,7 @@ function FileBrowser({
7064
7384
  },
7065
7385
  [supportsMutation, result, selectedPath, active, onSelectFile]
7066
7386
  );
7067
- const onKeyDown = useCallback22(
7387
+ const onKeyDown = useCallback23(
7068
7388
  (e) => {
7069
7389
  if (draftCreate || draftRename) return;
7070
7390
  if (flatRows.length === 0) return;
@@ -7413,8 +7733,8 @@ function InlineInput({
7413
7733
  onCancel
7414
7734
  }) {
7415
7735
  const [value, setValue] = useState24(initialValue);
7416
- const ref = useRef17(null);
7417
- const doneRef = useRef17(false);
7736
+ const ref = useRef18(null);
7737
+ const doneRef = useRef18(false);
7418
7738
  useEffect17(() => {
7419
7739
  const el = ref.current;
7420
7740
  if (!el) return;
@@ -7597,10 +7917,10 @@ import { Loader2Icon as Loader2Icon2, SaveIcon } from "lucide-react";
7597
7917
  import {
7598
7918
  lazy as lazy3,
7599
7919
  Suspense as Suspense3,
7600
- useCallback as useCallback23,
7920
+ useCallback as useCallback24,
7601
7921
  useEffect as useEffect19,
7602
7922
  useMemo as useMemo10,
7603
- useRef as useRef18,
7923
+ useRef as useRef19,
7604
7924
  useState as useState26
7605
7925
  } from "react";
7606
7926
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -7669,7 +7989,7 @@ function CodeEditor({
7669
7989
  const [saveError, setSaveError] = useState26(null);
7670
7990
  const [savedTick, setSavedTick] = useState26(false);
7671
7991
  const dirty = value !== baseline;
7672
- const lastSeed = useRef18({ path, contents: initialContents });
7992
+ const lastSeed = useRef19({ path, contents: initialContents });
7673
7993
  useEffect19(() => {
7674
7994
  const seedChanged = lastSeed.current.path !== path || lastSeed.current.contents !== initialContents;
7675
7995
  if (!seedChanged) return;
@@ -7712,9 +8032,9 @@ function CodeEditor({
7712
8032
  cancelled = true;
7713
8033
  };
7714
8034
  }, [langKey]);
7715
- const saveRef = useRef18(() => {
8035
+ const saveRef = useRef19(() => {
7716
8036
  });
7717
- const save = useCallback23(async () => {
8037
+ const save = useCallback24(async () => {
7718
8038
  if (readOnly) return;
7719
8039
  const snapshot = value;
7720
8040
  if (snapshot === baseline) return;
@@ -7858,7 +8178,7 @@ function EditorSkeleton() {
7858
8178
 
7859
8179
  // src/components/sandbox-files.tsx
7860
8180
  import { FileIcon as FileIcon3 } from "lucide-react";
7861
- import { useCallback as useCallback24, useEffect as useEffect20, useMemo as useMemo11, useRef as useRef19, useState as useState27 } from "react";
8181
+ import { useCallback as useCallback25, useEffect as useEffect20, useMemo as useMemo11, useRef as useRef20, useState as useState27 } from "react";
7862
8182
  import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
7863
8183
  var STATUS_TINT2 = {
7864
8184
  added: "text-og-status-idle",
@@ -7896,7 +8216,7 @@ function SandboxFiles({
7896
8216
  const [staged, setStaged] = useState27(false);
7897
8217
  const [layout, setLayout] = useState27("unified");
7898
8218
  const [editMode, setEditMode] = useState27(false);
7899
- const rootRef = useRef19(null);
8219
+ const rootRef = useRef20(null);
7900
8220
  const [wide, setWide] = useState27(false);
7901
8221
  useEffect20(() => {
7902
8222
  const el = rootRef.current;
@@ -7916,7 +8236,7 @@ function SandboxFiles({
7916
8236
  const selectedDiff = changed.find((f) => f.path === effectiveSelected) ?? null;
7917
8237
  const viewPath = effectiveSelected && !selectedDiff ? effectiveSelected : null;
7918
8238
  const fileView = useFileView(viewPath, files.readFile);
7919
- const selectFile = useCallback24((path) => {
8239
+ const selectFile = useCallback25((path) => {
7920
8240
  setSelected(path);
7921
8241
  setEditMode(false);
7922
8242
  }, []);
@@ -8229,7 +8549,7 @@ function Notice({ children, className }) {
8229
8549
 
8230
8550
  // src/components/desktop-viewer.tsx
8231
8551
  import { LoaderCircleIcon as LoaderCircleIcon2, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from "lucide-react";
8232
- import { useEffect as useEffect21, useRef as useRef20, useState as useState28 } from "react";
8552
+ import { useEffect as useEffect21, useRef as useRef21, useState as useState28 } from "react";
8233
8553
  import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
8234
8554
  var DESKTOP_MEDIA_BACKGROUND = "#000";
8235
8555
  function isHardUnavailable(reason) {
@@ -8262,7 +8582,7 @@ function DesktopViewer({
8262
8582
  connectTimeoutMs = 13e3,
8263
8583
  className
8264
8584
  }) {
8265
- const containerRef = useRef20(null);
8585
+ const containerRef = useRef21(null);
8266
8586
  const [consented, setConsented] = useState28(false);
8267
8587
  const [takeControl, setTakeControl] = useState28(interactive ?? false);
8268
8588
  const externallyControlled = interactive !== void 0;
@@ -8304,9 +8624,9 @@ function DesktopViewer({
8304
8624
  });
8305
8625
  const connected = stream.state === "connected";
8306
8626
  const hasLiveUrl = Boolean(connectCapability?.url);
8307
- const streamStateRef = useRef20(stream.state);
8627
+ const streamStateRef = useRef21(stream.state);
8308
8628
  streamStateRef.current = stream.state;
8309
- const warmKeyRef = useRef20(null);
8629
+ const warmKeyRef = useRef21(null);
8310
8630
  useEffect21(() => {
8311
8631
  if (!isWatching || !coldWarmable || needsAck || viewerCapReached) {
8312
8632
  if (!coldWarmable) warmKeyRef.current = null;
@@ -8599,7 +8919,7 @@ function defaultNotice(title, body, onRetry) {
8599
8919
  }
8600
8920
 
8601
8921
  // src/components/workspace-dock.tsx
8602
- import { useCallback as useCallback25, useEffect as useEffect22, useLayoutEffect, useState as useState29 } from "react";
8922
+ import { useCallback as useCallback26, useEffect as useEffect22, useLayoutEffect as useLayoutEffect2, useState as useState29 } from "react";
8603
8923
  import {
8604
8924
  ChevronsLeftRightIcon,
8605
8925
  Maximize2Icon,
@@ -8615,7 +8935,7 @@ import {
8615
8935
  usePanelRef
8616
8936
  } from "react-resizable-panels";
8617
8937
  import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
8618
- var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 : useLayoutEffect;
8938
+ var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 : useLayoutEffect2;
8619
8939
  var DOCK_OVERLAY_BREAKPOINT = 1024;
8620
8940
  function useIsNarrow(maxWidth) {
8621
8941
  const [narrow, setNarrow] = useState29(false);
@@ -8663,14 +8983,14 @@ function WorkspaceDock({
8663
8983
  const current = activeTab ?? internalTab;
8664
8984
  const tabIds = tabs.map((tab) => tab.id).join("\0");
8665
8985
  const firstTabId = tabs[0]?.id ?? "";
8666
- const setTab = useCallback25(
8986
+ const setTab = useCallback26(
8667
8987
  (id) => {
8668
8988
  setInternalTab(id);
8669
8989
  onActiveTabChange?.(id);
8670
8990
  },
8671
8991
  [onActiveTabChange]
8672
8992
  );
8673
- const setCollapsed = useCallback25(
8993
+ const setCollapsed = useCallback26(
8674
8994
  (next) => {
8675
8995
  setInternalCollapsed((previous) => previous === next ? previous : next);
8676
8996
  onCollapsedChange?.(next);
@@ -8693,11 +9013,11 @@ function WorkspaceDock({
8693
9013
  setTab(firstTabId);
8694
9014
  }
8695
9015
  }, [tabIds, firstTabId, current, setTab]);
8696
- const collapse = useCallback25(() => {
9016
+ const collapse = useCallback26(() => {
8697
9017
  dockPanelRef.current?.collapse();
8698
9018
  setCollapsed(true);
8699
9019
  }, [dockPanelRef, setCollapsed]);
8700
- const expand = useCallback25(() => {
9020
+ const expand = useCallback26(() => {
8701
9021
  dockPanelRef.current?.expand();
8702
9022
  setCollapsed(false);
8703
9023
  }, [dockPanelRef, setCollapsed]);
@@ -8866,7 +9186,7 @@ function DockChrome({
8866
9186
  }
8867
9187
 
8868
9188
  // src/hooks/use-codex-accounts.ts
8869
- import { useCallback as useCallback26, useState as useState30 } from "react";
9189
+ import { useCallback as useCallback27, useState as useState30 } from "react";
8870
9190
  function isCodexAccountEvent(event) {
8871
9191
  return event.type === "codex.account.switched" || event.type === "turn.started";
8872
9192
  }
@@ -8883,7 +9203,7 @@ function useCodexAccounts(options = {}) {
8883
9203
  const codexClient = options.codexClient ?? client;
8884
9204
  const sessionId = options.sessionId;
8885
9205
  const sharedEvents = options.events;
8886
- const load = useCallback26(async () => {
9206
+ const load = useCallback27(async () => {
8887
9207
  const accountsP = codexClient.listCodexAccounts(workspaceId);
8888
9208
  const sessionP = sessionId && codexClient.getSession ? codexClient.getSession(workspaceId, sessionId).catch(() => null) : Promise.resolve(null);
8889
9209
  const [acc, session] = await Promise.all([accountsP, sessionP]);
@@ -8907,7 +9227,7 @@ function useCodexAccounts(options = {}) {
8907
9227
  () => void state.refresh(),
8908
9228
  { enabled: options.enabled ?? true, ...sharedEvents !== void 0 ? { events: sharedEvents } : {} }
8909
9229
  );
8910
- const pin = useCallback26(
9230
+ const pin = useCallback27(
8911
9231
  async (target) => {
8912
9232
  if (!sessionId || !codexClient.pinSessionCodexAccount) {
8913
9233
  return false;
@@ -8923,7 +9243,7 @@ function useCodexAccounts(options = {}) {
8923
9243
  },
8924
9244
  [codexClient, workspaceId, sessionId, mutation.run, state.refresh]
8925
9245
  );
8926
- const refreshUsage = useCallback26(
9246
+ const refreshUsage = useCallback27(
8927
9247
  async () => {
8928
9248
  if (!codexClient.refreshCodexUsage) {
8929
9249
  return false;