@opengeni/react 0.6.3 → 0.9.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,43 @@ function formatDurationFacet(durationMs) {
2734
2755
  }
2735
2756
 
2736
2757
  // src/hooks/use-session-events.ts
2758
+ var TAIL_PAGE_SIZE = 5e3;
2759
+ var INITIAL_FETCH_CAP = 1;
2760
+ var OLDER_GROUP_TARGET = 32;
2761
+ var OLDER_FETCH_CAP = 2;
2762
+ var BOUNDARY_PAGE_CAP = 4;
2737
2763
  function useSessionEvents(sessionId, options = {}) {
2738
2764
  const { client, workspaceId } = useOpenGeni(options);
2739
2765
  const enabled = options.enabled ?? true;
2740
2766
  const after = options.after ?? 0;
2767
+ const replay = options.replay ?? "windowed";
2768
+ const fullReplay = replay === "full" || after !== 0;
2741
2769
  const [events, setEvents] = useState8([]);
2742
2770
  const [connectionState, setConnectionState] = useState8("idle");
2743
2771
  const [error, setError] = useState8(null);
2744
- const lastSequenceRef = useRef(after);
2745
- const streamKeyRef = useRef(null);
2772
+ const [hasOlder, setHasOlder] = useState8(false);
2773
+ const [initialLoading, setInitialLoading] = useState8(true);
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);
2790
+ setInitialLoading(true);
2752
2791
  lastSequenceRef.current = after;
2792
+ oldestSequenceRef.current = null;
2793
+ hasOlderRef.current = false;
2794
+ loadingOlderRef.current = false;
2753
2795
  }
2754
2796
  if (!sessionId || !enabled) {
2755
2797
  setConnectionState("idle");
@@ -2767,7 +2809,7 @@ function useSessionEvents(sessionId, options = {}) {
2767
2809
  pending = [];
2768
2810
  const lastInBatch = batch[batch.length - 1];
2769
2811
  if (lastInBatch) {
2770
- lastSequenceRef.current = lastInBatch.sequence;
2812
+ lastSequenceRef.current = Math.max(lastSequenceRef.current, ...batch.map(eventResumeSequence));
2771
2813
  }
2772
2814
  setEvents((existing) => [...existing, ...batch]);
2773
2815
  };
@@ -2776,6 +2818,28 @@ function useSessionEvents(sessionId, options = {}) {
2776
2818
  };
2777
2819
  void (async () => {
2778
2820
  try {
2821
+ if (!fullReplay) {
2822
+ setConnectionState("connecting");
2823
+ const window2 = await loadEventWindow(client, workspaceId, sessionId, {
2824
+ before: Number.MAX_SAFE_INTEGER,
2825
+ pageSize: TAIL_PAGE_SIZE,
2826
+ targetGroups: Number.POSITIVE_INFINITY,
2827
+ maxFetches: INITIAL_FETCH_CAP,
2828
+ signal: controller.signal
2829
+ });
2830
+ if (controller.signal.aborted) {
2831
+ return;
2832
+ }
2833
+ oldestSequenceRef.current = window2.oldestSequence;
2834
+ hasOlderRef.current = window2.hasOlder;
2835
+ lastSequenceRef.current = window2.newestSequence;
2836
+ setHasOlder(window2.hasOlder);
2837
+ setEvents(window2.events);
2838
+ setInitialLoading(false);
2839
+ }
2840
+ if (fullReplay) {
2841
+ setInitialLoading(false);
2842
+ }
2779
2843
  const stream = client.streamEvents(workspaceId, sessionId, {
2780
2844
  after: lastSequenceRef.current,
2781
2845
  signal: controller.signal,
@@ -2807,7 +2871,51 @@ function useSessionEvents(sessionId, options = {}) {
2807
2871
  clearTimeout(flushTimer);
2808
2872
  }
2809
2873
  };
2810
- }, [client, workspaceId, sessionId, after, enabled]);
2874
+ }, [client, workspaceId, sessionId, after, enabled, fullReplay]);
2875
+ const loadOlder = useCallback3(async () => {
2876
+ if (!sessionId || fullReplay || loadingOlderRef.current || !hasOlderRef.current) {
2877
+ return false;
2878
+ }
2879
+ const before = oldestSequenceRef.current;
2880
+ if (before === null) {
2881
+ hasOlderRef.current = false;
2882
+ setHasOlder(false);
2883
+ return false;
2884
+ }
2885
+ const generation = generationRef.current;
2886
+ loadingOlderRef.current = true;
2887
+ setLoadingOlder(true);
2888
+ try {
2889
+ const window2 = await loadEventWindow(client, workspaceId, sessionId, {
2890
+ before,
2891
+ pageSize: TAIL_PAGE_SIZE,
2892
+ targetGroups: OLDER_GROUP_TARGET,
2893
+ maxFetches: OLDER_FETCH_CAP
2894
+ });
2895
+ if (generationRef.current !== generation) {
2896
+ return false;
2897
+ }
2898
+ if (window2.events.length === 0) {
2899
+ oldestSequenceRef.current = null;
2900
+ hasOlderRef.current = false;
2901
+ setHasOlder(false);
2902
+ return false;
2903
+ }
2904
+ oldestSequenceRef.current = window2.oldestSequence;
2905
+ hasOlderRef.current = window2.hasOlder;
2906
+ setHasOlder(window2.hasOlder);
2907
+ setEvents((existing) => {
2908
+ assertPrependOrder(existing, window2.events);
2909
+ return [...window2.events, ...existing];
2910
+ });
2911
+ return window2.hasOlder;
2912
+ } finally {
2913
+ if (generationRef.current === generation) {
2914
+ loadingOlderRef.current = false;
2915
+ setLoadingOlder(false);
2916
+ }
2917
+ }
2918
+ }, [client, workspaceId, sessionId, fullReplay]);
2811
2919
  const timeline = useMemo2(() => buildTimeline(events), [events]);
2812
2920
  const sessionStatus = useMemo2(() => sessionStatusFromEvents(events), [events]);
2813
2921
  return {
@@ -2816,12 +2924,144 @@ function useSessionEvents(sessionId, options = {}) {
2816
2924
  sessionStatus,
2817
2925
  connectionState,
2818
2926
  lastSequence: lastSequenceRef.current,
2927
+ initialLoading: fullReplay ? false : initialLoading,
2928
+ hasOlder: fullReplay ? false : hasOlder,
2929
+ loadingOlder: fullReplay ? false : loadingOlder,
2930
+ loadOlder,
2819
2931
  error
2820
2932
  };
2821
2933
  }
2934
+ async function loadEventWindow(client, workspaceId, sessionId, options) {
2935
+ let cursor = options.before;
2936
+ let buffer = [];
2937
+ let reachedStart = false;
2938
+ let fetches = 0;
2939
+ while (fetches < options.maxFetches) {
2940
+ if (buffer.length > 0 && groupCount(buffer) >= options.targetGroups) {
2941
+ break;
2942
+ }
2943
+ const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {
2944
+ pageSize: options.pageSize,
2945
+ ...options.signal ? { signal: options.signal } : {}
2946
+ });
2947
+ fetches += 1;
2948
+ if (page.length === 0) {
2949
+ reachedStart = true;
2950
+ break;
2951
+ }
2952
+ assertAscending(page);
2953
+ buffer = [...page, ...buffer];
2954
+ cursor = page[0].sequence;
2955
+ if (isLogStart(page[0])) {
2956
+ reachedStart = true;
2957
+ break;
2958
+ }
2959
+ }
2960
+ let snapPages = 0;
2961
+ while (!reachedStart && findBoundaryIndex(buffer) === -1 && snapPages < BOUNDARY_PAGE_CAP && fetches < options.maxFetches) {
2962
+ const page = await loadPreviousPage(client, workspaceId, sessionId, cursor, {
2963
+ pageSize: options.pageSize,
2964
+ ...options.signal ? { signal: options.signal } : {}
2965
+ });
2966
+ fetches += 1;
2967
+ snapPages += 1;
2968
+ if (page.length === 0) {
2969
+ reachedStart = true;
2970
+ break;
2971
+ }
2972
+ assertAscending(page);
2973
+ buffer = [...page, ...buffer];
2974
+ cursor = page[0].sequence;
2975
+ if (isLogStart(page[0])) {
2976
+ reachedStart = true;
2977
+ break;
2978
+ }
2979
+ }
2980
+ if (!reachedStart) {
2981
+ const boundary = findBoundaryIndex(buffer);
2982
+ if (boundary > 0) {
2983
+ buffer = buffer.slice(boundary);
2984
+ }
2985
+ }
2986
+ const oldest = buffer[0] ?? null;
2987
+ const newest = buffer[buffer.length - 1] ?? null;
2988
+ return {
2989
+ events: buffer,
2990
+ oldestSequence: oldest?.sequence ?? null,
2991
+ newestSequence: newest ? maxResumeSequence(buffer) : 0,
2992
+ hasOlder: buffer.length > 0 && !reachedStart && oldest?.type !== "session.created"
2993
+ };
2994
+ }
2995
+ function findBoundaryIndex(events) {
2996
+ for (let index = 0; index < events.length; index += 1) {
2997
+ const type = events[index].type;
2998
+ if (type === "session.created" || type === "user.message") {
2999
+ return index;
3000
+ }
3001
+ }
3002
+ return -1;
3003
+ }
3004
+ async function loadPreviousPage(client, workspaceId, sessionId, before, options) {
3005
+ if (options.signal?.aborted) {
3006
+ throw abortError();
3007
+ }
3008
+ const requested = options.pageSize;
3009
+ if (requested === 0) {
3010
+ return Object.assign([], { requested });
3011
+ }
3012
+ const page = await client.listEvents(workspaceId, sessionId, { before, limit: requested, compact: true });
3013
+ if (options.signal?.aborted) {
3014
+ throw abortError();
3015
+ }
3016
+ return Object.assign(page, { requested });
3017
+ }
3018
+ function groupCount(events) {
3019
+ if (events.length === 0) {
3020
+ return 0;
3021
+ }
3022
+ return groupTimeline(buildTimeline(events)).length;
3023
+ }
3024
+ function isLogStart(event) {
3025
+ return event.type === "session.created" || event.sequence <= 1;
3026
+ }
3027
+ function maxResumeSequence(events) {
3028
+ return events.reduce((max, event) => Math.max(max, eventResumeSequence(event)), 0);
3029
+ }
3030
+ function eventResumeSequence(event) {
3031
+ const payload = asRecord2(event.payload);
3032
+ const coalescedUntil = Number(payload.coalescedUntil);
3033
+ return Math.max(event.sequence, Number.isFinite(coalescedUntil) ? Math.floor(coalescedUntil) : 0);
3034
+ }
3035
+ function asRecord2(value) {
3036
+ return value && typeof value === "object" ? value : {};
3037
+ }
3038
+ function assertAscending(events) {
3039
+ for (let index = 1; index < events.length; index += 1) {
3040
+ if (events[index - 1].sequence >= events[index].sequence) {
3041
+ throw new Error("@opengeni/react: session events must be ordered by ascending sequence");
3042
+ }
3043
+ }
3044
+ }
3045
+ function assertPrependOrder(existing, older) {
3046
+ if (!shouldAssertDevelopment() || existing.length === 0 || older.length === 0) {
3047
+ return;
3048
+ }
3049
+ if (older[older.length - 1].sequence >= existing[0].sequence) {
3050
+ throw new Error("@opengeni/react: loadOlder returned overlapping session events");
3051
+ }
3052
+ }
3053
+ function shouldAssertDevelopment() {
3054
+ const processEnv = globalThis.process?.env;
3055
+ return processEnv !== void 0 && processEnv.NODE_ENV !== "production";
3056
+ }
3057
+ function abortError() {
3058
+ const error = new Error("The operation was aborted.");
3059
+ error.name = "AbortError";
3060
+ return error;
3061
+ }
2822
3062
 
2823
3063
  // src/hooks/use-composer.ts
2824
- import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef2, useState as useState9 } from "react";
3064
+ import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef3, useState as useState9 } from "react";
2825
3065
  function useComposer(sessionId, options = {}) {
2826
3066
  const { client, workspaceId } = useOpenGeni(options);
2827
3067
  const defaultMode = options.defaultMode ?? "queue";
@@ -2830,14 +3070,14 @@ function useComposer(sessionId, options = {}) {
2830
3070
  const [sending, setSending] = useState9(false);
2831
3071
  const [interrupting, setInterrupting] = useState9(false);
2832
3072
  const [error, setError] = useState9(null);
2833
- const pendingClientEventId = useRef2(null);
3073
+ const pendingClientEventId = useRef3(null);
2834
3074
  const onSent = options.onSent;
2835
- const modeRef = useRef2(mode);
3075
+ const modeRef = useRef3(mode);
2836
3076
  modeRef.current = mode;
2837
- const sendExtrasRef = useRef2(options.sendExtras);
3077
+ const sendExtrasRef = useRef3(options.sendExtras);
2838
3078
  sendExtrasRef.current = options.sendExtras;
2839
3079
  const targetKey = `${workspaceId}\0${sessionId ?? ""}`;
2840
- const targetKeyRef = useRef2(targetKey);
3080
+ const targetKeyRef = useRef3(targetKey);
2841
3081
  useEffect4(() => {
2842
3082
  if (targetKeyRef.current !== targetKey) {
2843
3083
  targetKeyRef.current = targetKey;
@@ -2847,7 +3087,7 @@ function useComposer(sessionId, options = {}) {
2847
3087
  setMode(defaultMode);
2848
3088
  }
2849
3089
  }, [targetKey, defaultMode]);
2850
- const send = useCallback3(
3090
+ const send = useCallback4(
2851
3091
  async (explicit) => {
2852
3092
  const draftAtSend = value;
2853
3093
  const text = (explicit ?? draftAtSend).trim();
@@ -2883,7 +3123,7 @@ function useComposer(sessionId, options = {}) {
2883
3123
  [client, workspaceId, sessionId, value, sending, onSent]
2884
3124
  );
2885
3125
  const hasReadyResources = (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;
2886
- const interrupt = useCallback3(
3126
+ const interrupt = useCallback4(
2887
3127
  async (reason) => {
2888
3128
  if (!sessionId || interrupting) {
2889
3129
  return;
@@ -2900,7 +3140,7 @@ function useComposer(sessionId, options = {}) {
2900
3140
  },
2901
3141
  [client, workspaceId, sessionId, interrupting]
2902
3142
  );
2903
- const updateValue = useCallback3((next) => {
3143
+ const updateValue = useCallback4((next) => {
2904
3144
  pendingClientEventId.current = null;
2905
3145
  setValue(next);
2906
3146
  }, []);
@@ -2915,7 +3155,7 @@ function useComposer(sessionId, options = {}) {
2915
3155
  interrupt,
2916
3156
  interrupting,
2917
3157
  error,
2918
- clearError: useCallback3(() => setError(null), [])
3158
+ clearError: useCallback4(() => setError(null), [])
2919
3159
  };
2920
3160
  }
2921
3161
  var FILE_ONLY_MESSAGE_TEXT = "(see attached files)";
@@ -2940,14 +3180,14 @@ function generateClientEventId() {
2940
3180
  }
2941
3181
 
2942
3182
  // src/hooks/use-file-attachments.ts
2943
- import { useCallback as useCallback4, useRef as useRef3, useState as useState10 } from "react";
3183
+ import { useCallback as useCallback5, useRef as useRef4, useState as useState10 } from "react";
2944
3184
  var isImage = (file) => file.type.startsWith("image/");
2945
3185
  function useFileAttachments(options = {}) {
2946
3186
  const { client, workspaceId } = useOpenGeni(options);
2947
3187
  const pasteFilter = options.pasteFilter ?? isImage;
2948
3188
  const [attachments, setAttachments] = useState10([]);
2949
- const sources = useRef3(/* @__PURE__ */ new Map());
2950
- const startUpload = useCallback4((id, file) => {
3189
+ const sources = useRef4(/* @__PURE__ */ new Map());
3190
+ const startUpload = useCallback5((id, file) => {
2951
3191
  void client.uploadFile(workspaceId, {
2952
3192
  filename: file.name || "file",
2953
3193
  contentType: file.type || "application/octet-stream",
@@ -2958,7 +3198,7 @@ function useFileAttachments(options = {}) {
2958
3198
  setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "failed", error: error instanceof Error ? error.message : String(error) } : attachment));
2959
3199
  });
2960
3200
  }, [client, workspaceId]);
2961
- const addFiles = useCallback4((files) => {
3201
+ const addFiles = useCallback5((files) => {
2962
3202
  for (const file of files) {
2963
3203
  const id = crypto.randomUUID();
2964
3204
  sources.current.set(id, file);
@@ -2974,7 +3214,7 @@ function useFileAttachments(options = {}) {
2974
3214
  startUpload(id, file);
2975
3215
  }
2976
3216
  }, [startUpload]);
2977
- const retry = useCallback4((id) => {
3217
+ const retry = useCallback5((id) => {
2978
3218
  const file = sources.current.get(id);
2979
3219
  if (!file) {
2980
3220
  return;
@@ -2982,7 +3222,7 @@ function useFileAttachments(options = {}) {
2982
3222
  setAttachments((current) => current.map((attachment) => attachment.id === id ? { ...attachment, status: "uploading", error: void 0 } : attachment));
2983
3223
  startUpload(id, file);
2984
3224
  }, [startUpload]);
2985
- const addFromPaste = useCallback4((event) => {
3225
+ const addFromPaste = useCallback5((event) => {
2986
3226
  const clipboardFiles = event.clipboardData?.files;
2987
3227
  if (!clipboardFiles) {
2988
3228
  return;
@@ -2992,7 +3232,7 @@ function useFileAttachments(options = {}) {
2992
3232
  addFiles(files);
2993
3233
  }
2994
3234
  }, [addFiles, pasteFilter]);
2995
- const remove = useCallback4((id) => {
3235
+ const remove = useCallback5((id) => {
2996
3236
  sources.current.delete(id);
2997
3237
  setAttachments((current) => {
2998
3238
  const removed = current.find((attachment) => attachment.id === id);
@@ -3002,7 +3242,7 @@ function useFileAttachments(options = {}) {
3002
3242
  return current.filter((attachment) => attachment.id !== id);
3003
3243
  });
3004
3244
  }, []);
3005
- const clear = useCallback4(() => {
3245
+ const clear = useCallback5(() => {
3006
3246
  sources.current.clear();
3007
3247
  setAttachments((current) => {
3008
3248
  for (const attachment of current) {
@@ -3026,7 +3266,7 @@ function useFileAttachments(options = {}) {
3026
3266
  }
3027
3267
 
3028
3268
  // src/hooks/use-turn-queue.ts
3029
- import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef4, useState as useState11 } from "react";
3269
+ import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef5, useState as useState11 } from "react";
3030
3270
  function isTurnQueueEvent(event) {
3031
3271
  return event.type.startsWith("turn.");
3032
3272
  }
@@ -3070,9 +3310,9 @@ function useTurnQueue(sessionId, options = {}) {
3070
3310
  const [loading, setLoading] = useState11(enabled);
3071
3311
  const [error, setError] = useState11(null);
3072
3312
  const mutation = useMutationRunner();
3073
- const generation = useRef4(0);
3074
- const targetKeyRef = useRef4(null);
3075
- const load = useCallback5(async () => {
3313
+ const generation = useRef5(0);
3314
+ const targetKeyRef = useRef5(null);
3315
+ const load = useCallback6(async () => {
3076
3316
  if (!sessionId) {
3077
3317
  return;
3078
3318
  }
@@ -3121,7 +3361,7 @@ function useTurnQueue(sessionId, options = {}) {
3121
3361
  enabled,
3122
3362
  ...options.events !== void 0 ? { events: options.events } : {}
3123
3363
  });
3124
- const editTurn = useCallback5(
3364
+ const editTurn = useCallback6(
3125
3365
  async (turnId, update) => {
3126
3366
  if (!sessionId) {
3127
3367
  return null;
@@ -3137,7 +3377,7 @@ function useTurnQueue(sessionId, options = {}) {
3137
3377
  },
3138
3378
  [client, workspaceId, sessionId, mutation.run, load]
3139
3379
  );
3140
- const reorderTurns = useCallback5(
3380
+ const reorderTurns = useCallback6(
3141
3381
  async (turnIds) => {
3142
3382
  if (!sessionId || turnIds.length === 0) {
3143
3383
  return null;
@@ -3156,7 +3396,7 @@ function useTurnQueue(sessionId, options = {}) {
3156
3396
  },
3157
3397
  [client, workspaceId, sessionId, mutation.run, load]
3158
3398
  );
3159
- const removeTurn = useCallback5(
3399
+ const removeTurn = useCallback6(
3160
3400
  async (turnId) => {
3161
3401
  if (!sessionId) {
3162
3402
  return null;
@@ -3190,7 +3430,7 @@ function useTurnQueue(sessionId, options = {}) {
3190
3430
 
3191
3431
  // src/hooks/use-goal.ts
3192
3432
  import { OpenGeniApiError } from "@opengeni/sdk";
3193
- import { useCallback as useCallback6, useEffect as useEffect6, useRef as useRef5, useState as useState12 } from "react";
3433
+ import { useCallback as useCallback7, useEffect as useEffect6, useRef as useRef6, useState as useState12 } from "react";
3194
3434
  function isGoalEvent(event) {
3195
3435
  return event.type.startsWith("goal.");
3196
3436
  }
@@ -3203,9 +3443,9 @@ function useGoal(sessionId, options = {}) {
3203
3443
  const [loading, setLoading] = useState12(enabled);
3204
3444
  const [error, setError] = useState12(null);
3205
3445
  const mutation = useMutationRunner();
3206
- const generation = useRef5(0);
3207
- const targetKeyRef = useRef5(null);
3208
- const load = useCallback6(async () => {
3446
+ const generation = useRef6(0);
3447
+ const targetKeyRef = useRef6(null);
3448
+ const load = useCallback7(async () => {
3209
3449
  if (!sessionId) {
3210
3450
  return;
3211
3451
  }
@@ -3266,7 +3506,7 @@ function useGoal(sessionId, options = {}) {
3266
3506
  enabled,
3267
3507
  ...sharedEvents !== void 0 ? { events: sharedEvents } : {}
3268
3508
  });
3269
- const pause = useCallback6(
3509
+ const pause = useCallback7(
3270
3510
  async (rationale) => {
3271
3511
  if (!sessionId) {
3272
3512
  return null;
@@ -3282,7 +3522,7 @@ function useGoal(sessionId, options = {}) {
3282
3522
  },
3283
3523
  [client, workspaceId, sessionId, mutation.run]
3284
3524
  );
3285
- const resume = useCallback6(async () => {
3525
+ const resume = useCallback7(async () => {
3286
3526
  if (!sessionId) {
3287
3527
  return null;
3288
3528
  }
@@ -3309,12 +3549,12 @@ function useGoal(sessionId, options = {}) {
3309
3549
  }
3310
3550
 
3311
3551
  // src/hooks/use-session-control.ts
3312
- import { useCallback as useCallback7 } from "react";
3552
+ import { useCallback as useCallback8 } from "react";
3313
3553
  function useSessionControl(sessionId, options = {}) {
3314
3554
  const { client, workspaceId } = useOpenGeni(options);
3315
3555
  const interruptMutation = useMutationRunner();
3316
3556
  const approvalMutation = useMutationRunner();
3317
- const interrupt = useCallback7(
3557
+ const interrupt = useCallback8(
3318
3558
  async (reason) => {
3319
3559
  if (!sessionId) {
3320
3560
  return null;
@@ -3323,7 +3563,7 @@ function useSessionControl(sessionId, options = {}) {
3323
3563
  },
3324
3564
  [client, workspaceId, sessionId, interruptMutation.run]
3325
3565
  );
3326
- const decide = useCallback7(
3566
+ const decide = useCallback8(
3327
3567
  async (approvalId, decision, message) => {
3328
3568
  if (!sessionId) {
3329
3569
  return null;
@@ -3336,16 +3576,16 @@ function useSessionControl(sessionId, options = {}) {
3336
3576
  },
3337
3577
  [client, workspaceId, sessionId, approvalMutation.run]
3338
3578
  );
3339
- const approve = useCallback7(
3579
+ const approve = useCallback8(
3340
3580
  async (approvalId, message) => await decide(approvalId, "approve", message),
3341
3581
  [decide]
3342
3582
  );
3343
- const reject = useCallback7(
3583
+ const reject = useCallback8(
3344
3584
  async (approvalId, message) => await decide(approvalId, "reject", message),
3345
3585
  [decide]
3346
3586
  );
3347
3587
  const error = approvalMutation.mutationError ?? interruptMutation.mutationError;
3348
- const clearError = useCallback7(() => {
3588
+ const clearError = useCallback8(() => {
3349
3589
  interruptMutation.clearMutationError();
3350
3590
  approvalMutation.clearMutationError();
3351
3591
  }, [interruptMutation.clearMutationError, approvalMutation.clearMutationError]);
@@ -3361,11 +3601,11 @@ function useSessionControl(sessionId, options = {}) {
3361
3601
  }
3362
3602
 
3363
3603
  // src/hooks/use-scheduled-tasks.ts
3364
- import { useCallback as useCallback8 } from "react";
3604
+ import { useCallback as useCallback9 } from "react";
3365
3605
  function useScheduledTasks(options = {}) {
3366
3606
  const { client, workspaceId } = useOpenGeni(options);
3367
3607
  const limit = options.limit;
3368
- const load = useCallback8(
3608
+ const load = useCallback9(
3369
3609
  async () => await client.listScheduledTasks(workspaceId, limit !== void 0 ? { limit } : {}),
3370
3610
  [client, workspaceId, limit]
3371
3611
  );
@@ -3374,11 +3614,11 @@ function useScheduledTasks(options = {}) {
3374
3614
  }
3375
3615
 
3376
3616
  // src/hooks/use-workspace-sessions.ts
3377
- import { useCallback as useCallback9 } from "react";
3617
+ import { useCallback as useCallback10 } from "react";
3378
3618
  function useWorkspaceSessions(options = {}) {
3379
3619
  const { client, workspaceId } = useOpenGeni(options);
3380
3620
  const limit = options.limit;
3381
- const load = useCallback9(
3621
+ const load = useCallback10(
3382
3622
  async () => await client.listSessions(workspaceId, limit !== void 0 ? { limit } : {}),
3383
3623
  [client, workspaceId, limit]
3384
3624
  );
@@ -3387,13 +3627,13 @@ function useWorkspaceSessions(options = {}) {
3387
3627
  }
3388
3628
 
3389
3629
  // src/hooks/use-environments.ts
3390
- import { useCallback as useCallback10 } from "react";
3630
+ import { useCallback as useCallback11 } from "react";
3391
3631
  function useEnvironments(options = {}) {
3392
3632
  const { client, workspaceId } = useOpenGeni(options);
3393
- const load = useCallback10(async () => await client.listEnvironments(workspaceId), [client, workspaceId]);
3633
+ const load = useCallback11(async () => await client.listEnvironments(workspaceId), [client, workspaceId]);
3394
3634
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3395
3635
  const mutation = useMutationRunner();
3396
- const create = useCallback10(
3636
+ const create = useCallback11(
3397
3637
  async (request) => {
3398
3638
  const result = await mutation.run(() => client.createEnvironment(workspaceId, request));
3399
3639
  if (result) {
@@ -3403,7 +3643,7 @@ function useEnvironments(options = {}) {
3403
3643
  },
3404
3644
  [client, workspaceId, mutation.run, state.refresh]
3405
3645
  );
3406
- const update = useCallback10(
3646
+ const update = useCallback11(
3407
3647
  async (environmentId, request) => {
3408
3648
  const result = await mutation.run(() => client.updateEnvironment(workspaceId, environmentId, request));
3409
3649
  if (result) {
@@ -3413,7 +3653,7 @@ function useEnvironments(options = {}) {
3413
3653
  },
3414
3654
  [client, workspaceId, mutation.run, state.refresh]
3415
3655
  );
3416
- const remove = useCallback10(
3656
+ const remove = useCallback11(
3417
3657
  async (environmentId) => {
3418
3658
  const result = await mutation.run(async () => {
3419
3659
  await client.deleteEnvironment(workspaceId, environmentId);
@@ -3426,7 +3666,7 @@ function useEnvironments(options = {}) {
3426
3666
  },
3427
3667
  [client, workspaceId, mutation.run, state.refresh]
3428
3668
  );
3429
- const setVariable = useCallback10(
3669
+ const setVariable = useCallback11(
3430
3670
  async (environmentId, name, value) => {
3431
3671
  const result = await mutation.run(() => client.setEnvironmentVariable(workspaceId, environmentId, name, value));
3432
3672
  if (result) {
@@ -3436,7 +3676,7 @@ function useEnvironments(options = {}) {
3436
3676
  },
3437
3677
  [client, workspaceId, mutation.run, state.refresh]
3438
3678
  );
3439
- const deleteVariable = useCallback10(
3679
+ const deleteVariable = useCallback11(
3440
3680
  async (environmentId, name) => {
3441
3681
  const result = await mutation.run(async () => {
3442
3682
  await client.deleteEnvironmentVariable(workspaceId, environmentId, name);
@@ -3466,13 +3706,13 @@ function useEnvironments(options = {}) {
3466
3706
  }
3467
3707
 
3468
3708
  // src/hooks/use-packs.ts
3469
- import { useCallback as useCallback11 } from "react";
3709
+ import { useCallback as useCallback12 } from "react";
3470
3710
  function usePacks(options = {}) {
3471
3711
  const { client, workspaceId } = useOpenGeni(options);
3472
- const load = useCallback11(async () => await client.listPacks(workspaceId), [client, workspaceId]);
3712
+ const load = useCallback12(async () => await client.listPacks(workspaceId), [client, workspaceId]);
3473
3713
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3474
3714
  const mutation = useMutationRunner();
3475
- const register = useCallback11(
3715
+ const register = useCallback12(
3476
3716
  async (manifest) => {
3477
3717
  const result = await mutation.run(() => client.registerPack(workspaceId, manifest));
3478
3718
  if (result) {
@@ -3482,7 +3722,7 @@ function usePacks(options = {}) {
3482
3722
  },
3483
3723
  [client, workspaceId, mutation.run, state.refresh]
3484
3724
  );
3485
- const enable = useCallback11(
3725
+ const enable = useCallback12(
3486
3726
  async (packId, request = {}) => {
3487
3727
  const result = await mutation.run(() => client.enablePack(workspaceId, packId, request));
3488
3728
  if (result) {
@@ -3492,7 +3732,7 @@ function usePacks(options = {}) {
3492
3732
  },
3493
3733
  [client, workspaceId, mutation.run, state.refresh]
3494
3734
  );
3495
- const remove = useCallback11(
3735
+ const remove = useCallback12(
3496
3736
  async (packId) => {
3497
3737
  const result = await mutation.run(async () => {
3498
3738
  await client.deletePack(workspaceId, packId);
@@ -3506,7 +3746,7 @@ function usePacks(options = {}) {
3506
3746
  [client, workspaceId, mutation.run, state.refresh]
3507
3747
  );
3508
3748
  const installations = state.data?.installations ?? [];
3509
- const installationFor = useCallback11(
3749
+ const installationFor = useCallback12(
3510
3750
  (packId) => installations.find((installation) => installation.packId === packId) ?? null,
3511
3751
  [installations]
3512
3752
  );
@@ -3527,13 +3767,13 @@ function usePacks(options = {}) {
3527
3767
  }
3528
3768
 
3529
3769
  // src/hooks/use-workspaces.ts
3530
- import { useCallback as useCallback12 } from "react";
3770
+ import { useCallback as useCallback13 } from "react";
3531
3771
  function useWorkspaces(options = {}) {
3532
3772
  const client = useOpenGeniClient(options);
3533
- const load = useCallback12(async () => await client.listWorkspaces(), [client]);
3773
+ const load = useCallback13(async () => await client.listWorkspaces(), [client]);
3534
3774
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3535
3775
  const mutation = useMutationRunner();
3536
- const create = useCallback12(
3776
+ const create = useCallback13(
3537
3777
  async (request) => {
3538
3778
  const result = await mutation.run(() => client.createWorkspace(request));
3539
3779
  if (result) {
@@ -3543,7 +3783,7 @@ function useWorkspaces(options = {}) {
3543
3783
  },
3544
3784
  [client, mutation.run, state.refresh]
3545
3785
  );
3546
- const update = useCallback12(
3786
+ const update = useCallback13(
3547
3787
  async (workspaceId, request) => {
3548
3788
  const result = await mutation.run(() => client.updateWorkspace(workspaceId, request));
3549
3789
  if (result) {
@@ -3567,12 +3807,12 @@ function useWorkspaces(options = {}) {
3567
3807
  }
3568
3808
 
3569
3809
  // src/hooks/use-billing-usage.ts
3570
- import { useCallback as useCallback13 } from "react";
3810
+ import { useCallback as useCallback14 } from "react";
3571
3811
  function useBillingUsage(options = {}) {
3572
3812
  const client = useOpenGeniClient(options);
3573
3813
  const accountId = options.accountId;
3574
3814
  const workspaceId = options.workspaceId;
3575
- const load = useCallback13(
3815
+ const load = useCallback14(
3576
3816
  async () => await client.getBillingUsage({
3577
3817
  ...accountId !== void 0 ? { accountId } : {},
3578
3818
  ...workspaceId !== void 0 ? { workspaceId } : {}
@@ -3590,10 +3830,10 @@ function useBillingUsage(options = {}) {
3590
3830
  }
3591
3831
 
3592
3832
  // src/hooks/use-available-models.ts
3593
- import { useCallback as useCallback14 } from "react";
3833
+ import { useCallback as useCallback15 } from "react";
3594
3834
  function useAvailableModels(options = {}) {
3595
3835
  const client = useOpenGeniClient(options);
3596
- const load = useCallback14(async () => await client.getClientConfig(), [client]);
3836
+ const load = useCallback15(async () => await client.getClientConfig(), [client]);
3597
3837
  const state = usePolledValue(load, { pollIntervalMs: options.pollIntervalMs, enabled: options.enabled });
3598
3838
  return {
3599
3839
  models: state.data?.models ?? [],
@@ -3609,7 +3849,7 @@ import {
3609
3849
  OpenGeniApiError as OpenGeniApiError2,
3610
3850
  applyUrlRotation
3611
3851
  } from "@opengeni/sdk";
3612
- import { useCallback as useCallback15, useEffect as useEffect7, useRef as useRef6, useState as useState13 } from "react";
3852
+ import { useCallback as useCallback16, useEffect as useEffect7, useRef as useRef7, useState as useState13 } from "react";
3613
3853
  function desktopAttachable(cell) {
3614
3854
  if (cell.transport !== null) return true;
3615
3855
  return cell.reason === "lease_cold" || cell.reason === "not_provisioned" || cell.reason === null;
@@ -3644,9 +3884,9 @@ function useSessionCapabilities(sessionId, options = {}) {
3644
3884
  const [viewerCapReached, setViewerCapReached] = useState13(false);
3645
3885
  const [viewerId, setViewerId] = useState13(null);
3646
3886
  const [nonce, setNonce] = useState13(0);
3647
- const epochRef = useRef6(0);
3648
- const viewerIdRef = useRef6(null);
3649
- const renegotiate = useCallback15(() => {
3887
+ const epochRef = useRef7(0);
3888
+ const viewerIdRef = useRef7(null);
3889
+ const renegotiate = useCallback16(() => {
3650
3890
  setNonce((n) => n + 1);
3651
3891
  }, []);
3652
3892
  useEffect7(() => {
@@ -3844,7 +4084,7 @@ import {
3844
4084
  desktopSocketUrl,
3845
4085
  nextDesktopState
3846
4086
  } from "@opengeni/sdk";
3847
- import { useEffect as useEffect9, useRef as useRef8, useState as useState15 } from "react";
4087
+ import { useEffect as useEffect9, useRef as useRef9, useState as useState15 } from "react";
3848
4088
 
3849
4089
  // src/lib/relay-wire.ts
3850
4090
  import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
@@ -3917,7 +4157,7 @@ function decodeStreamFrame(bytes) {
3917
4157
  }
3918
4158
 
3919
4159
  // src/hooks/use-relay-frame-stream.ts
3920
- import { useEffect as useEffect8, useRef as useRef7, useState as useState14 } from "react";
4160
+ import { useEffect as useEffect8, useRef as useRef8, useState as useState14 } from "react";
3921
4161
  var TAG_OPEN = 1;
3922
4162
  var TAG_OPENACK = 2;
3923
4163
  var TAG_FRAME = 3;
@@ -3935,7 +4175,7 @@ function useRelayFrameStream(options) {
3935
4175
  const [state, setState] = useState14("idle");
3936
4176
  const [error, setError] = useState14(null);
3937
4177
  const [nonce, setNonce] = useState14(0);
3938
- const stateRef = useRef7("idle");
4178
+ const stateRef = useRef8("idle");
3939
4179
  const setBoth = (next) => {
3940
4180
  stateRef.current = next;
3941
4181
  setState(next);
@@ -3944,7 +4184,7 @@ function useRelayFrameStream(options) {
3944
4184
  const transport = capability?.transport ?? null;
3945
4185
  const url = capability?.url ?? null;
3946
4186
  const token = capability?.token ?? null;
3947
- const factoryRef = useRef7(webSocketFactory);
4187
+ const factoryRef = useRef8(webSocketFactory);
3948
4188
  factoryRef.current = webSocketFactory;
3949
4189
  useEffect8(() => {
3950
4190
  if (typeof window === "undefined") return;
@@ -4138,7 +4378,7 @@ function useDesktopStream(options) {
4138
4378
  const [state, setState] = useState15("idle");
4139
4379
  const [error, setError] = useState15(null);
4140
4380
  const [nonce, setNonce] = useState15(0);
4141
- const stateRef = useRef8("idle");
4381
+ const stateRef = useRef9("idle");
4142
4382
  const setBoth = (next) => {
4143
4383
  stateRef.current = next;
4144
4384
  setState(next);
@@ -4148,11 +4388,11 @@ function useDesktopStream(options) {
4148
4388
  const token = capability?.token ?? null;
4149
4389
  const transport = capability?.transport ?? null;
4150
4390
  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);
4391
+ const rfbRef = useRef9(null);
4392
+ const interactiveRef = useRef9(interactive);
4393
+ const scaleViewportRef = useRef9(scaleViewport);
4394
+ const modeRef = useRef9(mode);
4395
+ const rfbFactoryRef = useRef9(rfbFactory);
4156
4396
  interactiveRef.current = interactive;
4157
4397
  scaleViewportRef.current = scaleViewport;
4158
4398
  modeRef.current = mode;
@@ -4245,7 +4485,7 @@ import {
4245
4485
  ttydResizeFrame,
4246
4486
  TtydServerCommand
4247
4487
  } from "@opengeni/sdk";
4248
- import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef9, useState as useState16 } from "react";
4488
+ import { useEffect as useEffect10, useMemo as useMemo3, useRef as useRef10, useState as useState16 } from "react";
4249
4489
  function decodeFrame(data) {
4250
4490
  if (typeof data === "string") {
4251
4491
  return { command: data.charAt(0), payload: data.slice(1) };
@@ -4258,13 +4498,13 @@ function decodeFrame(data) {
4258
4498
  function useTerminalStream(options) {
4259
4499
  const { capability, onOutput, onTitle, initialCols, initialRows } = options;
4260
4500
  const [status, setStatus] = useState16("closed");
4261
- const wsRef = useRef9(null);
4262
- const sizeRef = useRef9({
4501
+ const wsRef = useRef10(null);
4502
+ const sizeRef = useRef10({
4263
4503
  cols: initialCols ?? 80,
4264
4504
  rows: initialRows ?? 24
4265
4505
  });
4266
- const onOutputRef = useRef9(onOutput);
4267
- const onTitleRef = useRef9(onTitle);
4506
+ const onOutputRef = useRef10(onOutput);
4507
+ const onTitleRef = useRef10(onTitle);
4268
4508
  onOutputRef.current = onOutput;
4269
4509
  onTitleRef.current = onTitle;
4270
4510
  const transport = capability?.transport ?? null;
@@ -4367,7 +4607,7 @@ function useTerminalStream(options) {
4367
4607
 
4368
4608
  // src/hooks/use-sandbox-terminal.ts
4369
4609
  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";
4610
+ import { useCallback as useCallback17, useEffect as useEffect11, useMemo as useMemo4, useRef as useRef11, useState as useState17 } from "react";
4371
4611
  function useSandboxTerminal(sessionId, options) {
4372
4612
  const { client, workspaceId } = useOpenGeni(options);
4373
4613
  const includeAgentFirehose = options.includeAgentFirehose ?? true;
@@ -4377,7 +4617,7 @@ function useSandboxTerminal(sessionId, options) {
4377
4617
  const [openedPtyId, setOpenedPtyId] = useState17(null);
4378
4618
  const [openError, setOpenError] = useState17(null);
4379
4619
  const [reopenNonce, setReopenNonce] = useState17(0);
4380
- const openInFlight = useRef10(false);
4620
+ const openInFlight = useRef11(false);
4381
4621
  const boxWarm = liveness === void 0 || liveness === "warm" || liveness === "draining";
4382
4622
  useEffect11(() => {
4383
4623
  if (!interactive || !sessionId || ptyFilter || !boxWarm) return;
@@ -4467,7 +4707,7 @@ function useSandboxTerminal(sessionId, options) {
4467
4707
  });
4468
4708
  };
4469
4709
  }, [client, workspaceId, sessionId, activePtyId, canWrite, openedPtyId]);
4470
- const close = useCallback16(() => {
4710
+ const close = useCallback17(() => {
4471
4711
  if (!activePtyId || !sessionId) return;
4472
4712
  void client.terminalPtyClose(workspaceId, sessionId, { ptyId: activePtyId }).catch(() => {
4473
4713
  });
@@ -4483,7 +4723,7 @@ function useSandboxTerminal(sessionId, options) {
4483
4723
  }
4484
4724
 
4485
4725
  // src/hooks/use-sandbox-files.ts
4486
- import { useCallback as useCallback17, useEffect as useEffect12, useRef as useRef11, useState as useState18 } from "react";
4726
+ import { useCallback as useCallback18, useEffect as useEffect12, useRef as useRef12, useState as useState18 } from "react";
4487
4727
  function parentOf(path) {
4488
4728
  const i = path.lastIndexOf("/");
4489
4729
  return i <= 0 ? "" : path.slice(0, i);
@@ -4603,15 +4843,15 @@ function useSandboxFiles(sessionId, options = {}) {
4603
4843
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
4604
4844
  const rootPath = options.rootPath ?? "";
4605
4845
  const [tree, setTree] = useState18([]);
4606
- const treeRef = useRef11([]);
4846
+ const treeRef = useRef12([]);
4607
4847
  const [loading, setLoading] = useState18(false);
4608
4848
  const [expandingPaths, setExpandingPaths] = useState18(/* @__PURE__ */ new Set());
4609
4849
  const [error, setError] = useState18(null);
4610
- const statusRef = useRef11(/* @__PURE__ */ new Map());
4611
- const ownRevisionsRef = useRef11(/* @__PURE__ */ new Set());
4850
+ const statusRef = useRef12(/* @__PURE__ */ new Map());
4851
+ const ownRevisionsRef = useRef12(/* @__PURE__ */ new Set());
4612
4852
  const onMutationError = options.onMutationError;
4613
4853
  treeRef.current = tree;
4614
- const applyStatus = useCallback17((nodes) => {
4854
+ const applyStatus = useCallback18((nodes) => {
4615
4855
  const overlay = statusRef.current;
4616
4856
  if (overlay.size === 0) return nodes;
4617
4857
  const walk = (list) => list.map((node) => {
@@ -4623,7 +4863,7 @@ function useSandboxFiles(sessionId, options = {}) {
4623
4863
  });
4624
4864
  return walk(nodes);
4625
4865
  }, []);
4626
- const refresh = useCallback17(async () => {
4866
+ const refresh = useCallback18(async () => {
4627
4867
  if (!sessionId) return;
4628
4868
  setLoading(true);
4629
4869
  setError(null);
@@ -4649,7 +4889,7 @@ function useSandboxFiles(sessionId, options = {}) {
4649
4889
  setLoading(false);
4650
4890
  }
4651
4891
  }, [client, workspaceId, sessionId, rootPath, applyStatus]);
4652
- const expand = useCallback17(
4892
+ const expand = useCallback18(
4653
4893
  async (path) => {
4654
4894
  if (!sessionId) return;
4655
4895
  setExpandingPaths((prev) => {
@@ -4674,14 +4914,14 @@ function useSandboxFiles(sessionId, options = {}) {
4674
4914
  },
4675
4915
  [client, workspaceId, sessionId, applyStatus]
4676
4916
  );
4677
- const readFile = useCallback17(
4917
+ const readFile = useCallback18(
4678
4918
  async (path) => {
4679
4919
  if (!sessionId) throw new Error("no session");
4680
4920
  return await client.fsRead(workspaceId, sessionId, { path });
4681
4921
  },
4682
4922
  [client, workspaceId, sessionId]
4683
4923
  );
4684
- const reconcilePath = useCallback17(
4924
+ const reconcilePath = useCallback18(
4685
4925
  async (path) => {
4686
4926
  if (!sessionId) return;
4687
4927
  if (!parentIsLoaded(treeRef.current, path)) return;
@@ -4700,7 +4940,7 @@ function useSandboxFiles(sessionId, options = {}) {
4700
4940
  },
4701
4941
  [client, workspaceId, sessionId, applyStatus]
4702
4942
  );
4703
- const runOptimistic = useCallback17(
4943
+ const runOptimistic = useCallback18(
4704
4944
  async (opName, apply, op, reconcileParents) => {
4705
4945
  const snapshot = treeRef.current;
4706
4946
  setTree(applyStatus(apply(snapshot)));
@@ -4722,7 +4962,7 @@ function useSandboxFiles(sessionId, options = {}) {
4722
4962
  },
4723
4963
  [applyStatus, reconcilePath, onMutationError]
4724
4964
  );
4725
- const writeFile = useCallback17(
4965
+ const writeFile = useCallback18(
4726
4966
  async (path, content) => {
4727
4967
  if (!sessionId) throw new Error("no session");
4728
4968
  const parent = parentOf(path);
@@ -4737,7 +4977,7 @@ function useSandboxFiles(sessionId, options = {}) {
4737
4977
  },
4738
4978
  [client, workspaceId, sessionId, tree, runOptimistic]
4739
4979
  );
4740
- const createFile = useCallback17(
4980
+ const createFile = useCallback18(
4741
4981
  async (path) => {
4742
4982
  if (!sessionId) throw new Error("no session");
4743
4983
  const parent = parentOf(path);
@@ -4751,7 +4991,7 @@ function useSandboxFiles(sessionId, options = {}) {
4751
4991
  },
4752
4992
  [client, workspaceId, sessionId, runOptimistic]
4753
4993
  );
4754
- const createDir = useCallback17(
4994
+ const createDir = useCallback18(
4755
4995
  async (path) => {
4756
4996
  if (!sessionId) throw new Error("no session");
4757
4997
  const parent = parentOf(path);
@@ -4765,7 +5005,7 @@ function useSandboxFiles(sessionId, options = {}) {
4765
5005
  },
4766
5006
  [client, workspaceId, sessionId, runOptimistic]
4767
5007
  );
4768
- const deleteEntry = useCallback17(
5008
+ const deleteEntry = useCallback18(
4769
5009
  async (path, recursive = false) => {
4770
5010
  if (!sessionId) throw new Error("no session");
4771
5011
  await runOptimistic(
@@ -4777,7 +5017,7 @@ function useSandboxFiles(sessionId, options = {}) {
4777
5017
  },
4778
5018
  [client, workspaceId, sessionId, runOptimistic]
4779
5019
  );
4780
- const moveEntry = useCallback17(
5020
+ const moveEntry = useCallback18(
4781
5021
  async (path, newPath, opts) => {
4782
5022
  if (!sessionId) throw new Error("no session");
4783
5023
  const from = parentOf(path);
@@ -4807,7 +5047,7 @@ function useSandboxFiles(sessionId, options = {}) {
4807
5047
  }
4808
5048
  void refresh();
4809
5049
  }, [enabled, refresh]);
4810
- const refreshGitOverlay = useCallback17(async () => {
5050
+ const refreshGitOverlay = useCallback18(async () => {
4811
5051
  if (!sessionId) return;
4812
5052
  try {
4813
5053
  const status = await client.gitStatus(workspaceId, sessionId, { path: rootPath });
@@ -4823,10 +5063,10 @@ function useSandboxFiles(sessionId, options = {}) {
4823
5063
  }
4824
5064
  }, [client, workspaceId, sessionId, rootPath, applyStatus]);
4825
5065
  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);
5066
+ const lastSeqRef = useRef12(0);
5067
+ const pendingParentsRef = useRef12(/* @__PURE__ */ new Set());
5068
+ const pendingGitRef = useRef12(false);
5069
+ const debounceRef = useRef12(null);
4830
5070
  useEffect12(() => {
4831
5071
  if (!enabled || !events) return;
4832
5072
  let sawNew = false;
@@ -4870,7 +5110,7 @@ function useSandboxFiles(sessionId, options = {}) {
4870
5110
  },
4871
5111
  []
4872
5112
  );
4873
- const wasLiveRef = useRef11(false);
5113
+ const wasLiveRef = useRef12(false);
4874
5114
  const liveness = options.liveness;
4875
5115
  useEffect12(() => {
4876
5116
  const live = liveness === "warm" || liveness === "draining";
@@ -4898,7 +5138,7 @@ function useSandboxFiles(sessionId, options = {}) {
4898
5138
  }
4899
5139
 
4900
5140
  // src/hooks/use-sandbox-git.ts
4901
- import { useCallback as useCallback18, useEffect as useEffect13, useRef as useRef12, useState as useState19 } from "react";
5141
+ import { useCallback as useCallback19, useEffect as useEffect13, useRef as useRef13, useState as useState19 } from "react";
4902
5142
  function useSandboxGit(sessionId, options = {}) {
4903
5143
  const { client, workspaceId } = useOpenGeni(options);
4904
5144
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
@@ -4911,7 +5151,7 @@ function useSandboxGit(sessionId, options = {}) {
4911
5151
  const [behind, setBehind] = useState19(0);
4912
5152
  const [loading, setLoading] = useState19(false);
4913
5153
  const [error, setError] = useState19(null);
4914
- const refresh = useCallback18(async () => {
5154
+ const refresh = useCallback19(async () => {
4915
5155
  if (!sessionId) return;
4916
5156
  setLoading(true);
4917
5157
  setError(null);
@@ -4943,7 +5183,7 @@ function useSandboxGit(sessionId, options = {}) {
4943
5183
  void refresh();
4944
5184
  }, [enabled, refresh]);
4945
5185
  const events = options.events;
4946
- const lastChangeRef = useRef12(0);
5186
+ const lastChangeRef = useRef13(0);
4947
5187
  useEffect13(() => {
4948
5188
  if (!enabled || !events) return;
4949
5189
  let latest = lastChangeRef.current;
@@ -5192,14 +5432,14 @@ function clearErrorMessage(cause) {
5192
5432
  }
5193
5433
 
5194
5434
  // src/hooks/use-slash-commands.ts
5195
- import { useCallback as useCallback19, useMemo as useMemo5, useRef as useRef13, useState as useState20 } from "react";
5435
+ import { useCallback as useCallback20, useMemo as useMemo5, useRef as useRef14, useState as useState20 } from "react";
5196
5436
  function useSlashCommands(options) {
5197
5437
  const { commands, context, handlers, value, setValue } = options;
5198
5438
  const [highlight, setHighlight] = useState20(0);
5199
5439
  const [dismissedValue, setDismissedValue] = useState20(null);
5200
5440
  const dismissed = dismissedValue !== null && dismissedValue === value;
5201
- const navigatedRef = useRef13(false);
5202
- const navTokenRef = useRef13(value);
5441
+ const navigatedRef = useRef14(false);
5442
+ const navTokenRef = useRef14(value);
5203
5443
  if (navTokenRef.current !== value) {
5204
5444
  navTokenRef.current = value;
5205
5445
  navigatedRef.current = false;
@@ -5232,7 +5472,7 @@ function useSlashCommands(options) {
5232
5472
  const isCommandDraft = parsed !== null && items.length > 0;
5233
5473
  const clampedHighlight = items.length === 0 ? 0 : Math.min(highlight, items.length - 1);
5234
5474
  const activeArgHint = activeCommand ? argHint(activeCommand.args) : "";
5235
- const buildContext = useCallback19(
5475
+ const buildContext = useCallback20(
5236
5476
  (command) => {
5237
5477
  if (!context) {
5238
5478
  return null;
@@ -5241,7 +5481,7 @@ function useSlashCommands(options) {
5241
5481
  },
5242
5482
  [context, handlers]
5243
5483
  );
5244
- const execute = useCallback19(
5484
+ const execute = useCallback20(
5245
5485
  async (command, args) => {
5246
5486
  const ctx = buildContext(command);
5247
5487
  if (!ctx) {
@@ -5261,20 +5501,20 @@ function useSlashCommands(options) {
5261
5501
  },
5262
5502
  [buildContext, setValue]
5263
5503
  );
5264
- const autocomplete = useCallback19(
5504
+ const autocomplete = useCallback20(
5265
5505
  (command) => {
5266
5506
  setValue(`/${command.name} `);
5267
5507
  setHighlight(0);
5268
5508
  },
5269
5509
  [setValue]
5270
5510
  );
5271
- const autocompleteHighlighted = useCallback19(() => {
5511
+ const autocompleteHighlighted = useCallback20(() => {
5272
5512
  const command = items[clampedHighlight];
5273
5513
  if (command) {
5274
5514
  autocomplete(command);
5275
5515
  }
5276
5516
  }, [items, clampedHighlight, autocomplete]);
5277
- const runResolved = useCallback19(
5517
+ const runResolved = useCallback20(
5278
5518
  async (command, options2) => {
5279
5519
  if (!parsed) {
5280
5520
  return;
@@ -5297,7 +5537,7 @@ function useSlashCommands(options) {
5297
5537
  },
5298
5538
  [parsed, activeCommand, autocomplete, execute]
5299
5539
  );
5300
- const runHighlighted = useCallback19(async () => {
5540
+ const runHighlighted = useCallback20(async () => {
5301
5541
  if (!parsed) {
5302
5542
  return;
5303
5543
  }
@@ -5316,7 +5556,7 @@ function useSlashCommands(options) {
5316
5556
  }
5317
5557
  await runResolved(command);
5318
5558
  }, [parsed, activeCommand, items, clampedHighlight, runResolved]);
5319
- const runAt = useCallback19(
5559
+ const runAt = useCallback20(
5320
5560
  async (index) => {
5321
5561
  const command = items[index];
5322
5562
  if (!command) {
@@ -5326,8 +5566,8 @@ function useSlashCommands(options) {
5326
5566
  },
5327
5567
  [items, runResolved]
5328
5568
  );
5329
- const runningRef = useRef13(false);
5330
- const onKeyDown = useCallback19(
5569
+ const runningRef = useRef14(false);
5570
+ const onKeyDown = useCallback20(
5331
5571
  (event) => {
5332
5572
  if (!open) {
5333
5573
  return false;
@@ -5469,7 +5709,7 @@ function CommandPalette({ open, items, highlight, onHighlight, onRun, argHintTex
5469
5709
  // src/components/chat-composer.tsx
5470
5710
  import { ArrowUpIcon, FileIcon, ImageIcon as ImageIcon2, LoaderCircleIcon, PaperclipIcon, RotateCwIcon, SquareIcon, XIcon as XIcon2 } from "lucide-react";
5471
5711
  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";
5712
+ import { useCallback as useCallback21, useEffect as useEffect14, useId as useId2, useMemo as useMemo7, useRef as useRef15, useState as useState21 } from "react";
5473
5713
 
5474
5714
  // src/components/model-picker.tsx
5475
5715
  import { ChevronDownIcon } from "lucide-react";
@@ -5546,15 +5786,15 @@ function ChatComposer({
5546
5786
  commandContext,
5547
5787
  onClearView
5548
5788
  }) {
5549
- const textareaRef = useRef14(null);
5550
- const fileInputRef = useRef14(null);
5789
+ const textareaRef = useRef15(null);
5790
+ const fileInputRef = useRef15(null);
5551
5791
  const active = status != null && ACTIVE_STATUSES.has(status);
5552
5792
  const blockedByUpload = attachments?.uploading === true;
5553
5793
  const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;
5554
5794
  const canSend = (composer.canSend || hasReadyAttachment) && !blockedByUpload && !composer.sending;
5555
5795
  const [dragging, setDragging] = useState21(false);
5556
5796
  const dragCarriesFiles = (event) => event.dataTransfer != null && [...event.dataTransfer.types].includes("Files");
5557
- const handleDragOver = useCallback20(
5797
+ const handleDragOver = useCallback21(
5558
5798
  (event) => {
5559
5799
  if (!attachments || !dragCarriesFiles(event)) {
5560
5800
  return;
@@ -5564,7 +5804,7 @@ function ChatComposer({
5564
5804
  },
5565
5805
  [attachments]
5566
5806
  );
5567
- const handleDragLeave = useCallback20(
5807
+ const handleDragLeave = useCallback21(
5568
5808
  (event) => {
5569
5809
  if (!attachments) {
5570
5810
  return;
@@ -5576,7 +5816,7 @@ function ChatComposer({
5576
5816
  },
5577
5817
  [attachments]
5578
5818
  );
5579
- const handleDrop = useCallback20(
5819
+ const handleDrop = useCallback21(
5580
5820
  (event) => {
5581
5821
  if (!attachments || !dragCarriesFiles(event)) {
5582
5822
  return;
@@ -5593,7 +5833,7 @@ function ChatComposer({
5593
5833
  const [helpOpen, setHelpOpen] = useState21(false);
5594
5834
  const [confirmState, setConfirmState] = useState21(null);
5595
5835
  const listboxId = useId2();
5596
- const resize = useCallback20(() => {
5836
+ const resize = useCallback21(() => {
5597
5837
  const textarea = textareaRef.current;
5598
5838
  if (!textarea) {
5599
5839
  return;
@@ -5662,14 +5902,14 @@ function ChatComposer({
5662
5902
  void composer.send();
5663
5903
  }
5664
5904
  };
5665
- const handlePaste = useCallback20(
5905
+ const handlePaste = useCallback21(
5666
5906
  (event) => {
5667
5907
  onPaste?.(event);
5668
5908
  attachments?.addFromPaste(event);
5669
5909
  },
5670
5910
  [onPaste, attachments]
5671
5911
  );
5672
- const handleFileChange = useCallback20(
5912
+ const handleFileChange = useCallback21(
5673
5913
  (event) => {
5674
5914
  if (event.target.files) {
5675
5915
  attachments?.addFiles(event.target.files);
@@ -5915,7 +6155,7 @@ function ConfirmBar({
5915
6155
  onConfirm,
5916
6156
  returnFocusRef
5917
6157
  }) {
5918
- const confirmRef = useRef14(null);
6158
+ const confirmRef = useRef15(null);
5919
6159
  const descriptionId = useId2();
5920
6160
  useEffect14(() => {
5921
6161
  const returnTo = returnFocusRef?.current ?? null;
@@ -6071,7 +6311,7 @@ import {
6071
6311
  TriangleAlertIcon as TriangleAlertIcon2
6072
6312
  } from "lucide-react";
6073
6313
  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";
6314
+ import { useCallback as useCallback22, useEffect as useEffect15, useLayoutEffect, useMemo as useMemo8, useRef as useRef16, useState as useState22 } from "react";
6075
6315
 
6076
6316
  // src/components/markdown.tsx
6077
6317
  import { memo } from "react";
@@ -6230,19 +6470,38 @@ function MessageTimeline({
6230
6470
  onOpenSession,
6231
6471
  toolRegistry = defaultToolRegistry,
6232
6472
  autoFollow = true,
6473
+ hasOlder = false,
6474
+ loadingOlder = false,
6475
+ onLoadOlder,
6233
6476
  emptyState,
6234
6477
  className
6235
6478
  }) {
6236
6479
  const resolvedItems = useMemo8(() => items ?? buildTimeline(events ?? []), [items, events]);
6237
6480
  const groups = useMemo8(() => groupTimeline(resolvedItems), [resolvedItems]);
6238
- const scrollRef = useRef15(null);
6481
+ const firstGroupKey = groups[0] ? timelineGroupKey(groups[0]) : null;
6482
+ const scrollRef = useRef16(null);
6483
+ const topSentinelRef = useRef16(null);
6484
+ const previousBulkFirstKeyRef = useRef16(void 0);
6239
6485
  const [pinned, setPinned] = useState22(true);
6240
- const pinnedRef = useRef15(true);
6241
- const anchorRef = useRef15(null);
6486
+ const [bulkActive, setBulkActive] = useState22(true);
6487
+ const [revealed, setRevealed] = useState22(false);
6488
+ const programmaticScrollRef = useRef16(false);
6489
+ const assignScrollTop = useCallback22((node, value) => {
6490
+ const previous = node.scrollTop;
6491
+ programmaticScrollRef.current = true;
6492
+ node.scrollTop = value;
6493
+ if (node.scrollTop === previous) {
6494
+ programmaticScrollRef.current = false;
6495
+ }
6496
+ }, []);
6497
+ const pinnedRef = useRef16(true);
6498
+ const anchorRef = useRef16(null);
6242
6499
  const lastItem = resolvedItems[resolvedItems.length - 1];
6243
6500
  const streaming = lastItem !== void 0 && (lastItem.kind === "agent-message" || lastItem.kind === "reasoning") && lastItem.streaming;
6244
6501
  const working = status === "running" && !streaming;
6245
- const captureAnchor = useCallback21(() => {
6502
+ const firstKeyChangedForBulk = previousBulkFirstKeyRef.current !== void 0 && previousBulkFirstKeyRef.current !== firstGroupKey;
6503
+ const bulkRender = groups.length > 0 && (bulkActive || firstKeyChangedForBulk);
6504
+ const captureAnchor = useCallback22(() => {
6246
6505
  const node = scrollRef.current;
6247
6506
  const inner = node?.firstElementChild;
6248
6507
  if (!node || !inner) {
@@ -6251,6 +6510,9 @@ function MessageTimeline({
6251
6510
  }
6252
6511
  const containerTop = node.getBoundingClientRect().top;
6253
6512
  for (const child of Array.from(inner.children)) {
6513
+ if (child instanceof HTMLElement && child.dataset.ogTimelineChrome !== void 0) {
6514
+ continue;
6515
+ }
6254
6516
  const rect = child.getBoundingClientRect();
6255
6517
  if (rect.bottom > containerTop + 1) {
6256
6518
  anchorRef.current = { el: child, top: rect.top - containerTop };
@@ -6259,12 +6521,43 @@ function MessageTimeline({
6259
6521
  }
6260
6522
  anchorRef.current = null;
6261
6523
  }, []);
6262
- useEffect15(() => {
6524
+ useLayoutEffect(() => {
6263
6525
  const node = scrollRef.current;
6264
6526
  if (node && autoFollow && pinned) {
6265
- node.scrollTop = node.scrollHeight;
6527
+ assignScrollTop(node, node.scrollHeight);
6528
+ }
6529
+ if (!revealed && groups.length > 0) {
6530
+ setRevealed(true);
6266
6531
  }
6267
- }, [resolvedItems, working, autoFollow, pinned]);
6532
+ }, [resolvedItems, working, autoFollow, pinned, revealed, groups.length, assignScrollTop]);
6533
+ useLayoutEffect(() => {
6534
+ if (groups.length === 0 && revealed) {
6535
+ setRevealed(false);
6536
+ }
6537
+ }, [groups.length, revealed]);
6538
+ useLayoutEffect(() => {
6539
+ previousBulkFirstKeyRef.current = firstGroupKey;
6540
+ if (!bulkRender) {
6541
+ return;
6542
+ }
6543
+ setBulkActive(true);
6544
+ const frame = requestFrame(() => setBulkActive(false));
6545
+ return () => cancelFrame(frame);
6546
+ }, [bulkRender, firstGroupKey]);
6547
+ useEffect15(() => {
6548
+ const root = scrollRef.current;
6549
+ const target = topSentinelRef.current;
6550
+ if (!root || !target || !hasOlder || loadingOlder || !onLoadOlder || typeof IntersectionObserver === "undefined") {
6551
+ return;
6552
+ }
6553
+ const observer = new IntersectionObserver((entries) => {
6554
+ if (entries.some((entry) => entry.isIntersecting)) {
6555
+ onLoadOlder();
6556
+ }
6557
+ }, { root, rootMargin: "1600px 0px 0px 0px" });
6558
+ observer.observe(target);
6559
+ return () => observer.disconnect();
6560
+ }, [hasOlder, loadingOlder, onLoadOlder, firstGroupKey]);
6268
6561
  useEffect15(() => {
6269
6562
  const node = scrollRef.current;
6270
6563
  const inner = node?.firstElementChild;
@@ -6277,7 +6570,7 @@ function MessageTimeline({
6277
6570
  return;
6278
6571
  }
6279
6572
  if (autoFollow && pinnedRef.current) {
6280
- current.scrollTop = current.scrollHeight;
6573
+ assignScrollTop(current, current.scrollHeight);
6281
6574
  } else {
6282
6575
  const anchor = anchorRef.current;
6283
6576
  if (anchor && anchor.el.isConnected) {
@@ -6285,7 +6578,7 @@ function MessageTimeline({
6285
6578
  const now = anchor.el.getBoundingClientRect().top - containerTop;
6286
6579
  const diff = now - anchor.top;
6287
6580
  if (diff !== 0) {
6288
- current.scrollTop += diff;
6581
+ assignScrollTop(current, current.scrollTop + diff);
6289
6582
  }
6290
6583
  }
6291
6584
  }
@@ -6293,32 +6586,47 @@ function MessageTimeline({
6293
6586
  });
6294
6587
  observer.observe(inner);
6295
6588
  return () => observer.disconnect();
6296
- }, [autoFollow, captureAnchor]);
6589
+ }, [autoFollow, captureAnchor, assignScrollTop]);
6297
6590
  const onScroll = () => {
6298
6591
  const node = scrollRef.current;
6299
6592
  if (!node) {
6300
6593
  return;
6301
6594
  }
6595
+ const programmatic = programmaticScrollRef.current;
6596
+ programmaticScrollRef.current = false;
6302
6597
  const nextPinned = node.scrollHeight - node.scrollTop - node.clientHeight < 48;
6303
- pinnedRef.current = nextPinned;
6304
- setPinned(nextPinned);
6598
+ if (nextPinned || !programmatic) {
6599
+ pinnedRef.current = nextPinned;
6600
+ setPinned(nextPinned);
6601
+ }
6305
6602
  captureAnchor();
6306
6603
  };
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
- ] }) }),
6604
+ 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: [
6605
+ /* @__PURE__ */ jsx15(
6606
+ "div",
6607
+ {
6608
+ ref: scrollRef,
6609
+ onScroll,
6610
+ style: groups.length > 0 && !revealed ? { visibility: "hidden" } : void 0,
6611
+ className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-4 py-6 [overflow-anchor:none] sm:px-6",
6612
+ children: /* @__PURE__ */ jsxs12("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-5", children: [
6613
+ groups.length === 0 && !working ? emptyState ?? /* @__PURE__ */ jsx15("p", { className: "py-10 text-center text-sm text-og-fg-subtle", children: "No activity yet." }) : null,
6614
+ 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,
6615
+ 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,
6616
+ groups.map((group) => /* @__PURE__ */ jsx15(
6617
+ TimelineGroupView,
6618
+ {
6619
+ group,
6620
+ renderMessageText,
6621
+ onOpenSession,
6622
+ toolRegistry
6623
+ },
6624
+ timelineGroupKey(group)
6625
+ )),
6626
+ 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
6627
+ ] })
6628
+ }
6629
+ ),
6322
6630
  /* @__PURE__ */ jsx15(AnimatePresence4, { children: !pinned && autoFollow ? /* @__PURE__ */ jsxs12(
6323
6631
  motion4.button,
6324
6632
  {
@@ -6347,7 +6655,20 @@ function MessageTimeline({
6347
6655
  ]
6348
6656
  }
6349
6657
  ) : null })
6350
- ] }) });
6658
+ ] }) }) });
6659
+ }
6660
+ function requestFrame(callback) {
6661
+ if (typeof requestAnimationFrame === "function") {
6662
+ return requestAnimationFrame(callback);
6663
+ }
6664
+ return window.setTimeout(() => callback(performance.now()), 16);
6665
+ }
6666
+ function cancelFrame(id) {
6667
+ if (typeof cancelAnimationFrame === "function") {
6668
+ cancelAnimationFrame(id);
6669
+ return;
6670
+ }
6671
+ window.clearTimeout(id);
6351
6672
  }
6352
6673
  function TimelineGroupView({
6353
6674
  group,
@@ -6448,7 +6769,8 @@ function UserMessageRow({
6448
6769
  item,
6449
6770
  renderMessageText
6450
6771
  }) {
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: [
6772
+ const enter = useEntranceAnimation();
6773
+ 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
6774
  item.pending ? /* @__PURE__ */ jsx15("span", { className: "px-1 text-og-xs text-og-fg-subtle", children: "queued" }) : null,
6453
6775
  /* @__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
6776
  ] }) });
@@ -6457,8 +6779,9 @@ function AgentMessageRow({
6457
6779
  item,
6458
6780
  renderMessageText
6459
6781
  }) {
6782
+ const enter = useEntranceAnimation();
6460
6783
  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: [
6784
+ 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
6785
  renderMessageText(item.text, item),
6463
6786
  caret
6464
6787
  ] }) : (
@@ -6472,8 +6795,9 @@ function AgentMessageRow({
6472
6795
  ) });
6473
6796
  }
6474
6797
  function SessionStatusRow({ item }) {
6798
+ const enter = useEntranceAnimation();
6475
6799
  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: [
6800
+ 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
6801
  /* @__PURE__ */ jsx15("span", { className: "h-px flex-1 bg-og-border" }),
6478
6802
  /* @__PURE__ */ jsxs12("span", { className: "inline-flex items-center gap-1.5", children: [
6479
6803
  /* @__PURE__ */ jsx15(StatusDot, { status: item.status, className: "size-1" }),
@@ -6494,8 +6818,9 @@ var GOAL_META = {
6494
6818
  continuation: { label: "Continuing toward the goal", pill: NEUTRAL_PILL, icon: ArrowRightIcon }
6495
6819
  };
6496
6820
  function GoalRow({ item }) {
6821
+ const enter = useEntranceAnimation();
6497
6822
  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: [
6823
+ 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
6824
  /* @__PURE__ */ jsx15(Icon, { className: "size-3.5 shrink-0" }),
6500
6825
  /* @__PURE__ */ jsxs12("span", { className: "truncate", children: [
6501
6826
  label,
@@ -6504,8 +6829,9 @@ function GoalRow({ item }) {
6504
6829
  ] }) });
6505
6830
  }
6506
6831
  function NoticeRow({ item }) {
6832
+ const enter = useEntranceAnimation();
6507
6833
  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: [
6834
+ 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
6835
  /* @__PURE__ */ jsx15(TriangleAlertIcon2, { className: cn("mt-0.5 size-4 shrink-0", item.tone === "cancelled" && "opacity-60") }),
6510
6836
  /* @__PURE__ */ jsx15("span", { className: "min-w-0 whitespace-pre-wrap break-words", children: item.text })
6511
6837
  ] });
@@ -6571,7 +6897,7 @@ function FleetTile({ session, title, subtitle, onOpen, className }) {
6571
6897
  }
6572
6898
 
6573
6899
  // src/components/sandbox-terminal.tsx
6574
- import { useEffect as useEffect16, useRef as useRef16, useState as useState23 } from "react";
6900
+ import { useEffect as useEffect16, useRef as useRef17, useState as useState23 } from "react";
6575
6901
  import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
6576
6902
  function SandboxTerminal({
6577
6903
  result,
@@ -6586,13 +6912,13 @@ function SandboxTerminal({
6586
6912
  onActivate,
6587
6913
  className
6588
6914
  }) {
6589
- const containerRef = useRef16(null);
6590
- const termRef = useRef16(null);
6591
- const fitRef = useRef16(null);
6592
- const writtenRef = useRef16(/* @__PURE__ */ new Set());
6915
+ const containerRef = useRef17(null);
6916
+ const termRef = useRef17(null);
6917
+ const fitRef = useRef17(null);
6918
+ const writtenRef = useRef17(/* @__PURE__ */ new Set());
6593
6919
  const [ready, setReady] = useState23(false);
6594
6920
  const ptyWs = terminalCapability?.transport === "pty-ws" && Boolean(terminalCapability?.url);
6595
- const ptyOutputQueueRef = useRef16([]);
6921
+ const ptyOutputQueueRef = useRef17([]);
6596
6922
  const ptyStream = useTerminalStream({
6597
6923
  capability: ptyWs ? {
6598
6924
  transport: terminalCapability.transport,
@@ -6687,7 +7013,7 @@ function SandboxTerminal({
6687
7013
  if (!ready || !term || !theme) return;
6688
7014
  term.options.theme = theme;
6689
7015
  }, [ready, theme]);
6690
- const enteredPtyRef = useRef16(false);
7016
+ const enteredPtyRef = useRef17(false);
6691
7017
  useEffect16(() => {
6692
7018
  const term = termRef.current;
6693
7019
  if (!ready || !term) return;
@@ -6847,10 +7173,10 @@ import {
6847
7173
  Trash2Icon
6848
7174
  } from "lucide-react";
6849
7175
  import {
6850
- useCallback as useCallback22,
7176
+ useCallback as useCallback23,
6851
7177
  useEffect as useEffect17,
6852
7178
  useMemo as useMemo9,
6853
- useRef as useRef17,
7179
+ useRef as useRef18,
6854
7180
  useState as useState24
6855
7181
  } from "react";
6856
7182
  import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
@@ -6897,9 +7223,9 @@ function FileBrowser({
6897
7223
  const [dragOver, setDragOver] = useState24(null);
6898
7224
  const [menu, setMenu] = useState24(null);
6899
7225
  const [busy, setBusy] = useState24(false);
6900
- const containerRef = useRef17(null);
7226
+ const containerRef = useRef18(null);
6901
7227
  const cursor = active ?? selectedPath ?? null;
6902
- const expand = useCallback22(
7228
+ const expand = useCallback23(
6903
7229
  async (path) => {
6904
7230
  const node = findNode(result.tree, path);
6905
7231
  if (node && node.kind === "dir" && node.children === void 0) {
@@ -6917,14 +7243,14 @@ function FileBrowser({
6917
7243
  },
6918
7244
  [result]
6919
7245
  );
6920
- const open = useCallback22(
7246
+ const open = useCallback23(
6921
7247
  (path) => {
6922
7248
  setExpanded((prev) => new Set(prev).add(path));
6923
7249
  void expand(path);
6924
7250
  },
6925
7251
  [expand]
6926
7252
  );
6927
- const toggle = useCallback22(
7253
+ const toggle = useCallback23(
6928
7254
  async (node) => {
6929
7255
  if (node.kind !== "dir") return;
6930
7256
  const isOpen = expanded.has(node.path);
@@ -6952,7 +7278,7 @@ function FileBrowser({
6952
7278
  return rows;
6953
7279
  }, [result.tree, expanded]);
6954
7280
  const supportsMutation = editable;
6955
- const runDelete = useCallback22(
7281
+ const runDelete = useCallback23(
6956
7282
  async (node) => {
6957
7283
  if (!supportsMutation) return;
6958
7284
  const recursive = node.kind === "dir";
@@ -6971,7 +7297,7 @@ function FileBrowser({
6971
7297
  },
6972
7298
  [supportsMutation, confirmDelete, result]
6973
7299
  );
6974
- const commitCreate = useCallback22(
7300
+ const commitCreate = useCallback23(
6975
7301
  async (name) => {
6976
7302
  const draft = draftCreate;
6977
7303
  setDraftCreate(null);
@@ -6996,7 +7322,7 @@ function FileBrowser({
6996
7322
  },
6997
7323
  [draftCreate, supportsMutation, result, open, onSelectFile]
6998
7324
  );
6999
- const commitRename = useCallback22(
7325
+ const commitRename = useCallback23(
7000
7326
  async (name) => {
7001
7327
  const draft = draftRename;
7002
7328
  setDraftRename(null);
@@ -7019,7 +7345,7 @@ function FileBrowser({
7019
7345
  },
7020
7346
  [draftRename, supportsMutation, result, selectedPath, active, onSelectFile]
7021
7347
  );
7022
- const startCreate = useCallback22(
7348
+ const startCreate = useCallback23(
7023
7349
  (kind) => {
7024
7350
  if (!supportsMutation) return;
7025
7351
  const anchor = cursor ? findNode(result.tree, cursor) : void 0;
@@ -7031,7 +7357,7 @@ function FileBrowser({
7031
7357
  },
7032
7358
  [supportsMutation, cursor, result.tree, open]
7033
7359
  );
7034
- const startRename = useCallback22(
7360
+ const startRename = useCallback23(
7035
7361
  (node) => {
7036
7362
  if (!supportsMutation) return;
7037
7363
  setDraftCreate(null);
@@ -7040,7 +7366,7 @@ function FileBrowser({
7040
7366
  },
7041
7367
  [supportsMutation]
7042
7368
  );
7043
- const onDropOnto = useCallback22(
7369
+ const onDropOnto = useCallback23(
7044
7370
  async (targetDir, sourcePath) => {
7045
7371
  setDragOver(null);
7046
7372
  if (!supportsMutation || !sourcePath) return;
@@ -7064,7 +7390,7 @@ function FileBrowser({
7064
7390
  },
7065
7391
  [supportsMutation, result, selectedPath, active, onSelectFile]
7066
7392
  );
7067
- const onKeyDown = useCallback22(
7393
+ const onKeyDown = useCallback23(
7068
7394
  (e) => {
7069
7395
  if (draftCreate || draftRename) return;
7070
7396
  if (flatRows.length === 0) return;
@@ -7413,8 +7739,8 @@ function InlineInput({
7413
7739
  onCancel
7414
7740
  }) {
7415
7741
  const [value, setValue] = useState24(initialValue);
7416
- const ref = useRef17(null);
7417
- const doneRef = useRef17(false);
7742
+ const ref = useRef18(null);
7743
+ const doneRef = useRef18(false);
7418
7744
  useEffect17(() => {
7419
7745
  const el = ref.current;
7420
7746
  if (!el) return;
@@ -7597,10 +7923,10 @@ import { Loader2Icon as Loader2Icon2, SaveIcon } from "lucide-react";
7597
7923
  import {
7598
7924
  lazy as lazy3,
7599
7925
  Suspense as Suspense3,
7600
- useCallback as useCallback23,
7926
+ useCallback as useCallback24,
7601
7927
  useEffect as useEffect19,
7602
7928
  useMemo as useMemo10,
7603
- useRef as useRef18,
7929
+ useRef as useRef19,
7604
7930
  useState as useState26
7605
7931
  } from "react";
7606
7932
  import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -7669,7 +7995,7 @@ function CodeEditor({
7669
7995
  const [saveError, setSaveError] = useState26(null);
7670
7996
  const [savedTick, setSavedTick] = useState26(false);
7671
7997
  const dirty = value !== baseline;
7672
- const lastSeed = useRef18({ path, contents: initialContents });
7998
+ const lastSeed = useRef19({ path, contents: initialContents });
7673
7999
  useEffect19(() => {
7674
8000
  const seedChanged = lastSeed.current.path !== path || lastSeed.current.contents !== initialContents;
7675
8001
  if (!seedChanged) return;
@@ -7712,9 +8038,9 @@ function CodeEditor({
7712
8038
  cancelled = true;
7713
8039
  };
7714
8040
  }, [langKey]);
7715
- const saveRef = useRef18(() => {
8041
+ const saveRef = useRef19(() => {
7716
8042
  });
7717
- const save = useCallback23(async () => {
8043
+ const save = useCallback24(async () => {
7718
8044
  if (readOnly) return;
7719
8045
  const snapshot = value;
7720
8046
  if (snapshot === baseline) return;
@@ -7858,7 +8184,7 @@ function EditorSkeleton() {
7858
8184
 
7859
8185
  // src/components/sandbox-files.tsx
7860
8186
  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";
8187
+ import { useCallback as useCallback25, useEffect as useEffect20, useMemo as useMemo11, useRef as useRef20, useState as useState27 } from "react";
7862
8188
  import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
7863
8189
  var STATUS_TINT2 = {
7864
8190
  added: "text-og-status-idle",
@@ -7896,7 +8222,7 @@ function SandboxFiles({
7896
8222
  const [staged, setStaged] = useState27(false);
7897
8223
  const [layout, setLayout] = useState27("unified");
7898
8224
  const [editMode, setEditMode] = useState27(false);
7899
- const rootRef = useRef19(null);
8225
+ const rootRef = useRef20(null);
7900
8226
  const [wide, setWide] = useState27(false);
7901
8227
  useEffect20(() => {
7902
8228
  const el = rootRef.current;
@@ -7916,7 +8242,7 @@ function SandboxFiles({
7916
8242
  const selectedDiff = changed.find((f) => f.path === effectiveSelected) ?? null;
7917
8243
  const viewPath = effectiveSelected && !selectedDiff ? effectiveSelected : null;
7918
8244
  const fileView = useFileView(viewPath, files.readFile);
7919
- const selectFile = useCallback24((path) => {
8245
+ const selectFile = useCallback25((path) => {
7920
8246
  setSelected(path);
7921
8247
  setEditMode(false);
7922
8248
  }, []);
@@ -8229,7 +8555,7 @@ function Notice({ children, className }) {
8229
8555
 
8230
8556
  // src/components/desktop-viewer.tsx
8231
8557
  import { LoaderCircleIcon as LoaderCircleIcon2, MonitorIcon, MousePointerClickIcon, WifiOffIcon } from "lucide-react";
8232
- import { useEffect as useEffect21, useRef as useRef20, useState as useState28 } from "react";
8558
+ import { useEffect as useEffect21, useRef as useRef21, useState as useState28 } from "react";
8233
8559
  import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
8234
8560
  var DESKTOP_MEDIA_BACKGROUND = "#000";
8235
8561
  function isHardUnavailable(reason) {
@@ -8262,7 +8588,7 @@ function DesktopViewer({
8262
8588
  connectTimeoutMs = 13e3,
8263
8589
  className
8264
8590
  }) {
8265
- const containerRef = useRef20(null);
8591
+ const containerRef = useRef21(null);
8266
8592
  const [consented, setConsented] = useState28(false);
8267
8593
  const [takeControl, setTakeControl] = useState28(interactive ?? false);
8268
8594
  const externallyControlled = interactive !== void 0;
@@ -8304,9 +8630,9 @@ function DesktopViewer({
8304
8630
  });
8305
8631
  const connected = stream.state === "connected";
8306
8632
  const hasLiveUrl = Boolean(connectCapability?.url);
8307
- const streamStateRef = useRef20(stream.state);
8633
+ const streamStateRef = useRef21(stream.state);
8308
8634
  streamStateRef.current = stream.state;
8309
- const warmKeyRef = useRef20(null);
8635
+ const warmKeyRef = useRef21(null);
8310
8636
  useEffect21(() => {
8311
8637
  if (!isWatching || !coldWarmable || needsAck || viewerCapReached) {
8312
8638
  if (!coldWarmable) warmKeyRef.current = null;
@@ -8599,7 +8925,7 @@ function defaultNotice(title, body, onRetry) {
8599
8925
  }
8600
8926
 
8601
8927
  // src/components/workspace-dock.tsx
8602
- import { useCallback as useCallback25, useEffect as useEffect22, useLayoutEffect, useState as useState29 } from "react";
8928
+ import { useCallback as useCallback26, useEffect as useEffect22, useLayoutEffect as useLayoutEffect2, useState as useState29 } from "react";
8603
8929
  import {
8604
8930
  ChevronsLeftRightIcon,
8605
8931
  Maximize2Icon,
@@ -8615,7 +8941,7 @@ import {
8615
8941
  usePanelRef
8616
8942
  } from "react-resizable-panels";
8617
8943
  import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
8618
- var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 : useLayoutEffect;
8944
+ var useDockLayoutEffect = typeof window === "undefined" ? useEffect22 : useLayoutEffect2;
8619
8945
  var DOCK_OVERLAY_BREAKPOINT = 1024;
8620
8946
  function useIsNarrow(maxWidth) {
8621
8947
  const [narrow, setNarrow] = useState29(false);
@@ -8663,14 +8989,14 @@ function WorkspaceDock({
8663
8989
  const current = activeTab ?? internalTab;
8664
8990
  const tabIds = tabs.map((tab) => tab.id).join("\0");
8665
8991
  const firstTabId = tabs[0]?.id ?? "";
8666
- const setTab = useCallback25(
8992
+ const setTab = useCallback26(
8667
8993
  (id) => {
8668
8994
  setInternalTab(id);
8669
8995
  onActiveTabChange?.(id);
8670
8996
  },
8671
8997
  [onActiveTabChange]
8672
8998
  );
8673
- const setCollapsed = useCallback25(
8999
+ const setCollapsed = useCallback26(
8674
9000
  (next) => {
8675
9001
  setInternalCollapsed((previous) => previous === next ? previous : next);
8676
9002
  onCollapsedChange?.(next);
@@ -8693,11 +9019,11 @@ function WorkspaceDock({
8693
9019
  setTab(firstTabId);
8694
9020
  }
8695
9021
  }, [tabIds, firstTabId, current, setTab]);
8696
- const collapse = useCallback25(() => {
9022
+ const collapse = useCallback26(() => {
8697
9023
  dockPanelRef.current?.collapse();
8698
9024
  setCollapsed(true);
8699
9025
  }, [dockPanelRef, setCollapsed]);
8700
- const expand = useCallback25(() => {
9026
+ const expand = useCallback26(() => {
8701
9027
  dockPanelRef.current?.expand();
8702
9028
  setCollapsed(false);
8703
9029
  }, [dockPanelRef, setCollapsed]);
@@ -8866,7 +9192,7 @@ function DockChrome({
8866
9192
  }
8867
9193
 
8868
9194
  // src/hooks/use-codex-accounts.ts
8869
- import { useCallback as useCallback26, useState as useState30 } from "react";
9195
+ import { useCallback as useCallback27, useState as useState30 } from "react";
8870
9196
  function isCodexAccountEvent(event) {
8871
9197
  return event.type === "codex.account.switched" || event.type === "turn.started";
8872
9198
  }
@@ -8883,7 +9209,7 @@ function useCodexAccounts(options = {}) {
8883
9209
  const codexClient = options.codexClient ?? client;
8884
9210
  const sessionId = options.sessionId;
8885
9211
  const sharedEvents = options.events;
8886
- const load = useCallback26(async () => {
9212
+ const load = useCallback27(async () => {
8887
9213
  const accountsP = codexClient.listCodexAccounts(workspaceId);
8888
9214
  const sessionP = sessionId && codexClient.getSession ? codexClient.getSession(workspaceId, sessionId).catch(() => null) : Promise.resolve(null);
8889
9215
  const [acc, session] = await Promise.all([accountsP, sessionP]);
@@ -8907,7 +9233,7 @@ function useCodexAccounts(options = {}) {
8907
9233
  () => void state.refresh(),
8908
9234
  { enabled: options.enabled ?? true, ...sharedEvents !== void 0 ? { events: sharedEvents } : {} }
8909
9235
  );
8910
- const pin = useCallback26(
9236
+ const pin = useCallback27(
8911
9237
  async (target) => {
8912
9238
  if (!sessionId || !codexClient.pinSessionCodexAccount) {
8913
9239
  return false;
@@ -8923,7 +9249,7 @@ function useCodexAccounts(options = {}) {
8923
9249
  },
8924
9250
  [codexClient, workspaceId, sessionId, mutation.run, state.refresh]
8925
9251
  );
8926
- const refreshUsage = useCallback26(
9252
+ const refreshUsage = useCallback27(
8927
9253
  async () => {
8928
9254
  if (!codexClient.refreshCodexUsage) {
8929
9255
  return false;