@wrongstack/webui 0.255.0 → 0.256.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -63,26 +63,14 @@ function installFaviconVisibilityReset() {
63
63
  }
64
64
 
65
65
  // src/lib/ws-client.ts
66
- var WS_TOKEN_KEY = "ws_token";
67
- function getStoredToken() {
66
+ function getTokenFromWsUrl(wsUrl) {
68
67
  try {
69
- return sessionStorage.getItem(WS_TOKEN_KEY);
68
+ const u = new URL(wsUrl);
69
+ return u.searchParams.get("token");
70
70
  } catch {
71
71
  return null;
72
72
  }
73
73
  }
74
- function setStoredToken(token) {
75
- try {
76
- sessionStorage.setItem(WS_TOKEN_KEY, token);
77
- } catch {
78
- }
79
- }
80
- function clearStoredToken() {
81
- try {
82
- sessionStorage.removeItem(WS_TOKEN_KEY);
83
- } catch {
84
- }
85
- }
86
74
  var WrongStackWebSocketClient = class {
87
75
  ws = null;
88
76
  url;
@@ -120,7 +108,53 @@ var WrongStackWebSocketClient = class {
120
108
  constructor(url) {
121
109
  this.url = url ?? defaultWsUrl();
122
110
  }
111
+ /**
112
+ * Exchange a stored token for an HttpOnly auth cookie via `/ws-auth`.
113
+ * Called once before the first connect so subsequent reconnections can
114
+ * drop the `?token=` from the WS URL (C-2 fix — token-in-URL closes
115
+ * the C-598 query-string exposure class). No-op when the cookie is
116
+ * already set, when the server is on a loopback bind (no token
117
+ * required), or when no token is available yet.
118
+ *
119
+ * Failure is non-fatal: the legacy `?token=` URL path still works, so
120
+ * the client just continues to use it. Cookie is a defense-in-depth
121
+ * layer, not a hard requirement.
122
+ */
123
+ async ensureAuthCookie() {
124
+ if (typeof window === "undefined") return;
125
+ if (document.cookie.split(";").some((c) => c.trim().startsWith("ws_token="))) {
126
+ return;
127
+ }
128
+ const token = getTokenFromWsUrl(this.url);
129
+ if (!token) return;
130
+ const authUrl = httpOriginForAuth() + `/ws-auth?token=${encodeURIComponent(token)}`;
131
+ try {
132
+ const res = await fetch(authUrl, {
133
+ method: "GET",
134
+ credentials: "same-origin",
135
+ // Cache-Control: no-store on the server side. Don't let the
136
+ // browser cache a 401 or replay a stale response.
137
+ cache: "no-store"
138
+ });
139
+ if (!res.ok) {
140
+ console.warn(JSON.stringify({
141
+ level: "warn",
142
+ event: "ws_client.ws_auth_failed",
143
+ status: res.status,
144
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
145
+ }));
146
+ }
147
+ } catch (err) {
148
+ console.warn(JSON.stringify({
149
+ level: "warn",
150
+ event: "ws_client.ws_auth_error",
151
+ message: err instanceof Error ? err.message : String(err),
152
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
153
+ }));
154
+ }
155
+ }
123
156
  async connect() {
157
+ await this.ensureAuthCookie();
124
158
  return new Promise((resolve, reject) => {
125
159
  if (this.ws?.readyState === WebSocket.OPEN) {
126
160
  resolve();
@@ -128,8 +162,8 @@ var WrongStackWebSocketClient = class {
128
162
  }
129
163
  this.setStatus({ state: "connecting" });
130
164
  try {
131
- const storedToken = getStoredToken();
132
- const wsUrl = storedToken ? `${this.url}${this.url.includes("?") ? "&" : "?"}token=${storedToken}` : this.url;
165
+ const urlToken = getTokenFromWsUrl(this.url);
166
+ const wsUrl = urlToken ? `${this.url}${this.url.includes("?") ? "&" : "?"}token=${urlToken}` : this.url;
133
167
  this.ws = new WebSocket(wsUrl);
134
168
  this.ws.binaryType = "arraybuffer";
135
169
  const connectTimeout = setTimeout(() => {
@@ -264,9 +298,6 @@ var WrongStackWebSocketClient = class {
264
298
  if (msg.type === "session.start") {
265
299
  const payload = msg.payload;
266
300
  this.sessionId = payload.sessionId;
267
- if (payload.wsToken) {
268
- setStoredToken(payload.wsToken);
269
- }
270
301
  }
271
302
  this.emit(msg);
272
303
  }
@@ -510,7 +541,6 @@ var WrongStackWebSocketClient = class {
510
541
  }
511
542
  this.ws?.close();
512
543
  this.ws = null;
513
- clearStoredToken();
514
544
  }
515
545
  get isConnected() {
516
546
  return this.ws?.readyState === WebSocket.OPEN;
@@ -538,6 +568,18 @@ function defaultWsUrl() {
538
568
  }
539
569
  return `ws://${window.location.hostname}:${port}`;
540
570
  }
571
+ function httpOriginForAuth() {
572
+ if (typeof window === "undefined" || !window.location?.hostname) {
573
+ return "http://127.0.0.1:3456";
574
+ }
575
+ const host = window.location.hostname.toLowerCase();
576
+ const pagePort = window.location.port ? Number.parseInt(window.location.port, 10) : Number.NaN;
577
+ const httpPort = Number.isFinite(pagePort) && pagePort > 0 ? pagePort : 3456;
578
+ if (host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host === "::1") {
579
+ return `http://127.0.0.1:${httpPort}`;
580
+ }
581
+ return `http://${window.location.hostname}:${httpPort}`;
582
+ }
541
583
  function getWSClient(url) {
542
584
  if (!client) {
543
585
  client = new WrongStackWebSocketClient(url);
@@ -619,11 +661,15 @@ var useChatStore = create()(
619
661
  }));
620
662
  },
621
663
  appendToolProgress: (id, line) => {
664
+ get().appendToolProgressLines(id, [line]);
665
+ },
666
+ appendToolProgressLines: (id, lines) => {
667
+ if (lines.length === 0) return;
622
668
  set((state) => ({
623
669
  messages: state.messages.map((m) => {
624
670
  if (m.id !== id) return m;
625
671
  const prev = m.progressLines ?? [];
626
- const next = [...prev, line];
672
+ const next = [...prev, ...lines];
627
673
  const trimmed = next.length > 30 ? next.slice(next.length - 30) : next;
628
674
  return { ...m, progressLines: trimmed };
629
675
  })
@@ -828,6 +874,7 @@ var useUIStore = create4()(
828
874
  shortcutsOpen: false,
829
875
  searchOpen: false,
830
876
  searchQuery: "",
877
+ scrollTarget: null,
831
878
  promptHistory: [],
832
879
  sidebarWidth: SIDEBAR_DEFAULT_WIDTH,
833
880
  pinnedIds: [],
@@ -852,6 +899,7 @@ var useUIStore = create4()(
852
899
  setShortcutsOpen: (open) => set({ shortcutsOpen: open }),
853
900
  setSearchOpen: (open) => set({ searchOpen: open, searchQuery: open ? "" : "" }),
854
901
  setSearchQuery: (q) => set({ searchQuery: q }),
902
+ requestScrollToMessage: (id) => set((s) => ({ scrollTarget: { id, nonce: (s.scrollTarget?.nonce ?? 0) + 1 } })),
855
903
  pushPrompt: (text) => set((state) => {
856
904
  const trimmed = text.trim();
857
905
  if (!trimmed) return state;
@@ -1924,6 +1972,69 @@ function notifyIfHidden(title, body, tag) {
1924
1972
  }
1925
1973
  }
1926
1974
 
1975
+ // src/lib/stream-coalescer.ts
1976
+ function scheduleRaf(cb) {
1977
+ if (typeof requestAnimationFrame === "function") {
1978
+ requestAnimationFrame(cb);
1979
+ } else {
1980
+ queueMicrotask(cb);
1981
+ }
1982
+ }
1983
+ var StreamCoalescer = class {
1984
+ pending = /* @__PURE__ */ new Map();
1985
+ scheduled = false;
1986
+ /**
1987
+ * Queue `text` under `key`, to be flushed via `flush(key, joinedText)` on the
1988
+ * next frame. Repeated calls for the same key before a flush concatenate.
1989
+ * The `flush` callback is captured per key from the latest push.
1990
+ */
1991
+ push(key, text, flush) {
1992
+ if (!text) return;
1993
+ const existing = this.pending.get(key);
1994
+ if (existing) {
1995
+ existing.buffer += text;
1996
+ existing.flush = flush;
1997
+ } else {
1998
+ this.pending.set(key, { buffer: text, flush });
1999
+ }
2000
+ this.schedule();
2001
+ }
2002
+ schedule() {
2003
+ if (this.scheduled) return;
2004
+ this.scheduled = true;
2005
+ scheduleRaf(() => {
2006
+ this.scheduled = false;
2007
+ this.drain();
2008
+ });
2009
+ }
2010
+ drain() {
2011
+ if (this.pending.size === 0) return;
2012
+ const batch = Array.from(this.pending.entries());
2013
+ this.pending.clear();
2014
+ for (const [key, p] of batch) {
2015
+ if (p.buffer) p.flush(key, p.buffer);
2016
+ }
2017
+ }
2018
+ /** Discard a key's buffered text without flushing. Used when the thinking
2019
+ * buffer is cleared (model started replying) so a pending thinking delta
2020
+ * can't re-populate it a frame later. */
2021
+ drop(key) {
2022
+ this.pending.delete(key);
2023
+ }
2024
+ /** Drain a single key immediately (if buffered). Safe to call when empty. */
2025
+ flush(key) {
2026
+ const p = this.pending.get(key);
2027
+ if (!p) return;
2028
+ this.pending.delete(key);
2029
+ if (p.buffer) p.flush(key, p.buffer);
2030
+ }
2031
+ /** Drain every buffered key immediately. Call at run end / before finalize. */
2032
+ flushAll() {
2033
+ this.drain();
2034
+ }
2035
+ };
2036
+ var streamCoalescer = new StreamCoalescer();
2037
+
1927
2038
  // src/hooks/ws-handlers.ts
1928
2039
  function handleSessionStart(msg) {
1929
2040
  const vizStart = wsToVizEvent("session.start", msg.payload);
@@ -2095,6 +2206,7 @@ function handleProviderResponse(msg) {
2095
2206
  if (payload.stopReason !== "tool_use" && payload.stopReason !== "tool_call") useChatStore.getState().setLoading(false);
2096
2207
  const id = useChatStore.getState().currentAssistantMessageId;
2097
2208
  if (id) {
2209
+ streamCoalescer.flush(id);
2098
2210
  useChatStore.getState().finalizeMessage(id);
2099
2211
  if (payload.usage.output > 0) useChatStore.getState().updateMessage(id, { usage: payload.usage });
2100
2212
  }
@@ -2124,17 +2236,26 @@ function handleIterationStarted(msg) {
2124
2236
  function handleTextDelta(msg) {
2125
2237
  const payload = msg.payload;
2126
2238
  useChatStore.getState().clearThinking();
2239
+ streamCoalescer.drop("__thinking__");
2127
2240
  let id = useChatStore.getState().currentAssistantMessageId;
2128
2241
  if (!id) {
2129
2242
  id = useChatStore.getState().addMessage({ role: "assistant", content: "", streaming: true });
2130
2243
  useChatStore.getState().setCurrentAssistantMessage(id);
2131
2244
  }
2132
- useChatStore.getState().appendToMessage(id, payload.text);
2245
+ streamCoalescer.push(
2246
+ id,
2247
+ payload.text,
2248
+ (mid, text) => useChatStore.getState().appendToMessage(mid, text)
2249
+ );
2133
2250
  }
2134
2251
  function handleThinkingDelta(msg) {
2135
2252
  const payload = msg.payload;
2136
2253
  if (!payload.text) return;
2137
- useChatStore.getState().appendThinking(payload.text);
2254
+ streamCoalescer.push(
2255
+ "__thinking__",
2256
+ payload.text,
2257
+ (_k, text) => useChatStore.getState().appendThinking(text)
2258
+ );
2138
2259
  }
2139
2260
  function handleToolStarted(msg) {
2140
2261
  const payload = msg.payload;
@@ -2144,6 +2265,7 @@ function handleToolStarted(msg) {
2144
2265
  return;
2145
2266
  }
2146
2267
  useChatStore.getState().clearThinking();
2268
+ streamCoalescer.drop("__thinking__");
2147
2269
  useChatStore.getState().setCurrentAssistantMessage(null);
2148
2270
  const id = useChatStore.getState().addMessage({ role: "tool", content: "", toolName: payload.name, toolInput: payload.input, toolUseId: payload.id });
2149
2271
  useChatStore.getState().setCurrentToolId(id);
@@ -2157,7 +2279,15 @@ function handleToolProgress(msg) {
2157
2279
  const owner = messages.find((m) => m.toolUseId === payload.id);
2158
2280
  if (!owner) return;
2159
2281
  const prefix = payload.event?.type === "warning" ? "\u26A0 " : "";
2160
- useChatStore.getState().appendToolProgress(owner.id, prefix + text);
2282
+ streamCoalescer.push(
2283
+ owner.id,
2284
+ `${prefix}${text}
2285
+ `,
2286
+ (oid, buffered) => useChatStore.getState().appendToolProgressLines(
2287
+ oid,
2288
+ buffered.split("\n").filter((l) => l.length > 0)
2289
+ )
2290
+ );
2161
2291
  }
2162
2292
  function handleToolExecuted(msg) {
2163
2293
  const payload = msg.payload;
@@ -2165,6 +2295,7 @@ function handleToolExecuted(msg) {
2165
2295
  const owner = payload.id ? messages.find((m) => m.toolUseId === payload.id) : currentToolId ? messages.find((m) => m.id === currentToolId) : void 0;
2166
2296
  if (owner?.toolResult !== void 0) return;
2167
2297
  if (owner) {
2298
+ streamCoalescer.drop(owner.id);
2168
2299
  useChatStore.getState().setToolResult(owner.id, payload.output ?? "", payload.ok);
2169
2300
  useChatStore.getState().updateMessage(owner.id, { toolDurationMs: payload.durationMs });
2170
2301
  }
@@ -2185,6 +2316,7 @@ function handleToolConfirmNeeded(msg) {
2185
2316
  }
2186
2317
  function handleRunResult(msg) {
2187
2318
  const payload = msg.payload;
2319
+ streamCoalescer.flushAll();
2188
2320
  useSessionStore.getState().setIteration(null);
2189
2321
  useChatStore.getState().setLoading(false);
2190
2322
  useChatStore.getState().setCurrentAssistantMessage(null);
@@ -3062,11 +3194,103 @@ import {
3062
3194
  import { useCallback as useCallback2, useEffect as useEffect5, useMemo, useRef as useRef2, useState as useState3 } from "react";
3063
3195
 
3064
3196
  // src/components/ChatView/utils.ts
3197
+ import { expectDefined as expectDefined3 } from "@wrongstack/core";
3065
3198
  function fmtTok(n) {
3066
3199
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
3067
3200
  if (n >= 1e3) return `${(n / 1e3).toFixed(n >= 1e4 ? 0 : 1)}k`;
3068
3201
  return String(n);
3069
3202
  }
3203
+ var dayKey = (ts) => {
3204
+ const d = new Date(ts);
3205
+ return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
3206
+ };
3207
+ function dayLabel(ts, now) {
3208
+ const d = new Date(ts);
3209
+ const today = new Date(now);
3210
+ const yest = new Date(now - 864e5);
3211
+ if (dayKey(ts) === dayKey(today.getTime())) return "Today";
3212
+ if (dayKey(ts) === dayKey(yest.getTime())) return "Yesterday";
3213
+ return d.toLocaleDateString(void 0, {
3214
+ weekday: "short",
3215
+ month: "short",
3216
+ day: "numeric",
3217
+ year: d.getFullYear() === today.getFullYear() ? void 0 : "numeric"
3218
+ });
3219
+ }
3220
+ function buildChatRows(messages, now = Date.now()) {
3221
+ const groups = [];
3222
+ for (let i = 0; i < messages.length; i++) {
3223
+ const m = expectDefined3(messages[i]);
3224
+ if (m.role === "tool") {
3225
+ const last = groups[groups.length - 1];
3226
+ if (last && last.kind === "tools") {
3227
+ last.tools.push(m);
3228
+ } else {
3229
+ groups.push({ kind: "tools", tools: [m], key: m.id });
3230
+ }
3231
+ } else {
3232
+ const prev = messages[i - 1];
3233
+ groups.push({ kind: "msg", message: m, isFirst: !prev || prev.role !== m.role });
3234
+ }
3235
+ }
3236
+ const turns = [];
3237
+ for (const g of groups) {
3238
+ if (g.kind === "msg" && g.message.role === "user") {
3239
+ turns.push({ kind: "user", message: g.message, key: g.message.id });
3240
+ continue;
3241
+ }
3242
+ const last = turns[turns.length - 1];
3243
+ if (last && last.kind === "agent") {
3244
+ last.items.push(g);
3245
+ } else {
3246
+ const key = g.kind === "msg" ? g.message.id : g.key;
3247
+ turns.push({ kind: "agent", items: [g], key });
3248
+ }
3249
+ }
3250
+ const turnTs = (t) => {
3251
+ if (t.kind === "user") return t.message.timestamp;
3252
+ const first = expectDefined3(t.items[0]);
3253
+ return first.kind === "msg" ? first.message.timestamp : first.tools[0]?.timestamp ?? 0;
3254
+ };
3255
+ const rows = [];
3256
+ let prevDay = null;
3257
+ for (let idx = 0; idx < turns.length; idx++) {
3258
+ const t = expectDefined3(turns[idx]);
3259
+ const ts = turnTs(t);
3260
+ const day = dayKey(ts);
3261
+ if (day !== prevDay) {
3262
+ rows.push({ kind: "day", key: `day-${day}-${idx}`, label: dayLabel(ts, now) });
3263
+ prevDay = day;
3264
+ }
3265
+ if (t.kind === "user") {
3266
+ rows.push({ kind: "user", key: t.key, message: t.message });
3267
+ continue;
3268
+ }
3269
+ const isLastTurn = idx === turns.length - 1;
3270
+ const items = t.items.map((g, gi) => {
3271
+ const isContinuation = gi > 0;
3272
+ if (g.kind === "msg") {
3273
+ return {
3274
+ kind: "msg",
3275
+ key: g.message.id,
3276
+ message: g.message,
3277
+ isFirst: !isContinuation && g.isFirst,
3278
+ isContinuation
3279
+ };
3280
+ }
3281
+ return {
3282
+ kind: "tools",
3283
+ key: g.key,
3284
+ tools: g.tools,
3285
+ isContinuation,
3286
+ isLastGroup: gi === t.items.length - 1,
3287
+ hasRunningTool: g.tools.some((tt) => tt.toolResult === void 0)
3288
+ };
3289
+ });
3290
+ rows.push({ kind: "agent", key: t.key, items, isLastTurn });
3291
+ }
3292
+ return rows;
3293
+ }
3070
3294
 
3071
3295
  // src/components/ContextBar.tsx
3072
3296
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -4425,7 +4649,7 @@ function TaskBoard({
4425
4649
  }
4426
4650
 
4427
4651
  // src/components/WorktreeGraph.tsx
4428
- import { expectDefined as expectDefined3 } from "@wrongstack/core";
4652
+ import { expectDefined as expectDefined4 } from "@wrongstack/core";
4429
4653
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
4430
4654
  var LANE_COLORS = ["#3b82f6", "#06b6d4", "#22c55e", "#eab308", "#f97316", "#a855f7", "#ec4899"];
4431
4655
  var shortBranch = (b) => b.replace(/^wstack\/ap\//, "");
@@ -4464,7 +4688,7 @@ function WorktreeGraph({
4464
4688
  /* @__PURE__ */ jsx9("text", { x: trunkX - 4, y: 14, fontSize: 11, fill: "#9ca3af", children: baseBranch || "HEAD" }),
4465
4689
  /* @__PURE__ */ jsx9("circle", { cx: trunkX, cy: 20, r: 5, fill: "#F93951" }),
4466
4690
  nodes.map((n) => {
4467
- const e = EDGE_STATE[n.handle.status] ?? expectDefined3(EDGE_STATE.active);
4691
+ const e = EDGE_STATE[n.handle.status] ?? expectDefined4(EDGE_STATE.active);
4468
4692
  const merged = n.handle.status === "merged";
4469
4693
  const conflict = n.handle.status === "needs-review" || n.handle.status === "failed";
4470
4694
  return /* @__PURE__ */ jsxs8("g", { className: "transition-all duration-500", children: [
@@ -4792,7 +5016,6 @@ function AutoPhaseView({ onClose }) {
4792
5016
  }
4793
5017
 
4794
5018
  // src/components/ChatView/index.tsx
4795
- import { expectDefined as expectDefined12 } from "@wrongstack/core";
4796
5019
  import {
4797
5020
  Activity as Activity3,
4798
5021
  ArrowDown as ArrowDown3,
@@ -4806,7 +5029,8 @@ import {
4806
5029
  Terminal as Terminal4,
4807
5030
  Zap as Zap5
4808
5031
  } from "lucide-react";
4809
- import { useCallback as useCallback10, useEffect as useEffect18, useRef as useRef14, useState as useState24 } from "react";
5032
+ import { memo as memo5, useCallback as useCallback10, useEffect as useEffect18, useMemo as useMemo8, useRef as useRef14, useState as useState24 } from "react";
5033
+ import { VList } from "virtua";
4810
5034
 
4811
5035
  // src/components/AutonomyPicker.tsx
4812
5036
  import {
@@ -4925,7 +5149,7 @@ function AutonomyPicker({
4925
5149
  }
4926
5150
 
4927
5151
  // src/components/ChatInput.tsx
4928
- import { expectDefined as expectDefined6 } from "@wrongstack/core";
5152
+ import { expectDefined as expectDefined7 } from "@wrongstack/core";
4929
5153
  import { Pencil, Send, Square as Square2, Sparkles as Sparkles3 } from "lucide-react";
4930
5154
  import { useCallback as useCallback5, useEffect as useEffect10, useRef as useRef7, useState as useState9 } from "react";
4931
5155
 
@@ -5436,7 +5660,7 @@ function renderGroupedList(filtered, index, dispatch, setIndex) {
5436
5660
  }
5437
5661
 
5438
5662
  // src/components/FilePicker.tsx
5439
- import { expectDefined as expectDefined4 } from "@wrongstack/core";
5663
+ import { expectDefined as expectDefined5 } from "@wrongstack/core";
5440
5664
  import { FileText as FileText2, Folder } from "lucide-react";
5441
5665
  import { useEffect as useEffect8, useRef as useRef5, useState as useState7 } from "react";
5442
5666
  import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
@@ -5478,7 +5702,7 @@ function FilePicker({ query, onPick, onClose }) {
5478
5702
  } else if (e.key === "Enter" || e.key === "Tab") {
5479
5703
  if (files.length === 0) return;
5480
5704
  e.preventDefault();
5481
- onPick(expectDefined4(files[index]));
5705
+ onPick(expectDefined5(files[index]));
5482
5706
  } else if (e.key === "Escape") {
5483
5707
  e.preventDefault();
5484
5708
  onClose();
@@ -5516,7 +5740,7 @@ function FilePicker({ query, onPick, onClose }) {
5516
5740
  }
5517
5741
 
5518
5742
  // src/components/ChatInput/slash-commands.ts
5519
- import { expectDefined as expectDefined5 } from "@wrongstack/core";
5743
+ import { expectDefined as expectDefined6 } from "@wrongstack/core";
5520
5744
  var SLASH_COMMANDS = [
5521
5745
  // Session
5522
5746
  { name: "/new", category: "Session", description: "Start a brand-new session (fresh on disk and in memory)" },
@@ -5543,12 +5767,12 @@ var SLASH_COMMANDS = [
5543
5767
  // Config
5544
5768
  { name: "/settings", category: "Config", aliases: ["/model"], description: "Open settings (provider/model/keys)" },
5545
5769
  { name: "/enhance", category: "Config", description: "Toggle prompt refinement before sending" },
5546
- { name: "/abort", category: "Config", aliases: ["/stop"], description: "Abort the current run" },
5770
+ { name: "/interrupt", category: "Run", aliases: ["/abort", "/stop", "/int"], description: "Stop the current run (abort the in-flight request)" },
5547
5771
  // App
5548
5772
  { name: "/help", category: "App", description: "Show every slash command and what it does" },
5549
5773
  { name: "/exit", category: "App", description: "Exit the session and close WebUI" }
5550
5774
  ];
5551
- var SLASH_CATEGORY_ORDER = ["Session", "Inspect", "Config", "App"];
5775
+ var SLASH_CATEGORY_ORDER = ["Run", "Session", "Inspect", "Config", "App"];
5552
5776
  function matchSlash(query) {
5553
5777
  const q = query.toLowerCase();
5554
5778
  if (q === "/" || q === "") return SLASH_COMMANDS;
@@ -5559,7 +5783,7 @@ function matchSlash(query) {
5559
5783
  function detectAtMention(value, cursor) {
5560
5784
  let i = cursor - 1;
5561
5785
  while (i >= 0) {
5562
- const c = expectDefined5(value[i]);
5786
+ const c = expectDefined6(value[i]);
5563
5787
  if (c === "@") {
5564
5788
  const prev = i > 0 ? value[i - 1] : "";
5565
5789
  if (i === 0 || /\s/.test(prev ?? "")) {
@@ -6160,8 +6384,10 @@ function ChatInput({
6160
6384
  downloadChatAsMarkdown();
6161
6385
  addMessage({ role: "assistant", content: "\u{1F4E5} Chat exported to your downloads folder." });
6162
6386
  return true;
6387
+ case "/interrupt":
6163
6388
  case "/abort":
6164
6389
  case "/stop":
6390
+ case "/int":
6165
6391
  sendAbort();
6166
6392
  setLoading(false);
6167
6393
  return true;
@@ -6367,7 +6593,7 @@ function ChatInput({
6367
6593
  setLoading(false);
6368
6594
  const all = useChatStore.getState().messages;
6369
6595
  for (let i = all.length - 1; i >= 0; i--) {
6370
- const m = expectDefined6(all[i]);
6596
+ const m = expectDefined7(all[i]);
6371
6597
  if (m.role === "user" && m.content) {
6372
6598
  setInput(m.content);
6373
6599
  requestAnimationFrame(() => {
@@ -7041,7 +7267,7 @@ function CheckpointTimeline({
7041
7267
  }
7042
7268
 
7043
7269
  // src/components/ContextModePicker.tsx
7044
- import { expectDefined as expectDefined7 } from "@wrongstack/core";
7270
+ import { expectDefined as expectDefined8 } from "@wrongstack/core";
7045
7271
  import { Check as Check2, ChevronDown as ChevronDown3, Gauge as Gauge2, Wrench as Wrench4, Zap as Zap3, FileSearch } from "lucide-react";
7046
7272
  import { useCallback as useCallback7, useEffect as useEffect12, useRef as useRef9, useState as useState11 } from "react";
7047
7273
  import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
@@ -7100,7 +7326,7 @@ function ContextModePicker() {
7100
7326
  setOpen(false);
7101
7327
  }, [client2]);
7102
7328
  const items = contextModes.length > 0 ? contextModes : FALLBACK_MODES;
7103
- const active = items.find((m) => m.id === contextMode) ?? expectDefined7(items[0]);
7329
+ const active = items.find((m) => m.id === contextMode) ?? expectDefined8(items[0]);
7104
7330
  return /* @__PURE__ */ jsxs17("div", { ref: rootRef, className: "relative shrink-0", children: [
7105
7331
  /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-1", children: [
7106
7332
  /* @__PURE__ */ jsxs17(
@@ -7386,7 +7612,7 @@ function CostChip() {
7386
7612
  }
7387
7613
 
7388
7614
  // src/components/MessageBubble/index.tsx
7389
- import { expectDefined as expectDefined10 } from "@wrongstack/core";
7615
+ import { expectDefined as expectDefined11 } from "@wrongstack/core";
7390
7616
 
7391
7617
  // src/lib/tool-summary.ts
7392
7618
  var FALLBACK_HEAD_FIELDS = [
@@ -7523,7 +7749,7 @@ import ReactMarkdown from "react-markdown";
7523
7749
  import remarkGfm from "remark-gfm";
7524
7750
 
7525
7751
  // src/components/DiffView.tsx
7526
- import { expectDefined as expectDefined8 } from "@wrongstack/core";
7752
+ import { expectDefined as expectDefined9 } from "@wrongstack/core";
7527
7753
  import { memo, useMemo as useMemo3 } from "react";
7528
7754
  import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
7529
7755
  var DiffView = memo(function DiffView2({ oldText, newText, caption }) {
@@ -7595,8 +7821,8 @@ function computeDiff(oldText, newText) {
7595
7821
  const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
7596
7822
  for (let i2 = n - 1; i2 >= 0; i2--) {
7597
7823
  for (let j2 = m - 1; j2 >= 0; j2--) {
7598
- if (a[i2] === b[j2]) expectDefined8(dp[i2])[j2] = expectDefined8(dp[i2 + 1]?.[j2 + 1]) + 1;
7599
- else expectDefined8(dp[i2])[j2] = Math.max(expectDefined8(dp[i2 + 1]?.[j2]), expectDefined8(dp[i2]?.[j2 + 1]));
7824
+ if (a[i2] === b[j2]) expectDefined9(dp[i2])[j2] = expectDefined9(dp[i2 + 1]?.[j2 + 1]) + 1;
7825
+ else expectDefined9(dp[i2])[j2] = Math.max(expectDefined9(dp[i2 + 1]?.[j2]), expectDefined9(dp[i2]?.[j2 + 1]));
7600
7826
  }
7601
7827
  }
7602
7828
  const rows = [];
@@ -7604,19 +7830,19 @@ function computeDiff(oldText, newText) {
7604
7830
  let j = 0;
7605
7831
  while (i < n && j < m) {
7606
7832
  if (a[i] === b[j]) {
7607
- rows.push({ kind: "ctx", text: expectDefined8(a[i]) });
7833
+ rows.push({ kind: "ctx", text: expectDefined9(a[i]) });
7608
7834
  i++;
7609
7835
  j++;
7610
- } else if (expectDefined8(dp[i + 1]?.[j]) >= expectDefined8(dp[i]?.[j + 1])) {
7611
- rows.push({ kind: "del", text: expectDefined8(a[i]) });
7836
+ } else if (expectDefined9(dp[i + 1]?.[j]) >= expectDefined9(dp[i]?.[j + 1])) {
7837
+ rows.push({ kind: "del", text: expectDefined9(a[i]) });
7612
7838
  i++;
7613
7839
  } else {
7614
- rows.push({ kind: "add", text: expectDefined8(b[j]) });
7840
+ rows.push({ kind: "add", text: expectDefined9(b[j]) });
7615
7841
  j++;
7616
7842
  }
7617
7843
  }
7618
- while (i < n) rows.push({ kind: "del", text: expectDefined8(a[i++]) });
7619
- while (j < m) rows.push({ kind: "add", text: expectDefined8(b[j++]) });
7844
+ while (i < n) rows.push({ kind: "del", text: expectDefined9(a[i++]) });
7845
+ while (j < m) rows.push({ kind: "add", text: expectDefined9(b[j++]) });
7620
7846
  return rows;
7621
7847
  }
7622
7848
  function diffFromToolInput(toolName, input) {
@@ -8022,12 +8248,12 @@ var markdownComponents = {
8022
8248
  const match = /language-(\w+)/.exec(className ?? "");
8023
8249
  const codeText = String(children ?? "").replace(/\n$/, "");
8024
8250
  if (inline || !match) {
8025
- return /* @__PURE__ */ jsx24("code", { className: cn("rounded bg-muted/60 px-1.5 py-0.5 text-[0.85em] font-mono", className), ...props, children });
8251
+ return /* @__PURE__ */ jsx24("code", { className: cn("rounded border border-border/60 px-1.5 py-0.5 text-[0.85em] font-mono", className), ...props, children });
8026
8252
  }
8027
8253
  const lines = useMemo6(() => codeText.split("\n"), [codeText]);
8028
8254
  const hasLineNumbers = lines.length > 1;
8029
- return /* @__PURE__ */ jsxs22("div", { className: "not-prose relative my-3 rounded-lg border bg-muted/30 overflow-hidden group/codeblock", children: [
8030
- /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between px-3 py-1 border-b bg-muted/40 text-xs", children: [
8255
+ return /* @__PURE__ */ jsxs22("div", { className: "not-prose relative my-3 rounded-lg border border-border overflow-hidden group/codeblock", children: [
8256
+ /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between px-3 py-1 border-b border-border text-xs", children: [
8031
8257
  /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
8032
8258
  /* @__PURE__ */ jsx24(FileCode2, { className: "h-3 w-3 text-muted-foreground" }),
8033
8259
  /* @__PURE__ */ jsx24("span", { className: "font-mono text-muted-foreground font-medium", children: match[1] }),
@@ -8044,13 +8270,13 @@ var markdownComponents = {
8044
8270
  "pre",
8045
8271
  {
8046
8272
  "aria-hidden": true,
8047
- className: "text-xs font-mono leading-[1.55] py-3 pl-3 pr-2 text-muted-foreground/40 select-none border-r border-border/30 bg-muted/10 tabular-nums text-right shrink-0",
8273
+ className: "text-xs font-mono leading-[1.55] py-3 pl-3 pr-2 text-muted-foreground/40 select-none border-r border-border/30 tabular-nums text-right shrink-0",
8048
8274
  children: lines.map((_, i) => /* @__PURE__ */ jsx24("div", { children: i + 1 }, i))
8049
8275
  }
8050
8276
  ),
8051
8277
  /* @__PURE__ */ jsx24("pre", { className: "overflow-x-auto py-3 px-3 text-xs leading-[1.55] font-mono flex-1", children: /* @__PURE__ */ jsx24("code", { className: cn("hljs", className), ...props, children }) })
8052
8278
  ] }) : /* @__PURE__ */ jsx24("pre", { className: "overflow-x-auto p-3 text-xs leading-relaxed font-mono max-h-[40rem]", children: /* @__PURE__ */ jsx24("code", { className: cn("hljs", className), ...props, children }) }),
8053
- /* @__PURE__ */ jsx24("div", { className: "pointer-events-none absolute bottom-8 left-0 right-0 h-8 bg-gradient-to-t from-muted/30 to-transparent opacity-0 group-hover/codeblock:opacity-100 transition-opacity" })
8279
+ /* @__PURE__ */ jsx24("div", { className: "pointer-events-none absolute bottom-8 left-0 right-0 h-8 bg-gradient-to-t from-black/10 to-transparent opacity-0 group-hover/codeblock:opacity-100 transition-opacity" })
8054
8280
  ] });
8055
8281
  }
8056
8282
  };
@@ -8092,13 +8318,13 @@ function CopyButton({
8092
8318
  }
8093
8319
 
8094
8320
  // src/components/MessageBubble/ErrorBody.tsx
8095
- import { expectDefined as expectDefined9 } from "@wrongstack/core";
8321
+ import { expectDefined as expectDefined10 } from "@wrongstack/core";
8096
8322
  import { useState as useState16 } from "react";
8097
8323
  import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
8098
8324
  function detectStackBoundary(text) {
8099
8325
  const lines = text.split("\n");
8100
8326
  for (let i = 0; i < lines.length; i++) {
8101
- const ln = expectDefined9(lines[i]);
8327
+ const ln = expectDefined10(lines[i]);
8102
8328
  if (/^\s*at\s+\S+.*\(.*:\d+:\d+\)\s*$/.test(ln)) return i;
8103
8329
  if (/^\s*at\s+\S+\.\S+\(\S+\.java:\d+\)\s*$/.test(ln)) return i;
8104
8330
  if (/^\s+File "[^"]+", line \d+/.test(ln)) return i;
@@ -8229,7 +8455,7 @@ var MessageBubble = memo3(function MessageBubble2({
8229
8455
  if (message.role !== "assistant" || isLoading) return false;
8230
8456
  const all = useChatStore.getState().messages;
8231
8457
  for (let i = all.length - 1; i >= 0; i--) {
8232
- const m = expectDefined10(all[i]);
8458
+ const m = expectDefined11(all[i]);
8233
8459
  if (m.role === "assistant") return m.id === message.id;
8234
8460
  }
8235
8461
  return false;
@@ -8246,7 +8472,7 @@ var MessageBubble = memo3(function MessageBubble2({
8246
8472
  }
8247
8473
  }
8248
8474
  if (userIdx === -1) return;
8249
- const userMsg = expectDefined10(all[userIdx]);
8475
+ const userMsg = expectDefined11(all[userIdx]);
8250
8476
  truncateAfter(userMsg.id);
8251
8477
  addMessage({ role: "user", content: userMsg.content });
8252
8478
  setLoading(true);
@@ -8723,8 +8949,10 @@ function SearchOverlay() {
8723
8949
  const query = useUIStore((s) => s.searchQuery);
8724
8950
  const setQuery = useUIStore((s) => s.setSearchQuery);
8725
8951
  const messages = useChatStore((s) => s.messages);
8952
+ const requestScrollToMessage = useUIStore((s) => s.requestScrollToMessage);
8726
8953
  const inputRef = useRef13(null);
8727
8954
  const [activeHit, setActiveHit] = useState21(0);
8955
+ const [repaintNonce, setRepaintNonce] = useState21(0);
8728
8956
  useEffect16(() => {
8729
8957
  if (open) requestAnimationFrame(() => inputRef.current?.focus());
8730
8958
  }, [open]);
@@ -8794,15 +9022,18 @@ function SearchOverlay() {
8794
9022
  highlights.delete("chat-search-active");
8795
9023
  }
8796
9024
  return clear;
8797
- }, [query, hits, activeHit, open]);
9025
+ }, [query, hits, activeHit, open, repaintNonce]);
8798
9026
  useEffect16(() => {
8799
9027
  const id = hits[activeHit];
8800
9028
  if (!id) return;
8801
- const el = document.querySelector(`[data-message-id="${id}"]`);
8802
- if (el) {
8803
- el.scrollIntoView({ behavior: "smooth", block: "center" });
8804
- }
8805
- }, [hits, activeHit]);
9029
+ requestScrollToMessage(id);
9030
+ let n = 0;
9031
+ let raf = requestAnimationFrame(function tick() {
9032
+ setRepaintNonce((v) => v + 1);
9033
+ if (++n < 3) raf = requestAnimationFrame(tick);
9034
+ });
9035
+ return () => cancelAnimationFrame(raf);
9036
+ }, [hits, activeHit, requestScrollToMessage]);
8806
9037
  if (!open) return null;
8807
9038
  const step = (dir) => {
8808
9039
  if (hits.length === 0) return;
@@ -8876,7 +9107,7 @@ function SearchOverlay() {
8876
9107
  }
8877
9108
 
8878
9109
  // src/components/ToolGroup.tsx
8879
- import { expectDefined as expectDefined11 } from "@wrongstack/core";
9110
+ import { expectDefined as expectDefined12 } from "@wrongstack/core";
8880
9111
  import { CheckCircle2 as CheckCircle26, ChevronDown as ChevronDown7, ChevronRight as ChevronRight5, Loader2 as Loader22, Terminal as Terminal3, XCircle as XCircle6 } from "lucide-react";
8881
9112
  import { memo as memo4, useState as useState22 } from "react";
8882
9113
  import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
@@ -8894,7 +9125,7 @@ var ToolGroup = memo4(function ToolGroup2({
8894
9125
  }) {
8895
9126
  const [open, setOpen] = useState22(defaultOpen);
8896
9127
  if (tools.length === 1) {
8897
- return /* @__PURE__ */ jsx32(MessageBubble, { message: expectDefined11(tools[0]), isFirst: true, isContinuation });
9128
+ return /* @__PURE__ */ jsx32(MessageBubble, { message: expectDefined12(tools[0]), isFirst: true, isContinuation });
8898
9129
  }
8899
9130
  const running = tools.filter((t) => t.toolResult === void 0).length;
8900
9131
  const errored = tools.filter((t) => t.isError).length;
@@ -8942,13 +9173,13 @@ var ToolGroup = memo4(function ToolGroup2({
8942
9173
  import {
8943
9174
  ArchiveRestore as ArchiveRestore2,
8944
9175
  ArrowRight as ArrowRight3,
8945
- Bug,
8946
9176
  Clock as Clock7,
9177
+ Crosshair,
8947
9178
  KeyRound,
8948
9179
  Keyboard as Keyboard2,
9180
+ Lightbulb as Lightbulb2,
8949
9181
  Search as Search3,
8950
9182
  Sparkles as Sparkles4,
8951
- Wrench as Wrench5,
8952
9183
  Zap as Zap4
8953
9184
  } from "lucide-react";
8954
9185
  import { useEffect as useEffect17, useState as useState23 } from "react";
@@ -8956,46 +9187,46 @@ import { Fragment as Fragment8, jsx as jsx33, jsxs as jsxs31 } from "react/jsx-r
8956
9187
  var CARDS = [
8957
9188
  {
8958
9189
  icon: Search3,
8959
- title: "Explore",
8960
- hint: "Understand the code before changing it",
9190
+ title: "Understand",
9191
+ hint: "Explore and analyze the codebase",
8961
9192
  tone: "text-blue-600 dark:text-blue-400 bg-blue-500/10 border-blue-500/20",
8962
9193
  prompts: [
8963
- "Walk me through this codebase: what are the top-level packages or modules, what does each do, and how do they depend on one another? What cross-cutting patterns or abstractions should I understand first?",
8964
- "Find the public API surface of this project \u2014 all exported functions, classes, and types that external consumers rely on. Flag any that lack documentation or have unclear contracts.",
8965
- "Map the data flow for a single user action from entry point to persistence. Where does validation happen? Where are side effects triggered? Show me the call chain and any middleware involved."
9194
+ "Map out the structure of this codebase: what are the main modules or components, how do they depend on each other, and what are the key patterns used throughout?",
9195
+ "Find and document the public API surface \u2014 all exported interfaces, functions, and types that other parts of the system depend on.",
9196
+ "Trace the flow of data through the system for a typical operation. Where does input validation happen? Where are side effects triggered?"
8966
9197
  ]
8967
9198
  },
8968
9199
  {
8969
- icon: Wrench5,
8970
- title: "Build",
8971
- hint: "Add a feature end-to-end",
9200
+ icon: Lightbulb2,
9201
+ title: "Create",
9202
+ hint: "Build new features and functionality",
8972
9203
  tone: "text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 border-emerald-500/20",
8973
9204
  prompts: [
8974
- "Add a new end-to-end feature. Walk through the layers: data model, API/serialization, business logic, UI (if applicable), and tests. Use existing patterns in this codebase rather than inventing new ones.",
8975
- "Write comprehensive tests for an existing module that has low coverage. Cover happy paths, edge cases, and error states. Use whatever test runner and patterns this project already uses.",
8976
- "Add structured logging or observability to a critical code path. Use the project\u2019s existing logging conventions. Make sure errors carry enough context to debug without re-running."
9205
+ "Add a new feature that covers the full stack: data model, business logic, and any UI or API layers. Follow existing patterns in this codebase.",
9206
+ "Write comprehensive tests for a module with low coverage. Include happy paths, edge cases, and error scenarios.",
9207
+ "Add observability to a critical path \u2014 structured logging, error tracking, or metrics that help diagnose issues in production."
8977
9208
  ]
8978
9209
  },
8979
9210
  {
8980
- icon: Bug,
8981
- title: "Debug",
8982
- hint: "Track a problem to its root cause",
9211
+ icon: Crosshair,
9212
+ title: "Investigate",
9213
+ hint: "Debug issues and find root causes",
8983
9214
  tone: "text-amber-600 dark:text-amber-400 bg-amber-500/10 border-amber-500/20",
8984
9215
  prompts: [
8985
- "Something isn't behaving as expected \u2014 data looks wrong, a feature silently fails, or state drifts over time. Help me trace it: start from the symptom, follow the code path, and identify where the logic diverges from intent.",
8986
- "The app works fine locally but breaks in production or CI. Check for environment differences, missing config, race conditions, or infrastructure-level assumptions that might explain the gap.",
8987
- "Performance degrades under load or over time. Profile the hot path, identify bottlenecks (N+1 queries, blocking I/O, large allocations, expensive renders), and propose targeted fixes with measurable impact."
9216
+ "Something isn't working as expected \u2014 help me trace from the symptom to the root cause. Follow the code path and identify where behavior diverges from intent.",
9217
+ "There's a difference between how this works locally versus in production or CI. Check for environment differences, configuration issues, or hidden assumptions.",
9218
+ "Performance is degrading. Identify the bottlenecks \u2014 whether N+1 queries, blocking I/O, unnecessary allocations, or something else \u2014 and propose targeted fixes."
8988
9219
  ]
8989
9220
  },
8990
9221
  {
8991
9222
  icon: Sparkles4,
8992
- title: "Refactor",
8993
- hint: "Clean up without breaking behavior",
9223
+ title: "Improve",
9224
+ hint: "Refactor and optimize existing code",
8994
9225
  tone: "text-violet-600 dark:text-violet-400 bg-violet-500/10 border-violet-500/20",
8995
9226
  prompts: [
8996
- "Find duplicated or near-duplicated logic across the codebase. Extract the shared pieces into a single module or utility, update call sites, and ensure the existing tests still pass.",
8997
- "Identify modules that have grown too large or have too many responsibilities. Propose a split that respects the project\u2019s existing structure, keeps the public API stable, and can be done incrementally.",
8998
- "Audit error handling across the codebase: are errors propagated consistently? Are they wrapped with enough context? Are there swallowed errors or bare panics? Propose a uniform approach and apply it to the worst offenders."
9227
+ "Find duplicated or similar logic that could be consolidated into shared utilities. Extract the common parts and update the call sites.",
9228
+ "Identify modules that have grown too large or handle too many responsibilities. Propose a cleaner separation that can be done incrementally.",
9229
+ "Review error handling across the codebase: are errors consistent, well-contextualized, and properly propagated? Suggest improvements to the worst cases."
8999
9230
  ]
9000
9231
  }
9001
9232
  ];
@@ -9211,62 +9442,73 @@ function WelcomeScreen() {
9211
9442
  ] });
9212
9443
  }
9213
9444
 
9214
- // src/components/ui/scroll-area.tsx
9215
- import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
9216
- import * as React2 from "react";
9217
- import { jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
9218
- var ScrollArea = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs32(
9219
- ScrollAreaPrimitive.Root,
9220
- {
9221
- ref,
9222
- className: cn("relative overflow-hidden", className),
9223
- ...props,
9224
- children: [
9225
- /* @__PURE__ */ jsx34(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
9226
- /* @__PURE__ */ jsx34(ScrollBar, {}),
9227
- /* @__PURE__ */ jsx34(ScrollAreaPrimitive.Corner, {})
9228
- ]
9229
- }
9230
- ));
9231
- ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
9232
- var ScrollBar = React2.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx34(
9233
- ScrollAreaPrimitive.ScrollAreaScrollbar,
9234
- {
9235
- ref,
9236
- orientation,
9237
- className: cn(
9238
- "flex touch-none select-none transition-colors",
9239
- orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
9240
- orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
9241
- className
9242
- ),
9243
- ...props,
9244
- children: /* @__PURE__ */ jsx34(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
9245
- }
9246
- ));
9247
- ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
9248
-
9249
9445
  // src/components/ChatView/ThinkingBubble.tsx
9250
9446
  import { Brain as Brain2 } from "lucide-react";
9251
- import { jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
9447
+ import { jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
9252
9448
  function ThinkingBubble() {
9253
9449
  const buf = useChatStore((s) => s.thinkingBuffer);
9254
9450
  if (!buf) return null;
9255
9451
  const tailLines = buf.split("\n").slice(-6);
9256
9452
  const tail = tailLines.join("\n").trim();
9257
- return /* @__PURE__ */ jsxs33("div", { className: "flex gap-3 animate-message", children: [
9258
- /* @__PURE__ */ jsx35("div", { className: "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center bg-violet-500/10 text-violet-600 dark:text-violet-400 ring-2 ring-offset-2 ring-offset-background ring-violet-500/20", children: /* @__PURE__ */ jsx35(Brain2, { className: "h-4 w-4 animate-pulse" }) }),
9259
- /* @__PURE__ */ jsxs33("div", { className: "flex flex-col gap-1 max-w-[85%] min-w-0", children: [
9260
- /* @__PURE__ */ jsx35("span", { className: "text-xs font-medium text-violet-600 dark:text-violet-400 px-1", children: "Thinking\u2026" }),
9261
- /* @__PURE__ */ jsx35("div", { className: "rounded-2xl rounded-bl-md px-3 py-2 bg-violet-500/[0.04] border border-violet-500/20 text-foreground/80", children: /* @__PURE__ */ jsx35("pre", { className: "whitespace-pre-wrap break-words font-sans text-xs leading-relaxed italic max-h-32 overflow-hidden", children: tail || "\u2026" }) })
9453
+ return /* @__PURE__ */ jsxs32("div", { className: "flex gap-3 animate-message", children: [
9454
+ /* @__PURE__ */ jsx34("div", { className: "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center bg-violet-500/10 text-violet-600 dark:text-violet-400 ring-2 ring-offset-2 ring-offset-background ring-violet-500/20", children: /* @__PURE__ */ jsx34(Brain2, { className: "h-4 w-4 animate-pulse" }) }),
9455
+ /* @__PURE__ */ jsxs32("div", { className: "flex flex-col gap-1 max-w-[85%] min-w-0", children: [
9456
+ /* @__PURE__ */ jsx34("span", { className: "text-xs font-medium text-violet-600 dark:text-violet-400 px-1", children: "Thinking\u2026" }),
9457
+ /* @__PURE__ */ jsx34("div", { className: "rounded-2xl rounded-bl-md px-3 py-2 bg-violet-500/[0.04] border border-violet-500/20 text-foreground/80", children: /* @__PURE__ */ jsx34("pre", { className: "whitespace-pre-wrap break-words font-sans text-xs leading-relaxed italic max-h-32 overflow-hidden", children: tail || "\u2026" }) })
9262
9458
  ] })
9263
9459
  ] });
9264
9460
  }
9265
9461
 
9266
9462
  // src/components/ChatView/index.tsx
9267
- import { Fragment as Fragment9, jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
9463
+ import { Fragment as Fragment9, jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
9464
+ var ChatRowView = memo5(function ChatRowView2({
9465
+ row,
9466
+ isLoading,
9467
+ compactMode,
9468
+ isFirstRow
9469
+ }) {
9470
+ const wrap = cn(
9471
+ "mx-auto max-w-5xl w-full px-4",
9472
+ isFirstRow && "pt-4",
9473
+ compactMode ? "pb-3" : "pb-6"
9474
+ );
9475
+ if (row.kind === "day") {
9476
+ return /* @__PURE__ */ jsx35("div", { className: wrap, children: /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-3 py-1 text-[11px] text-muted-foreground/70 uppercase tracking-wider font-medium", children: [
9477
+ /* @__PURE__ */ jsx35("div", { className: "flex-1 h-px bg-border/50" }),
9478
+ /* @__PURE__ */ jsx35("span", { children: row.label }),
9479
+ /* @__PURE__ */ jsx35("div", { className: "flex-1 h-px bg-border/50" })
9480
+ ] }) });
9481
+ }
9482
+ if (row.kind === "user") {
9483
+ return /* @__PURE__ */ jsx35("div", { className: wrap, children: /* @__PURE__ */ jsx35(MessageBubble, { message: row.message, isFirst: true }) });
9484
+ }
9485
+ return /* @__PURE__ */ jsx35("div", { className: wrap, children: /* @__PURE__ */ jsx35("div", { className: cn("chat-turn", compactMode ? "space-y-1" : "space-y-1.5"), children: row.items.map((it) => {
9486
+ if (it.kind === "msg") {
9487
+ return /* @__PURE__ */ jsx35(
9488
+ MessageBubble,
9489
+ {
9490
+ message: it.message,
9491
+ isFirst: it.isFirst,
9492
+ isContinuation: it.isContinuation
9493
+ },
9494
+ it.key
9495
+ );
9496
+ }
9497
+ const defaultOpen = row.isLastTurn && it.isLastGroup && isLoading && it.hasRunningTool;
9498
+ return /* @__PURE__ */ jsx35(
9499
+ ToolGroup,
9500
+ {
9501
+ tools: it.tools,
9502
+ defaultOpen,
9503
+ isContinuation: it.isContinuation
9504
+ },
9505
+ it.key
9506
+ );
9507
+ }) }) });
9508
+ });
9268
9509
  function ChatView() {
9269
- const { messages, isLoading } = useChatStore();
9510
+ const messages = useChatStore((s) => s.messages);
9511
+ const isLoading = useChatStore((s) => s.isLoading);
9270
9512
  const sidebarOpen = useUIStore((s) => s.sidebarOpen);
9271
9513
  const toggleSidebar = useUIStore((s) => s.toggleSidebar);
9272
9514
  const compactMode = useUIStore((s) => s.compactMode);
@@ -9297,7 +9539,24 @@ function ChatView() {
9297
9539
  };
9298
9540
  }, [switcherOpen]);
9299
9541
  const { provider, model } = useConfigStore();
9300
- const scrollRef = useRef14(null);
9542
+ const vlistRef = useRef14(null);
9543
+ const rows = useMemo8(() => buildChatRows(messages), [messages]);
9544
+ const childCountRef = useRef14(0);
9545
+ childCountRef.current = rows.length + 1;
9546
+ const rowIndexById = useMemo8(() => {
9547
+ const map = /* @__PURE__ */ new Map();
9548
+ rows.forEach((row, i) => {
9549
+ if (row.kind === "user") map.set(row.message.id, i);
9550
+ else if (row.kind === "agent") {
9551
+ for (const it of row.items) {
9552
+ if (it.kind === "msg") map.set(it.message.id, i);
9553
+ else for (const t of it.tools) map.set(t.id, i);
9554
+ }
9555
+ }
9556
+ });
9557
+ return map;
9558
+ }, [rows]);
9559
+ const scrollTarget = useUIStore((s) => s.scrollTarget);
9301
9560
  const autonomy = useLocalPrefs((s) => s.autonomy);
9302
9561
  const handleAutonomyChange = useCallback10((mode) => {
9303
9562
  useLocalPrefs.getState().set({ autonomy: mode });
@@ -9318,58 +9577,52 @@ function ChatView() {
9318
9577
  const [unreadCount, setUnreadCount] = useState24(0);
9319
9578
  const [scrolledDeep, setScrolledDeep] = useState24(false);
9320
9579
  const lastSeenCount = useRef14(messages.length);
9321
- const getViewport = useCallback10(() => {
9322
- return scrollRef.current?.querySelector("[data-radix-scroll-area-viewport]") ?? null;
9580
+ const handleScroll = useCallback10(() => {
9581
+ const h = vlistRef.current;
9582
+ if (!h) return;
9583
+ const dist = h.scrollSize - h.scrollOffset - h.viewportSize;
9584
+ const nowPinned = dist < 120;
9585
+ setPinnedToBottom(nowPinned);
9586
+ if (nowPinned) {
9587
+ setUnreadCount(0);
9588
+ lastSeenCount.current = useChatStore.getState().messages.length;
9589
+ }
9590
+ setScrolledDeep(h.scrollOffset > h.viewportSize && h.scrollSize > h.viewportSize * 2.5);
9323
9591
  }, []);
9324
9592
  useEffect18(() => {
9325
- const viewport = getViewport();
9326
- if (!viewport) return;
9327
- const onScroll = () => {
9328
- const dist = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
9329
- const nowPinned = dist < 120;
9330
- setPinnedToBottom(nowPinned);
9331
- if (nowPinned) {
9332
- setUnreadCount(0);
9333
- lastSeenCount.current = messages.length;
9334
- }
9335
- const deep = viewport.scrollTop > viewport.clientHeight && viewport.scrollHeight > viewport.clientHeight * 2.5;
9336
- setScrolledDeep(deep);
9337
- };
9338
- viewport.addEventListener("scroll", onScroll, { passive: true });
9339
- return () => viewport.removeEventListener("scroll", onScroll);
9340
- }, [getViewport, messages.length]);
9341
- useEffect18(() => {
9342
- const viewport = getViewport();
9343
- if (!viewport) return;
9593
+ const h = vlistRef.current;
9594
+ if (!h) return;
9344
9595
  if (pinnedToBottom) {
9345
- viewport.scrollTop = viewport.scrollHeight;
9596
+ h.scrollToIndex(childCountRef.current - 1, { align: "end" });
9346
9597
  lastSeenCount.current = messages.length;
9347
9598
  } else {
9348
9599
  const delta = messages.length - lastSeenCount.current;
9349
9600
  if (delta > 0) setUnreadCount(delta);
9350
9601
  }
9351
- }, [messages, pinnedToBottom, getViewport]);
9602
+ }, [messages, pinnedToBottom]);
9352
9603
  useEffect18(() => {
9353
- const viewport = getViewport();
9354
- if (!viewport) return;
9355
- viewport.scrollTop = viewport.scrollHeight;
9356
9604
  setPinnedToBottom(true);
9357
9605
  setUnreadCount(0);
9358
9606
  lastSeenCount.current = useChatStore.getState().messages.length;
9359
- }, [sessionId, getViewport]);
9607
+ requestAnimationFrame(() => {
9608
+ vlistRef.current?.scrollToIndex(childCountRef.current - 1, { align: "end" });
9609
+ });
9610
+ }, [sessionId]);
9611
+ useEffect18(() => {
9612
+ if (!scrollTarget) return;
9613
+ const idx = rowIndexById.get(scrollTarget.id);
9614
+ if (idx === void 0) return;
9615
+ vlistRef.current?.scrollToIndex(idx, { align: "center", smooth: true });
9616
+ }, [scrollTarget, rowIndexById]);
9360
9617
  const scrollToBottom = useCallback10(() => {
9361
- const viewport = getViewport();
9362
- if (!viewport) return;
9363
- viewport.scrollTo({ top: viewport.scrollHeight, behavior: "smooth" });
9618
+ vlistRef.current?.scrollToIndex(childCountRef.current - 1, { align: "end", smooth: true });
9364
9619
  setPinnedToBottom(true);
9365
9620
  setUnreadCount(0);
9366
- lastSeenCount.current = messages.length;
9367
- }, [getViewport, messages.length]);
9621
+ lastSeenCount.current = useChatStore.getState().messages.length;
9622
+ }, []);
9368
9623
  const scrollToTop = useCallback10(() => {
9369
- const viewport = getViewport();
9370
- if (!viewport) return;
9371
- viewport.scrollTo({ top: 0, behavior: "smooth" });
9372
- }, [getViewport]);
9624
+ vlistRef.current?.scrollToIndex(0, { align: "start", smooth: true });
9625
+ }, []);
9373
9626
  const [runStartedAt, setRunStartedAt] = useState24(null);
9374
9627
  const [nowTick, setNowTick] = useState24(() => Date.now());
9375
9628
  const streamAnchor = useRef14(null);
@@ -9398,11 +9651,11 @@ function ChatView() {
9398
9651
  })();
9399
9652
  const stateTone = agentState === "idle" ? "bg-muted text-muted-foreground" : agentState === "streaming" ? "bg-blue-500/10 text-blue-600 dark:text-blue-400" : "bg-amber-500/10 text-amber-600 dark:text-amber-400";
9400
9653
  const hasStatusContent = maxContext > 0 && lastInputTokens > 0 || totalTokens.input > 0 || !!startTime;
9401
- return /* @__PURE__ */ jsxs34("div", { className: "flex flex-col flex-1 min-h-0", children: [
9402
- /* @__PURE__ */ jsxs34("header", { className: "flex flex-col border-b bg-card/95 backdrop-blur-sm supports-[backdrop-filter]:bg-card/80 shrink-0 sticky top-0 z-20", children: [
9403
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center justify-between gap-2 px-3 py-2", children: [
9404
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-1.5 min-w-0 flex-1 overflow-hidden", children: [
9405
- !sidebarOpen && /* @__PURE__ */ jsx36(
9654
+ return /* @__PURE__ */ jsxs33("div", { className: "flex flex-col flex-1 min-h-0", children: [
9655
+ /* @__PURE__ */ jsxs33("header", { className: "flex flex-col border-b bg-card/95 backdrop-blur-sm supports-[backdrop-filter]:bg-card/80 shrink-0 sticky top-0 z-20", children: [
9656
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between gap-2 px-3 py-2", children: [
9657
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-1.5 min-w-0 flex-1 overflow-hidden", children: [
9658
+ !sidebarOpen && /* @__PURE__ */ jsx35(
9406
9659
  Button,
9407
9660
  {
9408
9661
  variant: "ghost",
@@ -9410,11 +9663,11 @@ function ChatView() {
9410
9663
  className: "h-7 w-7 shrink-0",
9411
9664
  onClick: toggleSidebar,
9412
9665
  title: "Open sidebar (Ctrl+\\\\)",
9413
- children: /* @__PURE__ */ jsx36(PanelLeftOpen, { className: "h-4 w-4" })
9666
+ children: /* @__PURE__ */ jsx35(PanelLeftOpen, { className: "h-4 w-4" })
9414
9667
  }
9415
9668
  ),
9416
- !sidebarOpen && /* @__PURE__ */ jsx36("div", { className: "flex items-center gap-1.5 shrink-0 mr-1", children: /* @__PURE__ */ jsx36("div", { className: "w-5 h-5 rounded bg-primary flex items-center justify-center", children: /* @__PURE__ */ jsx36(Zap5, { className: "h-3 w-3 text-primary-foreground" }) }) }),
9417
- /* @__PURE__ */ jsxs34(
9669
+ !sidebarOpen && /* @__PURE__ */ jsx35("div", { className: "flex items-center gap-1.5 shrink-0 mr-1", children: /* @__PURE__ */ jsx35("div", { className: "w-5 h-5 rounded bg-primary flex items-center justify-center", children: /* @__PURE__ */ jsx35(Zap5, { className: "h-3 w-3 text-primary-foreground" }) }) }),
9670
+ /* @__PURE__ */ jsxs33(
9418
9671
  "span",
9419
9672
  {
9420
9673
  className: cn(
@@ -9423,12 +9676,12 @@ function ChatView() {
9423
9676
  ),
9424
9677
  title: `Agent state: ${agentState}`,
9425
9678
  children: [
9426
- agentState !== "idle" && /* @__PURE__ */ jsx36("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-pulse" }),
9427
- /* @__PURE__ */ jsx36("span", { children: agentState })
9679
+ agentState !== "idle" && /* @__PURE__ */ jsx35("span", { className: "h-1.5 w-1.5 rounded-full bg-current animate-pulse" }),
9680
+ /* @__PURE__ */ jsx35("span", { children: agentState })
9428
9681
  ]
9429
9682
  }
9430
9683
  ),
9431
- sessionId && (renamingTitle ? /* @__PURE__ */ jsx36(
9684
+ sessionId && (renamingTitle ? /* @__PURE__ */ jsx35(
9432
9685
  "input",
9433
9686
  {
9434
9687
  value: titleDraft,
@@ -9451,7 +9704,7 @@ function ChatView() {
9451
9704
  className: "h-5 px-1.5 text-[11px] bg-background border border-primary/40 rounded focus:outline-none focus:ring-1 focus:ring-ring shrink-0 w-32",
9452
9705
  autoFocus: true
9453
9706
  }
9454
- ) : /* @__PURE__ */ jsxs34(
9707
+ ) : /* @__PURE__ */ jsxs33(
9455
9708
  "button",
9456
9709
  {
9457
9710
  type: "button",
@@ -9462,15 +9715,15 @@ function ChatView() {
9462
9715
  className: "flex items-center gap-1 text-[11px] font-medium text-foreground/80 hover:text-foreground truncate max-w-[12rem] shrink-0 px-1 -mx-1 rounded hover:bg-muted/50 transition-colors",
9463
9716
  title: "Click to rename session",
9464
9717
  children: [
9465
- /* @__PURE__ */ jsx36(Pencil3, { className: "h-2.5 w-2.5 text-muted-foreground shrink-0" }),
9466
- /* @__PURE__ */ jsx36("span", { className: "truncate", children: nickname || sessionTitle || "Untitled" })
9718
+ /* @__PURE__ */ jsx35(Pencil3, { className: "h-2.5 w-2.5 text-muted-foreground shrink-0" }),
9719
+ /* @__PURE__ */ jsx35("span", { className: "truncate", children: nickname || sessionTitle || "Untitled" })
9467
9720
  ]
9468
9721
  }
9469
9722
  ))
9470
9723
  ] }),
9471
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-1.5 shrink-0", children: [
9472
- historyEntries.length > 1 && /* @__PURE__ */ jsxs34("div", { ref: switcherRef, className: "relative shrink-0", children: [
9473
- /* @__PURE__ */ jsxs34(
9724
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-1.5 shrink-0", children: [
9725
+ historyEntries.length > 1 && /* @__PURE__ */ jsxs33("div", { ref: switcherRef, className: "relative shrink-0", children: [
9726
+ /* @__PURE__ */ jsxs33(
9474
9727
  "button",
9475
9728
  {
9476
9729
  type: "button",
@@ -9478,12 +9731,12 @@ function ChatView() {
9478
9731
  className: "flex items-center gap-0.5 px-1 py-0.5 rounded text-[10px] text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",
9479
9732
  title: "Switch session",
9480
9733
  children: [
9481
- /* @__PURE__ */ jsx36(History2, { className: "h-3 w-3" }),
9482
- /* @__PURE__ */ jsx36(ChevronDown8, { className: "h-2.5 w-2.5" })
9734
+ /* @__PURE__ */ jsx35(History2, { className: "h-3 w-3" }),
9735
+ /* @__PURE__ */ jsx35(ChevronDown8, { className: "h-2.5 w-2.5" })
9483
9736
  ]
9484
9737
  }
9485
9738
  ),
9486
- switcherOpen && /* @__PURE__ */ jsx36("div", { className: "absolute left-0 top-full mt-1 z-40 w-64 rounded-md border bg-popover shadow-lg p-1 max-h-60 overflow-y-auto", children: historyEntries.slice(0, 15).map((e) => /* @__PURE__ */ jsxs34(
9739
+ switcherOpen && /* @__PURE__ */ jsx35("div", { className: "absolute left-0 top-full mt-1 z-40 w-64 rounded-md border bg-popover shadow-lg p-1 max-h-60 overflow-y-auto", children: historyEntries.slice(0, 15).map((e) => /* @__PURE__ */ jsxs33(
9487
9740
  "button",
9488
9741
  {
9489
9742
  type: "button",
@@ -9497,8 +9750,8 @@ function ChatView() {
9497
9750
  e.isCurrent && "bg-primary/10"
9498
9751
  ),
9499
9752
  children: [
9500
- /* @__PURE__ */ jsx36("div", { className: "font-medium truncate", children: e.title || "(empty)" }),
9501
- /* @__PURE__ */ jsxs34("div", { className: "text-[10px] text-muted-foreground font-mono truncate", children: [
9753
+ /* @__PURE__ */ jsx35("div", { className: "font-medium truncate", children: e.title || "(empty)" }),
9754
+ /* @__PURE__ */ jsxs33("div", { className: "text-[10px] text-muted-foreground font-mono truncate", children: [
9502
9755
  e.provider,
9503
9756
  "/",
9504
9757
  e.model,
@@ -9511,7 +9764,7 @@ function ChatView() {
9511
9764
  e.id
9512
9765
  )) })
9513
9766
  ] }),
9514
- /* @__PURE__ */ jsxs34(
9767
+ /* @__PURE__ */ jsxs33(
9515
9768
  "button",
9516
9769
  {
9517
9770
  type: "button",
@@ -9519,20 +9772,20 @@ function ChatView() {
9519
9772
  className: "group hidden sm:flex items-center gap-1 px-2 py-0.5 rounded-md border bg-background/50 hover:bg-accent hover:border-primary/40 transition-colors text-[11px] min-w-0 shrink-0",
9520
9773
  title: "Change provider / model (Ctrl+M)",
9521
9774
  children: [
9522
- /* @__PURE__ */ jsx36(Cpu5, { className: "h-3 w-3 text-muted-foreground group-hover:text-foreground shrink-0" }),
9523
- /* @__PURE__ */ jsxs34("span", { className: "font-mono truncate max-w-[9rem] xl:max-w-[16rem]", children: [
9524
- /* @__PURE__ */ jsx36("span", { className: "text-muted-foreground", children: provider || "no-provider" }),
9525
- /* @__PURE__ */ jsx36("span", { className: "text-muted-foreground/40 mx-0.5", children: "/" }),
9526
- /* @__PURE__ */ jsx36("span", { className: "font-medium", children: model || "no-model" })
9775
+ /* @__PURE__ */ jsx35(Cpu5, { className: "h-3 w-3 text-muted-foreground group-hover:text-foreground shrink-0" }),
9776
+ /* @__PURE__ */ jsxs33("span", { className: "font-mono truncate max-w-[9rem] xl:max-w-[16rem]", children: [
9777
+ /* @__PURE__ */ jsx35("span", { className: "text-muted-foreground", children: provider || "no-provider" }),
9778
+ /* @__PURE__ */ jsx35("span", { className: "text-muted-foreground/40 mx-0.5", children: "/" }),
9779
+ /* @__PURE__ */ jsx35("span", { className: "font-medium", children: model || "no-model" })
9527
9780
  ] })
9528
9781
  ]
9529
9782
  }
9530
9783
  ),
9531
- /* @__PURE__ */ jsxs34("div", { className: "hidden md:flex items-center gap-1.5 shrink-0", children: [
9532
- /* @__PURE__ */ jsx36(ModePicker, {}),
9533
- /* @__PURE__ */ jsx36(ContextModePicker, {})
9784
+ /* @__PURE__ */ jsxs33("div", { className: "hidden md:flex items-center gap-1.5 shrink-0", children: [
9785
+ /* @__PURE__ */ jsx35(ModePicker, {}),
9786
+ /* @__PURE__ */ jsx35(ContextModePicker, {})
9534
9787
  ] }),
9535
- iteration && /* @__PURE__ */ jsxs34(
9788
+ iteration && /* @__PURE__ */ jsxs33(
9536
9789
  "button",
9537
9790
  {
9538
9791
  type: "button",
@@ -9540,17 +9793,17 @@ function ChatView() {
9540
9793
  title: "Agent iteration \u2014 click to jump to live activity",
9541
9794
  onClick: () => document.getElementById("chat-activity")?.scrollIntoView({ behavior: "smooth", block: "center" }),
9542
9795
  children: [
9543
- /* @__PURE__ */ jsx36(Activity3, { className: "h-3 w-3 animate-pulse" }),
9796
+ /* @__PURE__ */ jsx35(Activity3, { className: "h-3 w-3 animate-pulse" }),
9544
9797
  "iter ",
9545
9798
  iteration.index,
9546
9799
  iteration.max > 0 ? `/${iteration.max}` : ""
9547
9800
  ]
9548
9801
  }
9549
9802
  ),
9550
- /* @__PURE__ */ jsx36(AutonomyPicker, { value: autonomy, onChange: handleAutonomyChange, compact: true })
9803
+ /* @__PURE__ */ jsx35(AutonomyPicker, { value: autonomy, onChange: handleAutonomyChange, compact: true })
9551
9804
  ] }),
9552
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-0.5 shrink-0", children: [
9553
- /* @__PURE__ */ jsxs34(
9805
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-0.5 shrink-0", children: [
9806
+ /* @__PURE__ */ jsxs33(
9554
9807
  Button,
9555
9808
  {
9556
9809
  variant: processOpen ? "secondary" : "ghost",
@@ -9559,12 +9812,12 @@ function ChatView() {
9559
9812
  onClick: () => setProcessOpen((v) => !v),
9560
9813
  title: "Running processes",
9561
9814
  children: [
9562
- /* @__PURE__ */ jsx36(Terminal4, { className: "h-4 w-4" }),
9563
- processOpen && /* @__PURE__ */ jsx36("span", { className: "absolute -bottom-0.5 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-amber-500" })
9815
+ /* @__PURE__ */ jsx35(Terminal4, { className: "h-4 w-4" }),
9816
+ processOpen && /* @__PURE__ */ jsx35("span", { className: "absolute -bottom-0.5 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-amber-500" })
9564
9817
  ]
9565
9818
  }
9566
9819
  ),
9567
- /* @__PURE__ */ jsxs34(
9820
+ /* @__PURE__ */ jsxs33(
9568
9821
  Button,
9569
9822
  {
9570
9823
  variant: checkpointOpen ? "secondary" : "ghost",
@@ -9573,16 +9826,16 @@ function ChatView() {
9573
9826
  onClick: () => setCheckpointOpen((v) => !v),
9574
9827
  title: "Session checkpoints \u2014 rewind",
9575
9828
  children: [
9576
- /* @__PURE__ */ jsx36(History2, { className: "h-4 w-4" }),
9577
- checkpointOpen && /* @__PURE__ */ jsx36("span", { className: "absolute -bottom-0.5 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-violet-500" })
9829
+ /* @__PURE__ */ jsx35(History2, { className: "h-4 w-4" }),
9830
+ checkpointOpen && /* @__PURE__ */ jsx35("span", { className: "absolute -bottom-0.5 left-1/2 -translate-x-1/2 w-1 h-1 rounded-full bg-violet-500" })
9578
9831
  ]
9579
9832
  }
9580
9833
  )
9581
9834
  ] })
9582
9835
  ] }),
9583
- hasStatusContent && /* @__PURE__ */ jsxs34("div", { className: "flex items-center justify-between gap-3 px-3 py-1 border-t bg-muted/20 text-[11px] text-muted-foreground", children: [
9584
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-3 min-w-0 flex-1 tabular-nums", children: [
9585
- lastInputTokens > 0 && /* @__PURE__ */ jsx36(
9836
+ hasStatusContent && /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between gap-3 px-3 py-1 border-t bg-muted/20 text-[11px] text-muted-foreground", children: [
9837
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-3 min-w-0 flex-1 tabular-nums", children: [
9838
+ lastInputTokens > 0 && /* @__PURE__ */ jsx35(
9586
9839
  ContextFillBar,
9587
9840
  {
9588
9841
  pct: ctxPct,
@@ -9591,26 +9844,26 @@ function ChatView() {
9591
9844
  onClick: () => setBreakdownOpen(true)
9592
9845
  }
9593
9846
  ),
9594
- totalTokens.input > 0 && /* @__PURE__ */ jsxs34(Fragment9, { children: [
9595
- /* @__PURE__ */ jsxs34("span", { className: "flex items-center gap-1", children: [
9596
- /* @__PURE__ */ jsx36("span", { className: "font-medium text-foreground", children: fmtTok(totalTokens.input) }),
9597
- /* @__PURE__ */ jsx36("span", { children: "in" })
9847
+ totalTokens.input > 0 && /* @__PURE__ */ jsxs33(Fragment9, { children: [
9848
+ /* @__PURE__ */ jsxs33("span", { className: "flex items-center gap-1", children: [
9849
+ /* @__PURE__ */ jsx35("span", { className: "font-medium text-foreground", children: fmtTok(totalTokens.input) }),
9850
+ /* @__PURE__ */ jsx35("span", { children: "in" })
9598
9851
  ] }),
9599
- /* @__PURE__ */ jsxs34("span", { className: "flex items-center gap-1", children: [
9600
- /* @__PURE__ */ jsx36("span", { className: "font-medium text-foreground", children: fmtTok(totalTokens.output) }),
9601
- /* @__PURE__ */ jsx36("span", { children: "out" })
9852
+ /* @__PURE__ */ jsxs33("span", { className: "flex items-center gap-1", children: [
9853
+ /* @__PURE__ */ jsx35("span", { className: "font-medium text-foreground", children: fmtTok(totalTokens.output) }),
9854
+ /* @__PURE__ */ jsx35("span", { children: "out" })
9602
9855
  ] }),
9603
9856
  totalTokens.cacheRead && totalTokens.cacheRead > 0 && (() => {
9604
9857
  const denom = (totalTokens.cacheRead ?? 0) + totalTokens.input;
9605
9858
  const pct = denom > 0 ? Math.round((totalTokens.cacheRead ?? 0) / denom * 100) : 0;
9606
- return /* @__PURE__ */ jsxs34(
9859
+ return /* @__PURE__ */ jsxs33(
9607
9860
  "span",
9608
9861
  {
9609
9862
  className: "flex items-center gap-1",
9610
9863
  title: `Cache hit ratio: ${pct}%`,
9611
9864
  children: [
9612
- /* @__PURE__ */ jsx36("span", { className: "font-medium text-foreground", children: fmtTok(totalTokens.cacheRead) }),
9613
- /* @__PURE__ */ jsxs34("span", { children: [
9865
+ /* @__PURE__ */ jsx35("span", { className: "font-medium text-foreground", children: fmtTok(totalTokens.cacheRead) }),
9866
+ /* @__PURE__ */ jsxs33("span", { children: [
9614
9867
  "cache (",
9615
9868
  pct,
9616
9869
  "%)"
@@ -9619,15 +9872,15 @@ function ChatView() {
9619
9872
  }
9620
9873
  );
9621
9874
  })(),
9622
- /* @__PURE__ */ jsx36(CostChip, {})
9875
+ /* @__PURE__ */ jsx35(CostChip, {})
9623
9876
  ] })
9624
9877
  ] }),
9625
- startTime && /* @__PURE__ */ jsx36("span", { className: "text-muted-foreground/70 tabular-nums shrink-0", children: formatDuration3(startTime) })
9878
+ startTime && /* @__PURE__ */ jsx35("span", { className: "text-muted-foreground/70 tabular-nums shrink-0", children: formatDuration3(startTime) })
9626
9879
  ] })
9627
9880
  ] }),
9628
- /* @__PURE__ */ jsxs34("div", { className: "flex-1 relative overflow-hidden", children: [
9629
- /* @__PURE__ */ jsx36(SearchOverlay, {}),
9630
- !pinnedToBottom && /* @__PURE__ */ jsxs34(
9881
+ /* @__PURE__ */ jsxs33("div", { className: "flex-1 relative overflow-hidden", children: [
9882
+ /* @__PURE__ */ jsx35(SearchOverlay, {}),
9883
+ !pinnedToBottom && /* @__PURE__ */ jsxs33(
9631
9884
  "button",
9632
9885
  {
9633
9886
  type: "button",
@@ -9639,12 +9892,12 @@ function ChatView() {
9639
9892
  "hover:bg-primary/90 transition-colors animate-message"
9640
9893
  ),
9641
9894
  children: [
9642
- /* @__PURE__ */ jsx36(ArrowDown3, { className: "h-3.5 w-3.5" }),
9895
+ /* @__PURE__ */ jsx35(ArrowDown3, { className: "h-3.5 w-3.5" }),
9643
9896
  unreadCount > 0 ? `${unreadCount} new message${unreadCount === 1 ? "" : "s"}` : "Jump to latest"
9644
9897
  ]
9645
9898
  }
9646
9899
  ),
9647
- scrolledDeep && /* @__PURE__ */ jsxs34(
9900
+ scrolledDeep && /* @__PURE__ */ jsxs33(
9648
9901
  "button",
9649
9902
  {
9650
9903
  type: "button",
@@ -9657,135 +9910,29 @@ function ChatView() {
9657
9910
  "hover:text-foreground hover:bg-background transition-colors animate-message"
9658
9911
  ),
9659
9912
  children: [
9660
- /* @__PURE__ */ jsx36(ArrowUp3, { className: "h-3 w-3" }),
9661
- /* @__PURE__ */ jsx36("span", { children: "Top" })
9913
+ /* @__PURE__ */ jsx35(ArrowUp3, { className: "h-3 w-3" }),
9914
+ /* @__PURE__ */ jsx35("span", { children: "Top" })
9662
9915
  ]
9663
9916
  }
9664
9917
  ),
9665
- /* @__PURE__ */ jsx36(ScrollArea, { className: "h-full", ref: scrollRef, children: /* @__PURE__ */ jsxs34(
9666
- "div",
9667
- {
9668
- className: cn(
9669
- "mx-auto pb-8",
9670
- compactMode ? "max-w-5xl p-3 space-y-3" : "max-w-5xl p-4 space-y-6"
9671
- ),
9672
- children: [
9673
- messages.length === 0 && !isLoading && /* @__PURE__ */ jsx36(WelcomeScreen, {}),
9674
- (() => {
9675
- const groups = [];
9676
- for (let i = 0; i < messages.length; i++) {
9677
- const m = expectDefined12(messages[i]);
9678
- if (m.role === "tool") {
9679
- const last = groups[groups.length - 1];
9680
- if (last && last.kind === "tools") {
9681
- last.tools.push(m);
9682
- } else {
9683
- groups.push({ kind: "tools", tools: [m], key: m.id });
9684
- }
9685
- } else {
9686
- const prev = messages[i - 1];
9687
- groups.push({
9688
- kind: "msg",
9689
- message: m,
9690
- isFirst: !prev || prev.role !== m.role
9691
- });
9692
- }
9693
- }
9694
- const turns = [];
9695
- for (const g of groups) {
9696
- if (g.kind === "msg" && g.message.role === "user") {
9697
- turns.push({ kind: "user", message: g.message, key: g.message.id });
9698
- continue;
9699
- }
9700
- const last = turns[turns.length - 1];
9701
- if (last && last.kind === "agent") {
9702
- last.items.push(g);
9703
- } else {
9704
- const key = g.kind === "msg" ? g.message.id : g.key;
9705
- turns.push({ kind: "agent", items: [g], key });
9706
- }
9707
- }
9708
- let prevDay = null;
9709
- const dayKey = (ts) => {
9710
- const d = new Date(ts);
9711
- return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
9712
- };
9713
- const dayLabel = (ts) => {
9714
- const d = new Date(ts);
9715
- const today = /* @__PURE__ */ new Date();
9716
- const yest = new Date(Date.now() - 864e5);
9717
- if (dayKey(ts) === dayKey(today.getTime())) return "Today";
9718
- if (dayKey(ts) === dayKey(yest.getTime())) return "Yesterday";
9719
- return d.toLocaleDateString(void 0, {
9720
- weekday: "short",
9721
- month: "short",
9722
- day: "numeric",
9723
- year: d.getFullYear() === today.getFullYear() ? void 0 : "numeric"
9724
- });
9725
- };
9726
- const turnTs = (t) => {
9727
- if (t.kind === "user") return t.message.timestamp;
9728
- const first = expectDefined12(t.items[0]);
9729
- return first.kind === "msg" ? first.message.timestamp : first.tools[0]?.timestamp;
9730
- };
9731
- const out = [];
9732
- for (let idx = 0; idx < turns.length; idx++) {
9733
- const t = expectDefined12(turns[idx]);
9734
- const ts = turnTs(t);
9735
- const day = dayKey(ts);
9736
- if (day !== prevDay) {
9737
- out.push(
9738
- /* @__PURE__ */ jsxs34(
9739
- "div",
9740
- {
9741
- className: "flex items-center gap-3 py-1 text-[11px] text-muted-foreground/70 uppercase tracking-wider font-medium",
9742
- children: [
9743
- /* @__PURE__ */ jsx36("div", { className: "flex-1 h-px bg-border/50" }),
9744
- /* @__PURE__ */ jsx36("span", { children: dayLabel(ts) }),
9745
- /* @__PURE__ */ jsx36("div", { className: "flex-1 h-px bg-border/50" })
9746
- ]
9747
- },
9748
- `day-${day}-${idx}`
9749
- )
9750
- );
9751
- prevDay = day;
9752
- }
9753
- if (t.kind === "user") {
9754
- out.push(/* @__PURE__ */ jsx36(MessageBubble, { message: t.message, isFirst: true }, t.key));
9755
- continue;
9756
- }
9757
- const isLastTurn = idx === turns.length - 1;
9758
- out.push(
9759
- /* @__PURE__ */ jsx36("div", { className: cn("chat-turn", compactMode ? "space-y-1" : "space-y-1.5"), children: t.items.map((g, gi) => {
9760
- const continuation = gi > 0;
9761
- if (g.kind === "msg") {
9762
- return /* @__PURE__ */ jsx36(
9763
- MessageBubble,
9764
- {
9765
- message: g.message,
9766
- isFirst: !continuation && g.isFirst,
9767
- isContinuation: continuation
9768
- },
9769
- g.message.id
9770
- );
9771
- }
9772
- const isLatestRunning = isLastTurn && gi === t.items.length - 1 && isLoading && g.tools.some((tt) => tt.toolResult === void 0);
9773
- return /* @__PURE__ */ jsx36(
9774
- ToolGroup,
9775
- {
9776
- tools: g.tools,
9777
- defaultOpen: isLatestRunning,
9778
- isContinuation: continuation
9779
- },
9780
- g.key
9781
- );
9782
- }) }, t.key)
9783
- );
9784
- }
9785
- return out;
9786
- })(),
9787
- /* @__PURE__ */ jsxs34("div", { id: "chat-activity", children: [
9788
- /* @__PURE__ */ jsx36(ThinkingBubble, {}),
9918
+ rows.length === 0 && !isLoading ? /* @__PURE__ */ jsx35("div", { className: "mx-auto max-w-5xl w-full px-4 pt-4", children: /* @__PURE__ */ jsx35(WelcomeScreen, {}) }) : /* @__PURE__ */ jsxs33(VList, { ref: vlistRef, className: "h-full", onScroll: handleScroll, children: [
9919
+ rows.map((row, i) => /* @__PURE__ */ jsx35(
9920
+ ChatRowView,
9921
+ {
9922
+ row,
9923
+ isLoading,
9924
+ compactMode,
9925
+ isFirstRow: i === 0
9926
+ },
9927
+ row.key
9928
+ )),
9929
+ /* @__PURE__ */ jsxs33(
9930
+ "div",
9931
+ {
9932
+ id: "chat-activity",
9933
+ className: cn("mx-auto max-w-5xl w-full px-4", compactMode ? "pb-3" : "pb-8"),
9934
+ children: [
9935
+ /* @__PURE__ */ jsx35(ThinkingBubble, {}),
9789
9936
  isLoading && (() => {
9790
9937
  const last = messages[messages.length - 1];
9791
9938
  const runningTools = messages.filter(
@@ -9827,94 +9974,95 @@ function ChatView() {
9827
9974
  } else if (streamAnchor.current) {
9828
9975
  streamAnchor.current = null;
9829
9976
  }
9830
- return /* @__PURE__ */ jsxs34("div", { className: "flex gap-3 animate-message", children: [
9831
- /* @__PURE__ */ jsx36("div", { className: "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center bg-accent text-accent-foreground ring-2 ring-offset-2 ring-offset-background ring-accent/20", children: /* @__PURE__ */ jsx36(Bot4, { className: "h-4 w-4" }) }),
9832
- /* @__PURE__ */ jsx36("div", { className: "flex flex-col gap-1.5", children: /* @__PURE__ */ jsx36("div", { className: "rounded-2xl px-4 py-3 bg-card border text-foreground", children: /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-3 text-sm", children: [
9833
- /* @__PURE__ */ jsxs34("span", { className: "flex gap-1", children: [
9834
- /* @__PURE__ */ jsx36("span", { className: "h-1.5 w-1.5 rounded-full bg-primary/70 animate-bounce [animation-delay:-0.3s]" }),
9835
- /* @__PURE__ */ jsx36("span", { className: "h-1.5 w-1.5 rounded-full bg-primary/70 animate-bounce [animation-delay:-0.15s]" }),
9836
- /* @__PURE__ */ jsx36("span", { className: "h-1.5 w-1.5 rounded-full bg-primary/70 animate-bounce" })
9977
+ return /* @__PURE__ */ jsxs33("div", { className: "flex gap-3 animate-message", children: [
9978
+ /* @__PURE__ */ jsx35("div", { className: "flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center bg-accent text-accent-foreground ring-2 ring-offset-2 ring-offset-background ring-accent/20", children: /* @__PURE__ */ jsx35(Bot4, { className: "h-4 w-4" }) }),
9979
+ /* @__PURE__ */ jsx35("div", { className: "flex flex-col gap-1.5", children: /* @__PURE__ */ jsx35("div", { className: "rounded-2xl px-4 py-3 bg-card border text-foreground", children: /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-3 text-sm", children: [
9980
+ /* @__PURE__ */ jsxs33("span", { className: "flex gap-1", children: [
9981
+ /* @__PURE__ */ jsx35("span", { className: "h-1.5 w-1.5 rounded-full bg-primary/70 animate-bounce [animation-delay:-0.3s]" }),
9982
+ /* @__PURE__ */ jsx35("span", { className: "h-1.5 w-1.5 rounded-full bg-primary/70 animate-bounce [animation-delay:-0.15s]" }),
9983
+ /* @__PURE__ */ jsx35("span", { className: "h-1.5 w-1.5 rounded-full bg-primary/70 animate-bounce" })
9837
9984
  ] }),
9838
- /* @__PURE__ */ jsx36("span", { className: "text-foreground/90", children: label }),
9839
- /* @__PURE__ */ jsx36("span", { className: "text-xs text-muted-foreground tabular-nums", children: elapsed }),
9840
- iteration && /* @__PURE__ */ jsxs34("span", { className: "text-xs text-muted-foreground tabular-nums", children: [
9985
+ /* @__PURE__ */ jsx35("span", { className: "text-foreground/90", children: label }),
9986
+ /* @__PURE__ */ jsx35("span", { className: "text-xs text-muted-foreground tabular-nums", children: elapsed }),
9987
+ iteration && /* @__PURE__ */ jsxs33("span", { className: "text-xs text-muted-foreground tabular-nums", children: [
9841
9988
  "\xB7 iter ",
9842
9989
  iteration.index,
9843
9990
  iteration.max > 0 ? `/${iteration.max}` : ""
9844
9991
  ] }),
9845
- speedLabel && /* @__PURE__ */ jsxs34("span", { className: "text-xs text-muted-foreground/80 tabular-nums", children: [
9992
+ speedLabel && /* @__PURE__ */ jsxs33("span", { className: "text-xs text-muted-foreground/80 tabular-nums", children: [
9846
9993
  "\xB7 ",
9847
9994
  speedLabel
9848
9995
  ] })
9849
9996
  ] }) }) })
9850
9997
  ] });
9851
9998
  })()
9852
- ] })
9853
- ]
9854
- }
9855
- ) })
9999
+ ]
10000
+ },
10001
+ "__live"
10002
+ )
10003
+ ] })
9856
10004
  ] }),
9857
- /* @__PURE__ */ jsxs34("div", { className: "border-t bg-card/50 backdrop-blur supports-[backdrop-filter]:bg-card/50 shrink-0", children: [
9858
- /* @__PURE__ */ jsxs34("div", { className: "max-w-5xl mx-auto px-4 pt-1.5 flex items-center gap-3 text-[10px] text-muted-foreground/50 select-none overflow-x-auto", children: [
9859
- /* @__PURE__ */ jsxs34("span", { title: "Enter", className: "inline-flex items-center gap-1", children: [
9860
- /* @__PURE__ */ jsx36("kbd", { children: "Enter" }),
10005
+ /* @__PURE__ */ jsxs33("div", { className: "border-t bg-card/50 backdrop-blur supports-[backdrop-filter]:bg-card/50 shrink-0", children: [
10006
+ /* @__PURE__ */ jsxs33("div", { className: "max-w-5xl mx-auto px-4 pt-1.5 flex items-center gap-3 text-[10px] text-muted-foreground/50 select-none overflow-x-auto", children: [
10007
+ /* @__PURE__ */ jsxs33("span", { title: "Enter", className: "inline-flex items-center gap-1", children: [
10008
+ /* @__PURE__ */ jsx35("kbd", { children: "Enter" }),
9861
10009
  " send"
9862
10010
  ] }),
9863
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9864
- /* @__PURE__ */ jsxs34("span", { title: "Shift+Enter", className: "inline-flex items-center gap-1", children: [
9865
- /* @__PURE__ */ jsx36("kbd", { children: "Shift" }),
10011
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10012
+ /* @__PURE__ */ jsxs33("span", { title: "Shift+Enter", className: "inline-flex items-center gap-1", children: [
10013
+ /* @__PURE__ */ jsx35("kbd", { children: "Shift" }),
9866
10014
  "+",
9867
- /* @__PURE__ */ jsx36("kbd", { children: "\u21B5" }),
10015
+ /* @__PURE__ */ jsx35("kbd", { children: "\u21B5" }),
9868
10016
  " newline"
9869
10017
  ] }),
9870
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9871
- /* @__PURE__ */ jsxs34("span", { title: "Ctrl+\\\\", className: "inline-flex items-center gap-1", children: [
9872
- /* @__PURE__ */ jsx36("kbd", { children: "Ctrl+\\" }),
10018
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10019
+ /* @__PURE__ */ jsxs33("span", { title: "Ctrl+\\\\", className: "inline-flex items-center gap-1", children: [
10020
+ /* @__PURE__ */ jsx35("kbd", { children: "Ctrl+\\" }),
9873
10021
  " sidebar"
9874
10022
  ] }),
9875
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9876
- /* @__PURE__ */ jsxs34("span", { title: "Ctrl+F", className: "inline-flex items-center gap-1", children: [
9877
- /* @__PURE__ */ jsx36("kbd", { children: "Ctrl+F" }),
10023
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10024
+ /* @__PURE__ */ jsxs33("span", { title: "Ctrl+F", className: "inline-flex items-center gap-1", children: [
10025
+ /* @__PURE__ */ jsx35("kbd", { children: "Ctrl+F" }),
9878
10026
  " search"
9879
10027
  ] }),
9880
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9881
- /* @__PURE__ */ jsxs34("span", { title: "Ctrl+K", className: "inline-flex items-center gap-1", children: [
9882
- /* @__PURE__ */ jsx36("kbd", { children: "Ctrl+K" }),
10028
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10029
+ /* @__PURE__ */ jsxs33("span", { title: "Ctrl+K", className: "inline-flex items-center gap-1", children: [
10030
+ /* @__PURE__ */ jsx35("kbd", { children: "Ctrl+K" }),
9883
10031
  " palette"
9884
10032
  ] }),
9885
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9886
- /* @__PURE__ */ jsxs34("span", { title: "Ctrl+L / Ctrl+N", className: "inline-flex items-center gap-1", children: [
9887
- /* @__PURE__ */ jsx36("kbd", { children: "Ctrl+L" }),
10033
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10034
+ /* @__PURE__ */ jsxs33("span", { title: "Ctrl+L / Ctrl+N", className: "inline-flex items-center gap-1", children: [
10035
+ /* @__PURE__ */ jsx35("kbd", { children: "Ctrl+L" }),
9888
10036
  " clear"
9889
10037
  ] }),
9890
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9891
- /* @__PURE__ */ jsxs34("span", { title: "j/k to navigate", className: "inline-flex items-center gap-1", children: [
9892
- /* @__PURE__ */ jsx36("kbd", { children: "j" }),
9893
- /* @__PURE__ */ jsx36("kbd", { children: "k" }),
10038
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10039
+ /* @__PURE__ */ jsxs33("span", { title: "j/k to navigate", className: "inline-flex items-center gap-1", children: [
10040
+ /* @__PURE__ */ jsx35("kbd", { children: "j" }),
10041
+ /* @__PURE__ */ jsx35("kbd", { children: "k" }),
9894
10042
  " navigate"
9895
10043
  ] }),
9896
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9897
- /* @__PURE__ */ jsxs34("span", { title: "Ctrl+M", className: "inline-flex items-center gap-1", children: [
9898
- /* @__PURE__ */ jsx36("kbd", { children: "Ctrl+M" }),
10044
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10045
+ /* @__PURE__ */ jsxs33("span", { title: "Ctrl+M", className: "inline-flex items-center gap-1", children: [
10046
+ /* @__PURE__ */ jsx35("kbd", { children: "Ctrl+M" }),
9899
10047
  " model"
9900
10048
  ] }),
9901
- /* @__PURE__ */ jsx36("span", { className: "opacity-50", children: "\xB7" }),
9902
- /* @__PURE__ */ jsxs34("span", { title: "Ctrl+Shift+D", className: "inline-flex items-center gap-1", children: [
9903
- /* @__PURE__ */ jsx36("kbd", { children: "Ctrl+\u21E7D" }),
10049
+ /* @__PURE__ */ jsx35("span", { className: "opacity-50", children: "\xB7" }),
10050
+ /* @__PURE__ */ jsxs33("span", { title: "Ctrl+Shift+D", className: "inline-flex items-center gap-1", children: [
10051
+ /* @__PURE__ */ jsx35("kbd", { children: "Ctrl+\u21E7D" }),
9904
10052
  " density"
9905
10053
  ] })
9906
10054
  ] }),
9907
- /* @__PURE__ */ jsx36("div", { className: "p-4", children: /* @__PURE__ */ jsx36("div", { className: "max-w-5xl mx-auto", children: /* @__PURE__ */ jsx36(ChatInput, { onOpenBreakdown: () => setBreakdownOpen(true) }) }) })
10055
+ /* @__PURE__ */ jsx35("div", { className: "p-4", children: /* @__PURE__ */ jsx35("div", { className: "max-w-5xl mx-auto", children: /* @__PURE__ */ jsx35(ChatInput, { onOpenBreakdown: () => setBreakdownOpen(true) }) }) })
9908
10056
  ] }),
9909
- /* @__PURE__ */ jsx36(ProcessMonitor, { open: processOpen, onClose: () => setProcessOpen(false) }),
9910
- /* @__PURE__ */ jsx36(CheckpointTimeline, { open: checkpointOpen, onClose: () => setCheckpointOpen(false) }),
9911
- /* @__PURE__ */ jsx36(ContextBreakdownModal, { open: breakdownOpen, onClose: () => setBreakdownOpen(false) })
10057
+ /* @__PURE__ */ jsx35(ProcessMonitor, { open: processOpen, onClose: () => setProcessOpen(false) }),
10058
+ /* @__PURE__ */ jsx35(CheckpointTimeline, { open: checkpointOpen, onClose: () => setCheckpointOpen(false) }),
10059
+ /* @__PURE__ */ jsx35(ContextBreakdownModal, { open: breakdownOpen, onClose: () => setBreakdownOpen(false) })
9912
10060
  ] });
9913
10061
  }
9914
10062
 
9915
10063
  // src/components/CodeEditor.tsx
9916
10064
  import { X as X8, Circle as Circle3 } from "lucide-react";
9917
- import { useCallback as useCallback11, useEffect as useEffect19, useMemo as useMemo8, useRef as useRef15 } from "react";
10065
+ import { useCallback as useCallback11, useEffect as useEffect19, useMemo as useMemo9, useRef as useRef15 } from "react";
9918
10066
  import Editor, { loader } from "@monaco-editor/react";
9919
10067
  import * as monaco2 from "monaco-editor";
9920
10068
 
@@ -10274,7 +10422,7 @@ function getMonacoTheme() {
10274
10422
  }
10275
10423
 
10276
10424
  // src/components/CodeEditor.tsx
10277
- import { jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
10425
+ import { jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
10278
10426
  loader.config({ monaco: monaco2 });
10279
10427
  var LANG_MAP = {
10280
10428
  ts: "typescript",
@@ -10314,10 +10462,10 @@ function EditorTabs() {
10314
10462
  const setActiveFile = useFileStore((s) => s.setActiveFile);
10315
10463
  const closeFile = useFileStore((s) => s.closeFile);
10316
10464
  if (openFiles.length === 0) return null;
10317
- return /* @__PURE__ */ jsx37("div", { className: "flex items-center border-b bg-muted/40 overflow-x-auto shrink-0", children: openFiles.map((f) => {
10465
+ return /* @__PURE__ */ jsx36("div", { className: "flex items-center border-b bg-muted/40 overflow-x-auto shrink-0", children: openFiles.map((f) => {
10318
10466
  const isActive = f.path === activeFilePath;
10319
10467
  const baseName = f.path.split("/").pop() ?? f.path;
10320
- return /* @__PURE__ */ jsxs35(
10468
+ return /* @__PURE__ */ jsxs34(
10321
10469
  "button",
10322
10470
  {
10323
10471
  type: "button",
@@ -10334,9 +10482,9 @@ function EditorTabs() {
10334
10482
  ),
10335
10483
  title: f.path,
10336
10484
  children: [
10337
- f.dirty && /* @__PURE__ */ jsx37(Circle3, { className: "h-2 w-2 fill-current text-primary shrink-0" }),
10338
- /* @__PURE__ */ jsx37("span", { className: "truncate", children: baseName }),
10339
- /* @__PURE__ */ jsx37(
10485
+ f.dirty && /* @__PURE__ */ jsx36(Circle3, { className: "h-2 w-2 fill-current text-primary shrink-0" }),
10486
+ /* @__PURE__ */ jsx36("span", { className: "truncate", children: baseName }),
10487
+ /* @__PURE__ */ jsx36(
10340
10488
  X8,
10341
10489
  {
10342
10490
  className: cn(
@@ -10361,7 +10509,7 @@ function CodeEditor() {
10361
10509
  const updateContent = useFileStore((s) => s.updateContent);
10362
10510
  const { theme: appTheme } = useTheme();
10363
10511
  const editorRef = useRef15(null);
10364
- const activeFile = useMemo8(
10512
+ const activeFile = useMemo9(
10365
10513
  () => openFiles.find((f) => f.path === activeFilePath) ?? null,
10366
10514
  [openFiles, activeFilePath]
10367
10515
  );
@@ -10408,14 +10556,14 @@ function CodeEditor() {
10408
10556
  return () => window.removeEventListener("keydown", onKeyDown);
10409
10557
  }, [activeFilePath]);
10410
10558
  if (openFiles.length === 0) {
10411
- return /* @__PURE__ */ jsx37("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxs35("div", { className: "text-center space-y-2", children: [
10412
- /* @__PURE__ */ jsx37("p", { className: "text-sm text-muted-foreground", children: "No files open" }),
10413
- /* @__PURE__ */ jsx37("p", { className: "text-[11px] text-muted-foreground/60", children: "Select a file from the explorer to start editing" })
10559
+ return /* @__PURE__ */ jsx36("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxs34("div", { className: "text-center space-y-2", children: [
10560
+ /* @__PURE__ */ jsx36("p", { className: "text-sm text-muted-foreground", children: "No files open" }),
10561
+ /* @__PURE__ */ jsx36("p", { className: "text-[11px] text-muted-foreground/60", children: "Select a file from the explorer to start editing" })
10414
10562
  ] }) });
10415
10563
  }
10416
- return /* @__PURE__ */ jsxs35("div", { className: "flex-1 flex flex-col overflow-hidden", children: [
10417
- /* @__PURE__ */ jsx37(EditorTabs, {}),
10418
- /* @__PURE__ */ jsx37("div", { className: "flex-1 relative", children: activeFile ? /* @__PURE__ */ jsx37(
10564
+ return /* @__PURE__ */ jsxs34("div", { className: "flex-1 flex flex-col overflow-hidden", children: [
10565
+ /* @__PURE__ */ jsx36(EditorTabs, {}),
10566
+ /* @__PURE__ */ jsx36("div", { className: "flex-1 relative", children: activeFile ? /* @__PURE__ */ jsx36(
10419
10567
  Editor,
10420
10568
  {
10421
10569
  language,
@@ -10423,7 +10571,7 @@ function CodeEditor() {
10423
10571
  onChange: handleChange,
10424
10572
  theme: monacoTheme,
10425
10573
  onMount: handleMount,
10426
- loading: /* @__PURE__ */ jsx37("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx37("span", { className: "text-[11px] text-muted-foreground animate-pulse", children: "Loading editor\u2026" }) }),
10574
+ loading: /* @__PURE__ */ jsx36("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx36("span", { className: "text-[11px] text-muted-foreground animate-pulse", children: "Loading editor\u2026" }) }),
10427
10575
  options: {
10428
10576
  minimap: { enabled: false },
10429
10577
  fontSize: 13,
@@ -10443,23 +10591,23 @@ function CodeEditor() {
10443
10591
  }
10444
10592
  },
10445
10593
  activeFile.path
10446
- ) : /* @__PURE__ */ jsx37("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx37("p", { className: "text-[11px] text-muted-foreground", children: "Select a tab to view its content" }) }) })
10594
+ ) : /* @__PURE__ */ jsx36("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx36("p", { className: "text-[11px] text-muted-foreground", children: "Select a tab to view its content" }) }) })
10447
10595
  ] });
10448
10596
  }
10449
10597
 
10450
10598
  // src/components/ConfirmDialog.tsx
10451
- import { AlertTriangle as AlertTriangle3, FileEdit, Globe as Globe2, ShieldAlert, Terminal as Terminal5, Wrench as Wrench6 } from "lucide-react";
10599
+ import { AlertTriangle as AlertTriangle3, FileEdit, Globe as Globe2, ShieldAlert, Terminal as Terminal5, Wrench as Wrench5 } from "lucide-react";
10452
10600
  import { useEffect as useEffect20, useRef as useRef16 } from "react";
10453
10601
 
10454
10602
  // src/components/ui/dialog.tsx
10455
10603
  import * as DialogPrimitive from "@radix-ui/react-dialog";
10456
10604
  import { X as X9 } from "lucide-react";
10457
- import * as React3 from "react";
10458
- import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
10605
+ import * as React2 from "react";
10606
+ import { jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
10459
10607
  var Dialog = DialogPrimitive.Root;
10460
10608
  var DialogTrigger = DialogPrimitive.Trigger;
10461
10609
  var DialogPortal = DialogPrimitive.Portal;
10462
- var DialogOverlay = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx38(
10610
+ var DialogOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx37(
10463
10611
  DialogPrimitive.Overlay,
10464
10612
  {
10465
10613
  ref,
@@ -10471,9 +10619,9 @@ var DialogOverlay = React3.forwardRef(({ className, ...props }, ref) => /* @__PU
10471
10619
  }
10472
10620
  ));
10473
10621
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
10474
- var DialogContent = React3.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs36(DialogPortal, { children: [
10475
- /* @__PURE__ */ jsx38(DialogOverlay, {}),
10476
- /* @__PURE__ */ jsxs36(
10622
+ var DialogContent = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs35(DialogPortal, { children: [
10623
+ /* @__PURE__ */ jsx37(DialogOverlay, {}),
10624
+ /* @__PURE__ */ jsxs35(
10477
10625
  DialogPrimitive.Content,
10478
10626
  {
10479
10627
  ref,
@@ -10484,18 +10632,18 @@ var DialogContent = React3.forwardRef(({ className, children, ...props }, ref) =
10484
10632
  ...props,
10485
10633
  children: [
10486
10634
  children,
10487
- /* @__PURE__ */ jsxs36(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
10488
- /* @__PURE__ */ jsx38(X9, { className: "h-4 w-4" }),
10489
- /* @__PURE__ */ jsx38("span", { className: "sr-only", children: "Close" })
10635
+ /* @__PURE__ */ jsxs35(DialogPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [
10636
+ /* @__PURE__ */ jsx37(X9, { className: "h-4 w-4" }),
10637
+ /* @__PURE__ */ jsx37("span", { className: "sr-only", children: "Close" })
10490
10638
  ] })
10491
10639
  ]
10492
10640
  }
10493
10641
  )
10494
10642
  ] }));
10495
10643
  DialogContent.displayName = DialogPrimitive.Content.displayName;
10496
- var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx38("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
10644
+ var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsx37("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
10497
10645
  DialogHeader.displayName = "DialogHeader";
10498
- var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx38(
10646
+ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx37(
10499
10647
  "div",
10500
10648
  {
10501
10649
  className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
@@ -10503,7 +10651,7 @@ var DialogFooter = ({ className, ...props }) => /* @__PURE__ */ jsx38(
10503
10651
  }
10504
10652
  );
10505
10653
  DialogFooter.displayName = "DialogFooter";
10506
- var DialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx38(
10654
+ var DialogTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx37(
10507
10655
  DialogPrimitive.Title,
10508
10656
  {
10509
10657
  ref,
@@ -10512,7 +10660,7 @@ var DialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE
10512
10660
  }
10513
10661
  ));
10514
10662
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
10515
- var DialogDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx38(
10663
+ var DialogDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx37(
10516
10664
  DialogPrimitive.Description,
10517
10665
  {
10518
10666
  ref,
@@ -10523,12 +10671,12 @@ var DialogDescription = React3.forwardRef(({ className, ...props }, ref) => /* @
10523
10671
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
10524
10672
 
10525
10673
  // src/components/ConfirmDialog.tsx
10526
- import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
10674
+ import { jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
10527
10675
  function pickToolIcon(toolName) {
10528
10676
  if (/edit|write|create|patch/i.test(toolName)) return FileEdit;
10529
10677
  if (/bash|shell|exec|run|command/i.test(toolName)) return Terminal5;
10530
10678
  if (/fetch|http|web|curl|request/i.test(toolName)) return Globe2;
10531
- return Wrench6;
10679
+ return Wrench5;
10532
10680
  }
10533
10681
  function SmartInputPreview({
10534
10682
  toolName,
@@ -10536,7 +10684,7 @@ function SmartInputPreview({
10536
10684
  }) {
10537
10685
  const diffArgs = diffFromToolInput(toolName, input);
10538
10686
  if (diffArgs) {
10539
- return /* @__PURE__ */ jsx39("div", { className: "rounded-lg overflow-hidden border", children: /* @__PURE__ */ jsx39(
10687
+ return /* @__PURE__ */ jsx38("div", { className: "rounded-lg overflow-hidden border", children: /* @__PURE__ */ jsx38(
10540
10688
  DiffView,
10541
10689
  {
10542
10690
  oldText: diffArgs.oldText,
@@ -10549,12 +10697,12 @@ function SmartInputPreview({
10549
10697
  const obj = input;
10550
10698
  const cmd = obj.command ?? obj.cmd ?? obj.script;
10551
10699
  if (typeof cmd === "string" && cmd.trim().length > 0) {
10552
- return /* @__PURE__ */ jsxs37("div", { className: "rounded-lg border bg-background/40 overflow-hidden", children: [
10553
- /* @__PURE__ */ jsxs37("div", { className: "px-3 py-1.5 text-[10px] uppercase tracking-wider text-muted-foreground border-b bg-muted/40 flex items-center gap-1.5", children: [
10554
- /* @__PURE__ */ jsx39(Terminal5, { className: "h-3 w-3" }),
10555
- /* @__PURE__ */ jsx39("span", { children: "Command" })
10700
+ return /* @__PURE__ */ jsxs36("div", { className: "rounded-lg border bg-background/40 overflow-hidden", children: [
10701
+ /* @__PURE__ */ jsxs36("div", { className: "px-3 py-1.5 text-[10px] uppercase tracking-wider text-muted-foreground border-b bg-muted/40 flex items-center gap-1.5", children: [
10702
+ /* @__PURE__ */ jsx38(Terminal5, { className: "h-3 w-3" }),
10703
+ /* @__PURE__ */ jsx38("span", { children: "Command" })
10556
10704
  ] }),
10557
- /* @__PURE__ */ jsxs37("pre", { className: "px-3 py-2 text-xs font-mono whitespace-pre-wrap break-all max-h-40 overflow-auto", children: [
10705
+ /* @__PURE__ */ jsxs36("pre", { className: "px-3 py-2 text-xs font-mono whitespace-pre-wrap break-all max-h-40 overflow-auto", children: [
10558
10706
  "$",
10559
10707
  cmd
10560
10708
  ] })
@@ -10563,16 +10711,16 @@ function SmartInputPreview({
10563
10711
  const url = obj.url;
10564
10712
  if (typeof url === "string") {
10565
10713
  const method = obj.method ?? "GET";
10566
- return /* @__PURE__ */ jsxs37("div", { className: "rounded-lg border bg-background/40 px-3 py-2 text-xs font-mono", children: [
10567
- /* @__PURE__ */ jsx39("span", { className: "text-muted-foreground", children: method.toUpperCase() }),
10714
+ return /* @__PURE__ */ jsxs36("div", { className: "rounded-lg border bg-background/40 px-3 py-2 text-xs font-mono", children: [
10715
+ /* @__PURE__ */ jsx38("span", { className: "text-muted-foreground", children: method.toUpperCase() }),
10568
10716
  " ",
10569
- /* @__PURE__ */ jsx39("span", { className: "break-all", children: url })
10717
+ /* @__PURE__ */ jsx38("span", { className: "break-all", children: url })
10570
10718
  ] });
10571
10719
  }
10572
10720
  }
10573
- return /* @__PURE__ */ jsxs37("div", { className: "p-3 rounded-lg bg-muted/50 border text-xs font-mono", children: [
10574
- /* @__PURE__ */ jsx39("div", { className: "text-muted-foreground mb-2", children: "Input:" }),
10575
- /* @__PURE__ */ jsx39("pre", { className: "whitespace-pre-wrap break-all max-h-60 overflow-auto", children: JSON.stringify(input, null, 2) })
10721
+ return /* @__PURE__ */ jsxs36("div", { className: "p-3 rounded-lg bg-muted/50 border text-xs font-mono", children: [
10722
+ /* @__PURE__ */ jsx38("div", { className: "text-muted-foreground mb-2", children: "Input:" }),
10723
+ /* @__PURE__ */ jsx38("pre", { className: "whitespace-pre-wrap break-all max-h-60 overflow-auto", children: JSON.stringify(input, null, 2) })
10576
10724
  ] });
10577
10725
  }
10578
10726
  function ConfirmDialog() {
@@ -10610,50 +10758,50 @@ function ConfirmDialog() {
10610
10758
  return () => window.removeEventListener("keydown", onKey);
10611
10759
  }, [showConfirmDialog, confirmInfo?.id]);
10612
10760
  if (!confirmInfo) {
10613
- return /* @__PURE__ */ jsx39(Dialog, { open: showConfirmDialog, onOpenChange: () => hideConfirm(), children: /* @__PURE__ */ jsx39(DialogContent, {}) });
10761
+ return /* @__PURE__ */ jsx38(Dialog, { open: showConfirmDialog, onOpenChange: () => hideConfirm(), children: /* @__PURE__ */ jsx38(DialogContent, {}) });
10614
10762
  }
10615
10763
  const Icon2 = pickToolIcon(confirmInfo.toolName);
10616
10764
  const isEdit = /edit|write/i.test(confirmInfo.toolName);
10617
- return /* @__PURE__ */ jsx39(Dialog, { open: showConfirmDialog, onOpenChange: () => hideConfirm(), children: /* @__PURE__ */ jsxs37(DialogContent, { className: "sm:max-w-2xl border-yellow-500/50", ref: dialogRef, tabIndex: -1, children: [
10618
- /* @__PURE__ */ jsxs37(DialogHeader, { children: [
10619
- /* @__PURE__ */ jsxs37(DialogTitle, { className: "flex items-center gap-2", children: [
10620
- /* @__PURE__ */ jsx39(ShieldAlert, { className: "h-5 w-5 text-yellow-500 animate-pulse" }),
10765
+ return /* @__PURE__ */ jsx38(Dialog, { open: showConfirmDialog, onOpenChange: () => hideConfirm(), children: /* @__PURE__ */ jsxs36(DialogContent, { className: "sm:max-w-2xl border-yellow-500/50", ref: dialogRef, tabIndex: -1, children: [
10766
+ /* @__PURE__ */ jsxs36(DialogHeader, { children: [
10767
+ /* @__PURE__ */ jsxs36(DialogTitle, { className: "flex items-center gap-2", children: [
10768
+ /* @__PURE__ */ jsx38(ShieldAlert, { className: "h-5 w-5 text-yellow-500 animate-pulse" }),
10621
10769
  "Approval required: ",
10622
10770
  confirmInfo.toolName
10623
10771
  ] }),
10624
- /* @__PURE__ */ jsxs37(DialogDescription, { children: [
10772
+ /* @__PURE__ */ jsxs36(DialogDescription, { children: [
10625
10773
  "The agent wants to ",
10626
10774
  isEdit ? "modify a file" : "run this tool",
10627
10775
  ". Review the request below and decide whether to proceed."
10628
10776
  ] })
10629
10777
  ] }),
10630
- /* @__PURE__ */ jsxs37("div", { className: "py-2 space-y-3", children: [
10631
- /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-3 p-3 rounded-lg bg-muted", children: [
10632
- /* @__PURE__ */ jsx39(Icon2, { className: "h-5 w-5 text-muted-foreground" }),
10633
- /* @__PURE__ */ jsxs37("div", { className: "min-w-0", children: [
10634
- /* @__PURE__ */ jsx39("div", { className: "font-medium font-mono truncate", children: confirmInfo.toolName }),
10635
- /* @__PURE__ */ jsxs37("div", { className: "text-xs text-muted-foreground", children: [
10778
+ /* @__PURE__ */ jsxs36("div", { className: "py-2 space-y-3", children: [
10779
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-3 p-3 rounded-lg bg-muted", children: [
10780
+ /* @__PURE__ */ jsx38(Icon2, { className: "h-5 w-5 text-muted-foreground" }),
10781
+ /* @__PURE__ */ jsxs36("div", { className: "min-w-0", children: [
10782
+ /* @__PURE__ */ jsx38("div", { className: "font-medium font-mono truncate", children: confirmInfo.toolName }),
10783
+ /* @__PURE__ */ jsxs36("div", { className: "text-xs text-muted-foreground", children: [
10636
10784
  isEdit ? "File modification" : "Tool execution",
10637
10785
  " \u2014 preview below"
10638
10786
  ] })
10639
10787
  ] })
10640
10788
  ] }),
10641
- confirmInfo.input !== void 0 && /* @__PURE__ */ jsx39(SmartInputPreview, { toolName: confirmInfo.toolName, input: confirmInfo.input }),
10642
- confirmInfo.suggestedPattern && /* @__PURE__ */ jsxs37("div", { className: "flex items-start gap-2 p-3 rounded-lg bg-yellow-500/10 border border-yellow-500/20", children: [
10643
- /* @__PURE__ */ jsx39(AlertTriangle3, { className: "h-4 w-4 text-yellow-600 mt-0.5 shrink-0" }),
10644
- /* @__PURE__ */ jsxs37("div", { className: "text-sm min-w-0", children: [
10645
- /* @__PURE__ */ jsx39("div", { className: "font-medium text-yellow-800 dark:text-yellow-200", children: "Trust pattern suggestion" }),
10646
- /* @__PURE__ */ jsx39("div", { className: "font-mono text-xs mt-1 break-all", children: confirmInfo.suggestedPattern }),
10647
- /* @__PURE__ */ jsxs37("div", { className: "text-xs text-muted-foreground mt-1", children: [
10789
+ confirmInfo.input !== void 0 && /* @__PURE__ */ jsx38(SmartInputPreview, { toolName: confirmInfo.toolName, input: confirmInfo.input }),
10790
+ confirmInfo.suggestedPattern && /* @__PURE__ */ jsxs36("div", { className: "flex items-start gap-2 p-3 rounded-lg bg-yellow-500/10 border border-yellow-500/20", children: [
10791
+ /* @__PURE__ */ jsx38(AlertTriangle3, { className: "h-4 w-4 text-yellow-600 mt-0.5 shrink-0" }),
10792
+ /* @__PURE__ */ jsxs36("div", { className: "text-sm min-w-0", children: [
10793
+ /* @__PURE__ */ jsx38("div", { className: "font-medium text-yellow-800 dark:text-yellow-200", children: "Trust pattern suggestion" }),
10794
+ /* @__PURE__ */ jsx38("div", { className: "font-mono text-xs mt-1 break-all", children: confirmInfo.suggestedPattern }),
10795
+ /* @__PURE__ */ jsxs36("div", { className: "text-xs text-muted-foreground mt-1", children: [
10648
10796
  "Picking ",
10649
- /* @__PURE__ */ jsx39("span", { className: "font-medium", children: "Always" }),
10797
+ /* @__PURE__ */ jsx38("span", { className: "font-medium", children: "Always" }),
10650
10798
  " will whitelist matching calls for this project."
10651
10799
  ] })
10652
10800
  ] })
10653
10801
  ] })
10654
10802
  ] }),
10655
- /* @__PURE__ */ jsxs37(DialogFooter, { className: "gap-2 sm:gap-2 flex-wrap", children: [
10656
- /* @__PURE__ */ jsxs37(
10803
+ /* @__PURE__ */ jsxs36(DialogFooter, { className: "gap-2 sm:gap-2 flex-wrap", children: [
10804
+ /* @__PURE__ */ jsxs36(
10657
10805
  Button,
10658
10806
  {
10659
10807
  variant: "outline",
@@ -10662,11 +10810,11 @@ function ConfirmDialog() {
10662
10810
  title: "Reject this and all future calls matching the pattern (d)",
10663
10811
  children: [
10664
10812
  "Deny always ",
10665
- /* @__PURE__ */ jsx39("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background", children: "d" })
10813
+ /* @__PURE__ */ jsx38("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background", children: "d" })
10666
10814
  ]
10667
10815
  }
10668
10816
  ),
10669
- /* @__PURE__ */ jsxs37(
10817
+ /* @__PURE__ */ jsxs36(
10670
10818
  Button,
10671
10819
  {
10672
10820
  variant: "outline",
@@ -10675,11 +10823,11 @@ function ConfirmDialog() {
10675
10823
  title: "Reject this single call (Esc / n)",
10676
10824
  children: [
10677
10825
  "No ",
10678
- /* @__PURE__ */ jsx39("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background", children: "n" })
10826
+ /* @__PURE__ */ jsx38("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background", children: "n" })
10679
10827
  ]
10680
10828
  }
10681
10829
  ),
10682
- /* @__PURE__ */ jsxs37(
10830
+ /* @__PURE__ */ jsxs36(
10683
10831
  Button,
10684
10832
  {
10685
10833
  variant: "outline",
@@ -10688,11 +10836,11 @@ function ConfirmDialog() {
10688
10836
  title: "Approve and remember the pattern for the project (a)",
10689
10837
  children: [
10690
10838
  "Always ",
10691
- /* @__PURE__ */ jsx39("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background", children: "a" })
10839
+ /* @__PURE__ */ jsx38("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background", children: "a" })
10692
10840
  ]
10693
10841
  }
10694
10842
  ),
10695
- /* @__PURE__ */ jsxs37(
10843
+ /* @__PURE__ */ jsxs36(
10696
10844
  Button,
10697
10845
  {
10698
10846
  size: "sm",
@@ -10700,7 +10848,7 @@ function ConfirmDialog() {
10700
10848
  title: "Approve this single call (y)",
10701
10849
  children: [
10702
10850
  "Yes ",
10703
- /* @__PURE__ */ jsx39("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background/80", children: "y" })
10851
+ /* @__PURE__ */ jsx38("kbd", { className: "ml-1 text-[10px] border rounded px-1 bg-background/80", children: "y" })
10704
10852
  ]
10705
10853
  }
10706
10854
  )
@@ -10711,7 +10859,7 @@ function ConfirmDialog() {
10711
10859
  // src/components/ConfirmModal.tsx
10712
10860
  import { useEffect as useEffect21 } from "react";
10713
10861
  import { create as create15 } from "zustand";
10714
- import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
10862
+ import { jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
10715
10863
  var useConfirmModalStore = create15()((set, get) => ({
10716
10864
  request: null,
10717
10865
  open: (request) => {
@@ -10742,21 +10890,21 @@ function ConfirmModalHost() {
10742
10890
  window.addEventListener("keydown", onKey);
10743
10891
  return () => window.removeEventListener("keydown", onKey);
10744
10892
  }, [request]);
10745
- return /* @__PURE__ */ jsx40(
10893
+ return /* @__PURE__ */ jsx39(
10746
10894
  Dialog,
10747
10895
  {
10748
10896
  open: request !== null,
10749
10897
  onOpenChange: (open) => {
10750
10898
  if (!open) settle(false);
10751
10899
  },
10752
- children: /* @__PURE__ */ jsxs38(DialogContent, { className: "max-w-md", children: [
10753
- /* @__PURE__ */ jsxs38(DialogHeader, { children: [
10754
- /* @__PURE__ */ jsx40(DialogTitle, { children: request?.title }),
10755
- request?.message && /* @__PURE__ */ jsx40(DialogDescription, { children: request.message })
10900
+ children: /* @__PURE__ */ jsxs37(DialogContent, { className: "max-w-md", children: [
10901
+ /* @__PURE__ */ jsxs37(DialogHeader, { children: [
10902
+ /* @__PURE__ */ jsx39(DialogTitle, { children: request?.title }),
10903
+ request?.message && /* @__PURE__ */ jsx39(DialogDescription, { children: request.message })
10756
10904
  ] }),
10757
- /* @__PURE__ */ jsxs38(DialogFooter, { className: "gap-2", children: [
10758
- /* @__PURE__ */ jsx40(Button, { variant: "outline", size: "sm", onClick: () => settle(false), children: request?.cancelLabel ?? "Cancel" }),
10759
- /* @__PURE__ */ jsx40(
10905
+ /* @__PURE__ */ jsxs37(DialogFooter, { className: "gap-2", children: [
10906
+ /* @__PURE__ */ jsx39(Button, { variant: "outline", size: "sm", onClick: () => settle(false), children: request?.cancelLabel ?? "Cancel" }),
10907
+ /* @__PURE__ */ jsx39(
10760
10908
  Button,
10761
10909
  {
10762
10910
  variant: request?.danger ? "destructive" : "default",
@@ -10775,7 +10923,7 @@ function ConfirmModalHost() {
10775
10923
  // src/components/ConnectionBanner.tsx
10776
10924
  import { Loader2 as Loader23, RotateCcw as RotateCcw4, WifiOff, X as X10 } from "lucide-react";
10777
10925
  import { useEffect as useEffect22, useState as useState25 } from "react";
10778
- import { jsx as jsx41, jsxs as jsxs39 } from "react/jsx-runtime";
10926
+ import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
10779
10927
  function ConnectionBanner() {
10780
10928
  const wsStatus = useConfigStore((s) => s.wsStatus);
10781
10929
  const wsUrl = useConfigStore((s) => s.wsUrl);
@@ -10795,7 +10943,7 @@ function ConnectionBanner() {
10795
10943
  const isReconnecting = wsStatus.state === "reconnecting";
10796
10944
  const errorText = wsStatus.state === "closed" ? wsStatus.error : wsStatus.state === "reconnecting" ? wsStatus.lastError : void 0;
10797
10945
  const remaining = isReconnecting ? Math.max(0, Math.ceil((wsStatus.nextRetryAt - now) / 1e3)) : 0;
10798
- return /* @__PURE__ */ jsxs39(
10946
+ return /* @__PURE__ */ jsxs38(
10799
10947
  "div",
10800
10948
  {
10801
10949
  className: cn(
@@ -10803,12 +10951,12 @@ function ConnectionBanner() {
10803
10951
  isReconnecting ? "bg-orange-500/10 text-orange-700 dark:text-orange-300 border-orange-500/30" : "bg-red-500/10 text-red-700 dark:text-red-300 border-red-500/30"
10804
10952
  ),
10805
10953
  children: [
10806
- isReconnecting ? /* @__PURE__ */ jsx41(Loader23, { className: "h-4 w-4 animate-spin shrink-0" }) : /* @__PURE__ */ jsx41(WifiOff, { className: "h-4 w-4 shrink-0" }),
10807
- /* @__PURE__ */ jsxs39("div", { className: "flex-1 min-w-0", children: [
10808
- /* @__PURE__ */ jsx41("div", { className: "font-medium", children: isReconnecting ? `Reconnecting to backend (attempt ${wsStatus.attempt}) \u2014 retrying in ${remaining}s` : "Disconnected from backend" }),
10809
- errorText && /* @__PURE__ */ jsx41("div", { className: "text-xs opacity-80 truncate", children: errorText })
10954
+ isReconnecting ? /* @__PURE__ */ jsx40(Loader23, { className: "h-4 w-4 animate-spin shrink-0" }) : /* @__PURE__ */ jsx40(WifiOff, { className: "h-4 w-4 shrink-0" }),
10955
+ /* @__PURE__ */ jsxs38("div", { className: "flex-1 min-w-0", children: [
10956
+ /* @__PURE__ */ jsx40("div", { className: "font-medium", children: isReconnecting ? `Reconnecting to backend (attempt ${wsStatus.attempt}) \u2014 retrying in ${remaining}s` : "Disconnected from backend" }),
10957
+ errorText && /* @__PURE__ */ jsx40("div", { className: "text-xs opacity-80 truncate", children: errorText })
10810
10958
  ] }),
10811
- /* @__PURE__ */ jsxs39(
10959
+ /* @__PURE__ */ jsxs38(
10812
10960
  "button",
10813
10961
  {
10814
10962
  type: "button",
@@ -10820,19 +10968,19 @@ function ConnectionBanner() {
10820
10968
  ),
10821
10969
  title: "Retry connection now",
10822
10970
  children: [
10823
- /* @__PURE__ */ jsx41(RotateCcw4, { className: "h-3 w-3" }),
10971
+ /* @__PURE__ */ jsx40(RotateCcw4, { className: "h-3 w-3" }),
10824
10972
  "Retry now"
10825
10973
  ]
10826
10974
  }
10827
10975
  ),
10828
- /* @__PURE__ */ jsx41(
10976
+ /* @__PURE__ */ jsx40(
10829
10977
  "button",
10830
10978
  {
10831
10979
  type: "button",
10832
10980
  onClick: () => setDismissed(true),
10833
10981
  className: "text-current/60 hover:text-current shrink-0",
10834
10982
  title: "Dismiss (chip in topbar still shows status)",
10835
- children: /* @__PURE__ */ jsx41(X10, { className: "h-4 w-4" })
10983
+ children: /* @__PURE__ */ jsx40(X10, { className: "h-4 w-4" })
10836
10984
  }
10837
10985
  )
10838
10986
  ]
@@ -10843,7 +10991,7 @@ function ConnectionBanner() {
10843
10991
  // src/components/ErrorBoundary.tsx
10844
10992
  import { AlertTriangle as AlertTriangle4, RefreshCw as RefreshCw2 } from "lucide-react";
10845
10993
  import { Component } from "react";
10846
- import { jsx as jsx42, jsxs as jsxs40 } from "react/jsx-runtime";
10994
+ import { jsx as jsx41, jsxs as jsxs39 } from "react/jsx-runtime";
10847
10995
  var ErrorBoundary = class extends Component {
10848
10996
  state = { error: null };
10849
10997
  static getDerivedStateFromError(error) {
@@ -10858,17 +11006,17 @@ var ErrorBoundary = class extends Component {
10858
11006
  };
10859
11007
  render() {
10860
11008
  if (this.state.error) {
10861
- return /* @__PURE__ */ jsx42("div", { className: "flex items-center justify-center h-screen bg-background", children: /* @__PURE__ */ jsxs40("div", { className: "flex flex-col items-center gap-4 p-8 max-w-md text-center", children: [
10862
- /* @__PURE__ */ jsx42(AlertTriangle4, { className: "h-12 w-12 text-destructive" }),
10863
- /* @__PURE__ */ jsx42("h1", { className: "text-lg font-semibold", children: "Something went wrong" }),
10864
- /* @__PURE__ */ jsx42("p", { className: "text-sm text-muted-foreground", children: "A rendering error occurred. Your session is still active on the server \u2014 reloading will pick up where you left off." }),
10865
- /* @__PURE__ */ jsx42("pre", { className: "text-xs font-mono text-muted-foreground bg-muted/50 rounded p-3 max-h-32 overflow-auto w-full text-left", children: this.state.error.message }),
10866
- /* @__PURE__ */ jsxs40("div", { className: "flex gap-2", children: [
10867
- /* @__PURE__ */ jsxs40(Button, { size: "sm", variant: "outline", onClick: () => window.location.reload(), children: [
10868
- /* @__PURE__ */ jsx42(RefreshCw2, { className: "h-4 w-4 mr-1" }),
11009
+ return /* @__PURE__ */ jsx41("div", { className: "flex items-center justify-center h-screen bg-background", children: /* @__PURE__ */ jsxs39("div", { className: "flex flex-col items-center gap-4 p-8 max-w-md text-center", children: [
11010
+ /* @__PURE__ */ jsx41(AlertTriangle4, { className: "h-12 w-12 text-destructive" }),
11011
+ /* @__PURE__ */ jsx41("h1", { className: "text-lg font-semibold", children: "Something went wrong" }),
11012
+ /* @__PURE__ */ jsx41("p", { className: "text-sm text-muted-foreground", children: "A rendering error occurred. Your session is still active on the server \u2014 reloading will pick up where you left off." }),
11013
+ /* @__PURE__ */ jsx41("pre", { className: "text-xs font-mono text-muted-foreground bg-muted/50 rounded p-3 max-h-32 overflow-auto w-full text-left", children: this.state.error.message }),
11014
+ /* @__PURE__ */ jsxs39("div", { className: "flex gap-2", children: [
11015
+ /* @__PURE__ */ jsxs39(Button, { size: "sm", variant: "outline", onClick: () => window.location.reload(), children: [
11016
+ /* @__PURE__ */ jsx41(RefreshCw2, { className: "h-4 w-4 mr-1" }),
10869
11017
  "Reload page"
10870
11018
  ] }),
10871
- /* @__PURE__ */ jsx42(Button, { size: "sm", onClick: this.handleReset, children: "Try again" })
11019
+ /* @__PURE__ */ jsx41(Button, { size: "sm", onClick: this.handleReset, children: "Try again" })
10872
11020
  ] })
10873
11021
  ] }) });
10874
11022
  }
@@ -10878,7 +11026,7 @@ var ErrorBoundary = class extends Component {
10878
11026
 
10879
11027
  // src/components/QuickModelSwitcher.tsx
10880
11028
  import { ArrowRight as ArrowRight4, Cpu as Cpu6, Search as Search4 } from "lucide-react";
10881
- import { useEffect as useEffect23, useMemo as useMemo9, useRef as useRef17, useState as useState26 } from "react";
11029
+ import { useEffect as useEffect23, useMemo as useMemo10, useRef as useRef17, useState as useState26 } from "react";
10882
11030
 
10883
11031
  // src/components/QuickModelSwitcher.filter.ts
10884
11032
  function buildModelCandidates(saved, modelsByProvider, query, currentProvider, currentModel) {
@@ -10906,7 +11054,7 @@ function buildModelCandidates(saved, modelsByProvider, query, currentProvider, c
10906
11054
  }
10907
11055
 
10908
11056
  // src/components/QuickModelSwitcher.tsx
10909
- import { jsx as jsx43, jsxs as jsxs41 } from "react/jsx-runtime";
11057
+ import { jsx as jsx42, jsxs as jsxs40 } from "react/jsx-runtime";
10910
11058
  function QuickModelSwitcher() {
10911
11059
  const open = useUIStore((s) => s.modelSwitcherOpen);
10912
11060
  const setOpen = useUIStore((s) => s.setModelSwitcherOpen);
@@ -10967,7 +11115,7 @@ function QuickModelSwitcher() {
10967
11115
  }
10968
11116
  }
10969
11117
  }, [open, saved, modelsByProvider, listProviderModels]);
10970
- const candidates = useMemo9(
11118
+ const candidates = useMemo10(
10971
11119
  () => buildModelCandidates(
10972
11120
  saved,
10973
11121
  modelsByProvider,
@@ -10987,7 +11135,7 @@ function QuickModelSwitcher() {
10987
11135
  setOpen(false);
10988
11136
  };
10989
11137
  if (!open) return null;
10990
- return /* @__PURE__ */ jsx43(
11138
+ return /* @__PURE__ */ jsx42(
10991
11139
  "div",
10992
11140
  {
10993
11141
  className: "fixed inset-0 z-50 flex items-start justify-center bg-background/60 backdrop-blur-sm pt-[15vh]",
@@ -10997,10 +11145,10 @@ function QuickModelSwitcher() {
10997
11145
  onKeyDown: (e) => {
10998
11146
  if (e.key === "Escape") setOpen(false);
10999
11147
  },
11000
- children: /* @__PURE__ */ jsxs41("div", { className: "w-full max-w-xl rounded-xl border bg-popover shadow-2xl overflow-hidden", children: [
11001
- /* @__PURE__ */ jsxs41("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [
11002
- /* @__PURE__ */ jsx43(Search4, { className: "h-4 w-4 text-muted-foreground" }),
11003
- /* @__PURE__ */ jsx43(
11148
+ children: /* @__PURE__ */ jsxs40("div", { className: "w-full max-w-xl rounded-xl border bg-popover shadow-2xl overflow-hidden", children: [
11149
+ /* @__PURE__ */ jsxs40("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [
11150
+ /* @__PURE__ */ jsx42(Search4, { className: "h-4 w-4 text-muted-foreground" }),
11151
+ /* @__PURE__ */ jsx42(
11004
11152
  "input",
11005
11153
  {
11006
11154
  ref: inputRef,
@@ -11028,9 +11176,9 @@ function QuickModelSwitcher() {
11028
11176
  className: "flex-1 bg-transparent outline-none text-sm placeholder:text-muted-foreground"
11029
11177
  }
11030
11178
  ),
11031
- /* @__PURE__ */ jsx43("span", { className: "text-[10px] text-muted-foreground font-mono", children: "\u2191\u2193 \xB7 Enter \xB7 Esc" })
11179
+ /* @__PURE__ */ jsx42("span", { className: "text-[10px] text-muted-foreground font-mono", children: "\u2191\u2193 \xB7 Enter \xB7 Esc" })
11032
11180
  ] }),
11033
- /* @__PURE__ */ jsx43("div", { className: "max-h-[50vh] overflow-y-auto py-1", children: candidates.length === 0 ? /* @__PURE__ */ jsx43("div", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: saved.length === 0 ? "No saved providers \u2014 register a key in Settings first." : "Loading models\u2026" }) : candidates.map((c, idx) => /* @__PURE__ */ jsxs41(
11181
+ /* @__PURE__ */ jsx42("div", { className: "max-h-[50vh] overflow-y-auto py-1", children: candidates.length === 0 ? /* @__PURE__ */ jsx42("div", { className: "px-4 py-8 text-center text-sm text-muted-foreground", children: saved.length === 0 ? "No saved providers \u2014 register a key in Settings first." : "Loading models\u2026" }) : candidates.map((c, idx) => /* @__PURE__ */ jsxs40(
11034
11182
  "button",
11035
11183
  {
11036
11184
  type: "button",
@@ -11042,7 +11190,7 @@ function QuickModelSwitcher() {
11042
11190
  c.isCurrent && "font-medium"
11043
11191
  ),
11044
11192
  children: [
11045
- /* @__PURE__ */ jsx43(
11193
+ /* @__PURE__ */ jsx42(
11046
11194
  Cpu6,
11047
11195
  {
11048
11196
  className: cn(
@@ -11051,19 +11199,19 @@ function QuickModelSwitcher() {
11051
11199
  )
11052
11200
  }
11053
11201
  ),
11054
- /* @__PURE__ */ jsxs41("div", { className: "min-w-0 flex-1", children: [
11055
- /* @__PURE__ */ jsxs41("div", { className: "truncate", children: [
11056
- /* @__PURE__ */ jsx43("span", { className: "text-muted-foreground", children: c.provider }),
11057
- /* @__PURE__ */ jsx43("span", { className: "mx-1 text-muted-foreground/40", children: "\xB7" }),
11058
- /* @__PURE__ */ jsx43("span", { children: c.modelName })
11202
+ /* @__PURE__ */ jsxs40("div", { className: "min-w-0 flex-1", children: [
11203
+ /* @__PURE__ */ jsxs40("div", { className: "truncate", children: [
11204
+ /* @__PURE__ */ jsx42("span", { className: "text-muted-foreground", children: c.provider }),
11205
+ /* @__PURE__ */ jsx42("span", { className: "mx-1 text-muted-foreground/40", children: "\xB7" }),
11206
+ /* @__PURE__ */ jsx42("span", { children: c.modelName })
11059
11207
  ] }),
11060
- c.contextWindow && /* @__PURE__ */ jsxs41("div", { className: "text-[10px] text-muted-foreground font-mono", children: [
11208
+ c.contextWindow && /* @__PURE__ */ jsxs40("div", { className: "text-[10px] text-muted-foreground font-mono", children: [
11061
11209
  c.model,
11062
11210
  " \xB7 ctx ",
11063
11211
  c.contextWindow.toLocaleString()
11064
11212
  ] })
11065
11213
  ] }),
11066
- c.isCurrent ? /* @__PURE__ */ jsx43("span", { className: "text-[10px] uppercase tracking-wide text-primary font-semibold", children: "active" }) : /* @__PURE__ */ jsx43(ArrowRight4, { className: "h-3.5 w-3.5 text-muted-foreground opacity-0 group-hover:opacity-100" })
11214
+ c.isCurrent ? /* @__PURE__ */ jsx42("span", { className: "text-[10px] uppercase tracking-wide text-primary font-semibold", children: "active" }) : /* @__PURE__ */ jsx42(ArrowRight4, { className: "h-3.5 w-3.5 text-muted-foreground opacity-0 group-hover:opacity-100" })
11067
11215
  ]
11068
11216
  },
11069
11217
  `${c.provider}:${c.model}`
@@ -11093,11 +11241,11 @@ import {
11093
11241
  import { useState as useState28, useEffect as useEffect24, useCallback as useCallback13 } from "react";
11094
11242
 
11095
11243
  // src/components/ui/input.tsx
11096
- import * as React4 from "react";
11097
- import { jsx as jsx44 } from "react/jsx-runtime";
11098
- var Input = React4.forwardRef(
11244
+ import * as React3 from "react";
11245
+ import { jsx as jsx43 } from "react/jsx-runtime";
11246
+ var Input = React3.forwardRef(
11099
11247
  ({ className, type, ...props }, ref) => {
11100
- return /* @__PURE__ */ jsx44(
11248
+ return /* @__PURE__ */ jsx43(
11101
11249
  "input",
11102
11250
  {
11103
11251
  type,
@@ -11113,6 +11261,41 @@ var Input = React4.forwardRef(
11113
11261
  );
11114
11262
  Input.displayName = "Input";
11115
11263
 
11264
+ // src/components/ui/scroll-area.tsx
11265
+ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
11266
+ import * as React4 from "react";
11267
+ import { jsx as jsx44, jsxs as jsxs41 } from "react/jsx-runtime";
11268
+ var ScrollArea = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs41(
11269
+ ScrollAreaPrimitive.Root,
11270
+ {
11271
+ ref,
11272
+ className: cn("relative overflow-hidden", className),
11273
+ ...props,
11274
+ children: [
11275
+ /* @__PURE__ */ jsx44(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
11276
+ /* @__PURE__ */ jsx44(ScrollBar, {}),
11277
+ /* @__PURE__ */ jsx44(ScrollAreaPrimitive.Corner, {})
11278
+ ]
11279
+ }
11280
+ ));
11281
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
11282
+ var ScrollBar = React4.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx44(
11283
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
11284
+ {
11285
+ ref,
11286
+ orientation,
11287
+ className: cn(
11288
+ "flex touch-none select-none transition-colors",
11289
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
11290
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
11291
+ className
11292
+ ),
11293
+ ...props,
11294
+ children: /* @__PURE__ */ jsx44(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
11295
+ }
11296
+ ));
11297
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
11298
+
11116
11299
  // src/components/ui/tabs.tsx
11117
11300
  import * as TabsPrimitive from "@radix-ui/react-tabs";
11118
11301
  import * as React5 from "react";
@@ -13003,7 +13186,7 @@ import {
13003
13186
  Database as Database3,
13004
13187
  FolderOpen as FolderOpen3,
13005
13188
  Target,
13006
- Wrench as Wrench7,
13189
+ Wrench as Wrench6,
13007
13190
  X as X13,
13008
13191
  FileText as FileText3,
13009
13192
  Terminal as Terminal6,
@@ -13085,7 +13268,7 @@ var TOOL_ICONS = {
13085
13268
  exec: /* @__PURE__ */ jsx55(Terminal6, { className: "h-3 w-3" }),
13086
13269
  glob: /* @__PURE__ */ jsx55(FolderOpen3, { className: "h-3 w-3" }),
13087
13270
  grep: /* @__PURE__ */ jsx55(Target, { className: "h-3 w-3" }),
13088
- edit: /* @__PURE__ */ jsx55(Wrench7, { className: "h-3 w-3" }),
13271
+ edit: /* @__PURE__ */ jsx55(Wrench6, { className: "h-3 w-3" }),
13089
13272
  fetch: /* @__PURE__ */ jsx55(Globe5, { className: "h-3 w-3" }),
13090
13273
  search: /* @__PURE__ */ jsx55(Target, { className: "h-3 w-3" })
13091
13274
  };
@@ -13132,7 +13315,7 @@ function AgentNode({ data }) {
13132
13315
  /* @__PURE__ */ jsxs50("div", { className: "flex-1 min-w-0", children: [
13133
13316
  /* @__PURE__ */ jsx55("div", { className: "text-[10px] font-bold truncate", style: { color: colors }, children: data.label }),
13134
13317
  data.currentTool && /* @__PURE__ */ jsxs50("div", { className: "flex items-center gap-1 text-[9px] text-amber-400/70", children: [
13135
- /* @__PURE__ */ jsx55(Wrench7, { className: "h-2.5 w-2.5" }),
13318
+ /* @__PURE__ */ jsx55(Wrench6, { className: "h-2.5 w-2.5" }),
13136
13319
  /* @__PURE__ */ jsx55("span", { className: "truncate font-mono", children: data.currentTool })
13137
13320
  ] })
13138
13321
  ] }),
@@ -13172,7 +13355,7 @@ function AgentNode({ data }) {
13172
13355
  }
13173
13356
  function ToolNode({ data }) {
13174
13357
  const colors = data.color || "#f59e0b";
13175
- const icon = TOOL_ICONS[data.label?.toLowerCase() ?? ""] || /* @__PURE__ */ jsx55(Wrench7, { className: "h-3 w-3" });
13358
+ const icon = TOOL_ICONS[data.label?.toLowerCase() ?? ""] || /* @__PURE__ */ jsx55(Wrench6, { className: "h-3 w-3" });
13176
13359
  return /* @__PURE__ */ jsxs50("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/10 p-2 min-w-[100px] transition-all", children: [
13177
13360
  /* @__PURE__ */ jsxs50("div", { className: "flex items-center gap-2", children: [
13178
13361
  /* @__PURE__ */ jsx55("span", { style: { color: colors }, children: icon }),
@@ -13744,7 +13927,7 @@ import {
13744
13927
  Loader2 as Loader28,
13745
13928
  Minimize2
13746
13929
  } from "lucide-react";
13747
- import { useCallback as useCallback17, useEffect as useEffect29, useMemo as useMemo11, useRef as useRef19, useState as useState32 } from "react";
13930
+ import { useCallback as useCallback17, useEffect as useEffect29, useMemo as useMemo12, useRef as useRef19, useState as useState32 } from "react";
13748
13931
  import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
13749
13932
  var EXT_ICONS = {
13750
13933
  // ── Code ──
@@ -13970,7 +14153,7 @@ function FileExplorer() {
13970
14153
  const segments = cwd.replace(/\\/g, "/").split("/").filter(Boolean);
13971
14154
  return (segments[segments.length - 1] ?? "") === projectName;
13972
14155
  })();
13973
- const breadcrumbs = useMemo11(() => {
14156
+ const breadcrumbs = useMemo12(() => {
13974
14157
  if (!cwd || !projectName) return [];
13975
14158
  const norm = cwd.replace(/\\/g, "/");
13976
14159
  const segments = norm.split("/").filter(Boolean);
@@ -14063,7 +14246,7 @@ function FileExplorer() {
14063
14246
  }, [treeLoading]);
14064
14247
  const [selectedPath, setSelectedPath] = useState32(null);
14065
14248
  const [globalExpand, setGlobalExpand] = useState32(null);
14066
- const dirCount = useMemo11(() => {
14249
+ const dirCount = useMemo12(() => {
14067
14250
  let count = 0;
14068
14251
  const walk = (nodes) => {
14069
14252
  for (const n of nodes) {
@@ -14074,7 +14257,7 @@ function FileExplorer() {
14074
14257
  walk(tree);
14075
14258
  return count;
14076
14259
  }, [tree]);
14077
- const cwdStats = useMemo11(() => {
14260
+ const cwdStats = useMemo12(() => {
14078
14261
  let files = 0;
14079
14262
  let dirs = 0;
14080
14263
  for (const n of tree) {
@@ -14774,12 +14957,12 @@ function ProjectsPanel({ fullView }) {
14774
14957
  }
14775
14958
 
14776
14959
  // src/components/SidePanel/AgentsPanel.tsx
14777
- import { Bot as Bot10, LayoutGrid as LayoutGrid2, Wrench as Wrench9 } from "lucide-react";
14778
- import { useMemo as useMemo13, useState as useState36 } from "react";
14960
+ import { Bot as Bot10, LayoutGrid as LayoutGrid2, Wrench as Wrench8 } from "lucide-react";
14961
+ import { useMemo as useMemo14, useState as useState36 } from "react";
14779
14962
 
14780
14963
  // src/components/FleetPanel.tsx
14781
- import { Bot as Bot9, Check as Check7, ChevronDown as ChevronDown9, ChevronRight as ChevronRight8, Clock as Clock11, Copy as Copy4, Cpu as Cpu12, Crown, Wrench as Wrench8, X as X14, Zap as Zap9 } from "lucide-react";
14782
- import { useCallback as useCallback19, useMemo as useMemo12, useState as useState35 } from "react";
14964
+ import { Bot as Bot9, Check as Check7, ChevronDown as ChevronDown9, ChevronRight as ChevronRight8, Clock as Clock11, Copy as Copy4, Cpu as Cpu12, Crown, Wrench as Wrench7, X as X14, Zap as Zap9 } from "lucide-react";
14965
+ import { useCallback as useCallback19, useMemo as useMemo13, useState as useState35 } from "react";
14783
14966
 
14784
14967
  // src/components/ui/sparkline.tsx
14785
14968
  import { jsx as jsx59 } from "react/jsx-runtime";
@@ -14985,7 +15168,7 @@ function AgentDetail({
14985
15168
  active ? "border-primary/30 bg-primary/[0.04]" : "border-border bg-muted/30"
14986
15169
  ),
14987
15170
  children: [
14988
- /* @__PURE__ */ jsx60(Wrench8, { className: cn("h-3.5 w-3.5", active ? "text-primary animate-pulse" : "text-muted-foreground") }),
15171
+ /* @__PURE__ */ jsx60(Wrench7, { className: cn("h-3.5 w-3.5", active ? "text-primary animate-pulse" : "text-muted-foreground") }),
14989
15172
  /* @__PURE__ */ jsx60("span", { className: "text-xs font-mono", children: tool }),
14990
15173
  /* @__PURE__ */ jsx60("span", { className: "text-[10px] text-muted-foreground ml-auto", children: agent.currentTool ? "running\u2026" : "last tool" })
14991
15174
  ]
@@ -15122,7 +15305,7 @@ function AgentCard({
15122
15305
  ),
15123
15306
  title: a.currentTool ? `running ${tool}` : `last: ${tool}`,
15124
15307
  children: [
15125
- /* @__PURE__ */ jsx60(Wrench8, { className: cn("h-2.5 w-2.5 shrink-0", active && "animate-pulse") }),
15308
+ /* @__PURE__ */ jsx60(Wrench7, { className: cn("h-2.5 w-2.5 shrink-0", active && "animate-pulse") }),
15126
15309
  /* @__PURE__ */ jsx60("span", { className: "truncate font-mono", children: tool })
15127
15310
  ]
15128
15311
  }
@@ -15158,7 +15341,7 @@ function FleetPanel({
15158
15341
  const agents = useFleetStore((s) => s.agents);
15159
15342
  const [collapsed, setCollapsed] = useState35(true);
15160
15343
  const [selectedId, setSelectedId] = useState35(null);
15161
- const list = useMemo12(() => {
15344
+ const list = useMemo13(() => {
15162
15345
  const arr = Array.from(agents.values());
15163
15346
  arr.sort((x, y) => {
15164
15347
  const xa = x.status === "running" ? 0 : 1;
@@ -15261,7 +15444,7 @@ function AgentRow2({ agent, onClick }) {
15261
15444
  /* @__PURE__ */ jsx61("span", { className: "tabular ml-auto text-[10px] text-foreground/70", children: fmtCost3(agent.costUsd) })
15262
15445
  ] }),
15263
15446
  (agent.currentTool || agent.lastTool) && /* @__PURE__ */ jsxs55("div", { className: "flex items-center gap-1 mt-1 text-[10px] text-muted-foreground truncate", children: [
15264
- /* @__PURE__ */ jsx61(Wrench9, { className: cn("h-2.5 w-2.5 shrink-0", active && "animate-pulse text-primary") }),
15447
+ /* @__PURE__ */ jsx61(Wrench8, { className: cn("h-2.5 w-2.5 shrink-0", active && "animate-pulse text-primary") }),
15265
15448
  /* @__PURE__ */ jsx61("span", { className: "truncate font-mono", children: agent.currentTool ?? agent.lastTool })
15266
15449
  ] })
15267
15450
  ]
@@ -15272,7 +15455,7 @@ function AgentsPanel() {
15272
15455
  const fleetAgents = useFleetStore((s) => s.agents);
15273
15456
  const setCurrentView = useUIStore((s) => s.setCurrentView);
15274
15457
  const [selectedAgentId, setSelectedAgentId] = useState36(null);
15275
- const fleetList = useMemo13(() => {
15458
+ const fleetList = useMemo14(() => {
15276
15459
  const arr = Array.from(fleetAgents.values());
15277
15460
  arr.sort((x, y) => {
15278
15461
  const xa = x.status === "running" ? 0 : 1;
@@ -15331,7 +15514,7 @@ import {
15331
15514
  Trash2 as Trash24,
15332
15515
  X as X15
15333
15516
  } from "lucide-react";
15334
- import { useCallback as useCallback20, useEffect as useEffect32, useMemo as useMemo14, useState as useState37 } from "react";
15517
+ import { useCallback as useCallback20, useEffect as useEffect32, useMemo as useMemo15, useState as useState37 } from "react";
15335
15518
  import { Fragment as Fragment15, jsx as jsx62, jsxs as jsxs56 } from "react/jsx-runtime";
15336
15519
  var formatRelative = (iso) => {
15337
15520
  const ts = Date.parse(iso);
@@ -15378,7 +15561,7 @@ function SessionList({
15378
15561
  },
15379
15562
  [resumeSession]
15380
15563
  );
15381
- const emptySessionIds = useMemo14(
15564
+ const emptySessionIds = useMemo15(
15382
15565
  () => getEmptySessionIds(historyEntries),
15383
15566
  [historyEntries]
15384
15567
  );
@@ -15644,7 +15827,7 @@ import {
15644
15827
  Wifi as Wifi2,
15645
15828
  WifiOff as WifiOff3
15646
15829
  } from "lucide-react";
15647
- import { useCallback as useCallback21, useEffect as useEffect34, useMemo as useMemo15, useState as useState39 } from "react";
15830
+ import { useCallback as useCallback21, useEffect as useEffect34, useMemo as useMemo16, useState as useState39 } from "react";
15648
15831
  import { jsx as jsx64, jsxs as jsxs58 } from "react/jsx-runtime";
15649
15832
  function fmtCost4(v) {
15650
15833
  if (v <= 0) return "$0.000";
@@ -15779,7 +15962,7 @@ function SessionPanel() {
15779
15962
  const t = setInterval(() => setNow(Date.now()), 1e3);
15780
15963
  return () => clearInterval(t);
15781
15964
  }, [startedAt]);
15782
- const runningAgents = useMemo15(
15965
+ const runningAgents = useMemo16(
15783
15966
  () => Array.from(fleetAgents.values()).filter((a) => a.status === "running").length,
15784
15967
  [fleetAgents]
15785
15968
  );
@@ -16215,7 +16398,7 @@ function SidePanel() {
16215
16398
 
16216
16399
  // src/components/WorkspaceDock.tsx
16217
16400
  import { Bot as Bot11, GitBranch as GitBranch3, ListTodo as ListTodo2, Maximize2 as Maximize22, Rocket as Rocket4, Target as Target3, Users as Users3 } from "lucide-react";
16218
- import { useCallback as useCallback26, useEffect as useEffect41, useMemo as useMemo16, useRef as useRef24, useState as useState46 } from "react";
16401
+ import { useCallback as useCallback26, useEffect as useEffect41, useMemo as useMemo17, useRef as useRef24, useState as useState46 } from "react";
16219
16402
 
16220
16403
  // src/components/CollabPanel.tsx
16221
16404
  import { Eye as Eye2, LogIn, LogOut, MessageSquareWarning, Pause as Pause5, Play as Play6, Users as Users2 } from "lucide-react";
@@ -17248,7 +17431,7 @@ function WorkspaceDock({ sessionId }) {
17248
17431
  );
17249
17432
  const [worktreeView, setWorktreeView] = useState46("graph");
17250
17433
  const fleetTotal = fleetAgents.size;
17251
- const fleetRunning = useMemo16(
17434
+ const fleetRunning = useMemo17(
17252
17435
  () => Array.from(fleetAgents.values()).filter((a) => a.status === "running").length,
17253
17436
  [fleetAgents]
17254
17437
  );
@@ -17398,8 +17581,8 @@ function WorkspaceDock({ sessionId }) {
17398
17581
  }
17399
17582
 
17400
17583
  // src/components/AgentsMonitor.tsx
17401
- import { Bot as Bot12, ChevronLeft, ChevronRight as ChevronRight10, Cpu as Cpu14, Crown as Crown2, Loader2 as Loader211, Wrench as Wrench10, X as X16, Zap as Zap10 } from "lucide-react";
17402
- import { useCallback as useCallback27, useEffect as useEffect42, useMemo as useMemo17, useState as useState47 } from "react";
17584
+ import { Bot as Bot12, ChevronLeft, ChevronRight as ChevronRight10, Cpu as Cpu14, Crown as Crown2, Loader2 as Loader211, Wrench as Wrench9, X as X16, Zap as Zap10 } from "lucide-react";
17585
+ import { useCallback as useCallback27, useEffect as useEffect42, useMemo as useMemo18, useState as useState47 } from "react";
17403
17586
  import { jsx as jsx73, jsxs as jsxs67 } from "react/jsx-runtime";
17404
17587
  function fmtCost5(v) {
17405
17588
  if (v <= 0) return "$0";
@@ -17499,7 +17682,7 @@ function AgentCard2({ agent, isLeader }) {
17499
17682
  ] })
17500
17683
  ] }),
17501
17684
  (agent.currentTool || agent.lastTool) && /* @__PURE__ */ jsxs67("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground", children: [
17502
- /* @__PURE__ */ jsx73(Wrench10, { className: cn("h-3 w-3", active && "animate-pulse text-primary") }),
17685
+ /* @__PURE__ */ jsx73(Wrench9, { className: cn("h-3 w-3", active && "animate-pulse text-primary") }),
17503
17686
  /* @__PURE__ */ jsx73("span", { className: "font-mono", children: agent.currentTool ?? agent.lastTool }),
17504
17687
  active && /* @__PURE__ */ jsx73(Loader211, { className: "h-3 w-3 animate-spin" })
17505
17688
  ] }),
@@ -17525,7 +17708,7 @@ function AgentsMonitor({ onClose }) {
17525
17708
  const fleetAgents = useFleetStore((s) => s.agents);
17526
17709
  const leaderId = useFleetStore((s) => s.leaderId);
17527
17710
  const [selectedIdx, setSelectedIdx] = useState47(0);
17528
- const fleetList = useMemo17(() => {
17711
+ const fleetList = useMemo18(() => {
17529
17712
  const arr = Array.from(fleetAgents.values());
17530
17713
  arr.sort((x, y) => {
17531
17714
  if (x.id === leaderId) return -1;
@@ -17664,11 +17847,11 @@ import {
17664
17847
  Loader2 as Loader212,
17665
17848
  Timer as Timer2,
17666
17849
  Users as Users4,
17667
- Wrench as Wrench11,
17850
+ Wrench as Wrench10,
17668
17851
  XCircle as XCircle9,
17669
17852
  Zap as Zap11
17670
17853
  } from "lucide-react";
17671
- import { useCallback as useCallback28, useEffect as useEffect43, useMemo as useMemo18, useState as useState48 } from "react";
17854
+ import { useCallback as useCallback28, useEffect as useEffect43, useMemo as useMemo19, useState as useState48 } from "react";
17672
17855
 
17673
17856
  // src/components/ui/dropdown-menu.tsx
17674
17857
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
@@ -17901,7 +18084,7 @@ function FleetAgentDetailPanel({
17901
18084
  }, []);
17902
18085
  const totalToolDuration = agent.toolLog.reduce((sum, t) => sum + t.durationMs, 0);
17903
18086
  const avgToolDuration = agent.toolLog.length > 0 ? Math.round(totalToolDuration / agent.toolLog.length) : 0;
17904
- const uniqueTools = useMemo18(() => {
18087
+ const uniqueTools = useMemo19(() => {
17905
18088
  const tools = /* @__PURE__ */ new Set();
17906
18089
  agent.toolLog.forEach((t) => tools.add(t.name));
17907
18090
  return tools.size;
@@ -18025,7 +18208,7 @@ function FleetAgentDetailPanel({
18025
18208
  "rounded-lg border px-4 py-3 flex items-center gap-3",
18026
18209
  active ? "border-primary/30 bg-primary/[0.04]" : "border-border bg-muted/30"
18027
18210
  ), children: [
18028
- /* @__PURE__ */ jsx77(Wrench11, { className: cn("h-4 w-4", active ? "text-primary animate-pulse" : "text-muted-foreground") }),
18211
+ /* @__PURE__ */ jsx77(Wrench10, { className: cn("h-4 w-4", active ? "text-primary animate-pulse" : "text-muted-foreground") }),
18029
18212
  /* @__PURE__ */ jsx77("span", { className: "text-sm font-mono font-medium", children: agent.currentTool }),
18030
18213
  active ? /* @__PURE__ */ jsxs71("span", { className: "ml-auto flex items-center gap-1.5 text-[10px] text-primary", children: [
18031
18214
  /* @__PURE__ */ jsx77(Loader212, { className: "h-3 w-3 animate-spin" }),
@@ -18111,7 +18294,7 @@ function FleetAgentDetailPanel({
18111
18294
  className: "w-full flex items-center justify-between px-4 py-2 border-b bg-muted/30 hover:bg-muted/50 transition-colors",
18112
18295
  children: [
18113
18296
  /* @__PURE__ */ jsxs71("span", { className: "text-[10px] font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-2", children: [
18114
- /* @__PURE__ */ jsx77(Wrench11, { className: "h-3 w-3" }),
18297
+ /* @__PURE__ */ jsx77(Wrench10, { className: "h-3 w-3" }),
18115
18298
  "Tool Log (",
18116
18299
  agent.toolLog.length,
18117
18300
  " calls)"
@@ -18216,7 +18399,7 @@ function FleetMonitor({
18216
18399
  const t = setInterval(() => setNowTick(Date.now()), 1e3);
18217
18400
  return () => clearInterval(t);
18218
18401
  }, []);
18219
- const fleetList = useMemo18(() => {
18402
+ const fleetList = useMemo19(() => {
18220
18403
  const arr = Array.from(fleetAgents.values());
18221
18404
  arr.sort((x, y) => {
18222
18405
  if (x.id === leaderId) return -1;
@@ -18228,7 +18411,7 @@ function FleetMonitor({
18228
18411
  });
18229
18412
  return arr;
18230
18413
  }, [fleetAgents, leaderId]);
18231
- const totalCost = useMemo18(
18414
+ const totalCost = useMemo19(
18232
18415
  () => Array.from(fleetAgents.values()).reduce((sum, a) => sum + a.costUsd, 0),
18233
18416
  [fleetAgents]
18234
18417
  );