@wrongstack/tui 0.8.6 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -162,156 +162,37 @@ function FilePicker({ query, matches, selected }) {
162
162
  function highlight(path3, query) {
163
163
  return path3;
164
164
  }
165
- var STATUS_ICON = {
166
- idle: { icon: "\u25CB", color: "gray" },
167
- running: { icon: "\u25CF", color: "green" },
168
- success: { icon: "\u2713", color: "green" },
169
- failed: { icon: "\u2717", color: "red" },
170
- timeout: { icon: "\u23F1", color: "yellow" },
171
- stopped: { icon: "\u2298", color: "yellow" }
172
- };
173
- function fmtCost(n) {
174
- if (n === 0) return "\u2014";
175
- return `$${n.toFixed(3)}`;
176
- }
177
- function fmtCount(n) {
178
- if (n === 0) return "\u2014";
179
- return String(n);
180
- }
181
- function fmtDuration(ms) {
182
- if (ms < 1e3) return `${ms}ms`;
183
- return `${(ms / 1e3).toFixed(1)}s`;
184
- }
185
- function fmtBytes(n) {
186
- if (n < 1024) return `${n}B`;
187
- return `${(n / 1024).toFixed(1)}KB`;
188
- }
189
- function fmtRecentTool(tool) {
190
- const status = tool.ok === false ? "fail" : "ok";
191
- const name = tool.name.length > 24 ? `${tool.name.slice(0, 23)}...` : tool.name;
192
- const parts = [status, name];
193
- if (typeof tool.durationMs === "number") parts.push(fmtDuration(tool.durationMs));
194
- if (typeof tool.outputBytes === "number" && tool.outputBytes > 0) parts.push(fmtBytes(tool.outputBytes));
195
- if (typeof tool.outputLines === "number" && tool.outputLines > 0) parts.push(`${tool.outputLines}L`);
196
- return parts.join(" ");
197
- }
198
- function fmtRecentMessage(message) {
199
- const text = message.text.replace(/\s+/g, " ");
200
- return text.length > 80 ? `${text.slice(0, 79)}...` : text;
201
- }
202
- function fmtModel(provider, model) {
203
- if (!provider && !model) return "";
204
- const p = provider ?? "";
205
- const m = model ?? "";
206
- return p && m ? `${p}/${m}` : p || m;
207
- }
208
- function resolveName(entry, roster) {
209
- const rosterEntry = roster?.[entry.id];
210
- if (rosterEntry) return rosterEntry.name;
211
- return entry.name;
212
- }
213
165
  function FleetPanel({ entries, totalCost, roster }) {
214
166
  const list = Object.values(entries);
215
167
  if (list.length === 0) return null;
216
- const sorted = [...list].sort((a, b) => {
217
- const order = { running: 0, success: 1, failed: 2, timeout: 3, stopped: 4, idle: 5 };
218
- const ao = order[a.status] ?? 9;
219
- const bo = order[b.status] ?? 9;
220
- if (ao !== bo) return ao - bo;
221
- return b.lastEventAt - a.lastEventAt;
222
- });
223
- const runningCount = list.filter((e) => e.status === "running").length;
224
- const totalLabel = totalCost > 0 ? `$${totalCost.toFixed(3)} \xB7 ${runningCount} active` : `${runningCount} active`;
225
- return /* @__PURE__ */ jsxs(
226
- Box,
227
- {
228
- flexDirection: "column",
229
- paddingX: 1,
230
- borderStyle: "single",
231
- borderTop: false,
232
- borderBottom: false,
233
- borderLeft: false,
234
- borderRight: false,
235
- children: [
236
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
237
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Fleet" }),
238
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
239
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
240
- list.length,
241
- " agent",
242
- list.length === 1 ? "" : "s"
243
- ] }),
244
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
245
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: totalLabel })
246
- ] }),
247
- sorted.map((entry) => {
248
- const si = STATUS_ICON[entry.status];
249
- const modelTag = fmtModel(entry.provider, entry.model);
250
- const name = resolveName(entry, roster);
251
- const recentTools = (entry.recentTools ?? []).slice(-2).map(fmtRecentTool).join(" | ");
252
- const recentMessages = (entry.recentMessages ?? []).slice(-2).map(fmtRecentMessage);
253
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
254
- /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
255
- /* @__PURE__ */ jsx(Text, { color: si.color, children: si.icon }),
256
- /* @__PURE__ */ jsx(Text, { children: name.slice(0, 16).padEnd(16) }),
257
- modelTag ? /* @__PURE__ */ jsxs(Fragment, { children: [
258
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
259
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: modelTag })
260
- ] }) : null,
261
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
262
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
263
- fmtCount(entry.iterations).padStart(3),
264
- "it"
265
- ] }),
266
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
267
- fmtCount(entry.toolCalls).padStart(3),
268
- "tc"
269
- ] }),
270
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
271
- /* @__PURE__ */ jsx(Text, { color: "yellow", children: fmtCost(entry.cost) })
272
- ] }),
273
- entry.status === "running" && entry.currentTool ? /* @__PURE__ */ jsxs(Box, { paddingLeft: 2, children: [
274
- /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
275
- "\u2192 ",
276
- entry.currentTool.name
277
- ] }),
278
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
279
- " (",
280
- Math.max(0, Date.now() - entry.currentTool.startedAt),
281
- "ms)"
282
- ] })
283
- ] }) : null,
284
- recentTools ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
285
- "tools: ",
286
- recentTools
287
- ] }) }) : null,
288
- recentMessages.map((message, index) => /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
289
- "msg: ",
290
- message
291
- ] }) }, `${entry.id}-msg-${index}-${message}`)),
292
- entry.budgetWarning ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
293
- "\u26A1 hitting ",
294
- entry.budgetWarning.kind,
295
- " limit (",
296
- entry.budgetWarning.used,
297
- "/",
298
- entry.budgetWarning.limit,
299
- ") \u2014 extending"
300
- ] }) }) : null,
301
- entry.status === "running" && entry.streamingText ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
302
- ">",
303
- " ",
304
- entry.streamingText.slice(-80)
305
- ] }) }) : null,
306
- entry.transcriptPath ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
307
- "log: ",
308
- entry.transcriptPath
309
- ] }) }) : null
310
- ] }, entry.id);
311
- })
312
- ]
313
- }
314
- );
168
+ const running = list.filter((e) => e.status === "running");
169
+ const runningCount = running.length;
170
+ const costLabel = totalCost > 0 ? ` \xB7 $${totalCost.toFixed(3)}` : "";
171
+ const summaryLine = runningCount > 0 ? `${runningCount} running${costLabel}` : `idle${costLabel}`;
172
+ const shown = running.slice(0, 3);
173
+ const overflow = running.length > 3 ? running.length - 3 : 0;
174
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
175
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
176
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u26A1 Fleet" }),
177
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
178
+ /* @__PURE__ */ jsx(Text, { children: summaryLine })
179
+ ] }),
180
+ shown.map((entry) => {
181
+ const name = roster?.[entry.id]?.name ?? entry.name;
182
+ const tool = entry.currentTool?.name ?? "\u2014";
183
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
184
+ /* @__PURE__ */ jsx(Text, { color: "green", children: "\u25CF" }),
185
+ /* @__PURE__ */ jsx(Text, { children: name.slice(0, 12).padEnd(12) }),
186
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2192" }),
187
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: tool })
188
+ ] }, entry.id);
189
+ }),
190
+ overflow > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
191
+ " +",
192
+ overflow,
193
+ " more running"
194
+ ] }) : null
195
+ ] });
315
196
  }
316
197
  function StatusBar({
317
198
  model,
@@ -721,7 +602,7 @@ function fmtTokens(n) {
721
602
  if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
722
603
  return `${(n / 1e6).toFixed(1)}M`;
723
604
  }
724
- function fmtCost2(n) {
605
+ function fmtCost(n) {
725
606
  if (n === 0) return "\u2014";
726
607
  return `$${n.toFixed(3)}`;
727
608
  }
@@ -832,7 +713,7 @@ function FleetMonitor({
832
713
  /* @__PURE__ */ jsx(Text, { color: s2.color, children: e.status.padEnd(10) }),
833
714
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: `L${e.iterations} ${e.toolCalls}t`.padEnd(8) }),
834
715
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed.padEnd(8).slice(0, 8) }),
835
- /* @__PURE__ */ jsx(Text, { color: "yellow", children: fmtCost2(e.cost) }),
716
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: fmtCost(e.cost) }),
836
717
  e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
837
718
  " \u26A1\xD7",
838
719
  e.extensions
@@ -865,6 +746,20 @@ var STATUS2 = {
865
746
  function isTerminal(status) {
866
747
  return status === "success" || status === "failed" || status === "timeout" || status === "stopped";
867
748
  }
749
+ var IDLE_HIDE_MS = 6e4;
750
+ function selectLiveAgents(all, now, idleHideMs = IDLE_HIDE_MS) {
751
+ const visible = all.filter((e) => {
752
+ if (isTerminal(e.status)) return false;
753
+ if (e.status === "running") return true;
754
+ return now - e.lastEventAt < idleHideMs;
755
+ });
756
+ return visible.sort((a, b) => {
757
+ if (a.status === "running" && b.status !== "running") return -1;
758
+ if (a.status !== "running" && b.status === "running") return 1;
759
+ if (a.status === "running") return a.startedAt - b.startedAt;
760
+ return b.lastEventAt - a.lastEventAt;
761
+ });
762
+ }
868
763
  function fmtTokens2(n) {
869
764
  if (n < 1e3) return String(n);
870
765
  if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
@@ -882,15 +777,14 @@ function AgentsMonitor({
882
777
  nowTick
883
778
  }) {
884
779
  const all = Object.values(entries);
885
- const live = all.filter((e) => !isTerminal(e.status));
780
+ const live = selectLiveAgents(all, nowTick);
886
781
  const running = live.filter((e) => e.status === "running").length;
887
782
  const totalDone = all.filter((e) => e.status === "success").length;
888
783
  const totalFailed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
889
- const ordered = [...live].sort((a, b) => {
890
- if (a.status === "running" && b.status !== "running") return -1;
891
- if (a.status !== "running" && b.status === "running") return 1;
892
- return a.startedAt - b.startedAt;
893
- });
784
+ const hiddenIdle = all.filter(
785
+ (e) => e.status === "idle" && nowTick - e.lastEventAt >= IDLE_HIDE_MS
786
+ ).length;
787
+ const ordered = live;
894
788
  const shown = ordered.slice(0, 8);
895
789
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
896
790
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
@@ -927,7 +821,12 @@ function AgentsMonitor({
927
821
  /* @__PURE__ */ jsxs(Text, { color: "green", children: [
928
822
  "$",
929
823
  totalCost.toFixed(3)
930
- ] })
824
+ ] }),
825
+ hiddenIdle > 0 ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
826
+ "\xB7 ",
827
+ hiddenIdle,
828
+ " idle hidden"
829
+ ] }) : null
931
830
  ] }),
932
831
  shown.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No live agents \u2014 spawn with /spawn or /fleet dispatch." }) : null,
933
832
  shown.map((e) => {
@@ -1286,8 +1185,8 @@ function WorktreeMonitor({
1286
1185
  nowTick,
1287
1186
  onClose
1288
1187
  }) {
1289
- useInput((_, key) => {
1290
- if (key.escape) onClose();
1188
+ useInput((input, key) => {
1189
+ if (key.escape || key.ctrl && input === "w") onClose();
1291
1190
  });
1292
1191
  const list = Object.values(worktrees);
1293
1192
  const active = list.filter((w) => ["active", "committing", "merging"].includes(w.status)).length;
@@ -1607,7 +1506,7 @@ function ToolStreamBox({
1607
1506
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
1608
1507
  /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u25C6 " }),
1609
1508
  /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: name }),
1610
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration2(elapsedMs)}` }),
1509
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration(elapsedMs)}` }),
1611
1510
  hidden > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${MAX_STREAM_LINES})` }) : null
1612
1511
  ] }),
1613
1512
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [
@@ -1702,7 +1601,7 @@ function Entry({
1702
1601
  parts.push(`${entry.outputLines} L`);
1703
1602
  }
1704
1603
  if (entry.outputBytes && entry.outputBytes > 0) {
1705
- parts.push(fmtBytes2(entry.outputBytes));
1604
+ parts.push(fmtBytes(entry.outputBytes));
1706
1605
  }
1707
1606
  if (entry.outputTokens && entry.outputTokens > 0) {
1708
1607
  parts.push(`\u2248${fmtTok2(entry.outputTokens)} tok`);
@@ -1718,7 +1617,7 @@ function Entry({
1718
1617
  /* @__PURE__ */ jsx(Text, { children: " " }),
1719
1618
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: argSummary })
1720
1619
  ] }) : null,
1721
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${fmtDuration2(entry.durationMs)}` }),
1620
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${fmtDuration(entry.durationMs)}` }),
1722
1621
  sizeChip ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \xB7 ${sizeChip}` }) : null
1723
1622
  ] }),
1724
1623
  outLines.map((line, i) => (
@@ -1830,7 +1729,7 @@ function fmtTok2(n) {
1830
1729
  if (n >= 1e3) return `${(n / 1e3).toFixed(n >= 1e4 ? 0 : 1)}k`;
1831
1730
  return String(n);
1832
1731
  }
1833
- function fmtDuration2(ms) {
1732
+ function fmtDuration(ms) {
1834
1733
  if (ms < 1e3) return `${ms}ms`;
1835
1734
  if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
1836
1735
  const totalSec = Math.floor(ms / 1e3);
@@ -1958,7 +1857,7 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
1958
1857
  const bytes = numOf(o["bytes_written"]) ?? numOf(o["bytes"]);
1959
1858
  const created = o["created"] === true;
1960
1859
  const tag = created ? "created" : "updated";
1961
- if (bytes !== void 0) return [`${tag} \xB7 ${fmtBytes2(bytes)}`];
1860
+ if (bytes !== void 0) return [`${tag} \xB7 ${fmtBytes(bytes)}`];
1962
1861
  return [tag];
1963
1862
  }
1964
1863
  }
@@ -2023,17 +1922,17 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
2023
1922
  if (json && typeof json === "object") {
2024
1923
  const o = json;
2025
1924
  const bytes = numOf(o["bytes"]);
2026
- if (bytes !== void 0) return [`${fmtBytes2(bytes)} read`];
1925
+ if (bytes !== void 0) return [`${fmtBytes(bytes)} read`];
2027
1926
  }
2028
1927
  const range = scanNumberedRange(text);
2029
1928
  if (range.count > 0 && range.first !== void 0 && range.last !== void 0) {
2030
1929
  if (range.first === range.last) {
2031
- return [`L${range.first} \xB7 ${fmtBytes2(text.length)}`];
1930
+ return [`L${range.first} \xB7 ${fmtBytes(text.length)}`];
2032
1931
  }
2033
1932
  const contiguous = range.count === range.last - range.first + 1;
2034
1933
  const head = `L${range.first}\u2013${range.last}`;
2035
1934
  const tail = contiguous ? `${range.count} line${range.count === 1 ? "" : "s"}` : `${range.count} lines (gaps)`;
2036
- return [`${head} \xB7 ${tail} \xB7 ${fmtBytes2(text.length)}`];
1935
+ return [`${head} \xB7 ${tail} \xB7 ${fmtBytes(text.length)}`];
2037
1936
  }
2038
1937
  }
2039
1938
  if (toolName === "grep" || toolName === "glob") {
@@ -2091,7 +1990,7 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
2091
1990
  const head = [];
2092
1991
  if (status !== void 0) head.push(`HTTP ${status}`);
2093
1992
  if (ct) head.push(ct.split(";")[0] ?? ct);
2094
- if (content) head.push(fmtBytes2(Buffer.byteLength(content, "utf8")));
1993
+ if (content) head.push(fmtBytes(Buffer.byteLength(content, "utf8")));
2095
1994
  const lines = [];
2096
1995
  if (head.length > 0) lines.push(head.join(" \xB7 "));
2097
1996
  if (url && status !== void 0 && (status < 200 || status >= 400)) {
@@ -2182,7 +2081,7 @@ function formatToolOutput(toolName, output, ok, _outputBytes, outputLines) {
2182
2081
  if (runner && runner !== "none") head.push(runner);
2183
2082
  head.push(`${passed}/${total} passed`);
2184
2083
  if (failed > 0) head.push(`${failed} failed`);
2185
- if (duration !== void 0) head.push(fmtDuration2(duration));
2084
+ if (duration !== void 0) head.push(fmtDuration(duration));
2186
2085
  return [head.join(" \xB7 ")];
2187
2086
  }
2188
2087
  }
@@ -2467,7 +2366,7 @@ function countLines(text) {
2467
2366
  if (!text) return 0;
2468
2367
  return text.replace(/\n$/, "").split("\n").length;
2469
2368
  }
2470
- function fmtBytes2(n) {
2369
+ function fmtBytes(n) {
2471
2370
  if (n < 1024) return `${n}B`;
2472
2371
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
2473
2372
  return `${(n / (1024 * 1024)).toFixed(1)}MB`;
@@ -2555,20 +2454,20 @@ function fmtElapsed6(ms) {
2555
2454
  const s2 = Math.floor(ms % 6e4 / 1e3);
2556
2455
  return `${m}m${s2.toString().padStart(2, "0")}s`;
2557
2456
  }
2558
- function fmtBytes3(n) {
2457
+ function fmtBytes2(n) {
2559
2458
  if (n < 1024) return `${n}B`;
2560
2459
  return `${(n / 1024).toFixed(1)}KB`;
2561
2460
  }
2562
- function fmtRecentTool2(tool) {
2461
+ function fmtRecentTool(tool) {
2563
2462
  const status = tool.ok === false ? "fail" : "ok";
2564
2463
  const name = tool.name.length > 18 ? `${tool.name.slice(0, 17)}...` : tool.name;
2565
2464
  const parts = [status, name];
2566
2465
  if (typeof tool.durationMs === "number") parts.push(fmtElapsed6(tool.durationMs));
2567
- if (typeof tool.outputBytes === "number" && tool.outputBytes > 0) parts.push(fmtBytes3(tool.outputBytes));
2466
+ if (typeof tool.outputBytes === "number" && tool.outputBytes > 0) parts.push(fmtBytes2(tool.outputBytes));
2568
2467
  if (typeof tool.outputLines === "number" && tool.outputLines > 0) parts.push(`${tool.outputLines}L`);
2569
2468
  return parts.join(" ");
2570
2469
  }
2571
- function fmtRecentMessage2(message) {
2470
+ function fmtRecentMessage(message) {
2572
2471
  const text = message.text.replace(/\s+/g, " ");
2573
2472
  return text.length > 48 ? `${text.slice(0, 47)}...` : text;
2574
2473
  }
@@ -2585,8 +2484,8 @@ function LiveActivityStrip({
2585
2484
  const toolElapsed = e.currentTool ? now - e.currentTool.startedAt : 0;
2586
2485
  const taskElapsed = now - e.startedAt;
2587
2486
  const toolSeg = e.currentTool ? `\u2192 ${e.currentTool.name} (${fmtElapsed6(toolElapsed)})` : "idle between tools";
2588
- const recentTools = (e.recentTools ?? []).slice(-2).map(fmtRecentTool2).join(" | ");
2589
- const messageText = e.streamingText.trim() || (e.recentMessages ?? []).slice(-1).map(fmtRecentMessage2).join("");
2487
+ const recentTools = (e.recentTools ?? []).slice(-2).map(fmtRecentTool).join(" | ");
2488
+ const messageText = e.streamingText.trim() || (e.recentMessages ?? []).slice(-1).map(fmtRecentMessage).join("");
2590
2489
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
2591
2490
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25CF" }),
2592
2491
  /* @__PURE__ */ jsx(Text, { children: e.name.slice(0, 14).padEnd(14) }),
@@ -2611,7 +2510,7 @@ function LiveActivityStrip({
2611
2510
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
2612
2511
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2613
2512
  "msg: ",
2614
- fmtRecentMessage2({ text: messageText})
2513
+ fmtRecentMessage({ text: messageText})
2615
2514
  ] })
2616
2515
  ] }) : null
2617
2516
  ] }, e.id);
@@ -3879,10 +3778,10 @@ function App({
3879
3778
  const handleRewindTo = React2.useCallback(async (checkpointIndex) => {
3880
3779
  const sessionId = agent.ctx.session.id;
3881
3780
  if (!sessionId) return;
3882
- const rewinder = new DefaultSessionRewinder(sessionsDir ?? "");
3781
+ const rewinder = new DefaultSessionRewinder(sessionsDir ?? "", projectRoot ?? agent.ctx.cwd);
3883
3782
  await rewinder.rewindToCheckpoint(sessionId, checkpointIndex);
3884
3783
  await agent.ctx.session.truncateToCheckpoint(checkpointIndex);
3885
- }, [agent.ctx.session, sessionsDir]);
3784
+ }, [agent.ctx.session, sessionsDir, projectRoot, agent.ctx.cwd]);
3886
3785
  const setDraft = (buffer, cursor) => {
3887
3786
  draftRef.current = { buffer, cursor };
3888
3787
  dispatch({ type: "setBuffer", buffer, cursor });
@@ -5537,6 +5436,10 @@ function App({
5537
5436
  return;
5538
5437
  }
5539
5438
  if (key.ctrl && input === "w") {
5439
+ if (state.worktreeMonitorOpen) {
5440
+ dispatch({ type: "worktreeMonitorToggle" });
5441
+ return;
5442
+ }
5540
5443
  if (cursor === 0) return;
5541
5444
  const beforeCursor = buffer.slice(0, cursor);
5542
5445
  const lastWordStart = beforeCursor.lastIndexOf(" ") + 1;