@wrongstack/tui 0.32.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +105 -40
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Readable } from 'stream';
|
|
2
|
+
import { writeErr, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, buildChildEnv } from '@wrongstack/core';
|
|
3
|
+
export { buildGoalPreamble } from '@wrongstack/core';
|
|
2
4
|
import { Box, Text, render, useApp, useStdout, measureElement, Static, useInput, useStdin } from 'ink';
|
|
3
5
|
import React4, { useState, useEffect, useReducer, useRef, useMemo, useCallback, useLayoutEffect } from 'react';
|
|
4
6
|
import * as fs2 from 'fs/promises';
|
|
5
7
|
import * as path2 from 'path';
|
|
6
|
-
import { InputBuilder, DefaultSessionRewinder, formatTodosList, buildGoalPreamble, buildChildEnv } from '@wrongstack/core';
|
|
7
|
-
export { buildGoalPreamble } from '@wrongstack/core';
|
|
8
8
|
import { routeImagesForModel } from '@wrongstack/runtime/vision';
|
|
9
9
|
import { getProcessRegistry } from '@wrongstack/tools';
|
|
10
10
|
import { readClipboardImage } from '@wrongstack/runtime/clipboard';
|
|
@@ -526,6 +526,11 @@ function fmtCost(n) {
|
|
|
526
526
|
if (n === 0) return "\u2014";
|
|
527
527
|
return `$${n.toFixed(3)}`;
|
|
528
528
|
}
|
|
529
|
+
function fmtModelLabel(provider, model) {
|
|
530
|
+
if (!model && !provider) return "";
|
|
531
|
+
const short = model ? model.includes("/") ? model.slice(model.lastIndexOf("/") + 1) : model : "?";
|
|
532
|
+
return provider ? `${provider}:${short}` : short;
|
|
533
|
+
}
|
|
529
534
|
function FleetMonitor({
|
|
530
535
|
entries,
|
|
531
536
|
totalCost,
|
|
@@ -598,7 +603,7 @@ function FleetMonitor({
|
|
|
598
603
|
"\u2717",
|
|
599
604
|
failed
|
|
600
605
|
] }) : null,
|
|
601
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+F to close" })
|
|
606
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+F / F2 to close" })
|
|
602
607
|
] }),
|
|
603
608
|
collabSession ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
604
609
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
@@ -658,20 +663,24 @@ function FleetMonitor({
|
|
|
658
663
|
shown.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
659
664
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
660
665
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " " }),
|
|
661
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "name".padEnd(
|
|
662
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "
|
|
663
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "
|
|
666
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "name".padEnd(14) }),
|
|
667
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "model".padEnd(18) }),
|
|
668
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "status".padEnd(9) }),
|
|
669
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "L/t\xB7ctx".padEnd(12) }),
|
|
664
670
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "elapsed".padEnd(8) }),
|
|
665
671
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "cost" })
|
|
666
672
|
] }),
|
|
667
673
|
shown.map((e) => {
|
|
668
674
|
const s2 = STATUS[e.status];
|
|
669
675
|
const elapsed = e.status === "running" ? fmtElapsed(Math.max(0, nowTick - e.startedAt)) : fmtElapsed(Math.max(0, nowTick - e.lastEventAt)) + " ago";
|
|
676
|
+
const model = fmtModelLabel(e.provider, e.model) || "\u2014";
|
|
677
|
+
const ltCtx = e.ctxPct !== void 0 ? `L${e.iterations} ${e.toolCalls}t ${Math.round(e.ctxPct * 100)}%` : `L${e.iterations} ${e.toolCalls}t`;
|
|
670
678
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
671
679
|
/* @__PURE__ */ jsx(Text, { color: s2.color, children: s2.icon }),
|
|
672
|
-
/* @__PURE__ */ jsx(Text, { children: e.name.padEnd(
|
|
673
|
-
/* @__PURE__ */ jsx(Text, {
|
|
674
|
-
/* @__PURE__ */ jsx(Text, {
|
|
680
|
+
/* @__PURE__ */ jsx(Text, { children: e.name.padEnd(14).slice(0, 14) }),
|
|
681
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: model.padEnd(18).slice(0, 18) }),
|
|
682
|
+
/* @__PURE__ */ jsx(Text, { color: s2.color, children: e.status.padEnd(9) }),
|
|
683
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ltCtx.padEnd(12).slice(0, 12) }),
|
|
675
684
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed.padEnd(8).slice(0, 8) }),
|
|
676
685
|
/* @__PURE__ */ jsx(Text, { color: "yellow", children: fmtCost(e.cost) }),
|
|
677
686
|
e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
@@ -786,7 +795,7 @@ function AgentsMonitor({
|
|
|
786
795
|
"\u2717",
|
|
787
796
|
totalFailed
|
|
788
797
|
] }) : null,
|
|
789
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+G to close" })
|
|
798
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Ctrl+G / F3 to close" })
|
|
790
799
|
] }),
|
|
791
800
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
792
801
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "shown" }),
|
|
@@ -821,6 +830,7 @@ function AgentsMonitor({
|
|
|
821
830
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
|
|
822
831
|
/* @__PURE__ */ jsx(Text, { color: s2.color, bold: true, children: s2.icon }),
|
|
823
832
|
/* @__PURE__ */ jsx(Text, { bold: true, children: e.name }),
|
|
833
|
+
fmtModelLabel(e.provider, e.model) ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: fmtModelLabel(e.provider, e.model) }) : null,
|
|
824
834
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
825
835
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: elapsed }),
|
|
826
836
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
@@ -831,6 +841,10 @@ function AgentsMonitor({
|
|
|
831
841
|
e.toolCalls,
|
|
832
842
|
"t"
|
|
833
843
|
] }),
|
|
844
|
+
e.ctxPct !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
845
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7" }),
|
|
846
|
+
/* @__PURE__ */ jsx(ContextBar, { pct: e.ctxPct, tokens: e.ctxTokens, maxTokens: e.ctxMaxTokens })
|
|
847
|
+
] }) : null,
|
|
834
848
|
e.extensions && e.extensions > 0 ? /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
|
|
835
849
|
"\u26A1\xD7",
|
|
836
850
|
e.extensions
|
|
@@ -877,11 +891,7 @@ function AgentsMonitor({
|
|
|
877
891
|
e.failureReason && e.status !== "success" ? /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "red", children: [
|
|
878
892
|
"\u2717 ",
|
|
879
893
|
e.failureReason
|
|
880
|
-
] }) }) : null
|
|
881
|
-
e.ctxPct !== void 0 ? /* @__PURE__ */ jsxs(Box, { paddingLeft: 2, children: [
|
|
882
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "ctx " }),
|
|
883
|
-
/* @__PURE__ */ jsx(ContextBar, { pct: e.ctxPct, tokens: e.ctxTokens, maxTokens: e.ctxMaxTokens })
|
|
884
|
-
] }) : null
|
|
894
|
+
] }) }) : null
|
|
885
895
|
] }, e.id);
|
|
886
896
|
})
|
|
887
897
|
] });
|
|
@@ -1041,7 +1051,7 @@ function ConfirmPrompt({
|
|
|
1041
1051
|
onDecision
|
|
1042
1052
|
}) {
|
|
1043
1053
|
React4.useEffect(() => {
|
|
1044
|
-
|
|
1054
|
+
writeOut("\x07");
|
|
1045
1055
|
}, []);
|
|
1046
1056
|
useInput((input2, _key) => {
|
|
1047
1057
|
if (!input2 || input2 === "\r" || input2 === "\n") return;
|
|
@@ -1182,9 +1192,9 @@ function helpSections(opts) {
|
|
|
1182
1192
|
{
|
|
1183
1193
|
title: "Monitors",
|
|
1184
1194
|
entries: [
|
|
1185
|
-
{ keys: "Ctrl+F", desc: "fleet orchestration monitor" },
|
|
1186
|
-
{ keys: "Ctrl+G", desc: "agents live monitor" },
|
|
1187
|
-
{ keys: "Ctrl+T", desc: "worktree monitor" },
|
|
1195
|
+
{ keys: "Ctrl+F / F2", desc: "fleet orchestration monitor" },
|
|
1196
|
+
{ keys: "Ctrl+G / F3", desc: "agents live monitor" },
|
|
1197
|
+
{ keys: "Ctrl+T / F4", desc: "worktree monitor" },
|
|
1188
1198
|
{ keys: "Esc", desc: "close the open monitor / overlay" }
|
|
1189
1199
|
]
|
|
1190
1200
|
},
|
|
@@ -3181,6 +3191,42 @@ function truncMid(s2, max) {
|
|
|
3181
3191
|
return `${s2.slice(0, max - 1)}\u2026`;
|
|
3182
3192
|
}
|
|
3183
3193
|
|
|
3194
|
+
// src/fn-keys.ts
|
|
3195
|
+
function fnKey(data) {
|
|
3196
|
+
switch (data) {
|
|
3197
|
+
case "\x1BOP":
|
|
3198
|
+
case "\x1B[11~":
|
|
3199
|
+
return 1;
|
|
3200
|
+
case "\x1BOQ":
|
|
3201
|
+
case "\x1B[12~":
|
|
3202
|
+
return 2;
|
|
3203
|
+
case "\x1BOR":
|
|
3204
|
+
case "\x1B[13~":
|
|
3205
|
+
return 3;
|
|
3206
|
+
case "\x1BOS":
|
|
3207
|
+
case "\x1B[14~":
|
|
3208
|
+
return 4;
|
|
3209
|
+
case "\x1B[15~":
|
|
3210
|
+
return 5;
|
|
3211
|
+
case "\x1B[17~":
|
|
3212
|
+
return 6;
|
|
3213
|
+
case "\x1B[18~":
|
|
3214
|
+
return 7;
|
|
3215
|
+
case "\x1B[19~":
|
|
3216
|
+
return 8;
|
|
3217
|
+
case "\x1B[20~":
|
|
3218
|
+
return 9;
|
|
3219
|
+
case "\x1B[21~":
|
|
3220
|
+
return 10;
|
|
3221
|
+
case "\x1B[23~":
|
|
3222
|
+
return 11;
|
|
3223
|
+
case "\x1B[24~":
|
|
3224
|
+
return 12;
|
|
3225
|
+
default:
|
|
3226
|
+
return null;
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3184
3230
|
// src/input-tokens.ts
|
|
3185
3231
|
var INLINE_TOKEN_SRC = "\\[(?:pasted|image|file) #\\d+[^\\]]*\\]|\\[file:[^\\]]+\\]";
|
|
3186
3232
|
var AT_END = new RegExp(`(?:${INLINE_TOKEN_SRC})$`);
|
|
@@ -3375,9 +3421,18 @@ function Input({
|
|
|
3375
3421
|
useEffect(() => {
|
|
3376
3422
|
if (!stdin || disabled) return;
|
|
3377
3423
|
const handleData = (data) => {
|
|
3378
|
-
const
|
|
3379
|
-
|
|
3380
|
-
|
|
3424
|
+
const s2 = data.toString();
|
|
3425
|
+
const kind = isHomeEnd(s2);
|
|
3426
|
+
if (kind === "home") {
|
|
3427
|
+
onKey("", { ...EMPTY_KEY, home: true });
|
|
3428
|
+
return;
|
|
3429
|
+
}
|
|
3430
|
+
if (kind === "end") {
|
|
3431
|
+
onKey("", { ...EMPTY_KEY, end: true });
|
|
3432
|
+
return;
|
|
3433
|
+
}
|
|
3434
|
+
const fn = fnKey(s2);
|
|
3435
|
+
if (fn !== null) onKey("", { ...EMPTY_KEY, fn });
|
|
3381
3436
|
};
|
|
3382
3437
|
stdin.on("data", handleData);
|
|
3383
3438
|
return () => {
|
|
@@ -3974,7 +4029,7 @@ function WorktreeMonitor({
|
|
|
3974
4029
|
failed
|
|
3975
4030
|
] })
|
|
3976
4031
|
] }) : null,
|
|
3977
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+T / Esc to close" })
|
|
4032
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502 Ctrl+T / F4 / Esc to close" })
|
|
3978
4033
|
] }),
|
|
3979
4034
|
list.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No worktrees. They appear when AutoPhase runs with isolation on." }) : list.map((w) => {
|
|
3980
4035
|
const s2 = fmt(w.status);
|
|
@@ -5990,7 +6045,7 @@ function App({
|
|
|
5990
6045
|
const prevEntriesCount = useRef(0);
|
|
5991
6046
|
const eraseLiveRegion = useCallback(() => {
|
|
5992
6047
|
try {
|
|
5993
|
-
|
|
6048
|
+
writeOut("\x1B[J");
|
|
5994
6049
|
} catch {
|
|
5995
6050
|
}
|
|
5996
6051
|
}, []);
|
|
@@ -6202,7 +6257,7 @@ function App({
|
|
|
6202
6257
|
const arg = args.trim().toLowerCase();
|
|
6203
6258
|
if (arg === "off") {
|
|
6204
6259
|
try {
|
|
6205
|
-
|
|
6260
|
+
writeOut(ALT_OFF);
|
|
6206
6261
|
} catch {
|
|
6207
6262
|
return { message: "Failed to exit alt-screen." };
|
|
6208
6263
|
}
|
|
@@ -6213,7 +6268,7 @@ function App({
|
|
|
6213
6268
|
}
|
|
6214
6269
|
if (arg === "on") {
|
|
6215
6270
|
try {
|
|
6216
|
-
|
|
6271
|
+
writeOut(ALT_ON);
|
|
6217
6272
|
} catch {
|
|
6218
6273
|
return { message: "Failed to re-enter alt-screen." };
|
|
6219
6274
|
}
|
|
@@ -6254,9 +6309,9 @@ function App({
|
|
|
6254
6309
|
};
|
|
6255
6310
|
}
|
|
6256
6311
|
try {
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6312
|
+
writeOut(ALT_ON);
|
|
6313
|
+
writeOut("\x1B[H");
|
|
6314
|
+
writeOut(MOUSE_ON_SEQ);
|
|
6260
6315
|
} catch {
|
|
6261
6316
|
return { message: "Failed to enable mouse mode." };
|
|
6262
6317
|
}
|
|
@@ -6267,8 +6322,8 @@ function App({
|
|
|
6267
6322
|
};
|
|
6268
6323
|
}
|
|
6269
6324
|
try {
|
|
6270
|
-
|
|
6271
|
-
|
|
6325
|
+
writeOut(MOUSE_OFF_SEQ);
|
|
6326
|
+
writeOut(ALT_OFF);
|
|
6272
6327
|
} catch {
|
|
6273
6328
|
return { message: "Failed to disable mouse mode." };
|
|
6274
6329
|
}
|
|
@@ -7728,25 +7783,23 @@ function App({
|
|
|
7728
7783
|
});
|
|
7729
7784
|
return;
|
|
7730
7785
|
}
|
|
7731
|
-
|
|
7786
|
+
const toggleFleetOverlay = () => {
|
|
7732
7787
|
if (state.agentsMonitorOpen) {
|
|
7733
7788
|
dispatch({ type: "toggleAgentsMonitor" });
|
|
7734
7789
|
dispatch({ type: "toggleMonitor" });
|
|
7735
7790
|
} else {
|
|
7736
7791
|
dispatch({ type: "toggleMonitor" });
|
|
7737
7792
|
}
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
if (key.ctrl && input === "g") {
|
|
7793
|
+
};
|
|
7794
|
+
const toggleAgentsOverlay = () => {
|
|
7741
7795
|
if (state.monitorOpen) {
|
|
7742
7796
|
dispatch({ type: "toggleMonitor" });
|
|
7743
7797
|
dispatch({ type: "toggleAgentsMonitor" });
|
|
7744
7798
|
} else {
|
|
7745
7799
|
dispatch({ type: "toggleAgentsMonitor" });
|
|
7746
7800
|
}
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
if (key.ctrl && input === "t") {
|
|
7801
|
+
};
|
|
7802
|
+
const toggleWorktreeOverlay = () => {
|
|
7750
7803
|
if (state.worktreeMonitorOpen) {
|
|
7751
7804
|
dispatch({ type: "worktreeMonitorToggle" });
|
|
7752
7805
|
return;
|
|
@@ -7755,6 +7808,17 @@ function App({
|
|
|
7755
7808
|
if (state.monitorOpen) dispatch({ type: "toggleMonitor" });
|
|
7756
7809
|
if (state.autoPhase?.monitorOpen) dispatch({ type: "autoPhaseMonitorToggle" });
|
|
7757
7810
|
dispatch({ type: "worktreeMonitorToggle" });
|
|
7811
|
+
};
|
|
7812
|
+
if (key.ctrl && input === "f" || key.fn === 2) {
|
|
7813
|
+
toggleFleetOverlay();
|
|
7814
|
+
return;
|
|
7815
|
+
}
|
|
7816
|
+
if (key.ctrl && input === "g" || key.fn === 3) {
|
|
7817
|
+
toggleAgentsOverlay();
|
|
7818
|
+
return;
|
|
7819
|
+
}
|
|
7820
|
+
if (key.ctrl && input === "t" || key.fn === 4) {
|
|
7821
|
+
toggleWorktreeOverlay();
|
|
7758
7822
|
return;
|
|
7759
7823
|
}
|
|
7760
7824
|
if (key.ctrl && input === "s") {
|
|
@@ -7910,6 +7974,7 @@ function App({
|
|
|
7910
7974
|
return;
|
|
7911
7975
|
}
|
|
7912
7976
|
if (!input || key.ctrl || key.meta) return;
|
|
7977
|
+
if (input.charCodeAt(0) === 27) return;
|
|
7913
7978
|
if (input.length > PASTE_THRESHOLD_CHARS) {
|
|
7914
7979
|
await commitPaste(input);
|
|
7915
7980
|
return;
|
|
@@ -8634,7 +8699,7 @@ async function runTui(opts) {
|
|
|
8634
8699
|
const stdout = process.stdout;
|
|
8635
8700
|
const stdin = process.stdin;
|
|
8636
8701
|
if (!stdout.isTTY || !stdin.isTTY) {
|
|
8637
|
-
|
|
8702
|
+
writeErr(
|
|
8638
8703
|
"wstack: --tui requires an interactive terminal on both stdin and stdout.\n Drop the flag (use the plain REPL) or run wstack directly without piping.\n"
|
|
8639
8704
|
);
|
|
8640
8705
|
return 2;
|
|
@@ -8861,7 +8926,7 @@ async function runTui(opts) {
|
|
|
8861
8926
|
{ exitOnCtrlC: false, stdin: inkStdin }
|
|
8862
8927
|
);
|
|
8863
8928
|
} catch (err) {
|
|
8864
|
-
|
|
8929
|
+
writeErr(
|
|
8865
8930
|
`wstack: TUI failed to start: ${err instanceof Error ? err.message : String(err)}
|
|
8866
8931
|
`
|
|
8867
8932
|
);
|