chivgent 0.16.0 → 0.18.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/README.md +71 -1
- package/README.zh-CN.md +56 -1
- package/dist/cli-options.d.ts +2 -0
- package/dist/cli-options.d.ts.map +1 -1
- package/dist/cli-options.js +6 -0
- package/dist/cli-options.js.map +1 -1
- package/dist/cli.js +86 -23
- package/dist/cli.js.map +1 -1
- package/dist/evals/runner.d.ts.map +1 -1
- package/dist/evals/runner.js +1 -19
- package/dist/evals/runner.js.map +1 -1
- package/dist/remote/framing.d.ts +3 -1
- package/dist/remote/framing.d.ts.map +1 -1
- package/dist/remote/framing.js +23 -9
- package/dist/remote/framing.js.map +1 -1
- package/dist/repl.d.ts +1 -0
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +89 -65
- package/dist/repl.js.map +1 -1
- package/dist/shell/output.d.ts.map +1 -1
- package/dist/shell/output.js +3 -14
- package/dist/shell/output.js.map +1 -1
- package/dist/shell/truncate.d.ts +2 -0
- package/dist/shell/truncate.d.ts.map +1 -1
- package/dist/shell/truncate.js +17 -6
- package/dist/shell/truncate.js.map +1 -1
- package/dist/tools/target.d.ts +10 -0
- package/dist/tools/target.d.ts.map +1 -0
- package/dist/tools/target.js +27 -0
- package/dist/tools/target.js.map +1 -0
- package/dist/tui/input.d.ts +24 -0
- package/dist/tui/input.d.ts.map +1 -0
- package/dist/tui/input.js +45 -0
- package/dist/tui/input.js.map +1 -0
- package/dist/tui/live.d.ts +38 -0
- package/dist/tui/live.d.ts.map +1 -0
- package/dist/tui/live.js +116 -0
- package/dist/tui/live.js.map +1 -0
- package/dist/tui/paint.d.ts +38 -0
- package/dist/tui/paint.d.ts.map +1 -0
- package/dist/tui/paint.js +86 -0
- package/dist/tui/paint.js.map +1 -0
- package/dist/tui/state.d.ts +49 -0
- package/dist/tui/state.d.ts.map +1 -0
- package/dist/tui/state.js +105 -0
- package/dist/tui/state.js.map +1 -0
- package/dist/tui/text.d.ts +7 -0
- package/dist/tui/text.d.ts.map +1 -0
- package/dist/tui/text.js +31 -0
- package/dist/tui/text.js.map +1 -0
- package/dist/tui/view.d.ts +24 -0
- package/dist/tui/view.d.ts.map +1 -0
- package/dist/tui/view.js +83 -0
- package/dist/tui/view.js.map +1 -0
- package/dist/tui/welcome.d.ts +12 -0
- package/dist/tui/welcome.d.ts.map +1 -0
- package/dist/tui/welcome.js +28 -0
- package/dist/tui/welcome.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/tui/live.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AASjD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,iEAAiE;IACjE,IAAI,IAAI,IAAI,CAAC;IACb,0DAA0D;IAC1D,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CA+FvE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGlE"}
|
package/dist/tui/live.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { formatTokens } from "../providers/usage.js";
|
|
2
|
+
import { terminalText, fitLine } from "./text.js";
|
|
3
|
+
import { Painter } from "./paint.js";
|
|
4
|
+
import { EMPTY_STATE, reduce } from "./state.js";
|
|
5
|
+
import { transcriptLines, view } from "./view.js";
|
|
6
|
+
/** How often the region redraws on its own, so elapsed time advances. */
|
|
7
|
+
const TICK_MS = 1000;
|
|
8
|
+
const DEFAULT_WIDTH = 80;
|
|
9
|
+
/**
|
|
10
|
+
* Drives the live region from the event stream.
|
|
11
|
+
*
|
|
12
|
+
* The three pure pieces do the work — `reduce` holds the state, `view` turns it
|
|
13
|
+
* into lines, `Painter` writes only what changed. This is the wiring between
|
|
14
|
+
* them, and the only part that owns a timer or a stream.
|
|
15
|
+
*/
|
|
16
|
+
export function createLiveRegion(options) {
|
|
17
|
+
const clock = options.now ?? (() => Date.now());
|
|
18
|
+
const painter = new Painter({ stream: options.stream });
|
|
19
|
+
let state = EMPTY_STATE;
|
|
20
|
+
let timer;
|
|
21
|
+
const paint = () => {
|
|
22
|
+
painter.render(view(state, {
|
|
23
|
+
// Leave one cell spare to avoid a terminal's pending autowrap state.
|
|
24
|
+
width: Math.max(1, options.width() - 1),
|
|
25
|
+
height: Math.max(1, (options.height?.() ?? 24) - 2),
|
|
26
|
+
now: clock(),
|
|
27
|
+
}));
|
|
28
|
+
};
|
|
29
|
+
const startClock = () => {
|
|
30
|
+
if (timer !== undefined) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
timer = setInterval(paint, options.tickMs ?? TICK_MS);
|
|
34
|
+
// Never a reason to keep the process alive: the region describes work that
|
|
35
|
+
// is happening elsewhere.
|
|
36
|
+
timer.unref?.();
|
|
37
|
+
};
|
|
38
|
+
const stopClock = () => {
|
|
39
|
+
if (timer !== undefined) {
|
|
40
|
+
clearInterval(timer);
|
|
41
|
+
timer = undefined;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
listener: (event) => {
|
|
46
|
+
if (event.type === "turn_end") {
|
|
47
|
+
// The finished turn moves into the terminal's own scrollback: the
|
|
48
|
+
// region is erased first so the transcript lands where it was, then
|
|
49
|
+
// the region is drawn again below it.
|
|
50
|
+
painter.clear();
|
|
51
|
+
const lines = transcriptLines(options.answerStream === undefined ? event : {
|
|
52
|
+
...event,
|
|
53
|
+
message: { ...event.message, content: "" },
|
|
54
|
+
});
|
|
55
|
+
if (lines.length > 0) {
|
|
56
|
+
options.stream.write(`${terminalText(lines.join("\n"))}\n`);
|
|
57
|
+
}
|
|
58
|
+
if (options.answerStream !== undefined && event.message.content.trim().length > 0) {
|
|
59
|
+
options.answerStream.write(`${event.message.content}\n`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const previous = state;
|
|
63
|
+
state = reduce(state, event, clock());
|
|
64
|
+
if (event.type === "agent_start") {
|
|
65
|
+
startClock();
|
|
66
|
+
}
|
|
67
|
+
if (event.type === "agent_end") {
|
|
68
|
+
stopClock();
|
|
69
|
+
painter.clear();
|
|
70
|
+
// Cancellation can end a streamed turn before turn_end arrives.
|
|
71
|
+
if (previous.run?.text) {
|
|
72
|
+
(options.answerStream ?? options.stream).write(`${terminalText(previous.run.text)}\n`);
|
|
73
|
+
}
|
|
74
|
+
const label = event.status === "completed" ? "Completed"
|
|
75
|
+
: event.status === "aborted" ? "Stopped"
|
|
76
|
+
: event.status === "max_turns" ? "Turn limit reached" : "Failed";
|
|
77
|
+
const parts = [label, `${event.turnCount} turn(s)`];
|
|
78
|
+
if (previous.run !== undefined) {
|
|
79
|
+
parts.push(`${Math.max(0, Math.round((clock() - previous.run.startedAt) / 1000))}s`);
|
|
80
|
+
}
|
|
81
|
+
if (event.usage !== undefined) {
|
|
82
|
+
parts.push(`${formatTokens(event.usage.usage.totalTokens)} tokens${event.usage.complete ? "" : "+"}`);
|
|
83
|
+
}
|
|
84
|
+
options.stream.write(`${fitLine(parts.join(" · "), options.width() - 1)}\n`);
|
|
85
|
+
if (event.error !== undefined) {
|
|
86
|
+
options.stream.write(`${terminalText(event.error)}\n`);
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
paint();
|
|
91
|
+
},
|
|
92
|
+
stop: () => {
|
|
93
|
+
stopClock();
|
|
94
|
+
painter.clear();
|
|
95
|
+
state = EMPTY_STATE;
|
|
96
|
+
},
|
|
97
|
+
resized: () => {
|
|
98
|
+
if (state.run === undefined)
|
|
99
|
+
return;
|
|
100
|
+
painter.invalidate(options.width());
|
|
101
|
+
paint();
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The usable width, or a sane default.
|
|
107
|
+
*
|
|
108
|
+
* `columns` is not merely absent off a terminal — it can be `0`, which `??`
|
|
109
|
+
* lets through and which then collapses every line to the minimum. A width has
|
|
110
|
+
* to be positive to mean anything.
|
|
111
|
+
*/
|
|
112
|
+
export function terminalWidth(stream) {
|
|
113
|
+
const columns = stream.columns;
|
|
114
|
+
return columns !== undefined && columns > 0 ? columns : DEFAULT_WIDTH;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/tui/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAkB,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAElD,yEAAyE;AACzE,MAAM,OAAO,GAAG,IAAI,CAAC;AACrB,MAAM,aAAa,GAAG,EAAE,CAAC;AAqBzB;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA0B;IACzD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxD,IAAI,KAAK,GAAc,WAAW,CAAC;IACnC,IAAI,KAAiC,CAAC;IAEtC,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;YACzB,qEAAqE;YACrE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACvC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;YACnD,GAAG,EAAE,KAAK,EAAE;SACb,CAAC,CAAC,CAAC;IACN,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QACD,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC;QACtD,2EAA2E;QAC3E,0BAA0B;QAC1B,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,GAAS,EAAE;QAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,aAAa,CAAC,KAAK,CAAC,CAAC;YACrB,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,CAAC,KAAiB,EAAQ,EAAE;YACpC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,kEAAkE;gBAClE,oEAAoE;gBACpE,sCAAsC;gBACtC,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;oBACzE,GAAG,KAAK;oBACR,OAAO,EAAE,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;iBAC3C,CAAC,CAAC;gBACH,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC9D,CAAC;gBACD,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClF,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,KAAK,CAAC;YACvB,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YAEtC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBACjC,UAAU,EAAE,CAAC;YACf,CAAC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC/B,SAAS,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,gEAAgE;gBAChE,IAAI,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;oBACvB,CAAC,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzF,CAAC;gBACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW;oBACtD,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS;wBACxC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,CAAC;gBACnE,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,SAAS,UAAU,CAAC,CAAC;gBACpD,IAAI,QAAQ,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;oBAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gBACvF,CAAC;gBACD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBAC9B,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;gBACxG,CAAC;gBACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC7E,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;oBAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACzD,CAAC;gBACD,OAAO;YACT,CAAC;YACD,KAAK,EAAE,CAAC;QACV,CAAC;QAED,IAAI,EAAE,GAAS,EAAE;YACf,SAAS,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,KAAK,GAAG,WAAW,CAAC;QACtB,CAAC;QAED,OAAO,EAAE,GAAS,EAAE;YAClB,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;gBAAE,OAAO;YACpC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YACpC,KAAK,EAAE,CAAC;QACV,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,MAA4B;IACxD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { OutputStream } from "../render.js";
|
|
2
|
+
export interface PainterOptions {
|
|
3
|
+
readonly stream: OutputStream;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Draws the live region and keeps it up to date.
|
|
7
|
+
*
|
|
8
|
+
* Rewrites only the lines whose content changed. The cost model here is bytes
|
|
9
|
+
* written to a terminal, and line granularity already turns the common case —
|
|
10
|
+
* a timer ticking in the status line — from repainting the block into
|
|
11
|
+
* rewriting one line. Cell-level diffing buys the rest, and in a region of
|
|
12
|
+
* five or six lines it is not worth what it costs to build.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Painter {
|
|
15
|
+
private readonly options;
|
|
16
|
+
/**
|
|
17
|
+
* The lines currently on screen. The cursor is always on the blank line
|
|
18
|
+
* just below them, which is what lets the caller keep its own prompt line
|
|
19
|
+
* without the painter knowing anything about it.
|
|
20
|
+
*/
|
|
21
|
+
private previous;
|
|
22
|
+
private invalidated;
|
|
23
|
+
private previousRows;
|
|
24
|
+
constructor(options: PainterOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Discards the diff baseline.
|
|
27
|
+
*
|
|
28
|
+
* After a resize the previous line array no longer describes what is on
|
|
29
|
+
* screen — the terminal has reflowed it — so comparing against it would keep
|
|
30
|
+
* lines that are no longer there. This is the one moment a full repaint is
|
|
31
|
+
* the correct answer rather than a lazy one.
|
|
32
|
+
*/
|
|
33
|
+
invalidate(columns?: number): void;
|
|
34
|
+
render(lines: readonly string[]): void;
|
|
35
|
+
/** Erases the region entirely, leaving the cursor where it began. */
|
|
36
|
+
clear(): void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=paint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint.d.ts","sourceRoot":"","sources":["../../src/tui/paint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAMjD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,qBAAa,OAAO;IAUN,OAAO,CAAC,QAAQ,CAAC,OAAO;IATpC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,YAAY,CAAK;IAEzB,YAA6B,OAAO,EAAE,cAAc,EAAI;IAExD;;;;;;;OAOG;IACH,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAQjC;IAED,MAAM,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CA4BrC;IAED,qEAAqE;IACrE,KAAK,IAAI,IAAI,CAcZ;CACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { displayWidth } from "./text.js";
|
|
2
|
+
const CURSOR_UP = "\u001B[A";
|
|
3
|
+
const CLEAR_LINE = "\u001B[2K";
|
|
4
|
+
const CARRIAGE_RETURN = "\r";
|
|
5
|
+
/**
|
|
6
|
+
* Draws the live region and keeps it up to date.
|
|
7
|
+
*
|
|
8
|
+
* Rewrites only the lines whose content changed. The cost model here is bytes
|
|
9
|
+
* written to a terminal, and line granularity already turns the common case —
|
|
10
|
+
* a timer ticking in the status line — from repainting the block into
|
|
11
|
+
* rewriting one line. Cell-level diffing buys the rest, and in a region of
|
|
12
|
+
* five or six lines it is not worth what it costs to build.
|
|
13
|
+
*/
|
|
14
|
+
export class Painter {
|
|
15
|
+
options;
|
|
16
|
+
/**
|
|
17
|
+
* The lines currently on screen. The cursor is always on the blank line
|
|
18
|
+
* just below them, which is what lets the caller keep its own prompt line
|
|
19
|
+
* without the painter knowing anything about it.
|
|
20
|
+
*/
|
|
21
|
+
previous = [];
|
|
22
|
+
invalidated = false;
|
|
23
|
+
previousRows = 0;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.options = options;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Discards the diff baseline.
|
|
29
|
+
*
|
|
30
|
+
* After a resize the previous line array no longer describes what is on
|
|
31
|
+
* screen — the terminal has reflowed it — so comparing against it would keep
|
|
32
|
+
* lines that are no longer there. This is the one moment a full repaint is
|
|
33
|
+
* the correct answer rather than a lazy one.
|
|
34
|
+
*/
|
|
35
|
+
invalidate(columns) {
|
|
36
|
+
this.invalidated = true;
|
|
37
|
+
if (columns !== undefined && columns > 0) {
|
|
38
|
+
this.previousRows = this.previous.reduce((rows, line) => rows + Math.max(1, Math.ceil(displayWidth(line) / columns)), 0);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
render(lines) {
|
|
42
|
+
if (!this.invalidated && sameLines(this.previous, lines)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Back to the top of the region, then forward a line at a time, so the
|
|
46
|
+
// cursor ends where it began and the caller's prompt line is undisturbed.
|
|
47
|
+
let out = CURSOR_UP.repeat(this.previousRows) + CARRIAGE_RETURN;
|
|
48
|
+
const height = Math.max(this.previousRows, lines.length);
|
|
49
|
+
for (let index = 0; index < height; index += 1) {
|
|
50
|
+
const next = lines[index];
|
|
51
|
+
if (next === undefined) {
|
|
52
|
+
// The region shrank: erase the leftover rather than leaving it behind.
|
|
53
|
+
out += `${CLEAR_LINE}\n`;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
out += !this.invalidated && this.previous[index] === next ? "\n" : `${CLEAR_LINE}${next}\n`;
|
|
57
|
+
}
|
|
58
|
+
// A shrunken region left the cursor below its new last line.
|
|
59
|
+
if (height > lines.length) {
|
|
60
|
+
out += CURSOR_UP.repeat(height - lines.length);
|
|
61
|
+
}
|
|
62
|
+
this.options.stream.write(out);
|
|
63
|
+
this.previous = [...lines];
|
|
64
|
+
this.previousRows = lines.length;
|
|
65
|
+
this.invalidated = false;
|
|
66
|
+
}
|
|
67
|
+
/** Erases the region entirely, leaving the cursor where it began. */
|
|
68
|
+
clear() {
|
|
69
|
+
const height = this.previousRows;
|
|
70
|
+
if (height === 0) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
this.options.stream.write(CURSOR_UP.repeat(height) +
|
|
74
|
+
CARRIAGE_RETURN +
|
|
75
|
+
`${CLEAR_LINE}\n`.repeat(height) +
|
|
76
|
+
CURSOR_UP.repeat(height));
|
|
77
|
+
this.previous = [];
|
|
78
|
+
this.previousRows = 0;
|
|
79
|
+
this.invalidated = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function sameLines(left, right) {
|
|
83
|
+
return (left.length === right.length &&
|
|
84
|
+
left.every((line, index) => line === right[index]));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=paint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint.js","sourceRoot":"","sources":["../../src/tui/paint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AgentEvent } from "../events.js";
|
|
2
|
+
import { type UsageTotal } from "../providers/usage.js";
|
|
3
|
+
/**
|
|
4
|
+
* What the live region knows.
|
|
5
|
+
*
|
|
6
|
+
* Every consumer of the event stream before this one was append-only: an event
|
|
7
|
+
* arrived, it was printed, it was forgotten. This is the first that has to
|
|
8
|
+
* rebuild "what is happening now" from the same stream and keep it correct as
|
|
9
|
+
* more arrives.
|
|
10
|
+
*
|
|
11
|
+
* State is deliberately bounded to the run in progress. A finished turn is
|
|
12
|
+
* flushed to the terminal's own scrollback and dropped from here, so a long
|
|
13
|
+
* session does not grow this object — which is the reason the alternate screen
|
|
14
|
+
* buffer is not taken (see docs/stage-14-tui.md §2.1).
|
|
15
|
+
*/
|
|
16
|
+
export interface ViewState {
|
|
17
|
+
/** Absent between runs; the live region is then just the prompt. */
|
|
18
|
+
readonly run?: RunState;
|
|
19
|
+
}
|
|
20
|
+
export interface RunState {
|
|
21
|
+
readonly turn: number;
|
|
22
|
+
readonly maxTurns: number;
|
|
23
|
+
readonly startedAt: number;
|
|
24
|
+
/** Assistant text for the turn in progress. Cleared when the turn ends. */
|
|
25
|
+
readonly text: string;
|
|
26
|
+
/** Tools running right now, in the order they started. */
|
|
27
|
+
readonly running: readonly RunningTool[];
|
|
28
|
+
readonly usage?: UsageTotal;
|
|
29
|
+
readonly status: RunStatus;
|
|
30
|
+
}
|
|
31
|
+
export type RunStatus = "thinking" | "running-tools";
|
|
32
|
+
export interface RunningTool {
|
|
33
|
+
readonly toolCallId: string;
|
|
34
|
+
readonly name: string;
|
|
35
|
+
/** The path or command the call was aimed at, when it has one. */
|
|
36
|
+
readonly target?: string;
|
|
37
|
+
/** The tool's latest progress snapshot. Replaced, never appended to. */
|
|
38
|
+
readonly progress: string;
|
|
39
|
+
readonly startedAt: number;
|
|
40
|
+
}
|
|
41
|
+
export declare const EMPTY_STATE: ViewState;
|
|
42
|
+
/**
|
|
43
|
+
* Folds one event into the view state.
|
|
44
|
+
*
|
|
45
|
+
* Pure, and takes `now` rather than reading the clock, so the whole model can
|
|
46
|
+
* be tested without a terminal and without a fake timer.
|
|
47
|
+
*/
|
|
48
|
+
export declare function reduce(state: ViewState, event: AgentEvent, now: number): ViewState;
|
|
49
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/tui/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGlE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,oEAAoE;IACpE,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;CAC5B;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,eAAe,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,WAAW,EAAE,SAAc,CAAC;AAazC;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,GACV,SAAS,CAkGX"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { addUsage } from "../providers/usage.js";
|
|
2
|
+
import { callTarget } from "../tools/target.js";
|
|
3
|
+
export const EMPTY_STATE = {};
|
|
4
|
+
function startRun(maxTurns, now) {
|
|
5
|
+
return {
|
|
6
|
+
turn: 0,
|
|
7
|
+
maxTurns,
|
|
8
|
+
startedAt: now,
|
|
9
|
+
text: "",
|
|
10
|
+
running: [],
|
|
11
|
+
status: "thinking",
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Folds one event into the view state.
|
|
16
|
+
*
|
|
17
|
+
* Pure, and takes `now` rather than reading the clock, so the whole model can
|
|
18
|
+
* be tested without a terminal and without a fake timer.
|
|
19
|
+
*/
|
|
20
|
+
export function reduce(state, event, now) {
|
|
21
|
+
if (event.type === "agent_start") {
|
|
22
|
+
return { run: startRun(event.maxTurns, now) };
|
|
23
|
+
}
|
|
24
|
+
if (event.type === "agent_end") {
|
|
25
|
+
// The run's transcript has already gone to scrollback; nothing is left to
|
|
26
|
+
// keep alive.
|
|
27
|
+
return EMPTY_STATE;
|
|
28
|
+
}
|
|
29
|
+
const run = state.run;
|
|
30
|
+
if (run === undefined) {
|
|
31
|
+
// An event outside a run. Dropping it is right: the live region describes
|
|
32
|
+
// a run, and inventing one from a mid-stream event would show a run whose
|
|
33
|
+
// beginning was never seen.
|
|
34
|
+
return state;
|
|
35
|
+
}
|
|
36
|
+
switch (event.type) {
|
|
37
|
+
case "turn_start":
|
|
38
|
+
return { run: { ...run, turn: event.turn, status: "thinking" } };
|
|
39
|
+
case "message_start":
|
|
40
|
+
return { run: { ...run, status: "thinking" } };
|
|
41
|
+
case "message_update":
|
|
42
|
+
// A DELTA. Appending is the only correct move: replacing would leave the
|
|
43
|
+
// last token and lose the answer.
|
|
44
|
+
return { run: { ...run, text: run.text + event.delta } };
|
|
45
|
+
case "message_end":
|
|
46
|
+
// The authoritative message, after any deltas. Taking it wholesale also
|
|
47
|
+
// covers the non-streaming case, where no delta ever arrived.
|
|
48
|
+
return {
|
|
49
|
+
run: {
|
|
50
|
+
...run,
|
|
51
|
+
text: event.message.content,
|
|
52
|
+
...(event.usage === undefined && run.usage === undefined
|
|
53
|
+
? {}
|
|
54
|
+
: { usage: addUsage(run.usage, event.usage) }),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
case "tool_execution_start": {
|
|
58
|
+
const target = callTarget(event.arguments);
|
|
59
|
+
const tool = {
|
|
60
|
+
toolCallId: event.toolCallId,
|
|
61
|
+
name: event.toolName,
|
|
62
|
+
...(target === undefined ? {} : { target }),
|
|
63
|
+
progress: "",
|
|
64
|
+
startedAt: now,
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
run: {
|
|
68
|
+
...run,
|
|
69
|
+
running: [...run.running, tool],
|
|
70
|
+
status: "running-tools",
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
case "tool_execution_update":
|
|
75
|
+
// A SNAPSHOT, already truncated to a bounded window by the tool.
|
|
76
|
+
// Appending would stack the same output repeatedly, and because the
|
|
77
|
+
// window has had its front dropped the result would not even be the
|
|
78
|
+
// real output. Replace.
|
|
79
|
+
return {
|
|
80
|
+
run: {
|
|
81
|
+
...run,
|
|
82
|
+
running: run.running.map((tool) => tool.toolCallId === event.toolCallId
|
|
83
|
+
? { ...tool, progress: event.content }
|
|
84
|
+
: tool),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
case "tool_execution_end": {
|
|
88
|
+
const running = run.running.filter((tool) => tool.toolCallId !== event.toolCallId);
|
|
89
|
+
return {
|
|
90
|
+
run: {
|
|
91
|
+
...run,
|
|
92
|
+
running,
|
|
93
|
+
status: running.length === 0 ? "thinking" : "running-tools",
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
case "turn_end":
|
|
98
|
+
// The turn is flushed to scrollback by the caller; what is left alive is
|
|
99
|
+
// only the fact that the run continues.
|
|
100
|
+
return { run: { ...run, text: "", running: [], status: "thinking" } };
|
|
101
|
+
default:
|
|
102
|
+
return state;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/tui/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import stringWidth from "string-width";
|
|
2
|
+
/** Terminal content may contain cursor controls; only our painter owns those. */
|
|
3
|
+
export declare function terminalText(text: string): string;
|
|
4
|
+
export { stringWidth as displayWidth };
|
|
5
|
+
/** Fit terminal cells, preserving whole graphemes (including joined emoji). */
|
|
6
|
+
export declare function fitLine(text: string, columns: number): string;
|
|
7
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/tui/text.ts"],"names":[],"mappings":"AACA,OAAO,WAAW,MAAM,cAAc,CAAC;AAIvC,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,CAAC;AAEvC,+EAA+E;AAC/E,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAc7D"}
|
package/dist/tui/text.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { stripVTControlCharacters } from "node:util";
|
|
2
|
+
import stringWidth from "string-width";
|
|
3
|
+
const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
4
|
+
/** Terminal content may contain cursor controls; only our painter owns those. */
|
|
5
|
+
export function terminalText(text) {
|
|
6
|
+
return stripVTControlCharacters(text)
|
|
7
|
+
.replace(/\r\n/g, "\n")
|
|
8
|
+
.replace(/\t/g, " ")
|
|
9
|
+
.replace(/[\u0000-\u0009\u000b-\u001f\u007f-\u009f]/g, "");
|
|
10
|
+
}
|
|
11
|
+
export { stringWidth as displayWidth };
|
|
12
|
+
/** Fit terminal cells, preserving whole graphemes (including joined emoji). */
|
|
13
|
+
export function fitLine(text, columns) {
|
|
14
|
+
const width = Math.max(0, Math.floor(columns));
|
|
15
|
+
const clean = terminalText(text).replace(/\n/g, " ");
|
|
16
|
+
if (width === 0)
|
|
17
|
+
return "";
|
|
18
|
+
if (stringWidth(clean) <= width)
|
|
19
|
+
return clean;
|
|
20
|
+
let result = "";
|
|
21
|
+
let used = 0;
|
|
22
|
+
for (const { segment } of graphemes.segment(clean)) {
|
|
23
|
+
const size = stringWidth(segment);
|
|
24
|
+
if (used + size > width - 1)
|
|
25
|
+
break;
|
|
26
|
+
result += segment;
|
|
27
|
+
used += size;
|
|
28
|
+
}
|
|
29
|
+
return `${result}…`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/tui/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;AAE7E,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,wBAAwB,CAAC,IAAI,CAAC;SAClC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;SACtB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;SACpB,OAAO,CAAC,4CAA4C,EAAE,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,CAAC;AAEvC,+EAA+E;AAC/E,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,OAAe;IACnD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACrD,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3B,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAC9C,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,CAAC;YAAE,MAAM;QACnC,MAAM,IAAI,OAAO,CAAC;QAClB,IAAI,IAAI,IAAI,CAAC;IACf,CAAC;IACD,OAAO,GAAG,MAAM,GAAG,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { TurnEndEvent } from "../events.js";
|
|
2
|
+
import type { ViewState } from "./state.js";
|
|
3
|
+
export interface ViewOptions {
|
|
4
|
+
readonly width: number;
|
|
5
|
+
readonly now: number;
|
|
6
|
+
readonly height?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Renders the live region. Pure: no terminal, no clock, no colour.
|
|
10
|
+
*
|
|
11
|
+
* Colour is left to the painter so this stays comparable line by line — an
|
|
12
|
+
* escape sequence in the middle of a string makes "did this line change" a
|
|
13
|
+
* question about bytes rather than about content.
|
|
14
|
+
*/
|
|
15
|
+
export declare function view(state: ViewState, options: ViewOptions): readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* What a finished turn leaves behind in the terminal's own scrollback.
|
|
18
|
+
*
|
|
19
|
+
* Derived from the event rather than from the state, because by the time this
|
|
20
|
+
* is wanted the state has already been cleared — and because the event carries
|
|
21
|
+
* the authoritative message either way.
|
|
22
|
+
*/
|
|
23
|
+
export declare function transcriptLines(event: TurnEndEvent): readonly string[];
|
|
24
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/tui/view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,YAAY,CAAC;AAQzD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAmBD;;;;;;GAMG;AACH,wBAAgB,IAAI,CAClB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,WAAW,GACnB,SAAS,MAAM,EAAE,CAqCnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,MAAM,EAAE,CActE"}
|
package/dist/tui/view.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { formatTokens } from "../providers/usage.js";
|
|
2
|
+
import { callTarget } from "../tools/target.js";
|
|
3
|
+
import { fitLine } from "./text.js";
|
|
4
|
+
/** Tools listed individually before the rest are summarised as a count. */
|
|
5
|
+
const MAX_LISTED_TOOLS = 3;
|
|
6
|
+
/** Lines of the answer kept visible while it streams. */
|
|
7
|
+
const MAX_TEXT_LINES = 3;
|
|
8
|
+
function elapsed(from, now) {
|
|
9
|
+
const seconds = Math.max(0, Math.round((now - from) / 1000));
|
|
10
|
+
if (seconds < 60) {
|
|
11
|
+
return `${seconds}s`;
|
|
12
|
+
}
|
|
13
|
+
return `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, "0")}s`;
|
|
14
|
+
}
|
|
15
|
+
function describeTool(tool, now) {
|
|
16
|
+
const head = tool.target === undefined ? tool.name : `${tool.name} ${tool.target}`;
|
|
17
|
+
// The newest line of a tool's output says more than its first, and a running
|
|
18
|
+
// command's interesting output is at the end.
|
|
19
|
+
const latest = tool.progress.split("\n").filter((line) => line.length > 0).at(-1);
|
|
20
|
+
const suffix = latest === undefined ? "" : ` ${latest}`;
|
|
21
|
+
return ` ${head} (${elapsed(tool.startedAt, now)})${suffix}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Renders the live region. Pure: no terminal, no clock, no colour.
|
|
25
|
+
*
|
|
26
|
+
* Colour is left to the painter so this stays comparable line by line — an
|
|
27
|
+
* escape sequence in the middle of a string makes "did this line change" a
|
|
28
|
+
* question about bytes rather than about content.
|
|
29
|
+
*/
|
|
30
|
+
export function view(state, options) {
|
|
31
|
+
const run = state.run;
|
|
32
|
+
if (run === undefined) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const lines = [];
|
|
36
|
+
const tail = run.text.split("\n").slice(-MAX_TEXT_LINES);
|
|
37
|
+
for (const line of tail) {
|
|
38
|
+
if (line.length > 0) {
|
|
39
|
+
lines.push(fitLine(line, options.width));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const tool of run.running.slice(0, MAX_LISTED_TOOLS)) {
|
|
43
|
+
lines.push(fitLine(describeTool(tool, options.now), options.width));
|
|
44
|
+
}
|
|
45
|
+
const hidden = run.running.length - MAX_LISTED_TOOLS;
|
|
46
|
+
if (hidden > 0) {
|
|
47
|
+
lines.push(fitLine(` and ${hidden} more`, options.width));
|
|
48
|
+
}
|
|
49
|
+
const status = [
|
|
50
|
+
run.status === "thinking" ? "thinking" : "running tools",
|
|
51
|
+
`turn ${run.turn}/${run.maxTurns}`,
|
|
52
|
+
elapsed(run.startedAt, options.now),
|
|
53
|
+
];
|
|
54
|
+
if (run.usage !== undefined && run.usage.usage.totalTokens > 0) {
|
|
55
|
+
status.push(`${formatTokens(run.usage.usage.totalTokens)} tokens${run.usage.complete ? "" : "+"}`);
|
|
56
|
+
}
|
|
57
|
+
status.push("ctrl+c to stop");
|
|
58
|
+
lines.push(fitLine(status.join(" · "), options.width));
|
|
59
|
+
return lines.slice(-Math.max(1, options.height ?? lines.length));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* What a finished turn leaves behind in the terminal's own scrollback.
|
|
63
|
+
*
|
|
64
|
+
* Derived from the event rather than from the state, because by the time this
|
|
65
|
+
* is wanted the state has already been cleared — and because the event carries
|
|
66
|
+
* the authoritative message either way.
|
|
67
|
+
*/
|
|
68
|
+
export function transcriptLines(event) {
|
|
69
|
+
const lines = [];
|
|
70
|
+
// A result carries no arguments, so the target comes from the call that
|
|
71
|
+
// produced it — the same join by call id the eval runner makes.
|
|
72
|
+
const calls = new Map(event.message.toolCalls.map((call) => [call.id, call]));
|
|
73
|
+
for (const result of event.toolResults) {
|
|
74
|
+
const target = callTarget(calls.get(result.toolCallId)?.arguments);
|
|
75
|
+
const head = target === undefined ? result.toolName : `${result.toolName} ${target}`;
|
|
76
|
+
lines.push(` ${head}${result.isError ? " (failed)" : ""}`);
|
|
77
|
+
}
|
|
78
|
+
if (event.message.content.trim().length > 0) {
|
|
79
|
+
lines.push(event.message.content);
|
|
80
|
+
}
|
|
81
|
+
return lines;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/tui/view.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,2EAA2E;AAC3E,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,yDAAyD;AACzD,MAAM,cAAc,GAAG,CAAC,CAAC;AASzB,SAAS,OAAO,CAAC,IAAY,EAAE,GAAW;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAC7D,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC;QACjB,OAAO,GAAG,OAAO,GAAG,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;AACjF,CAAC;AAED,SAAS,YAAY,CAAC,IAAiB,EAAE,GAAW;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IACnF,6EAA6E;IAC7E,8CAA8C;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;IACzD,OAAO,KAAK,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAClB,KAAgB,EAChB,OAAoB;IAEpB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;IACtB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC;IACzD,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,EAAE,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,gBAAgB,CAAC;IACrD,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,MAAM,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,MAAM,GAAG;QACb,GAAG,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe;QACxD,QAAQ,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,QAAQ,EAAE;QAClC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC;KACpC,CAAC;IACF,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;QAC/D,MAAM,CAAC,IAAI,CACT,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CACtF,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC9B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAEzD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,KAAmB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,wEAAwE;IACxE,gEAAgE;IAChE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9E,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,EAAE,CAAC;QACrF,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface WelcomeOptions {
|
|
2
|
+
readonly version: string;
|
|
3
|
+
readonly provider: string;
|
|
4
|
+
readonly model: string;
|
|
5
|
+
readonly cwd: string;
|
|
6
|
+
readonly sessionId: string;
|
|
7
|
+
readonly resumed: boolean;
|
|
8
|
+
readonly signedOut: boolean;
|
|
9
|
+
readonly width: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function welcome(options: WelcomeOptions): string;
|
|
12
|
+
//# sourceMappingURL=welcome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"welcome.d.ts","sourceRoot":"","sources":["../../src/tui/welcome.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAyBvD"}
|