@wrongstack/tui 0.8.0 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +234 -135
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -721,6 +721,10 @@ function fmtTokens(n) {
|
|
|
721
721
|
if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
|
|
722
722
|
return `${(n / 1e6).toFixed(1)}M`;
|
|
723
723
|
}
|
|
724
|
+
function fmtCost2(n) {
|
|
725
|
+
if (n === 0) return "\u2014";
|
|
726
|
+
return `$${n.toFixed(3)}`;
|
|
727
|
+
}
|
|
724
728
|
function FleetMonitor({
|
|
725
729
|
entries,
|
|
726
730
|
totalCost,
|
|
@@ -730,17 +734,19 @@ function FleetMonitor({
|
|
|
730
734
|
}) {
|
|
731
735
|
const all = Object.values(entries);
|
|
732
736
|
const running = all.filter((e) => e.status === "running");
|
|
737
|
+
const idle = all.filter((e) => e.status === "idle").length;
|
|
733
738
|
const done = all.filter((e) => e.status === "success").length;
|
|
734
739
|
const failed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
|
|
735
740
|
const concurrencyRatio = maxConcurrent > 0 ? running.length / maxConcurrent : 0;
|
|
736
|
-
const maxTools = Math.max(1, ...all.map((e) => e.toolCalls));
|
|
737
741
|
const ordered = [...all].sort((a, b) => {
|
|
738
742
|
const ra = a.status === "running" ? 0 : a.status === "idle" ? 1 : 2;
|
|
739
743
|
const rb = b.status === "running" ? 0 : b.status === "idle" ? 1 : 2;
|
|
740
744
|
if (ra !== rb) return ra - rb;
|
|
745
|
+
if (ra === 2) return b.lastEventAt - a.lastEventAt;
|
|
741
746
|
return a.startedAt - b.startedAt;
|
|
742
747
|
});
|
|
743
|
-
const shown = ordered.slice(0,
|
|
748
|
+
const shown = ordered.slice(0, 12);
|
|
749
|
+
const overflow = all.length - shown.length;
|
|
744
750
|
const events = [];
|
|
745
751
|
for (const e of all) {
|
|
746
752
|
events.push({ at: e.startedAt, icon: "\u25CF", color: "cyan", text: `${e.name} spawned` });
|
|
@@ -763,15 +769,19 @@ function FleetMonitor({
|
|
|
763
769
|
}
|
|
764
770
|
}
|
|
765
771
|
events.sort((a, b) => b.at - a.at);
|
|
766
|
-
const timeline = events.slice(0,
|
|
772
|
+
const timeline = events.slice(0, 8);
|
|
767
773
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
768
774
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
769
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "FLEET
|
|
775
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "FLEET \xB7 ORCHESTRATION" }),
|
|
770
776
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
771
777
|
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
772
778
|
"\u25B6",
|
|
773
779
|
running.length
|
|
774
780
|
] }),
|
|
781
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
782
|
+
"\u25CB",
|
|
783
|
+
idle
|
|
784
|
+
] }),
|
|
775
785
|
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
776
786
|
"\u2713",
|
|
777
787
|
done
|
|
@@ -786,7 +796,7 @@ function FleetMonitor({
|
|
|
786
796
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "concurrency" }),
|
|
787
797
|
/* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
788
798
|
"[",
|
|
789
|
-
renderProgress(concurrencyRatio,
|
|
799
|
+
renderProgress(concurrencyRatio, 12),
|
|
790
800
|
"]"
|
|
791
801
|
] }),
|
|
792
802
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
@@ -804,36 +814,33 @@ function FleetMonitor({
|
|
|
804
814
|
/* @__PURE__ */ jsx(Text, { color: "green", children: ` $${totalCost.toFixed(3)}` })
|
|
805
815
|
] }),
|
|
806
816
|
shown.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No subagents yet \u2014 spawn with /fleet spawn or /fleet dispatch." }) : null,
|
|
807
|
-
shown.
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
/* @__PURE__ */
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
817
|
+
shown.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
818
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
819
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
820
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "name".padEnd(16) }),
|
|
821
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "status".padEnd(10) }),
|
|
822
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "L/t".padEnd(8) }),
|
|
823
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "elapsed".padEnd(8) }),
|
|
824
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "cost" })
|
|
825
|
+
] }),
|
|
826
|
+
shown.map((e) => {
|
|
827
|
+
const s = STATUS[e.status];
|
|
828
|
+
const elapsed = e.status === "running" ? fmtElapsed(Math.max(0, nowTick - e.startedAt)) : fmtElapsed(Math.max(0, nowTick - e.lastEventAt)) + " ago";
|
|
829
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
830
|
+
/* @__PURE__ */ jsx(Text, { color: s.color, children: s.icon }),
|
|
831
|
+
/* @__PURE__ */ jsx(Text, { children: e.name.padEnd(16).slice(0, 16) }),
|
|
832
|
+
/* @__PURE__ */ jsx(Text, { color: s.color, children: e.status.padEnd(10) }),
|
|
833
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `L${e.iterations} ${e.toolCalls}t`.padEnd(8) }),
|
|
834
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed.padEnd(8).slice(0, 8) }),
|
|
835
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: fmtCost2(e.cost) }),
|
|
825
836
|
e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
826
|
-
"\u26A1\xD7",
|
|
837
|
+
" \u26A1\xD7",
|
|
827
838
|
e.extensions
|
|
828
839
|
] }) : null
|
|
829
|
-
] })
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
tool ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: tool }) : null
|
|
834
|
-
] })
|
|
835
|
-
] }, e.id);
|
|
836
|
-
}),
|
|
840
|
+
] }, e.id);
|
|
841
|
+
}),
|
|
842
|
+
overflow > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` \u2026 +${overflow} more` }) : null
|
|
843
|
+
] }) : null,
|
|
837
844
|
timeline.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
838
845
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "timeline" }),
|
|
839
846
|
timeline.map((ev, i) => (
|
|
@@ -855,11 +862,19 @@ var STATUS2 = {
|
|
|
855
862
|
timeout: { icon: "\u23F1", color: "yellow" },
|
|
856
863
|
stopped: { icon: "\u2298", color: "gray" }
|
|
857
864
|
};
|
|
865
|
+
function isTerminal(status) {
|
|
866
|
+
return status === "success" || status === "failed" || status === "timeout" || status === "stopped";
|
|
867
|
+
}
|
|
858
868
|
function fmtTokens2(n) {
|
|
859
869
|
if (n < 1e3) return String(n);
|
|
860
870
|
if (n < 1e6) return `${(n / 1e3).toFixed(1)}k`;
|
|
861
871
|
return `${(n / 1e6).toFixed(1)}M`;
|
|
862
872
|
}
|
|
873
|
+
function snippet(s, max = 72) {
|
|
874
|
+
const oneLine2 = s.replace(/\s+/g, " ").trim();
|
|
875
|
+
if (oneLine2.length <= max) return oneLine2;
|
|
876
|
+
return `${oneLine2.slice(0, max - 1)}\u2026`;
|
|
877
|
+
}
|
|
863
878
|
function AgentsMonitor({
|
|
864
879
|
entries,
|
|
865
880
|
totalCost,
|
|
@@ -867,81 +882,69 @@ function AgentsMonitor({
|
|
|
867
882
|
nowTick
|
|
868
883
|
}) {
|
|
869
884
|
const all = Object.values(entries);
|
|
870
|
-
const
|
|
871
|
-
const
|
|
872
|
-
const
|
|
873
|
-
const
|
|
874
|
-
const ordered = [...
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
if (ra !== rb) return ra - rb;
|
|
885
|
+
const live = all.filter((e) => !isTerminal(e.status));
|
|
886
|
+
const running = live.filter((e) => e.status === "running").length;
|
|
887
|
+
const totalDone = all.filter((e) => e.status === "success").length;
|
|
888
|
+
const totalFailed = all.filter((e) => e.status === "failed" || e.status === "timeout").length;
|
|
889
|
+
const ordered = [...live].sort((a, b) => {
|
|
890
|
+
if (a.status === "running" && b.status !== "running") return -1;
|
|
891
|
+
if (a.status !== "running" && b.status === "running") return 1;
|
|
878
892
|
return a.startedAt - b.startedAt;
|
|
879
893
|
});
|
|
880
|
-
const shown = ordered.slice(0,
|
|
881
|
-
const events = [];
|
|
882
|
-
for (const e of all) {
|
|
883
|
-
events.push({ at: e.startedAt, icon: "\u25CF", color: "cyan", text: `${e.name} spawned` });
|
|
884
|
-
if (e.status !== "running" && e.status !== "idle") {
|
|
885
|
-
const s = STATUS2[e.status];
|
|
886
|
-
events.push({
|
|
887
|
-
at: e.lastEventAt,
|
|
888
|
-
icon: s.icon,
|
|
889
|
-
color: s.color,
|
|
890
|
-
text: `${e.name} ${e.status} (${e.toolCalls}t)`
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
if (e.budgetWarning) {
|
|
894
|
-
events.push({
|
|
895
|
-
at: e.budgetWarning.at,
|
|
896
|
-
icon: "\u26A1",
|
|
897
|
-
color: "yellow",
|
|
898
|
-
text: `${e.name} ${e.budgetWarning.kind} ${e.budgetWarning.used}/${e.budgetWarning.limit} \u2014 extending`
|
|
899
|
-
});
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
events.sort((a, b) => b.at - a.at);
|
|
903
|
-
const timeline = events.slice(0, 6);
|
|
894
|
+
const shown = ordered.slice(0, 8);
|
|
904
895
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
905
896
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
906
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "AGENTS
|
|
897
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "magenta", children: "AGENTS \xB7 LIVE" }),
|
|
907
898
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }),
|
|
908
899
|
/* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
909
900
|
"\u25B6",
|
|
910
|
-
running
|
|
901
|
+
running
|
|
911
902
|
] }),
|
|
903
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
904
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "done" }),
|
|
912
905
|
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
913
906
|
"\u2713",
|
|
914
|
-
|
|
907
|
+
totalDone
|
|
915
908
|
] }),
|
|
916
|
-
|
|
909
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
910
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "failed" }),
|
|
911
|
+
totalFailed > 0 ? /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
917
912
|
"\u2717",
|
|
918
|
-
|
|
913
|
+
totalFailed
|
|
919
914
|
] }) : null,
|
|
920
915
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+G to close" })
|
|
921
916
|
] }),
|
|
922
917
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
923
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "
|
|
924
|
-
/* @__PURE__ */ jsx(Text, { color: "magenta", children:
|
|
918
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "shown" }),
|
|
919
|
+
/* @__PURE__ */ jsx(Text, { color: "magenta", children: live.length }),
|
|
925
920
|
totalTokens ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
921
|
+
" ",
|
|
926
922
|
fmtTokens2(totalTokens.input),
|
|
927
923
|
"\u2191 ",
|
|
928
924
|
fmtTokens2(totalTokens.output),
|
|
929
925
|
"\u2193"
|
|
930
926
|
] }) : null,
|
|
931
|
-
/* @__PURE__ */
|
|
927
|
+
/* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
928
|
+
"$",
|
|
929
|
+
totalCost.toFixed(3)
|
|
930
|
+
] })
|
|
932
931
|
] }),
|
|
933
|
-
shown.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No
|
|
932
|
+
shown.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No live agents \u2014 spawn with /spawn or /fleet dispatch." }) : null,
|
|
934
933
|
shown.map((e) => {
|
|
935
934
|
const s = STATUS2[e.status];
|
|
936
935
|
const elapsed = e.status === "running" ? fmtElapsed(Math.max(0, nowTick - e.startedAt)) : e.status;
|
|
937
936
|
const spark = sparkline(bucketActivity(e.recentTools, nowTick));
|
|
938
|
-
const
|
|
939
|
-
|
|
937
|
+
const lastTool = e.recentTools[e.recentTools.length - 1];
|
|
938
|
+
const lastMessage = e.recentMessages[e.recentMessages.length - 1];
|
|
939
|
+
const streamTail = e.streamingText ? snippet(e.streamingText.slice(-160)) : "";
|
|
940
|
+
const toolElapsed = e.currentTool ? Math.max(0, nowTick - e.currentTool.startedAt) : 0;
|
|
941
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
940
942
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
941
943
|
/* @__PURE__ */ jsx(Text, { color: s.color, bold: true, children: s.icon }),
|
|
942
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: e.name
|
|
943
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children:
|
|
944
|
-
/* @__PURE__ */ jsx(Text, {
|
|
944
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: e.name }),
|
|
945
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
946
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed }),
|
|
947
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
945
948
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
946
949
|
"L",
|
|
947
950
|
e.iterations,
|
|
@@ -954,24 +957,46 @@ function AgentsMonitor({
|
|
|
954
957
|
e.extensions
|
|
955
958
|
] }) : null
|
|
956
959
|
] }),
|
|
957
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
958
|
-
/* @__PURE__ */
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
960
|
+
e.status === "running" && e.currentTool ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingLeft: 2, children: [
|
|
961
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
962
|
+
"\u2192 ",
|
|
963
|
+
e.currentTool.name
|
|
964
|
+
] }),
|
|
965
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
966
|
+
"(",
|
|
967
|
+
toolElapsed,
|
|
968
|
+
"ms)"
|
|
969
|
+
] })
|
|
970
|
+
] }) : null,
|
|
971
|
+
spark || lastTool ? /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingLeft: 2, children: [
|
|
972
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: spark || "" }),
|
|
973
|
+
lastTool ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
974
|
+
"last: ",
|
|
975
|
+
lastTool.name,
|
|
976
|
+
typeof lastTool.durationMs === "number" ? ` ${lastTool.durationMs}ms` : "",
|
|
977
|
+
lastTool.ok === false ? " \u2717" : ""
|
|
978
|
+
] }) : null
|
|
979
|
+
] }) : null,
|
|
980
|
+
e.status === "running" && streamTail ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
981
|
+
">",
|
|
982
|
+
" ",
|
|
983
|
+
streamTail
|
|
984
|
+
] }) }) : null,
|
|
985
|
+
(e.status !== "running" || !streamTail) && lastMessage ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
986
|
+
"msg: ",
|
|
987
|
+
snippet(lastMessage.text)
|
|
988
|
+
] }) }) : null,
|
|
989
|
+
e.budgetWarning ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
990
|
+
"\u26A1 ",
|
|
991
|
+
e.budgetWarning.kind,
|
|
992
|
+
" ",
|
|
993
|
+
e.budgetWarning.used,
|
|
994
|
+
"/",
|
|
995
|
+
e.budgetWarning.limit,
|
|
996
|
+
" \u2014 extending"
|
|
997
|
+
] }) }) : null
|
|
962
998
|
] }, e.id);
|
|
963
|
-
})
|
|
964
|
-
timeline.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
965
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "timeline" }),
|
|
966
|
-
timeline.map((ev, i) => (
|
|
967
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: timeline is rebuilt per render
|
|
968
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
969
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${fmtElapsed(Math.max(0, nowTick - ev.at))} ago`.padEnd(10) }),
|
|
970
|
-
/* @__PURE__ */ jsx(Text, { color: ev.color, children: ev.icon }),
|
|
971
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ev.text })
|
|
972
|
-
] }, i)
|
|
973
|
-
))
|
|
974
|
-
] }) : null
|
|
999
|
+
})
|
|
975
1000
|
] });
|
|
976
1001
|
}
|
|
977
1002
|
|
|
@@ -1155,7 +1180,17 @@ function padCell(text, width, align) {
|
|
|
1155
1180
|
}
|
|
1156
1181
|
function History({ entries, streamingText, toolStream }) {
|
|
1157
1182
|
const { stdout } = useStdout();
|
|
1158
|
-
const
|
|
1183
|
+
const [termSize, setTermSize] = useState({ columns: stdout?.columns ?? 80, rows: stdout?.rows ?? 24 });
|
|
1184
|
+
useEffect(() => {
|
|
1185
|
+
const handleResize = () => {
|
|
1186
|
+
setTermSize({ columns: stdout?.columns ?? 80, rows: stdout?.rows ?? 24 });
|
|
1187
|
+
};
|
|
1188
|
+
process.stdout.on("resize", handleResize);
|
|
1189
|
+
return () => {
|
|
1190
|
+
process.stdout.off("resize", handleResize);
|
|
1191
|
+
};
|
|
1192
|
+
}, [stdout]);
|
|
1193
|
+
const termWidth = termSize.columns;
|
|
1159
1194
|
const tail = streamingText ? tailForDisplay(streamingText, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
1160
1195
|
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
1161
1196
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -1954,12 +1989,12 @@ function formatMatchHit(hit) {
|
|
|
1954
1989
|
const o = hit;
|
|
1955
1990
|
const file = stringOf(o["file"]) ?? stringOf(o["path"]);
|
|
1956
1991
|
const line = numOf(o["line"]) ?? numOf(o["lineNumber"]);
|
|
1957
|
-
const
|
|
1992
|
+
const snippet2 = stringOf(o["text"]) ?? stringOf(o["match"]) ?? stringOf(o["preview"]);
|
|
1958
1993
|
if (file) {
|
|
1959
1994
|
const head = line !== void 0 ? `${shortenPath(file, 40)}:${line}` : shortenPath(file, 50);
|
|
1960
|
-
return
|
|
1995
|
+
return snippet2 ? `${head} ${truncMid(snippet2.replace(/\s+/g, " "), 40)}` : head;
|
|
1961
1996
|
}
|
|
1962
|
-
if (
|
|
1997
|
+
if (snippet2) return truncMid(snippet2, 70);
|
|
1963
1998
|
}
|
|
1964
1999
|
return void 0;
|
|
1965
2000
|
}
|
|
@@ -3102,6 +3137,50 @@ function reducer(state, action) {
|
|
|
3102
3137
|
fleetTokens: action.input !== void 0 || action.output !== void 0 ? { input: action.input ?? state.fleetTokens.input, output: action.output ?? state.fleetTokens.output } : state.fleetTokens
|
|
3103
3138
|
};
|
|
3104
3139
|
}
|
|
3140
|
+
case "leaderIterStart": {
|
|
3141
|
+
return {
|
|
3142
|
+
...state,
|
|
3143
|
+
leader: {
|
|
3144
|
+
...state.leader,
|
|
3145
|
+
iterations: state.leader.iterations + 1,
|
|
3146
|
+
iterating: true,
|
|
3147
|
+
lastEventAt: Date.now()
|
|
3148
|
+
}
|
|
3149
|
+
};
|
|
3150
|
+
}
|
|
3151
|
+
case "leaderIterEnd": {
|
|
3152
|
+
return {
|
|
3153
|
+
...state,
|
|
3154
|
+
leader: { ...state.leader, iterating: false, lastEventAt: Date.now() }
|
|
3155
|
+
};
|
|
3156
|
+
}
|
|
3157
|
+
case "leaderToolStart": {
|
|
3158
|
+
return {
|
|
3159
|
+
...state,
|
|
3160
|
+
leader: {
|
|
3161
|
+
...state.leader,
|
|
3162
|
+
currentTool: { name: action.name, startedAt: Date.now() },
|
|
3163
|
+
lastEventAt: Date.now()
|
|
3164
|
+
}
|
|
3165
|
+
};
|
|
3166
|
+
}
|
|
3167
|
+
case "leaderToolEnd": {
|
|
3168
|
+
const now = Date.now();
|
|
3169
|
+
const recentTools = [
|
|
3170
|
+
...state.leader.recentTools,
|
|
3171
|
+
{ name: action.name, ok: action.ok, durationMs: action.durationMs, at: now }
|
|
3172
|
+
].slice(-8);
|
|
3173
|
+
return {
|
|
3174
|
+
...state,
|
|
3175
|
+
leader: {
|
|
3176
|
+
...state.leader,
|
|
3177
|
+
toolCalls: state.leader.toolCalls + 1,
|
|
3178
|
+
currentTool: void 0,
|
|
3179
|
+
recentTools,
|
|
3180
|
+
lastEventAt: now
|
|
3181
|
+
}
|
|
3182
|
+
};
|
|
3183
|
+
}
|
|
3105
3184
|
case "setStreamFleet": {
|
|
3106
3185
|
return { ...state, streamFleet: action.enabled };
|
|
3107
3186
|
}
|
|
@@ -3299,6 +3378,15 @@ function App({
|
|
|
3299
3378
|
confirmQueue: [],
|
|
3300
3379
|
contextChipVersion: 0,
|
|
3301
3380
|
fleet: {},
|
|
3381
|
+
leader: {
|
|
3382
|
+
iterations: 0,
|
|
3383
|
+
toolCalls: 0,
|
|
3384
|
+
recentTools: [],
|
|
3385
|
+
currentTool: void 0,
|
|
3386
|
+
startedAt: Date.now(),
|
|
3387
|
+
lastEventAt: Date.now(),
|
|
3388
|
+
iterating: false
|
|
3389
|
+
},
|
|
3302
3390
|
fleetCost: 0,
|
|
3303
3391
|
fleetTokens: { input: 0, output: 0 },
|
|
3304
3392
|
streamFleet: true,
|
|
@@ -3396,6 +3484,25 @@ function App({
|
|
|
3396
3484
|
}
|
|
3397
3485
|
return { running, idle, pending: 0, completed };
|
|
3398
3486
|
}, [state.fleet]);
|
|
3487
|
+
const entriesWithLeader = useMemo(() => {
|
|
3488
|
+
const leaderEntry = {
|
|
3489
|
+
id: "leader",
|
|
3490
|
+
name: "LEADER",
|
|
3491
|
+
provider,
|
|
3492
|
+
model,
|
|
3493
|
+
status: state.status === "running" || state.status === "streaming" || state.leader.iterating ? "running" : "idle",
|
|
3494
|
+
streamingText: "",
|
|
3495
|
+
iterations: state.leader.iterations,
|
|
3496
|
+
toolCalls: state.leader.toolCalls,
|
|
3497
|
+
recentTools: state.leader.recentTools,
|
|
3498
|
+
recentMessages: [],
|
|
3499
|
+
cost: 0,
|
|
3500
|
+
startedAt: state.leader.startedAt,
|
|
3501
|
+
lastEventAt: state.leader.lastEventAt,
|
|
3502
|
+
currentTool: state.leader.currentTool
|
|
3503
|
+
};
|
|
3504
|
+
return { leader: leaderEntry, ...state.fleet };
|
|
3505
|
+
}, [state.fleet, state.leader, state.status, provider, model]);
|
|
3399
3506
|
const STREAM_COLORS = ["cyan", "magenta", "yellow", "green", "blue"];
|
|
3400
3507
|
const labelsRef = useRef(/* @__PURE__ */ new Map());
|
|
3401
3508
|
const labelFor = (id, name) => {
|
|
@@ -3411,32 +3518,6 @@ function App({
|
|
|
3411
3518
|
m.set(id, v);
|
|
3412
3519
|
return v;
|
|
3413
3520
|
};
|
|
3414
|
-
const fleetAgents = useMemo(() => {
|
|
3415
|
-
const entries = Object.entries(state.fleet);
|
|
3416
|
-
if (entries.length === 0) return void 0;
|
|
3417
|
-
const active = entries.filter(([_id, e]) => e.status === "running" || e.status === "idle");
|
|
3418
|
-
if (active.length === 0) return void 0;
|
|
3419
|
-
active.sort((a, b) => {
|
|
3420
|
-
const sa = a[1].status === "running" ? 0 : 1;
|
|
3421
|
-
const sb = b[1].status === "running" ? 0 : 1;
|
|
3422
|
-
if (sa !== sb) return sa - sb;
|
|
3423
|
-
return a[1].startedAt - b[1].startedAt;
|
|
3424
|
-
});
|
|
3425
|
-
return active.slice(0, 4).map(([id, e]) => {
|
|
3426
|
-
const lbl = labelFor(id, e.name);
|
|
3427
|
-
return {
|
|
3428
|
-
label: lbl.label,
|
|
3429
|
-
color: lbl.color,
|
|
3430
|
-
elapsedMs: Math.max(0, nowTick - e.startedAt),
|
|
3431
|
-
toolCalls: e.toolCalls,
|
|
3432
|
-
running: e.status === "running",
|
|
3433
|
-
// Last/current action, so the 4th line shows what each agent is
|
|
3434
|
-
// doing right now (e.g. "▶ 12s · 8t · bash") rather than just counts.
|
|
3435
|
-
tool: e.currentTool?.name,
|
|
3436
|
-
extensions: e.extensions
|
|
3437
|
-
};
|
|
3438
|
-
});
|
|
3439
|
-
}, [state.fleet, nowTick]);
|
|
3440
3521
|
const [planCounts, setPlanCounts] = useState(null);
|
|
3441
3522
|
useEffect(() => {
|
|
3442
3523
|
const planPath = agent.ctx.meta["plan.path"];
|
|
@@ -3851,6 +3932,13 @@ function App({
|
|
|
3851
3932
|
});
|
|
3852
3933
|
const offToolStart = events.on("tool.started", (e) => {
|
|
3853
3934
|
dispatch({ type: "toolStarted", id: e.id, name: e.name });
|
|
3935
|
+
dispatch({ type: "leaderToolStart", name: e.name });
|
|
3936
|
+
});
|
|
3937
|
+
const offIterStart = events.on("iteration.started", () => {
|
|
3938
|
+
dispatch({ type: "leaderIterStart" });
|
|
3939
|
+
});
|
|
3940
|
+
const offIterEnd = events.on("iteration.completed", () => {
|
|
3941
|
+
dispatch({ type: "leaderIterEnd" });
|
|
3854
3942
|
});
|
|
3855
3943
|
const offToolProgress = events.on("tool.progress", (e) => {
|
|
3856
3944
|
if (e.event.type !== "partial_output" || !e.event.text) return;
|
|
@@ -3882,6 +3970,7 @@ function App({
|
|
|
3882
3970
|
});
|
|
3883
3971
|
dispatch({ type: "toolEnded", name: e.name });
|
|
3884
3972
|
dispatch({ type: "toolStreamClear", name: e.name });
|
|
3973
|
+
dispatch({ type: "leaderToolEnd", name: e.name, ok: e.ok, durationMs: e.durationMs });
|
|
3885
3974
|
if (e.ok && e.name === "todo") {
|
|
3886
3975
|
dispatch({
|
|
3887
3976
|
type: "addEntry",
|
|
@@ -3941,6 +4030,8 @@ function App({
|
|
|
3941
4030
|
return () => {
|
|
3942
4031
|
offDelta();
|
|
3943
4032
|
offToolStart();
|
|
4033
|
+
offIterStart();
|
|
4034
|
+
offIterEnd();
|
|
3944
4035
|
offToolProgress();
|
|
3945
4036
|
offTool();
|
|
3946
4037
|
offRetry();
|
|
@@ -4112,16 +4203,26 @@ function App({
|
|
|
4112
4203
|
}, [events, onClearHistory]);
|
|
4113
4204
|
useEffect(() => {
|
|
4114
4205
|
const offFired = events.on("compaction.fired", (e) => {
|
|
4115
|
-
const { level, tokens, load, maxContext: maxContext2, report
|
|
4206
|
+
const { level, tokens, load, maxContext: maxContext2, report } = e;
|
|
4116
4207
|
const pct = (load * 100).toFixed(0);
|
|
4117
4208
|
const before = report.before;
|
|
4118
4209
|
const after = report.after;
|
|
4119
4210
|
const saved = before - after;
|
|
4211
|
+
if (saved <= 0) {
|
|
4212
|
+
dispatch({
|
|
4213
|
+
type: "addEntry",
|
|
4214
|
+
entry: {
|
|
4215
|
+
kind: "info",
|
|
4216
|
+
text: `\u25B8 compaction skipped at ${level} \u2014 load ${pct}% (${tokens.toLocaleString()} of ${maxContext2.toLocaleString()} tok). preserveK protects recent turns; nothing to elide.`
|
|
4217
|
+
}
|
|
4218
|
+
});
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
4120
4221
|
const table = [
|
|
4121
|
-
`\u25B8 context compacted at ${level}
|
|
4122
|
-
` tokens before
|
|
4123
|
-
` tokens after
|
|
4124
|
-
` saved
|
|
4222
|
+
`\u25B8 context compacted at ${level} \u2014 load ${pct}% (${tokens.toLocaleString()} of ${maxContext2.toLocaleString()} tok, full request)`,
|
|
4223
|
+
` msg tokens before ${before.toLocaleString().padStart(8)}`,
|
|
4224
|
+
` msg tokens after ${after.toLocaleString().padStart(8)}`,
|
|
4225
|
+
` saved ${saved.toLocaleString().padStart(8)} (${(saved / before * 100).toFixed(1)}%)`
|
|
4125
4226
|
];
|
|
4126
4227
|
for (const line of table) {
|
|
4127
4228
|
dispatch({ type: "addEntry", entry: { kind: "info", text: line } });
|
|
@@ -4130,7 +4231,7 @@ function App({
|
|
|
4130
4231
|
const offFailed = events.on("compaction.failed", (e) => {
|
|
4131
4232
|
const { level, load, maxContext: maxContext2, fatal } = e;
|
|
4132
4233
|
const pct = (load * 100).toFixed(0);
|
|
4133
|
-
const text = fatal ? `\u2717 compaction failed at ${level}
|
|
4234
|
+
const text = fatal ? `\u2717 compaction failed at ${level} \u2014 load ${pct}% of ${maxContext2.toLocaleString()} tok \u2014 FATAL` : `\u26A0 compaction failed at ${level} \u2014 load ${pct}% of ${maxContext2.toLocaleString()} tok \u2014 continuing`;
|
|
4134
4235
|
dispatch({ type: "addEntry", entry: { kind: fatal ? "error" : "warn", text } });
|
|
4135
4236
|
});
|
|
4136
4237
|
return () => {
|
|
@@ -5314,7 +5415,6 @@ User message:
|
|
|
5314
5415
|
todos,
|
|
5315
5416
|
plan: planCounts ?? void 0,
|
|
5316
5417
|
fleet: fleetCounts,
|
|
5317
|
-
fleetAgents,
|
|
5318
5418
|
git: gitInfo,
|
|
5319
5419
|
context: contextWindow,
|
|
5320
5420
|
projectName,
|
|
@@ -5328,13 +5428,12 @@ User message:
|
|
|
5328
5428
|
state.agentsMonitorOpen ? /* @__PURE__ */ jsx(
|
|
5329
5429
|
AgentsMonitor,
|
|
5330
5430
|
{
|
|
5331
|
-
entries:
|
|
5431
|
+
entries: entriesWithLeader,
|
|
5332
5432
|
totalCost: state.fleetCost,
|
|
5333
5433
|
totalTokens: state.fleetTokens,
|
|
5334
5434
|
nowTick
|
|
5335
5435
|
}
|
|
5336
|
-
) :
|
|
5337
|
-
state.monitorOpen ? /* @__PURE__ */ jsx(
|
|
5436
|
+
) : state.monitorOpen ? /* @__PURE__ */ jsx(
|
|
5338
5437
|
FleetMonitor,
|
|
5339
5438
|
{
|
|
5340
5439
|
entries: state.fleet,
|