sisyphi 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -1,28 +1,135 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ EXEC_ENV,
4
+ augmentedPath,
5
+ exec,
6
+ execSafe,
3
7
  loadConfig
4
- } from "./chunk-KQBSC5KY.js";
8
+ } from "./chunk-LWWRGQWM.js";
5
9
  import {
6
10
  buildSessionContext,
7
11
  computeActiveTimeMs,
8
- resolveReports
9
- } from "./chunk-DBR33QHM.js";
12
+ formatDuration,
13
+ rawSend,
14
+ resolveReports,
15
+ statusColor
16
+ } from "./chunk-T7ETTIQK.js";
10
17
  import {
18
+ shellQuote
19
+ } from "./chunk-6G226ZK7.js";
20
+ import {
21
+ __commonJS,
22
+ __toESM,
11
23
  contextDir,
12
24
  globalDir,
13
25
  goalPath,
14
26
  logsDir,
15
27
  roadmapPath,
16
- sessionDir,
17
- socketPath
18
- } from "./chunk-YGBGKMTF.js";
28
+ sessionDir
29
+ } from "./chunk-JXKUI4P6.js";
30
+
31
+ // node_modules/eastasianwidth/eastasianwidth.js
32
+ var require_eastasianwidth = __commonJS({
33
+ "node_modules/eastasianwidth/eastasianwidth.js"(exports, module) {
34
+ "use strict";
35
+ var eaw = {};
36
+ if ("undefined" == typeof module) {
37
+ window.eastasianwidth = eaw;
38
+ } else {
39
+ module.exports = eaw;
40
+ }
41
+ eaw.eastAsianWidth = function(character) {
42
+ var x = character.charCodeAt(0);
43
+ var y = character.length == 2 ? character.charCodeAt(1) : 0;
44
+ var codePoint = x;
45
+ if (55296 <= x && x <= 56319 && (56320 <= y && y <= 57343)) {
46
+ x &= 1023;
47
+ y &= 1023;
48
+ codePoint = x << 10 | y;
49
+ codePoint += 65536;
50
+ }
51
+ if (12288 == codePoint || 65281 <= codePoint && codePoint <= 65376 || 65504 <= codePoint && codePoint <= 65510) {
52
+ return "F";
53
+ }
54
+ if (8361 == codePoint || 65377 <= codePoint && codePoint <= 65470 || 65474 <= codePoint && codePoint <= 65479 || 65482 <= codePoint && codePoint <= 65487 || 65490 <= codePoint && codePoint <= 65495 || 65498 <= codePoint && codePoint <= 65500 || 65512 <= codePoint && codePoint <= 65518) {
55
+ return "H";
56
+ }
57
+ if (4352 <= codePoint && codePoint <= 4447 || 4515 <= codePoint && codePoint <= 4519 || 4602 <= codePoint && codePoint <= 4607 || 9001 <= codePoint && codePoint <= 9002 || 11904 <= codePoint && codePoint <= 11929 || 11931 <= codePoint && codePoint <= 12019 || 12032 <= codePoint && codePoint <= 12245 || 12272 <= codePoint && codePoint <= 12283 || 12289 <= codePoint && codePoint <= 12350 || 12353 <= codePoint && codePoint <= 12438 || 12441 <= codePoint && codePoint <= 12543 || 12549 <= codePoint && codePoint <= 12589 || 12593 <= codePoint && codePoint <= 12686 || 12688 <= codePoint && codePoint <= 12730 || 12736 <= codePoint && codePoint <= 12771 || 12784 <= codePoint && codePoint <= 12830 || 12832 <= codePoint && codePoint <= 12871 || 12880 <= codePoint && codePoint <= 13054 || 13056 <= codePoint && codePoint <= 19903 || 19968 <= codePoint && codePoint <= 42124 || 42128 <= codePoint && codePoint <= 42182 || 43360 <= codePoint && codePoint <= 43388 || 44032 <= codePoint && codePoint <= 55203 || 55216 <= codePoint && codePoint <= 55238 || 55243 <= codePoint && codePoint <= 55291 || 63744 <= codePoint && codePoint <= 64255 || 65040 <= codePoint && codePoint <= 65049 || 65072 <= codePoint && codePoint <= 65106 || 65108 <= codePoint && codePoint <= 65126 || 65128 <= codePoint && codePoint <= 65131 || 110592 <= codePoint && codePoint <= 110593 || 127488 <= codePoint && codePoint <= 127490 || 127504 <= codePoint && codePoint <= 127546 || 127552 <= codePoint && codePoint <= 127560 || 127568 <= codePoint && codePoint <= 127569 || 131072 <= codePoint && codePoint <= 194367 || 177984 <= codePoint && codePoint <= 196605 || 196608 <= codePoint && codePoint <= 262141) {
58
+ return "W";
59
+ }
60
+ if (32 <= codePoint && codePoint <= 126 || 162 <= codePoint && codePoint <= 163 || 165 <= codePoint && codePoint <= 166 || 172 == codePoint || 175 == codePoint || 10214 <= codePoint && codePoint <= 10221 || 10629 <= codePoint && codePoint <= 10630) {
61
+ return "Na";
62
+ }
63
+ if (161 == codePoint || 164 == codePoint || 167 <= codePoint && codePoint <= 168 || 170 == codePoint || 173 <= codePoint && codePoint <= 174 || 176 <= codePoint && codePoint <= 180 || 182 <= codePoint && codePoint <= 186 || 188 <= codePoint && codePoint <= 191 || 198 == codePoint || 208 == codePoint || 215 <= codePoint && codePoint <= 216 || 222 <= codePoint && codePoint <= 225 || 230 == codePoint || 232 <= codePoint && codePoint <= 234 || 236 <= codePoint && codePoint <= 237 || 240 == codePoint || 242 <= codePoint && codePoint <= 243 || 247 <= codePoint && codePoint <= 250 || 252 == codePoint || 254 == codePoint || 257 == codePoint || 273 == codePoint || 275 == codePoint || 283 == codePoint || 294 <= codePoint && codePoint <= 295 || 299 == codePoint || 305 <= codePoint && codePoint <= 307 || 312 == codePoint || 319 <= codePoint && codePoint <= 322 || 324 == codePoint || 328 <= codePoint && codePoint <= 331 || 333 == codePoint || 338 <= codePoint && codePoint <= 339 || 358 <= codePoint && codePoint <= 359 || 363 == codePoint || 462 == codePoint || 464 == codePoint || 466 == codePoint || 468 == codePoint || 470 == codePoint || 472 == codePoint || 474 == codePoint || 476 == codePoint || 593 == codePoint || 609 == codePoint || 708 == codePoint || 711 == codePoint || 713 <= codePoint && codePoint <= 715 || 717 == codePoint || 720 == codePoint || 728 <= codePoint && codePoint <= 731 || 733 == codePoint || 735 == codePoint || 768 <= codePoint && codePoint <= 879 || 913 <= codePoint && codePoint <= 929 || 931 <= codePoint && codePoint <= 937 || 945 <= codePoint && codePoint <= 961 || 963 <= codePoint && codePoint <= 969 || 1025 == codePoint || 1040 <= codePoint && codePoint <= 1103 || 1105 == codePoint || 8208 == codePoint || 8211 <= codePoint && codePoint <= 8214 || 8216 <= codePoint && codePoint <= 8217 || 8220 <= codePoint && codePoint <= 8221 || 8224 <= codePoint && codePoint <= 8226 || 8228 <= codePoint && codePoint <= 8231 || 8240 == codePoint || 8242 <= codePoint && codePoint <= 8243 || 8245 == codePoint || 8251 == codePoint || 8254 == codePoint || 8308 == codePoint || 8319 == codePoint || 8321 <= codePoint && codePoint <= 8324 || 8364 == codePoint || 8451 == codePoint || 8453 == codePoint || 8457 == codePoint || 8467 == codePoint || 8470 == codePoint || 8481 <= codePoint && codePoint <= 8482 || 8486 == codePoint || 8491 == codePoint || 8531 <= codePoint && codePoint <= 8532 || 8539 <= codePoint && codePoint <= 8542 || 8544 <= codePoint && codePoint <= 8555 || 8560 <= codePoint && codePoint <= 8569 || 8585 == codePoint || 8592 <= codePoint && codePoint <= 8601 || 8632 <= codePoint && codePoint <= 8633 || 8658 == codePoint || 8660 == codePoint || 8679 == codePoint || 8704 == codePoint || 8706 <= codePoint && codePoint <= 8707 || 8711 <= codePoint && codePoint <= 8712 || 8715 == codePoint || 8719 == codePoint || 8721 == codePoint || 8725 == codePoint || 8730 == codePoint || 8733 <= codePoint && codePoint <= 8736 || 8739 == codePoint || 8741 == codePoint || 8743 <= codePoint && codePoint <= 8748 || 8750 == codePoint || 8756 <= codePoint && codePoint <= 8759 || 8764 <= codePoint && codePoint <= 8765 || 8776 == codePoint || 8780 == codePoint || 8786 == codePoint || 8800 <= codePoint && codePoint <= 8801 || 8804 <= codePoint && codePoint <= 8807 || 8810 <= codePoint && codePoint <= 8811 || 8814 <= codePoint && codePoint <= 8815 || 8834 <= codePoint && codePoint <= 8835 || 8838 <= codePoint && codePoint <= 8839 || 8853 == codePoint || 8857 == codePoint || 8869 == codePoint || 8895 == codePoint || 8978 == codePoint || 9312 <= codePoint && codePoint <= 9449 || 9451 <= codePoint && codePoint <= 9547 || 9552 <= codePoint && codePoint <= 9587 || 9600 <= codePoint && codePoint <= 9615 || 9618 <= codePoint && codePoint <= 9621 || 9632 <= codePoint && codePoint <= 9633 || 9635 <= codePoint && codePoint <= 9641 || 9650 <= codePoint && codePoint <= 9651 || 9654 <= codePoint && codePoint <= 9655 || 9660 <= codePoint && codePoint <= 9661 || 9664 <= codePoint && codePoint <= 9665 || 9670 <= codePoint && codePoint <= 9672 || 9675 == codePoint || 9678 <= codePoint && codePoint <= 9681 || 9698 <= codePoint && codePoint <= 9701 || 9711 == codePoint || 9733 <= codePoint && codePoint <= 9734 || 9737 == codePoint || 9742 <= codePoint && codePoint <= 9743 || 9748 <= codePoint && codePoint <= 9749 || 9756 == codePoint || 9758 == codePoint || 9792 == codePoint || 9794 == codePoint || 9824 <= codePoint && codePoint <= 9825 || 9827 <= codePoint && codePoint <= 9829 || 9831 <= codePoint && codePoint <= 9834 || 9836 <= codePoint && codePoint <= 9837 || 9839 == codePoint || 9886 <= codePoint && codePoint <= 9887 || 9918 <= codePoint && codePoint <= 9919 || 9924 <= codePoint && codePoint <= 9933 || 9935 <= codePoint && codePoint <= 9953 || 9955 == codePoint || 9960 <= codePoint && codePoint <= 9983 || 10045 == codePoint || 10071 == codePoint || 10102 <= codePoint && codePoint <= 10111 || 11093 <= codePoint && codePoint <= 11097 || 12872 <= codePoint && codePoint <= 12879 || 57344 <= codePoint && codePoint <= 63743 || 65024 <= codePoint && codePoint <= 65039 || 65533 == codePoint || 127232 <= codePoint && codePoint <= 127242 || 127248 <= codePoint && codePoint <= 127277 || 127280 <= codePoint && codePoint <= 127337 || 127344 <= codePoint && codePoint <= 127386 || 917760 <= codePoint && codePoint <= 917999 || 983040 <= codePoint && codePoint <= 1048573 || 1048576 <= codePoint && codePoint <= 1114109) {
64
+ return "A";
65
+ }
66
+ return "N";
67
+ };
68
+ eaw.characterLength = function(character) {
69
+ var code = this.eastAsianWidth(character);
70
+ if (code == "F" || code == "W" || code == "A") {
71
+ return 2;
72
+ } else {
73
+ return 1;
74
+ }
75
+ };
76
+ function stringToArray(string) {
77
+ return string.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
78
+ }
79
+ eaw.length = function(string) {
80
+ var characters = stringToArray(string);
81
+ var len = 0;
82
+ for (var i = 0; i < characters.length; i++) {
83
+ len = len + this.characterLength(characters[i]);
84
+ }
85
+ return len;
86
+ };
87
+ eaw.slice = function(text, start, end) {
88
+ textLen = eaw.length(text);
89
+ start = start ? start : 0;
90
+ end = end ? end : 1;
91
+ if (start < 0) {
92
+ start = textLen + start;
93
+ }
94
+ if (end < 0) {
95
+ end = textLen + end;
96
+ }
97
+ var result = "";
98
+ var eawLen = 0;
99
+ var chars = stringToArray(text);
100
+ for (var i = 0; i < chars.length; i++) {
101
+ var char = chars[i];
102
+ var charLen = eaw.length(char);
103
+ if (eawLen >= start - (charLen == 2 ? 1 : 0)) {
104
+ if (eawLen + charLen <= end) {
105
+ result += char;
106
+ } else {
107
+ break;
108
+ }
109
+ }
110
+ eawLen += charLen;
111
+ }
112
+ return result;
113
+ };
114
+ }
115
+ });
116
+
117
+ // node_modules/emoji-regex/index.js
118
+ var require_emoji_regex = __commonJS({
119
+ "node_modules/emoji-regex/index.js"(exports, module) {
120
+ "use strict";
121
+ module.exports = function() {
122
+ return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
123
+ };
124
+ }
125
+ });
19
126
 
20
127
  // src/tui/index.tsx
21
128
  import { render } from "ink";
22
129
 
23
130
  // src/tui/App.tsx
24
- import { useState as useState4, useEffect as useEffect3, useCallback as useCallback2, useMemo as useMemo4, useRef as useRef3 } from "react";
25
- import { Box as Box13, Text as Text13, useApp, useStdout } from "ink";
131
+ import { useState as useState4, useEffect as useEffect3, useCallback as useCallback2, useMemo as useMemo6, useRef as useRef3 } from "react";
132
+ import { Box as Box11, Text as Text11, useApp, useStdout } from "ink";
26
133
 
27
134
  // src/tui/components/SessionTree.tsx
28
135
  import { Box, Text } from "ink";
@@ -62,25 +169,70 @@ function isAncestorLastSibling(nodes, index, depth) {
62
169
  return true;
63
170
  }
64
171
 
65
- // src/tui/lib/format.ts
66
- function formatDuration(startOrMs, endIso) {
67
- let totalMs;
68
- if (typeof startOrMs === "number") {
69
- totalMs = startOrMs;
70
- } else {
71
- const start = new Date(startOrMs).getTime();
72
- const end = endIso ? new Date(endIso).getTime() : Date.now();
73
- totalMs = end - start;
172
+ // node_modules/ansi-regex/index.js
173
+ function ansiRegex({ onlyFirst = false } = {}) {
174
+ const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
175
+ const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`;
176
+ const csi = "[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]";
177
+ const pattern = `${osc}|${csi}`;
178
+ return new RegExp(pattern, onlyFirst ? void 0 : "g");
179
+ }
180
+
181
+ // node_modules/strip-ansi/index.js
182
+ var regex = ansiRegex();
183
+ function stripAnsi(string) {
184
+ if (typeof string !== "string") {
185
+ throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
186
+ }
187
+ if (!string.includes("\x1B") && !string.includes("\x9B")) {
188
+ return string;
189
+ }
190
+ return string.replace(regex, "");
191
+ }
192
+
193
+ // node_modules/string-width/index.js
194
+ var import_eastasianwidth = __toESM(require_eastasianwidth(), 1);
195
+ var import_emoji_regex = __toESM(require_emoji_regex(), 1);
196
+ function stringWidth(string, options = {}) {
197
+ if (typeof string !== "string" || string.length === 0) {
198
+ return 0;
199
+ }
200
+ options = {
201
+ ambiguousIsNarrow: true,
202
+ ...options
203
+ };
204
+ string = stripAnsi(string);
205
+ if (string.length === 0) {
206
+ return 0;
207
+ }
208
+ string = string.replace((0, import_emoji_regex.default)(), " ");
209
+ const ambiguousCharacterWidth = options.ambiguousIsNarrow ? 1 : 2;
210
+ let width = 0;
211
+ for (const character of string) {
212
+ const codePoint = character.codePointAt(0);
213
+ if (codePoint <= 31 || codePoint >= 127 && codePoint <= 159) {
214
+ continue;
215
+ }
216
+ if (codePoint >= 768 && codePoint <= 879) {
217
+ continue;
218
+ }
219
+ const code = import_eastasianwidth.default.eastAsianWidth(character);
220
+ switch (code) {
221
+ case "F":
222
+ case "W":
223
+ width += 2;
224
+ break;
225
+ case "A":
226
+ width += ambiguousCharacterWidth;
227
+ break;
228
+ default:
229
+ width += 1;
230
+ }
74
231
  }
75
- const totalSeconds = Math.floor(totalMs / 1e3);
76
- if (totalSeconds < 0) return "0s";
77
- const hours = Math.floor(totalSeconds / 3600);
78
- const minutes = Math.floor(totalSeconds % 3600 / 60);
79
- const seconds = totalSeconds % 60;
80
- if (hours > 0) return `${hours}h${minutes}m`;
81
- if (minutes > 0) return `${minutes}m${seconds}s`;
82
- return `${seconds}s`;
232
+ return width;
83
233
  }
234
+
235
+ // src/tui/lib/format.ts
84
236
  function formatTimeAgo(iso) {
85
237
  const diff = Date.now() - new Date(iso).getTime();
86
238
  const minutes = Math.floor(diff / 6e4);
@@ -94,11 +246,20 @@ function formatTime(iso) {
94
246
  return `${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}`;
95
247
  }
96
248
  function truncate(text, max) {
97
- if (max < 4) return text.slice(0, max);
98
- if (text.length <= max) return text;
99
- const cut = text.lastIndexOf(" ", max - 1);
100
- const breakAt = cut > max * 0.6 ? cut : max - 1;
101
- return text.slice(0, breakAt) + "\u2026";
249
+ const clean = text.replace(/\n/g, " ").replace(/✅/g, "\u2713").replace(/❌/g, "\u2717").replace(new RegExp("\\p{Emoji_Presentation}", "gu"), "");
250
+ if (max < 4) return clean.slice(0, max);
251
+ const w = stringWidth(clean);
252
+ if (w <= max) return clean;
253
+ let result = clean;
254
+ while (stringWidth(result) > max - 1 && result.length > 0) {
255
+ const cut = result.lastIndexOf(" ", result.length - 2);
256
+ if (cut > max * 0.4) {
257
+ result = result.slice(0, cut);
258
+ } else {
259
+ result = result.slice(0, result.length - 1);
260
+ }
261
+ }
262
+ return result + "\u2026";
102
263
  }
103
264
  function stripMarkdown(text) {
104
265
  return text.replace(/^#{1,6}\s+/gm, "").replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/~~(.+?)~~/g, "$1").replace(/`{1,3}[^`]*`{1,3}/g, "").replace(/^[-*+]\s+/gm, "").replace(/^\d+[.)]\s+/gm, "").replace(/\[(.+?)\]\(.+?\)/g, "$1").replace(/^>\s+/gm, "").replace(/---+/g, "").replace(/\n+/g, " ").replace(/\s+/g, " ").trim();
@@ -137,24 +298,6 @@ function durationColor(startOrMs, endIso) {
137
298
  if (totalMs < 30 * 60 * 1e3) return "yellow";
138
299
  return "red";
139
300
  }
140
- function statusColor(status) {
141
- switch (status) {
142
- case "active":
143
- case "running":
144
- return "green";
145
- case "completed":
146
- return "cyan";
147
- case "paused":
148
- return "yellow";
149
- case "killed":
150
- case "crashed":
151
- return "red";
152
- case "lost":
153
- return "gray";
154
- default:
155
- return "white";
156
- }
157
- }
158
301
  function statusIndicator(status) {
159
302
  switch (status) {
160
303
  case "active":
@@ -202,20 +345,42 @@ function stripFrontmatter(content) {
202
345
  return content.slice(end + 4).trimStart();
203
346
  }
204
347
  function cleanMarkdown(line) {
205
- return line.replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/~~(.+?)~~/g, "$1").replace(/`(.+?)`/g, "$1").replace(/\[(.+?)\]\(.+?\)/g, "$1");
348
+ return line.replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/~~(.+?)~~/g, "$1").replace(/`(.+?)`/g, "$1").replace(/\[(.+?)\]\(.+?\)/g, "$1").replace(/✅/g, "\u2713").replace(/❌/g, "\u2717").replace(new RegExp("\\p{Emoji_Presentation}", "gu"), "");
349
+ }
350
+ function seg(text, opts) {
351
+ return { text, ...opts };
352
+ }
353
+ function singleLine(text, opts) {
354
+ return [seg(text, opts)];
206
355
  }
207
356
  function wrapText(text, width) {
208
357
  if (width <= 0) return text.split("\n");
209
358
  const result = [];
210
359
  for (const rawLine of text.split("\n")) {
211
- if (rawLine.length <= width) {
360
+ if (stringWidth(rawLine) <= width) {
212
361
  result.push(rawLine);
213
362
  continue;
214
363
  }
215
364
  let remaining = rawLine;
216
- while (remaining.length > width) {
217
- let breakAt = remaining.lastIndexOf(" ", width);
218
- if (breakAt <= 0) breakAt = width;
365
+ while (stringWidth(remaining) > width) {
366
+ let breakAt = -1;
367
+ let estimate = Math.min(remaining.length, width);
368
+ for (let i = estimate; i >= 0; i--) {
369
+ if (remaining[i] === " " && stringWidth(remaining.slice(0, i)) <= width) {
370
+ breakAt = i;
371
+ break;
372
+ }
373
+ }
374
+ if (breakAt <= 0) {
375
+ breakAt = remaining.length;
376
+ for (let i = 1; i <= remaining.length; i++) {
377
+ if (stringWidth(remaining.slice(0, i)) > width) {
378
+ breakAt = i - 1;
379
+ break;
380
+ }
381
+ }
382
+ if (breakAt <= 0) breakAt = 1;
383
+ }
219
384
  result.push(remaining.slice(0, breakAt));
220
385
  remaining = remaining.slice(breakAt).trimStart();
221
386
  }
@@ -239,12 +404,13 @@ function SessionTree({ nodes, cursorIndex, width, height, focused }) {
239
404
  children: [
240
405
  /* @__PURE__ */ jsx(Text, { bold: true, children: " Sessions " }),
241
406
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No sessions found." }),
242
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press [n] to create one." })
407
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press [n] to create one." }),
408
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press [?] for all keybindings." })
243
409
  ]
244
410
  }
245
411
  );
246
412
  }
247
- const maxVisible = Math.max(1, height - 3);
413
+ const maxVisible = Math.max(1, height - 4);
248
414
  const halfVisible = Math.floor(maxVisible / 2);
249
415
  const scrollOffset = Math.max(
250
416
  0,
@@ -375,20 +541,22 @@ function renderNodeContent(node, maxWidth) {
375
541
  color: "white",
376
542
  dim: node.fileCount === 0
377
543
  };
378
- case "context-file":
544
+ case "context-file": {
545
+ const maxLabel = Math.max(8, maxWidth - 4);
379
546
  return {
380
547
  icon: "\xB7",
381
- label: node.label,
548
+ label: truncate(node.label, maxLabel),
382
549
  meta: "",
383
550
  color: "gray",
384
551
  dim: false
385
552
  };
553
+ }
386
554
  }
387
555
  }
388
556
 
389
557
  // src/tui/components/SessionDetail.tsx
390
558
  import { useMemo } from "react";
391
- import { Box as Box3, Text as Text3 } from "ink";
559
+ import { Box as Box4, Text as Text4 } from "ink";
392
560
 
393
561
  // src/tui/components/PlanView.tsx
394
562
  import { Box as Box2, Text as Text2 } from "ink";
@@ -468,15 +636,53 @@ function buildPlanLines(content, maxLines, width) {
468
636
  return lines;
469
637
  }
470
638
 
471
- // src/tui/components/SessionDetail.tsx
639
+ // src/tui/components/ScrollablePanel.tsx
640
+ import { Box as Box3, Text as Text3 } from "ink";
472
641
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
473
- function seg(text, opts) {
474
- return { text, ...opts };
475
- }
476
- function simple(text, opts) {
477
- return [seg(text, opts)];
642
+ function ScrollablePanel({
643
+ lines,
644
+ width,
645
+ height,
646
+ scrollOffset = 0,
647
+ focused = false,
648
+ borderColor = "gray"
649
+ }) {
650
+ const innerHeight = height - 2;
651
+ const hasOverflow = lines.length > innerHeight;
652
+ const viewableHeight = hasOverflow ? innerHeight - 1 : innerHeight;
653
+ const maxScroll = Math.max(0, lines.length - viewableHeight);
654
+ const effectiveOffset = Math.min(scrollOffset, maxScroll);
655
+ const visible = lines.slice(effectiveOffset, effectiveOffset + viewableHeight);
656
+ const padCount = Math.max(0, viewableHeight - visible.length);
657
+ const scrollPct = maxScroll > 0 ? Math.round(effectiveOffset / maxScroll * 100) : 100;
658
+ return /* @__PURE__ */ jsxs2(
659
+ Box3,
660
+ {
661
+ flexDirection: "column",
662
+ width,
663
+ overflow: "hidden",
664
+ borderStyle: "round",
665
+ borderColor: focused ? "blue" : borderColor,
666
+ paddingX: 1,
667
+ children: [
668
+ visible.map((segs, i) => /* @__PURE__ */ jsx3(Text3, { children: segs.map((s, j) => /* @__PURE__ */ jsx3(Text3, { color: s.color, bold: s.bold, dimColor: s.dim, italic: s.italic, children: s.text }, j)) }, i)),
669
+ padCount > 0 && Array.from({ length: padCount }, (_, i) => /* @__PURE__ */ jsx3(Text3, { children: " " }, `p${i}`)),
670
+ hasOverflow && /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
671
+ " ",
672
+ "\u2195 ",
673
+ scrollPct,
674
+ "% \xB7 ",
675
+ lines.length,
676
+ " lines"
677
+ ] })
678
+ ]
679
+ }
680
+ );
478
681
  }
479
- function buildLines(session, planContent, goalContent, logsContent, width, paneAlive) {
682
+
683
+ // src/tui/components/SessionDetail.tsx
684
+ import { jsx as jsx4 } from "react/jsx-runtime";
685
+ function buildLines(session, planContent, goalContent, _logsContent, width, paneAlive) {
480
686
  const lines = [];
481
687
  const contentWidth = width - 4;
482
688
  const agents = session.agents ?? [];
@@ -486,7 +692,7 @@ function buildLines(session, planContent, goalContent, logsContent, width, paneA
486
692
  const conflicts = agents.filter((a) => a.mergeStatus === "conflict");
487
693
  const goalText = goalContent ? cleanMarkdown(stripFrontmatter(goalContent).trim()) : session.task;
488
694
  goalText.split("\n").flatMap((l) => wrapText(l, contentWidth - 2)).forEach((line, i) => {
489
- lines.push(simple(`${i === 0 ? " " : " "}${line}`, { bold: true }));
695
+ lines.push(singleLine(`${i === 0 ? " " : " "}${line}`, { bold: true }));
490
696
  });
491
697
  const lastCycle = cycles.length > 0 ? cycles[cycles.length - 1] : null;
492
698
  const cycleNum = lastCycle?.cycle ?? 0;
@@ -519,34 +725,40 @@ function buildLines(session, planContent, goalContent, logsContent, width, paneA
519
725
  }
520
726
  if (conflicts.length > 0) {
521
727
  lines.push(
522
- simple(
728
+ singleLine(
523
729
  ` \u26A0 ${conflicts.length} merge conflict${conflicts.length > 1 ? "s" : ""}`,
524
730
  { color: "red", bold: true }
525
731
  )
526
732
  );
733
+ lines.push(
734
+ singleLine(
735
+ " resolve in worktree, then [x] restart agent",
736
+ { color: "red", dim: true }
737
+ )
738
+ );
527
739
  }
528
- lines.push(simple(" "));
740
+ lines.push(singleLine(" "));
529
741
  lines.push([
530
742
  seg(" \u258E \u25C8 PLAN", { color: "yellow", bold: true })
531
743
  ]);
532
744
  const planLines = buildPlanLines(planContent, 99999, width);
533
745
  if (planLines.length === 0) {
534
- lines.push(simple(" orchestrator will create one", { dim: true, italic: true }));
746
+ lines.push(singleLine(" orchestrator will create one", { dim: true, italic: true }));
535
747
  } else {
536
748
  for (const pl of planLines) {
537
- lines.push(simple(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));
749
+ lines.push(singleLine(pl.text, { bold: pl.bold, dim: pl.dim, color: pl.color }));
538
750
  }
539
751
  }
540
752
  if (session.status === "completed" && session.completionReport) {
541
- lines.push(simple(" "));
753
+ lines.push(singleLine(" "));
542
754
  lines.push([seg(" \u258E \u2713 COMPLETION", { color: "cyan", bold: true })]);
543
755
  wrapText(cleanMarkdown(session.completionReport), contentWidth - 6).forEach(
544
756
  (l) => {
545
- lines.push(simple(` ${l}`, { dim: true }));
757
+ lines.push(singleLine(` ${l}`, { dim: true }));
546
758
  }
547
759
  );
548
760
  }
549
- lines.push(simple(" "));
761
+ lines.push(singleLine(" "));
550
762
  lines.push([
551
763
  seg(" \u258E \u27F3 CYCLES", { color: "blue", bold: true }),
552
764
  seg(` (${cycles.length})`, { dim: true })
@@ -564,7 +776,7 @@ function buildLines(session, planContent, goalContent, logsContent, width, paneA
564
776
  ]);
565
777
  };
566
778
  if (cycles.length === 0) {
567
- lines.push(simple(" waiting for orchestrator\u2026", { dim: true, italic: true }));
779
+ lines.push(singleLine(" waiting for orchestrator\u2026", { dim: true, italic: true }));
568
780
  } else {
569
781
  const sortedMsgs = [...messages].sort(
570
782
  (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
@@ -646,8 +858,8 @@ function SessionDetail({
646
858
  focused = false
647
859
  }) {
648
860
  if (!session) {
649
- return /* @__PURE__ */ jsx3(
650
- Box3,
861
+ return /* @__PURE__ */ jsx4(
862
+ Box4,
651
863
  {
652
864
  flexDirection: "column",
653
865
  width,
@@ -656,7 +868,7 @@ function SessionDetail({
656
868
  paddingX: 1,
657
869
  justifyContent: "center",
658
870
  alignItems: "center",
659
- children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Select a session to view details" })
871
+ children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Select a session to view details" })
660
872
  }
661
873
  );
662
874
  }
@@ -664,55 +876,22 @@ function SessionDetail({
664
876
  () => buildLines(session, planContent, goalContent, logsContent, width, paneAlive),
665
877
  [session, planContent, goalContent, logsContent, width, paneAlive]
666
878
  );
667
- const innerHeight = height - 2;
668
- const hasOverflow = allLines.length > innerHeight;
669
- const viewableHeight = hasOverflow ? innerHeight - 1 : innerHeight;
670
- const maxScroll = Math.max(0, allLines.length - viewableHeight);
671
- const effectiveOffset = Math.min(scrollOffset, maxScroll);
672
- const visible = allLines.slice(effectiveOffset, effectiveOffset + viewableHeight);
673
- const padCount = viewableHeight - visible.length;
674
- const scrollPct = maxScroll > 0 ? Math.round(effectiveOffset / maxScroll * 100) : 100;
675
- return /* @__PURE__ */ jsxs2(
676
- Box3,
879
+ return /* @__PURE__ */ jsx4(
880
+ ScrollablePanel,
677
881
  {
678
- flexDirection: "column",
882
+ lines: allLines,
679
883
  width,
680
- borderStyle: "round",
681
- borderColor: focused ? "blue" : "gray",
682
- paddingX: 1,
683
- children: [
684
- visible.map((line, i) => /* @__PURE__ */ jsx3(Text3, { children: line.map((s, j) => /* @__PURE__ */ jsx3(
685
- Text3,
686
- {
687
- color: s.color,
688
- bold: s.bold,
689
- dimColor: s.dim,
690
- italic: s.italic,
691
- children: s.text
692
- },
693
- j
694
- )) }, effectiveOffset + i)),
695
- padCount > 0 && Array.from({ length: padCount }, (_, i) => /* @__PURE__ */ jsx3(Text3, { children: " " }, `pad-${i}`)),
696
- hasOverflow && /* @__PURE__ */ jsxs2(Text3, { dimColor: true, children: [
697
- " ",
698
- "[tab] scroll \xB7 ",
699
- scrollPct,
700
- "% \xB7 ",
701
- allLines.length,
702
- " lines"
703
- ] })
704
- ]
884
+ height,
885
+ scrollOffset,
886
+ focused
705
887
  }
706
888
  );
707
889
  }
708
890
 
709
891
  // src/tui/components/LogsPanel.tsx
710
892
  import { useMemo as useMemo2 } from "react";
711
- import { Box as Box4, Text as Text4 } from "ink";
712
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
713
- function seg2(text, opts) {
714
- return { text, ...opts };
715
- }
893
+ import { Box as Box5, Text as Text5 } from "ink";
894
+ import { jsx as jsx5 } from "react/jsx-runtime";
716
895
  function buildLines2(cycleLogs, width) {
717
896
  const lines = [];
718
897
  const contentWidth = width - 4;
@@ -721,17 +900,17 @@ function buildLines2(cycleLogs, width) {
721
900
  }
722
901
  const sorted = [...cycleLogs].sort((a, b) => b.cycle - a.cycle);
723
902
  for (const { cycle, content } of sorted) {
724
- lines.push([seg2(` Cycle ${cycle}`, { color: "blue", bold: true })]);
903
+ lines.push([seg(` Cycle ${cycle}`, { color: "blue", bold: true })]);
725
904
  const cleaned = cleanMarkdown(stripFrontmatter(content)).trim();
726
905
  if (cleaned) {
727
906
  for (const rawLine of cleaned.split("\n")) {
728
907
  const wrapped = wrapText(rawLine, contentWidth - 2);
729
908
  for (const wl of wrapped) {
730
- lines.push([seg2(` ${wl}`, { dim: true })]);
909
+ lines.push([seg(` ${wl}`, { dim: true })]);
731
910
  }
732
911
  }
733
912
  }
734
- lines.push([seg2(" ")]);
913
+ lines.push([seg(" ")]);
735
914
  }
736
915
  return lines;
737
916
  }
@@ -743,8 +922,8 @@ function LogsPanel({
743
922
  focused = false
744
923
  }) {
745
924
  if (cycleLogs.length === 0) {
746
- return /* @__PURE__ */ jsx4(
747
- Box4,
925
+ return /* @__PURE__ */ jsx5(
926
+ Box5,
748
927
  {
749
928
  flexDirection: "column",
750
929
  width,
@@ -753,7 +932,7 @@ function LogsPanel({
753
932
  paddingX: 1,
754
933
  justifyContent: "center",
755
934
  alignItems: "center",
756
- children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "No logs" })
935
+ children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "No logs" })
757
936
  }
758
937
  );
759
938
  }
@@ -761,316 +940,235 @@ function LogsPanel({
761
940
  () => buildLines2(cycleLogs, width),
762
941
  [cycleLogs, width]
763
942
  );
764
- const innerHeight = height - 2;
765
- const hasOverflow = allLines.length > innerHeight;
766
- const viewableHeight = hasOverflow ? innerHeight - 1 : innerHeight;
767
- const maxScroll = Math.max(0, allLines.length - viewableHeight);
768
- const effectiveOffset = Math.min(scrollOffset, maxScroll);
769
- const visible = allLines.slice(effectiveOffset, effectiveOffset + viewableHeight);
770
- const padCount = viewableHeight - visible.length;
771
- const scrollPct = maxScroll > 0 ? Math.round(effectiveOffset / maxScroll * 100) : 100;
772
- return /* @__PURE__ */ jsxs3(
773
- Box4,
943
+ return /* @__PURE__ */ jsx5(
944
+ ScrollablePanel,
774
945
  {
775
- flexDirection: "column",
946
+ lines: allLines,
776
947
  width,
777
- borderStyle: "round",
778
- borderColor: focused ? "blue" : "gray",
779
- paddingX: 1,
780
- children: [
781
- visible.map((line, i) => /* @__PURE__ */ jsx4(Text4, { children: line.map((s, j) => /* @__PURE__ */ jsx4(Text4, { color: s.color, bold: s.bold, dimColor: s.dim, children: s.text }, j)) }, effectiveOffset + i)),
782
- padCount > 0 && Array.from({ length: padCount }, (_, i) => /* @__PURE__ */ jsx4(Text4, { children: " " }, `pad-${i}`)),
783
- hasOverflow && /* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
784
- " ",
785
- "[tab] scroll \xB7 ",
786
- scrollPct,
787
- "% \xB7 ",
788
- allLines.length,
789
- " lines"
790
- ] })
791
- ]
948
+ height,
949
+ scrollOffset,
950
+ focused
792
951
  }
793
952
  );
794
953
  }
795
954
 
796
955
  // src/tui/components/CycleDetail.tsx
797
- import { Box as Box5, Text as Text5 } from "ink";
798
- import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
799
- function CycleDetail({ cycle, agents, width, height }) {
956
+ import { useMemo as useMemo3 } from "react";
957
+ import { jsx as jsx6 } from "react/jsx-runtime";
958
+ function buildLines3(cycle, agents, width) {
959
+ const lines = [];
800
960
  const contentWidth = width - 4;
801
- const dur = cycle.completedAt ? formatDuration(cycle.timestamp, cycle.completedAt) : "running";
802
961
  const isRunning = !cycle.completedAt;
962
+ const dur = cycle.completedAt ? formatDuration(cycle.timestamp, cycle.completedAt) : "running";
803
963
  const cycleAgents = agents.filter((a) => cycle.agentsSpawned.includes(a.id));
804
- const headerLines = 4;
805
- const agentLinesBudget = cycleAgents.reduce((sum, a) => {
806
- let n = 1;
807
- if (a.instruction) n++;
808
- if (a.status === "completed" && a.reports.length > 0) n++;
809
- return sum + n;
810
- }, 0);
811
- const agentSectionLines = Math.max(1, agentLinesBudget) + 2;
812
- const promptAvailable = height - headerLines - agentSectionLines - 6;
813
- return /* @__PURE__ */ jsxs4(
814
- Box5,
964
+ lines.push(singleLine(` Cycle ${cycle.cycle}`, { bold: true }));
965
+ lines.push([
966
+ seg(" "),
967
+ seg(isRunning ? "running" : "completed", { color: isRunning ? "green" : "gray" }),
968
+ seg(` \xB7 ${dur} \xB7 ${cycleAgents.length} agent${cycleAgents.length !== 1 ? "s" : ""}`, { dim: true }),
969
+ ...cycle.mode ? [
970
+ seg(" \xB7 ", { dim: true }),
971
+ seg(cycle.mode, {
972
+ color: cycle.mode === "planning" ? "blue" : cycle.mode === "implementation" ? "green" : "cyan"
973
+ })
974
+ ] : []
975
+ ]);
976
+ lines.push(singleLine(
977
+ ` ${formatTime(cycle.timestamp)}${cycle.completedAt ? ` \u2192 ${formatTime(cycle.completedAt)}` : ""}`,
978
+ { dim: true }
979
+ ));
980
+ lines.push(singleLine(" "));
981
+ lines.push([seg(" \u258E \u229E AGENTS", { color: "green", bold: true })]);
982
+ if (cycleAgents.length === 0) {
983
+ lines.push(singleLine(" orchestrator spawning agents\u2026", { dim: true, italic: true }));
984
+ } else {
985
+ for (const agent of cycleAgents) {
986
+ const nameLabel = agent.name !== agent.id ? agent.name : agent.agentType;
987
+ const instrPreview = agent.instruction.split("\n")[0] || "";
988
+ const latestReport = agent.reports.length > 0 ? agent.reports[agent.reports.length - 1] : null;
989
+ const reportSummary = latestReport && agent.status === "completed" ? extractFirstSentence(latestReport.summary, contentWidth - 14) : null;
990
+ const agentDur = formatDuration(agent.spawnedAt, agent.completedAt);
991
+ const durClr = durationColor(agent.spawnedAt, agent.completedAt) || void 0;
992
+ lines.push([
993
+ seg(" "),
994
+ seg(agentStatusIcon(agent.status), { color: statusColor(agent.status) }),
995
+ seg(` ${agent.id}`, { bold: true }),
996
+ seg(` ${truncate(nameLabel, contentWidth - 30)}`, {
997
+ color: agentTypeColor(agent.agentType) || void 0,
998
+ dim: !agentTypeColor(agent.agentType)
999
+ }),
1000
+ seg(` \xB7 ${agent.status} \xB7 `, { dim: true }),
1001
+ seg(agentDur, { color: durClr, dim: !durClr })
1002
+ ]);
1003
+ if (instrPreview) {
1004
+ lines.push(singleLine(` ${truncate(instrPreview, contentWidth - 10)}`, { dim: true }));
1005
+ }
1006
+ if (reportSummary) {
1007
+ lines.push([
1008
+ seg(" "),
1009
+ seg("\u21B3", { color: "cyan" }),
1010
+ seg(` ${reportSummary}`, { dim: true })
1011
+ ]);
1012
+ }
1013
+ }
1014
+ }
1015
+ if (cycle.nextPrompt) {
1016
+ lines.push(singleLine(" "));
1017
+ lines.push([seg(" \u258E \u25B7 NEXT PROMPT", { color: "yellow", bold: true })]);
1018
+ for (const wl of wrapText(cycle.nextPrompt, contentWidth - 6)) {
1019
+ lines.push(singleLine(` ${wl}`, { dim: true }));
1020
+ }
1021
+ }
1022
+ return lines;
1023
+ }
1024
+ function CycleDetail({ cycle, agents, width, height, scrollOffset = 0, focused = false }) {
1025
+ const allLines = useMemo3(
1026
+ () => buildLines3(cycle, agents, width),
1027
+ [cycle, agents, width]
1028
+ );
1029
+ return /* @__PURE__ */ jsx6(
1030
+ ScrollablePanel,
815
1031
  {
816
- flexDirection: "column",
1032
+ lines: allLines,
817
1033
  width,
818
- borderStyle: "round",
819
- borderColor: "gray",
820
- paddingX: 1,
821
- children: [
822
- /* @__PURE__ */ jsxs4(Text5, { bold: true, children: [
823
- " Cycle ",
824
- cycle.cycle
825
- ] }),
826
- /* @__PURE__ */ jsxs4(Box5, { children: [
827
- /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: " " }),
828
- /* @__PURE__ */ jsx5(Text5, { color: isRunning ? "green" : "gray", children: isRunning ? "running" : "completed" }),
829
- /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
830
- " \xB7 ",
831
- dur,
832
- " \xB7 ",
833
- cycleAgents.length,
834
- " agent",
835
- cycleAgents.length !== 1 ? "s" : "",
836
- cycle.mode ? " \xB7 " : ""
837
- ] }),
838
- cycle.mode && /* @__PURE__ */ jsx5(Text5, { color: cycle.mode === "planning" ? "blue" : cycle.mode === "implementation" ? "green" : "cyan", children: cycle.mode })
839
- ] }),
840
- /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
841
- " ",
842
- formatTime(cycle.timestamp),
843
- cycle.completedAt ? ` \u2192 ${formatTime(cycle.completedAt)}` : ""
844
- ] }),
845
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
846
- /* @__PURE__ */ jsxs4(Text5, { color: "green", bold: true, children: [
847
- " ",
848
- "\u258E \u229E AGENTS"
849
- ] }),
850
- cycleAgents.length === 0 ? /* @__PURE__ */ jsxs4(Text5, { dimColor: true, italic: true, children: [
851
- " ",
852
- "orchestrator spawning agents\u2026"
853
- ] }) : cycleAgents.map((agent) => {
854
- const nameLabel = agent.name !== agent.id ? agent.name : agent.agentType;
855
- const instrPreview = agent.instruction.split("\n")[0] || "";
856
- const latestReport = agent.reports.length > 0 ? agent.reports[agent.reports.length - 1] : null;
857
- const reportSummary = latestReport && agent.status === "completed" ? extractFirstSentence(latestReport.summary, contentWidth - 14) : null;
858
- return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", children: [
859
- /* @__PURE__ */ jsxs4(Box5, { children: [
860
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
861
- /* @__PURE__ */ jsx5(Text5, { color: statusColor(agent.status), children: agentStatusIcon(agent.status) }),
862
- /* @__PURE__ */ jsxs4(Text5, { bold: true, children: [
863
- " ",
864
- agent.id
865
- ] }),
866
- /* @__PURE__ */ jsxs4(Text5, { color: agentTypeColor(agent.agentType), dimColor: !agentTypeColor(agent.agentType), children: [
867
- " ",
868
- truncate(nameLabel, contentWidth - 30)
869
- ] }),
870
- (() => {
871
- const dur2 = formatDuration(agent.spawnedAt, agent.completedAt);
872
- const durColor = durationColor(agent.spawnedAt, agent.completedAt) || void 0;
873
- return /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
874
- " \xB7 ",
875
- agent.status,
876
- " \xB7 ",
877
- /* @__PURE__ */ jsx5(Text5, { color: durColor, children: dur2 })
878
- ] });
879
- })()
880
- ] }),
881
- instrPreview && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
882
- " ",
883
- truncate(instrPreview, contentWidth - 10)
884
- ] }),
885
- reportSummary && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
886
- " ",
887
- /* @__PURE__ */ jsx5(Text5, { color: "cyan", children: "\u21B3" }),
888
- " ",
889
- reportSummary
890
- ] })
891
- ] }, agent.id);
892
- }),
893
- cycle.nextPrompt && /* @__PURE__ */ jsxs4(Fragment, { children: [
894
- /* @__PURE__ */ jsx5(Text5, { children: " " }),
895
- /* @__PURE__ */ jsxs4(Text5, { color: "yellow", bold: true, children: [
896
- " ",
897
- "\u258E \u25B7 NEXT PROMPT"
898
- ] }),
899
- wrapText(cycle.nextPrompt, contentWidth - 6).slice(0, Math.max(3, promptAvailable)).map((line, i) => /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
900
- " ",
901
- line
902
- ] }, i))
903
- ] })
904
- ]
1034
+ height,
1035
+ scrollOffset,
1036
+ focused
905
1037
  }
906
1038
  );
907
1039
  }
908
1040
 
909
1041
  // src/tui/components/AgentDetail.tsx
910
- import { Box as Box6, Text as Text6 } from "ink";
911
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
912
- function AgentDetail({ agent, reportBlocks, width, height }) {
1042
+ import { useMemo as useMemo4 } from "react";
1043
+ import { jsx as jsx7 } from "react/jsx-runtime";
1044
+ function buildLines4(agent, reportBlocks, width) {
1045
+ const lines = [];
913
1046
  const contentWidth = width - 4;
914
1047
  const dur = formatDuration(agent.spawnedAt, agent.completedAt);
915
1048
  const icon = agentStatusIcon(agent.status);
916
1049
  const color = statusColor(agent.status);
917
1050
  const nameLabel = agent.name !== agent.id ? agent.name : agent.agentType;
918
- const metaLines = 3;
919
- const alertLines = (agent.killedReason ? 1 : 0) + (agent.mergeStatus === "conflict" && agent.mergeDetails ? 2 : 0);
920
- const timestampLines = 1 + (agent.completedAt ? 1 : 0) + (agent.paneId ? 1 : 0) + (agent.worktreePath ? 1 : 0) + (agent.branchName ? 1 : 0) + 2;
921
- const reportHeader = agent.reports.length > 0 ? 2 : 0;
922
- const fixedLines = metaLines + alertLines + timestampLines + reportHeader + 4;
923
- const hasResolvedReports = reportBlocks && reportBlocks.length > 0;
924
- const availableForContent = Math.max(6, height - fixedLines);
925
- let instrMaxLines;
926
- let reportMaxLines;
927
- if (hasResolvedReports) {
928
- instrMaxLines = Math.max(4, Math.floor(availableForContent * 0.35));
929
- reportMaxLines = Math.max(4, availableForContent - instrMaxLines);
930
- } else {
931
- const summaryLines = agent.reports.length;
932
- instrMaxLines = Math.max(4, availableForContent - summaryLines - 1);
933
- reportMaxLines = summaryLines;
1051
+ const maxMergeLines = 3;
1052
+ lines.push([
1053
+ seg(" "),
1054
+ seg(icon, { color }),
1055
+ seg(` ${agent.id} \xB7 ${nameLabel}`, { bold: true })
1056
+ ]);
1057
+ const mergeSegs = [];
1058
+ if (agent.mergeStatus) {
1059
+ mergeSegs.push(seg(" \xB7 ", { dim: true }));
1060
+ switch (agent.mergeStatus) {
1061
+ case "merged":
1062
+ mergeSegs.push(seg("\u2295 merged", { color: "green" }));
1063
+ break;
1064
+ case "pending":
1065
+ mergeSegs.push(seg("\u25CC pending", { color: "yellow" }));
1066
+ break;
1067
+ case "no-changes":
1068
+ mergeSegs.push(seg("\u2205 no changes", { color: "gray" }));
1069
+ break;
1070
+ case "conflict":
1071
+ mergeSegs.push(seg("\u26A0 conflict", { color: "red" }));
1072
+ break;
1073
+ default:
1074
+ mergeSegs.push(seg(agent.mergeStatus, { dim: true }));
1075
+ }
934
1076
  }
935
- return /* @__PURE__ */ jsxs5(
936
- Box6,
1077
+ lines.push([
1078
+ seg(" "),
1079
+ seg(agent.status, { color }),
1080
+ seg(` \xB7 ${dur} \xB7 ${agent.agentType}`, { dim: true }),
1081
+ ...mergeSegs
1082
+ ]);
1083
+ if (agent.killedReason) {
1084
+ lines.push(singleLine(` \u26A0 ${agent.killedReason}`, { color: "red" }));
1085
+ }
1086
+ if (agent.mergeStatus === "conflict" && agent.mergeDetails) {
1087
+ for (const ml of wrapText(agent.mergeDetails, contentWidth - 6).slice(0, maxMergeLines)) {
1088
+ lines.push(singleLine(` \u26A0 ${ml}`, { color: "red" }));
1089
+ }
1090
+ }
1091
+ if (agent.mergeStatus === "conflict") {
1092
+ lines.push(singleLine(" resolve conflicts in worktree dir, then restart", { color: "red", dim: true }));
1093
+ }
1094
+ lines.push(singleLine(" "));
1095
+ lines.push(singleLine(" \u258E \u25B7 INSTRUCTION", { color: "white", bold: true }));
1096
+ for (const wl of wrapText(agent.instruction, contentWidth - 6)) {
1097
+ lines.push(singleLine(` ${wl}`, { dim: true }));
1098
+ }
1099
+ if (agent.reports.length > 0) {
1100
+ const hasResolved = reportBlocks && reportBlocks.length > 0;
1101
+ lines.push(singleLine(" "));
1102
+ lines.push([seg(` \u258E \u25C7 REPORTS (${agent.reports.length})`, { color: "cyan", bold: true })]);
1103
+ if (hasResolved) {
1104
+ for (let i = 0; i < reportBlocks.length; i++) {
1105
+ const block = reportBlocks[i];
1106
+ const badge = block.type === "final" ? "FINAL" : "UPDATE";
1107
+ const badgeColor = block.type === "final" ? "cyan" : "yellow";
1108
+ if (i > 0) lines.push(singleLine(" "));
1109
+ lines.push([
1110
+ seg(" "),
1111
+ seg(badge, { color: badgeColor, bold: block.type === "final" }),
1112
+ seg(` ${formatTime(block.timestamp)}`, { dim: true })
1113
+ ]);
1114
+ for (const wl of wrapText(cleanMarkdown(block.content.trim()), contentWidth - 10)) {
1115
+ lines.push(singleLine(` ${wl}`, { dim: true }));
1116
+ }
1117
+ }
1118
+ } else {
1119
+ for (const report of agent.reports) {
1120
+ const badge = report.type === "final" ? "FINAL" : "UPDATE";
1121
+ const badgeColor = report.type === "final" ? "cyan" : "yellow";
1122
+ lines.push([
1123
+ seg(" "),
1124
+ seg(badge, { color: badgeColor, bold: report.type === "final" }),
1125
+ seg(` ${formatTime(report.timestamp)} ${report.summary.split("\n")[0]}`, { dim: true })
1126
+ ]);
1127
+ }
1128
+ }
1129
+ }
1130
+ lines.push(singleLine(" "));
1131
+ lines.push(singleLine(" \u258E \u25E6 META", { color: "gray", bold: true }));
1132
+ lines.push(singleLine(` Spawned: ${formatTime(agent.spawnedAt)}`, { dim: true }));
1133
+ if (agent.completedAt) {
1134
+ lines.push(singleLine(` Completed: ${formatTime(agent.completedAt)}`, { dim: true }));
1135
+ }
1136
+ if (agent.paneId) {
1137
+ lines.push(singleLine(` Pane: ${agent.paneId}`, { dim: true }));
1138
+ }
1139
+ if (agent.worktreePath) {
1140
+ lines.push(singleLine(` Worktree: ${agent.worktreePath}`, { dim: true }));
1141
+ }
1142
+ if (agent.branchName) {
1143
+ lines.push(singleLine(` Branch: ${agent.branchName}`, { dim: true }));
1144
+ }
1145
+ return lines;
1146
+ }
1147
+ function AgentDetail({ agent, reportBlocks, width, height, scrollOffset = 0, focused = false }) {
1148
+ const allLines = useMemo4(
1149
+ () => buildLines4(agent, reportBlocks, width),
1150
+ [agent, reportBlocks, width]
1151
+ );
1152
+ return /* @__PURE__ */ jsx7(
1153
+ ScrollablePanel,
937
1154
  {
938
- flexDirection: "column",
1155
+ lines: allLines,
939
1156
  width,
940
- borderStyle: "round",
941
- borderColor: "gray",
942
- paddingX: 1,
943
- children: [
944
- /* @__PURE__ */ jsxs5(Text6, { bold: true, children: [
945
- " ",
946
- /* @__PURE__ */ jsx6(Text6, { color, children: icon }),
947
- " ",
948
- agent.id,
949
- " \xB7 ",
950
- nameLabel
951
- ] }),
952
- /* @__PURE__ */ jsxs5(Box6, { children: [
953
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " " }),
954
- /* @__PURE__ */ jsx6(Text6, { color, children: agent.status }),
955
- /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
956
- " \xB7 ",
957
- dur,
958
- " \xB7 ",
959
- agent.agentType
960
- ] }),
961
- agent.mergeStatus && /* @__PURE__ */ jsxs5(Fragment2, { children: [
962
- /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: " \xB7 " }),
963
- agent.mergeStatus === "merged" && /* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2295 merged" }),
964
- agent.mergeStatus === "pending" && /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "\u25CC pending" }),
965
- agent.mergeStatus === "no-changes" && /* @__PURE__ */ jsx6(Text6, { color: "gray", children: "\u2205 no changes" }),
966
- agent.mergeStatus === "conflict" && /* @__PURE__ */ jsx6(Text6, { color: "red", children: "\u26A0 conflict" }),
967
- !["merged", "pending", "no-changes", "conflict"].includes(agent.mergeStatus) && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: agent.mergeStatus })
968
- ] })
969
- ] }),
970
- agent.killedReason && /* @__PURE__ */ jsxs5(Text6, { color: "red", children: [
971
- " ",
972
- "\u26A0 ",
973
- agent.killedReason
974
- ] }),
975
- agent.mergeStatus === "conflict" && agent.mergeDetails && /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: wrapText(agent.mergeDetails, contentWidth - 6).map((line, i) => /* @__PURE__ */ jsxs5(Text6, { color: "red", children: [
976
- " ",
977
- "\u26A0 ",
978
- line
979
- ] }, i)) }),
980
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
981
- /* @__PURE__ */ jsxs5(Text6, { color: "white", bold: true, children: [
982
- " ",
983
- "\u258E \u25B7 INSTRUCTION"
984
- ] }),
985
- wrapText(agent.instruction, contentWidth - 6).slice(0, instrMaxLines).map((line, i) => /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
986
- " ",
987
- line
988
- ] }, i)),
989
- agent.reports.length > 0 && /* @__PURE__ */ jsxs5(Fragment2, { children: [
990
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
991
- /* @__PURE__ */ jsxs5(Text6, { color: "cyan", bold: true, children: [
992
- " ",
993
- "\u258E \u25C7 REPORTS (",
994
- agent.reports.length,
995
- ")"
996
- ] }),
997
- hasResolvedReports ? /* @__PURE__ */ jsx6(Box6, { flexDirection: "column", children: reportBlocks.slice(0, Math.min(reportBlocks.length, 3)).map((block, i) => {
998
- const badge = block.type === "final" ? "FINAL" : "UPDATE";
999
- const badgeColor = block.type === "final" ? "cyan" : "yellow";
1000
- const linesPerReport = Math.max(2, Math.floor(reportMaxLines / Math.min(reportBlocks.length, 3)) - 2);
1001
- return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
1002
- i > 0 && /* @__PURE__ */ jsx6(Text6, { children: " " }),
1003
- /* @__PURE__ */ jsxs5(Box6, { children: [
1004
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
1005
- /* @__PURE__ */ jsx6(Text6, { color: badgeColor, bold: block.type === "final", children: badge }),
1006
- /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1007
- " ",
1008
- formatTime(block.timestamp)
1009
- ] })
1010
- ] }),
1011
- wrapText(cleanMarkdown(block.content.trim()), contentWidth - 10).slice(0, linesPerReport).map((line, j) => /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1012
- " ",
1013
- line
1014
- ] }, j))
1015
- ] }, i);
1016
- }) }) : agent.reports.slice(0, reportMaxLines).map((report, i) => {
1017
- const badge = report.type === "final" ? "FINAL" : "UPDATE";
1018
- const badgeColor = report.type === "final" ? "cyan" : "yellow";
1019
- return /* @__PURE__ */ jsxs5(Box6, { children: [
1020
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
1021
- /* @__PURE__ */ jsx6(Text6, { color: badgeColor, bold: report.type === "final", children: badge }),
1022
- /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1023
- " ",
1024
- formatTime(report.timestamp),
1025
- " ",
1026
- report.summary.split("\n")[0]
1027
- ] })
1028
- ] }, i);
1029
- })
1030
- ] }),
1031
- /* @__PURE__ */ jsx6(Text6, { children: " " }),
1032
- /* @__PURE__ */ jsxs5(Text6, { color: "gray", bold: true, children: [
1033
- " ",
1034
- "\u258E \u25E6 META"
1035
- ] }),
1036
- /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1037
- " ",
1038
- "Spawned: ",
1039
- formatTime(agent.spawnedAt)
1040
- ] }),
1041
- agent.completedAt && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1042
- " ",
1043
- "Completed: ",
1044
- formatTime(agent.completedAt)
1045
- ] }),
1046
- agent.paneId && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1047
- " ",
1048
- "Pane: ",
1049
- agent.paneId
1050
- ] }),
1051
- agent.worktreePath && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1052
- " ",
1053
- "Worktree: ",
1054
- agent.worktreePath
1055
- ] }),
1056
- agent.branchName && /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
1057
- " ",
1058
- "Branch: ",
1059
- agent.branchName
1060
- ] })
1061
- ]
1157
+ height,
1158
+ scrollOffset,
1159
+ focused
1062
1160
  }
1063
1161
  );
1064
1162
  }
1065
1163
 
1066
1164
  // src/tui/components/ReportView.tsx
1067
- import { useState, useMemo as useMemo3 } from "react";
1068
- import { Box as Box7, Text as Text7, useInput } from "ink";
1069
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1165
+ import { useState, useMemo as useMemo5 } from "react";
1166
+ import { Box as Box6, Text as Text6, useInput } from "ink";
1167
+ import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
1070
1168
  function ReportView({ agent, reportBlocks, width, height, onClose }) {
1071
1169
  const [scrollOffset, setScrollOffset] = useState(0);
1072
1170
  const contentWidth = width - 6;
1073
- const lines = useMemo3(() => {
1171
+ const lines = useMemo5(() => {
1074
1172
  const lines2 = [];
1075
1173
  if (reportBlocks.length === 0) {
1076
1174
  lines2.push({ text: "", dim: true });
@@ -1132,8 +1230,8 @@ function ReportView({ agent, reportBlocks, width, height, onClose }) {
1132
1230
  const icon = agentStatusIcon(agent.status);
1133
1231
  const color = statusColor(agent.status);
1134
1232
  const dur = formatDuration(agent.spawnedAt, agent.completedAt);
1135
- return /* @__PURE__ */ jsxs6(
1136
- Box7,
1233
+ return /* @__PURE__ */ jsxs3(
1234
+ Box6,
1137
1235
  {
1138
1236
  flexDirection: "column",
1139
1237
  width,
@@ -1142,17 +1240,17 @@ function ReportView({ agent, reportBlocks, width, height, onClose }) {
1142
1240
  borderColor: "cyan",
1143
1241
  paddingX: 1,
1144
1242
  children: [
1145
- /* @__PURE__ */ jsxs6(Text7, { bold: true, children: [
1243
+ /* @__PURE__ */ jsxs3(Text6, { bold: true, children: [
1146
1244
  " ",
1147
- /* @__PURE__ */ jsx7(Text7, { color, children: icon }),
1245
+ /* @__PURE__ */ jsx8(Text6, { color, children: icon }),
1148
1246
  " ",
1149
1247
  agent.id,
1150
1248
  " ",
1151
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "\xB7" }),
1249
+ /* @__PURE__ */ jsx8(Text6, { dimColor: true, children: "\xB7" }),
1152
1250
  " ",
1153
1251
  agent.name !== agent.id ? agent.name : agent.agentType
1154
1252
  ] }),
1155
- /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1253
+ /* @__PURE__ */ jsxs3(Text6, { dimColor: true, children: [
1156
1254
  " ",
1157
1255
  agent.status,
1158
1256
  " \xB7 ",
@@ -1164,28 +1262,28 @@ function ReportView({ agent, reportBlocks, width, height, onClose }) {
1164
1262
  " report",
1165
1263
  totalReports !== 1 ? "s" : ""
1166
1264
  ] }),
1167
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + divider(contentWidth - 2) }),
1168
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", flexGrow: 1, children: visible.map((line, i) => /* @__PURE__ */ jsx7(
1169
- Text7,
1265
+ /* @__PURE__ */ jsx8(Text6, { dimColor: true, children: " " + divider(contentWidth - 2) }),
1266
+ /* @__PURE__ */ jsx8(Box6, { flexDirection: "column", flexGrow: 1, children: visible.map((line, i) => /* @__PURE__ */ jsx8(
1267
+ Text6,
1170
1268
  {
1171
1269
  color: line.color,
1172
1270
  bold: line.bold,
1173
1271
  dimColor: line.dim,
1174
1272
  children: line.text
1175
1273
  },
1176
- scrollOffset + i
1274
+ i
1177
1275
  )) }),
1178
- /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: " " + divider(contentWidth - 2) }),
1179
- /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1276
+ /* @__PURE__ */ jsx8(Text6, { dimColor: true, children: " " + divider(contentWidth - 2) }),
1277
+ /* @__PURE__ */ jsxs3(Text6, { dimColor: true, children: [
1180
1278
  " ",
1181
1279
  "[esc] back [\u2191\u2193] scroll [",
1182
1280
  "] page",
1183
1281
  " ",
1184
- /* @__PURE__ */ jsxs6(Text7, { children: [
1282
+ /* @__PURE__ */ jsxs3(Text6, { children: [
1185
1283
  scrollPct,
1186
1284
  "%"
1187
1285
  ] }),
1188
- maxScroll > 0 && /* @__PURE__ */ jsxs6(Text7, { dimColor: true, children: [
1286
+ maxScroll > 0 && /* @__PURE__ */ jsxs3(Text6, { dimColor: true, children: [
1189
1287
  " \xB7 ",
1190
1288
  lines.length,
1191
1289
  " lines"
@@ -1196,58 +1294,10 @@ function ReportView({ agent, reportBlocks, width, height, onClose }) {
1196
1294
  );
1197
1295
  }
1198
1296
 
1199
- // src/tui/components/MessageLog.tsx
1200
- import { Box as Box8, Text as Text8 } from "ink";
1201
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1202
- function sourceLabel(msg) {
1203
- if (msg.source.type === "user") return "You";
1204
- if (msg.source.type === "agent") return msg.source.agentId;
1205
- return "system";
1206
- }
1207
- function sourceColor(msg) {
1208
- if (msg.source.type === "user") return "yellow";
1209
- if (msg.source.type === "agent") return "cyan";
1210
- return "gray";
1211
- }
1212
- function MessageLog({ messages, maxMessages, width }) {
1213
- if (messages.length === 0) {
1214
- return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
1215
- /* @__PURE__ */ jsx8(Text8, { bold: true, dimColor: true, children: "Messages" }),
1216
- /* @__PURE__ */ jsx8(Text8, { dimColor: true, italic: true, children: " No messages" })
1217
- ] });
1218
- }
1219
- const recent = messages.slice(-maxMessages);
1220
- const contentWidth = Math.max(10, width - 20);
1221
- return /* @__PURE__ */ jsxs7(Box8, { flexDirection: "column", children: [
1222
- /* @__PURE__ */ jsx8(Text8, { bold: true, dimColor: true, children: "Messages" }),
1223
- recent.map((msg) => {
1224
- const time = formatTime(msg.timestamp);
1225
- const label = sourceLabel(msg);
1226
- const color = sourceColor(msg);
1227
- const content = truncate(msg.summary || msg.content, contentWidth);
1228
- return /* @__PURE__ */ jsxs7(Text8, { children: [
1229
- " ",
1230
- /* @__PURE__ */ jsxs7(Text8, { dimColor: true, children: [
1231
- "[",
1232
- time,
1233
- "]"
1234
- ] }),
1235
- " ",
1236
- /* @__PURE__ */ jsxs7(Text8, { color, bold: true, children: [
1237
- label,
1238
- ":"
1239
- ] }),
1240
- " ",
1241
- content
1242
- ] }, msg.id);
1243
- })
1244
- ] });
1245
- }
1246
-
1247
1297
  // src/tui/components/InputBar.tsx
1248
1298
  import { useState as useState2, useEffect, useRef } from "react";
1249
- import { Box as Box9, Text as Text9, useInput as useInput2 } from "ink";
1250
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1299
+ import { Box as Box7, Text as Text7, useInput as useInput2 } from "ink";
1300
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
1251
1301
  var INPUT_MODES = /* @__PURE__ */ new Set([
1252
1302
  "resume",
1253
1303
  "continue",
@@ -1341,163 +1391,163 @@ function InputBar({ mode, defaultText, onSubmit, onCancel }) {
1341
1391
  { isActive: INPUT_MODES.has(mode) }
1342
1392
  );
1343
1393
  if (mode === "navigate") {
1344
- return /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Press [m] to message orchestrator, [n] for new session" }) });
1394
+ return /* @__PURE__ */ jsx9(Box7, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text7, { dimColor: true, children: "Press [m] to message orchestrator, [n] for new session" }) });
1345
1395
  }
1346
1396
  if (mode === "report-detail" || mode === "leader" || mode === "copy-menu" || mode === "help" || !INPUT_MODES.has(mode)) {
1347
1397
  return null;
1348
1398
  }
1349
1399
  const prompt = PROMPTS[mode] ?? mode;
1350
- return /* @__PURE__ */ jsxs8(Box9, { paddingX: 1, children: [
1351
- /* @__PURE__ */ jsxs8(Text9, { color: "yellow", children: [
1400
+ return /* @__PURE__ */ jsxs4(Box7, { paddingX: 1, children: [
1401
+ /* @__PURE__ */ jsxs4(Text7, { color: "yellow", children: [
1352
1402
  prompt,
1353
1403
  " > "
1354
1404
  ] }),
1355
- /* @__PURE__ */ jsx9(Text9, { children: text.slice(0, cursorPos) }),
1356
- /* @__PURE__ */ jsx9(Text9, { inverse: true, children: cursorPos < text.length ? text[cursorPos] : " " }),
1357
- /* @__PURE__ */ jsx9(Text9, { children: text.slice(cursorPos + 1) }),
1358
- /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: " (enter to send, esc to cancel)" })
1405
+ /* @__PURE__ */ jsx9(Text7, { children: text.slice(0, cursorPos) }),
1406
+ /* @__PURE__ */ jsx9(Text7, { inverse: true, children: cursorPos < text.length ? text[cursorPos] : " " }),
1407
+ /* @__PURE__ */ jsx9(Text7, { children: text.slice(cursorPos + 1) }),
1408
+ /* @__PURE__ */ jsx9(Text7, { dimColor: true, children: " (enter to send, esc to cancel)" })
1359
1409
  ] });
1360
1410
  }
1361
1411
 
1362
1412
  // src/tui/components/StatusLine.tsx
1363
- import { Box as Box10, Text as Text10 } from "ink";
1364
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1413
+ import { Box as Box8, Text as Text8 } from "ink";
1414
+ import { Fragment, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1365
1415
  function StatusLine({ mode, detailFocused = false, logsFocused = false, showLogs = false, cursorNodeType }) {
1366
1416
  if (mode === "report-detail") {
1367
1417
  return null;
1368
1418
  }
1369
1419
  if (mode === "leader") {
1370
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1371
- /* @__PURE__ */ jsx10(Text10, { color: "magenta", bold: true, children: "LEADER" }),
1372
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " press a command key or [esc] to cancel" })
1420
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1421
+ /* @__PURE__ */ jsx10(Text8, { color: "magenta", bold: true, children: "LEADER" }),
1422
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " press a command key or [esc] to cancel" })
1373
1423
  ] });
1374
1424
  }
1375
1425
  if (mode === "copy-menu") {
1376
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1377
- /* @__PURE__ */ jsx10(Text10, { color: "cyan", bold: true, children: "COPY" }),
1378
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " [p] path [C] context [l] logs [s] session ID [esc] cancel" })
1426
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1427
+ /* @__PURE__ */ jsx10(Text8, { color: "cyan", bold: true, children: "COPY" }),
1428
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " [p] path [C] context [l] logs [s] session ID [esc] cancel" })
1379
1429
  ] });
1380
1430
  }
1381
1431
  if (mode === "help") {
1382
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1383
- /* @__PURE__ */ jsx10(Text10, { color: "yellow", bold: true, children: "HELP" }),
1384
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " [esc] or [?] to dismiss" })
1432
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1433
+ /* @__PURE__ */ jsx10(Text8, { color: "yellow", bold: true, children: "HELP" }),
1434
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " [esc] or [?] to dismiss" })
1385
1435
  ] });
1386
1436
  }
1387
1437
  if (mode === "delete-confirm") {
1388
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1389
- /* @__PURE__ */ jsx10(Text10, { color: "red", bold: true, children: "DELETE" }),
1390
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " type 'yes' to confirm, [esc] to cancel" })
1438
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1439
+ /* @__PURE__ */ jsx10(Text8, { color: "red", bold: true, children: "DELETE" }),
1440
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " type 'yes' to confirm, [esc] to cancel" })
1391
1441
  ] });
1392
1442
  }
1393
1443
  if (mode === "spawn-agent") {
1394
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1395
- /* @__PURE__ */ jsx10(Text10, { color: "green", bold: true, children: "SPAWN" }),
1396
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " enter agent instruction, [esc] to cancel" })
1444
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1445
+ /* @__PURE__ */ jsx10(Text8, { color: "green", bold: true, children: "SPAWN" }),
1446
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " enter agent instruction, [esc] to cancel" })
1397
1447
  ] });
1398
1448
  }
1399
1449
  if (mode === "search") {
1400
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1401
- /* @__PURE__ */ jsx10(Text10, { color: "blue", bold: true, children: "SEARCH" }),
1402
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " type to filter, enter to apply, [esc] to cancel" })
1450
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1451
+ /* @__PURE__ */ jsx10(Text8, { color: "blue", bold: true, children: "SEARCH" }),
1452
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " type to filter, enter to apply, [esc] to cancel" })
1403
1453
  ] });
1404
1454
  }
1405
1455
  if (mode === "message-agent") {
1406
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1407
- /* @__PURE__ */ jsx10(Text10, { color: "cyan", bold: true, children: "MESSAGE" }),
1408
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " enter message for agent, [esc] to cancel" })
1456
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1457
+ /* @__PURE__ */ jsx10(Text8, { color: "cyan", bold: true, children: "MESSAGE" }),
1458
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " enter message for agent, [esc] to cancel" })
1409
1459
  ] });
1410
1460
  }
1411
1461
  if (mode === "shell-command") {
1412
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1413
- /* @__PURE__ */ jsx10(Text10, { color: "magenta", bold: true, children: "SHELL" }),
1414
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " enter command, [esc] to cancel" })
1462
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1463
+ /* @__PURE__ */ jsx10(Text8, { color: "magenta", bold: true, children: "SHELL" }),
1464
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " enter command, [esc] to cancel" })
1415
1465
  ] });
1416
1466
  }
1417
1467
  if (mode !== "navigate") {
1418
- return /* @__PURE__ */ jsx10(Box10, { paddingX: 1, children: /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "[enter] send [esc] cancel" }) });
1468
+ return /* @__PURE__ */ jsx10(Box8, { paddingX: 1, children: /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "[enter] send [esc] cancel" }) });
1419
1469
  }
1420
1470
  if (logsFocused) {
1421
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1422
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[jk/\u2191\u2193]" }),
1423
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " scroll " }),
1424
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[h/\u2190/tab]" }),
1425
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " back " }),
1426
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[t]" }),
1427
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "oggle logs " }),
1428
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u2502 " }),
1429
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[m]" }),
1430
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "sg " }),
1431
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[g]" }),
1432
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "oal " }),
1433
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[n]" }),
1434
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "ew " }),
1435
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[p]" }),
1436
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "lan " }),
1437
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[w]" }),
1438
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "indow " }),
1439
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[R]" }),
1440
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "esume " }),
1441
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[q]" }),
1442
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "uit" })
1471
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1472
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[jk/\u2191\u2193]" }),
1473
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " scroll " }),
1474
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[h/\u2190/tab]" }),
1475
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " back " }),
1476
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[t]" }),
1477
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "oggle logs " }),
1478
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "\u2502 " }),
1479
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[m]" }),
1480
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "sg " }),
1481
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[g]" }),
1482
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "oal " }),
1483
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[n]" }),
1484
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "ew " }),
1485
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[p]" }),
1486
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "lan " }),
1487
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[w]" }),
1488
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "indow " }),
1489
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[R]" }),
1490
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "esume " }),
1491
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[q]" }),
1492
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "uit" })
1443
1493
  ] });
1444
1494
  }
1445
1495
  if (detailFocused) {
1446
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1447
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[jk/\u2191\u2193]" }),
1448
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " scroll " }),
1449
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[h/\u2190/tab]" }),
1450
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " back " }),
1451
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[t]" }),
1452
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "oggle logs " }),
1453
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u2502 " }),
1454
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[m]" }),
1455
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "sg " }),
1456
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[g]" }),
1457
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "oal " }),
1458
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[n]" }),
1459
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "ew " }),
1460
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[p]" }),
1461
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "lan " }),
1462
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[w]" }),
1463
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "indow " }),
1464
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[R]" }),
1465
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "esume " }),
1466
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[q]" }),
1467
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "uit" })
1496
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1497
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[jk/\u2191\u2193]" }),
1498
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " scroll " }),
1499
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[h/\u2190/tab]" }),
1500
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " back " }),
1501
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[t]" }),
1502
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "oggle logs " }),
1503
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "\u2502 " }),
1504
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[m]" }),
1505
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "sg " }),
1506
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[g]" }),
1507
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "oal " }),
1508
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[n]" }),
1509
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "ew " }),
1510
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[p]" }),
1511
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "lan " }),
1512
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[w]" }),
1513
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "indow " }),
1514
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[R]" }),
1515
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "esume " }),
1516
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[q]" }),
1517
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "uit" })
1468
1518
  ] });
1469
1519
  }
1470
- return /* @__PURE__ */ jsxs9(Box10, { paddingX: 1, children: [
1471
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[hjkl]" }),
1472
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " navigate " }),
1473
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u2502 " }),
1474
- cursorNodeType === "context-file" && /* @__PURE__ */ jsxs9(Fragment3, { children: [
1475
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[e]" }),
1476
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "dit " }),
1477
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[\u23CE]" }),
1478
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " open " })
1520
+ return /* @__PURE__ */ jsxs5(Box8, { paddingX: 1, children: [
1521
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[hjkl]" }),
1522
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " navigate " }),
1523
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "\u2502 " }),
1524
+ cursorNodeType === "context-file" && /* @__PURE__ */ jsxs5(Fragment, { children: [
1525
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[e]" }),
1526
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "dit " }),
1527
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[\u23CE]" }),
1528
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " open " })
1479
1529
  ] }),
1480
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[space]" }),
1481
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " leader " }),
1482
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[tab]" }),
1483
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " detail " }),
1484
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[t]" }),
1485
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "oggle logs " }),
1486
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "\u2502 " }),
1487
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[m]" }),
1488
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "sg " }),
1489
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[n]" }),
1490
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "ew " }),
1491
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[R]" }),
1492
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "esume " }),
1493
- /* @__PURE__ */ jsx10(Text10, { bold: true, children: "[q]" }),
1494
- /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "uit" })
1530
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[space]" }),
1531
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " leader " }),
1532
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[tab]" }),
1533
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: " detail " }),
1534
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[t]" }),
1535
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "oggle logs " }),
1536
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "\u2502 " }),
1537
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[m]" }),
1538
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "sg " }),
1539
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[n]" }),
1540
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "ew " }),
1541
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[R]" }),
1542
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "esume " }),
1543
+ /* @__PURE__ */ jsx10(Text8, { bold: true, children: "[q]" }),
1544
+ /* @__PURE__ */ jsx10(Text8, { dimColor: true, children: "uit" })
1495
1545
  ] });
1496
1546
  }
1497
1547
 
1498
1548
  // src/tui/components/LeaderOverlay.tsx
1499
- import { Box as Box11, Text as Text11 } from "ink";
1500
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1549
+ import { Box as Box9, Text as Text9 } from "ink";
1550
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
1501
1551
  var LEADER_WIDTH = 26;
1502
1552
  var LEADER_HEIGHT = 19;
1503
1553
  var COPY_HEIGHT = 9;
@@ -1507,8 +1557,8 @@ function pad(s) {
1507
1557
  }
1508
1558
  function LeaderOverlay({ mode, rows, cols }) {
1509
1559
  if (mode === "leader") {
1510
- return /* @__PURE__ */ jsxs10(
1511
- Box11,
1560
+ return /* @__PURE__ */ jsxs6(
1561
+ Box9,
1512
1562
  {
1513
1563
  position: "absolute",
1514
1564
  marginTop: rows - LEADER_HEIGHT - 2,
@@ -1518,30 +1568,30 @@ function LeaderOverlay({ mode, rows, cols }) {
1518
1568
  borderStyle: "round",
1519
1569
  borderColor: "magenta",
1520
1570
  children: [
1521
- /* @__PURE__ */ jsx11(Text11, { bold: true, color: "magenta", children: pad(" LEADER") }),
1522
- /* @__PURE__ */ jsx11(Text11, { children: pad(" ") }),
1523
- /* @__PURE__ */ jsx11(Text11, { children: pad(" y copy menu") }),
1524
- /* @__PURE__ */ jsx11(Text11, { children: pad(" d delete session") }),
1525
- /* @__PURE__ */ jsx11(Text11, { children: pad(" l daemon logs") }),
1526
- /* @__PURE__ */ jsx11(Text11, { children: pad(" o open session dir") }),
1527
- /* @__PURE__ */ jsx11(Text11, { children: pad(" a spawn agent") }),
1528
- /* @__PURE__ */ jsx11(Text11, { children: pad(" m message agent") }),
1529
- /* @__PURE__ */ jsx11(Text11, { children: pad(" / search") }),
1530
- /* @__PURE__ */ jsx11(Text11, { children: pad(" ! shell command") }),
1531
- /* @__PURE__ */ jsx11(Text11, { children: pad(" j jump to pane") }),
1532
- /* @__PURE__ */ jsx11(Text11, { children: pad(" k kill session/agent") }),
1533
- /* @__PURE__ */ jsx11(Text11, { children: pad(" q quit") }),
1534
- /* @__PURE__ */ jsx11(Text11, { children: pad(" ? help") }),
1535
- /* @__PURE__ */ jsx11(Text11, { children: pad(" 1-9 jump to session") }),
1536
- /* @__PURE__ */ jsx11(Text11, { children: pad(" ") }),
1537
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: pad(" esc dismiss") })
1571
+ /* @__PURE__ */ jsx11(Text9, { bold: true, color: "magenta", children: pad(" LEADER") }),
1572
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" ") }),
1573
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" y copy menu") }),
1574
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" d delete session") }),
1575
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" l daemon logs") }),
1576
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" o open session dir") }),
1577
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" a spawn agent") }),
1578
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" m message agent") }),
1579
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" / search") }),
1580
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" ! shell command") }),
1581
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" j jump to pane") }),
1582
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" k kill session/agent") }),
1583
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" q quit") }),
1584
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" ? help") }),
1585
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" 1-9 jump to session") }),
1586
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" ") }),
1587
+ /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: pad(" esc dismiss") })
1538
1588
  ]
1539
1589
  }
1540
1590
  );
1541
1591
  }
1542
1592
  if (mode === "copy-menu") {
1543
- return /* @__PURE__ */ jsxs10(
1544
- Box11,
1593
+ return /* @__PURE__ */ jsxs6(
1594
+ Box9,
1545
1595
  {
1546
1596
  position: "absolute",
1547
1597
  marginTop: rows - COPY_HEIGHT - 2,
@@ -1551,13 +1601,13 @@ function LeaderOverlay({ mode, rows, cols }) {
1551
1601
  borderStyle: "round",
1552
1602
  borderColor: "cyan",
1553
1603
  children: [
1554
- /* @__PURE__ */ jsx11(Text11, { bold: true, color: "cyan", children: pad(" COPY") }),
1555
- /* @__PURE__ */ jsx11(Text11, { children: pad(" ") }),
1556
- /* @__PURE__ */ jsx11(Text11, { children: pad(" p session path") }),
1557
- /* @__PURE__ */ jsx11(Text11, { children: pad(" C LLM context") }),
1558
- /* @__PURE__ */ jsx11(Text11, { children: pad(" l logs content") }),
1559
- /* @__PURE__ */ jsx11(Text11, { children: pad(" s session ID") }),
1560
- /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: pad(" esc cancel") })
1604
+ /* @__PURE__ */ jsx11(Text9, { bold: true, color: "cyan", children: pad(" COPY") }),
1605
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" ") }),
1606
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" p session path") }),
1607
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" C LLM context") }),
1608
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" l logs content") }),
1609
+ /* @__PURE__ */ jsx11(Text9, { children: pad(" s session ID") }),
1610
+ /* @__PURE__ */ jsx11(Text9, { dimColor: true, children: pad(" esc cancel") })
1561
1611
  ]
1562
1612
  }
1563
1613
  );
@@ -1566,8 +1616,8 @@ function LeaderOverlay({ mode, rows, cols }) {
1566
1616
  }
1567
1617
 
1568
1618
  // src/tui/components/HelpOverlay.tsx
1569
- import { Box as Box12, Text as Text12 } from "ink";
1570
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1619
+ import { Box as Box10, Text as Text10 } from "ink";
1620
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
1571
1621
  var HELP_WIDTH = 62;
1572
1622
  var INNER2 = HELP_WIDTH - 2;
1573
1623
  function pad2(s) {
@@ -1602,8 +1652,8 @@ function HelpOverlay({ mode, rows, cols }) {
1602
1652
  row(" y \u2192 l logs content", " y \u2192 s session ID")
1603
1653
  ];
1604
1654
  const overlayHeight = Math.min(lines.length + 4, rows - 2);
1605
- return /* @__PURE__ */ jsxs11(
1606
- Box12,
1655
+ return /* @__PURE__ */ jsxs7(
1656
+ Box10,
1607
1657
  {
1608
1658
  position: "absolute",
1609
1659
  marginTop: Math.max(0, Math.floor((rows - overlayHeight) / 2)),
@@ -1613,13 +1663,13 @@ function HelpOverlay({ mode, rows, cols }) {
1613
1663
  borderStyle: "round",
1614
1664
  borderColor: "yellow",
1615
1665
  children: [
1616
- /* @__PURE__ */ jsx12(Text12, { bold: true, color: "yellow", children: pad2(" KEYBINDINGS (esc or ? to close)") }),
1617
- /* @__PURE__ */ jsx12(Text12, { children: pad2(" ") }),
1666
+ /* @__PURE__ */ jsx12(Text10, { bold: true, color: "yellow", children: pad2(" KEYBINDINGS (esc or ? to close)") }),
1667
+ /* @__PURE__ */ jsx12(Text10, { children: pad2(" ") }),
1618
1668
  lines.map((line, i) => {
1619
- if (line === "") return /* @__PURE__ */ jsx12(Text12, { children: pad2(" ") }, i);
1620
- return /* @__PURE__ */ jsx12(Text12, { children: pad2(line) }, i);
1669
+ if (line === "") return /* @__PURE__ */ jsx12(Text10, { children: pad2(" ") }, i);
1670
+ return /* @__PURE__ */ jsx12(Text10, { children: pad2(line) }, i);
1621
1671
  }),
1622
- /* @__PURE__ */ jsx12(Text12, { children: pad2(" ") })
1672
+ /* @__PURE__ */ jsx12(Text10, { children: pad2(" ") })
1623
1673
  ]
1624
1674
  }
1625
1675
  );
@@ -1629,38 +1679,8 @@ function HelpOverlay({ mode, rows, cols }) {
1629
1679
  import { useState as useState3, useEffect as useEffect2, useRef as useRef2, useCallback } from "react";
1630
1680
 
1631
1681
  // src/tui/lib/client.ts
1632
- import { connect } from "net";
1633
1682
  function send(request) {
1634
- const sock = socketPath();
1635
- return new Promise((resolve, reject) => {
1636
- const socket = connect(sock);
1637
- let data = "";
1638
- const timeout = setTimeout(() => {
1639
- socket.destroy();
1640
- reject(new Error("Request timed out"));
1641
- }, 5e3);
1642
- socket.on("connect", () => {
1643
- socket.write(JSON.stringify(request) + "\n");
1644
- });
1645
- socket.on("data", (chunk) => {
1646
- data += chunk.toString();
1647
- const idx = data.indexOf("\n");
1648
- if (idx !== -1) {
1649
- clearTimeout(timeout);
1650
- const line = data.slice(0, idx);
1651
- socket.destroy();
1652
- try {
1653
- resolve(JSON.parse(line));
1654
- } catch {
1655
- reject(new Error(`Invalid JSON from daemon`));
1656
- }
1657
- }
1658
- });
1659
- socket.on("error", (err) => {
1660
- clearTimeout(timeout);
1661
- reject(err);
1662
- });
1663
- });
1683
+ return rawSend(request, 5e3);
1664
1684
  }
1665
1685
 
1666
1686
  // src/tui/hooks/usePolling.ts
@@ -1672,23 +1692,6 @@ import { execSync } from "child_process";
1672
1692
  import { join } from "path";
1673
1693
  import { readFileSync, writeFileSync, mkdtempSync, rmSync, cpSync, existsSync, mkdirSync } from "fs";
1674
1694
  import { tmpdir } from "os";
1675
- var EXEC_ENV = {
1676
- ...process.env,
1677
- PATH: `/opt/homebrew/bin:/usr/local/bin:${process.env["PATH"] ?? "/usr/bin:/bin"}`
1678
- };
1679
- function exec(cmd) {
1680
- return execSync(cmd, { encoding: "utf-8", env: EXEC_ENV }).trim();
1681
- }
1682
- function execSafe(cmd) {
1683
- try {
1684
- return execSync(cmd, { encoding: "utf-8", env: EXEC_ENV, stdio: ["pipe", "pipe", "pipe"] }).trim();
1685
- } catch {
1686
- return null;
1687
- }
1688
- }
1689
- function shellQuote(s) {
1690
- return `'${s.replace(/'/g, "'\\''")}'`;
1691
- }
1692
1695
  function selectWindow(windowId) {
1693
1696
  execSafe(`tmux select-window -t "${windowId}"`);
1694
1697
  }
@@ -1727,7 +1730,7 @@ Run \`sisyphus list\` and \`sisyphus status\` to see current state.`;
1727
1730
  const rendered = template.replace(/\{\{CWD\}\}/g, cwd2);
1728
1731
  const promptPath = join(globalDir(), "dashboard-companion-prompt.md");
1729
1732
  writeFileSync(promptPath, rendered, "utf-8");
1730
- const pathEnv = `/opt/homebrew/bin:/usr/local/bin:${process.env["PATH"] ?? "/usr/bin:/bin"}`;
1733
+ const pathEnv = augmentedPath();
1731
1734
  const claudeCmd = `SISYPHUS_COMPANION_CWD=${shellQuote(cwd2)} PATH=${shellQuote(pathEnv)} claude --dangerously-skip-permissions --plugin-dir ${shellQuote(pluginDir)} --append-system-prompt "$(cat ${shellQuote(promptPath)})"`;
1732
1735
  const result = exec(
1733
1736
  `tmux split-window -h -d -l 33% -P -F "#{pane_id}" -c ${shellQuote(cwd2)} ${shellQuote(claudeCmd)}`
@@ -1799,6 +1802,15 @@ function usePolling(cwd2, selectedSessionId, intervalMs = 2500) {
1799
1802
  const listRes = await send({ type: "list", cwd: cwd2 });
1800
1803
  if (!mountedRef.current) return;
1801
1804
  const sessions = listRes.ok ? listRes.data?.sessions ?? [] : [];
1805
+ for (const s of sessions) {
1806
+ if (s.status !== "completed" && s.tmuxWindowId) {
1807
+ try {
1808
+ s.windowAlive = windowExists(s.tmuxWindowId);
1809
+ } catch {
1810
+ s.windowAlive = false;
1811
+ }
1812
+ }
1813
+ }
1802
1814
  let selectedSession = null;
1803
1815
  let planContent = "";
1804
1816
  let goalContent = "";
@@ -1812,11 +1824,8 @@ function usePolling(cwd2, selectedSessionId, intervalMs = 2500) {
1812
1824
  selectedSession = statusRes.data?.session ?? null;
1813
1825
  }
1814
1826
  if (selectedSession?.tmuxWindowId) {
1815
- try {
1816
- paneAlive = windowExists(selectedSession.tmuxWindowId);
1817
- } catch {
1818
- paneAlive = false;
1819
- }
1827
+ const cached = sessions.find((s) => s.id === selectedIdRef.current);
1828
+ paneAlive = cached?.windowAlive ?? false;
1820
1829
  }
1821
1830
  try {
1822
1831
  const pp = roadmapPath(cwd2, selectedIdRef.current);
@@ -1855,7 +1864,11 @@ function usePolling(cwd2, selectedSessionId, intervalMs = 2500) {
1855
1864
  }
1856
1865
  }
1857
1866
  if (mountedRef.current) {
1858
- setState({ sessions, selectedSession, planContent, goalContent, logsContent, logsCycles, paneAlive, contextFiles, error: null });
1867
+ const next = { sessions, selectedSession, planContent, goalContent, logsContent, logsCycles, paneAlive, contextFiles, error: null };
1868
+ setState((prev) => {
1869
+ if (JSON.stringify(prev) === JSON.stringify(next)) return prev;
1870
+ return next;
1871
+ });
1859
1872
  }
1860
1873
  } catch (err) {
1861
1874
  if (mountedRef.current) {
@@ -2100,15 +2113,14 @@ function copyToClipboard(text) {
2100
2113
  }
2101
2114
 
2102
2115
  // src/tui/lib/tree.ts
2103
- import { readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
2104
2116
  import { join as join3 } from "path";
2105
2117
  function sessionSortKey(s) {
2106
2118
  if (s.status === "completed") return 4;
2107
- const open = s.tmuxWindowId ? windowExists(s.tmuxWindowId) : false;
2119
+ const open = s.windowAlive ?? false;
2108
2120
  if (s.status === "active") return open ? 0 : 1;
2109
2121
  return open ? 2 : 3;
2110
2122
  }
2111
- function buildTree(sessions, selectedSession, expanded, cwd2) {
2123
+ function buildTree(sessions, selectedSession, expanded, cwd2, polledContextFiles = []) {
2112
2124
  const nodes = [];
2113
2125
  const sorted = [...sessions].sort((a, b) => {
2114
2126
  const keyDiff = sessionSortKey(a) - sessionSortKey(b);
@@ -2213,7 +2225,7 @@ function buildTree(sessions, selectedSession, expanded, cwd2) {
2213
2225
  });
2214
2226
  if (msgsExpanded) {
2215
2227
  for (const msg of messages) {
2216
- const sourceLabel2 = msg.source.type === "user" ? "You" : msg.source.type === "agent" ? msg.source.agentId : "system";
2228
+ const sourceLabel = msg.source.type === "user" ? "You" : msg.source.type === "agent" ? msg.source.agentId : "system";
2217
2229
  nodes.push({
2218
2230
  id: `message:${s.id}:${msg.id}`,
2219
2231
  type: "message",
@@ -2222,23 +2234,14 @@ function buildTree(sessions, selectedSession, expanded, cwd2) {
2222
2234
  expanded: false,
2223
2235
  sessionId: s.id,
2224
2236
  messageId: msg.id,
2225
- source: sourceLabel2,
2237
+ source: sourceLabel,
2226
2238
  summary: msg.summary || msg.content,
2227
2239
  timestamp: msg.timestamp
2228
2240
  });
2229
2241
  }
2230
2242
  }
2231
2243
  }
2232
- const ctxDir = contextDir(cwd2, s.id);
2233
- let contextFiles = [];
2234
- try {
2235
- if (existsSync3(ctxDir)) {
2236
- contextFiles = readdirSync2(ctxDir).filter(
2237
- (f) => !f.startsWith(".")
2238
- ).sort();
2239
- }
2240
- } catch {
2241
- }
2244
+ const contextFiles = isSelected ? polledContextFiles : [];
2242
2245
  const ctxNodeId = `context:${s.id}`;
2243
2246
  const ctxExpanded = expanded.has(ctxNodeId);
2244
2247
  nodes.push({
@@ -2260,7 +2263,7 @@ function buildTree(sessions, selectedSession, expanded, cwd2) {
2260
2263
  expanded: false,
2261
2264
  sessionId: s.id,
2262
2265
  label: filename,
2263
- filePath: join3(ctxDir, filename)
2266
+ filePath: join3(contextDir(cwd2, s.id), filename)
2264
2267
  });
2265
2268
  }
2266
2269
  }
@@ -2279,8 +2282,8 @@ function findParentIndex(nodes, index) {
2279
2282
  }
2280
2283
 
2281
2284
  // src/tui/App.tsx
2282
- import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
2283
- import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
2285
+ import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
2286
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
2284
2287
  function resolveEditor(configEditor) {
2285
2288
  if (configEditor) return configEditor;
2286
2289
  if (process.env.EDITOR) return process.env.EDITOR;
@@ -2306,16 +2309,16 @@ function App({ cwd: cwd2 }) {
2306
2309
  const cursorNodeIdRef = useRef3(null);
2307
2310
  const prevNodesRef = useRef3([]);
2308
2311
  const { sessions, selectedSession, planContent, goalContent, logsContent, logsCycles, paneAlive, contextFiles, error } = usePolling(cwd2, selectedSessionId);
2309
- const filteredSessions = useMemo4(() => {
2312
+ const filteredSessions = useMemo6(() => {
2310
2313
  if (!searchFilter) return sessions;
2311
2314
  const q = searchFilter.toLowerCase();
2312
2315
  return sessions.filter(
2313
2316
  (s) => s.task.toLowerCase().includes(q) || s.id.toLowerCase().includes(q)
2314
2317
  );
2315
2318
  }, [sessions, searchFilter]);
2316
- const nodes = useMemo4(
2317
- () => buildTree(filteredSessions, selectedSession, expanded, cwd2),
2318
- [filteredSessions, selectedSession, expanded, cwd2]
2319
+ const nodes = useMemo6(
2320
+ () => buildTree(filteredSessions, selectedSession, expanded, cwd2, contextFiles),
2321
+ [filteredSessions, selectedSession, expanded, cwd2, contextFiles]
2319
2322
  );
2320
2323
  if (nodes === prevNodesRef.current) {
2321
2324
  const node = nodes[cursorIndex];
@@ -2989,29 +2992,29 @@ function App({ cwd: cwd2 }) {
2989
2992
  setFocusPane("tree");
2990
2993
  setTargetAgentId(null);
2991
2994
  }, []);
2992
- const reportAgent = useMemo4(() => {
2995
+ const reportAgent = useMemo6(() => {
2993
2996
  if (mode === "report-detail") return getAgentForNode(cursorNode);
2994
2997
  return null;
2995
2998
  }, [mode, cursorNode, getAgentForNode]);
2996
- const reportBlocks = useMemo4(
2999
+ const reportBlocks = useMemo6(
2997
3000
  () => reportAgent ? resolveReports(reportAgent.reports) : [],
2998
3001
  [reportAgent]
2999
3002
  );
3000
- const detailAgent = useMemo4(() => {
3003
+ const detailAgent = useMemo6(() => {
3001
3004
  if (!cursorNode) return null;
3002
3005
  if (cursorNode.type === "agent" || cursorNode.type === "report") {
3003
3006
  return getAgentForNode(cursorNode);
3004
3007
  }
3005
3008
  return null;
3006
3009
  }, [cursorNode, getAgentForNode]);
3007
- const detailReportBlocks = useMemo4(
3010
+ const detailReportBlocks = useMemo6(
3008
3011
  () => detailAgent ? resolveReports(detailAgent.reports) : [],
3009
3012
  [detailAgent]
3010
3013
  );
3011
- const contextFileContent = useMemo4(() => {
3014
+ const contextFileContent = useMemo6(() => {
3012
3015
  if (!cursorNode || cursorNode.type !== "context-file") return null;
3013
3016
  try {
3014
- if (existsSync4(cursorNode.filePath)) {
3017
+ if (existsSync3(cursorNode.filePath)) {
3015
3018
  return readFileSync3(cursorNode.filePath, "utf-8");
3016
3019
  }
3017
3020
  } catch {
@@ -3075,7 +3078,9 @@ function App({ cwd: cwd2 }) {
3075
3078
  logsContent,
3076
3079
  width: detailWidth2,
3077
3080
  height: contentHeight2,
3078
- paneAlive
3081
+ paneAlive,
3082
+ scrollOffset: detailScrollOffset,
3083
+ focused: focusPane === "detail"
3079
3084
  }
3080
3085
  );
3081
3086
  }
@@ -3085,7 +3090,9 @@ function App({ cwd: cwd2 }) {
3085
3090
  cycle,
3086
3091
  agents: session.agents,
3087
3092
  width: detailWidth2,
3088
- height: contentHeight2
3093
+ height: contentHeight2,
3094
+ scrollOffset: detailScrollOffset,
3095
+ focused: focusPane === "detail"
3089
3096
  }
3090
3097
  );
3091
3098
  }
@@ -3100,7 +3107,9 @@ function App({ cwd: cwd2 }) {
3100
3107
  logsContent,
3101
3108
  width: detailWidth2,
3102
3109
  height: contentHeight2,
3103
- paneAlive
3110
+ paneAlive,
3111
+ scrollOffset: detailScrollOffset,
3112
+ focused: focusPane === "detail"
3104
3113
  }
3105
3114
  );
3106
3115
  }
@@ -3110,7 +3119,9 @@ function App({ cwd: cwd2 }) {
3110
3119
  agent,
3111
3120
  reportBlocks: detailReportBlocks,
3112
3121
  width: detailWidth2,
3113
- height: contentHeight2
3122
+ height: contentHeight2,
3123
+ scrollOffset: detailScrollOffset,
3124
+ focused: focusPane === "detail"
3114
3125
  }
3115
3126
  );
3116
3127
  }
@@ -3125,7 +3136,9 @@ function App({ cwd: cwd2 }) {
3125
3136
  logsContent,
3126
3137
  width: detailWidth2,
3127
3138
  height: contentHeight2,
3128
- paneAlive
3139
+ paneAlive,
3140
+ scrollOffset: detailScrollOffset,
3141
+ focused: focusPane === "detail"
3129
3142
  }
3130
3143
  );
3131
3144
  }
@@ -3137,45 +3150,22 @@ function App({ cwd: cwd2 }) {
3137
3150
  if (specificBlock) {
3138
3151
  const badge = specificBlock.type === "final" ? "FINAL" : "UPDATE";
3139
3152
  const badgeColor = specificBlock.type === "final" ? "cyan" : "yellow";
3140
- const reportLines = wrapText(specificBlock.content.trim(), detailWidth2 - 8);
3141
- const viewableLines = contentHeight2 - 7;
3142
- return /* @__PURE__ */ jsxs12(
3143
- Box13,
3153
+ const reportContentLines = [
3154
+ [seg(" "), seg(badge, { color: badgeColor }), seg(` ${agent.id} \xB7 ${agent.name !== agent.id ? agent.name : agent.agentType}`, { bold: true })],
3155
+ singleLine(` ${formatTime(specificBlock.timestamp)}`, { dim: true }),
3156
+ singleLine(" "),
3157
+ [seg(" \u258E CONTENT", { color: badgeColor, bold: true })],
3158
+ ...wrapText(specificBlock.content.trim(), detailWidth2 - 8).map((l) => singleLine(` ${l}`))
3159
+ ];
3160
+ return /* @__PURE__ */ jsx13(
3161
+ ScrollablePanel,
3144
3162
  {
3145
- flexDirection: "column",
3163
+ lines: reportContentLines,
3146
3164
  width: detailWidth2,
3147
- borderStyle: "round",
3148
- borderColor: badgeColor,
3149
- paddingX: 1,
3150
- children: [
3151
- /* @__PURE__ */ jsxs12(Text13, { bold: true, children: [
3152
- " ",
3153
- /* @__PURE__ */ jsx13(Text13, { color: badgeColor, children: badge }),
3154
- " ",
3155
- agent.id,
3156
- " \xB7 ",
3157
- agent.name !== agent.id ? agent.name : agent.agentType
3158
- ] }),
3159
- /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3160
- " ",
3161
- formatTime(specificBlock.timestamp)
3162
- ] }),
3163
- /* @__PURE__ */ jsx13(Text13, { children: " " }),
3164
- /* @__PURE__ */ jsxs12(Text13, { color: badgeColor, bold: true, children: [
3165
- " ",
3166
- "\u258E CONTENT"
3167
- ] }),
3168
- reportLines.slice(0, viewableLines).map((line, i) => /* @__PURE__ */ jsxs12(Text13, { children: [
3169
- " ",
3170
- line
3171
- ] }, i)),
3172
- reportLines.length > viewableLines && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3173
- " ",
3174
- "\u2026 ",
3175
- reportLines.length - viewableLines,
3176
- " more lines [enter] full view"
3177
- ] })
3178
- ]
3165
+ height: contentHeight2,
3166
+ scrollOffset: detailScrollOffset,
3167
+ focused: focusPane === "detail",
3168
+ borderColor: badgeColor
3179
3169
  }
3180
3170
  );
3181
3171
  }
@@ -3185,127 +3175,114 @@ function App({ cwd: cwd2 }) {
3185
3175
  agent,
3186
3176
  reportBlocks: detailReportBlocks,
3187
3177
  width: detailWidth2,
3188
- height: contentHeight2
3178
+ height: contentHeight2,
3179
+ scrollOffset: detailScrollOffset,
3180
+ focused: focusPane === "detail"
3189
3181
  }
3190
3182
  );
3191
3183
  }
3192
- case "messages":
3193
- return /* @__PURE__ */ jsxs12(
3194
- Box13,
3184
+ case "messages": {
3185
+ const msgsLines = [
3186
+ singleLine(` Messages (${session.messages.length})`, { bold: true })
3187
+ ];
3188
+ if (session.messages.length === 0) {
3189
+ msgsLines.push(singleLine(" No messages", { dim: true, italic: true }));
3190
+ } else {
3191
+ for (const msg of session.messages) {
3192
+ const time = formatTime(msg.timestamp);
3193
+ const label = msg.source.type === "user" ? "You" : msg.source.type === "agent" ? msg.source.agentId : "system";
3194
+ const labelColor = msg.source.type === "user" ? "yellow" : msg.source.type === "agent" ? "cyan" : "gray";
3195
+ const maxContent = Math.max(10, detailWidth2 - label.length - 20);
3196
+ msgsLines.push([
3197
+ seg(` [${time}] `, { dim: true }),
3198
+ seg(`${label}: `, { color: labelColor, bold: true }),
3199
+ seg(wrapText(msg.summary || msg.content, maxContent)[0] || "", {})
3200
+ ]);
3201
+ }
3202
+ }
3203
+ return /* @__PURE__ */ jsx13(
3204
+ ScrollablePanel,
3195
3205
  {
3196
- flexDirection: "column",
3206
+ lines: msgsLines,
3197
3207
  width: detailWidth2,
3198
- borderStyle: "round",
3199
- borderColor: "gray",
3200
- paddingX: 1,
3201
- children: [
3202
- /* @__PURE__ */ jsxs12(Text13, { bold: true, children: [
3203
- " Messages (",
3204
- session.messages.length,
3205
- ")"
3206
- ] }),
3207
- /* @__PURE__ */ jsx13(
3208
- MessageLog,
3209
- {
3210
- messages: session.messages,
3211
- maxMessages: contentHeight2 - 4,
3212
- width: detailWidth2 - 4
3213
- }
3214
- )
3215
- ]
3208
+ height: contentHeight2,
3209
+ scrollOffset: detailScrollOffset,
3210
+ focused: focusPane === "detail"
3216
3211
  }
3217
3212
  );
3213
+ }
3218
3214
  case "message": {
3219
3215
  const msg = session.messages.find((m) => m.id === cursorNode.messageId);
3220
- return /* @__PURE__ */ jsxs12(
3221
- Box13,
3216
+ const msgContentLines = [
3217
+ singleLine(" Message", { bold: true })
3218
+ ];
3219
+ if (msg) {
3220
+ msgContentLines.push(singleLine(` ${cursorNode.source} \xB7 ${cursorNode.timestamp}`, { dim: true }));
3221
+ for (const l of wrapText(msg.content, detailWidth2 - 8)) {
3222
+ msgContentLines.push(singleLine(` ${l}`));
3223
+ }
3224
+ } else {
3225
+ msgContentLines.push(singleLine(" Message not found", { dim: true }));
3226
+ }
3227
+ return /* @__PURE__ */ jsx13(
3228
+ ScrollablePanel,
3222
3229
  {
3223
- flexDirection: "column",
3230
+ lines: msgContentLines,
3224
3231
  width: detailWidth2,
3225
- borderStyle: "round",
3226
- borderColor: "gray",
3227
- paddingX: 1,
3228
- children: [
3229
- /* @__PURE__ */ jsx13(Text13, { bold: true, children: " Message" }),
3230
- msg ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
3231
- /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3232
- " ",
3233
- cursorNode.source,
3234
- " \xB7 ",
3235
- cursorNode.timestamp
3236
- ] }),
3237
- /* @__PURE__ */ jsxs12(Text13, { children: [
3238
- " ",
3239
- msg.content
3240
- ] })
3241
- ] }) : /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Message not found" })
3242
- ]
3232
+ height: contentHeight2,
3233
+ scrollOffset: detailScrollOffset,
3234
+ focused: focusPane === "detail"
3243
3235
  }
3244
3236
  );
3245
3237
  }
3246
- case "context":
3247
- return /* @__PURE__ */ jsxs12(
3248
- Box13,
3238
+ case "context": {
3239
+ const ctxLines = [
3240
+ [seg(" "), seg("\u229E", { color: "white" }), seg(` Context (${contextFiles.length})`, { bold: true })]
3241
+ ];
3242
+ if (contextFiles.length === 0) {
3243
+ ctxLines.push(singleLine(" No context files found.", { dim: true }));
3244
+ } else {
3245
+ for (const f of contextFiles) {
3246
+ ctxLines.push(singleLine(` \xB7 ${f}`, { dim: true }));
3247
+ }
3248
+ }
3249
+ return /* @__PURE__ */ jsx13(
3250
+ ScrollablePanel,
3249
3251
  {
3250
- flexDirection: "column",
3252
+ lines: ctxLines,
3251
3253
  width: detailWidth2,
3252
- borderStyle: "round",
3253
- borderColor: "gray",
3254
- paddingX: 1,
3255
- children: [
3256
- /* @__PURE__ */ jsxs12(Text13, { bold: true, children: [
3257
- " ",
3258
- /* @__PURE__ */ jsx13(Text13, { color: "white", children: "\u229E" }),
3259
- " Context (",
3260
- contextFiles.length,
3261
- ")"
3262
- ] }),
3263
- contextFiles.length === 0 ? /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3264
- " ",
3265
- "No context files found."
3266
- ] }) : contextFiles.map((f) => /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3267
- " \xB7 ",
3268
- f
3269
- ] }, f))
3270
- ]
3254
+ height: contentHeight2,
3255
+ scrollOffset: detailScrollOffset,
3256
+ focused: focusPane === "detail"
3271
3257
  }
3272
3258
  );
3259
+ }
3273
3260
  case "context-file": {
3274
- const fileLines = contextFileContent != null ? wrapText(cleanMarkdown(stripFrontmatter(contextFileContent)), detailWidth2 - 8) : [];
3275
- const viewableLines = contentHeight2 - 6;
3276
- return /* @__PURE__ */ jsxs12(
3277
- Box13,
3261
+ const ctxFileLines = [
3262
+ [seg(" "), seg("\u229E", { color: "white" }), seg(` ${cursorNode.label}`, { bold: true })],
3263
+ singleLine(" ")
3264
+ ];
3265
+ if (contextFileContent == null) {
3266
+ ctxFileLines.push(singleLine(" File not found or unreadable.", { dim: true }));
3267
+ } else {
3268
+ const wrapped = wrapText(cleanMarkdown(stripFrontmatter(contextFileContent)), detailWidth2 - 8);
3269
+ if (wrapped.length === 0) {
3270
+ ctxFileLines.push(singleLine(" (empty)", { dim: true }));
3271
+ } else {
3272
+ for (const l of wrapped) {
3273
+ ctxFileLines.push(singleLine(` ${l}`));
3274
+ }
3275
+ }
3276
+ }
3277
+ return /* @__PURE__ */ jsx13(
3278
+ ScrollablePanel,
3278
3279
  {
3279
- flexDirection: "column",
3280
+ lines: ctxFileLines,
3280
3281
  width: detailWidth2,
3281
- borderStyle: "round",
3282
- borderColor: "white",
3283
- paddingX: 1,
3284
- children: [
3285
- /* @__PURE__ */ jsxs12(Text13, { bold: true, children: [
3286
- " ",
3287
- /* @__PURE__ */ jsx13(Text13, { color: "white", children: "\u229E" }),
3288
- " ",
3289
- cursorNode.label
3290
- ] }),
3291
- /* @__PURE__ */ jsx13(Text13, { children: " " }),
3292
- contextFileContent == null ? /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3293
- " ",
3294
- "File not found or unreadable."
3295
- ] }) : fileLines.length === 0 ? /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3296
- " ",
3297
- "(empty)"
3298
- ] }) : fileLines.slice(0, viewableLines).map((line, i) => /* @__PURE__ */ jsxs12(Text13, { children: [
3299
- " ",
3300
- line
3301
- ] }, i)),
3302
- fileLines.length > viewableLines && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3303
- " ",
3304
- "\u2026 ",
3305
- fileLines.length - viewableLines,
3306
- " more lines"
3307
- ] })
3308
- ]
3282
+ height: contentHeight2,
3283
+ scrollOffset: detailScrollOffset,
3284
+ focused: focusPane === "detail",
3285
+ borderColor: "white"
3309
3286
  }
3310
3287
  );
3311
3288
  }
@@ -3318,15 +3295,30 @@ function App({ cwd: cwd2 }) {
3318
3295
  goalContent,
3319
3296
  width: detailWidth2,
3320
3297
  height: contentHeight2,
3321
- paneAlive
3298
+ paneAlive,
3299
+ scrollOffset: detailScrollOffset,
3300
+ focused: focusPane === "detail"
3322
3301
  }
3323
3302
  );
3324
3303
  }
3325
3304
  },
3326
3305
  [cursorNode, session, planContent, goalContent, logsContent, paneAlive, agents, mode, reportAgent, reportBlocks, detailReportBlocks, handleCancel, detailScrollOffset, focusPane, contextFiles, contextFileContent]
3327
3306
  );
3328
- return /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", width: cols, height: rows, children: [
3329
- /* @__PURE__ */ jsxs12(Box13, { flexDirection: "row", height: contentHeight, children: [
3307
+ if (cols < 60 || rows < 12) {
3308
+ return /* @__PURE__ */ jsxs8(Box11, { flexDirection: "column", width: cols, height: rows, justifyContent: "center", alignItems: "center", children: [
3309
+ /* @__PURE__ */ jsx13(Text11, { color: "yellow", bold: true, children: "Terminal too small" }),
3310
+ /* @__PURE__ */ jsxs8(Text11, { dimColor: true, children: [
3311
+ "Minimum: 60\xD712 (current: ",
3312
+ cols,
3313
+ "\xD7",
3314
+ rows,
3315
+ ")"
3316
+ ] }),
3317
+ /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: "Resize your terminal and try again." })
3318
+ ] });
3319
+ }
3320
+ return /* @__PURE__ */ jsxs8(Box11, { flexDirection: "column", width: cols, height: rows, children: [
3321
+ /* @__PURE__ */ jsxs8(Box11, { flexDirection: "row", height: contentHeight, children: [
3330
3322
  /* @__PURE__ */ jsx13(
3331
3323
  SessionTree,
3332
3324
  {
@@ -3349,8 +3341,8 @@ function App({ cwd: cwd2 }) {
3349
3341
  }
3350
3342
  )
3351
3343
  ] }),
3352
- notification && /* @__PURE__ */ jsx13(Box13, { paddingX: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "yellow", bold: true, children: /error|failed/i.test(notification) ? `\u2715 ${notification}` : /success|created|killed|sent|copied|deleted/i.test(notification) ? `\u2713 ${notification}` : `\u2139 ${notification}` }) }),
3353
- error && !notification && /* @__PURE__ */ jsx13(Box13, { paddingX: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: "red", children: [
3344
+ notification && /* @__PURE__ */ jsx13(Box11, { paddingX: 1, children: /* @__PURE__ */ jsx13(Text11, { color: "yellow", bold: true, children: /error|failed/i.test(notification) ? `\u2715 ${notification}` : /success|created|killed|sent|copied|deleted/i.test(notification) ? `\u2713 ${notification}` : `\u2139 ${notification}` }) }),
3345
+ error && !notification && /* @__PURE__ */ jsx13(Box11, { paddingX: 1, children: /* @__PURE__ */ jsxs8(Text11, { color: "red", children: [
3354
3346
  "\u26A0 ",
3355
3347
  error
3356
3348
  ] }) }),