@wrongstack/webui 0.77.0 → 0.82.6

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.html CHANGED
@@ -5,10 +5,10 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/wrongstack.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>WrongStack WebUI</title>
8
- <script type="module" crossorigin src="/assets/index-H4ofeiKr.js"></script>
9
- <link rel="modulepreload" crossorigin href="/assets/vendor-DBuK7aZd.js">
8
+ <script type="module" crossorigin src="/assets/index-D1cZ__pQ.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/assets/vendor-CumDpIdV.js">
10
10
  <link rel="stylesheet" crossorigin href="/assets/vendor-DW1jimNH.css">
11
- <link rel="stylesheet" crossorigin href="/assets/index-Df1jRLwk.css">
11
+ <link rel="stylesheet" crossorigin href="/assets/index-DB5NTtW7.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
package/dist/index.js CHANGED
@@ -473,19 +473,25 @@ function getWSClient(url) {
473
473
  // src/stores/chat-store.ts
474
474
  import { create } from "zustand";
475
475
  import { persist } from "zustand/middleware";
476
+ function expectDefined(value) {
477
+ if (value === null || value === void 0) {
478
+ throw new Error("Expected value to be defined");
479
+ }
480
+ return value;
481
+ }
476
482
  function dedupeRepeatedBlocks(text) {
477
483
  if (!text) return text;
478
484
  const paraSplit = text.split(/\n{2,}/);
479
485
  const paras = [];
480
486
  for (const p of paraSplit) {
481
- if (paras.length > 0 && paras[paras.length - 1].trim() === p.trim()) continue;
487
+ if (paras.length > 0 && paras[paras.length - 1]?.trim() === p.trim()) continue;
482
488
  paras.push(p);
483
489
  }
484
490
  const cleaned = paras.map((p) => {
485
491
  const lines = p.split("\n");
486
492
  const out = [];
487
493
  for (const line of lines) {
488
- if (out.length > 0 && line.trim().length > 0 && out[out.length - 1].trim() === line.trim()) {
494
+ if (out.length > 0 && line.trim().length > 0 && out[out.length - 1]?.trim() === line.trim()) {
489
495
  continue;
490
496
  }
491
497
  out.push(line);
@@ -595,7 +601,7 @@ var useChatStore = create()(
595
601
  if (queue.length === 0) return null;
596
602
  const [next, ...rest] = queue;
597
603
  set({ queue: rest });
598
- return next;
604
+ return expectDefined(next);
599
605
  },
600
606
  removeQueued: (idx) => set((state) => ({ queue: state.queue.filter((_, i) => i !== idx) })),
601
607
  clearQueue: () => set({ queue: [] }),
@@ -1052,6 +1058,12 @@ function notifyIfHidden(title, body, tag) {
1052
1058
  }
1053
1059
 
1054
1060
  // src/hooks/ws-handlers.ts
1061
+ function expectDefined2(value) {
1062
+ if (value === null || value === void 0) {
1063
+ throw new Error("Expected value to be defined");
1064
+ }
1065
+ return value;
1066
+ }
1055
1067
  function handleSessionStart(msg) {
1056
1068
  const payload = msg.payload;
1057
1069
  const prev = useSessionStore.getState().session?.id;
@@ -1101,8 +1113,8 @@ function handleSessionStart(msg) {
1101
1113
  const all = useChatStore.getState().messages;
1102
1114
  let last;
1103
1115
  for (let i = all.length - 1; i >= 0; i--) {
1104
- if (all[i].toolUseId === String(b.tool_use_id ?? "")) {
1105
- last = all[i];
1116
+ if (all[i]?.toolUseId === String(b.tool_use_id ?? "")) {
1117
+ last = expectDefined2(all[i]);
1106
1118
  break;
1107
1119
  }
1108
1120
  }
@@ -1147,7 +1159,7 @@ function handleKeyOperationResult(msg) {
1147
1159
  function handleContextCompacted(msg) {
1148
1160
  const payload = msg.payload;
1149
1161
  let summary = payload.reductions.length ? payload.reductions.map((r) => `${r.phase}: ${r.saved}`).join(", ") : "no-op";
1150
- if (payload.repaired) summary += `; repaired ${payload.repaired.removedToolUses.length} tool_use, ${payload.repaired.removedToolResults.length} tool_result, ${payload.repaired.removedMessages} empty messages`;
1162
+ if (payload.repaired) summary += `; repaired ${payload.repaired.removedToolUses?.length ?? 0} tool_use, ${payload.repaired.removedToolResults?.length ?? 0} tool_result, ${payload.repaired.removedMessages} empty messages`;
1151
1163
  useChatStore.getState().addMessage({ role: "assistant", content: `\u{1F5DC}\uFE0F Context compacted: ${payload.before} \u2192 ${payload.after} tokens (saved ~${payload.saved}). ${summary}` });
1152
1164
  useSessionStore.setState({ lastInputTokens: payload.after });
1153
1165
  }
@@ -1261,14 +1273,14 @@ function handleRunResult(msg) {
1261
1273
  let lastAssistantIdx = -1;
1262
1274
  let toolCount = 0;
1263
1275
  for (let i = all.length - 1; i >= 0; i--) {
1264
- const m = all[i];
1276
+ const m = expectDefined2(all[i]);
1265
1277
  if (m.role === "assistant" && lastAssistantIdx === -1 && m.content) lastAssistantIdx = i;
1266
1278
  if (m.role === "tool" && m.timestamp >= runStart.at) toolCount += 1;
1267
1279
  if (m.role === "user" && m.timestamp <= runStart.at) break;
1268
1280
  }
1269
1281
  if (lastAssistantIdx !== -1) {
1270
1282
  const sessionCost = useSessionStore.getState().cost;
1271
- useChatStore.getState().updateMessage(all[lastAssistantIdx].id, { runSummary: { iterations: payload.iterations, tools: toolCount, durationMs: Date.now() - runStart.at, costDelta: Math.max(0, sessionCost - runStart.cost) } });
1283
+ useChatStore.getState().updateMessage(all[lastAssistantIdx]?.id, { runSummary: { iterations: payload.iterations, tools: toolCount, durationMs: Date.now() - runStart.at, costDelta: Math.max(0, sessionCost - runStart.cost) } });
1272
1284
  }
1273
1285
  }
1274
1286
  useChatStore.getState().setRunStart(null);
@@ -2060,7 +2072,7 @@ function renderGroupedList(filtered, index, dispatch, setIndex) {
2060
2072
  const groups = {};
2061
2073
  filtered.forEach((it, i) => {
2062
2074
  if (!groups[it.category]) groups[it.category] = [];
2063
- groups[it.category].push({ item: it, globalIdx: i });
2075
+ groups[it.category]?.push({ item: it, globalIdx: i });
2064
2076
  });
2065
2077
  return /* @__PURE__ */ jsx2("div", { className: "p-1", children: Object.entries(groups).map(([cat, rows]) => /* @__PURE__ */ jsxs2("div", { children: [
2066
2078
  /* @__PURE__ */ jsx2("div", { className: "px-3 pt-2 pb-1 text-[10px] uppercase tracking-wider text-muted-foreground", children: cat }),
@@ -2096,6 +2108,12 @@ function renderGroupedList(filtered, index, dispatch, setIndex) {
2096
2108
  import { FileText, Folder } from "lucide-react";
2097
2109
  import { useEffect as useEffect4, useRef as useRef3, useState as useState2 } from "react";
2098
2110
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2111
+ function expectDefined3(value) {
2112
+ if (value === null || value === void 0) {
2113
+ throw new Error("Expected value to be defined");
2114
+ }
2115
+ return value;
2116
+ }
2099
2117
  function FilePicker({ query, onPick, onClose }) {
2100
2118
  const ws = useWebSocket();
2101
2119
  const wsUrl = useConfigStore((s) => s.wsUrl);
@@ -2134,7 +2152,7 @@ function FilePicker({ query, onPick, onClose }) {
2134
2152
  } else if (e.key === "Enter" || e.key === "Tab") {
2135
2153
  if (files.length === 0) return;
2136
2154
  e.preventDefault();
2137
- onPick(files[index]);
2155
+ onPick(expectDefined3(files[index]));
2138
2156
  } else if (e.key === "Escape") {
2139
2157
  e.preventDefault();
2140
2158
  onClose();
@@ -2210,25 +2228,64 @@ var Button = React.forwardRef(
2210
2228
  Button.displayName = "Button";
2211
2229
 
2212
2230
  // src/components/ChatInput/slash-commands.ts
2231
+ function expectDefined4(value) {
2232
+ if (value === null || value === void 0) {
2233
+ throw new Error("Expected value to be defined");
2234
+ }
2235
+ return value;
2236
+ }
2213
2237
  var SLASH_COMMANDS = [
2214
- { name: "/help", category: "App", description: "Show every slash command and what it does" },
2215
- { name: "/export", category: "Session", description: "Download the current chat as markdown" },
2216
- { name: "/todos", category: "Inspect", description: "List current todos (try `/todos clear` to reset)" },
2217
- { name: "/clear", category: "Session", description: "Wipe current context (keeps session id, disk record stays)" },
2238
+ // Run
2239
+ { name: "/abort", category: "Run", aliases: ["/stop"], description: "Abort the current run" },
2240
+ // Session
2218
2241
  { name: "/new", category: "Session", description: "Start a brand-new session (fresh on disk and in memory)" },
2242
+ { name: "/clear", category: "Session", description: "Wipe current context (keeps session id, disk record stays)" },
2219
2243
  { name: "/compact", category: "Session", description: "Shrink context \u2014 elide ancient tool output" },
2220
2244
  { name: "/repair", category: "Session", description: "Repair orphan tool_use/tool_result blocks in context" },
2245
+ { name: "/save", category: "Session", description: "Force-flush the session (auto-saved already)" },
2246
+ { name: "/load", category: "Session", aliases: ["/resume"], description: "Resume a previous session from disk" },
2247
+ { name: "/prune", category: "Session", description: "Delete old sessions (default older than 30 days)" },
2248
+ { name: "/export", category: "Session", description: "Download the current chat as markdown" },
2249
+ // Inspect
2221
2250
  { name: "/debug", category: "Inspect", aliases: ["/context"], description: "Per-section context size breakdown" },
2222
2251
  { name: "/tools", category: "Inspect", description: "List every registered tool the model can call" },
2223
2252
  { name: "/memory", category: "Inspect", description: "Show all remembered notes (project + user scope)" },
2224
2253
  { name: "/skill", category: "Inspect", aliases: ["/skills"], description: "List active skills" },
2225
2254
  { name: "/diag", category: "Inspect", description: "Runtime diagnostics (provider, tools, features, mode, usage)" },
2226
2255
  { name: "/stats", category: "Inspect", description: "Session stats: tokens, cache hit ratio, cost, elapsed" },
2227
- { name: "/save", category: "Session", description: "Force-flush the session (auto-saved already)" },
2228
- { name: "/abort", category: "Run", aliases: ["/stop"], description: "Abort the current run" },
2229
- { name: "/settings", category: "App", aliases: ["/model"], description: "Open settings (provider/model/keys)" }
2256
+ { name: "/todos", category: "Inspect", description: "List current todos (try `/todos clear` to reset)" },
2257
+ { name: "/codebase-reindex", category: "Inspect", aliases: ["/reindex"], description: "Rebuild the codebase symbol index" },
2258
+ // Agent
2259
+ { name: "/spawn", category: "Agent", description: "Spawn an isolated subagent to handle a task" },
2260
+ { name: "/agents", category: "Agent", description: "Show status of spawned subagents" },
2261
+ { name: "/fleet", category: "Agent", description: "Inspect and control the agent fleet" },
2262
+ { name: "/director", category: "Agent", description: "Promote to director mode at runtime" },
2263
+ { name: "/autonomy", category: "Agent", description: "Toggle or query autonomy mode (self-driving agent)" },
2264
+ { name: "/goal", category: "Agent", description: "Set, inspect, or clear the autonomous mission" },
2265
+ { name: "/autophase", category: "Agent", description: "Autonomous phase-based workflow with subagents" },
2266
+ { name: "/fix", category: "Agent", description: "Diagnose and fix a reported error or bug" },
2267
+ { name: "/sdd", category: "Agent", description: "AI-driven Specification-Driven Development workflow" },
2268
+ { name: "/btw", category: "Agent", description: "Drop a mid-run note without interrupting the agent" },
2269
+ { name: "/collab", category: "Agent", description: "Live collaboration helpers (status / invite / history)" },
2270
+ // Config
2271
+ { name: "/settings", category: "Config", aliases: ["/model"], description: "Open settings (provider/model/keys)" },
2272
+ { name: "/setmodel", category: "Config", description: "Quick-switch the active provider/model" },
2273
+ { name: "/models", category: "Config", description: "List available providers and models" },
2274
+ { name: "/mode", category: "Config", description: "Switch the active mode (persona/skill set)" },
2275
+ { name: "/yolo", category: "Config", description: "Toggle or query YOLO (auto-approve) mode" },
2276
+ { name: "/next", category: "Config", description: "Toggle next-task prediction after each turn" },
2277
+ { name: "/enhance", category: "Config", description: "Toggle prompt refinement before sending" },
2278
+ { name: "/mcp", category: "Config", aliases: ["/mcp-servers"], description: "Manage MCP servers" },
2279
+ { name: "/plugin", category: "Config", aliases: ["/plugins"], description: "Manage plugins" },
2280
+ { name: "/statusline", category: "Config", aliases: ["/sl"], description: "Customize status bar chips" },
2281
+ { name: "/telegram-setup", category: "Config", aliases: ["/tg-setup"], description: "Configure Telegram bot token and chat" },
2282
+ { name: "/init", category: "Config", description: "Create or update .wrongstack/AGENTS.md project context" },
2283
+ { name: "/worktree", category: "Config", aliases: ["/wt"], description: "Inspect/manage git worktrees for AutoPhase" },
2284
+ // App
2285
+ { name: "/help", category: "App", description: "Show every slash command and what it does" },
2286
+ { name: "/exit", category: "App", description: "Exit the current session" }
2230
2287
  ];
2231
- var SLASH_CATEGORY_ORDER = ["Run", "Session", "Inspect", "App"];
2288
+ var SLASH_CATEGORY_ORDER = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
2232
2289
  function matchSlash(query) {
2233
2290
  const q = query.toLowerCase();
2234
2291
  if (q === "/" || q === "") return SLASH_COMMANDS;
@@ -2239,7 +2296,7 @@ function matchSlash(query) {
2239
2296
  function detectAtMention(value, cursor) {
2240
2297
  let i = cursor - 1;
2241
2298
  while (i >= 0) {
2242
- const c = value[i];
2299
+ const c = expectDefined4(value[i]);
2243
2300
  if (c === "@") {
2244
2301
  const prev = i > 0 ? value[i - 1] : "";
2245
2302
  if (i === 0 || /\s/.test(prev ?? "")) {
@@ -2255,6 +2312,12 @@ function detectAtMention(value, cursor) {
2255
2312
 
2256
2313
  // src/components/ChatInput.tsx
2257
2314
  import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
2315
+ function expectDefined5(value) {
2316
+ if (value === null || value === void 0) {
2317
+ throw new Error("Expected value to be defined");
2318
+ }
2319
+ return value;
2320
+ }
2258
2321
  function ChatInput() {
2259
2322
  const { isLoading, setLoading, addMessage, clearMessages } = useChatStore();
2260
2323
  const queue = useChatStore((s) => s.queue);
@@ -2448,7 +2511,7 @@ function ChatInput() {
2448
2511
  setLoading(false);
2449
2512
  const all = useChatStore.getState().messages;
2450
2513
  for (let i = all.length - 1; i >= 0; i--) {
2451
- const m = all[i];
2514
+ const m = expectDefined5(all[i]);
2452
2515
  if (m.role === "user" && m.content) {
2453
2516
  setInput(m.content);
2454
2517
  requestAnimationFrame(() => {
@@ -2660,7 +2723,7 @@ function ChatInput() {
2660
2723
  const next = before + insertion + after;
2661
2724
  setInput(next);
2662
2725
  const lastTokenStart = before.length + lead.length + tokens.slice(0, -1).join(" ").length + (tokens.length > 1 ? 1 : 0);
2663
- const lastBasename = files[files.length - 1].name;
2726
+ const lastBasename = files[files.length - 1]?.name;
2664
2727
  requestAnimationFrame(() => {
2665
2728
  if (ta) {
2666
2729
  const cur = before.length + insertion.length - trail.length;
@@ -2712,14 +2775,14 @@ function ChatInput() {
2712
2775
  const byCategory = {};
2713
2776
  slashSuggestions.forEach((cmd, idx) => {
2714
2777
  if (!byCategory[cmd.category]) byCategory[cmd.category] = [];
2715
- byCategory[cmd.category].push({ cmd, idx });
2778
+ byCategory[cmd.category]?.push({ cmd, idx });
2716
2779
  });
2717
2780
  const orderedCategories = SLASH_CATEGORY_ORDER.filter((c) => byCategory[c]?.length);
2718
2781
  return /* @__PURE__ */ jsxs4("div", { className: "absolute bottom-full left-0 right-0 mb-2 rounded-lg border bg-popover shadow-md p-1 text-sm max-h-72 overflow-auto", children: [
2719
2782
  /* @__PURE__ */ jsx5("div", { className: "px-3 py-1 text-[10px] uppercase tracking-wider text-muted-foreground border-b mb-1", children: "\u2191/\u2193 select \xB7 Tab complete \xB7 Enter dispatch \xB7 Esc dismiss" }),
2720
2783
  orderedCategories.map((cat) => /* @__PURE__ */ jsxs4("div", { className: "mb-1", children: [
2721
2784
  /* @__PURE__ */ jsx5("div", { className: "px-3 pt-1 pb-0.5 text-[10px] uppercase tracking-wider text-muted-foreground/70 font-semibold", children: cat }),
2722
- byCategory[cat].map(({ cmd, idx }) => /* @__PURE__ */ jsxs4(
2785
+ byCategory[cat]?.map(({ cmd, idx }) => /* @__PURE__ */ jsxs4(
2723
2786
  "button",
2724
2787
  {
2725
2788
  type: "button",
@@ -2950,6 +3013,12 @@ function ConnectionChip({ wsStatus, wsConnected }) {
2950
3013
  import { Check, ChevronDown, Gauge } from "lucide-react";
2951
3014
  import { useEffect as useEffect7, useRef as useRef5, useState as useState5 } from "react";
2952
3015
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
3016
+ function expectDefined6(value) {
3017
+ if (value === null || value === void 0) {
3018
+ throw new Error("Expected value to be defined");
3019
+ }
3020
+ return value;
3021
+ }
2953
3022
  var FALLBACK_MODES = [
2954
3023
  {
2955
3024
  id: "balanced",
@@ -2985,7 +3054,7 @@ function ContextModePicker() {
2985
3054
  };
2986
3055
  }, [open]);
2987
3056
  const items = contextModes.length > 0 ? contextModes : FALLBACK_MODES;
2988
- const active = items.find((m) => m.id === contextMode) ?? items[0];
3057
+ const active = items.find((m) => m.id === contextMode) ?? expectDefined6(items[0]);
2989
3058
  return /* @__PURE__ */ jsxs6("div", { ref: rootRef, className: "relative shrink-0", children: [
2990
3059
  /* @__PURE__ */ jsxs6(
2991
3060
  "button",
@@ -3032,7 +3101,7 @@ function ContextModePicker() {
3032
3101
  /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1", children: [
3033
3102
  /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2", children: [
3034
3103
  /* @__PURE__ */ jsx7("span", { className: "text-xs font-mono", children: m.id }),
3035
- m.thresholds && /* @__PURE__ */ jsxs6("span", { className: "text-[10px] text-muted-foreground tabular-nums", children: [
3104
+ m.thresholds?.warn !== void 0 && /* @__PURE__ */ jsxs6("span", { className: "text-[10px] text-muted-foreground tabular-nums", children: [
3036
3105
  Math.round(m.thresholds.warn * 100),
3037
3106
  "/",
3038
3107
  Math.round(m.thresholds.soft * 100),
@@ -3322,6 +3391,12 @@ import remarkGfm from "remark-gfm";
3322
3391
  // src/components/DiffView.tsx
3323
3392
  import { memo, useMemo as useMemo2 } from "react";
3324
3393
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3394
+ function expectDefined7(value) {
3395
+ if (value === null || value === void 0) {
3396
+ throw new Error("Expected value to be defined");
3397
+ }
3398
+ return value;
3399
+ }
3325
3400
  var DiffView = memo(function DiffView2({ oldText, newText, caption }) {
3326
3401
  const rows = useMemo2(() => computeDiff(oldText, newText), [oldText, newText]);
3327
3402
  if (rows === null) {
@@ -3391,8 +3466,8 @@ function computeDiff(oldText, newText) {
3391
3466
  const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
3392
3467
  for (let i2 = n - 1; i2 >= 0; i2--) {
3393
3468
  for (let j2 = m - 1; j2 >= 0; j2--) {
3394
- if (a[i2] === b[j2]) dp[i2][j2] = dp[i2 + 1][j2 + 1] + 1;
3395
- else dp[i2][j2] = Math.max(dp[i2 + 1][j2], dp[i2][j2 + 1]);
3469
+ if (a[i2] === b[j2]) expectDefined7(dp[i2])[j2] = expectDefined7(dp[i2 + 1]?.[j2 + 1]) + 1;
3470
+ else expectDefined7(dp[i2])[j2] = Math.max(expectDefined7(dp[i2 + 1]?.[j2]), expectDefined7(dp[i2]?.[j2 + 1]));
3396
3471
  }
3397
3472
  }
3398
3473
  const rows = [];
@@ -3400,19 +3475,19 @@ function computeDiff(oldText, newText) {
3400
3475
  let j = 0;
3401
3476
  while (i < n && j < m) {
3402
3477
  if (a[i] === b[j]) {
3403
- rows.push({ kind: "ctx", text: a[i] });
3478
+ rows.push({ kind: "ctx", text: expectDefined7(a[i]) });
3404
3479
  i++;
3405
3480
  j++;
3406
- } else if (dp[i + 1][j] >= dp[i][j + 1]) {
3407
- rows.push({ kind: "del", text: a[i] });
3481
+ } else if (expectDefined7(dp[i + 1]?.[j]) >= expectDefined7(dp[i]?.[j + 1])) {
3482
+ rows.push({ kind: "del", text: expectDefined7(a[i]) });
3408
3483
  i++;
3409
3484
  } else {
3410
- rows.push({ kind: "add", text: b[j] });
3485
+ rows.push({ kind: "add", text: expectDefined7(b[j]) });
3411
3486
  j++;
3412
3487
  }
3413
3488
  }
3414
- while (i < n) rows.push({ kind: "del", text: a[i++] });
3415
- while (j < m) rows.push({ kind: "add", text: b[j++] });
3489
+ while (i < n) rows.push({ kind: "del", text: expectDefined7(a[i++]) });
3490
+ while (j < m) rows.push({ kind: "add", text: expectDefined7(b[j++]) });
3416
3491
  return rows;
3417
3492
  }
3418
3493
  function diffFromToolInput(toolName, input) {
@@ -3779,10 +3854,16 @@ function CopyButton({
3779
3854
  // src/components/MessageBubble/ErrorBody.tsx
3780
3855
  import { useState as useState9 } from "react";
3781
3856
  import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
3857
+ function expectDefined8(value) {
3858
+ if (value === null || value === void 0) {
3859
+ throw new Error("Expected value to be defined");
3860
+ }
3861
+ return value;
3862
+ }
3782
3863
  function detectStackBoundary(text) {
3783
3864
  const lines = text.split("\n");
3784
3865
  for (let i = 0; i < lines.length; i++) {
3785
- const ln = lines[i];
3866
+ const ln = expectDefined8(lines[i]);
3786
3867
  if (/^\s*at\s+\S+.*\(.*:\d+:\d+\)\s*$/.test(ln)) return i;
3787
3868
  if (/^\s*at\s+\S+\.\S+\(\S+\.java:\d+\)\s*$/.test(ln)) return i;
3788
3869
  if (/^\s+File "[^"]+", line \d+/.test(ln)) return i;
@@ -3885,6 +3966,12 @@ function ToolInputView({ input }) {
3885
3966
 
3886
3967
  // src/components/MessageBubble/index.tsx
3887
3968
  import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
3969
+ function expectDefined9(value) {
3970
+ if (value === null || value === void 0) {
3971
+ throw new Error("Expected value to be defined");
3972
+ }
3973
+ return value;
3974
+ }
3888
3975
  var MessageBubble = memo3(function MessageBubble2({
3889
3976
  message,
3890
3977
  isFirst = false,
@@ -3913,7 +4000,7 @@ var MessageBubble = memo3(function MessageBubble2({
3913
4000
  if (message.role !== "assistant" || isLoading) return false;
3914
4001
  const all = useChatStore.getState().messages;
3915
4002
  for (let i = all.length - 1; i >= 0; i--) {
3916
- const m = all[i];
4003
+ const m = expectDefined9(all[i]);
3917
4004
  if (m.role === "assistant") return m.id === message.id;
3918
4005
  }
3919
4006
  return false;
@@ -3924,13 +4011,13 @@ var MessageBubble = memo3(function MessageBubble2({
3924
4011
  if (idx === -1) return;
3925
4012
  let userIdx = -1;
3926
4013
  for (let i = idx - 1; i >= 0; i--) {
3927
- if (all[i].role === "user") {
4014
+ if (all[i]?.role === "user") {
3928
4015
  userIdx = i;
3929
4016
  break;
3930
4017
  }
3931
4018
  }
3932
4019
  if (userIdx === -1) return;
3933
- const userMsg = all[userIdx];
4020
+ const userMsg = expectDefined9(all[userIdx]);
3934
4021
  truncateAfter(userMsg.id);
3935
4022
  addMessage({ role: "user", content: userMsg.content });
3936
4023
  setLoading(true);
@@ -4007,7 +4094,14 @@ var MessageBubble = memo3(function MessageBubble2({
4007
4094
  const lines = message.toolResult ? message.toolResult.split("\n").length : 0;
4008
4095
  return /* @__PURE__ */ jsxs14("div", { className: "space-y-1", children: [
4009
4096
  inputSummary && !expanded && /* @__PURE__ */ jsx15("div", { className: "text-xs text-muted-foreground font-mono truncate", children: inputSummary }),
4010
- message.toolResult === void 0 && message.progressLines && message.progressLines.length > 0 && /* @__PURE__ */ jsx15("div", { className: "mt-1 rounded-md border border-amber-500/20 bg-amber-500/5 p-1.5 text-[11px] font-mono leading-snug max-h-32 overflow-auto", children: message.progressLines.slice(-6).map((line, i) => /* @__PURE__ */ jsx15("div", { className: "truncate text-muted-foreground", children: line }, i)) }),
4097
+ message.toolResult === void 0 && message.progressLines && message.progressLines.length > 0 && /* @__PURE__ */ jsx15("div", { className: "mt-1 rounded-md border border-amber-500/20 bg-amber-500/5 p-1.5 text-[11px] font-mono leading-snug max-h-32 overflow-auto", children: (() => {
4098
+ const seen = /* @__PURE__ */ new Map();
4099
+ return message.progressLines.slice(-6).map((line) => {
4100
+ const occurrence = seen.get(line) ?? 0;
4101
+ seen.set(line, occurrence + 1);
4102
+ return /* @__PURE__ */ jsx15("div", { className: "truncate text-muted-foreground", children: line }, `${line}-${occurrence}`);
4103
+ });
4104
+ })() }),
4011
4105
  expanded && message.toolInput !== void 0 && (() => {
4012
4106
  const diffArgs = diffFromToolInput(message.toolName, message.toolInput);
4013
4107
  if (diffArgs) return /* @__PURE__ */ jsx15(DiffView, { oldText: diffArgs.oldText, newText: diffArgs.newText, caption: diffArgs.caption });
@@ -4451,7 +4545,6 @@ function ThemeToggle({ className }) {
4451
4545
  "inline-flex items-center gap-0.5 rounded-lg border border-border bg-card/70 p-0.5 shadow-sm",
4452
4546
  className
4453
4547
  ),
4454
- role: "radiogroup",
4455
4548
  "aria-label": "Theme",
4456
4549
  children: OPTIONS.map(({ value, icon: Icon2, label }) => {
4457
4550
  const active = theme === value;
@@ -4459,8 +4552,7 @@ function ThemeToggle({ className }) {
4459
4552
  "button",
4460
4553
  {
4461
4554
  type: "button",
4462
- role: "radio",
4463
- "aria-checked": active,
4555
+ "aria-pressed": active,
4464
4556
  title: `${label} theme`,
4465
4557
  "aria-label": `${label} theme`,
4466
4558
  onClick: () => setTheme(value),
@@ -4481,6 +4573,12 @@ function ThemeToggle({ className }) {
4481
4573
  import { CheckCircle2 as CheckCircle23, ChevronDown as ChevronDown5, ChevronRight as ChevronRight3, Loader2 as Loader22, Terminal as Terminal2, XCircle as XCircle3 } from "lucide-react";
4482
4574
  import { memo as memo4, useState as useState15 } from "react";
4483
4575
  import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
4576
+ function expectDefined10(value) {
4577
+ if (value === null || value === void 0) {
4578
+ throw new Error("Expected value to be defined");
4579
+ }
4580
+ return value;
4581
+ }
4484
4582
  function formatDuration(ms) {
4485
4583
  if (ms < 1e3) return `${ms}ms`;
4486
4584
  if (ms < 6e4) return `${(ms / 1e3).toFixed(ms < 1e4 ? 2 : 1)}s`;
@@ -4495,7 +4593,7 @@ var ToolGroup = memo4(function ToolGroup2({
4495
4593
  }) {
4496
4594
  const [open, setOpen] = useState15(defaultOpen);
4497
4595
  if (tools.length === 1) {
4498
- return /* @__PURE__ */ jsx20(MessageBubble, { message: tools[0], isFirst: true, isContinuation });
4596
+ return /* @__PURE__ */ jsx20(MessageBubble, { message: expectDefined10(tools[0]), isFirst: true, isContinuation });
4499
4597
  }
4500
4598
  const running = tools.filter((t) => t.toolResult === void 0).length;
4501
4599
  const errored = tools.filter((t) => t.isError).length;
@@ -4868,6 +4966,12 @@ function ThinkingBubble() {
4868
4966
 
4869
4967
  // src/components/ChatView/index.tsx
4870
4968
  import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
4969
+ function expectDefined11(value) {
4970
+ if (value === null || value === void 0) {
4971
+ throw new Error("Expected value to be defined");
4972
+ }
4973
+ return value;
4974
+ }
4871
4975
  function ChatView() {
4872
4976
  const { messages, isLoading } = useChatStore();
4873
4977
  const setPaletteOpen = useUIStore((s) => s.setPaletteOpen);
@@ -5172,7 +5276,7 @@ function ChatView() {
5172
5276
  (() => {
5173
5277
  const groups = [];
5174
5278
  for (let i = 0; i < messages.length; i++) {
5175
- const m = messages[i];
5279
+ const m = expectDefined11(messages[i]);
5176
5280
  if (m.role === "tool") {
5177
5281
  const last = groups[groups.length - 1];
5178
5282
  if (last && last.kind === "tools") {
@@ -5223,12 +5327,12 @@ function ChatView() {
5223
5327
  };
5224
5328
  const turnTs = (t) => {
5225
5329
  if (t.kind === "user") return t.message.timestamp;
5226
- const first = t.items[0];
5227
- return first.kind === "msg" ? first.message.timestamp : first.tools[0].timestamp;
5330
+ const first = expectDefined11(t.items[0]);
5331
+ return first.kind === "msg" ? first.message.timestamp : first.tools[0]?.timestamp;
5228
5332
  };
5229
5333
  const out = [];
5230
5334
  for (let idx = 0; idx < turns.length; idx++) {
5231
- const t = turns[idx];
5335
+ const t = expectDefined11(turns[idx]);
5232
5336
  const ts = turnTs(t);
5233
5337
  const day = dayKey(ts);
5234
5338
  if (day !== prevDay) {
@@ -6565,7 +6669,7 @@ function ProviderSection({
6565
6669
  const catalogByFamily = filteredCatalog.reduce(
6566
6670
  (acc, p) => {
6567
6671
  if (!acc[p.family]) acc[p.family] = [];
6568
- acc[p.family].push(p);
6672
+ acc[p.family]?.push(p);
6569
6673
  return acc;
6570
6674
  },
6571
6675
  {}
@@ -7908,6 +8012,12 @@ function TodosPanel() {
7908
8012
 
7909
8013
  // src/App.tsx
7910
8014
  import { Fragment as Fragment11, jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
8015
+ function expectDefined12(value) {
8016
+ if (value === null || value === void 0) {
8017
+ throw new Error("Expected value to be defined");
8018
+ }
8019
+ return value;
8020
+ }
7911
8021
  function AppInner() {
7912
8022
  const { theme } = useTheme();
7913
8023
  const { currentView, sidebarOpen, toggleSidebar, setSearchOpen, setSidebarOpen } = useUIStore();
@@ -8016,12 +8126,12 @@ function AppInner() {
8016
8126
  }
8017
8127
  if (e.key === "g" && !e.shiftKey) {
8018
8128
  e.preventDefault();
8019
- focusBubble(bubbles[0]);
8129
+ focusBubble(expectDefined12(bubbles[0]));
8020
8130
  return;
8021
8131
  }
8022
8132
  if (e.key === "G" || e.key === "g" && e.shiftKey) {
8023
8133
  e.preventDefault();
8024
- focusBubble(bubbles[bubbles.length - 1]);
8134
+ focusBubble(expectDefined12(bubbles[bubbles.length - 1]));
8025
8135
  return;
8026
8136
  }
8027
8137
  if (e.key === "Escape" && current) {
@@ -8070,7 +8180,13 @@ function App() {
8070
8180
 
8071
8181
  // src/main.tsx
8072
8182
  import { jsx as jsx45 } from "react/jsx-runtime";
8073
- ReactDOM.createRoot(document.getElementById("root")).render(
8183
+ function expectDefined13(value) {
8184
+ if (value === null || value === void 0) {
8185
+ throw new Error("Expected value to be defined");
8186
+ }
8187
+ return value;
8188
+ }
8189
+ ReactDOM.createRoot(expectDefined13(document.getElementById("root"))).render(
8074
8190
  /* @__PURE__ */ jsx45(React6.StrictMode, { children: /* @__PURE__ */ jsx45(App, {}) })
8075
8191
  );
8076
8192
  //# sourceMappingURL=index.js.map