@wrongstack/tui 0.272.2 → 0.273.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -786,37 +786,9 @@ function StatusBar({
786
786
  mailbox.lastSubject.length > 40 ? `${mailbox.lastSubject.slice(0, 37)}\u2026` : mailbox.lastSubject
787
787
  ] })
788
788
  ] }) : null,
789
- fleetAgents && fleetAgents.length > 0 ? fleetAgents.map((a, i) => (
790
- // biome-ignore lint/suspicious/noArrayIndexKey: agent list is stable per render
791
- /* @__PURE__ */ jsxs(Text, { children: [
792
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
793
- " ",
794
- /* @__PURE__ */ jsx(Text, { color: a.color, bold: true, children: a.label }),
795
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
796
- /* @__PURE__ */ jsx(Text, { dimColor: !a.running, ...a.running ? { color: "yellow" } : {}, children: a.running ? "\u25B6" : "\xB7" }),
797
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
798
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtElapsed(a.elapsedMs) }),
799
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
800
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
801
- a.toolCalls,
802
- "t"
803
- ] }),
804
- a.tool ? /* @__PURE__ */ jsxs(Fragment, { children: [
805
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
806
- /* @__PURE__ */ jsx(Text, { color: "cyan", children: a.tool })
807
- ] }) : null,
808
- a.extensions && a.extensions > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
809
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
810
- /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
811
- "\u26A1\xD7",
812
- a.extensions
813
- ] })
814
- ] }) : null
815
- ] }, i)
816
- )) : null
817
- ] }) : fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => (
818
- // biome-ignore lint/suspicious/noArrayIndexKey: agent list is stable per render
819
- /* @__PURE__ */ jsxs(Text, { children: [
789
+ fleetAgents && fleetAgents.length > 0 ? fleetAgents.map((a, i) => /* @__PURE__ */ jsxs(Text, { children: [
790
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
791
+ " ",
820
792
  /* @__PURE__ */ jsx(Text, { color: a.color, bold: true, children: a.label }),
821
793
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
822
794
  /* @__PURE__ */ jsx(Text, { dimColor: !a.running, ...a.running ? { color: "yellow" } : {}, children: a.running ? "\u25B6" : "\xB7" }),
@@ -838,8 +810,30 @@ function StatusBar({
838
810
  a.extensions
839
811
  ] })
840
812
  ] }) : null
841
- ] }, i)
842
- )) }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) })
813
+ ] }, i)) : null
814
+ ] }) : fleetAgents && fleetAgents.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: fleetAgents.map((a, i) => /* @__PURE__ */ jsxs(Text, { children: [
815
+ /* @__PURE__ */ jsx(Text, { color: a.color, bold: true, children: a.label }),
816
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
817
+ /* @__PURE__ */ jsx(Text, { dimColor: !a.running, ...a.running ? { color: "yellow" } : {}, children: a.running ? "\u25B6" : "\xB7" }),
818
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
819
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtElapsed(a.elapsedMs) }),
820
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
821
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
822
+ a.toolCalls,
823
+ "t"
824
+ ] }),
825
+ a.tool ? /* @__PURE__ */ jsxs(Fragment, { children: [
826
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
827
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: a.tool })
828
+ ] }) : null,
829
+ a.extensions && a.extensions > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
830
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
831
+ /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
832
+ "\u26A1\xD7",
833
+ a.extensions
834
+ ] })
835
+ ] }) : null
836
+ ] }, i)) }) : /* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { children: " " }) })
843
837
  ]
844
838
  }
845
839
  );
@@ -981,10 +975,7 @@ var WAVE_COLORS = [
981
975
  // flamingo
982
976
  ];
983
977
  function WaveText({ text, phase }) {
984
- return /* @__PURE__ */ jsx(Text, { bold: true, children: Array.from(text).map((ch, i) => (
985
- // biome-ignore lint/suspicious/noArrayIndexKey: glyph order is positional and re-rendered each tick
986
- /* @__PURE__ */ jsx(Text, { color: WAVE_COLORS[(i + phase) % WAVE_COLORS.length] ?? "#ffffff", children: ch }, i)
987
- )) });
978
+ return /* @__PURE__ */ jsx(Text, { bold: true, children: Array.from(text).map((ch, i) => /* @__PURE__ */ jsx(Text, { color: WAVE_COLORS[(i + phase) % WAVE_COLORS.length] ?? "#ffffff", children: ch }, i)) });
988
979
  }
989
980
  var FILLED = "\u2588";
990
981
  var EMPTY = "\u2591";
@@ -1183,14 +1174,11 @@ function FleetMonitor({
1183
1174
  /* @__PURE__ */ jsx(Text, { bold: true, color: VERDICT_COLOR[collabSession.overallVerdict] ?? "white", children: collabSession.overallVerdict })
1184
1175
  ] }) : null
1185
1176
  ] }),
1186
- collabSession.timeline.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 0, children: collabSession.timeline.slice(0, 6).map((ev, i) => (
1187
- // biome-ignore lint/suspicious/noArrayIndexKey: timeline is rebuilt per render
1188
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1189
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
1190
- /* @__PURE__ */ jsx(Text, { ...ev.color ? { color: ev.color } : {}, children: ev.icon }),
1191
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
1192
- ] }, i)
1193
- )) }) : null
1177
+ collabSession.timeline.length > 0 ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 0, children: collabSession.timeline.slice(0, 6).map((ev, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1178
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
1179
+ /* @__PURE__ */ jsx(Text, { ...ev.color ? { color: ev.color } : {}, children: ev.icon }),
1180
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
1181
+ ] }, i)) }) : null
1194
1182
  ] }) : null,
1195
1183
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1196
1184
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "concurrency" }),
@@ -1248,14 +1236,11 @@ function FleetMonitor({
1248
1236
  ] }) : null,
1249
1237
  timeline.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1250
1238
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "timeline" }),
1251
- timeline.map((ev, i) => (
1252
- // biome-ignore lint/suspicious/noArrayIndexKey: timeline is rebuilt per render
1253
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1254
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
1255
- /* @__PURE__ */ jsx(Text, { color: ev.color, children: ev.icon }),
1256
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
1257
- ] }, i)
1258
- ))
1239
+ timeline.map((ev, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1240
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
1241
+ /* @__PURE__ */ jsx(Text, { color: ev.color, children: ev.icon }),
1242
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
1243
+ ] }, i))
1259
1244
  ] }) : null
1260
1245
  ] });
1261
1246
  }
@@ -1570,10 +1555,7 @@ function AgentDetail({
1570
1555
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "recent" }),
1571
1556
  entry.recentTools.slice(-4).map((tool, i) => {
1572
1557
  const visual = getToolVisual(tool.name);
1573
- return (
1574
- // biome-ignore lint/suspicious/noArrayIndexKey: recent tool entries do not carry stable ids.
1575
- /* @__PURE__ */ jsx(Text, { color: tool.ok === false ? "red" : visual.color, children: `\u2039${visual.glyph} ${formatRecentToolChip(tool)}\u203A` }, `${tool.name}-${tool.at}-${i}`)
1576
- );
1558
+ return /* @__PURE__ */ jsx(Text, { color: tool.ok === false ? "red" : visual.color, children: `\u2039${visual.glyph} ${formatRecentToolChip(tool)}\u203A` }, `${tool.name}-${tool.at}-${i}`);
1577
1559
  })
1578
1560
  ] }) : null,
1579
1561
  entry.status === "running" && streamTail ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -1853,10 +1835,7 @@ function BrainDecisionPrompt({
1853
1835
  /* @__PURE__ */ jsx(Text, { color: "white", children: question }),
1854
1836
  ctx.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1855
1837
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Context:" }),
1856
- ctx.map((line, index) => (
1857
- // biome-ignore lint/suspicious/noArrayIndexKey: context lines are static for this prompt render
1858
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: line }, index)
1859
- ))
1838
+ ctx.map((line, index) => /* @__PURE__ */ jsx(Text, { dimColor: true, children: line }, index))
1860
1839
  ] }) : null,
1861
1840
  options.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
1862
1841
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Options:" }),
@@ -3507,10 +3486,7 @@ function MarkdownView({
3507
3486
  /[\u2500-\u257F]/.test(qContent) ? (
3508
3487
  // Box-drawing characters inside blockquotes also need transparent
3509
3488
  // background to avoid inheriting the message panel background.
3510
- /* @__PURE__ */ jsx(Box, { flexDirection: "row", backgroundColor: "transparent", children: [...qContent].slice(0, (contentWidth ?? termWidth) - 2).map((ch, ci) => (
3511
- /* biome-ignore lint/suspicious/noArrayIndexKey: characters are not reorderable */
3512
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: ch }, ci)
3513
- )) })
3489
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", backgroundColor: "transparent", children: [...qContent].slice(0, (contentWidth ?? termWidth) - 2).map((ch, ci) => /* @__PURE__ */ jsx(Text, { dimColor: true, children: ch }, ci)) })
3514
3490
  ) : /* @__PURE__ */ jsx(InlineLine, { tokens: parseInline(qContent), dim: true })
3515
3491
  ] }, `q${key++}`)
3516
3492
  );
@@ -3540,10 +3516,7 @@ function MarkdownView({
3540
3516
  const maxW = contentWidth ?? termWidth;
3541
3517
  const chars = [...line].slice(0, maxW);
3542
3518
  rows.push(
3543
- /* @__PURE__ */ jsx(Box, { width: maxW, backgroundColor: "transparent", flexDirection: "row", children: chars.map((ch, ci) => (
3544
- /* biome-ignore lint/suspicious/noArrayIndexKey: characters are not reorderable */
3545
- /* @__PURE__ */ jsx(Text, { children: ch }, ci)
3546
- )) }, `bx${key++}`)
3519
+ /* @__PURE__ */ jsx(Box, { width: maxW, backgroundColor: "transparent", flexDirection: "row", children: chars.map((ch, ci) => /* @__PURE__ */ jsx(Text, { children: ch }, ci)) }, `bx${key++}`)
3547
3520
  );
3548
3521
  continue;
3549
3522
  }
@@ -3633,6 +3606,19 @@ function formatMatchHit(hit) {
3633
3606
  return void 0;
3634
3607
  }
3635
3608
  var ARG_BUDGET = 60;
3609
+ function stringArrayOf(v) {
3610
+ return Array.isArray(v) ? v.filter((item) => typeof item === "string") : void 0;
3611
+ }
3612
+ function fileScopeSummary(files, fallback) {
3613
+ const list = stringArrayOf(files);
3614
+ if (list && list.length > 0) {
3615
+ const first = list[0] ?? "";
3616
+ const more = list.length > 1 ? ` (+${list.length - 1})` : "";
3617
+ return first ? `${shortenPath(first, 42)}${more}` : `${list.length} files`;
3618
+ }
3619
+ const scalar = typeof files === "string" ? files : fallback;
3620
+ return scalar ? shortenPath(scalar, 44) : "";
3621
+ }
3636
3622
  function formatToolArgs(toolName, input) {
3637
3623
  if (!input || typeof input !== "object") return "";
3638
3624
  const obj = input;
@@ -3641,13 +3627,18 @@ function formatToolArgs(toolName, input) {
3641
3627
  case "write":
3642
3628
  case "edit":
3643
3629
  case "patch":
3644
- case "document":
3645
3630
  case "list_dir":
3646
3631
  case "ls":
3647
3632
  case "tree": {
3648
3633
  const p = stringOf(obj["path"]) ?? stringOf(obj["file"]);
3649
3634
  return p ? shortenPath(p, ARG_BUDGET) : "";
3650
3635
  }
3636
+ case "document": {
3637
+ const target = stringOf(obj["target"]) ?? "all";
3638
+ const scope = fileScopeSummary(obj["files"], stringOf(obj["path"]));
3639
+ const style = stringOf(obj["style"]);
3640
+ return [target, scope, style].filter(Boolean).join(" \xB7 ");
3641
+ }
3651
3642
  case "grep":
3652
3643
  case "search":
3653
3644
  case "replace": {
@@ -3663,12 +3654,19 @@ function formatToolArgs(toolName, input) {
3663
3654
  }
3664
3655
  case "bash":
3665
3656
  case "shell":
3666
- case "exec":
3667
3657
  case "install":
3668
3658
  case "git": {
3669
3659
  const cmd = stringOf(obj["command"]) ?? stringOf(obj["args"]);
3670
3660
  return cmd ? truncMid(cmd, ARG_BUDGET) : "";
3671
3661
  }
3662
+ case "exec": {
3663
+ const command = stringOf(obj["command"]);
3664
+ const args = stringArrayOf(obj["args"]) ?? [];
3665
+ const cwd = stringOf(obj["cwd"]);
3666
+ const cmd = [command, ...args].filter(Boolean).join(" ");
3667
+ const head = cmd ? truncMid(cmd, cwd ? 44 : ARG_BUDGET) : "";
3668
+ return cwd ? `${head} in ${shortenPath(cwd, 14)}` : head;
3669
+ }
3672
3670
  case "diff": {
3673
3671
  const files = Array.isArray(obj["files"]) ? obj["files"] : void 0;
3674
3672
  if (files && files.length > 0) {
@@ -3690,6 +3688,19 @@ function formatToolArgs(toolName, input) {
3690
3688
  if (Array.isArray(list)) return `${list.length} item${list.length === 1 ? "" : "s"}`;
3691
3689
  return "";
3692
3690
  }
3691
+ case "plan": {
3692
+ const action = stringOf(obj["action"]) ?? "show";
3693
+ const target = stringOf(obj["target"]) ?? stringOf(obj["title"]) ?? stringOf(obj["template"]) ?? "";
3694
+ const scope = stringOf(obj["scope"]);
3695
+ return [action, target ? truncMid(target, 34) : "", scope].filter(Boolean).join(" \xB7 ");
3696
+ }
3697
+ case "task": {
3698
+ const action = stringOf(obj["action"]) ?? "show";
3699
+ const task = obj["task"] && typeof obj["task"] === "object" ? obj["task"] : void 0;
3700
+ const target = stringOf(obj["target"]) ?? stringOf(obj["id"]) ?? stringOf(task?.["title"]) ?? (Array.isArray(obj["tasks"]) ? `${obj["tasks"].length} tasks` : "");
3701
+ const status = stringOf(obj["status"]);
3702
+ return [action, target ? truncMid(target, 32) : "", status].filter(Boolean).join(" \xB7 ");
3703
+ }
3693
3704
  case "lint":
3694
3705
  case "format":
3695
3706
  case "typecheck":
@@ -3717,19 +3728,79 @@ function formatToolArgs(toolName, input) {
3717
3728
  if (tmpl && name) return `${tmpl} \u2192 ${truncMid(name, ARG_BUDGET - tmpl.length - 4)}`;
3718
3729
  return name ?? tmpl ?? "";
3719
3730
  }
3720
- case "remember":
3721
- case "forget":
3731
+ case "remember": {
3732
+ const scope = stringOf(obj["scope"]);
3733
+ const type = stringOf(obj["type"]);
3734
+ const text = stringOf(obj["text"]);
3735
+ return [scope, type, text ? truncMid(text, 34) : ""].filter(Boolean).join(" \xB7 ");
3736
+ }
3737
+ case "forget": {
3738
+ const query = stringOf(obj["query"]);
3739
+ const scope = stringOf(obj["scope"]);
3740
+ return [query ? `"${truncMid(query, 36)}"` : "", scope].filter(Boolean).join(" \xB7 ");
3741
+ }
3742
+ case "search_memory":
3743
+ case "find_related_memories": {
3744
+ const query = stringOf(obj["query"]) ?? stringOf(obj["text"]);
3745
+ const scope = stringOf(obj["scope"]);
3746
+ return [query ? `"${truncMid(query, 36)}"` : "", scope].filter(Boolean).join(" \xB7 ");
3747
+ }
3722
3748
  case "memory": {
3723
3749
  const key = stringOf(obj["key"]) ?? stringOf(obj["name"]);
3724
3750
  return key ? truncMid(key, ARG_BUDGET) : "";
3725
3751
  }
3726
3752
  case "mode": {
3753
+ const action = stringOf(obj["action"]);
3727
3754
  const m = stringOf(obj["mode"]) ?? stringOf(obj["name"]);
3728
- return m ? truncMid(m, ARG_BUDGET) : "";
3755
+ return [action, m].filter(Boolean).join(" \xB7 ");
3729
3756
  }
3730
3757
  case "logs": {
3731
3758
  const target = stringOf(obj["target"]) ?? stringOf(obj["service"]) ?? stringOf(obj["path"]);
3732
- return target ? truncMid(target, ARG_BUDGET) : "";
3759
+ const filter = stringOf(obj["filter"]);
3760
+ const since = stringOf(obj["since"]);
3761
+ const lines = typeof obj["lines"] === "number" ? `${obj["lines"]} lines` : "";
3762
+ return [target ? shortenPath(target, 34) : "", filter ? `/${truncMid(filter, 16)}/` : "", since, lines].filter(Boolean).join(" \xB7 ");
3763
+ }
3764
+ case "tool_help": {
3765
+ const tool = stringOf(obj["tool"]) ?? "all";
3766
+ const format = stringOf(obj["format"]);
3767
+ return [tool, format].filter(Boolean).join(" \xB7 ");
3768
+ }
3769
+ case "tool_search": {
3770
+ const query = stringOf(obj["query"]);
3771
+ const tags = stringArrayOf(obj["tags"]);
3772
+ const filters = [
3773
+ query ? `"${truncMid(query, 28)}"` : "",
3774
+ tags && tags.length > 0 ? tags.join(",") : "",
3775
+ stringOf(obj["permission"]),
3776
+ typeof obj["mutating"] === "boolean" ? obj["mutating"] ? "mutating" : "read-only" : ""
3777
+ ].filter(Boolean);
3778
+ return filters.join(" \xB7 ");
3779
+ }
3780
+ case "tool_use": {
3781
+ const tool = stringOf(obj["tool"]);
3782
+ return tool ? `call ${tool}` : "";
3783
+ }
3784
+ case "batch_tool_use": {
3785
+ const calls = Array.isArray(obj["calls"]) ? obj["calls"] : [];
3786
+ const mode = obj["parallel"] === false ? "sequential" : "parallel";
3787
+ return `${calls.length} call${calls.length === 1 ? "" : "s"} \xB7 ${mode}`;
3788
+ }
3789
+ case "codebase-index": {
3790
+ const langs = stringArrayOf(obj["langs"]);
3791
+ const force = obj["force"] === true ? "force" : "";
3792
+ return [force, langs && langs.length > 0 ? langs.join(",") : "incremental"].filter(Boolean).join(" \xB7 ");
3793
+ }
3794
+ case "codebase-search": {
3795
+ const query = stringOf(obj["query"]);
3796
+ const filters = [stringOf(obj["kind"]), stringOf(obj["lang"]), stringOf(obj["file"]) ? `in ${shortenPath(String(obj["file"]), 24)}` : ""].filter(Boolean).join(" \xB7 ");
3797
+ return [query ? `"${truncMid(query, 30)}"` : "", filters].filter(Boolean).join(" \xB7 ");
3798
+ }
3799
+ case "codebase-stats":
3800
+ return "index health";
3801
+ case "set_working_dir": {
3802
+ const p = stringOf(obj["path"]);
3803
+ return p ? shortenPath(p, ARG_BUDGET) : "current";
3733
3804
  }
3734
3805
  }
3735
3806
  for (const key of ["path", "file", "url", "name", "query", "pattern", "command"]) {
@@ -4102,6 +4173,716 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
4102
4173
  const collapsed = text.replace(/\s+/g, " ").trim();
4103
4174
  return [truncMid(collapsed, GENERIC_BUDGET)];
4104
4175
  }
4176
+ var VISUAL_MAX_LINES = 7;
4177
+ var VISUAL_TEXT_BUDGET = 92;
4178
+ function formatToolVisualOutput(toolName, output, ok, input) {
4179
+ if (!output) return void 0;
4180
+ const text = output.trim();
4181
+ if (!text) return void 0;
4182
+ if (toolName === "read") return visualRead(text);
4183
+ if (toolName === "grep" || toolName === "search") return visualSearch(toolName, text);
4184
+ if (toolName === "glob") return visualPathList(toolName, text);
4185
+ if (toolName === "tree") return visualTree(text);
4186
+ if (toolName === "bash" || toolName === "shell" || toolName === "git" || toolName === "exec" || toolName === "install") {
4187
+ return visualCommand(toolName, text, ok);
4188
+ }
4189
+ if (toolName === "test" || toolName === "lint" || toolName === "typecheck" || toolName === "format") {
4190
+ return visualVerifier(toolName, text, ok);
4191
+ }
4192
+ if (toolName === "fetch" || toolName === "webfetch" || toolName === "web_fetch") {
4193
+ return visualFetch(text);
4194
+ }
4195
+ if (toolName === "json") return visualJson(text);
4196
+ if (toolName === "outdated") return visualOutdated(text);
4197
+ if (toolName === "audit") return visualAudit(text);
4198
+ if (toolName === "scaffold") return visualScaffold(text);
4199
+ if (toolName === "todo") return visualTodo(text);
4200
+ if (toolName === "task" || toolName === "plan") return visualWorkBoard(toolName, text, ok);
4201
+ if (toolName === "remember" || toolName === "forget" || toolName === "search_memory" || toolName === "find_related_memories") {
4202
+ return visualMemory(toolName, text, ok);
4203
+ }
4204
+ if (toolName === "logs") return visualLogs(text);
4205
+ if (toolName === "document") return visualDocument(text);
4206
+ if (toolName === "tool_help" || toolName === "tool_search") return visualToolCatalog(toolName, text);
4207
+ if (toolName === "tool_use" || toolName === "batch_tool_use") return visualMetaExecution(toolName, text, ok);
4208
+ if (toolName === "codebase-index" || toolName === "codebase-search" || toolName === "codebase-stats") {
4209
+ return visualCodebase(toolName, text, ok);
4210
+ }
4211
+ if (toolName === "set_working_dir") return visualWorkingDir(text, ok);
4212
+ if (toolName === "mode") return visualMode(text, ok);
4213
+ return void 0;
4214
+ }
4215
+ function ToolOutputLines({ lines, hasFollowingBlock }) {
4216
+ return /* @__PURE__ */ jsx(Fragment, { children: lines.map((line, i) => {
4217
+ const branch = i === lines.length - 1 && !hasFollowingBlock ? " \u2514\u2500 " : " \u251C\u2500 ";
4218
+ const color = colorForVisualKind(line.kind);
4219
+ return /* @__PURE__ */ jsxs(Text, { children: [
4220
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: branch }),
4221
+ line.marker ? /* @__PURE__ */ jsx(Text, { color, bold: true, children: line.marker }) : null,
4222
+ line.path ? /* @__PURE__ */ jsxs(Fragment, { children: [
4223
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: shortenPath(line.path, 56) }),
4224
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " })
4225
+ ] }) : null,
4226
+ line.lineNo ? /* @__PURE__ */ jsxs(Fragment, { children: [
4227
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: String(line.lineNo).padStart(4, " ") }),
4228
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u2502 " })
4229
+ ] }) : null,
4230
+ /* @__PURE__ */ jsx(Text, { color, dimColor: line.kind === "meta" || line.kind === "stdout", children: truncMid(line.text, VISUAL_TEXT_BUDGET) })
4231
+ ] }, `${line.kind}-${i}`);
4232
+ }) });
4233
+ }
4234
+ function colorForVisualKind(kind) {
4235
+ switch (kind) {
4236
+ case "ok":
4237
+ return "green";
4238
+ case "warn":
4239
+ return "yellow";
4240
+ case "error":
4241
+ case "stderr":
4242
+ return "red";
4243
+ case "path":
4244
+ case "match":
4245
+ return "cyan";
4246
+ case "code":
4247
+ return "white";
4248
+ case "stdout":
4249
+ case "meta":
4250
+ return void 0;
4251
+ }
4252
+ }
4253
+ function visualRead(text) {
4254
+ const lines = bodyLines(text);
4255
+ const numbered = lines.map((line) => line.match(/^\s*(\d+)→(.*)$/)).filter((match) => Boolean(match?.[1]));
4256
+ if (numbered.length === 0) {
4257
+ const first = firstNonEmpty(lines.join("\n"));
4258
+ return first ? [{ kind: "meta", text: first }] : void 0;
4259
+ }
4260
+ const rows = numbered.slice(0, 5).map((match) => ({
4261
+ kind: "code",
4262
+ lineNo: match[1],
4263
+ text: match[2] ?? ""
4264
+ }));
4265
+ if (numbered.length > rows.length) {
4266
+ rows.push({ kind: "meta", text: `${numbered.length - rows.length} more read line(s)` });
4267
+ }
4268
+ return rows;
4269
+ }
4270
+ function visualSearch(toolName, text) {
4271
+ const json = tryParseJson(text);
4272
+ if (json && typeof json === "object") {
4273
+ const obj = json;
4274
+ const matches = Array.isArray(obj["matches"]) ? obj["matches"] : Array.isArray(obj["results"]) ? obj["results"] : [];
4275
+ return visualSearchMatches(matches, numOf(obj["count"]) ?? matches.length);
4276
+ }
4277
+ const lines = bodyLines(text);
4278
+ if (lines.length === 0 || lines[0] === "(no matches)") return void 0;
4279
+ const rows = [];
4280
+ let currentPath;
4281
+ let consumed = 0;
4282
+ for (const line of lines) {
4283
+ if (consumed >= VISUAL_MAX_LINES) break;
4284
+ const fileHeader = line.match(/^(.+?) \((\d+) match\(es\), showing \d+\)$/);
4285
+ if (fileHeader?.[1]) {
4286
+ currentPath = fileHeader[1];
4287
+ rows.push({ kind: "path", path: currentPath, text: `${fileHeader[2] ?? "?"} match(es)` });
4288
+ consumed++;
4289
+ continue;
4290
+ }
4291
+ const direct = line.match(/^(.+?):(\d+):(.*)$/);
4292
+ const grouped = line.match(/^(\d+):(.*)$/);
4293
+ if (direct?.[1] && direct[2]) {
4294
+ rows.push({ kind: "match", path: direct[1], lineNo: direct[2], text: direct[3] ?? "" });
4295
+ consumed++;
4296
+ } else if (grouped?.[1]) {
4297
+ rows.push({ kind: "match", path: currentPath, lineNo: grouped[1], text: grouped[2] ?? "" });
4298
+ consumed++;
4299
+ } else if (line.trim() && !line.startsWith(`${toolName}:`)) {
4300
+ rows.push({ kind: "meta", text: line.trim() });
4301
+ consumed++;
4302
+ }
4303
+ }
4304
+ if (lines.length > consumed) rows.push({ kind: "meta", text: `${lines.length - consumed} more result line(s)` });
4305
+ return rows.length > 0 ? rows : void 0;
4306
+ }
4307
+ function visualSearchMatches(matches, count) {
4308
+ if (count === 0) return [{ kind: "ok", marker: "ok ", text: "no matches" }];
4309
+ const rows = [];
4310
+ for (const match of matches.slice(0, VISUAL_MAX_LINES)) {
4311
+ const hit = parseMatchHit(match);
4312
+ if (hit) rows.push({ kind: "match", path: hit.path, lineNo: hit.line, text: hit.text });
4313
+ }
4314
+ if (rows.length === 0) return count > 0 ? [{ kind: "meta", text: `${count} result${count === 1 ? "" : "s"}` }] : void 0;
4315
+ if (count > rows.length) rows.push({ kind: "meta", text: `${count - rows.length} more result(s)` });
4316
+ return rows;
4317
+ }
4318
+ function parseMatchHit(hit) {
4319
+ if (typeof hit === "string") {
4320
+ const m = hit.match(/^(.+?):(\d+):(.*)$/);
4321
+ return m?.[1] && m[2] ? { path: m[1], line: m[2], text: m[3] ?? "" } : { text: hit };
4322
+ }
4323
+ if (hit && typeof hit === "object") {
4324
+ const o = hit;
4325
+ const path7 = stringOf(o["file"]) ?? stringOf(o["path"]) ?? stringOf(o["url"]);
4326
+ const line = numOf(o["line"]) ?? numOf(o["lineNumber"]);
4327
+ const title = stringOf(o["title"]);
4328
+ const snippet2 = stringOf(o["snippet"]);
4329
+ const text = stringOf(o["text"]) ?? stringOf(o["match"]) ?? stringOf(o["preview"]) ?? [title, snippet2].filter(Boolean).join(" \u2014 ");
4330
+ return { path: path7, line: line === void 0 ? void 0 : String(line), text };
4331
+ }
4332
+ return void 0;
4333
+ }
4334
+ function visualPathList(toolName, text) {
4335
+ const json = tryParseJson(text);
4336
+ const files = json && typeof json === "object" && Array.isArray(json["files"]) ? json["files"].filter((v) => typeof v === "string") : bodyLines(text).filter((line) => line.trim() && !line.startsWith(`${toolName}:`));
4337
+ if (files.length === 0) return void 0;
4338
+ const rows = files.slice(0, VISUAL_MAX_LINES).map((file) => ({
4339
+ kind: "path",
4340
+ path: file,
4341
+ text: ""
4342
+ }));
4343
+ if (files.length > rows.length) rows.push({ kind: "meta", text: `${files.length - rows.length} more path(s)` });
4344
+ return rows;
4345
+ }
4346
+ function visualTree(text) {
4347
+ const lines = bodyLines(text).filter((line) => line.trim());
4348
+ if (lines.length === 0) return void 0;
4349
+ const rows = lines.slice(0, VISUAL_MAX_LINES).map((line) => ({
4350
+ kind: line.includes("\u2500\u2500") || line.includes("|--") ? "path" : "meta",
4351
+ text: line
4352
+ }));
4353
+ if (lines.length > rows.length) rows.push({ kind: "meta", text: `${lines.length - rows.length} more tree line(s)` });
4354
+ return rows;
4355
+ }
4356
+ function visualCommand(toolName, text, ok) {
4357
+ const json = tryParseJson(text);
4358
+ if (json && typeof json === "object") {
4359
+ const obj = json;
4360
+ return commandRows({
4361
+ exit: numOf(obj["exit_code"]) ?? numOf(obj["exitCode"]),
4362
+ timedOut: obj["timed_out"] === true || obj["timedOut"] === true,
4363
+ stdout: stringOf(obj["stdout"]) ?? stringOf(obj["output"]),
4364
+ stderr: stringOf(obj["stderr"]) ?? stringOf(obj["error"]),
4365
+ ok
4366
+ });
4367
+ }
4368
+ const header = parseHeaderLine(text);
4369
+ const sections = parseNamedSections(text);
4370
+ return commandRows({
4371
+ exit: numberFromParsedField(header.fields, "exit_code") ?? numberFromParsedField(header.fields, "exitCode"),
4372
+ timedOut: header.fields["timed_out"] === "true" || header.fields["timedOut"] === "true",
4373
+ stdout: sections.get("stdout") ?? sections.get("output"),
4374
+ stderr: sections.get("stderr") ?? sections.get("error"),
4375
+ ok,
4376
+ label: toolName
4377
+ });
4378
+ }
4379
+ function commandRows(opts) {
4380
+ const rows = [];
4381
+ const statusKind = opts.timedOut ? "warn" : opts.ok && (opts.exit ?? 0) === 0 ? "ok" : "error";
4382
+ const status = opts.timedOut ? "timed out" : opts.exit !== void 0 ? `exit ${opts.exit}` : opts.ok ? "completed" : "failed";
4383
+ rows.push({ kind: statusKind, marker: statusKind === "ok" ? "ok " : statusKind === "warn" ? "! " : "x ", text: opts.label ? `${opts.label} ${status}` : status });
4384
+ appendOutputPreview(rows, opts.stdout, "stdout");
4385
+ appendOutputPreview(rows, opts.stderr, "stderr");
4386
+ return rows.length > 0 ? rows.slice(0, VISUAL_MAX_LINES) : void 0;
4387
+ }
4388
+ function visualVerifier(toolName, text, ok) {
4389
+ const json = tryParseJson(text);
4390
+ if (json && typeof json === "object") {
4391
+ const obj = json;
4392
+ const errors = numOf(obj["errors"]) ?? numOf(obj["failed"]) ?? 0;
4393
+ const warnings = numOf(obj["warnings"]) ?? 0;
4394
+ const changed2 = numOf(obj["files_changed"]) ?? 0;
4395
+ const statusKind2 = !ok || errors > 0 ? "error" : changed2 > 0 ? "warn" : "ok";
4396
+ const parts = [
4397
+ toolName,
4398
+ errors > 0 ? `${errors} error${errors === 1 ? "" : "s"}` : void 0,
4399
+ warnings > 0 ? `${warnings} warning${warnings === 1 ? "" : "s"}` : void 0,
4400
+ changed2 > 0 ? `${changed2} changed` : void 0,
4401
+ toolName === "test" ? `${numOf(obj["passed"]) ?? 0}/${numOf(obj["tests_run"]) ?? 0} passed` : void 0
4402
+ ].filter(Boolean);
4403
+ return [{ kind: statusKind2, marker: statusKind2 === "ok" ? "ok " : statusKind2 === "warn" ? "! " : "x ", text: parts.join(" \xB7 ") || toolName }];
4404
+ }
4405
+ const header = parseHeaderLine(text);
4406
+ const sections = parseNamedSections(text);
4407
+ const report = sections.get("report") ?? "";
4408
+ const errorContext = sections.get("error_context");
4409
+ const fields = { ...header.fields, ...parseKeyValueLines(report) };
4410
+ const status = fields["status"];
4411
+ const errorCount = numberFromParsedField(fields, "errors") ?? numberFromParsedField(fields, "failed") ?? 0;
4412
+ const warningCount = numberFromParsedField(fields, "warnings") ?? 0;
4413
+ const changed = numberFromParsedField(fields, "files_changed") ?? 0;
4414
+ const statusKind = !ok || errorContext || errorCount > 0 ? "error" : status === "changed" || changed > 0 ? "warn" : "ok";
4415
+ const rows = [{
4416
+ kind: statusKind,
4417
+ marker: statusKind === "ok" ? "ok " : statusKind === "warn" ? "! " : "x ",
4418
+ text: [
4419
+ toolName,
4420
+ status ? `status=${status}` : void 0,
4421
+ errorCount > 0 ? `${errorCount} error${errorCount === 1 ? "" : "s"}` : void 0,
4422
+ warningCount > 0 ? `${warningCount} warning${warningCount === 1 ? "" : "s"}` : void 0,
4423
+ changed > 0 ? `${changed} changed` : void 0
4424
+ ].filter(Boolean).join(" \xB7 ")
4425
+ }];
4426
+ appendOutputPreview(rows, errorContext, "stderr");
4427
+ return rows.slice(0, VISUAL_MAX_LINES);
4428
+ }
4429
+ function visualFetch(text) {
4430
+ const json = tryParseJson(text);
4431
+ if (json && typeof json === "object") {
4432
+ const obj = json;
4433
+ const status = numOf(obj["status"]);
4434
+ const ct = stringOf(obj["content_type"]);
4435
+ const content = stringOf(obj["content"]);
4436
+ return fetchRows(status, ct, content);
4437
+ }
4438
+ const header = parseHeaderLine(text);
4439
+ return fetchRows(
4440
+ numberFromParsedField(header.fields, "status"),
4441
+ header.fields["content_type"],
4442
+ bodyLines(text).join("\n")
4443
+ );
4444
+ }
4445
+ function fetchRows(status, contentType, content) {
4446
+ const kind = status === void 0 ? "meta" : status >= 200 && status < 300 ? "ok" : status >= 300 && status < 400 ? "warn" : "error";
4447
+ const rows = [{
4448
+ kind,
4449
+ marker: kind === "ok" ? "ok " : kind === "warn" ? "! " : kind === "error" ? "x " : void 0,
4450
+ text: [status !== void 0 ? `HTTP ${status}` : "HTTP", contentType?.split(";")[0]].filter(Boolean).join(" \xB7 ")
4451
+ }];
4452
+ const preview = firstNonEmpty(content ?? "");
4453
+ if (preview) rows.push({ kind: "stdout", text: preview });
4454
+ return rows;
4455
+ }
4456
+ function visualJson(text) {
4457
+ const json = tryParseJson(text);
4458
+ if (!json || typeof json !== "object" || Array.isArray(json)) return void 0;
4459
+ const obj = json;
4460
+ const err = stringOf(obj["error"]);
4461
+ if (err) return [{ kind: "error", marker: "x ", text: err }];
4462
+ const type = stringOf(obj["type"]);
4463
+ const keys = Array.isArray(obj["keys"]) ? obj["keys"].length : void 0;
4464
+ return [{ kind: "ok", marker: "ok ", text: [type ?? "json", keys !== void 0 ? `${keys} key${keys === 1 ? "" : "s"}` : void 0].filter(Boolean).join(" \xB7 ") }];
4465
+ }
4466
+ function visualOutdated(text) {
4467
+ const lines = bodyLines(text).filter((line) => line.trim() && !line.startsWith("outdated"));
4468
+ if (lines.length === 0) return void 0;
4469
+ return lines.slice(0, VISUAL_MAX_LINES).map((line) => ({ kind: "warn", marker: "! ", text: line }));
4470
+ }
4471
+ function visualAudit(text) {
4472
+ const lines = bodyLines(text).filter((line) => line.trim() && !line.startsWith("audit"));
4473
+ if (lines.length === 0) return void 0;
4474
+ return lines.slice(0, VISUAL_MAX_LINES).map((line) => ({
4475
+ kind: /^critical|^high/i.test(line) ? "error" : /^moderate|^medium/i.test(line) ? "warn" : "meta",
4476
+ marker: /^critical|^high/i.test(line) ? "x " : /^moderate|^medium/i.test(line) ? "! " : void 0,
4477
+ text: line
4478
+ }));
4479
+ }
4480
+ function visualScaffold(text) {
4481
+ const json = tryParseJson(text);
4482
+ if (!json || typeof json !== "object") return void 0;
4483
+ const obj = json;
4484
+ const created = Array.isArray(obj["created"]) ? obj["created"] : [];
4485
+ const skipped = Array.isArray(obj["skipped"]) ? obj["skipped"] : [];
4486
+ const rows = [];
4487
+ for (const file of created.slice(0, 5)) {
4488
+ if (typeof file === "string") rows.push({ kind: "ok", marker: "+ ", path: file, text: "" });
4489
+ }
4490
+ if (skipped.length > 0) rows.push({ kind: "warn", marker: "! ", text: `${skipped.length} skipped` });
4491
+ return rows.length > 0 ? rows : void 0;
4492
+ }
4493
+ function visualTodo(text) {
4494
+ const json = tryParseJson(text);
4495
+ const fields = json && typeof json === "object" && !Array.isArray(json) ? recordToStringFields(json) : parseHeaderLine(text).fields;
4496
+ const count = numberFromParsedField(fields, "count") ?? 0;
4497
+ const inProgress = numberFromParsedField(fields, "in_progress") ?? 0;
4498
+ return [{
4499
+ kind: count > 0 ? "ok" : "meta",
4500
+ marker: count > 0 ? "ok " : void 0,
4501
+ text: `${count} todo${count === 1 ? "" : "s"}${inProgress > 0 ? ` \xB7 ${inProgress} in progress` : ""}`
4502
+ }];
4503
+ }
4504
+ function visualWorkBoard(toolName, text, ok) {
4505
+ const json = tryParseJson(text);
4506
+ if (json && typeof json === "object" && !Array.isArray(json)) {
4507
+ const obj = json;
4508
+ const rows2 = boardSummaryRows(toolName, recordToStringFields(obj), ok);
4509
+ appendBoardPreview(rows2, stringOf(obj["message"]));
4510
+ appendBoardPreview(rows2, stringOf(obj["plan"]));
4511
+ const todos = Array.isArray(obj["todos"]) ? obj["todos"] : [];
4512
+ for (const todo of todos.slice(0, 3)) {
4513
+ if (todo && typeof todo === "object") {
4514
+ const o = todo;
4515
+ rows2.push({ kind: "path", marker: "+ ", text: stringOf(o["content"]) ?? stringOf(o["id"]) ?? "todo" });
4516
+ }
4517
+ }
4518
+ return rows2.slice(0, VISUAL_MAX_LINES);
4519
+ }
4520
+ const header = parseHeaderLine(text);
4521
+ const sections = parseNamedSections(text);
4522
+ const rows = boardSummaryRows(toolName, header.fields, ok);
4523
+ appendBoardPreview(rows, sections.get("message") ?? sections.get("plan") ?? bodyLines(text).join("\n"));
4524
+ return rows.slice(0, VISUAL_MAX_LINES);
4525
+ }
4526
+ function boardSummaryRows(toolName, fields, ok) {
4527
+ const success = fields["ok"] !== "false" && ok;
4528
+ const count = numberFromParsedField(fields, "count");
4529
+ const open = numberFromParsedField(fields, "open");
4530
+ const completed = numberFromParsedField(fields, "completed");
4531
+ const inProgress = numberFromParsedField(fields, "inProgress") ?? numberFromParsedField(fields, "in_progress");
4532
+ const parts = [
4533
+ toolName,
4534
+ count !== void 0 ? `${count} item${count === 1 ? "" : "s"}` : void 0,
4535
+ open !== void 0 ? `${open} open` : void 0,
4536
+ completed !== void 0 ? `${completed} done` : void 0,
4537
+ inProgress !== void 0 && inProgress > 0 ? `${inProgress} in progress` : void 0
4538
+ ].filter(Boolean);
4539
+ return [{
4540
+ kind: success ? "ok" : "error",
4541
+ marker: success ? "ok " : "x ",
4542
+ text: parts.join(" \xB7 ") || toolName
4543
+ }];
4544
+ }
4545
+ function appendBoardPreview(rows, text) {
4546
+ if (!text) return;
4547
+ const lines = text.split(/\r?\n/).map((line) => line.replace(/^[\s│├└─>*-]+/, "").trim()).filter((line) => line && !line.startsWith("{") && !line.startsWith("["));
4548
+ for (const line of lines.slice(0, 4)) {
4549
+ rows.push({ kind: line.includes("failed") || line.includes("not configured") ? "error" : "meta", text: line });
4550
+ }
4551
+ }
4552
+ function visualMemory(toolName, text, ok) {
4553
+ const json = tryParseJson(text);
4554
+ if (json && typeof json === "object" && !Array.isArray(json)) {
4555
+ const obj = json;
4556
+ if (toolName === "search_memory" || toolName === "find_related_memories") {
4557
+ return memoryResultRows(Array.isArray(obj["results"]) ? obj["results"] : []);
4558
+ }
4559
+ const fields = recordToStringFields(obj);
4560
+ return [memoryStatusRow(toolName, fields, ok)];
4561
+ }
4562
+ const header = parseHeaderLine(text);
4563
+ if (toolName === "search_memory" || toolName === "find_related_memories") {
4564
+ return memoryResultRows(bodyLines(text));
4565
+ }
4566
+ return [memoryStatusRow(toolName, header.fields, ok)];
4567
+ }
4568
+ function memoryStatusRow(toolName, fields, ok) {
4569
+ const scope = fields["scope"];
4570
+ const removed = numberFromParsedField(fields, "removed");
4571
+ const text = toolName === "forget" ? `${removed ?? 0} removed${scope ? ` \xB7 ${scope}` : ""}` : `${toolName}${scope ? ` \xB7 ${scope}` : ""}`;
4572
+ return { kind: ok ? "ok" : "error", marker: ok ? "ok " : "x ", text };
4573
+ }
4574
+ function memoryResultRows(results) {
4575
+ if (results.length === 0) return [{ kind: "meta", text: "no memories" }];
4576
+ const rows = [];
4577
+ for (const result of results.slice(0, VISUAL_MAX_LINES)) {
4578
+ if (typeof result === "string") {
4579
+ const parsed = tryParseJson(result);
4580
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
4581
+ const o = parsed;
4582
+ rows.push({ kind: "meta", marker: tagMarker(stringOf(o["priority"])), text: memoryText(o) });
4583
+ } else {
4584
+ rows.push({ kind: "meta", text: result });
4585
+ }
4586
+ } else if (result && typeof result === "object") {
4587
+ const o = result;
4588
+ rows.push({ kind: "meta", marker: tagMarker(stringOf(o["priority"])), text: memoryText(o) });
4589
+ }
4590
+ }
4591
+ if (results.length > rows.length) rows.push({ kind: "meta", text: `${results.length - rows.length} more memory result(s)` });
4592
+ return rows;
4593
+ }
4594
+ function memoryText(o) {
4595
+ const type = stringOf(o["type"]);
4596
+ const scope = stringOf(o["scope"]);
4597
+ const text = stringOf(o["text"]) ?? "";
4598
+ return [type ? `[${type}]` : void 0, scope, text].filter(Boolean).join(" ");
4599
+ }
4600
+ function tagMarker(priority) {
4601
+ if (priority === "critical" || priority === "high") return "! ";
4602
+ return void 0;
4603
+ }
4604
+ function visualLogs(text) {
4605
+ const json = tryParseJson(text);
4606
+ if (json && typeof json === "object" && !Array.isArray(json)) {
4607
+ const obj = json;
4608
+ const rows2 = [{
4609
+ kind: "meta",
4610
+ text: `${stringOf(obj["source"]) ?? "logs"} \xB7 ${numOf(obj["total"]) ?? 0} entries${obj["truncated"] === true ? " \xB7 truncated" : ""}`
4611
+ }];
4612
+ const entries = Array.isArray(obj["entries"]) ? obj["entries"] : [];
4613
+ appendLogEntries(rows2, entries);
4614
+ return rows2;
4615
+ }
4616
+ const header = parseHeaderLine(text);
4617
+ const rows = [{ kind: "meta", text: `${header.label}${header.fields["total"] ? ` \xB7 ${header.fields["total"]} entries` : ""}` }];
4618
+ appendLogEntries(rows, bodyLines(text));
4619
+ return rows.slice(0, VISUAL_MAX_LINES);
4620
+ }
4621
+ function appendLogEntries(rows, entries) {
4622
+ for (const entry of entries.slice(0, 5)) {
4623
+ if (typeof entry === "string") {
4624
+ rows.push(logLine(entry));
4625
+ } else if (entry && typeof entry === "object") {
4626
+ const o = entry;
4627
+ rows.push(logLine([stringOf(o["timestamp"]), stringOf(o["level"]), stringOf(o["source"]), stringOf(o["message"])].filter(Boolean).join(" ")));
4628
+ }
4629
+ }
4630
+ if (entries.length > 5) rows.push({ kind: "meta", text: `${entries.length - 5} more log line(s)` });
4631
+ }
4632
+ function logLine(line) {
4633
+ const kind = /\b(error|fatal|panic)\b/i.test(line) ? "error" : /\b(warn|warning)\b/i.test(line) ? "warn" : "stdout";
4634
+ return { kind, marker: kind === "error" ? "x " : kind === "warn" ? "! " : void 0, text: line };
4635
+ }
4636
+ function visualDocument(text) {
4637
+ const json = tryParseJson(text);
4638
+ const rows = [];
4639
+ if (json && typeof json === "object" && !Array.isArray(json)) {
4640
+ const obj = json;
4641
+ rows.push({
4642
+ kind: "ok",
4643
+ marker: "ok ",
4644
+ text: `${numOf(obj["items_documented"]) ?? 0} documented \xB7 ${numOf(obj["files_processed"]) ?? 0} files \xB7 ${stringOf(obj["style"]) ?? "style"}`
4645
+ });
4646
+ appendDocumentResults(rows, Array.isArray(obj["results"]) ? obj["results"] : []);
4647
+ return rows.slice(0, VISUAL_MAX_LINES);
4648
+ }
4649
+ const header = parseHeaderLine(text);
4650
+ rows.push({
4651
+ kind: "ok",
4652
+ marker: "ok ",
4653
+ text: `${header.fields["items_documented"] ?? "0"} documented \xB7 ${header.fields["files_processed"] ?? "0"} files`
4654
+ });
4655
+ appendDocumentResults(rows, bodyLines(text));
4656
+ return rows.slice(0, VISUAL_MAX_LINES);
4657
+ }
4658
+ function appendDocumentResults(rows, results) {
4659
+ for (const result of results.slice(0, 5)) {
4660
+ const obj = typeof result === "string" ? tryParseJson(result) : result;
4661
+ if (obj && typeof obj === "object" && !Array.isArray(obj)) {
4662
+ const o = obj;
4663
+ const status = stringOf(o["status"]) ?? "item";
4664
+ rows.push({
4665
+ kind: status === "error" ? "error" : status === "skipped" ? "warn" : "path",
4666
+ marker: status === "error" ? "x " : status === "skipped" ? "! " : "+ ",
4667
+ path: stringOf(o["path"]),
4668
+ text: stringOf(o["name"]) ?? stringOf(o["signature"]) ?? status
4669
+ });
4670
+ } else if (typeof result === "string" && result.trim()) {
4671
+ rows.push({ kind: "meta", text: result.trim() });
4672
+ }
4673
+ }
4674
+ }
4675
+ function visualToolCatalog(toolName, text) {
4676
+ const json = tryParseJson(text);
4677
+ const rows = [];
4678
+ if (json && typeof json === "object" && !Array.isArray(json)) {
4679
+ const obj = json;
4680
+ const total = numOf(obj["total"]) ?? 0;
4681
+ rows.push({ kind: total > 0 ? "ok" : "warn", marker: total > 0 ? "ok " : "! ", text: `${toolName} \xB7 ${total} result${total === 1 ? "" : "s"}` });
4682
+ const tools = Array.isArray(obj["tools"]) ? obj["tools"] : [];
4683
+ for (const tool of tools.slice(0, 5)) {
4684
+ if (tool && typeof tool === "object") {
4685
+ const o = tool;
4686
+ rows.push({
4687
+ kind: o["mutating"] === true ? "warn" : "path",
4688
+ marker: o["mutating"] === true ? "! " : void 0,
4689
+ text: [stringOf(o["name"]), stringOf(o["permission"]), stringOf(o["description"])].filter(Boolean).join(" \xB7 ")
4690
+ });
4691
+ }
4692
+ }
4693
+ return rows.slice(0, VISUAL_MAX_LINES);
4694
+ }
4695
+ const header = parseHeaderLine(text);
4696
+ return [{ kind: "meta", text: header.label || toolName }];
4697
+ }
4698
+ function visualMetaExecution(toolName, text, ok) {
4699
+ const json = tryParseJson(text);
4700
+ if (!json || typeof json !== "object" || Array.isArray(json)) {
4701
+ const header = parseHeaderLine(text);
4702
+ return [{ kind: ok ? "ok" : "error", marker: ok ? "ok " : "x ", text: header.label || toolName }];
4703
+ }
4704
+ const obj = json;
4705
+ if (toolName === "tool_use") {
4706
+ const success = obj["success"] !== false && ok;
4707
+ const target = stringOf(obj["tool"]) ?? "tool";
4708
+ return [{
4709
+ kind: success ? "ok" : "error",
4710
+ marker: success ? "ok " : "x ",
4711
+ text: `${target} \xB7 ${numOf(obj["executionMs"]) ?? 0}ms${success ? "" : ` \xB7 ${stringOf(obj["error"]) ?? "failed"}`}`
4712
+ }];
4713
+ }
4714
+ const total = numOf(obj["total"]) ?? 0;
4715
+ const succeeded = numOf(obj["succeeded"]) ?? 0;
4716
+ const failed = numOf(obj["failed"]) ?? 0;
4717
+ const rows = [{
4718
+ kind: failed > 0 || !ok ? "error" : "ok",
4719
+ marker: failed > 0 || !ok ? "x " : "ok ",
4720
+ text: `${succeeded}/${total} succeeded${failed > 0 ? ` \xB7 ${failed} failed` : ""}`
4721
+ }];
4722
+ const results = Array.isArray(obj["results"]) ? obj["results"] : [];
4723
+ for (const result of results.slice(0, 5)) {
4724
+ if (result && typeof result === "object") {
4725
+ const r = result;
4726
+ const success = r["success"] !== false;
4727
+ rows.push({
4728
+ kind: success ? "ok" : "error",
4729
+ marker: success ? "ok " : "x ",
4730
+ text: `${stringOf(r["tool"]) ?? "tool"} \xB7 ${numOf(r["executionMs"]) ?? 0}ms${success ? "" : ` \xB7 ${stringOf(r["error"]) ?? "failed"}`}`
4731
+ });
4732
+ }
4733
+ }
4734
+ return rows.slice(0, VISUAL_MAX_LINES);
4735
+ }
4736
+ function visualCodebase(toolName, text, ok) {
4737
+ const json = tryParseJson(text);
4738
+ if (!json || typeof json !== "object" || Array.isArray(json)) {
4739
+ const header = parseHeaderLine(text);
4740
+ return [{ kind: ok ? "ok" : "warn", marker: ok ? "ok " : "! ", text: header.label || toolName }];
4741
+ }
4742
+ const obj = json;
4743
+ if (toolName === "codebase-search") {
4744
+ const status2 = stringOf(obj["indexStatus"]);
4745
+ const total = numOf(obj["total"]) ?? 0;
4746
+ const rows = [{
4747
+ kind: status2 ? "warn" : "ok",
4748
+ marker: status2 ? "! " : "ok ",
4749
+ text: status2 ?? `${total} symbol result${total === 1 ? "" : "s"} for "${stringOf(obj["query"]) ?? ""}"`
4750
+ }];
4751
+ const results = Array.isArray(obj["results"]) ? obj["results"] : [];
4752
+ for (const result of results.slice(0, 5)) {
4753
+ if (result && typeof result === "object") {
4754
+ const r = result;
4755
+ rows.push({
4756
+ kind: "match",
4757
+ path: stringOf(r["file"]),
4758
+ lineNo: numOf(r["line"])?.toString(),
4759
+ text: [stringOf(r["kind"]), stringOf(r["name"]), stringOf(r["signature"])].filter(Boolean).join(" \xB7 ")
4760
+ });
4761
+ }
4762
+ }
4763
+ return rows.slice(0, VISUAL_MAX_LINES);
4764
+ }
4765
+ if (toolName === "codebase-index") {
4766
+ const errors = Array.isArray(obj["errors"]) ? obj["errors"] : [];
4767
+ return [{
4768
+ kind: errors.length > 0 || !ok ? "error" : stringOf(obj["note"]) ? "warn" : "ok",
4769
+ marker: errors.length > 0 || !ok ? "x " : stringOf(obj["note"]) ? "! " : "ok ",
4770
+ text: stringOf(obj["note"]) ?? `${numOf(obj["filesIndexed"]) ?? 0} files \xB7 ${numOf(obj["symbolsIndexed"]) ?? 0} symbols \xB7 ${fmtDuration(numOf(obj["durationMs"]) ?? 0)}`
4771
+ }];
4772
+ }
4773
+ const status = stringOf(obj["indexStatus"]);
4774
+ return [{
4775
+ kind: status ? "warn" : "ok",
4776
+ marker: status ? "! " : "ok ",
4777
+ text: status ?? `${numOf(obj["totalSymbols"]) ?? 0} symbols \xB7 ${numOf(obj["totalFiles"]) ?? 0} files \xB7 ${fmtBytes(numOf(obj["sizeBytes"]) ?? 0)}`
4778
+ }];
4779
+ }
4780
+ function visualWorkingDir(text, ok) {
4781
+ const json = tryParseJson(text);
4782
+ const obj = json && typeof json === "object" && !Array.isArray(json) ? json : void 0;
4783
+ if (!obj) return void 0;
4784
+ const err = stringOf(obj["error"]);
4785
+ return [{
4786
+ kind: err || !ok ? "error" : "ok",
4787
+ marker: err || !ok ? "x " : "ok ",
4788
+ path: stringOf(obj["current"]),
4789
+ text: err ?? stringOf(obj["message"]) ?? "working directory"
4790
+ }];
4791
+ }
4792
+ function visualMode(text, ok) {
4793
+ const json = tryParseJson(text);
4794
+ const obj = json && typeof json === "object" && !Array.isArray(json) ? json : void 0;
4795
+ if (!obj) return void 0;
4796
+ if (Array.isArray(obj["modes"])) {
4797
+ const modes = obj["modes"];
4798
+ const rows = [{ kind: "ok", marker: "ok ", text: `${modes.length} mode${modes.length === 1 ? "" : "s"}` }];
4799
+ for (const mode of modes.slice(0, 5)) {
4800
+ if (mode && typeof mode === "object") {
4801
+ const m = mode;
4802
+ rows.push({ kind: "path", text: [stringOf(m["id"]), stringOf(m["name"]), stringOf(m["description"])].filter(Boolean).join(" \xB7 ") });
4803
+ }
4804
+ }
4805
+ return rows;
4806
+ }
4807
+ const success = obj["success"] !== false && ok;
4808
+ return [{
4809
+ kind: success ? "ok" : "error",
4810
+ marker: success ? "ok " : "x ",
4811
+ text: [stringOf(obj["action"]) ?? "mode", stringOf(obj["currentMode"]), stringOf(obj["message"])].filter(Boolean).join(" \xB7 ")
4812
+ }];
4813
+ }
4814
+ function recordToStringFields(obj) {
4815
+ const out = {};
4816
+ for (const [key, value] of Object.entries(obj)) {
4817
+ if (value === void 0 || value === null) continue;
4818
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
4819
+ out[key] = String(value);
4820
+ }
4821
+ }
4822
+ return out;
4823
+ }
4824
+ function appendOutputPreview(rows, output, kind) {
4825
+ if (!output) return;
4826
+ const lines = output.split(/\r?\n/).filter((line) => line.trim());
4827
+ for (const line of lines.slice(0, 3)) rows.push({ kind, text: line.trim() });
4828
+ if (lines.length > 3) rows.push({ kind: "meta", text: `${lines.length - 3} more ${kind} line(s)` });
4829
+ }
4830
+ function bodyLines(text) {
4831
+ const lines = text.replace(/\r/g, "").split("\n");
4832
+ if (lines.length > 0 && /^[^\n]+(?:\s+\([^)]*\))?$/.test(lines[0] ?? "")) {
4833
+ return lines.slice(1);
4834
+ }
4835
+ return lines;
4836
+ }
4837
+ function parseHeaderLine(text) {
4838
+ const first = text.split(/\r?\n/, 1)[0] ?? "";
4839
+ const match = first.match(/^(.+?)(?: \((.*)\))?$/);
4840
+ const label = match?.[1] ?? first;
4841
+ const rawFields = match?.[2] ?? "";
4842
+ return { label, fields: parseInlineFields(rawFields) };
4843
+ }
4844
+ function parseInlineFields(raw) {
4845
+ const fields = {};
4846
+ for (const match of raw.matchAll(/([A-Za-z_][A-Za-z0-9_]*)=([^ ]+)/g)) {
4847
+ if (match[1] && match[2]) fields[match[1]] = match[2];
4848
+ }
4849
+ return fields;
4850
+ }
4851
+ function parseNamedSections(text) {
4852
+ const sections = /* @__PURE__ */ new Map();
4853
+ const lines = text.replace(/\r/g, "").split("\n");
4854
+ let current;
4855
+ const buf = [];
4856
+ const flush = () => {
4857
+ if (current) sections.set(current, buf.join("\n").trim());
4858
+ buf.length = 0;
4859
+ };
4860
+ for (const line of lines.slice(1)) {
4861
+ const m = line.match(/^([a-z_]+):$/);
4862
+ if (m?.[1]) {
4863
+ flush();
4864
+ current = m[1];
4865
+ continue;
4866
+ }
4867
+ if (current) buf.push(line);
4868
+ }
4869
+ flush();
4870
+ return sections;
4871
+ }
4872
+ function parseKeyValueLines(text) {
4873
+ const out = {};
4874
+ for (const line of text.split(/\r?\n/)) {
4875
+ const m = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
4876
+ if (m?.[1]) out[m[1]] = m[2] ?? "";
4877
+ }
4878
+ return out;
4879
+ }
4880
+ function numberFromParsedField(fields, key) {
4881
+ const raw = fields[key];
4882
+ if (raw === void 0) return void 0;
4883
+ const n = Number.parseInt(raw, 10);
4884
+ return Number.isFinite(n) ? n : void 0;
4885
+ }
4105
4886
  var MAX_STREAM_DISPLAY_CHARS = 480;
4106
4887
  var MAX_STREAM_LINES = 8;
4107
4888
  function streamBoxRows(text, maxLines, contentWidth) {
@@ -4146,10 +4927,7 @@ var ToolStreamBox = React5.memo(function ToolStreamBox2({
4146
4927
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
4147
4928
  hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${MAX_STREAM_LINES})` }) : null
4148
4929
  ] }),
4149
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: rows.map((r, i) => (
4150
- // biome-ignore lint/suspicious/noArrayIndexKey: fixed-height block, index is the row
4151
- /* @__PURE__ */ jsx(Text, { dimColor: true, italic: Boolean(r.italic), children: r.text || " " }, i)
4152
- )) })
4930
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: 2, children: rows.map((r, i) => /* @__PURE__ */ jsx(Text, { dimColor: true, italic: Boolean(r.italic), children: r.text || " " }, i)) })
4153
4931
  ] });
4154
4932
  });
4155
4933
  function tailForDisplay(text, maxChars) {
@@ -4162,7 +4940,7 @@ function tailForDisplay(text, maxChars) {
4162
4940
  return `\u2026 ${text.slice(cut)}`;
4163
4941
  }
4164
4942
  var MAX_CODE_LINES = 80;
4165
- var DIFF_MAX_LINES = 8;
4943
+ var DIFF_MAX_LINES = 12;
4166
4944
  function CodeBlock({
4167
4945
  code,
4168
4946
  lang,
@@ -4194,58 +4972,83 @@ function CodeBlock({
4194
4972
  paddingX: 1,
4195
4973
  children: [
4196
4974
  lang !== "plain" ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: lang }) : null,
4197
- rows.map((tokens, i) => (
4198
- // biome-ignore lint/suspicious/noArrayIndexKey: code lines are positional
4199
- /* @__PURE__ */ jsxs(Text, { children: [
4200
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
4201
- tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */ jsx(
4202
- Text,
4203
- {
4204
- dimColor: Boolean(t.dim),
4205
- bold: Boolean(t.bold),
4206
- ...t.color ? { color: t.color } : {},
4207
- children: t.text
4208
- },
4209
- j
4210
- ))
4211
- ] }, i)
4212
- )),
4975
+ rows.map((tokens, i) => /* @__PURE__ */ jsxs(Text, { children: [
4976
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
4977
+ tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */ jsx(
4978
+ Text,
4979
+ {
4980
+ dimColor: Boolean(t.dim),
4981
+ bold: Boolean(t.bold),
4982
+ ...t.color ? { color: t.color } : {},
4983
+ children: t.text
4984
+ },
4985
+ j
4986
+ ))
4987
+ ] }, i)),
4213
4988
  hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: `\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
4214
4989
  ]
4215
4990
  }
4216
4991
  );
4217
4992
  }
4218
- function DiffBlock({ rows, hidden }) {
4993
+ function DiffBlock({
4994
+ rows,
4995
+ hidden,
4996
+ hiddenAdded = 0,
4997
+ hiddenRemoved = 0
4998
+ }) {
4219
4999
  let gutterWidth = 1;
4220
5000
  for (const r of rows) {
4221
- const n = r.kind === "del" ? r.oldLine : r.newLine;
4222
- if (typeof n === "number") {
4223
- const w = String(n).length;
4224
- if (w > gutterWidth) gutterWidth = w;
5001
+ for (const n of [r.oldLine, r.newLine]) {
5002
+ if (typeof n === "number") {
5003
+ const w = String(n).length;
5004
+ if (w > gutterWidth) gutterWidth = w;
5005
+ }
4225
5006
  }
4226
5007
  }
4227
5008
  const blank = " ".repeat(gutterWidth);
5009
+ const gutterPad = `${blank} ${blank}`;
5010
+ const footerStats = [
5011
+ hiddenAdded > 0 ? `+${hiddenAdded}` : "",
5012
+ hiddenRemoved > 0 ? `-${hiddenRemoved}` : ""
5013
+ ].filter(Boolean);
5014
+ const markerFor = (kind) => {
5015
+ if (kind === "add") return "+";
5016
+ if (kind === "del") return "-";
5017
+ return " ";
5018
+ };
5019
+ const textForDisplay = (row) => {
5020
+ if ((row.kind === "add" || row.kind === "del" || row.kind === "ctx") && row.text.length > 0) {
5021
+ return row.text.slice(1) || " ";
5022
+ }
5023
+ return row.text || " ";
5024
+ };
4228
5025
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 4, marginTop: 0, children: [
4229
5026
  rows.map((row, i) => {
4230
5027
  const key = i;
4231
5028
  if (row.kind === "hunk") {
4232
- return /* @__PURE__ */ jsx(Text, { color: "cyan", dimColor: true, children: row.text }, key);
5029
+ return /* @__PURE__ */ jsx(Text, { color: "cyan", dimColor: true, children: `${gutterPad} ${row.text}` }, key);
4233
5030
  }
4234
5031
  if (row.kind === "meta") {
4235
- return /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${blank} ${row.text}` }, key);
5032
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${gutterPad} ${row.text}` }, key);
4236
5033
  }
4237
- const lnNumber = row.kind === "del" ? row.oldLine : row.newLine;
4238
- const lnText = typeof lnNumber === "number" ? String(lnNumber).padStart(gutterWidth, " ") : blank;
5034
+ const oldLn = typeof row.oldLine === "number" ? String(row.oldLine).padStart(gutterWidth, " ") : blank;
5035
+ const newLn = typeof row.newLine === "number" ? String(row.newLine).padStart(gutterWidth, " ") : blank;
4239
5036
  if (row.kind === "ctx") {
4240
- return /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${lnText} ${row.text}` }, key);
5037
+ return /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${oldLn} ${newLn} ${textForDisplay(row)}` }, key);
4241
5038
  }
4242
5039
  const bg = row.kind === "add" ? theme.diffAddBg : theme.diffDelBg;
5040
+ const lineColor = row.kind === "add" ? theme.success : theme.error;
5041
+ const marker = markerFor(row.kind);
4243
5042
  return /* @__PURE__ */ jsxs(Text, { children: [
4244
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: `${lnText} ` }),
4245
- /* @__PURE__ */ jsx(Text, { backgroundColor: bg, color: "black", children: row.text })
5043
+ /* @__PURE__ */ jsx(Text, { color: row.kind === "del" ? lineColor : void 0, dimColor: row.kind !== "del", children: oldLn }),
5044
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
5045
+ /* @__PURE__ */ jsx(Text, { color: row.kind === "add" ? lineColor : void 0, dimColor: row.kind !== "add", children: newLn }),
5046
+ /* @__PURE__ */ jsx(Text, { children: " " }),
5047
+ /* @__PURE__ */ jsx(Text, { color: lineColor, bold: true, children: marker }),
5048
+ /* @__PURE__ */ jsx(Text, { backgroundColor: bg, color: "black", children: textForDisplay(row) })
4246
5049
  ] }, key);
4247
5050
  }),
4248
- hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: `${blank} \u2026 ${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
5051
+ hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, italic: true, children: `${gutterPad} \u2026 ${hidden} more line${hidden === 1 ? "" : "s"}${footerStats.length > 0 ? ` (${footerStats.join(" ")})` : ""}` }) : null
4249
5052
  ] });
4250
5053
  }
4251
5054
  function parseUnifiedDiff(diff, maxLines) {
@@ -4284,19 +5087,35 @@ function parseUnifiedDiff(diff, maxLines) {
4284
5087
  oldLn++;
4285
5088
  newLn++;
4286
5089
  }
4287
- if (all.length === 0) return { rows: [], hidden: 0 };
4288
- if (all.length <= maxLines) return { rows: all, hidden: 0 };
4289
- return { rows: all.slice(0, maxLines), hidden: all.length - maxLines };
5090
+ const added = all.filter((row) => row.kind === "add").length;
5091
+ const removed = all.filter((row) => row.kind === "del").length;
5092
+ if (all.length === 0) {
5093
+ return { rows: [], hidden: 0, added: 0, removed: 0, hiddenAdded: 0, hiddenRemoved: 0 };
5094
+ }
5095
+ if (all.length <= maxLines) {
5096
+ return { rows: all, hidden: 0, added, removed, hiddenAdded: 0, hiddenRemoved: 0 };
5097
+ }
5098
+ const rows = all.slice(0, maxLines);
5099
+ const hiddenRows = all.slice(maxLines);
5100
+ return {
5101
+ rows,
5102
+ hidden: hiddenRows.length,
5103
+ added,
5104
+ removed,
5105
+ hiddenAdded: hiddenRows.filter((row) => row.kind === "add").length,
5106
+ hiddenRemoved: hiddenRows.filter((row) => row.kind === "del").length
5107
+ };
4290
5108
  }
4291
- function extractDiffPreview(toolName, output) {
5109
+ function extractDiffPreview(toolName, output, input) {
4292
5110
  if (!output) return void 0;
4293
5111
  const text = output.trim();
4294
5112
  if (!text) return void 0;
4295
5113
  let diff;
4296
- if (toolName === "edit" || toolName === "diff") {
5114
+ if (toolName === "edit" || toolName === "diff" || toolName === "write") {
4297
5115
  const parsed = tryParseJson(text);
4298
5116
  if (parsed && typeof parsed === "object") {
4299
- diff = stringOf(parsed["diff"]);
5117
+ const obj = parsed;
5118
+ diff = toolName === "write" && obj["created"] === true ? newFileDiffFromWriteInput(obj, input) ?? stringOf(obj["diff"]) : stringOf(obj["diff"]);
4300
5119
  }
4301
5120
  } else if (toolName === "patch") {
4302
5121
  const parsed = tryParseJson(text);
@@ -4305,9 +5124,32 @@ function extractDiffPreview(toolName, output) {
4305
5124
  } else if (text.includes("@@") || text.startsWith("---")) {
4306
5125
  diff = text;
4307
5126
  }
5127
+ } else if (toolName === "replace") {
5128
+ const parsed = tryParseJson(text);
5129
+ if (parsed && typeof parsed === "object") {
5130
+ diff = collectReplaceDiffs(parsed);
5131
+ }
4308
5132
  }
4309
- if (!diff || !diff.trim() || diff.startsWith("(no-op")) return void 0;
4310
- return parseUnifiedDiff(diff, DIFF_MAX_LINES);
5133
+ if (!diff?.trim() || diff.startsWith("(no-op")) return void 0;
5134
+ const preview = parseUnifiedDiff(diff, DIFF_MAX_LINES);
5135
+ return preview.rows.length > 0 ? preview : void 0;
5136
+ }
5137
+ function collectReplaceDiffs(obj) {
5138
+ const results = Array.isArray(obj["results"]) ? obj["results"] : [];
5139
+ const diffs = results.map(
5140
+ (result) => result && typeof result === "object" ? stringOf(result["diff"]) : void 0
5141
+ ).filter((diff) => Boolean(diff?.trim()));
5142
+ return diffs.length > 0 ? diffs.join("\n") : void 0;
5143
+ }
5144
+ function newFileDiffFromWriteInput(output, input) {
5145
+ if (!input || typeof input !== "object") return void 0;
5146
+ const obj = input;
5147
+ const content = stringOf(obj["content"]);
5148
+ if (content === void 0) return void 0;
5149
+ const path7 = stringOf(output["path"]) ?? stringOf(obj["path"]) ?? "new file";
5150
+ const lines = content === "" ? [] : content.replace(/\n$/, "").split("\n");
5151
+ const header = [`+++ ${path7}`, `@@ -0,0 +1,${lines.length} @@`];
5152
+ return [...header, ...lines.map((line) => `+${line}`)].join("\n");
4311
5153
  }
4312
5154
  var MESSAGE_PANEL_CHROME_WIDTH = 2;
4313
5155
  function assistantContentWidth(termWidth) {
@@ -4354,20 +5196,14 @@ function AssistantBody({
4354
5196
  const segments = splitFencedBlocks(text);
4355
5197
  const inner = contentWidth ?? termWidth;
4356
5198
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: segments.map(
4357
- (seg, i) => seg.type === "code" ? (
4358
- // biome-ignore lint/suspicious/noArrayIndexKey: segment order is stable
4359
- /* @__PURE__ */ jsx(CodeBlock, { code: seg.text, lang: seg.lang ?? "plain", contentWidth: inner }, i)
4360
- ) : (
4361
- // biome-ignore lint/suspicious/noArrayIndexKey: segment order is stable
4362
- /* @__PURE__ */ jsx(
4363
- MarkdownView,
4364
- {
4365
- text: seg.text,
4366
- termWidth: inner,
4367
- tableWidth: termWidth - MESSAGE_PANEL_CHROME_WIDTH
4368
- },
4369
- i
4370
- )
5199
+ (seg, i) => seg.type === "code" ? /* @__PURE__ */ jsx(CodeBlock, { code: seg.text, lang: seg.lang ?? "plain", contentWidth: inner }, i) : /* @__PURE__ */ jsx(
5200
+ MarkdownView,
5201
+ {
5202
+ text: seg.text,
5203
+ termWidth: inner,
5204
+ tableWidth: termWidth - MESSAGE_PANEL_CHROME_WIDTH
5205
+ },
5206
+ i
4371
5207
  )
4372
5208
  ) });
4373
5209
  }
@@ -4403,10 +5239,7 @@ function AssistantTail({
4403
5239
  /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }),
4404
5240
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " (streaming\u2026)" })
4405
5241
  ] }),
4406
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rows.map((r, i) => (
4407
- // biome-ignore lint/suspicious/noArrayIndexKey: fixed-height block, index is the row
4408
- /* @__PURE__ */ jsx(Text, { color: "white", children: r || " " }, i)
4409
- )) })
5242
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: rows.map((r, i) => /* @__PURE__ */ jsx(Text, { color: "white", children: r || " " }, i)) })
4410
5243
  ]
4411
5244
  }
4412
5245
  );
@@ -4706,7 +5539,8 @@ var Entry = React5.memo(function Entry2({
4706
5539
  entry.outputBytes,
4707
5540
  entry.outputLines
4708
5541
  );
4709
- const diff = entry.ok ? extractDiffPreview(entry.name, entry.output) : void 0;
5542
+ const visualLines = formatToolVisualOutput(entry.name, entry.output, entry.ok, entry.input);
5543
+ const diff = entry.ok ? extractDiffPreview(entry.name, entry.output, entry.input) : void 0;
4710
5544
  const sizeChip = (() => {
4711
5545
  if (!entry.ok) return "";
4712
5546
  const parts = [];
@@ -4733,21 +5567,26 @@ var Entry = React5.memo(function Entry2({
4733
5567
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${fmtDuration(entry.durationMs)}` }),
4734
5568
  sizeChip ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${sizeChip}` }) : null
4735
5569
  ] }),
4736
- outLines.map((line, i) => (
4737
- // biome-ignore lint/suspicious/noArrayIndexKey: tool output lines are static, index is stable
4738
- /* @__PURE__ */ jsxs(Text, { children: [
4739
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: i === outLines.length - 1 && !diff ? " \u2514\u2500 " : " \u251C\u2500 " }),
4740
- /* @__PURE__ */ jsx(
4741
- Text,
4742
- {
4743
- dimColor: entry.ok && !line.startsWith("!"),
4744
- ...!entry.ok || line.startsWith("!") ? { color: "red" } : {},
4745
- children: line
4746
- }
4747
- )
4748
- ] }, i)
4749
- )),
4750
- diff ? /* @__PURE__ */ jsx(DiffBlock, { rows: diff.rows, hidden: diff.hidden }) : null
5570
+ visualLines ? /* @__PURE__ */ jsx(ToolOutputLines, { lines: visualLines, hasFollowingBlock: Boolean(diff) }) : outLines.map((line, i) => /* @__PURE__ */ jsxs(Text, { children: [
5571
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: i === outLines.length - 1 && !diff ? " \u2514\u2500 " : " \u251C\u2500 " }),
5572
+ /* @__PURE__ */ jsx(
5573
+ Text,
5574
+ {
5575
+ dimColor: entry.ok && !line.startsWith("!"),
5576
+ ...!entry.ok || line.startsWith("!") ? { color: "red" } : {},
5577
+ children: line
5578
+ }
5579
+ )
5580
+ ] }, i)),
5581
+ diff ? /* @__PURE__ */ jsx(
5582
+ DiffBlock,
5583
+ {
5584
+ rows: diff.rows,
5585
+ hidden: diff.hidden,
5586
+ hiddenAdded: diff.hiddenAdded,
5587
+ hiddenRemoved: diff.hiddenRemoved
5588
+ }
5589
+ ) : null
4751
5590
  ] });
4752
5591
  }
4753
5592
  case "info": {
@@ -4851,13 +5690,10 @@ var Entry = React5.memo(function Entry2({
4851
5690
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: entry.detail })
4852
5691
  ] }) : null
4853
5692
  ] }),
4854
- lines.slice(1).map((line, i) => (
4855
- // biome-ignore lint/suspicious/noArrayIndexKey: stable line index
4856
- /* @__PURE__ */ jsxs(Text, { children: [
4857
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
4858
- /* @__PURE__ */ jsx(Text, { children: line })
4859
- ] }, i)
4860
- ))
5693
+ lines.slice(1).map((line, i) => /* @__PURE__ */ jsxs(Text, { children: [
5694
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
5695
+ /* @__PURE__ */ jsx(Text, { children: line })
5696
+ ] }, i))
4861
5697
  ] });
4862
5698
  }
4863
5699
  }
@@ -5507,13 +6343,7 @@ var Input = memo(function Input2({
5507
6343
  }
5508
6344
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
5509
6345
  rows.map(
5510
- (row, i) => row.length === 0 ? (
5511
- // biome-ignore lint/suspicious/noArrayIndexKey: rows are positional and re-laid out every render
5512
- /* @__PURE__ */ jsx(Text, { children: " " }, i)
5513
- ) : (
5514
- // biome-ignore lint/suspicious/noArrayIndexKey: rows are positional and re-laid out every render
5515
- /* @__PURE__ */ jsx(Text, { children: renderRow2(row, `r${i}`, promptColor) }, i)
5516
- )
6346
+ (row, i) => row.length === 0 ? /* @__PURE__ */ jsx(Text, { children: " " }, i) : /* @__PURE__ */ jsx(Text, { children: renderRow2(row, `r${i}`, promptColor) }, i)
5517
6347
  ),
5518
6348
  hint ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) : null
5519
6349
  ] });
@@ -5673,30 +6503,172 @@ function PhaseMonitor({
5673
6503
  const isRunning = runningPhaseIds.includes(phaseKey);
5674
6504
  const elapsed = phase.startedAt ? fmtElapsed2(nowTick - phase.startedAt) : "\u2014";
5675
6505
  const progress = phase.totalTasks > 0 ? `${phase.completedTasks}/${phase.totalTasks}` : "\u2014";
5676
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
5677
- /* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
5678
- /* @__PURE__ */ jsx(Text, { bold: true, children: phase.name }),
5679
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5680
- /* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.label }),
5681
- isRunning ? /* @__PURE__ */ jsxs(Fragment, { children: [
5682
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5683
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5684
- "elapsed ",
5685
- elapsed
5686
- ] })
5687
- ] }) : null,
5688
- phase.totalTasks > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
6506
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
6507
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
6508
+ /* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
6509
+ /* @__PURE__ */ jsx(Text, { bold: true, children: phase.name }),
5689
6510
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
5690
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
5691
- "tasks ",
5692
- progress
6511
+ /* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.label }),
6512
+ isRunning ? /* @__PURE__ */ jsxs(Fragment, { children: [
6513
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
6514
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
6515
+ "elapsed ",
6516
+ elapsed
6517
+ ] })
6518
+ ] }) : null,
6519
+ phase.totalTasks > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
6520
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
6521
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
6522
+ "tasks ",
6523
+ progress
6524
+ ] })
5693
6525
  ] })
5694
- ] })
5695
- ] }) }, phaseKey);
6526
+ ] }),
6527
+ (phase.activeTasks ?? []).map((t) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginLeft: 2, children: [
6528
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u25CF" }),
6529
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: t.agent ?? "agent" }),
6530
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2192" }),
6531
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: t.title || "(task)" })
6532
+ ] }, t.taskId))
6533
+ ] }, phaseKey);
5696
6534
  }),
5697
6535
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate phases" }) })
5698
6536
  ] });
5699
6537
  }
6538
+ var STATUS3 = {
6539
+ pending: { icon: "\u25CB", color: "gray" },
6540
+ queued: { icon: "\u25D4", color: "cyan" },
6541
+ in_progress: { icon: "\u25B6", color: "yellow" },
6542
+ blocked: { icon: "\u2298", color: "magenta" },
6543
+ review: { icon: "\u25C6", color: "blue" },
6544
+ failed: { icon: "\u2717", color: "red" },
6545
+ completed: { icon: "\u2713", color: "green" },
6546
+ cancelled: { icon: "\u229D", color: "gray" }
6547
+ };
6548
+ var RUN_STATUS = {
6549
+ running: "yellow",
6550
+ paused: "magenta",
6551
+ completed: "green",
6552
+ failed: "red",
6553
+ deadlocked: "red",
6554
+ idle: "gray"
6555
+ };
6556
+ var PRIORITY = {
6557
+ critical: "red",
6558
+ high: "yellow",
6559
+ medium: "cyan",
6560
+ low: "gray"
6561
+ };
6562
+ var FEED_KIND = {
6563
+ started: { icon: "\u25B6", color: "yellow" },
6564
+ completed: { icon: "\u2713", color: "green" },
6565
+ failed: { icon: "\u2717", color: "red" },
6566
+ retrying: { icon: "\u21BB", color: "yellow" },
6567
+ wave: { icon: "\u224B", color: "magenta" },
6568
+ deadlock: { icon: "\u26A0", color: "red" },
6569
+ verification_failed: { icon: "\u26CA", color: "red" },
6570
+ conflict: { icon: "\u2442", color: "yellow" },
6571
+ split: { icon: "\u22D4", color: "cyan" },
6572
+ supervisor: { icon: "\u2726", color: "magenta" }
6573
+ };
6574
+ function clip(s2, n) {
6575
+ return s2.length > n ? `${s2.slice(0, n - 1)}\u2026` : s2;
6576
+ }
6577
+ function TaskCard({ task }) {
6578
+ const st2 = STATUS3[task.displayStatus] ?? { icon: "?", color: "white" };
6579
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, width: 26, children: [
6580
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
6581
+ /* @__PURE__ */ jsx(Text, { color: st2.color, bold: true, children: st2.icon }),
6582
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: task.shortId }),
6583
+ /* @__PURE__ */ jsx(Text, { color: PRIORITY[task.priority] ?? "gray", children: task.priority[0]?.toUpperCase() })
6584
+ ] }),
6585
+ /* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: clip(task.title, 24) }),
6586
+ task.deps.length > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
6587
+ "\u2190 ",
6588
+ clip(task.deps.join(", "), 22)
6589
+ ] }) : null,
6590
+ task.agentName ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
6591
+ /* @__PURE__ */ jsx(Text, { color: task.displayStatus === "in_progress" ? "yellow" : "gray", children: "\u25CF" }),
6592
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: clip(task.agentName, 14) }),
6593
+ task.retries > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
6594
+ "\u21BB",
6595
+ task.retries
6596
+ ] }) : null
6597
+ ] }) : null,
6598
+ task.worktreeBranch ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
6599
+ "\u2325 ",
6600
+ clip(task.worktreeBranch, 22)
6601
+ ] }) : null
6602
+ ] });
6603
+ }
6604
+ function SddBoardOverlay({
6605
+ snapshot
6606
+ }) {
6607
+ const byShort = new Map(snapshot.tasks.map((t) => [t.shortId, t]));
6608
+ const p = snapshot.progress;
6609
+ const chains = snapshot.diagnostics?.deadlockChains ?? [];
6610
+ const recentFeed = (snapshot.feed ?? []).slice(0, 6);
6611
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
6612
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginBottom: 1, children: [
6613
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "SDD BOARD" }),
6614
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
6615
+ /* @__PURE__ */ jsx(Text, { bold: true, children: clip(snapshot.title, 32) }),
6616
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
6617
+ /* @__PURE__ */ jsx(Text, { color: RUN_STATUS[snapshot.status] ?? "white", children: snapshot.status }),
6618
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
6619
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
6620
+ "wave ",
6621
+ snapshot.wave + 1
6622
+ ] }),
6623
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
6624
+ /* @__PURE__ */ jsxs(Text, { color: "green", children: [
6625
+ "\u2713",
6626
+ p.completed
6627
+ ] }),
6628
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "/" }),
6629
+ /* @__PURE__ */ jsx(Text, { children: p.total }),
6630
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
6631
+ "(",
6632
+ p.percentComplete,
6633
+ "%)"
6634
+ ] }),
6635
+ p.inProgress > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
6636
+ "\u25B6",
6637
+ p.inProgress
6638
+ ] }) : null,
6639
+ p.failed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
6640
+ "\u2717",
6641
+ p.failed
6642
+ ] }) : null,
6643
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+B close \xB7 c clean wt \xB7 z rollback" })
6644
+ ] }),
6645
+ chains.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
6646
+ /* @__PURE__ */ jsx(Text, { color: "red", bold: true, children: "\u26A0 Deadlock \u2014 blocked by failed tasks:" }),
6647
+ chains.map((c) => /* @__PURE__ */ jsxs(Text, { color: "red", children: [
6648
+ " ",
6649
+ c.blocked,
6650
+ " \u2190 ",
6651
+ c.blockedBy.join(", ")
6652
+ ] }, c.blocked))
6653
+ ] }) : null,
6654
+ snapshot.tasks.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No active SDD run. Start one with /sdd execute." }) : /* @__PURE__ */ jsx(Box, { flexDirection: "row", gap: 2, children: snapshot.columns.map((col) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginRight: 1, children: [
6655
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: col.label }),
6656
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(12) }),
6657
+ col.taskIds.map((sid) => byShort.get(sid)).filter((t) => Boolean(t)).map((t) => /* @__PURE__ */ jsx(TaskCard, { task: t }, t.id))
6658
+ ] }, col.label)) }),
6659
+ recentFeed.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
6660
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Recent activity" }),
6661
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500".repeat(12) }),
6662
+ recentFeed.map((f, i) => {
6663
+ const k = FEED_KIND[f.kind] ?? FEED_KIND.started;
6664
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
6665
+ /* @__PURE__ */ jsx(Text, { color: k?.color ?? "white", children: k?.icon ?? "\u2022" }),
6666
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: clip(f.text, 70) })
6667
+ ] }, `${f.ts}-${i}`);
6668
+ })
6669
+ ] }) : null
6670
+ ] });
6671
+ }
5700
6672
  var fmtElapsed3 = (ms) => {
5701
6673
  const s2 = Math.floor(ms / 1e3);
5702
6674
  const m = Math.floor(s2 / 60);
@@ -5705,7 +6677,7 @@ var fmtElapsed3 = (ms) => {
5705
6677
  if (m > 0) return `${m}:${String(s2 % 60).padStart(2, "0")}`;
5706
6678
  return `${s2}s`;
5707
6679
  };
5708
- var STATUS3 = {
6680
+ var STATUS4 = {
5709
6681
  pending: { icon: "\u25CB", color: "gray" },
5710
6682
  ready: { icon: "\u25D0", color: "cyan" },
5711
6683
  running: { icon: "\u25CF", color: "yellow" },
@@ -5715,7 +6687,7 @@ var STATUS3 = {
5715
6687
  skipped: { icon: "\u2298", color: "gray" }
5716
6688
  };
5717
6689
  function s(entry) {
5718
- return STATUS3[entry] ?? { icon: "?", color: "white" };
6690
+ return STATUS4[entry] ?? { icon: "?", color: "white" };
5719
6691
  }
5720
6692
  function PhasePanel({ phases, nowTick }) {
5721
6693
  const list = Object.values(phases);
@@ -6033,7 +7005,7 @@ function GoalPanel({
6033
7005
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: coordinatorRunning ? /* @__PURE__ */ jsxs(Fragment, { children: [
6034
7006
  /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF Coordinator running " }),
6035
7007
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[S] Stop coordinator" })
6036
- ] }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[C] Start coordinator" }) }) })
7008
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[C] Start coordinator" }) })
6037
7009
  ] });
6038
7010
  }
6039
7011
  const displayGoal = goal.refinedGoal || goal.goal;
@@ -6071,15 +7043,12 @@ function GoalPanel({
6071
7043
  ] }) }),
6072
7044
  goal.deliverables.map((d, i) => {
6073
7045
  const done = /^\[[x✓]\]|✅|\(done\)/i.test(d);
6074
- return (
6075
- // biome-ignore lint/suspicious/noArrayIndexKey: deliverables are stable text strings
6076
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { ...done ? { color: "green" } : {}, dimColor: !done, children: [
6077
- " ",
6078
- done ? "\u2713" : "\u25CB",
6079
- " ",
6080
- d
6081
- ] }) }, i)
6082
- );
7046
+ return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { ...done ? { color: "green" } : {}, dimColor: !done, children: [
7047
+ " ",
7048
+ done ? "\u2713" : "\u25CB",
7049
+ " ",
7050
+ d
7051
+ ] }) }, i);
6083
7052
  })
6084
7053
  ] }),
6085
7054
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
@@ -6103,7 +7072,7 @@ function GoalPanel({
6103
7072
  /* @__PURE__ */ jsx(Box, { marginTop: 1, children: coordinatorRunning ? /* @__PURE__ */ jsxs(Fragment, { children: [
6104
7073
  /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF Coordinator running " }),
6105
7074
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[S] Stop coordinator" })
6106
- ] }) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[C] Start coordinator" }) }) })
7075
+ ] }) : /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[C] Start coordinator" }) })
6107
7076
  ] })
6108
7077
  ] });
6109
7078
  }
@@ -7187,13 +8156,10 @@ function hintsFor(ctx) {
7187
8156
  }
7188
8157
  function KeyHintBar({ context }) {
7189
8158
  const hints = hintsFor(context);
7190
- return /* @__PURE__ */ jsx(Box, { flexDirection: "row", paddingX: 1, children: hints.map((h, i) => (
7191
- // biome-ignore lint/suspicious/noArrayIndexKey: hints are positional + stable
7192
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", marginRight: 2, children: [
7193
- /* @__PURE__ */ jsx(Text, { color: h.discovery ? theme.monitor.agents : theme.accent, children: h.key }),
7194
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${h.label}` })
7195
- ] }, i)
7196
- )) });
8159
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "row", paddingX: 1, children: hints.map((h, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", marginRight: 2, children: [
8160
+ /* @__PURE__ */ jsx(Text, { color: h.discovery ? theme.monitor.agents : theme.accent, children: h.key }),
8161
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${h.label}` })
8162
+ ] }, i)) });
7197
8163
  }
7198
8164
  function TodosMonitor({ todos }) {
7199
8165
  const { stdout } = useStdout();
@@ -7426,7 +8392,7 @@ var fmtElapsed6 = (ms) => {
7426
8392
  if (m > 0) return `${m}:${String(s2 % 60).padStart(2, "0")}`;
7427
8393
  return `${s2}s`;
7428
8394
  };
7429
- var STATUS4 = {
8395
+ var STATUS5 = {
7430
8396
  allocating: { icon: "\u25CB", color: "gray" },
7431
8397
  active: { icon: "\u25CF", color: "yellow" },
7432
8398
  committing: { icon: "\u25D0", color: "cyan" },
@@ -7436,7 +8402,7 @@ var STATUS4 = {
7436
8402
  failed: { icon: "\u2717", color: "red" }
7437
8403
  };
7438
8404
  function st(status) {
7439
- return STATUS4[status] ?? { icon: "?", color: "white" };
8405
+ return STATUS5[status] ?? { icon: "?", color: "white" };
7440
8406
  }
7441
8407
  function WorktreePanel({
7442
8408
  worktrees,
@@ -8399,6 +9365,46 @@ function useAutoPhaseEvents(subscribeAutoPhase, dispatch, stateRef) {
8399
9365
  });
8400
9366
  break;
8401
9367
  }
9368
+ case "phase.taskStarted": {
9369
+ const p = payload;
9370
+ dispatch({
9371
+ type: "autoPhaseTaskActive",
9372
+ phaseId: p.phaseId,
9373
+ taskId: p.taskId,
9374
+ title: p.taskTitle,
9375
+ agent: p.agentName,
9376
+ active: true
9377
+ });
9378
+ break;
9379
+ }
9380
+ case "phase.taskAssigned": {
9381
+ const p = payload;
9382
+ const active = stateRef.current.autoPhase?.phases[p.phaseId]?.activeTasks?.find(
9383
+ (t) => t.taskId === p.taskId
9384
+ );
9385
+ if (active) {
9386
+ dispatch({
9387
+ type: "autoPhaseTaskActive",
9388
+ phaseId: p.phaseId,
9389
+ taskId: p.taskId,
9390
+ title: active.title,
9391
+ agent: p.agentName,
9392
+ active: true
9393
+ });
9394
+ }
9395
+ break;
9396
+ }
9397
+ case "phase.taskFailed": {
9398
+ const p = payload;
9399
+ dispatch({
9400
+ type: "autoPhaseTaskActive",
9401
+ phaseId: p.phaseId,
9402
+ taskId: p.taskId,
9403
+ title: "",
9404
+ active: false
9405
+ });
9406
+ break;
9407
+ }
8402
9408
  case "phase.taskCompleted": {
8403
9409
  const p = payload;
8404
9410
  const existing = stateRef.current.autoPhase?.phases[p.phaseId];
@@ -8412,6 +9418,13 @@ function useAutoPhaseEvents(subscribeAutoPhase, dispatch, stateRef) {
8412
9418
  totalTasks: existing.totalTasks
8413
9419
  });
8414
9420
  }
9421
+ dispatch({
9422
+ type: "autoPhaseTaskActive",
9423
+ phaseId: p.phaseId,
9424
+ taskId: p.taskId,
9425
+ title: "",
9426
+ active: false
9427
+ });
8415
9428
  break;
8416
9429
  }
8417
9430
  case "autonomous.tick": {
@@ -8430,6 +9443,11 @@ function useAutoPhaseEvents(subscribeAutoPhase, dispatch, stateRef) {
8430
9443
  dispatch({ type: "autoPhaseReset" });
8431
9444
  break;
8432
9445
  }
9446
+ case "sdd.board.snapshot": {
9447
+ const p = payload;
9448
+ if (p.snapshot) dispatch({ type: "sddBoardSnapshot", snapshot: p.snapshot });
9449
+ break;
9450
+ }
8433
9451
  case "worktree.allocated": {
8434
9452
  const p = payload;
8435
9453
  dispatch({
@@ -8764,6 +9782,7 @@ function closePanels(state) {
8764
9782
  projectPicker: { ...state.projectPicker, open: false },
8765
9783
  fKeyPicker: { ...state.fKeyPicker, open: false },
8766
9784
  autoPhase: state.autoPhase ? { ...state.autoPhase, monitorOpen: false } : state.autoPhase,
9785
+ sddBoard: state.sddBoard ? { ...state.sddBoard, monitorOpen: false } : state.sddBoard,
8767
9786
  worktreeMonitorOpen: false,
8768
9787
  coordinator: { ...state.coordinator, monitorOpen: false }
8769
9788
  };
@@ -9905,12 +10924,31 @@ function reducer(state, action) {
9905
10924
  status: action.status,
9906
10925
  completedTasks: action.completedTasks,
9907
10926
  totalTasks: action.totalTasks,
9908
- startedAt: action.startedAt
10927
+ startedAt: action.startedAt,
10928
+ // Preserve the live worker list across status/count updates.
10929
+ activeTasks: existing.phases[action.phaseId]?.activeTasks
9909
10930
  }
9910
10931
  }
9911
10932
  }
9912
10933
  };
9913
10934
  }
10935
+ case "autoPhaseTaskActive": {
10936
+ if (!state.autoPhase) return state;
10937
+ const phase = state.autoPhase.phases[action.phaseId];
10938
+ if (!phase) return state;
10939
+ const without = (phase.activeTasks ?? []).filter((t) => t.taskId !== action.taskId);
10940
+ const activeTasks = action.active ? [...without, { taskId: action.taskId, title: action.title, agent: action.agent }] : without;
10941
+ return {
10942
+ ...state,
10943
+ autoPhase: {
10944
+ ...state.autoPhase,
10945
+ phases: {
10946
+ ...state.autoPhase.phases,
10947
+ [action.phaseId]: { ...phase, activeTasks }
10948
+ }
10949
+ }
10950
+ };
10951
+ }
9914
10952
  case "autoPhaseRunningPhases": {
9915
10953
  if (!state.autoPhase) return state;
9916
10954
  return {
@@ -9937,6 +10975,22 @@ function reducer(state, action) {
9937
10975
  case "autoPhaseReset": {
9938
10976
  return { ...state, autoPhase: null };
9939
10977
  }
10978
+ case "sddBoardSnapshot": {
10979
+ const monitorOpen = state.sddBoard?.monitorOpen ?? false;
10980
+ return { ...state, sddBoard: { snapshot: action.snapshot, monitorOpen } };
10981
+ }
10982
+ case "toggleSddBoardMonitor": {
10983
+ if (!state.sddBoard) return state;
10984
+ const opening = !state.sddBoard.monitorOpen;
10985
+ return opening ? {
10986
+ ...state,
10987
+ ...closePanels(state),
10988
+ sddBoard: { ...state.sddBoard, monitorOpen: true }
10989
+ } : {
10990
+ ...state,
10991
+ sddBoard: { ...state.sddBoard, monitorOpen: false }
10992
+ };
10993
+ }
9940
10994
  case "worktreeUpsert": {
9941
10995
  const prev = state.worktrees[action.handleId];
9942
10996
  const merged = {
@@ -10369,6 +11423,7 @@ function App({
10369
11423
  getAutonomy,
10370
11424
  getEternalEngine,
10371
11425
  getParallelEngine,
11426
+ getSddRun,
10372
11427
  subscribeEternalIteration,
10373
11428
  subscribeEternalStage,
10374
11429
  subscribeAutoPhase,
@@ -10627,6 +11682,7 @@ function App({
10627
11682
  eternalStage: null,
10628
11683
  goalSummary: null,
10629
11684
  autoPhase: null,
11685
+ sddBoard: null,
10630
11686
  worktrees: {},
10631
11687
  worktreeMonitorOpen: false,
10632
11688
  coordinator: {
@@ -10893,7 +11949,7 @@ function App({
10893
11949
  readGitInfo(agent.ctx.cwd).then((info) => {
10894
11950
  if (cancelled) return;
10895
11951
  setGitInfo(info);
10896
- if (info && info.branch) {
11952
+ if (info?.branch) {
10897
11953
  const prev = prevBranchRef.current;
10898
11954
  if (prev !== null && prev !== info.branch) {
10899
11955
  const msg = {
@@ -12395,9 +13451,12 @@ function App({
12395
13451
  (e) => e.status === "running"
12396
13452
  ).length;
12397
13453
  const autonomyRunning = eternalLoopRunningRef.current || parallelLoopRunningRef.current || getEternalEngine?.()?.currentState === "running" || getParallelEngine?.()?.currentState === "running";
12398
- if (autonomyRunning || fleetRunning > 0) {
13454
+ const sddRun = getSddRun?.();
13455
+ const sddRunning = sddRun?.isRunning() ?? false;
13456
+ if (autonomyRunning || fleetRunning > 0 || sddRunning) {
12399
13457
  getEternalEngine?.()?.stop();
12400
13458
  getParallelEngine?.()?.stop();
13459
+ if (sddRunning) sddRun?.stop();
12401
13460
  if (autonomyRunning) switchAutonomy?.("off");
12402
13461
  if (director) {
12403
13462
  const cap = new Promise((resolve) => {
@@ -12409,6 +13468,7 @@ function App({
12409
13468
  const killed2 = getProcessRegistry().killAll();
12410
13469
  const bits = [];
12411
13470
  if (autonomyRunning) bits.push("autonomy stopped");
13471
+ if (sddRunning) bits.push("SDD run stopped");
12412
13472
  if (fleetRunning > 0)
12413
13473
  bits.push(`${fleetRunning} agent${fleetRunning === 1 ? "" : "s"} terminated`);
12414
13474
  if (killed2.length > 0)
@@ -12434,7 +13494,7 @@ function App({
12434
13494
  return () => {
12435
13495
  process.off("SIGINT", onSigint);
12436
13496
  };
12437
- }, [director, getEternalEngine, getParallelEngine, switchAutonomy, onExit, exit]);
13497
+ }, [director, getEternalEngine, getParallelEngine, getSddRun, switchAutonomy, onExit, exit]);
12438
13498
  const commitPaste = async (full) => {
12439
13499
  const builder = builderRef.current;
12440
13500
  if (!builder || !full) return;
@@ -13120,6 +14180,42 @@ function App({
13120
14180
  toggleWorktreeOverlay();
13121
14181
  return;
13122
14182
  }
14183
+ if (key.ctrl && input === "b") {
14184
+ dispatch({ type: "toggleSddBoardMonitor" });
14185
+ return;
14186
+ }
14187
+ if (state.sddBoard?.monitorOpen && !key.ctrl && !key.meta) {
14188
+ if (input === "c") {
14189
+ const run = getSddRun?.();
14190
+ if (run) {
14191
+ void run.cleanupWorktrees().then((n) => {
14192
+ dispatch({
14193
+ type: "addEntry",
14194
+ entry: {
14195
+ kind: n > 0 ? "info" : "warn",
14196
+ text: n > 0 ? `Cleaned ${n} SDD worktree${n === 1 ? "" : "s"}.` : "No SDD worktrees to clean (stop the run first if it is live)."
14197
+ }
14198
+ });
14199
+ });
14200
+ }
14201
+ return;
14202
+ }
14203
+ if (input === "z") {
14204
+ const run = getSddRun?.();
14205
+ if (run) {
14206
+ void run.rollback().then((r) => {
14207
+ dispatch({
14208
+ type: "addEntry",
14209
+ entry: {
14210
+ kind: r.ok ? "info" : "warn",
14211
+ text: r.ok ? r.reverted > 0 ? `Rolled back ${r.reverted} run commit${r.reverted === 1 ? "" : "s"} (revert commits added).` : "Nothing to roll back." : `Rollback failed: ${r.reason ?? "unknown error"}`
14212
+ }
14213
+ });
14214
+ });
14215
+ }
14216
+ return;
14217
+ }
14218
+ }
13123
14219
  if (key.fn === 5) {
13124
14220
  if (state.planPanelOpen) {
13125
14221
  dispatch({ type: "togglePlanPanel" });
@@ -13270,7 +14366,7 @@ function App({
13270
14366
  featureMemory: cfg.featureMemory ?? true,
13271
14367
  featureSkills: cfg.featureSkills ?? true,
13272
14368
  featureModelsRegistry: cfg.featureModelsRegistry ?? true,
13273
- tokenSavingTier: cfg.tokenSavingTier ?? "off",
14369
+ tokenSavingTier: cfg.featureTokenSaving ?? "off",
13274
14370
  allowOutsideProjectRoot: cfg.allowOutsideProjectRoot ?? true,
13275
14371
  contextAutoCompact: cfg.contextAutoCompact ?? true,
13276
14372
  contextStrategy: cfg.contextStrategy ?? "hybrid",
@@ -14573,7 +15669,7 @@ User message:
14573
15669
  elapsedMs: state.autoPhase.elapsedMs,
14574
15670
  nowTick
14575
15671
  }
14576
- ) : state.worktreeMonitorOpen ? /* @__PURE__ */ jsx(
15672
+ ) : state.sddBoard?.monitorOpen ? /* @__PURE__ */ jsx(SddBoardOverlay, { snapshot: state.sddBoard.snapshot }) : state.worktreeMonitorOpen ? /* @__PURE__ */ jsx(
14577
15673
  WorktreeMonitor,
14578
15674
  {
14579
15675
  worktrees: state.worktrees,
@@ -14992,6 +16088,7 @@ async function runTui(opts) {
14992
16088
  getAutonomy: opts.getAutonomy,
14993
16089
  getEternalEngine: opts.getEternalEngine,
14994
16090
  getParallelEngine: opts.getParallelEngine,
16091
+ getSddRun: opts.getSddRun,
14995
16092
  subscribeEternalIteration: opts.subscribeEternalIteration,
14996
16093
  subscribeEternalStage: opts.subscribeEternalStage,
14997
16094
  subscribeAutoPhase: opts.subscribeAutoPhase,