@wrongstack/tui 0.8.4 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -0
- package/dist/index.js +384 -56
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -16,8 +16,8 @@ function stringifyInput(input) {
|
|
|
16
16
|
const obj = input;
|
|
17
17
|
return Object.entries(obj).filter(([k]) => k !== "content" && k !== "new_string").map(([k, v]) => `${k}: ${truncate(JSON.stringify(v), 80)}`).join(" ");
|
|
18
18
|
}
|
|
19
|
-
function truncate(
|
|
20
|
-
return
|
|
19
|
+
function truncate(s2, max) {
|
|
20
|
+
return s2.length <= max ? s2 : `${s2.slice(0, max - 1)}\u2026`;
|
|
21
21
|
}
|
|
22
22
|
function hasDiff(input) {
|
|
23
23
|
return Boolean(
|
|
@@ -677,11 +677,11 @@ function fmtElapsed(ms) {
|
|
|
677
677
|
const totalSec = Math.floor(ms / 1e3);
|
|
678
678
|
const h = Math.floor(totalSec / 3600);
|
|
679
679
|
const m = Math.floor(totalSec % 3600 / 60);
|
|
680
|
-
const
|
|
680
|
+
const s2 = totalSec % 60;
|
|
681
681
|
if (h > 0) {
|
|
682
|
-
return `${h}:${pad2(m)}:${pad2(
|
|
682
|
+
return `${h}:${pad2(m)}:${pad2(s2)}`;
|
|
683
683
|
}
|
|
684
|
-
return `${pad2(m)}:${pad2(
|
|
684
|
+
return `${pad2(m)}:${pad2(s2)}`;
|
|
685
685
|
}
|
|
686
686
|
function pad2(n) {
|
|
687
687
|
return n < 10 ? `0${n}` : String(n);
|
|
@@ -751,11 +751,11 @@ function FleetMonitor({
|
|
|
751
751
|
for (const e of all) {
|
|
752
752
|
events.push({ at: e.startedAt, icon: "\u25CF", color: "cyan", text: `${e.name} spawned` });
|
|
753
753
|
if (e.status !== "running" && e.status !== "idle") {
|
|
754
|
-
const
|
|
754
|
+
const s2 = STATUS[e.status];
|
|
755
755
|
events.push({
|
|
756
756
|
at: e.lastEventAt,
|
|
757
|
-
icon:
|
|
758
|
-
color:
|
|
757
|
+
icon: s2.icon,
|
|
758
|
+
color: s2.color,
|
|
759
759
|
text: `${e.name} ${e.status} (${e.toolCalls}t)`
|
|
760
760
|
});
|
|
761
761
|
}
|
|
@@ -824,12 +824,12 @@ function FleetMonitor({
|
|
|
824
824
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "cost" })
|
|
825
825
|
] }),
|
|
826
826
|
shown.map((e) => {
|
|
827
|
-
const
|
|
827
|
+
const s2 = STATUS[e.status];
|
|
828
828
|
const elapsed = e.status === "running" ? fmtElapsed(Math.max(0, nowTick - e.startedAt)) : fmtElapsed(Math.max(0, nowTick - e.lastEventAt)) + " ago";
|
|
829
829
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
830
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
830
|
+
/* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.icon }),
|
|
831
831
|
/* @__PURE__ */ jsx(Text, { children: e.name.padEnd(16).slice(0, 16) }),
|
|
832
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
832
|
+
/* @__PURE__ */ jsx(Text, { color: s2.color, children: e.status.padEnd(10) }),
|
|
833
833
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `L${e.iterations} ${e.toolCalls}t`.padEnd(8) }),
|
|
834
834
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed.padEnd(8).slice(0, 8) }),
|
|
835
835
|
/* @__PURE__ */ jsx(Text, { color: "yellow", children: fmtCost2(e.cost) }),
|
|
@@ -870,8 +870,8 @@ function fmtTokens2(n) {
|
|
|
870
870
|
if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
|
|
871
871
|
return `${(n / 1e6).toFixed(1)}M`;
|
|
872
872
|
}
|
|
873
|
-
function snippet(
|
|
874
|
-
const oneLine2 =
|
|
873
|
+
function snippet(s2, max = 72) {
|
|
874
|
+
const oneLine2 = s2.replace(/\s+/g, " ").trim();
|
|
875
875
|
if (oneLine2.length <= max) return oneLine2;
|
|
876
876
|
return `${oneLine2.slice(0, max - 1)}\u2026`;
|
|
877
877
|
}
|
|
@@ -931,7 +931,7 @@ function AgentsMonitor({
|
|
|
931
931
|
] }),
|
|
932
932
|
shown.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No live agents \u2014 spawn with /spawn or /fleet dispatch." }) : null,
|
|
933
933
|
shown.map((e) => {
|
|
934
|
-
const
|
|
934
|
+
const s2 = STATUS2[e.status];
|
|
935
935
|
const elapsed = e.status === "running" ? fmtElapsed(Math.max(0, nowTick - e.startedAt)) : e.status;
|
|
936
936
|
const spark = sparkline(bucketActivity(e.recentTools, nowTick));
|
|
937
937
|
const lastTool = e.recentTools[e.recentTools.length - 1];
|
|
@@ -940,7 +940,7 @@ function AgentsMonitor({
|
|
|
940
940
|
const toolElapsed = e.currentTool ? Math.max(0, nowTick - e.currentTool.startedAt) : 0;
|
|
941
941
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
942
942
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
943
|
-
/* @__PURE__ */ jsx(Text, { color:
|
|
943
|
+
/* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
|
|
944
944
|
/* @__PURE__ */ jsx(Text, { bold: true, children: e.name }),
|
|
945
945
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
946
946
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed }),
|
|
@@ -999,6 +999,179 @@ function AgentsMonitor({
|
|
|
999
999
|
})
|
|
1000
1000
|
] });
|
|
1001
1001
|
}
|
|
1002
|
+
var fmtElapsed2 = (ms) => {
|
|
1003
|
+
const s2 = Math.floor(ms / 1e3);
|
|
1004
|
+
const m = Math.floor(s2 / 60);
|
|
1005
|
+
const h = Math.floor(m / 60);
|
|
1006
|
+
if (h > 0) return `${h}:${String(m % 60).padStart(2, "0")}:${String(s2 % 60).padStart(2, "0")}`;
|
|
1007
|
+
if (m > 0) return `${m}:${String(s2 % 60).padStart(2, "0")}`;
|
|
1008
|
+
return `${s2}s`;
|
|
1009
|
+
};
|
|
1010
|
+
var PHASE_STATUS = {
|
|
1011
|
+
pending: { icon: "\u23F3", color: "gray", label: "pending" },
|
|
1012
|
+
ready: { icon: "\u{1F51C}", color: "cyan", label: "ready" },
|
|
1013
|
+
running: { icon: "\u25B6", color: "yellow", label: "running" },
|
|
1014
|
+
paused: { icon: "\u23F8", color: "magenta", label: "paused" },
|
|
1015
|
+
completed: { icon: "\u2713", color: "green", label: "done" },
|
|
1016
|
+
failed: { icon: "\u2717", color: "red", label: "failed" },
|
|
1017
|
+
skipped: { icon: "\u23ED", color: "gray", label: "skipped" }
|
|
1018
|
+
};
|
|
1019
|
+
function fmtPhase(s2) {
|
|
1020
|
+
return PHASE_STATUS[s2] ?? { icon: "?", color: "white", label: s2 };
|
|
1021
|
+
}
|
|
1022
|
+
function PhaseMonitor({
|
|
1023
|
+
phases,
|
|
1024
|
+
runningPhaseIds,
|
|
1025
|
+
elapsedMs,
|
|
1026
|
+
nowTick,
|
|
1027
|
+
onClose
|
|
1028
|
+
}) {
|
|
1029
|
+
useInput((_, key) => {
|
|
1030
|
+
if (key.escape) onClose();
|
|
1031
|
+
});
|
|
1032
|
+
const phaseList = Object.values(phases);
|
|
1033
|
+
const running = phaseList.filter((p) => runningPhaseIds.includes(Object.keys(phases).find((k) => phases[k] === p) ?? ""));
|
|
1034
|
+
const done = phaseList.filter((p) => p.status === "completed" || p.status === "skipped");
|
|
1035
|
+
const failed = phaseList.filter((p) => p.status === "failed");
|
|
1036
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
1037
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, marginBottom: 1, children: [
|
|
1038
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "PHASE MONITOR" }),
|
|
1039
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
1040
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1041
|
+
"\u23F1 ",
|
|
1042
|
+
fmtElapsed2(elapsedMs)
|
|
1043
|
+
] }),
|
|
1044
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
1045
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
1046
|
+
"\u25B6",
|
|
1047
|
+
running.length
|
|
1048
|
+
] }),
|
|
1049
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
1050
|
+
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
1051
|
+
"\u2713",
|
|
1052
|
+
done.length
|
|
1053
|
+
] }),
|
|
1054
|
+
failed.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1055
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
1056
|
+
/* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
1057
|
+
"\u2717",
|
|
1058
|
+
failed.length
|
|
1059
|
+
] })
|
|
1060
|
+
] }) : null,
|
|
1061
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+P / Esc to close" })
|
|
1062
|
+
] }),
|
|
1063
|
+
phaseList.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No phases active. Use /autophase start [title] to begin." }) : phaseList.map((phase, i) => {
|
|
1064
|
+
const s2 = fmtPhase(phase.status);
|
|
1065
|
+
const phaseKey = Object.keys(phases).find((k) => phases[k] === phase) ?? String(i);
|
|
1066
|
+
const isRunning = runningPhaseIds.includes(phaseKey);
|
|
1067
|
+
const elapsed = phase.startedAt ? fmtElapsed2(nowTick - phase.startedAt) : "\u2014";
|
|
1068
|
+
const progress = phase.totalTasks > 0 ? `${phase.completedTasks}/${phase.totalTasks}` : "\u2014";
|
|
1069
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
1070
|
+
/* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
|
|
1071
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: phase.name }),
|
|
1072
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
1073
|
+
/* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.label }),
|
|
1074
|
+
isRunning ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1075
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
1076
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1077
|
+
"elapsed ",
|
|
1078
|
+
elapsed
|
|
1079
|
+
] })
|
|
1080
|
+
] }) : null,
|
|
1081
|
+
phase.totalTasks > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1082
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
1083
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1084
|
+
"tasks ",
|
|
1085
|
+
progress
|
|
1086
|
+
] })
|
|
1087
|
+
] })
|
|
1088
|
+
] }) }, phaseKey);
|
|
1089
|
+
}),
|
|
1090
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 navigate phases \xB7 Esc close" }) })
|
|
1091
|
+
] });
|
|
1092
|
+
}
|
|
1093
|
+
var fmtElapsed3 = (ms) => {
|
|
1094
|
+
const s2 = Math.floor(ms / 1e3);
|
|
1095
|
+
const m = Math.floor(s2 / 60);
|
|
1096
|
+
const h = Math.floor(m / 60);
|
|
1097
|
+
if (h > 0) return `${h}:${String(m % 60).padStart(2, "0")}:${String(s2 % 60).padStart(2, "0")}`;
|
|
1098
|
+
if (m > 0) return `${m}:${String(s2 % 60).padStart(2, "0")}`;
|
|
1099
|
+
return `${s2}s`;
|
|
1100
|
+
};
|
|
1101
|
+
var STATUS3 = {
|
|
1102
|
+
pending: { icon: "\u25CB", color: "gray" },
|
|
1103
|
+
ready: { icon: "\u25D0", color: "cyan" },
|
|
1104
|
+
running: { icon: "\u25CF", color: "yellow" },
|
|
1105
|
+
paused: { icon: "\u23F8", color: "magenta" },
|
|
1106
|
+
completed: { icon: "\u2713", color: "green" },
|
|
1107
|
+
failed: { icon: "\u2717", color: "red" },
|
|
1108
|
+
skipped: { icon: "\u2298", color: "gray" }
|
|
1109
|
+
};
|
|
1110
|
+
function s(entry) {
|
|
1111
|
+
return STATUS3[entry] ?? { icon: "?", color: "white" };
|
|
1112
|
+
}
|
|
1113
|
+
function PhasePanel({ phases, runningPhaseIds, nowTick }) {
|
|
1114
|
+
const list = Object.values(phases);
|
|
1115
|
+
if (list.length === 0) return null;
|
|
1116
|
+
const done = list.filter((p) => p.status === "completed" || p.status === "skipped").length;
|
|
1117
|
+
const running = list.filter((p) => p.status === "running").length;
|
|
1118
|
+
const failed = list.filter((p) => p.status === "failed").length;
|
|
1119
|
+
return /* @__PURE__ */ jsxs(
|
|
1120
|
+
Box,
|
|
1121
|
+
{
|
|
1122
|
+
flexDirection: "column",
|
|
1123
|
+
paddingX: 1,
|
|
1124
|
+
borderStyle: "single",
|
|
1125
|
+
borderTop: false,
|
|
1126
|
+
borderBottom: false,
|
|
1127
|
+
borderLeft: false,
|
|
1128
|
+
borderRight: false,
|
|
1129
|
+
children: [
|
|
1130
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 2, children: [
|
|
1131
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Phases" }),
|
|
1132
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
1133
|
+
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
1134
|
+
"\u25B6",
|
|
1135
|
+
running
|
|
1136
|
+
] }),
|
|
1137
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1138
|
+
"\u2713",
|
|
1139
|
+
done
|
|
1140
|
+
] }),
|
|
1141
|
+
failed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
1142
|
+
"\u2717",
|
|
1143
|
+
failed
|
|
1144
|
+
] }) : null,
|
|
1145
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1146
|
+
"\xB7 ",
|
|
1147
|
+
list.length,
|
|
1148
|
+
" total"
|
|
1149
|
+
] }),
|
|
1150
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+P for details" })
|
|
1151
|
+
] }),
|
|
1152
|
+
list.map((phase, i) => {
|
|
1153
|
+
const phaseKey = Object.keys(phases).find((k) => phases[k] === phase) ?? String(i);
|
|
1154
|
+
const st = s(phase.status);
|
|
1155
|
+
const progress = phase.totalTasks > 0 ? `${phase.completedTasks}/${phase.totalTasks}` : "";
|
|
1156
|
+
const elapsed = phase.startedAt ? fmtElapsed3(nowTick - phase.startedAt) : "";
|
|
1157
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
1158
|
+
/* @__PURE__ */ jsx(Text, { color: st.color, children: st.icon }),
|
|
1159
|
+
/* @__PURE__ */ jsx(Text, { children: phase.name.slice(0, 14).padEnd(14) }),
|
|
1160
|
+
/* @__PURE__ */ jsx(Text, { color: st.color, dimColor: true, children: st.icon === "\u25CF" ? phase.status : "" }),
|
|
1161
|
+
progress ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1162
|
+
" ",
|
|
1163
|
+
progress
|
|
1164
|
+
] }) : null,
|
|
1165
|
+
elapsed && st.icon === "\u25CF" ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
1166
|
+
" ",
|
|
1167
|
+
elapsed
|
|
1168
|
+
] }) : null
|
|
1169
|
+
] }, phaseKey);
|
|
1170
|
+
})
|
|
1171
|
+
]
|
|
1172
|
+
}
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1002
1175
|
|
|
1003
1176
|
// src/markdown-table.ts
|
|
1004
1177
|
function renderMarkdownTables(text, maxWidth) {
|
|
@@ -1095,7 +1268,7 @@ function computeWidths(allRows, cols, maxWidth) {
|
|
|
1095
1268
|
if (w > natural[c]) natural[c] = Math.min(total + 1, w);
|
|
1096
1269
|
}
|
|
1097
1270
|
}
|
|
1098
|
-
const sumNatural = natural.reduce((
|
|
1271
|
+
const sumNatural = natural.reduce((s2, n) => s2 + n, 0);
|
|
1099
1272
|
if (sumNatural <= avail) return natural;
|
|
1100
1273
|
const widths = natural.slice();
|
|
1101
1274
|
let sum = sumNatural;
|
|
@@ -1116,9 +1289,9 @@ function computeWidths(allRows, cols, maxWidth) {
|
|
|
1116
1289
|
return widths;
|
|
1117
1290
|
}
|
|
1118
1291
|
var MIN_COL_WIDTH = 4;
|
|
1119
|
-
function longestWord(
|
|
1292
|
+
function longestWord(s2) {
|
|
1120
1293
|
let max = 0;
|
|
1121
|
-
for (const w of
|
|
1294
|
+
for (const w of s2.split(/\s+/)) if (w.length > max) max = w.length;
|
|
1122
1295
|
return max;
|
|
1123
1296
|
}
|
|
1124
1297
|
function border(left, mid, right, widths) {
|
|
@@ -2066,11 +2239,11 @@ function stringOf(v) {
|
|
|
2066
2239
|
function numOf(v) {
|
|
2067
2240
|
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
2068
2241
|
}
|
|
2069
|
-
function tryParseJson(
|
|
2070
|
-
const t =
|
|
2242
|
+
function tryParseJson(s2) {
|
|
2243
|
+
const t = s2.trimStart();
|
|
2071
2244
|
if (!t.startsWith("{") && !t.startsWith("[")) return void 0;
|
|
2072
2245
|
try {
|
|
2073
|
-
return JSON.parse(
|
|
2246
|
+
return JSON.parse(s2);
|
|
2074
2247
|
} catch {
|
|
2075
2248
|
return void 0;
|
|
2076
2249
|
}
|
|
@@ -2101,9 +2274,9 @@ function fmtBytes2(n) {
|
|
|
2101
2274
|
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)}KB`;
|
|
2102
2275
|
return `${(n / (1024 * 1024)).toFixed(1)}MB`;
|
|
2103
2276
|
}
|
|
2104
|
-
function truncMid(
|
|
2105
|
-
if (
|
|
2106
|
-
return `${
|
|
2277
|
+
function truncMid(s2, max) {
|
|
2278
|
+
if (s2.length <= max) return s2;
|
|
2279
|
+
return `${s2.slice(0, max - 1)}\u2026`;
|
|
2107
2280
|
}
|
|
2108
2281
|
function isHomeEnd(data) {
|
|
2109
2282
|
if (data === "\x1B[H" || data === "\x1B[1~" || data === "\x1BOH" || data === "\x1B[7~")
|
|
@@ -2177,12 +2350,12 @@ function Input({
|
|
|
2177
2350
|
hint ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint }) : null
|
|
2178
2351
|
] });
|
|
2179
2352
|
}
|
|
2180
|
-
function
|
|
2353
|
+
function fmtElapsed4(ms) {
|
|
2181
2354
|
if (ms < 1e3) return `${ms}ms`;
|
|
2182
2355
|
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
2183
2356
|
const m = Math.floor(ms / 6e4);
|
|
2184
|
-
const
|
|
2185
|
-
return `${m}m${
|
|
2357
|
+
const s2 = Math.floor(ms % 6e4 / 1e3);
|
|
2358
|
+
return `${m}m${s2.toString().padStart(2, "0")}s`;
|
|
2186
2359
|
}
|
|
2187
2360
|
function fmtBytes3(n) {
|
|
2188
2361
|
if (n < 1024) return `${n}B`;
|
|
@@ -2192,7 +2365,7 @@ function fmtRecentTool2(tool) {
|
|
|
2192
2365
|
const status = tool.ok === false ? "fail" : "ok";
|
|
2193
2366
|
const name = tool.name.length > 18 ? `${tool.name.slice(0, 17)}...` : tool.name;
|
|
2194
2367
|
const parts = [status, name];
|
|
2195
|
-
if (typeof tool.durationMs === "number") parts.push(
|
|
2368
|
+
if (typeof tool.durationMs === "number") parts.push(fmtElapsed4(tool.durationMs));
|
|
2196
2369
|
if (typeof tool.outputBytes === "number" && tool.outputBytes > 0) parts.push(fmtBytes3(tool.outputBytes));
|
|
2197
2370
|
if (typeof tool.outputLines === "number" && tool.outputLines > 0) parts.push(`${tool.outputLines}L`);
|
|
2198
2371
|
return parts.join(" ");
|
|
@@ -2213,7 +2386,7 @@ function LiveActivityStrip({
|
|
|
2213
2386
|
running.map((e) => {
|
|
2214
2387
|
const toolElapsed = e.currentTool ? now - e.currentTool.startedAt : 0;
|
|
2215
2388
|
const taskElapsed = now - e.startedAt;
|
|
2216
|
-
const toolSeg = e.currentTool ? `\u2192 ${e.currentTool.name} (${
|
|
2389
|
+
const toolSeg = e.currentTool ? `\u2192 ${e.currentTool.name} (${fmtElapsed4(toolElapsed)})` : "idle between tools";
|
|
2217
2390
|
const recentTools = (e.recentTools ?? []).slice(-2).map(fmtRecentTool2).join(" | ");
|
|
2218
2391
|
const messageText = e.streamingText.trim() || (e.recentMessages ?? []).slice(-1).map(fmtRecentMessage2).join("");
|
|
2219
2392
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
@@ -2227,7 +2400,7 @@ function LiveActivityStrip({
|
|
|
2227
2400
|
"it ",
|
|
2228
2401
|
e.toolCalls,
|
|
2229
2402
|
"tc \xB7 ",
|
|
2230
|
-
|
|
2403
|
+
fmtElapsed4(taskElapsed)
|
|
2231
2404
|
] }),
|
|
2232
2405
|
recentTools ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2233
2406
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "|" }),
|
|
@@ -2386,10 +2559,10 @@ async function walk(root, rel, depth, out) {
|
|
|
2386
2559
|
}
|
|
2387
2560
|
}
|
|
2388
2561
|
}
|
|
2389
|
-
function score(
|
|
2390
|
-
if (!query) return
|
|
2562
|
+
function score(s2, query) {
|
|
2563
|
+
if (!query) return s2.length;
|
|
2391
2564
|
const ql = query.toLowerCase();
|
|
2392
|
-
const sl =
|
|
2565
|
+
const sl = s2.toLowerCase();
|
|
2393
2566
|
let si = 0;
|
|
2394
2567
|
let firstHit = -1;
|
|
2395
2568
|
let lastHit = -1;
|
|
@@ -2402,7 +2575,7 @@ function score(s, query) {
|
|
|
2402
2575
|
si++;
|
|
2403
2576
|
}
|
|
2404
2577
|
const span = lastHit - firstHit;
|
|
2405
|
-
return span * 100 + firstHit * 2 +
|
|
2578
|
+
return span * 100 + firstHit * 2 + s2.length;
|
|
2406
2579
|
}
|
|
2407
2580
|
async function searchFiles(root, query, limit = 8) {
|
|
2408
2581
|
const all = await loadIndex(root);
|
|
@@ -2556,8 +2729,8 @@ function renderList(queue) {
|
|
|
2556
2729
|
}
|
|
2557
2730
|
return lines.join("\n");
|
|
2558
2731
|
}
|
|
2559
|
-
function oneLine(
|
|
2560
|
-
const collapsed =
|
|
2732
|
+
function oneLine(s2, max) {
|
|
2733
|
+
const collapsed = s2.replace(/\s+/g, " ").trim();
|
|
2561
2734
|
return collapsed.length <= max ? collapsed : `${collapsed.slice(0, max - 1)}\u2026`;
|
|
2562
2735
|
}
|
|
2563
2736
|
var USAGE2 = "Usage:\n /kill \u2014 list active processes + breaker state\n /kill list \u2014 same as /kill\n /kill all \u2014 kill all tracked processes (SIGTERM \u2192 SIGKILL)\n /kill force \u2014 kill all with SIGKILL immediately\n /kill reset \u2014 reset the circuit breaker to closed\n /kill <pid> \u2014 kill a specific process by PID";
|
|
@@ -3224,6 +3397,61 @@ function reducer(state, action) {
|
|
|
3224
3397
|
case "goalSummary": {
|
|
3225
3398
|
return { ...state, goalSummary: action.summary };
|
|
3226
3399
|
}
|
|
3400
|
+
case "autoPhaseInit": {
|
|
3401
|
+
return {
|
|
3402
|
+
...state,
|
|
3403
|
+
autoPhase: {
|
|
3404
|
+
title: action.title,
|
|
3405
|
+
phases: {},
|
|
3406
|
+
runningPhaseIds: [],
|
|
3407
|
+
elapsedMs: 0,
|
|
3408
|
+
monitorOpen: false
|
|
3409
|
+
}
|
|
3410
|
+
};
|
|
3411
|
+
}
|
|
3412
|
+
case "autoPhasePhaseUpdate": {
|
|
3413
|
+
const existing = state.autoPhase ?? {
|
|
3414
|
+
title: "AutoPhase",
|
|
3415
|
+
phases: {},
|
|
3416
|
+
runningPhaseIds: [],
|
|
3417
|
+
elapsedMs: 0,
|
|
3418
|
+
monitorOpen: false
|
|
3419
|
+
};
|
|
3420
|
+
return {
|
|
3421
|
+
...state,
|
|
3422
|
+
autoPhase: {
|
|
3423
|
+
...existing,
|
|
3424
|
+
phases: {
|
|
3425
|
+
...existing.phases,
|
|
3426
|
+
[action.phaseId]: {
|
|
3427
|
+
name: action.name,
|
|
3428
|
+
status: action.status,
|
|
3429
|
+
completedTasks: action.completedTasks,
|
|
3430
|
+
totalTasks: action.totalTasks,
|
|
3431
|
+
startedAt: action.startedAt
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3437
|
+
case "autoPhaseRunningPhases": {
|
|
3438
|
+
if (!state.autoPhase) return state;
|
|
3439
|
+
return {
|
|
3440
|
+
...state,
|
|
3441
|
+
autoPhase: { ...state.autoPhase, runningPhaseIds: action.phaseIds }
|
|
3442
|
+
};
|
|
3443
|
+
}
|
|
3444
|
+
case "autoPhaseElapsed": {
|
|
3445
|
+
if (!state.autoPhase) return state;
|
|
3446
|
+
return { ...state, autoPhase: { ...state.autoPhase, elapsedMs: action.ms } };
|
|
3447
|
+
}
|
|
3448
|
+
case "autoPhaseMonitorToggle": {
|
|
3449
|
+
if (!state.autoPhase) return state;
|
|
3450
|
+
return { ...state, autoPhase: { ...state.autoPhase, monitorOpen: !state.autoPhase.monitorOpen } };
|
|
3451
|
+
}
|
|
3452
|
+
case "autoPhaseReset": {
|
|
3453
|
+
return { ...state, autoPhase: null };
|
|
3454
|
+
}
|
|
3227
3455
|
}
|
|
3228
3456
|
}
|
|
3229
3457
|
var PASTE_THRESHOLD_CHARS = 200;
|
|
@@ -3234,7 +3462,7 @@ function buildSteeringPreamble(snapshot, newDirection) {
|
|
|
3234
3462
|
ctx.push(`- in-flight tools (now cancelled): ${snapshot.runningTools.join(", ")}`);
|
|
3235
3463
|
}
|
|
3236
3464
|
if (snapshot?.subagentsTerminated && snapshot.subagentsTerminated > 0) {
|
|
3237
|
-
const subDetails = snapshot.subagents.map((
|
|
3465
|
+
const subDetails = snapshot.subagents.map((s2) => `${s2.label}${s2.tool ? ` (was running: ${s2.tool})` : ""}`).join(", ");
|
|
3238
3466
|
ctx.push(
|
|
3239
3467
|
`- subagents (${snapshot.subagentsTerminated} terminated by me, do NOT await them): ${subDetails}`
|
|
3240
3468
|
);
|
|
@@ -3279,6 +3507,7 @@ function App({
|
|
|
3279
3507
|
getParallelEngine,
|
|
3280
3508
|
subscribeEternalIteration,
|
|
3281
3509
|
subscribeEternalStage,
|
|
3510
|
+
subscribeAutoPhase,
|
|
3282
3511
|
getSDDContext,
|
|
3283
3512
|
onSDDOutput,
|
|
3284
3513
|
appVersion,
|
|
@@ -3395,7 +3624,8 @@ function App({
|
|
|
3395
3624
|
checkpoints: [],
|
|
3396
3625
|
rewindOverlay: null,
|
|
3397
3626
|
eternalStage: null,
|
|
3398
|
-
goalSummary: null
|
|
3627
|
+
goalSummary: null,
|
|
3628
|
+
autoPhase: null
|
|
3399
3629
|
});
|
|
3400
3630
|
const builderRef = useRef(null);
|
|
3401
3631
|
if (builderRef.current === null) {
|
|
@@ -3794,9 +4024,9 @@ function App({
|
|
|
3794
4024
|
if (!text) {
|
|
3795
4025
|
return { message: "Usage: /steer <new direction>" };
|
|
3796
4026
|
}
|
|
3797
|
-
const
|
|
3798
|
-
const runningTools = Array.from(
|
|
3799
|
-
const subagents = Object.values(
|
|
4027
|
+
const s2 = stateRef.current;
|
|
4028
|
+
const runningTools = Array.from(s2.runningTools.values()).map((t) => t.name);
|
|
4029
|
+
const subagents = Object.values(s2.fleet).filter((e) => e.status === "running").map((e) => ({ label: e.name, status: e.status, tool: e.currentTool?.name }));
|
|
3800
4030
|
const subagentsTerminated = subagents.length;
|
|
3801
4031
|
const partialAssistantText = streamingTextRef.current.slice(-1500);
|
|
3802
4032
|
activeCtrlRef.current?.abort();
|
|
@@ -3804,7 +4034,7 @@ function App({
|
|
|
3804
4034
|
type: "steerStart",
|
|
3805
4035
|
snapshot: { runningTools, subagents, subagentsTerminated, partialAssistantText }
|
|
3806
4036
|
});
|
|
3807
|
-
const droppedCount =
|
|
4037
|
+
const droppedCount = s2.queue.length;
|
|
3808
4038
|
if (droppedCount > 0) dispatch({ type: "queueClear" });
|
|
3809
4039
|
if (director && subagentsTerminated > 0) {
|
|
3810
4040
|
const cap = new Promise((resolve) => {
|
|
@@ -3851,8 +4081,8 @@ function App({
|
|
|
3851
4081
|
handleRewindTo(idx);
|
|
3852
4082
|
return {};
|
|
3853
4083
|
}
|
|
3854
|
-
const
|
|
3855
|
-
if (
|
|
4084
|
+
const s2 = stateRef.current;
|
|
4085
|
+
if (s2.checkpoints.length === 0) {
|
|
3856
4086
|
return { message: "No checkpoints in this session yet." };
|
|
3857
4087
|
}
|
|
3858
4088
|
dispatch({ type: "rewindOverlayOpen" });
|
|
@@ -4201,6 +4431,69 @@ function App({
|
|
|
4201
4431
|
offRewound();
|
|
4202
4432
|
};
|
|
4203
4433
|
}, [events, onClearHistory]);
|
|
4434
|
+
useEffect(() => {
|
|
4435
|
+
if (!subscribeAutoPhase) return;
|
|
4436
|
+
const handler = (event, payload) => {
|
|
4437
|
+
switch (event) {
|
|
4438
|
+
case "phase.started": {
|
|
4439
|
+
const p = payload;
|
|
4440
|
+
dispatch({ type: "autoPhasePhaseUpdate", phaseId: p.phaseId, name: p.name, status: "running", completedTasks: 0, totalTasks: 0, startedAt: Date.now() });
|
|
4441
|
+
break;
|
|
4442
|
+
}
|
|
4443
|
+
case "phase.completed": {
|
|
4444
|
+
const p = payload;
|
|
4445
|
+
dispatch({ type: "autoPhasePhaseUpdate", phaseId: p.phaseId, name: p.name, status: "completed", completedTasks: 0, totalTasks: 0 });
|
|
4446
|
+
break;
|
|
4447
|
+
}
|
|
4448
|
+
case "phase.failed": {
|
|
4449
|
+
const p = payload;
|
|
4450
|
+
dispatch({ type: "autoPhasePhaseUpdate", phaseId: p.phaseId, name: p.name, status: "failed", completedTasks: 0, totalTasks: 0 });
|
|
4451
|
+
break;
|
|
4452
|
+
}
|
|
4453
|
+
case "phase.statusChange": {
|
|
4454
|
+
const p = payload;
|
|
4455
|
+
const status = p.to === "running" ? "running" : p.to;
|
|
4456
|
+
dispatch({ type: "autoPhasePhaseUpdate", phaseId: p.phaseId, name: p.name, status, completedTasks: 0, totalTasks: 0 });
|
|
4457
|
+
break;
|
|
4458
|
+
}
|
|
4459
|
+
case "phase.taskCompleted": {
|
|
4460
|
+
const p = payload;
|
|
4461
|
+
const existing = stateRef.current.autoPhase?.phases[p.phaseId];
|
|
4462
|
+
if (existing) {
|
|
4463
|
+
dispatch({
|
|
4464
|
+
type: "autoPhasePhaseUpdate",
|
|
4465
|
+
phaseId: p.phaseId,
|
|
4466
|
+
name: existing.name,
|
|
4467
|
+
status: existing.status,
|
|
4468
|
+
completedTasks: existing.completedTasks + 1,
|
|
4469
|
+
totalTasks: existing.totalTasks
|
|
4470
|
+
});
|
|
4471
|
+
}
|
|
4472
|
+
break;
|
|
4473
|
+
}
|
|
4474
|
+
case "autonomous.tick": {
|
|
4475
|
+
const p = payload;
|
|
4476
|
+
dispatch({ type: "autoPhaseRunningPhases", phaseIds: p.activePhases.map((ph) => ph.id) });
|
|
4477
|
+
const ap = stateRef.current.autoPhase;
|
|
4478
|
+
if (ap) {
|
|
4479
|
+
const firstPhase = ap.phases[Object.keys(ap.phases)[0] ?? ""];
|
|
4480
|
+
const elapsed = ap.elapsedMs > 0 ? ap.elapsedMs + 1e3 : Date.now() - (firstPhase?.startedAt ?? Date.now());
|
|
4481
|
+
dispatch({ type: "autoPhaseElapsed", ms: elapsed });
|
|
4482
|
+
}
|
|
4483
|
+
break;
|
|
4484
|
+
}
|
|
4485
|
+
case "graph.completed": {
|
|
4486
|
+
dispatch({ type: "autoPhaseReset" });
|
|
4487
|
+
break;
|
|
4488
|
+
}
|
|
4489
|
+
case "graph.failed": {
|
|
4490
|
+
dispatch({ type: "autoPhaseReset" });
|
|
4491
|
+
break;
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
};
|
|
4495
|
+
return subscribeAutoPhase(handler);
|
|
4496
|
+
}, [subscribeAutoPhase]);
|
|
4204
4497
|
useEffect(() => {
|
|
4205
4498
|
const offFired = events.on("compaction.fired", (e) => {
|
|
4206
4499
|
const { level, tokens, load, maxContext: maxContext2, report } = e;
|
|
@@ -4302,16 +4595,16 @@ function App({
|
|
|
4302
4595
|
streamFlushTimer = null;
|
|
4303
4596
|
};
|
|
4304
4597
|
const status = d.status();
|
|
4305
|
-
for (const
|
|
4306
|
-
const meta = d.getSubagentMeta(
|
|
4598
|
+
for (const s2 of status.subagents) {
|
|
4599
|
+
const meta = d.getSubagentMeta(s2.id);
|
|
4307
4600
|
dispatch({
|
|
4308
4601
|
type: "fleetSpawn",
|
|
4309
|
-
id:
|
|
4310
|
-
name: meta?.name ??
|
|
4602
|
+
id: s2.id,
|
|
4603
|
+
name: meta?.name ?? s2.name,
|
|
4311
4604
|
provider: meta?.provider,
|
|
4312
4605
|
model: meta?.model
|
|
4313
4606
|
});
|
|
4314
|
-
labelFor(
|
|
4607
|
+
labelFor(s2.id, meta?.name ?? s2.name);
|
|
4315
4608
|
}
|
|
4316
4609
|
dispatch({ type: "fleetCost", cost: d.snapshot().total.cost, input: d.snapshot().total.input, output: d.snapshot().total.output });
|
|
4317
4610
|
const seen = new Set(Object.keys(status.subagents));
|
|
@@ -4726,6 +5019,10 @@ function App({
|
|
|
4726
5019
|
}
|
|
4727
5020
|
return;
|
|
4728
5021
|
}
|
|
5022
|
+
if (key.ctrl && input === "p") {
|
|
5023
|
+
dispatch({ type: "autoPhaseMonitorToggle" });
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
4729
5026
|
if (state.autonomyPicker.open) {
|
|
4730
5027
|
if (key.escape) {
|
|
4731
5028
|
dispatch({ type: "autonomyPickerClose" });
|
|
@@ -4947,6 +5244,15 @@ function App({
|
|
|
4947
5244
|
if (state.historyIndex > 0) dispatch({ type: "historyDown" });
|
|
4948
5245
|
return;
|
|
4949
5246
|
}
|
|
5247
|
+
if (key.ctrl && input === "p") {
|
|
5248
|
+
if (state.autoPhase) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
5249
|
+
else {
|
|
5250
|
+
slashRegistry.dispatch("/autophase", agent.ctx).then((res) => {
|
|
5251
|
+
if (res?.message) dispatch({ type: "addEntry", entry: { kind: "info", text: res.message } });
|
|
5252
|
+
});
|
|
5253
|
+
}
|
|
5254
|
+
return;
|
|
5255
|
+
}
|
|
4950
5256
|
if (key.ctrl && input === "a") {
|
|
4951
5257
|
setDraft(buffer, 0);
|
|
4952
5258
|
return;
|
|
@@ -5194,6 +5500,10 @@ function App({
|
|
|
5194
5500
|
if (res?.message) {
|
|
5195
5501
|
dispatch({ type: "addEntry", entry: { kind: "info", text: res.message } });
|
|
5196
5502
|
}
|
|
5503
|
+
if (res?.metadata?.autoPhaseInit) {
|
|
5504
|
+
const m = res.metadata.autoPhaseInit;
|
|
5505
|
+
dispatch({ type: "autoPhaseInit", title: m.title });
|
|
5506
|
+
}
|
|
5197
5507
|
const ctxModel = agent.ctx.model;
|
|
5198
5508
|
if (ctxModel && ctxModel !== liveModel) setLiveModel(ctxModel);
|
|
5199
5509
|
const ctxProviderId = agent.ctx.provider?.id;
|
|
@@ -5433,6 +5743,15 @@ User message:
|
|
|
5433
5743
|
totalTokens: state.fleetTokens,
|
|
5434
5744
|
nowTick
|
|
5435
5745
|
}
|
|
5746
|
+
) : state.autoPhase?.monitorOpen ? /* @__PURE__ */ jsx(
|
|
5747
|
+
PhaseMonitor,
|
|
5748
|
+
{
|
|
5749
|
+
phases: state.autoPhase.phases,
|
|
5750
|
+
runningPhaseIds: state.autoPhase.runningPhaseIds,
|
|
5751
|
+
elapsedMs: state.autoPhase.elapsedMs,
|
|
5752
|
+
nowTick,
|
|
5753
|
+
onClose: () => dispatch({ type: "autoPhaseMonitorToggle" })
|
|
5754
|
+
}
|
|
5436
5755
|
) : state.monitorOpen ? /* @__PURE__ */ jsx(
|
|
5437
5756
|
FleetMonitor,
|
|
5438
5757
|
{
|
|
@@ -5441,7 +5760,15 @@ User message:
|
|
|
5441
5760
|
totalTokens: state.fleetTokens,
|
|
5442
5761
|
nowTick
|
|
5443
5762
|
}
|
|
5444
|
-
) : director ? /* @__PURE__ */ jsx(FleetPanel, { entries: state.fleet, totalCost: state.fleetCost, roster: fleetRoster }) : null
|
|
5763
|
+
) : director ? /* @__PURE__ */ jsx(FleetPanel, { entries: state.fleet, totalCost: state.fleetCost, roster: fleetRoster }) : null,
|
|
5764
|
+
state.autoPhase && !state.autoPhase.monitorOpen ? /* @__PURE__ */ jsx(
|
|
5765
|
+
PhasePanel,
|
|
5766
|
+
{
|
|
5767
|
+
phases: state.autoPhase.phases,
|
|
5768
|
+
runningPhaseIds: state.autoPhase.runningPhaseIds,
|
|
5769
|
+
nowTick
|
|
5770
|
+
}
|
|
5771
|
+
) : null
|
|
5445
5772
|
] });
|
|
5446
5773
|
}
|
|
5447
5774
|
function renderRunningTools(running) {
|
|
@@ -5500,9 +5827,9 @@ async function runTui(opts) {
|
|
|
5500
5827
|
const swallowSignals = ["SIGTSTP", "SIGQUIT", "SIGTTIN", "SIGTTOU"];
|
|
5501
5828
|
const swallow = () => {
|
|
5502
5829
|
};
|
|
5503
|
-
for (const
|
|
5830
|
+
for (const s2 of swallowSignals) {
|
|
5504
5831
|
try {
|
|
5505
|
-
process.on(
|
|
5832
|
+
process.on(s2, swallow);
|
|
5506
5833
|
} catch {
|
|
5507
5834
|
}
|
|
5508
5835
|
}
|
|
@@ -5521,13 +5848,13 @@ async function runTui(opts) {
|
|
|
5521
5848
|
const signals = ["SIGTERM", "SIGHUP", "SIGINT"];
|
|
5522
5849
|
const signalHandler = () => cleanup();
|
|
5523
5850
|
const exitHandler = () => cleanup();
|
|
5524
|
-
for (const
|
|
5851
|
+
for (const s2 of signals) process.on(s2, signalHandler);
|
|
5525
5852
|
process.on("exit", exitHandler);
|
|
5526
5853
|
const detachListeners = () => {
|
|
5527
|
-
for (const
|
|
5528
|
-
for (const
|
|
5854
|
+
for (const s2 of signals) process.off(s2, signalHandler);
|
|
5855
|
+
for (const s2 of swallowSignals) {
|
|
5529
5856
|
try {
|
|
5530
|
-
process.off(
|
|
5857
|
+
process.off(s2, swallow);
|
|
5531
5858
|
} catch {
|
|
5532
5859
|
}
|
|
5533
5860
|
}
|
|
@@ -5570,6 +5897,7 @@ async function runTui(opts) {
|
|
|
5570
5897
|
getParallelEngine: opts.getParallelEngine,
|
|
5571
5898
|
subscribeEternalIteration: opts.subscribeEternalIteration,
|
|
5572
5899
|
subscribeEternalStage: opts.subscribeEternalStage,
|
|
5900
|
+
subscribeAutoPhase: opts.subscribeAutoPhase,
|
|
5573
5901
|
appVersion: opts.appVersion,
|
|
5574
5902
|
provider: opts.provider,
|
|
5575
5903
|
family: opts.family,
|