@uniqueli/openwork 0.2.0 → 0.2.2

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.
@@ -12755,6 +12755,12 @@ const Key = createLucideIcon("Key", [
12755
12755
  ["path", { d: "m21 2-9.6 9.6", key: "1j0ho8" }],
12756
12756
  ["circle", { cx: "7.5", cy: "15.5", r: "5.5", key: "yqb3hr" }]
12757
12757
  ]);
12758
+ const LayoutGrid = createLucideIcon("LayoutGrid", [
12759
+ ["rect", { width: "7", height: "7", x: "3", y: "3", rx: "1", key: "1g98yp" }],
12760
+ ["rect", { width: "7", height: "7", x: "14", y: "3", rx: "1", key: "6d4xhi" }],
12761
+ ["rect", { width: "7", height: "7", x: "14", y: "14", rx: "1", key: "nxv5o0" }],
12762
+ ["rect", { width: "7", height: "7", x: "3", y: "14", rx: "1", key: "1bb6yr" }]
12763
+ ]);
12758
12764
  const ListTodo = createLucideIcon("ListTodo", [
12759
12765
  ["rect", { x: "3", y: "5", width: "6", height: "6", rx: "1", key: "1defrl" }],
12760
12766
  ["path", { d: "m3 17 2 2 4-4", key: "1jhpwq" }],
@@ -15579,14 +15585,7 @@ const buttonVariants = cva(
15579
15585
  const Button = reactExports.forwardRef(
15580
15586
  ({ className, variant, size: size2, asChild = false, ...props }, ref) => {
15581
15587
  const Comp = asChild ? Slot$3 : "button";
15582
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
15583
- Comp,
15584
- {
15585
- className: cn(buttonVariants({ variant, size: size2, className })),
15586
- ref,
15587
- ...props
15588
- }
15589
- );
15588
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(Comp, { className: cn(buttonVariants({ variant, size: size2, className })), ref, ...props });
15590
15589
  }
15591
15590
  );
15592
15591
  Button.displayName = "Button";
@@ -16711,6 +16710,8 @@ const useAppStore = create$1((set, get) => ({
16711
16710
  rightPanelTab: "todos",
16712
16711
  settingsOpen: false,
16713
16712
  sidebarCollapsed: false,
16713
+ showKanbanView: false,
16714
+ showSubagentsInKanban: true,
16714
16715
  // Thread actions
16715
16716
  loadThreads: async () => {
16716
16717
  const threads = await window.api.threads.list();
@@ -16723,12 +16724,13 @@ const useAppStore = create$1((set, get) => ({
16723
16724
  const thread = await window.api.threads.create(metadata);
16724
16725
  set((state) => ({
16725
16726
  threads: [thread, ...state.threads],
16726
- currentThreadId: thread.thread_id
16727
+ currentThreadId: thread.thread_id,
16728
+ showKanbanView: false
16727
16729
  }));
16728
16730
  return thread;
16729
16731
  },
16730
16732
  selectThread: async (threadId) => {
16731
- set({ currentThreadId: threadId });
16733
+ set({ currentThreadId: threadId, showKanbanView: false });
16732
16734
  },
16733
16735
  deleteThread: async (threadId) => {
16734
16736
  console.log("[Store] Deleting thread:", threadId);
@@ -16803,6 +16805,17 @@ const useAppStore = create$1((set, get) => ({
16803
16805
  },
16804
16806
  setSidebarCollapsed: (collapsed) => {
16805
16807
  set({ sidebarCollapsed: collapsed });
16808
+ },
16809
+ // Kanban actions
16810
+ setShowKanbanView: (show) => {
16811
+ if (show) {
16812
+ set({ showKanbanView: true, currentThreadId: null });
16813
+ } else {
16814
+ set({ showKanbanView: false });
16815
+ }
16816
+ },
16817
+ setShowSubagentsInKanban: (show) => {
16818
+ set({ showSubagentsInKanban: show });
16806
16819
  }
16807
16820
  }));
16808
16821
  const CR = "\r".charCodeAt(0);
@@ -44595,6 +44608,7 @@ class ElectronIPCTransport {
44595
44608
  this.accumulatedToolCalls.clear();
44596
44609
  this.completedToolCallsByName.clear();
44597
44610
  const threadId = payload.config?.configurable?.thread_id;
44611
+ const modelId = payload.config?.configurable?.model_id;
44598
44612
  if (!threadId) {
44599
44613
  return this.createErrorGenerator("MISSING_THREAD_ID", "Thread ID is required");
44600
44614
  }
@@ -44606,7 +44620,13 @@ class ElectronIPCTransport {
44606
44620
  if (!messageContent && !hasResumeCommand) {
44607
44621
  return this.createErrorGenerator("MISSING_MESSAGE", "Message content is required");
44608
44622
  }
44609
- return this.createStreamGenerator(threadId, messageContent, payload.command, payload.signal);
44623
+ return this.createStreamGenerator(
44624
+ threadId,
44625
+ messageContent,
44626
+ payload.command,
44627
+ payload.signal,
44628
+ modelId
44629
+ );
44610
44630
  }
44611
44631
  async *createErrorGenerator(code2, message) {
44612
44632
  yield {
@@ -44614,7 +44634,7 @@ class ElectronIPCTransport {
44614
44634
  data: { error: code2, message }
44615
44635
  };
44616
44636
  }
44617
- async *createStreamGenerator(threadId, message, command, signal) {
44637
+ async *createStreamGenerator(threadId, message, command, signal, modelId) {
44618
44638
  const eventQueue = [];
44619
44639
  let resolveNext = null;
44620
44640
  let isDone = false;
@@ -44627,22 +44647,28 @@ class ElectronIPCTransport {
44627
44647
  thread_id: threadId
44628
44648
  }
44629
44649
  };
44630
- const cleanup = window.api.agent.streamAgent(threadId, message, command, (ipcEvent) => {
44631
- const sdkEvents = this.convertToSDKEvents(ipcEvent, threadId);
44632
- for (const sdkEvent of sdkEvents) {
44633
- if (sdkEvent.event === "done" || sdkEvent.event === "error") {
44634
- isDone = true;
44635
- hasError = sdkEvent.event === "error";
44636
- }
44637
- if (resolveNext) {
44638
- const resolve = resolveNext;
44639
- resolveNext = null;
44640
- resolve(sdkEvent);
44641
- } else {
44642
- eventQueue.push(sdkEvent);
44650
+ const cleanup = window.api.agent.streamAgent(
44651
+ threadId,
44652
+ message,
44653
+ command,
44654
+ (ipcEvent) => {
44655
+ const sdkEvents = this.convertToSDKEvents(ipcEvent, threadId);
44656
+ for (const sdkEvent of sdkEvents) {
44657
+ if (sdkEvent.event === "done" || sdkEvent.event === "error") {
44658
+ isDone = true;
44659
+ hasError = sdkEvent.event === "error";
44660
+ }
44661
+ if (resolveNext) {
44662
+ const resolve = resolveNext;
44663
+ resolveNext = null;
44664
+ resolve(sdkEvent);
44665
+ } else {
44666
+ eventQueue.push(sdkEvent);
44667
+ }
44643
44668
  }
44644
- }
44645
- });
44669
+ },
44670
+ modelId
44671
+ );
44646
44672
  if (signal) {
44647
44673
  signal.addEventListener("abort", () => {
44648
44674
  cleanup();
@@ -45156,7 +45182,8 @@ const createDefaultThreadState = () => ({
45156
45182
  openFiles: [],
45157
45183
  activeTab: "agent",
45158
45184
  fileContents: {},
45159
- tokenUsage: null
45185
+ tokenUsage: null,
45186
+ draftInput: ""
45160
45187
  });
45161
45188
  const defaultStreamData = {
45162
45189
  messages: [],
@@ -45221,6 +45248,7 @@ function ThreadStreamHolder({
45221
45248
  function ThreadProvider({ children }) {
45222
45249
  const [threadStates, setThreadStates] = reactExports.useState({});
45223
45250
  const [activeThreadIds, setActiveThreadIds] = reactExports.useState(/* @__PURE__ */ new Set());
45251
+ const [loadingStates, setLoadingStates] = reactExports.useState({});
45224
45252
  const initializedThreadsRef = reactExports.useRef(/* @__PURE__ */ new Set());
45225
45253
  const actionsCache = reactExports.useRef({});
45226
45254
  const streamDataRef = reactExports.useRef({});
@@ -45235,6 +45263,10 @@ function ThreadProvider({ children }) {
45235
45263
  (threadId, data) => {
45236
45264
  streamDataRef.current[threadId] = data;
45237
45265
  notifyStreamSubscribers(threadId);
45266
+ setLoadingStates((prev) => {
45267
+ if (prev[threadId] === data.isLoading) return prev;
45268
+ return { ...prev, [threadId]: data.isLoading };
45269
+ });
45238
45270
  },
45239
45271
  [notifyStreamSubscribers]
45240
45272
  );
@@ -45254,12 +45286,26 @@ function ThreadProvider({ children }) {
45254
45286
  (threadId) => {
45255
45287
  const state = threadStates[threadId] || createDefaultThreadState();
45256
45288
  if (state.pendingApproval) {
45257
- console.log("[ThreadContext] getThreadState returning pendingApproval for:", threadId, state.pendingApproval);
45289
+ console.log(
45290
+ "[ThreadContext] getThreadState returning pendingApproval for:",
45291
+ threadId,
45292
+ state.pendingApproval
45293
+ );
45258
45294
  }
45259
45295
  return state;
45260
45296
  },
45261
45297
  [threadStates]
45262
45298
  );
45299
+ const getAllThreadStates = reactExports.useCallback(() => {
45300
+ return threadStates;
45301
+ }, [threadStates]);
45302
+ const getAllStreamLoadingStates = reactExports.useCallback(() => {
45303
+ return loadingStates;
45304
+ }, [loadingStates]);
45305
+ const subscribeToAllStreams = reactExports.useCallback(() => {
45306
+ return () => {
45307
+ };
45308
+ }, []);
45263
45309
  const updateThreadState = reactExports.useCallback(
45264
45310
  (threadId, updater) => {
45265
45311
  setThreadStates((prev) => {
@@ -45275,7 +45321,9 @@ function ThreadProvider({ children }) {
45275
45321
  );
45276
45322
  const parseErrorMessage = reactExports.useCallback((error) => {
45277
45323
  const errorMessage = typeof error === "string" ? error : error.message;
45278
- const contextWindowMatch = errorMessage.match(/prompt is too long: (\d+) tokens > (\d+) maximum/i);
45324
+ const contextWindowMatch = errorMessage.match(
45325
+ /prompt is too long: (\d+) tokens > (\d+) maximum/i
45326
+ );
45279
45327
  if (contextWindowMatch) {
45280
45328
  const [, usedTokens, maxTokens] = contextWindowMatch;
45281
45329
  const usedK = Math.round(parseInt(usedTokens) / 1e3);
@@ -45304,7 +45352,11 @@ function ThreadProvider({ children }) {
45304
45352
  switch (data.type) {
45305
45353
  case "interrupt":
45306
45354
  if (data.request) {
45307
- console.log("[ThreadContext] Setting pendingApproval for thread:", threadId, data.request);
45355
+ console.log(
45356
+ "[ThreadContext] Setting pendingApproval for thread:",
45357
+ threadId,
45358
+ data.request
45359
+ );
45308
45360
  updateThreadState(threadId, () => ({ pendingApproval: data.request }));
45309
45361
  }
45310
45362
  break;
@@ -45431,7 +45483,8 @@ function ThreadProvider({ children }) {
45431
45483
  closeFile: (path2) => {
45432
45484
  updateThreadState(threadId, (state) => {
45433
45485
  const newOpenFiles = state.openFiles.filter((f2) => f2.path !== path2);
45434
- const { [path2]: _2, ...newFileContents } = state.fileContents;
45486
+ const newFileContents = { ...state.fileContents };
45487
+ delete newFileContents[path2];
45435
45488
  let newActiveTab = state.activeTab;
45436
45489
  if (state.activeTab === path2) {
45437
45490
  const closedIndex = state.openFiles.findIndex((f2) => f2.path === path2);
@@ -45439,7 +45492,11 @@ function ThreadProvider({ children }) {
45439
45492
  else if (closedIndex > 0) newActiveTab = newOpenFiles[closedIndex - 1].path;
45440
45493
  else newActiveTab = newOpenFiles[0].path;
45441
45494
  }
45442
- return { openFiles: newOpenFiles, activeTab: newActiveTab, fileContents: newFileContents };
45495
+ return {
45496
+ openFiles: newOpenFiles,
45497
+ activeTab: newActiveTab,
45498
+ fileContents: newFileContents
45499
+ };
45443
45500
  });
45444
45501
  },
45445
45502
  setActiveTab: (tab2) => {
@@ -45449,6 +45506,9 @@ function ThreadProvider({ children }) {
45449
45506
  updateThreadState(threadId, (state) => ({
45450
45507
  fileContents: { ...state.fileContents, [path2]: content2 }
45451
45508
  }));
45509
+ },
45510
+ setDraftInput: (input) => {
45511
+ updateThreadState(threadId, () => ({ draftInput: input }));
45452
45512
  }
45453
45513
  };
45454
45514
  actionsCache.current[threadId] = actions;
@@ -45466,21 +45526,16 @@ function ThreadProvider({ children }) {
45466
45526
  if (metadata.currentModel) {
45467
45527
  actions.setCurrentModel(metadata.currentModel);
45468
45528
  }
45469
- }
45470
- } catch (error) {
45471
- console.error("[ThreadContext] Failed to load thread metadata:", error);
45472
- }
45473
- try {
45474
- const path2 = await window.api.workspace.get(threadId);
45475
- if (path2) {
45476
- actions.setWorkspacePath(path2);
45477
- const diskResult = await window.api.workspace.loadFromDisk(threadId);
45478
- if (diskResult.success) {
45479
- actions.setWorkspaceFiles(diskResult.files);
45529
+ if (metadata.workspacePath) {
45530
+ actions.setWorkspacePath(metadata.workspacePath);
45531
+ const diskResult = await window.api.workspace.loadFromDisk(threadId);
45532
+ if (diskResult.success) {
45533
+ actions.setWorkspaceFiles(diskResult.files);
45534
+ }
45480
45535
  }
45481
45536
  }
45482
45537
  } catch (error) {
45483
- console.error("[ThreadContext] Failed to load workspace path:", error);
45538
+ console.error("[ThreadContext] Failed to load thread metadata:", error);
45484
45539
  }
45485
45540
  try {
45486
45541
  const history = await window.api.threads.getHistory(threadId);
@@ -45561,7 +45616,7 @@ function ThreadProvider({ children }) {
45561
45616
  console.error("[ThreadContext] Failed to load thread history:", error);
45562
45617
  }
45563
45618
  },
45564
- [getThreadActions]
45619
+ [getThreadActions, updateThreadState]
45565
45620
  );
45566
45621
  const initializeThread = reactExports.useCallback(
45567
45622
  (threadId) => {
@@ -45587,7 +45642,7 @@ function ThreadProvider({ children }) {
45587
45642
  return next;
45588
45643
  });
45589
45644
  setThreadStates((prev) => {
45590
- const { [threadId]: _2, ...rest } = prev;
45645
+ const { [threadId]: _removed, ...rest } = prev;
45591
45646
  return rest;
45592
45647
  });
45593
45648
  }, []);
@@ -45598,9 +45653,22 @@ function ThreadProvider({ children }) {
45598
45653
  initializeThread,
45599
45654
  cleanupThread,
45600
45655
  subscribeToStream,
45601
- getStreamData
45656
+ getStreamData,
45657
+ getAllThreadStates,
45658
+ getAllStreamLoadingStates,
45659
+ subscribeToAllStreams
45602
45660
  }),
45603
- [getThreadState, getThreadActions, initializeThread, cleanupThread, subscribeToStream, getStreamData]
45661
+ [
45662
+ getThreadState,
45663
+ getThreadActions,
45664
+ initializeThread,
45665
+ cleanupThread,
45666
+ subscribeToStream,
45667
+ getStreamData,
45668
+ getAllThreadStates,
45669
+ getAllStreamLoadingStates,
45670
+ subscribeToAllStreams
45671
+ ]
45604
45672
  );
45605
45673
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(ThreadContext.Provider, { value: contextValue, children: [
45606
45674
  Array.from(activeThreadIds).map((threadId) => /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -45649,6 +45717,14 @@ function useThreadState(threadId) {
45649
45717
  const actions = context.getThreadActions(threadId);
45650
45718
  return { ...state, ...actions };
45651
45719
  }
45720
+ function useAllThreadStates() {
45721
+ const context = useThreadContext();
45722
+ return context.getAllThreadStates();
45723
+ }
45724
+ function useAllStreamLoadingStates() {
45725
+ const context = useThreadContext();
45726
+ return context.getAllStreamLoadingStates();
45727
+ }
45652
45728
  // @__NO_SIDE_EFFECTS__
45653
45729
  function createSlot$3(ownerName) {
45654
45730
  const SlotClone = /* @__PURE__ */ createSlotClone$3(ownerName);
@@ -50610,9 +50686,7 @@ var Portal2 = ContextMenuPortal;
50610
50686
  var Content2$1 = ContextMenuContent$1;
50611
50687
  var Item2 = ContextMenuItem$1;
50612
50688
  var Separator2 = ContextMenuSeparator$1;
50613
- function ContextMenu({
50614
- ...props
50615
- }) {
50689
+ function ContextMenu({ ...props }) {
50616
50690
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Root2$1, { "data-slot": "context-menu", ...props });
50617
50691
  }
50618
50692
  function ContextMenuTrigger({
@@ -50669,11 +50743,15 @@ function ContextMenuSeparator({
50669
50743
  }
50670
50744
  );
50671
50745
  }
50672
- function ThreadLoadingIcon({ threadId }) {
50746
+ function ThreadStatusIcon$1({ threadId }) {
50673
50747
  const { isLoading } = useThreadStream(threadId);
50748
+ const { pendingApproval } = useCurrentThread(threadId);
50674
50749
  if (isLoading) {
50675
50750
  return /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 shrink-0 text-status-info animate-spin" });
50676
50751
  }
50752
+ if (pendingApproval) {
50753
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "size-4 shrink-0 text-status-warning" });
50754
+ }
50677
50755
  return /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-4 shrink-0 text-muted-foreground" });
50678
50756
  }
50679
50757
  function ThreadListItem({
@@ -50702,7 +50780,7 @@ function ThreadListItem({
50702
50780
  }
50703
50781
  },
50704
50782
  children: [
50705
- /* @__PURE__ */ jsxRuntimeExports.jsx(ThreadLoadingIcon, { threadId: thread.thread_id }),
50783
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ThreadStatusIcon$1, { threadId: thread.thread_id }),
50706
50784
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0 overflow-hidden", children: isEditing ? /* @__PURE__ */ jsxRuntimeExports.jsx(
50707
50785
  "input",
50708
50786
  {
@@ -50744,17 +50822,10 @@ function ThreadListItem({
50744
50822
  "Rename"
50745
50823
  ] }),
50746
50824
  /* @__PURE__ */ jsxRuntimeExports.jsx(ContextMenuSeparator, {}),
50747
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
50748
- ContextMenuItem,
50749
- {
50750
- variant: "destructive",
50751
- onClick: onDelete,
50752
- children: [
50753
- /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-4 mr-2" }),
50754
- "Delete"
50755
- ]
50756
- }
50757
- )
50825
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenuItem, { variant: "destructive", onClick: onDelete, children: [
50826
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-4 mr-2" }),
50827
+ "Delete"
50828
+ ] })
50758
50829
  ] })
50759
50830
  ] });
50760
50831
  }
@@ -50765,7 +50836,8 @@ function ThreadSidebar() {
50765
50836
  createThread,
50766
50837
  selectThread,
50767
50838
  deleteThread,
50768
- updateThread
50839
+ updateThread,
50840
+ setShowKanbanView
50769
50841
  } = useAppStore();
50770
50842
  const [editingThreadId, setEditingThreadId] = reactExports.useState(null);
50771
50843
  const [editingTitle, setEditingTitle] = reactExports.useState("");
@@ -50788,10 +50860,19 @@ function ThreadSidebar() {
50788
50860
  await createThread({ title: `Thread ${(/* @__PURE__ */ new Date()).toLocaleDateString()}` });
50789
50861
  };
50790
50862
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: "flex h-full w-full flex-col border-r border-border bg-sidebar overflow-hidden", children: [
50791
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2", style: { paddingTop: "calc(8px + var(--sidebar-safe-padding, 0px))" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { variant: "ghost", size: "sm", className: "w-full justify-start gap-2", onClick: handleNewThread, children: [
50792
- /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-4" }),
50793
- "New Thread"
50794
- ] }) }),
50863
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2", style: { paddingTop: "calc(8px + var(--sidebar-safe-padding, 0px))" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
50864
+ Button,
50865
+ {
50866
+ variant: "ghost",
50867
+ size: "sm",
50868
+ className: "w-full justify-start gap-2",
50869
+ onClick: handleNewThread,
50870
+ children: [
50871
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-4" }),
50872
+ "New Thread"
50873
+ ]
50874
+ }
50875
+ ) }),
50795
50876
  /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2 space-y-1 overflow-hidden", children: [
50796
50877
  threads.map((thread) => /* @__PURE__ */ jsxRuntimeExports.jsx(
50797
50878
  ThreadListItem,
@@ -50810,10 +50891,26 @@ function ThreadSidebar() {
50810
50891
  thread.thread_id
50811
50892
  )),
50812
50893
  threads.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-8 text-center text-sm text-muted-foreground", children: "No threads yet" })
50813
- ] }) })
50894
+ ] }) }),
50895
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 border-t border-border", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
50896
+ Button,
50897
+ {
50898
+ variant: "ghost",
50899
+ size: "sm",
50900
+ className: "w-full justify-start gap-2",
50901
+ onClick: () => setShowKanbanView(true),
50902
+ children: [
50903
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LayoutGrid, { className: "size-4" }),
50904
+ "Overview"
50905
+ ]
50906
+ }
50907
+ ) })
50814
50908
  ] });
50815
50909
  }
50816
- function TabBar({ className, threadId: propThreadId }) {
50910
+ function TabBar({
50911
+ className,
50912
+ threadId: propThreadId
50913
+ }) {
50817
50914
  const { currentThreadId } = useAppStore();
50818
50915
  const threadId = propThreadId ?? currentThreadId;
50819
50916
  const threadState = useThreadState(threadId);
@@ -50821,36 +50918,42 @@ function TabBar({ className, threadId: propThreadId }) {
50821
50918
  return null;
50822
50919
  }
50823
50920
  const { openFiles, activeTab, setActiveTab, closeFile } = threadState;
50824
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(
50825
- "flex items-center h-9 border-b border-border bg-sidebar overflow-x-auto scrollbar-hide",
50826
- className
50827
- ), children: [
50828
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
50829
- "button",
50830
- {
50831
- onClick: () => setActiveTab("agent"),
50832
- className: cn(
50833
- "flex items-center gap-2 px-4 h-full text-sm font-medium transition-colors shrink-0 border-r border-border",
50834
- activeTab === "agent" ? "bg-primary/15 text-primary border-b-2 border-b-primary" : "text-muted-foreground hover:text-foreground hover:bg-background-interactive"
50921
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
50922
+ "div",
50923
+ {
50924
+ className: cn(
50925
+ "flex items-center h-9 border-b border-border bg-sidebar overflow-x-auto scrollbar-hide",
50926
+ className
50927
+ ),
50928
+ children: [
50929
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
50930
+ "button",
50931
+ {
50932
+ onClick: () => setActiveTab("agent"),
50933
+ className: cn(
50934
+ "flex items-center gap-2 px-4 h-full text-sm font-medium transition-colors shrink-0 border-r border-border",
50935
+ activeTab === "agent" ? "bg-primary/15 text-primary border-b-2 border-b-primary" : "text-muted-foreground hover:text-foreground hover:bg-background-interactive"
50936
+ ),
50937
+ children: [
50938
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Bot, { className: "size-4" }),
50939
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Agent" })
50940
+ ]
50941
+ }
50835
50942
  ),
50836
- children: [
50837
- /* @__PURE__ */ jsxRuntimeExports.jsx(Bot, { className: "size-4" }),
50838
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Agent" })
50839
- ]
50840
- }
50841
- ),
50842
- openFiles.map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
50843
- FileTab,
50844
- {
50845
- file,
50846
- isActive: activeTab === file.path,
50847
- onSelect: () => setActiveTab(file.path),
50848
- onClose: () => closeFile(file.path)
50849
- },
50850
- file.path
50851
- )),
50852
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0" })
50853
- ] });
50943
+ openFiles.map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
50944
+ FileTab,
50945
+ {
50946
+ file,
50947
+ isActive: activeTab === file.path,
50948
+ onSelect: () => setActiveTab(file.path),
50949
+ onClose: () => closeFile(file.path)
50950
+ },
50951
+ file.path
50952
+ )),
50953
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0" })
50954
+ ]
50955
+ }
50956
+ );
50854
50957
  }
50855
50958
  function FileTab({ file, isActive, onSelect, onClose }) {
50856
50959
  const handleClose = (e) => {
@@ -50925,27 +51028,8 @@ const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
50925
51028
  "tiff",
50926
51029
  "tif"
50927
51030
  ]);
50928
- const VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
50929
- "mp4",
50930
- "webm",
50931
- "ogg",
50932
- "ogv",
50933
- "mov",
50934
- "avi",
50935
- "wmv",
50936
- "flv",
50937
- "mkv"
50938
- ]);
50939
- const AUDIO_EXTENSIONS = /* @__PURE__ */ new Set([
50940
- "mp3",
50941
- "wav",
50942
- "ogg",
50943
- "oga",
50944
- "m4a",
50945
- "flac",
50946
- "aac",
50947
- "weba"
50948
- ]);
51031
+ const VIDEO_EXTENSIONS = /* @__PURE__ */ new Set(["mp4", "webm", "ogg", "ogv", "mov", "avi", "wmv", "flv", "mkv"]);
51032
+ const AUDIO_EXTENSIONS = /* @__PURE__ */ new Set(["mp3", "wav", "ogg", "oga", "m4a", "flac", "aac", "weba"]);
50949
51033
  const PDF_EXTENSIONS = /* @__PURE__ */ new Set(["pdf"]);
50950
51034
  const CODE_EXTENSIONS = /* @__PURE__ */ new Set([
50951
51035
  "ts",
@@ -51057,36 +51141,36 @@ function getFileType(fileName) {
51057
51141
  function getMimeType(ext) {
51058
51142
  const mimeTypes = {
51059
51143
  // Images
51060
- "png": "image/png",
51061
- "jpg": "image/jpeg",
51062
- "jpeg": "image/jpeg",
51063
- "gif": "image/gif",
51064
- "svg": "image/svg+xml",
51065
- "webp": "image/webp",
51066
- "bmp": "image/bmp",
51067
- "ico": "image/x-icon",
51068
- "tiff": "image/tiff",
51069
- "tif": "image/tiff",
51144
+ png: "image/png",
51145
+ jpg: "image/jpeg",
51146
+ jpeg: "image/jpeg",
51147
+ gif: "image/gif",
51148
+ svg: "image/svg+xml",
51149
+ webp: "image/webp",
51150
+ bmp: "image/bmp",
51151
+ ico: "image/x-icon",
51152
+ tiff: "image/tiff",
51153
+ tif: "image/tiff",
51070
51154
  // Video
51071
- "mp4": "video/mp4",
51072
- "webm": "video/webm",
51073
- "ogg": "video/ogg",
51074
- "ogv": "video/ogg",
51075
- "mov": "video/quicktime",
51076
- "avi": "video/x-msvideo",
51077
- "wmv": "video/x-ms-wmv",
51078
- "flv": "video/x-flv",
51079
- "mkv": "video/x-matroska",
51155
+ mp4: "video/mp4",
51156
+ webm: "video/webm",
51157
+ ogg: "video/ogg",
51158
+ ogv: "video/ogg",
51159
+ mov: "video/quicktime",
51160
+ avi: "video/x-msvideo",
51161
+ wmv: "video/x-ms-wmv",
51162
+ flv: "video/x-flv",
51163
+ mkv: "video/x-matroska",
51080
51164
  // Audio
51081
- "mp3": "audio/mpeg",
51082
- "wav": "audio/wav",
51083
- "oga": "audio/ogg",
51084
- "m4a": "audio/mp4",
51085
- "flac": "audio/flac",
51086
- "aac": "audio/aac",
51087
- "weba": "audio/webm",
51165
+ mp3: "audio/mpeg",
51166
+ wav: "audio/wav",
51167
+ oga: "audio/ogg",
51168
+ m4a: "audio/mp4",
51169
+ flac: "audio/flac",
51170
+ aac: "audio/aac",
51171
+ weba: "audio/webm",
51088
51172
  // PDF
51089
- "pdf": "application/pdf"
51173
+ pdf: "application/pdf"
51090
51174
  };
51091
51175
  return mimeTypes[ext] || "application/octet-stream";
51092
51176
  }
@@ -61610,25 +61694,25 @@ const SUPPORTED_LANGS = /* @__PURE__ */ new Set([
61610
61694
  ]);
61611
61695
  function getLanguage(ext) {
61612
61696
  const langMap = {
61613
- "ts": "typescript",
61614
- "tsx": "tsx",
61615
- "js": "javascript",
61616
- "jsx": "jsx",
61617
- "mjs": "javascript",
61618
- "cjs": "javascript",
61619
- "py": "python",
61620
- "json": "json",
61621
- "css": "css",
61622
- "html": "html",
61623
- "htm": "html",
61624
- "md": "markdown",
61625
- "mdx": "markdown",
61626
- "yaml": "yaml",
61627
- "yml": "yaml",
61628
- "sh": "bash",
61629
- "bash": "bash",
61630
- "zsh": "bash",
61631
- "sql": "sql"
61697
+ ts: "typescript",
61698
+ tsx: "tsx",
61699
+ js: "javascript",
61700
+ jsx: "jsx",
61701
+ mjs: "javascript",
61702
+ cjs: "javascript",
61703
+ py: "python",
61704
+ json: "json",
61705
+ css: "css",
61706
+ html: "html",
61707
+ htm: "html",
61708
+ md: "markdown",
61709
+ mdx: "markdown",
61710
+ yaml: "yaml",
61711
+ yml: "yaml",
61712
+ sh: "bash",
61713
+ bash: "bash",
61714
+ zsh: "bash",
61715
+ sql: "sql"
61632
61716
  };
61633
61717
  const lang2 = ext ? langMap[ext] : null;
61634
61718
  return lang2 && SUPPORTED_LANGS.has(lang2) ? lang2 : null;
@@ -61678,19 +61762,17 @@ function CodeViewer({ filePath, content: content2 }) {
61678
61762
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground/50", children: "•" }),
61679
61763
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground/70", children: language || "plain text" })
61680
61764
  ] }),
61681
- /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shiki-wrapper", children: highlightedHtml ? /* @__PURE__ */ jsxRuntimeExports.jsx(
61682
- "div",
61683
- {
61684
- className: "shiki-content",
61685
- dangerouslySetInnerHTML: { __html: highlightedHtml }
61686
- }
61687
- ) : (
61765
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shiki-wrapper", children: highlightedHtml ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shiki-content", dangerouslySetInnerHTML: { __html: highlightedHtml } }) : (
61688
61766
  // Fallback plain text rendering
61689
61767
  /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "p-4 text-sm font-mono leading-relaxed whitespace-pre-wrap break-all", children: content2 })
61690
61768
  ) }) })
61691
61769
  ] });
61692
61770
  }
61693
- function ImageViewer({ filePath, base64Content, mimeType }) {
61771
+ function ImageViewer({
61772
+ filePath,
61773
+ base64Content,
61774
+ mimeType
61775
+ }) {
61694
61776
  const [zoom, setZoom] = reactExports.useState(100);
61695
61777
  const [rotation, setRotation] = reactExports.useState(0);
61696
61778
  const [isPanning, setIsPanning] = reactExports.useState(false);
@@ -61700,10 +61782,18 @@ function ImageViewer({ filePath, base64Content, mimeType }) {
61700
61782
  const fileName = filePath.split("/").pop() || filePath;
61701
61783
  const imageUrl = `data:${mimeType};base64,${base64Content}`;
61702
61784
  const handleZoomIn = () => {
61703
- setZoom((prev) => Math.min(prev + 25, 400));
61785
+ const newZoom = Math.min(zoom + 25, 400);
61786
+ setZoom(newZoom);
61787
+ if (newZoom <= 100) {
61788
+ setPanOffset({ x: 0, y: 0 });
61789
+ }
61704
61790
  };
61705
61791
  const handleZoomOut = () => {
61706
- setZoom((prev) => Math.max(prev - 25, 25));
61792
+ const newZoom = Math.max(zoom - 25, 25);
61793
+ setZoom(newZoom);
61794
+ if (newZoom <= 100) {
61795
+ setPanOffset({ x: 0, y: 0 });
61796
+ }
61707
61797
  };
61708
61798
  const handleResetZoom = () => {
61709
61799
  setZoom(100);
@@ -61734,11 +61824,6 @@ function ImageViewer({ filePath, base64Content, mimeType }) {
61734
61824
  const handleMouseLeave = () => {
61735
61825
  setIsPanning(false);
61736
61826
  };
61737
- reactExports.useEffect(() => {
61738
- if (zoom <= 100) {
61739
- setPanOffset({ x: 0, y: 0 });
61740
- }
61741
- }, [zoom]);
61742
61827
  const canPan = zoom > 100;
61743
61828
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 flex-col min-h-0 overflow-hidden", children: [
61744
61829
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2 px-4 py-2 border-b border-border bg-background/50 shrink-0", children: [
@@ -61781,26 +61866,8 @@ function ImageViewer({ filePath, base64Content, mimeType }) {
61781
61866
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomIn, { className: "size-4" })
61782
61867
  }
61783
61868
  ),
61784
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61785
- Button,
61786
- {
61787
- variant: "ghost",
61788
- size: "sm",
61789
- onClick: handleRotate,
61790
- className: "h-7 px-2",
61791
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCw, { className: "size-4" })
61792
- }
61793
- ),
61794
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61795
- Button,
61796
- {
61797
- variant: "ghost",
61798
- size: "sm",
61799
- onClick: handleResetZoom,
61800
- className: "h-7 px-2",
61801
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Maximize2, { className: "size-4" })
61802
- }
61803
- )
61869
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "ghost", size: "sm", onClick: handleRotate, className: "h-7 px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCw, { className: "size-4" }) }),
61870
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "ghost", size: "sm", onClick: handleResetZoom, className: "h-7 px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Maximize2, { className: "size-4" }) })
61804
61871
  ] })
61805
61872
  ] }),
61806
61873
  /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -61833,7 +61900,12 @@ function ImageViewer({ filePath, base64Content, mimeType }) {
61833
61900
  ) })
61834
61901
  ] });
61835
61902
  }
61836
- function MediaViewer({ filePath, base64Content, mimeType, mediaType }) {
61903
+ function MediaViewer({
61904
+ filePath,
61905
+ base64Content,
61906
+ mimeType,
61907
+ mediaType
61908
+ }) {
61837
61909
  const fileName = filePath.split("/").pop() || filePath;
61838
61910
  const mediaUrl = `data:${mimeType};base64,${base64Content}`;
61839
61911
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 flex-col min-h-0 overflow-hidden", children: [
@@ -61864,18 +61936,10 @@ function MediaViewer({ filePath, base64Content, mimeType, mediaType }) {
61864
61936
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-muted-foreground", children: "Audio File" })
61865
61937
  ] })
61866
61938
  ] }),
61867
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
61868
- "audio",
61869
- {
61870
- controls: true,
61871
- className: "w-full max-w-md",
61872
- preload: "metadata",
61873
- children: [
61874
- /* @__PURE__ */ jsxRuntimeExports.jsx("source", { src: mediaUrl, type: mimeType }),
61875
- "Your browser does not support the audio tag."
61876
- ]
61877
- }
61878
- )
61939
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("audio", { controls: true, className: "w-full max-w-md", preload: "metadata", children: [
61940
+ /* @__PURE__ */ jsxRuntimeExports.jsx("source", { src: mediaUrl, type: mimeType }),
61941
+ "Your browser does not support the audio tag."
61942
+ ] })
61879
61943
  ] }) }) })
61880
61944
  ] });
61881
61945
  }
@@ -61895,39 +61959,22 @@ function PDFViewer({ filePath, base64Content }) {
61895
61959
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-muted-foreground/50", children: "•" }),
61896
61960
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "PDF Document" })
61897
61961
  ] }),
61898
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
61899
- Button,
61900
- {
61901
- variant: "ghost",
61902
- size: "sm",
61903
- onClick: handleOpenExternal,
61904
- className: "h-7 px-2 gap-1",
61905
- children: [
61906
- /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3" }),
61907
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Download" })
61908
- ]
61909
- }
61910
- )
61962
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { variant: "ghost", size: "sm", onClick: handleOpenExternal, className: "h-7 px-2 gap-1", children: [
61963
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-3" }),
61964
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Download" })
61965
+ ] })
61911
61966
  ] }),
61912
- /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col items-center min-h-full bg-muted/30", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
61913
- "object",
61914
- {
61915
- data: pdfUrl,
61916
- type: "application/pdf",
61917
- className: "w-full h-full min-h-[600px]",
61918
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center min-h-[600px] gap-4 p-8", children: [
61919
- /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "size-16 text-muted-foreground/50" }),
61920
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center", children: [
61921
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium text-foreground mb-2", children: fileName }),
61922
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-muted-foreground mb-4", children: "PDF preview not available in this browser" }),
61923
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { onClick: handleOpenExternal, variant: "outline", children: [
61924
- /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-4 mr-2" }),
61925
- "Download PDF"
61926
- ] })
61927
- ] })
61967
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col items-center min-h-full bg-muted/30", children: /* @__PURE__ */ jsxRuntimeExports.jsx("object", { data: pdfUrl, type: "application/pdf", className: "w-full h-full min-h-[600px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center min-h-[600px] gap-4 p-8", children: [
61968
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { className: "size-16 text-muted-foreground/50" }),
61969
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center", children: [
61970
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium text-foreground mb-2", children: fileName }),
61971
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-muted-foreground mb-4", children: "PDF preview not available in this browser" }),
61972
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Button, { onClick: handleOpenExternal, variant: "outline", children: [
61973
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "size-4 mr-2" }),
61974
+ "Download PDF"
61928
61975
  ] })
61929
- }
61930
- ) }) })
61976
+ ] })
61977
+ ] }) }) }) })
61931
61978
  ] });
61932
61979
  }
61933
61980
  function BinaryFileViewer({ filePath, size: size2 }) {
@@ -62142,16 +62189,23 @@ function TodosDisplay({ todos }) {
62142
62189
  const config2 = statusConfig[todo.status] || defaultConfig;
62143
62190
  const Icon2 = config2.icon;
62144
62191
  const isDone = todo.status === "completed" || todo.status === "cancelled";
62145
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(
62146
- "flex items-start gap-2 text-xs",
62147
- isDone && "opacity-50"
62148
- ), children: [
62149
- /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { className: cn("size-3.5 mt-0.5 shrink-0", config2.color) }),
62150
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn(isDone && "line-through"), children: todo.content })
62151
- ] }, todo.id || i2);
62192
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
62193
+ "div",
62194
+ {
62195
+ className: cn("flex items-start gap-2 text-xs", isDone && "opacity-50"),
62196
+ children: [
62197
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { className: cn("size-3.5 mt-0.5 shrink-0", config2.color) }),
62198
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn(isDone && "line-through"), children: todo.content })
62199
+ ]
62200
+ },
62201
+ todo.id || i2
62202
+ );
62152
62203
  }) });
62153
62204
  }
62154
- function FileListDisplay({ files, isGlob }) {
62205
+ function FileListDisplay({
62206
+ files,
62207
+ isGlob
62208
+ }) {
62155
62209
  const items = files.slice(0, 15);
62156
62210
  const hasMore = files.length > 15;
62157
62211
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-0.5", children: [
@@ -62170,12 +62224,17 @@ function FileListDisplay({ files, isGlob }) {
62170
62224
  ] })
62171
62225
  ] });
62172
62226
  }
62173
- function GrepResultsDisplay({ matches: matches2 }) {
62174
- const grouped = matches2.reduce((acc, match) => {
62175
- if (!acc[match.path]) acc[match.path] = [];
62176
- acc[match.path].push(match);
62177
- return acc;
62178
- }, {});
62227
+ function GrepResultsDisplay({
62228
+ matches: matches2
62229
+ }) {
62230
+ const grouped = matches2.reduce(
62231
+ (acc, match) => {
62232
+ if (!acc[match.path]) acc[match.path] = [];
62233
+ acc[match.path].push(match);
62234
+ return acc;
62235
+ },
62236
+ {}
62237
+ );
62179
62238
  const files = Object.keys(grouped).slice(0, 5);
62180
62239
  const hasMore = Object.keys(grouped).length > 5;
62181
62240
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
@@ -62252,7 +62311,10 @@ function FileEditSummary({ args }) {
62252
62311
  }
62253
62312
  return null;
62254
62313
  }
62255
- function CommandDisplay({ command, output }) {
62314
+ function CommandDisplay({
62315
+ command,
62316
+ output
62317
+ }) {
62256
62318
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs space-y-2 w-full overflow-hidden", children: [
62257
62319
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-mono bg-background rounded-sm p-2 flex items-center gap-2 min-w-0", children: [
62258
62320
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-status-info shrink-0", children: "$" }),
@@ -62264,7 +62326,10 @@ function CommandDisplay({ command, output }) {
62264
62326
  ] })
62265
62327
  ] });
62266
62328
  }
62267
- function TaskDisplay({ args, isExpanded }) {
62329
+ function TaskDisplay({
62330
+ args,
62331
+ isExpanded
62332
+ }) {
62268
62333
  const name2 = args.name;
62269
62334
  const description = args.description;
62270
62335
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs space-y-1", children: [
@@ -62272,13 +62337,16 @@ function TaskDisplay({ args, isExpanded }) {
62272
62337
  /* @__PURE__ */ jsxRuntimeExports.jsx(GitBranch, { className: "size-3 text-status-info" }),
62273
62338
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium truncate", children: name2 })
62274
62339
  ] }),
62275
- description && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: cn(
62276
- "text-muted-foreground pl-5",
62277
- !isExpanded && "line-clamp-2"
62278
- ), children: description })
62340
+ description && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: cn("text-muted-foreground pl-5", !isExpanded && "line-clamp-2"), children: description })
62279
62341
  ] });
62280
62342
  }
62281
- function ToolCallRenderer({ toolCall, result, isError: isError2, needsApproval, onApprovalDecision }) {
62343
+ function ToolCallRenderer({
62344
+ toolCall,
62345
+ result,
62346
+ isError: isError2,
62347
+ needsApproval,
62348
+ onApprovalDecision
62349
+ }) {
62282
62350
  const args = toolCall?.args || {};
62283
62351
  const [isExpanded, setIsExpanded] = reactExports.useState(false);
62284
62352
  if (!toolCall) {
@@ -62358,7 +62426,9 @@ function ToolCallRenderer({ toolCall, result, isError: isError2, needsApproval,
62358
62426
  }
62359
62427
  case "ls": {
62360
62428
  if (Array.isArray(result)) {
62361
- const dirs = result.filter((f2) => typeof f2 === "object" && f2.is_dir).length;
62429
+ const dirs = result.filter(
62430
+ (f2) => typeof f2 === "object" && f2.is_dir
62431
+ ).length;
62362
62432
  const files = result.length - dirs;
62363
62433
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
62364
62434
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-status-nominal flex items-center gap-1.5", children: [
@@ -62491,72 +62561,89 @@ function ToolCallRenderer({ toolCall, result, isError: isError2, needsApproval,
62491
62561
  const formattedContent = renderFormattedContent();
62492
62562
  const formattedResult = renderFormattedResult();
62493
62563
  const hasFormattedDisplay = formattedContent || formattedResult;
62494
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cn(
62495
- "rounded-sm border overflow-hidden",
62496
- needsApproval ? "border-amber-500/50 bg-amber-500/5" : "border-border bg-background-elevated"
62497
- ), children: [
62498
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
62499
- "button",
62500
- {
62501
- onClick: () => setIsExpanded(!isExpanded),
62502
- className: "flex w-full items-center gap-2 px-3 py-2 hover:bg-background-interactive transition-colors",
62503
- children: [
62504
- isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 text-muted-foreground shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" }),
62505
- /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { className: cn("size-4 shrink-0", needsApproval ? "text-amber-500" : "text-status-info") }),
62506
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium shrink-0", children: label }),
62507
- displayArg && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-left text-xs text-muted-foreground font-mono", children: displayArg }),
62508
- needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "warning", className: "ml-auto shrink-0", children: "APPROVAL" }),
62509
- !needsApproval && result === void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "ml-auto shrink-0 animate-pulse", children: "RUNNING" }),
62510
- result !== void 0 && !needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: isError2 ? "critical" : "nominal", className: "ml-auto shrink-0", children: isError2 ? "ERROR" : "OK" }),
62511
- isPanelSynced && !needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "shrink-0 text-[9px]", children: "SYNCED" })
62512
- ]
62513
- }
62514
- ),
62515
- needsApproval ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-amber-500/20 px-3 py-3 space-y-3", children: [
62516
- formattedContent,
62517
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
62518
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-section-header text-[10px] mb-1", children: "ARGUMENTS" }),
62519
- /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs font-mono bg-background p-2 rounded-sm overflow-auto max-h-24", children: JSON.stringify(args, null, 2) })
62520
- ] }),
62521
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
62522
- /* @__PURE__ */ jsxRuntimeExports.jsx(
62564
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
62565
+ "div",
62566
+ {
62567
+ className: cn(
62568
+ "rounded-sm border overflow-hidden",
62569
+ needsApproval ? "border-amber-500/50 bg-amber-500/5" : "border-border bg-background-elevated"
62570
+ ),
62571
+ children: [
62572
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
62523
62573
  "button",
62524
62574
  {
62525
- className: "px-3 py-1.5 text-xs border border-border rounded-sm hover:bg-background-interactive transition-colors",
62526
- onClick: handleReject,
62527
- children: "Reject"
62575
+ onClick: () => setIsExpanded(!isExpanded),
62576
+ className: "flex w-full items-center gap-2 px-3 py-2 hover:bg-background-interactive transition-colors",
62577
+ children: [
62578
+ isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4 text-muted-foreground shrink-0" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-4 text-muted-foreground shrink-0" }),
62579
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62580
+ Icon2,
62581
+ {
62582
+ className: cn("size-4 shrink-0", needsApproval ? "text-amber-500" : "text-status-info")
62583
+ }
62584
+ ),
62585
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium shrink-0", children: label }),
62586
+ displayArg && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-left text-xs text-muted-foreground font-mono", children: displayArg }),
62587
+ needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "warning", className: "ml-auto shrink-0", children: "APPROVAL" }),
62588
+ !needsApproval && result === void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "ml-auto shrink-0 animate-pulse", children: "RUNNING" }),
62589
+ result !== void 0 && !needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: isError2 ? "critical" : "nominal", className: "ml-auto shrink-0", children: isError2 ? "ERROR" : "OK" }),
62590
+ isPanelSynced && !needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "shrink-0 text-[9px]", children: "SYNCED" })
62591
+ ]
62528
62592
  }
62529
62593
  ),
62530
- /* @__PURE__ */ jsxRuntimeExports.jsx(
62531
- "button",
62532
- {
62533
- className: "px-3 py-1.5 text-xs bg-status-nominal text-background rounded-sm hover:bg-status-nominal/90 transition-colors",
62534
- onClick: handleApprove,
62535
- children: "Approve & Run"
62536
- }
62537
- )
62538
- ] })
62539
- ] }) : null,
62540
- hasFormattedDisplay && !isExpanded && !needsApproval && result !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-border px-3 py-2 space-y-2 overflow-hidden", children: [
62541
- formattedContent,
62542
- formattedResult
62543
- ] }),
62544
- isExpanded && !needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-border px-3 py-2 space-y-2 overflow-hidden", children: [
62545
- formattedContent,
62546
- formattedResult,
62547
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow-hidden w-full", children: [
62548
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-section-header mb-1", children: "RAW ARGUMENTS" }),
62549
- /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs font-mono bg-background p-2 rounded-sm overflow-auto max-h-48 w-full whitespace-pre-wrap break-all", children: JSON.stringify(args, null, 2) })
62550
- ] }),
62551
- result !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow-hidden w-full", children: [
62552
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-section-header mb-1", children: "RAW RESULT" }),
62553
- /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: cn(
62554
- "text-xs font-mono p-2 rounded-sm overflow-auto max-h-48 w-full whitespace-pre-wrap break-all",
62555
- isError2 ? "bg-status-critical/10 text-status-critical" : "bg-background"
62556
- ), children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
62557
- ] })
62558
- ] })
62559
- ] });
62594
+ needsApproval ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-amber-500/20 px-3 py-3 space-y-3", children: [
62595
+ formattedContent,
62596
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
62597
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-section-header text-[10px] mb-1", children: "ARGUMENTS" }),
62598
+ /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs font-mono bg-background p-2 rounded-sm overflow-auto max-h-24", children: JSON.stringify(args, null, 2) })
62599
+ ] }),
62600
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-2", children: [
62601
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62602
+ "button",
62603
+ {
62604
+ className: "px-3 py-1.5 text-xs border border-border rounded-sm hover:bg-background-interactive transition-colors",
62605
+ onClick: handleReject,
62606
+ children: "Reject"
62607
+ }
62608
+ ),
62609
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62610
+ "button",
62611
+ {
62612
+ className: "px-3 py-1.5 text-xs bg-status-nominal text-background rounded-sm hover:bg-status-nominal/90 transition-colors",
62613
+ onClick: handleApprove,
62614
+ children: "Approve & Run"
62615
+ }
62616
+ )
62617
+ ] })
62618
+ ] }) : null,
62619
+ hasFormattedDisplay && !isExpanded && !needsApproval && result !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-border px-3 py-2 space-y-2 overflow-hidden", children: [
62620
+ formattedContent,
62621
+ formattedResult
62622
+ ] }),
62623
+ isExpanded && !needsApproval && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-border px-3 py-2 space-y-2 overflow-hidden", children: [
62624
+ formattedContent,
62625
+ formattedResult,
62626
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow-hidden w-full", children: [
62627
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-section-header mb-1", children: "RAW ARGUMENTS" }),
62628
+ /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs font-mono bg-background p-2 rounded-sm overflow-auto max-h-48 w-full whitespace-pre-wrap break-all", children: JSON.stringify(args, null, 2) })
62629
+ ] }),
62630
+ result !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "overflow-hidden w-full", children: [
62631
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-section-header mb-1", children: "RAW RESULT" }),
62632
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62633
+ "pre",
62634
+ {
62635
+ className: cn(
62636
+ "text-xs font-mono p-2 rounded-sm overflow-auto max-h-48 w-full whitespace-pre-wrap break-all",
62637
+ isError2 ? "bg-status-critical/10 text-status-critical" : "bg-background"
62638
+ ),
62639
+ children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
62640
+ }
62641
+ )
62642
+ ] })
62643
+ ] })
62644
+ ]
62645
+ }
62646
+ );
62560
62647
  }
62561
62648
  function ok$1() {
62562
62649
  }
@@ -73902,7 +73989,13 @@ const StreamingMarkdown = reactExports.memo(function StreamingMarkdown2({
73902
73989
  isStreaming && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block w-2 h-4 ml-0.5 bg-foreground/70 animate-pulse" })
73903
73990
  ] });
73904
73991
  });
73905
- function MessageBubble({ message, isStreaming, toolResults, pendingApproval, onApprovalDecision }) {
73992
+ function MessageBubble({
73993
+ message,
73994
+ isStreaming,
73995
+ toolResults,
73996
+ pendingApproval,
73997
+ onApprovalDecision
73998
+ }) {
73906
73999
  const isUser = message.role === "user";
73907
74000
  const isTool = message.role === "tool";
73908
74001
  if (isTool) {
@@ -73945,14 +74038,14 @@ function MessageBubble({ message, isStreaming, toolResults, pendingApproval, onA
73945
74038
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 overflow-hidden", children: [
73946
74039
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 shrink-0", children: !isUser && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex size-8 items-center justify-center rounded-sm bg-status-info/10 text-status-info", children: getIcon() }) }),
73947
74040
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0 space-y-2 overflow-hidden", children: [
73948
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn(
73949
- "text-section-header",
73950
- isUser && "text-right"
73951
- ), children: getLabel() }),
73952
- content2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn(
73953
- "rounded-sm p-3 overflow-hidden",
73954
- isUser ? "bg-primary/10" : "bg-card"
73955
- ), children: content2 }),
74041
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("text-section-header", isUser && "text-right"), children: getLabel() }),
74042
+ content2 && /* @__PURE__ */ jsxRuntimeExports.jsx(
74043
+ "div",
74044
+ {
74045
+ className: cn("rounded-sm p-3 overflow-hidden", isUser ? "bg-primary/10" : "bg-card"),
74046
+ children: content2
74047
+ }
74048
+ ),
73956
74049
  hasToolCalls && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 overflow-hidden", children: message.tool_calls.map((toolCall, index2) => {
73957
74050
  const result = toolResults?.get(toolCall.id);
73958
74051
  const pendingId = pendingApproval?.tool_call?.id;
@@ -74333,14 +74426,10 @@ var Root2 = Popover$1;
74333
74426
  var Trigger = PopoverTrigger$1;
74334
74427
  var Portal$1 = PopoverPortal;
74335
74428
  var Content2 = PopoverContent$1;
74336
- function Popover({
74337
- ...props
74338
- }) {
74429
+ function Popover({ ...props }) {
74339
74430
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Root2, { "data-slot": "popover", ...props });
74340
74431
  }
74341
- function PopoverTrigger({
74342
- ...props
74343
- }) {
74432
+ function PopoverTrigger({ ...props }) {
74344
74433
  return /* @__PURE__ */ jsxRuntimeExports.jsx(Trigger, { "data-slot": "popover-trigger", ...props });
74345
74434
  }
74346
74435
  function PopoverContent({
@@ -74782,16 +74871,7 @@ const DialogContent = reactExports.forwardRef(({ className, children, ...props }
74782
74871
  )
74783
74872
  ] }));
74784
74873
  DialogContent.displayName = Content.displayName;
74785
- const DialogHeader = ({
74786
- className,
74787
- ...props
74788
- }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
74789
- "div",
74790
- {
74791
- className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className),
74792
- ...props
74793
- }
74794
- );
74874
+ const DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
74795
74875
  DialogHeader.displayName = "DialogHeader";
74796
74876
  const DialogTitle = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
74797
74877
  Title,
@@ -74831,10 +74911,13 @@ Input.displayName = "Input";
74831
74911
  const PROVIDER_INFO = {
74832
74912
  anthropic: { placeholder: "sk-ant-...", envVar: "ANTHROPIC_API_KEY" },
74833
74913
  openai: { placeholder: "sk-...", envVar: "OPENAI_API_KEY" },
74834
- google: { placeholder: "AIza...", envVar: "GOOGLE_API_KEY" },
74835
- custom: { placeholder: "your-api-key", envVar: "CUSTOM_API_KEY" }
74914
+ google: { placeholder: "AIza...", envVar: "GOOGLE_API_KEY" }
74836
74915
  };
74837
- function ApiKeyDialog({ open, onOpenChange, provider }) {
74916
+ function ApiKeyDialog({
74917
+ open,
74918
+ onOpenChange,
74919
+ provider
74920
+ }) {
74838
74921
  const [apiKey, setApiKey] = reactExports.useState("");
74839
74922
  const [showKey, setShowKey] = reactExports.useState(false);
74840
74923
  const [saving, setSaving] = reactExports.useState(false);
@@ -74965,14 +75048,14 @@ function ApiKeyDialog({ open, onOpenChange, provider }) {
74965
75048
  ] })
74966
75049
  ] }),
74967
75050
  provider.id === "custom" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
74968
- /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-muted-foreground", children: "Model Name (Optional)" }),
75051
+ /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-xs text-muted-foreground", children: "Model Name (optional)" }),
74969
75052
  /* @__PURE__ */ jsxRuntimeExports.jsx(
74970
75053
  Input,
74971
75054
  {
74972
75055
  type: "text",
74973
75056
  value: modelName,
74974
75057
  onChange: (e) => setModelName(e.target.value),
74975
- placeholder: "gpt-4, claude-3-opus, etc."
75058
+ placeholder: "e.g., gpt-4"
74976
75059
  }
74977
75060
  ),
74978
75061
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-muted-foreground", children: [
@@ -74981,32 +75064,29 @@ function ApiKeyDialog({ open, onOpenChange, provider }) {
74981
75064
  ] })
74982
75065
  ] })
74983
75066
  ] }),
74984
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [
74985
- hasExistingKey ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
74986
- Button,
74987
- {
74988
- type: "button",
74989
- variant: "destructive",
74990
- size: "sm",
74991
- onClick: handleDelete2,
74992
- disabled: deleting || saving,
74993
- children: [
74994
- deleting ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin mr-2" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-4 mr-2" }),
74995
- "Remove Key"
74996
- ]
74997
- }
74998
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", {}),
74999
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
75000
- /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), children: "Cancel" }),
75067
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between gap-2", children: [
75068
+ hasExistingKey && /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "destructive", size: "sm", onClick: handleDelete2, disabled: deleting, children: deleting ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75069
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin" }),
75070
+ "Removing..."
75071
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75072
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-4" }),
75073
+ "Remove"
75074
+ ] }) }),
75075
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 ml-auto", children: [
75001
75076
  /* @__PURE__ */ jsxRuntimeExports.jsx(
75002
75077
  Button,
75003
75078
  {
75004
- type: "button",
75005
- onClick: handleSave,
75006
- disabled: !apiKey.trim() || saving || provider.id === "custom" && !baseUrl.trim(),
75007
- children: saving ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin" }) : "Save"
75079
+ variant: "outline",
75080
+ size: "sm",
75081
+ onClick: () => onOpenChange(false),
75082
+ disabled: saving,
75083
+ children: "Cancel"
75008
75084
  }
75009
- )
75085
+ ),
75086
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "sm", onClick: handleSave, disabled: saving || !apiKey.trim(), children: saving ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75087
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin" }),
75088
+ "Saving..."
75089
+ ] }) : "Save" })
75010
75090
  ] })
75011
75091
  ] })
75012
75092
  ] }) });
@@ -75158,26 +75238,11 @@ function AddProviderDialog({ open, onOpenChange, onSuccess }) {
75158
75238
  ] })
75159
75239
  ] }),
75160
75240
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2", children: [
75161
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75162
- Button,
75163
- {
75164
- variant: "outline",
75165
- onClick: handleCancel,
75166
- disabled: saving,
75167
- children: "取消"
75168
- }
75169
- ),
75170
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75171
- Button,
75172
- {
75173
- onClick: handleSave,
75174
- disabled: saving || !id || !name2 || !baseUrl || !apiKey,
75175
- children: saving ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75176
- /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin mr-2" }),
75177
- "保存中..."
75178
- ] }) : "保存"
75179
- }
75180
- )
75241
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outline", onClick: handleCancel, disabled: saving, children: "取消" }),
75242
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { onClick: handleSave, disabled: saving || !id || !name2 || !baseUrl || !apiKey, children: saving ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75243
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 animate-spin mr-2" }),
75244
+ "保存中..."
75245
+ ] }) : "保存" })
75181
75246
  ] })
75182
75247
  ] }) });
75183
75248
  }
@@ -75191,11 +75256,21 @@ function GoogleIcon({ className }) {
75191
75256
  return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className, viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" }) });
75192
75257
  }
75193
75258
  function CustomIcon({ className }) {
75194
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
75195
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
75196
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 17l10 5 10-5" }),
75197
- /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 12l10 5 10-5" })
75198
- ] });
75259
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
75260
+ "svg",
75261
+ {
75262
+ className,
75263
+ viewBox: "0 0 24 24",
75264
+ fill: "none",
75265
+ stroke: "currentColor",
75266
+ strokeWidth: "2",
75267
+ children: [
75268
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
75269
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 17l10 5 10-5" }),
75270
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 12l10 5 10-5" })
75271
+ ]
75272
+ }
75273
+ );
75199
75274
  }
75200
75275
  const PROVIDER_ICONS = {
75201
75276
  anthropic: AnthropicIcon,
@@ -75211,8 +75286,7 @@ function getProviderIcon(providerId) {
75211
75286
  const FALLBACK_PROVIDERS = [
75212
75287
  { id: "anthropic", name: "Anthropic", hasApiKey: false },
75213
75288
  { id: "openai", name: "OpenAI", hasApiKey: false },
75214
- { id: "google", name: "Google", hasApiKey: false },
75215
- { id: "custom", name: "Custom API", hasApiKey: false }
75289
+ { id: "google", name: "Google", hasApiKey: false }
75216
75290
  ];
75217
75291
  function ModelSwitcher({ threadId }) {
75218
75292
  const [open, setOpen] = reactExports.useState(false);
@@ -75227,20 +75301,10 @@ function ModelSwitcher({ threadId }) {
75227
75301
  loadProviders();
75228
75302
  }, [loadModels, loadProviders]);
75229
75303
  const displayProviders = providers.length > 0 ? providers : FALLBACK_PROVIDERS;
75230
- reactExports.useEffect(() => {
75231
- if (!selectedProviderId && currentModel) {
75232
- const model = models.find((m2) => m2.id === currentModel);
75233
- if (model) {
75234
- setSelectedProviderId(model.provider);
75235
- }
75236
- }
75237
- if (!selectedProviderId && displayProviders.length > 0) {
75238
- setSelectedProviderId(displayProviders[0].id);
75239
- }
75240
- }, [currentModel, models, selectedProviderId, displayProviders]);
75304
+ const effectiveProviderId = selectedProviderId || (currentModel ? models.find((m2) => m2.id === currentModel)?.provider : null) || (displayProviders.length > 0 ? displayProviders[0].id : null);
75241
75305
  const selectedModel = models.find((m2) => m2.id === currentModel);
75242
- const filteredModels = selectedProviderId ? models.filter((m2) => m2.provider === selectedProviderId) : [];
75243
- const selectedProvider = displayProviders.find((p2) => p2.id === selectedProviderId);
75306
+ const filteredModels = effectiveProviderId ? models.filter((m2) => m2.provider === effectiveProviderId) : [];
75307
+ const selectedProvider = displayProviders.find((p2) => p2.id === effectiveProviderId);
75244
75308
  function handleProviderClick(provider) {
75245
75309
  setSelectedProviderId(provider.id);
75246
75310
  }
@@ -75301,7 +75365,7 @@ function ModelSwitcher({ threadId }) {
75301
75365
  onClick: () => handleProviderClick(provider),
75302
75366
  className: cn(
75303
75367
  "w-full flex items-center gap-1.5 px-2 py-1 rounded-sm text-xs transition-colors text-left",
75304
- selectedProviderId === provider.id ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
75368
+ effectiveProviderId === provider.id ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
75305
75369
  ),
75306
75370
  children: [
75307
75371
  /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { className: "size-3.5 shrink-0" }),
@@ -75321,10 +75385,20 @@ function ModelSwitcher({ threadId }) {
75321
75385
  },
75322
75386
  className: "w-full flex items-center justify-center gap-1.5 px-2 py-2 rounded-sm text-xs transition-colors text-muted-foreground hover:text-foreground hover:bg-muted/50 border-t border-border mt-1 pt-2",
75323
75387
  children: [
75324
- /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { className: "size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
75325
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
75326
- /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
75327
- ] }),
75388
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
75389
+ "svg",
75390
+ {
75391
+ className: "size-4",
75392
+ viewBox: "0 0 24 24",
75393
+ fill: "none",
75394
+ stroke: "currentColor",
75395
+ strokeWidth: "2",
75396
+ children: [
75397
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
75398
+ /* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
75399
+ ]
75400
+ }
75401
+ ),
75328
75402
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "添加Provider" })
75329
75403
  ]
75330
75404
  }
@@ -75341,14 +75415,7 @@ function ModelSwitcher({ threadId }) {
75341
75415
  "API key required for ",
75342
75416
  selectedProvider.name
75343
75417
  ] }),
75344
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75345
- Button,
75346
- {
75347
- size: "sm",
75348
- onClick: () => handleConfigureApiKey(selectedProvider),
75349
- children: "Configure API Key"
75350
- }
75351
- )
75418
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { size: "sm", onClick: () => handleConfigureApiKey(selectedProvider), children: "Configure API Key" })
75352
75419
  ] })
75353
75420
  ) : (
75354
75421
  // Show models list with scrollable area
@@ -75577,11 +75644,16 @@ const MODEL_CONTEXT_LIMITS = {
75577
75644
  "gpt-4o-mini": 128e3,
75578
75645
  "gpt-4-turbo": 128e3,
75579
75646
  "gpt-4": 8192,
75580
- "o1": 2e5,
75647
+ o1: 2e5,
75581
75648
  "o1-mini": 128e3,
75582
- "o3": 2e5,
75649
+ o3: 2e5,
75583
75650
  "o3-mini": 2e5,
75584
75651
  // Google models
75652
+ "gemini-3-pro-preview": 2e6,
75653
+ "gemini-3-flash-preview": 1e6,
75654
+ "gemini-2.5-pro": 2e6,
75655
+ "gemini-2.5-flash": 1e6,
75656
+ "gemini-2.5-flash-lite": 1e6,
75585
75657
  "gemini-2.0-flash": 1e6,
75586
75658
  "gemini-1.5-pro": 2e6,
75587
75659
  "gemini-1.5-flash": 1e6
@@ -75624,9 +75696,9 @@ function ContextUsageIndicator({
75624
75696
  const contextLimit = getContextLimit(modelId);
75625
75697
  const usedTokens = tokenUsage.inputTokens;
75626
75698
  const usagePercent = Math.min(usedTokens / contextLimit * 100, 100);
75627
- let colorClass = "text-muted-foreground";
75628
- let bgColorClass = "bg-muted-foreground/20";
75629
- let barColorClass = "bg-muted-foreground";
75699
+ let colorClass = "text-blue-500";
75700
+ let bgColorClass = "bg-blue-500/20";
75701
+ let barColorClass = "bg-blue-500";
75630
75702
  let statusText = "Normal";
75631
75703
  if (usagePercent >= 90) {
75632
75704
  colorClass = "text-red-500";
@@ -75670,96 +75742,97 @@ function ContextUsageIndicator({
75670
75742
  ]
75671
75743
  }
75672
75744
  ) }),
75673
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75674
- PopoverContent,
75675
- {
75676
- className: "w-72 p-0 bg-background border-border",
75677
- align: "end",
75678
- sideOffset: 8,
75679
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 space-y-3", children: [
75680
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
75681
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-foreground", children: "Context Window" }),
75682
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("text-[10px] font-medium px-1.5 py-0.5 rounded", bgColorClass, colorClass), children: statusText })
75683
- ] }),
75684
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
75685
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-2 bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
75686
- "div",
75687
- {
75688
- className: cn("h-full rounded-full transition-all", barColorClass),
75689
- style: { width: `${usagePercent}%` }
75690
- }
75691
- ) }),
75692
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-muted-foreground", children: [
75693
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
75694
- formatTokenCountFull(usedTokens),
75695
- " tokens"
75696
- ] }),
75697
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
75698
- formatTokenCountFull(contextLimit),
75699
- " max"
75700
- ] })
75701
- ] })
75745
+ /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverContent, { className: "w-72 p-0 bg-background border-border", align: "end", sideOffset: 8, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 space-y-3", children: [
75746
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
75747
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium text-foreground", children: "Context Window" }),
75748
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75749
+ "span",
75750
+ {
75751
+ className: cn(
75752
+ "text-[10px] font-medium px-1.5 py-0.5 rounded",
75753
+ bgColorClass,
75754
+ colorClass
75755
+ ),
75756
+ children: statusText
75757
+ }
75758
+ )
75759
+ ] }),
75760
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
75761
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-2 bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
75762
+ "div",
75763
+ {
75764
+ className: cn("h-full rounded-full transition-all", barColorClass),
75765
+ style: { width: `${usagePercent}%` }
75766
+ }
75767
+ ) }),
75768
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] text-muted-foreground", children: [
75769
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
75770
+ formatTokenCountFull(usedTokens),
75771
+ " tokens"
75702
75772
  ] }),
75703
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 pt-2 border-t border-border", children: [
75704
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium text-muted-foreground uppercase tracking-wider", children: "Token Breakdown" }),
75705
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
75706
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75707
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
75708
- /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowUp, { className: "size-3" }),
75709
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Input" })
75710
- ] }),
75711
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: formatTokenCountFull(tokenUsage.inputTokens) })
75712
- ] }),
75713
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75714
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
75715
- /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowDown, { className: "size-3" }),
75716
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Output" })
75717
- ] }),
75718
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: formatTokenCountFull(tokenUsage.outputTokens) })
75719
- ] }),
75720
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs pt-1 border-t border-border/50", children: [
75721
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
75722
- /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3" }),
75723
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Total" })
75724
- ] }),
75725
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: formatTokenCountFull(tokenUsage.totalTokens) })
75726
- ] })
75727
- ] })
75773
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
75774
+ formatTokenCountFull(contextLimit),
75775
+ " max"
75776
+ ] })
75777
+ ] })
75778
+ ] }),
75779
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 pt-2 border-t border-border", children: [
75780
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium text-muted-foreground uppercase tracking-wider", children: "Token Breakdown" }),
75781
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
75782
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75783
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
75784
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowUp, { className: "size-3" }),
75785
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Input" })
75786
+ ] }),
75787
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: formatTokenCountFull(tokenUsage.inputTokens) })
75728
75788
  ] }),
75729
- hasCacheData && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 pt-2 border-t border-border", children: [
75730
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium text-muted-foreground uppercase tracking-wider", children: "Cache" }),
75731
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
75732
- tokenUsage.cacheReadTokens !== void 0 && tokenUsage.cacheReadTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75733
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-green-500", children: [
75734
- /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { className: "size-3" }),
75735
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Cache hits" })
75736
- ] }),
75737
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-green-500", children: formatTokenCountFull(tokenUsage.cacheReadTokens) })
75738
- ] }),
75739
- tokenUsage.cacheCreationTokens !== void 0 && tokenUsage.cacheCreationTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75740
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-blue-500", children: [
75741
- /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { className: "size-3" }),
75742
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Cache created" })
75743
- ] }),
75744
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-blue-500", children: formatTokenCountFull(tokenUsage.cacheCreationTokens) })
75745
- ] })
75746
- ] })
75789
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75790
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
75791
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowDown, { className: "size-3" }),
75792
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Output" })
75793
+ ] }),
75794
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: formatTokenCountFull(tokenUsage.outputTokens) })
75747
75795
  ] }),
75748
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pt-2 border-t border-border", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] text-muted-foreground", children: [
75749
- "Last updated: ",
75750
- tokenUsage.lastUpdated.toLocaleTimeString()
75751
- ] }) })
75796
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs pt-1 border-t border-border/50", children: [
75797
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
75798
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "size-3" }),
75799
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Total" })
75800
+ ] }),
75801
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: formatTokenCountFull(tokenUsage.totalTokens) })
75802
+ ] })
75752
75803
  ] })
75753
- }
75754
- )
75804
+ ] }),
75805
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 pt-2 border-t border-border", children: [
75806
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-medium text-muted-foreground uppercase tracking-wider", children: "Cache" }),
75807
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1", children: hasCacheData ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75808
+ tokenUsage.cacheReadTokens !== void 0 && tokenUsage.cacheReadTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75809
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-green-500", children: [
75810
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { className: "size-3" }),
75811
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Cache hits" })
75812
+ ] }),
75813
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-green-500", children: formatTokenCountFull(tokenUsage.cacheReadTokens) })
75814
+ ] }),
75815
+ tokenUsage.cacheCreationTokens !== void 0 && tokenUsage.cacheCreationTokens > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-xs", children: [
75816
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-blue-500", children: [
75817
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { className: "size-3" }),
75818
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Cache created" })
75819
+ ] }),
75820
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-blue-500", children: formatTokenCountFull(tokenUsage.cacheCreationTokens) })
75821
+ ] })
75822
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-muted-foreground", children: "No cached tokens" }) })
75823
+ ] }),
75824
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pt-2 border-t border-border", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] text-muted-foreground", children: [
75825
+ "Last updated: ",
75826
+ tokenUsage.lastUpdated.toLocaleTimeString()
75827
+ ] }) })
75828
+ ] }) })
75755
75829
  ] });
75756
75830
  }
75757
75831
  function ChatContainer({ threadId }) {
75758
- const [input, setInput] = reactExports.useState("");
75759
75832
  const inputRef = reactExports.useRef(null);
75760
75833
  const scrollRef = reactExports.useRef(null);
75761
75834
  const isAtBottomRef = reactExports.useRef(true);
75762
- const { loadThreads, generateTitleForFirstMessage } = useAppStore();
75835
+ const { threads, loadThreads, generateTitleForFirstMessage } = useAppStore();
75763
75836
  const {
75764
75837
  messages: threadMessages,
75765
75838
  pendingApproval,
@@ -75768,13 +75841,15 @@ function ChatContainer({ threadId }) {
75768
75841
  workspacePath,
75769
75842
  tokenUsage,
75770
75843
  currentModel,
75844
+ draftInput: input,
75771
75845
  setTodos,
75772
75846
  setWorkspaceFiles,
75773
75847
  setWorkspacePath,
75774
75848
  setPendingApproval,
75775
75849
  appendMessage,
75776
75850
  setError,
75777
- clearError
75851
+ clearError,
75852
+ setDraftInput: setInput
75778
75853
  } = useCurrentThread(threadId);
75779
75854
  const streamData = useThreadStream(threadId);
75780
75855
  const stream = streamData.stream;
@@ -75784,12 +75859,15 @@ function ChatContainer({ threadId }) {
75784
75859
  if (!pendingApproval || !stream) return;
75785
75860
  setPendingApproval(null);
75786
75861
  try {
75787
- await stream.submit(null, { command: { resume: { decision } } });
75862
+ await stream.submit(null, {
75863
+ command: { resume: { decision } },
75864
+ config: { configurable: { thread_id: threadId, model_id: currentModel } }
75865
+ });
75788
75866
  } catch (err) {
75789
75867
  console.error("[ChatContainer] Resume command failed:", err);
75790
75868
  }
75791
75869
  },
75792
- [pendingApproval, setPendingApproval, stream]
75870
+ [pendingApproval, setPendingApproval, stream, threadId, currentModel]
75793
75871
  );
75794
75872
  const agentValues = stream?.values;
75795
75873
  const streamTodos = agentValues?.todos;
@@ -75924,7 +76002,11 @@ function ChatContainer({ threadId }) {
75924
76002
  };
75925
76003
  appendMessage(userMessage);
75926
76004
  if (isFirstMessage) {
75927
- generateTitleForFirstMessage(threadId, message);
76005
+ const currentThread = threads.find((t) => t.thread_id === threadId);
76006
+ const hasDefaultTitle = currentThread?.title?.startsWith("Thread ");
76007
+ if (hasDefaultTitle) {
76008
+ generateTitleForFirstMessage(threadId, message);
76009
+ }
75928
76010
  }
75929
76011
  await stream.submit(
75930
76012
  {
@@ -75932,7 +76014,7 @@ function ChatContainer({ threadId }) {
75932
76014
  },
75933
76015
  {
75934
76016
  config: {
75935
- configurable: { thread_id: threadId }
76017
+ configurable: { thread_id: threadId, model_id: currentModel }
75936
76018
  }
75937
76019
  }
75938
76020
  );
@@ -76034,7 +76116,17 @@ function ChatContainer({ threadId }) {
76034
76116
  style: { minHeight: "48px", maxHeight: "200px" }
76035
76117
  }
76036
76118
  ),
76037
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center shrink-0 h-12", children: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: handleCancel, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Square, { className: "size-4" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { type: "submit", variant: "default", size: "icon", disabled: !input.trim(), className: "rounded-md", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Send, { className: "size-4" }) }) })
76119
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center shrink-0 h-12", children: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: handleCancel, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Square, { className: "size-4" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
76120
+ Button,
76121
+ {
76122
+ type: "submit",
76123
+ variant: "default",
76124
+ size: "icon",
76125
+ disabled: !input.trim(),
76126
+ className: "rounded-md",
76127
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Send, { className: "size-4" })
76128
+ }
76129
+ ) })
76038
76130
  ] }),
76039
76131
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
76040
76132
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
@@ -76585,14 +76677,11 @@ function buildFileTree(files) {
76585
76677
  return root2;
76586
76678
  }
76587
76679
  function FileTree({ files }) {
76680
+ const { currentThreadId } = useAppStore();
76681
+ const threadState = useThreadState(currentThreadId);
76682
+ const openFile = threadState?.openFile;
76588
76683
  const tree = reactExports.useMemo(() => buildFileTree(files), [files]);
76589
- const [expanded, setExpanded] = reactExports.useState(() => {
76590
- const dirs = /* @__PURE__ */ new Set();
76591
- files.forEach((f2) => {
76592
- if (f2.is_dir ?? false) dirs.add(f2.path);
76593
- });
76594
- return dirs;
76595
- });
76684
+ const [expanded, setExpanded] = reactExports.useState(/* @__PURE__ */ new Set());
76596
76685
  const toggleExpand = reactExports.useCallback((path2) => {
76597
76686
  setExpanded((prev) => {
76598
76687
  const next = new Set(prev);
@@ -76610,59 +76699,64 @@ function FileTree({ files }) {
76610
76699
  node: node2,
76611
76700
  depth: 0,
76612
76701
  expanded,
76613
- onToggle: toggleExpand
76702
+ onToggle: toggleExpand,
76703
+ openFile
76614
76704
  },
76615
76705
  node2.path
76616
76706
  )) });
76617
76707
  }
76618
- function FileTreeNode({
76619
- node: node2,
76620
- depth,
76621
- expanded,
76622
- onToggle
76623
- }) {
76624
- const { currentThreadId } = useAppStore();
76625
- const threadState = useThreadState(currentThreadId);
76626
- const openFile = threadState?.openFile;
76627
- const isExpanded = expanded.has(node2.path);
76628
- const hasChildren = node2.children.length > 0;
76629
- const paddingLeft = 8 + depth * 16;
76630
- const handleClick = () => {
76631
- if (node2.is_dir) {
76632
- onToggle(node2.path);
76633
- } else if (openFile) {
76634
- openFile(node2.path, node2.name);
76635
- }
76636
- };
76637
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
76638
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
76639
- "div",
76640
- {
76641
- onClick: handleClick,
76642
- className: cn(
76643
- "flex items-center gap-1.5 py-1 pr-3 text-xs hover:bg-background-interactive cursor-pointer"
76644
- ),
76645
- style: { paddingLeft },
76646
- children: [
76647
- node2.is_dir ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3.5 flex items-center justify-center shrink-0", children: hasChildren && (isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground" })) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3.5 shrink-0" }),
76648
- /* @__PURE__ */ jsxRuntimeExports.jsx(FileIcon, { name: node2.name, isDir: node2.is_dir, isOpen: isExpanded }),
76649
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1", children: node2.name }),
76650
- !node2.is_dir && node2.size !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground tabular-nums shrink-0", children: formatSize(node2.size) })
76651
- ]
76708
+ const FileTreeNode = reactExports.memo(
76709
+ function FileTreeNode2({
76710
+ node: node2,
76711
+ depth,
76712
+ expanded,
76713
+ onToggle,
76714
+ openFile
76715
+ }) {
76716
+ const isExpanded = expanded.has(node2.path);
76717
+ const hasChildren = node2.children.length > 0;
76718
+ const paddingLeft = 8 + depth * 16;
76719
+ const handleClick = () => {
76720
+ if (node2.is_dir) {
76721
+ onToggle(node2.path);
76722
+ } else if (openFile) {
76723
+ openFile(node2.path, node2.name);
76652
76724
  }
76653
- ),
76654
- node2.is_dir && isExpanded && node2.children.map((child) => /* @__PURE__ */ jsxRuntimeExports.jsx(
76655
- FileTreeNode,
76656
- {
76657
- node: child,
76658
- depth: depth + 1,
76659
- expanded,
76660
- onToggle
76661
- },
76662
- child.path
76663
- ))
76664
- ] });
76665
- }
76725
+ };
76726
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
76727
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
76728
+ "div",
76729
+ {
76730
+ onClick: handleClick,
76731
+ className: cn(
76732
+ "flex items-center gap-1.5 py-1 pr-3 text-xs hover:bg-background-interactive cursor-pointer"
76733
+ ),
76734
+ style: { paddingLeft },
76735
+ children: [
76736
+ node2.is_dir ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3.5 flex items-center justify-center shrink-0", children: hasChildren && (isExpanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { className: "size-3 text-muted-foreground" })) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3.5 shrink-0" }),
76737
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FileIcon, { name: node2.name, isDir: node2.is_dir, isOpen: isExpanded }),
76738
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1", children: node2.name }),
76739
+ !node2.is_dir && node2.size !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-muted-foreground tabular-nums shrink-0", children: formatSize(node2.size) })
76740
+ ]
76741
+ }
76742
+ ),
76743
+ node2.is_dir && isExpanded && node2.children.map((child) => /* @__PURE__ */ jsxRuntimeExports.jsx(
76744
+ FileTreeNode2,
76745
+ {
76746
+ node: child,
76747
+ depth: depth + 1,
76748
+ expanded,
76749
+ onToggle,
76750
+ openFile
76751
+ },
76752
+ child.path
76753
+ ))
76754
+ ] });
76755
+ },
76756
+ (prevProps, nextProps) => {
76757
+ return prevProps.node === nextProps.node && prevProps.expanded.has(prevProps.node.path) === nextProps.expanded.has(nextProps.node.path) && prevProps.openFile === nextProps.openFile && prevProps.onToggle === nextProps.onToggle && prevProps.depth === nextProps.depth;
76758
+ }
76759
+ );
76666
76760
  function FileIcon({
76667
76761
  name: name2,
76668
76762
  isDir,
@@ -76743,27 +76837,321 @@ function formatSize(bytes) {
76743
76837
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
76744
76838
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
76745
76839
  }
76840
+ const columnConfig = {
76841
+ pending: { badge: "outline", borderColor: "border-t-border" },
76842
+ in_progress: { badge: "info", borderColor: "border-t-status-info" },
76843
+ interrupted: { badge: "warning", borderColor: "border-t-status-warning" },
76844
+ done: { badge: "nominal", borderColor: "border-t-status-nominal" }
76845
+ };
76846
+ function KanbanColumn({
76847
+ title,
76848
+ status,
76849
+ count: count2,
76850
+ children
76851
+ }) {
76852
+ const config2 = columnConfig[status];
76853
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
76854
+ "div",
76855
+ {
76856
+ className: cn(
76857
+ "flex flex-col min-w-[200px] w-[200px] flex-1 bg-muted/30 rounded-sm border border-border border-t-2",
76858
+ config2.borderColor
76859
+ ),
76860
+ children: [
76861
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-border", children: [
76862
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-section-header", children: title }),
76863
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: config2.badge, children: count2 })
76864
+ ] }),
76865
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 space-y-2", children }) })
76866
+ ]
76867
+ }
76868
+ );
76869
+ }
76870
+ const Card = reactExports.forwardRef(
76871
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx(
76872
+ "div",
76873
+ {
76874
+ ref,
76875
+ className: cn("rounded-sm border border-border bg-card text-card-foreground", className),
76876
+ ...props
76877
+ }
76878
+ )
76879
+ );
76880
+ Card.displayName = "Card";
76881
+ const CardHeader = reactExports.forwardRef(
76882
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref, className: cn("flex flex-col space-y-1.5 p-4", className), ...props })
76883
+ );
76884
+ CardHeader.displayName = "CardHeader";
76885
+ const CardTitle = reactExports.forwardRef(
76886
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { ref, className: cn("text-section-header", className), ...props })
76887
+ );
76888
+ CardTitle.displayName = "CardTitle";
76889
+ const CardDescription = reactExports.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
76890
+ CardDescription.displayName = "CardDescription";
76891
+ const CardContent = reactExports.forwardRef(
76892
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref, className: cn("p-4 pt-0", className), ...props })
76893
+ );
76894
+ CardContent.displayName = "CardContent";
76895
+ const CardFooter = reactExports.forwardRef(
76896
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref, className: cn("flex items-center p-4 pt-0", className), ...props })
76897
+ );
76898
+ CardFooter.displayName = "CardFooter";
76899
+ function ThreadStatusIcon({ threadId }) {
76900
+ const { isLoading } = useThreadStream(threadId);
76901
+ if (isLoading) {
76902
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-4 shrink-0 text-status-info animate-spin" });
76903
+ }
76904
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-4 shrink-0 text-muted-foreground" });
76905
+ }
76906
+ function ThreadKanbanCard({ thread, status, onClick }) {
76907
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
76908
+ Card,
76909
+ {
76910
+ className: cn(
76911
+ "cursor-pointer transition-all hover:border-border-emphasis hover:bg-background-interactive",
76912
+ status === "in_progress" && "border-status-info/50",
76913
+ status === "interrupted" && "!border-amber-500/50 !bg-amber-500/5"
76914
+ ),
76915
+ onClick,
76916
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-2", children: [
76917
+ status === "interrupted" ? /* @__PURE__ */ jsxRuntimeExports.jsx(MessageSquare, { className: "size-4 shrink-0 text-amber-500" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ThreadStatusIcon, { threadId: thread.thread_id }),
76918
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
76919
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
76920
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium truncate", children: thread.title || truncate(thread.thread_id, 20) }),
76921
+ status === "done" && /* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "nominal", className: "shrink-0 text-[9px]", children: "DONE" })
76922
+ ] }),
76923
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-1 text-[10px] text-muted-foreground", children: [
76924
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { className: "size-3" }),
76925
+ formatRelativeTime(thread.updated_at)
76926
+ ] })
76927
+ ] })
76928
+ ] }) })
76929
+ }
76930
+ );
76931
+ }
76932
+ function SubagentKanbanCard({
76933
+ subagent,
76934
+ parentThread,
76935
+ onClick
76936
+ }) {
76937
+ const isDone = subagent.status === "completed" || subagent.status === "failed";
76938
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
76939
+ Card,
76940
+ {
76941
+ className: cn(
76942
+ "cursor-pointer transition-all hover:border-border-emphasis hover:bg-background-interactive border-dashed",
76943
+ subagent.status === "running" && "border-status-info/50"
76944
+ ),
76945
+ onClick,
76946
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(CardContent, { className: "p-3 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-2 min-w-0", children: [
76947
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
76948
+ Bot,
76949
+ {
76950
+ className: cn(
76951
+ "size-4 shrink-0",
76952
+ subagent.status === "running" ? "text-status-info" : "text-muted-foreground"
76953
+ )
76954
+ }
76955
+ ),
76956
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0 overflow-hidden", children: [
76957
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
76958
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium truncate", children: subagent.name }),
76959
+ isDone && /* @__PURE__ */ jsxRuntimeExports.jsx(
76960
+ Badge,
76961
+ {
76962
+ variant: subagent.status === "failed" ? "critical" : "nominal",
76963
+ className: "shrink-0 text-[9px]",
76964
+ children: subagent.status === "failed" ? "FAILED" : "DONE"
76965
+ }
76966
+ )
76967
+ ] }),
76968
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-muted-foreground line-clamp-2 mt-0.5 break-words", children: subagent.description }),
76969
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-1 mt-1 text-[10px] text-muted-foreground", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate", children: [
76970
+ "↳ ",
76971
+ parentThread.title || truncate(parentThread.thread_id, 15)
76972
+ ] }) })
76973
+ ] })
76974
+ ] }) })
76975
+ }
76976
+ );
76977
+ }
76978
+ function getThreadKanbanStatus(thread, isLoading, hasDraft, hasPendingApproval) {
76979
+ if (hasPendingApproval || thread.status === "interrupted") return "interrupted";
76980
+ if (thread.status === "busy" || isLoading) return "in_progress";
76981
+ if (hasDraft) return "pending";
76982
+ return "done";
76983
+ }
76984
+ function KanbanView() {
76985
+ const { threads, selectThread, showSubagentsInKanban } = useAppStore();
76986
+ const allThreadStates = useAllThreadStates();
76987
+ const loadingStates = useAllStreamLoadingStates();
76988
+ const handleCardClick = (threadId) => {
76989
+ selectThread(threadId);
76990
+ };
76991
+ const categorizedThreads = reactExports.useMemo(() => {
76992
+ const result = {
76993
+ pending: [],
76994
+ in_progress: [],
76995
+ interrupted: [],
76996
+ done: []
76997
+ };
76998
+ for (const thread of threads) {
76999
+ const isLoading = loadingStates[thread.thread_id] ?? false;
77000
+ const threadState = allThreadStates[thread.thread_id];
77001
+ const hasDraft = Boolean(threadState?.draftInput?.trim());
77002
+ const hasPendingApproval = Boolean(threadState?.pendingApproval);
77003
+ const status = getThreadKanbanStatus(thread, isLoading, hasDraft, hasPendingApproval);
77004
+ result[status].push({ thread, status });
77005
+ }
77006
+ return result;
77007
+ }, [threads, loadingStates, allThreadStates]);
77008
+ const categorizedSubagents = reactExports.useMemo(() => {
77009
+ if (!showSubagentsInKanban) {
77010
+ return { pending: [], in_progress: [], interrupted: [], done: [] };
77011
+ }
77012
+ const result = {
77013
+ pending: [],
77014
+ in_progress: [],
77015
+ interrupted: [],
77016
+ done: []
77017
+ };
77018
+ const threadMap = new Map(threads.map((t) => [t.thread_id, t]));
77019
+ for (const [threadId, state] of Object.entries(allThreadStates)) {
77020
+ const parentThread = threadMap.get(threadId);
77021
+ if (!parentThread || !state.subagents) continue;
77022
+ for (const subagent of state.subagents) {
77023
+ let status;
77024
+ switch (subagent.status) {
77025
+ case "pending":
77026
+ status = "pending";
77027
+ break;
77028
+ case "running":
77029
+ status = "in_progress";
77030
+ break;
77031
+ case "completed":
77032
+ status = "done";
77033
+ break;
77034
+ case "failed":
77035
+ status = "done";
77036
+ break;
77037
+ default:
77038
+ status = "pending";
77039
+ }
77040
+ result[status].push({ subagent, parentThread, status });
77041
+ }
77042
+ }
77043
+ return result;
77044
+ }, [threads, allThreadStates, showSubagentsInKanban]);
77045
+ const columnData = [
77046
+ { status: "pending", title: "PENDING" },
77047
+ { status: "in_progress", title: "IN PROGRESS" },
77048
+ { status: "interrupted", title: "BLOCKED" },
77049
+ { status: "done", title: "DONE" }
77050
+ ];
77051
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col h-full bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-x-auto p-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full min-w-max gap-2", children: columnData.map(({ status, title }) => {
77052
+ const threadItems = categorizedThreads[status];
77053
+ const subagentItems = categorizedSubagents[status];
77054
+ const totalCount = threadItems.length + subagentItems.length;
77055
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(KanbanColumn, { title, status, count: totalCount, children: [
77056
+ threadItems.map(({ thread, status: threadStatus }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
77057
+ ThreadKanbanCard,
77058
+ {
77059
+ thread,
77060
+ status: threadStatus,
77061
+ onClick: () => handleCardClick(thread.thread_id)
77062
+ },
77063
+ thread.thread_id
77064
+ )),
77065
+ subagentItems.map(({ subagent, parentThread }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
77066
+ SubagentKanbanCard,
77067
+ {
77068
+ subagent,
77069
+ parentThread,
77070
+ onClick: () => handleCardClick(parentThread.thread_id)
77071
+ },
77072
+ subagent.id
77073
+ )),
77074
+ totalCount === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-sm text-muted-foreground py-8", children: "No items" })
77075
+ ] }, status);
77076
+ }) }) }) });
77077
+ }
77078
+ function KanbanHeader({ className }) {
77079
+ const { showSubagentsInKanban, setShowSubagentsInKanban, threads } = useAppStore();
77080
+ const activeCount = threads.filter(
77081
+ (t) => t.status === "busy" || t.status === "interrupted"
77082
+ ).length;
77083
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
77084
+ "div",
77085
+ {
77086
+ className: cn(
77087
+ "flex items-center justify-between px-3 app-no-drag relative overflow-hidden",
77088
+ className
77089
+ ),
77090
+ children: [
77091
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 pointer-events-none opacity-[0.03]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
77092
+ "div",
77093
+ {
77094
+ className: "absolute inset-0",
77095
+ style: {
77096
+ backgroundImage: "repeating-linear-gradient(0deg, transparent, transparent 2px, currentColor 2px, currentColor 3px)",
77097
+ backgroundSize: "100% 3px"
77098
+ }
77099
+ }
77100
+ ) }),
77101
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-[10px] font-mono uppercase tracking-wider text-muted-foreground", children: [
77102
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
77103
+ "div",
77104
+ {
77105
+ className: cn(
77106
+ "size-1.5 rounded-full",
77107
+ activeCount > 0 ? "bg-status-nominal animate-tactical-pulse" : "bg-muted-foreground"
77108
+ )
77109
+ }
77110
+ ),
77111
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "tabular-nums", children: activeCount > 0 ? `${activeCount} ACTIVE` : "IDLE" })
77112
+ ] }),
77113
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
77114
+ Button,
77115
+ {
77116
+ variant: showSubagentsInKanban ? "secondary" : "ghost",
77117
+ size: "sm",
77118
+ onClick: () => setShowSubagentsInKanban(!showSubagentsInKanban),
77119
+ className: "gap-2 h-7 relative",
77120
+ children: [
77121
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Bot, { className: "size-3.5" }),
77122
+ showSubagentsInKanban ? "Hide" : "Show",
77123
+ " Subagents"
77124
+ ]
77125
+ }
77126
+ )
77127
+ ]
77128
+ }
77129
+ );
77130
+ }
76746
77131
  const HANDLE_WIDTH = 6;
76747
77132
  function ResizeHandle({ onDrag }) {
76748
77133
  const startXRef = reactExports.useRef(0);
76749
- const handleMouseDown = reactExports.useCallback((e) => {
76750
- e.preventDefault();
76751
- startXRef.current = e.clientX;
76752
- const handleMouseMove = (e2) => {
76753
- const totalDelta = e2.clientX - startXRef.current;
76754
- onDrag(totalDelta);
76755
- };
76756
- const handleMouseUp = () => {
76757
- document.removeEventListener("mousemove", handleMouseMove);
76758
- document.removeEventListener("mouseup", handleMouseUp);
76759
- document.body.style.cursor = "";
76760
- document.body.style.userSelect = "";
76761
- };
76762
- document.addEventListener("mousemove", handleMouseMove);
76763
- document.addEventListener("mouseup", handleMouseUp);
76764
- document.body.style.cursor = "col-resize";
76765
- document.body.style.userSelect = "none";
76766
- }, [onDrag]);
77134
+ const handleMouseDown = reactExports.useCallback(
77135
+ (e) => {
77136
+ e.preventDefault();
77137
+ startXRef.current = e.clientX;
77138
+ const handleMouseMove = (e2) => {
77139
+ const totalDelta = e2.clientX - startXRef.current;
77140
+ onDrag(totalDelta);
77141
+ };
77142
+ const handleMouseUp = () => {
77143
+ document.removeEventListener("mousemove", handleMouseMove);
77144
+ document.removeEventListener("mouseup", handleMouseUp);
77145
+ document.body.style.cursor = "";
77146
+ document.body.style.userSelect = "";
77147
+ };
77148
+ document.addEventListener("mousemove", handleMouseMove);
77149
+ document.addEventListener("mouseup", handleMouseUp);
77150
+ document.body.style.cursor = "col-resize";
77151
+ document.body.style.userSelect = "none";
77152
+ },
77153
+ [onDrag]
77154
+ );
76767
77155
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
76768
77156
  "div",
76769
77157
  {
@@ -76781,7 +77169,7 @@ const RIGHT_MIN = 250;
76781
77169
  const RIGHT_MAX = 450;
76782
77170
  const RIGHT_DEFAULT = 320;
76783
77171
  function App() {
76784
- const { currentThreadId, loadThreads, createThread } = useAppStore();
77172
+ const { currentThreadId, loadThreads, createThread, showKanbanView } = useAppStore();
76785
77173
  const [isLoading, setIsLoading] = reactExports.useState(true);
76786
77174
  const [leftWidth, setLeftWidth] = reactExports.useState(LEFT_DEFAULT);
76787
77175
  const [rightWidth, setRightWidth] = reactExports.useState(RIGHT_DEFAULT);
@@ -76871,24 +77259,29 @@ function App() {
76871
77259
  },
76872
77260
  children: [
76873
77261
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-name", children: "OPENWORK" }),
76874
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-version", children: "0.2.0" })
77262
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-version", children: "0.2.2" })
76875
77263
  ]
76876
77264
  }
76877
77265
  ),
76878
77266
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-w-0", children: [
76879
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-9 w-full shrink-0 app-drag-region bg-sidebar", children: [
76880
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: leftWidth }, className: "shrink-0" }),
77267
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-9 w-full shrink-0 app-drag-region", children: [
77268
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: leftWidth }, className: "shrink-0 bg-sidebar" }),
76881
77269
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-[1px] shrink-0" }),
76882
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: currentThreadId && /* @__PURE__ */ jsxRuntimeExports.jsx(TabBar, { className: "h-full border-b-0" }) })
77270
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0 bg-background border-b border-border", children: showKanbanView ? /* @__PURE__ */ jsxRuntimeExports.jsx(KanbanHeader, { className: "h-full" }) : currentThreadId && /* @__PURE__ */ jsxRuntimeExports.jsx(TabBar, { className: "h-full border-b-0" }) })
76883
77271
  ] }),
76884
77272
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 overflow-hidden", children: [
76885
77273
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: leftWidth }, className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ThreadSidebar, {}) }),
76886
77274
  /* @__PURE__ */ jsxRuntimeExports.jsx(ResizeHandle, { onDrag: handleLeftResize }),
76887
- /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: "flex flex-1 flex-col min-w-0 overflow-hidden", children: currentThreadId ? /* @__PURE__ */ jsxRuntimeExports.jsx(TabbedPanel, { threadId: currentThreadId, showTabBar: false }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center text-muted-foreground", children: "Select or create a thread to begin" }) })
77275
+ showKanbanView ? (
77276
+ /* Kanban View - replaces center and right panels */
77277
+ /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: "flex flex-1 flex-col min-w-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(KanbanView, {}) })
77278
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: "flex flex-1 flex-col min-w-0 overflow-hidden", children: currentThreadId ? /* @__PURE__ */ jsxRuntimeExports.jsx(TabbedPanel, { threadId: currentThreadId, showTabBar: false }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-1 items-center justify-center text-muted-foreground", children: "Select or create a thread to begin" }) }) })
76888
77279
  ] })
76889
77280
  ] }),
76890
- /* @__PURE__ */ jsxRuntimeExports.jsx(ResizeHandle, { onDrag: handleRightResize }),
76891
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: rightWidth }, className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RightPanel, {}) })
77281
+ !showKanbanView && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
77282
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ResizeHandle, { onDrag: handleRightResize }),
77283
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { width: rightWidth }, className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RightPanel, {}) })
77284
+ ] })
76892
77285
  ] }) });
76893
77286
  }
76894
77287
  ReactDOM$1.createRoot(document.getElementById("root")).render(