@oh-my-pi/pi-tui 18.4.0 → 18.4.1
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/CHANGELOG.md +28 -0
- package/dist/types/chat/image-loading.d.ts +24 -0
- package/dist/types/chat/transcript-entry.d.ts +9 -0
- package/dist/types/chrome/transcript-container.d.ts +9 -2
- package/dist/types/overlays/agents-hub.d.ts +7 -4
- package/dist/types/overlays/rewind-selector.d.ts +3 -3
- package/dist/types/overlays/usage-dashboard.d.ts +9 -2
- package/dist/types/prompt/composer-cache.d.ts +34 -16
- package/dist/types/prompt/composer.d.ts +15 -18
- package/dist/types/prompt/welcome.d.ts +5 -2
- package/dist/types/status-line/component.d.ts +13 -4
- package/dist/types/status-line/metrics.d.ts +0 -1
- package/dist/types/status-line/startup.d.ts +38 -0
- package/dist/types/status-line/types.d.ts +0 -2
- package/dist/types/terminal-capabilities.d.ts +10 -6
- package/dist/types/tools/output-meta.d.ts +2 -1
- package/dist/types/tools/vibe.d.ts +4 -0
- package/package.json +9 -9
- package/src/chat/assistant-message.ts +27 -21
- package/src/chat/image-loading.ts +81 -0
- package/src/chat/tool-execution.ts +29 -13
- package/src/chat/transcript-entry.ts +16 -0
- package/src/chrome/transcript-container.ts +208 -74
- package/src/components/image.ts +10 -2
- package/src/overlays/agents-hub.ts +7 -18
- package/src/overlays/copy-selector.ts +3 -31
- package/src/overlays/model-hub.ts +49 -16
- package/src/overlays/rewind-selector.ts +51 -12
- package/src/overlays/usage-dashboard.ts +47 -6
- package/src/prompt/composer-cache.ts +217 -196
- package/src/prompt/composer.ts +40 -70
- package/src/prompt/welcome.ts +31 -28
- package/src/status-line/component.ts +73 -50
- package/src/status-line/metrics.ts +3 -21
- package/src/status-line/segments.ts +34 -50
- package/src/status-line/startup.ts +181 -0
- package/src/status-line/types.ts +0 -2
- package/src/terminal-capabilities.ts +12 -6
- package/src/terminal.ts +38 -9
- package/src/tools/output-meta.ts +11 -3
- package/src/tools/vibe.ts +15 -2
- package/src/tui.ts +66 -42
package/src/tools/vibe.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface VibeToolDetails {
|
|
|
23
23
|
op: VibeOp;
|
|
24
24
|
/** Live TV-wall snapshot of the owner's worker sessions at (or during) the call. */
|
|
25
25
|
screens: VibeScreenSnapshot[];
|
|
26
|
+
/** Sessions the director killed, left off `screens`; shown as a count. */
|
|
27
|
+
hiddenKilled?: string[];
|
|
26
28
|
spawned?: { id: string; cli: VibeCli; jobId: string };
|
|
27
29
|
send?: VibeSendOutcome;
|
|
28
30
|
wait?: {
|
|
@@ -46,6 +48,8 @@ export interface VibeScreenSnapshot {
|
|
|
46
48
|
id: string;
|
|
47
49
|
cli: VibeCli;
|
|
48
50
|
state: VibeSessionState;
|
|
51
|
+
/** Terminated by the director (`vibe_kill`) or mode teardown; unset for workers that died on their own. */
|
|
52
|
+
killed?: boolean;
|
|
49
53
|
model?: string;
|
|
50
54
|
turns: number;
|
|
51
55
|
queued: number;
|
|
@@ -373,13 +377,21 @@ export function createVibeToolRenderer(op: VibeOp) {
|
|
|
373
377
|
return new Text(header, 0, 0);
|
|
374
378
|
}
|
|
375
379
|
|
|
376
|
-
// wait/list: the TV wall.
|
|
380
|
+
// wait/list: the TV wall. Director-killed sessions arrive pre-filtered
|
|
381
|
+
// (see `hiddenKilled`) so a long-running director's wall stays legible.
|
|
377
382
|
const screens = details.screens;
|
|
383
|
+
const hiddenKilled = details.hiddenKilled?.length ?? 0;
|
|
384
|
+
const killedMeta = hiddenKilled > 0 ? [uiTheme.fg("dim", `${hiddenKilled} killed hidden`)] : [];
|
|
378
385
|
if (screens.length === 0) {
|
|
379
386
|
const fallback = result.content.find(part => part.type === "text")?.text ?? "no sessions";
|
|
387
|
+
const gist = hiddenKilled > 0 ? "no live sessions" : fallback;
|
|
380
388
|
return new Text(
|
|
381
389
|
renderStatusLine(
|
|
382
|
-
{
|
|
390
|
+
{
|
|
391
|
+
icon: "warning",
|
|
392
|
+
title: `vibe ${op}`,
|
|
393
|
+
meta: [uiTheme.fg("dim", frameText(gist, 60)), ...killedMeta],
|
|
394
|
+
},
|
|
383
395
|
uiTheme,
|
|
384
396
|
),
|
|
385
397
|
0,
|
|
@@ -394,6 +406,7 @@ export function createVibeToolRenderer(op: VibeOp) {
|
|
|
394
406
|
if (running > 0) meta.push(uiTheme.fg("accent", `${running} on air`));
|
|
395
407
|
if (settledById.size > 0) meta.push(uiTheme.fg("success", `${settledById.size} settled`));
|
|
396
408
|
if (details.wait?.timedOut) meta.push(uiTheme.fg("warning", "timed out"));
|
|
409
|
+
meta.push(...killedMeta);
|
|
397
410
|
const title =
|
|
398
411
|
op === "wait"
|
|
399
412
|
? waiting
|
package/src/tui.ts
CHANGED
|
@@ -883,7 +883,8 @@ export class TUI extends Container {
|
|
|
883
883
|
// engine paints only the modal on the alt buffer and leaves every
|
|
884
884
|
// normal-screen accounting field (#previousFrameLength, #viewportTopRow, …)
|
|
885
885
|
// untouched, so exiting reconciles cleanly against the terminal-restored
|
|
886
|
-
// normal screen. #altPreviousLines is the last alt frame,
|
|
886
|
+
// normal screen. #altPreviousLines is the last alt frame, diffed row by row
|
|
887
|
+
// against the next one.
|
|
887
888
|
#altActive = false;
|
|
888
889
|
#mouseTracking: MouseTrackingState = "off";
|
|
889
890
|
/** Product-owned probe for opt-in normal-buffer click capture (`tui.mouse`). Read every frame. */
|
|
@@ -2867,16 +2868,18 @@ export class TUI extends Container {
|
|
|
2867
2868
|
this.#providerWindow.length > 0;
|
|
2868
2869
|
if (diffable) {
|
|
2869
2870
|
for (let index = 0; index < rows; index++) {
|
|
2870
|
-
const previous = this.#providerPreparedRows[index];
|
|
2871
|
-
const current = prepared.rows[index]!;
|
|
2872
2871
|
if (
|
|
2873
|
-
this.#
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2872
|
+
!this.#rowNeedsRewrite(
|
|
2873
|
+
this.#providerWindow,
|
|
2874
|
+
this.#providerPreparedRows,
|
|
2875
|
+
prepared.lines,
|
|
2876
|
+
prepared.rows,
|
|
2877
|
+
index,
|
|
2878
|
+
)
|
|
2877
2879
|
) {
|
|
2878
2880
|
continue;
|
|
2879
2881
|
}
|
|
2882
|
+
const current = prepared.rows[index]!;
|
|
2880
2883
|
buffer += `\x1b[${newTop + index + 1};1H${this.#lineRewriteSequence(
|
|
2881
2884
|
current,
|
|
2882
2885
|
width,
|
|
@@ -3440,6 +3443,29 @@ export class TUI extends Container {
|
|
|
3440
3443
|
return visibleWidth(above);
|
|
3441
3444
|
}
|
|
3442
3445
|
|
|
3446
|
+
/**
|
|
3447
|
+
* Whether screen row `index` must be rewritten to turn the previously painted
|
|
3448
|
+
* frame into this one: its line, or the preparation it was painted with,
|
|
3449
|
+
* changed.
|
|
3450
|
+
*/
|
|
3451
|
+
#rowNeedsRewrite(
|
|
3452
|
+
previousLines: readonly string[],
|
|
3453
|
+
previousRows: readonly PreparedLine[],
|
|
3454
|
+
lines: readonly string[],
|
|
3455
|
+
rows: readonly PreparedLine[],
|
|
3456
|
+
index: number,
|
|
3457
|
+
): boolean {
|
|
3458
|
+
const previous = previousRows[index];
|
|
3459
|
+
const current = rows[index]!;
|
|
3460
|
+
return (
|
|
3461
|
+
previousLines[index] !== lines[index] ||
|
|
3462
|
+
previous === undefined ||
|
|
3463
|
+
previous.width !== current.width ||
|
|
3464
|
+
previous.widthEpoch !== current.widthEpoch ||
|
|
3465
|
+
previous.imageProtocol !== current.imageProtocol
|
|
3466
|
+
);
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3443
3469
|
#lineRewriteSequence(
|
|
3444
3470
|
line: PreparedLine,
|
|
3445
3471
|
width: number,
|
|
@@ -3549,9 +3575,11 @@ export class TUI extends Container {
|
|
|
3549
3575
|
}
|
|
3550
3576
|
|
|
3551
3577
|
/**
|
|
3552
|
-
*
|
|
3553
|
-
*
|
|
3554
|
-
*
|
|
3578
|
+
* Paint a frame on the alt buffer: only the rows that changed since the
|
|
3579
|
+
* previous frame, or every row when the height changed, a repaint is forced,
|
|
3580
|
+
* or a changed frame holds OSC 66 text before or after. Emits only
|
|
3581
|
+
* sync-output brackets, cursor moves, and per-row rewrites — never ED3 or
|
|
3582
|
+
* any native-scrollback byte. The hardware cursor stays hidden here.
|
|
3555
3583
|
*/
|
|
3556
3584
|
#emitAltFrame(prepared: PreparedLines, width: number, height: number, notifyPaint: boolean): void {
|
|
3557
3585
|
// The pass that composed this frame ran with `altScreen`, so the normal
|
|
@@ -3573,38 +3601,34 @@ export class TUI extends Container {
|
|
|
3573
3601
|
for (const seq of imageTransmits) transmitBuffer += seq;
|
|
3574
3602
|
this.terminal.write(transmitBuffer);
|
|
3575
3603
|
}
|
|
3576
|
-
//
|
|
3577
|
-
//
|
|
3578
|
-
//
|
|
3579
|
-
//
|
|
3604
|
+
// A forced repaint (resetDisplay, requestRender(true)) rewrites every row
|
|
3605
|
+
// even when the cached frame is byte-identical: the redraw gesture must
|
|
3606
|
+
// repair a corrupted modal. So does a changed frame with OSC 66 text in
|
|
3607
|
+
// it, before or after: a scaled glyph spans the rows below its own and the
|
|
3608
|
+
// terminal drops it when any of them is written, so those rows are not
|
|
3609
|
+
// independent. Otherwise rewrite only the rows that changed (a keystroke
|
|
3610
|
+
// in a modal touches a row or two), and skip an identical frame entirely.
|
|
3580
3611
|
const force = this.#forceViewportRepaintOnNextRender;
|
|
3581
3612
|
this.#forceViewportRepaintOnNextRender = false;
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
previous.width !== current.width ||
|
|
3591
|
-
previous.widthEpoch !== current.widthEpoch ||
|
|
3592
|
-
previous.imageProtocol !== current.imageProtocol
|
|
3593
|
-
) {
|
|
3594
|
-
same = false;
|
|
3595
|
-
break;
|
|
3596
|
-
}
|
|
3597
|
-
}
|
|
3598
|
-
if (same) {
|
|
3599
|
-
this.#altPreviousLines = prepared.lines;
|
|
3600
|
-
this.#altPreparedRows = prepared.rows;
|
|
3601
|
-
return;
|
|
3602
|
-
}
|
|
3603
|
-
}
|
|
3604
|
-
let buffer = `${this.#paintBeginSequence}\x1b[H`;
|
|
3613
|
+
const full =
|
|
3614
|
+
force ||
|
|
3615
|
+
this.#altPreviousLines.length !== height ||
|
|
3616
|
+
((this.#altPreviousLines.some(isOsc66Line) || prepared.lines.some(isOsc66Line)) &&
|
|
3617
|
+
prepared.rows.some((_row, r) =>
|
|
3618
|
+
this.#rowNeedsRewrite(this.#altPreviousLines, this.#altPreparedRows, prepared.lines, prepared.rows, r),
|
|
3619
|
+
));
|
|
3620
|
+
let rowsBuffer = "";
|
|
3605
3621
|
for (let r = 0; r < height; r++) {
|
|
3606
|
-
if (
|
|
3607
|
-
|
|
3622
|
+
if (full) {
|
|
3623
|
+
if (r > 0) rowsBuffer += "\n";
|
|
3624
|
+
} else if (
|
|
3625
|
+
this.#rowNeedsRewrite(this.#altPreviousLines, this.#altPreparedRows, prepared.lines, prepared.rows, r)
|
|
3626
|
+
) {
|
|
3627
|
+
rowsBuffer += `\x1b[${r + 1};1H`;
|
|
3628
|
+
} else {
|
|
3629
|
+
continue;
|
|
3630
|
+
}
|
|
3631
|
+
rowsBuffer += this.#lineRewriteSequence(
|
|
3608
3632
|
prepared.rows[r]!,
|
|
3609
3633
|
width,
|
|
3610
3634
|
r,
|
|
@@ -3613,10 +3637,10 @@ export class TUI extends Container {
|
|
|
3613
3637
|
this.#osc66SpacerGlyphWidth(prepared.lines, r),
|
|
3614
3638
|
);
|
|
3615
3639
|
}
|
|
3616
|
-
buffer += this.#paintEndSequence;
|
|
3617
|
-
this.terminal.write(buffer);
|
|
3618
3640
|
this.#altPreviousLines = prepared.lines;
|
|
3619
3641
|
this.#altPreparedRows = prepared.rows;
|
|
3642
|
+
if (rowsBuffer === "") return;
|
|
3643
|
+
this.terminal.write(`${this.#paintBeginSequence}${full ? "\x1b[H" : ""}${rowsBuffer}${this.#paintEndSequence}`);
|
|
3620
3644
|
this.#debugPaint = { lines: prepared.lines, windowTop: 0, altScreen: true };
|
|
3621
3645
|
if (notifyPaint) {
|
|
3622
3646
|
this.#notifyPaint({
|
|
@@ -3628,6 +3652,6 @@ export class TUI extends Container {
|
|
|
3628
3652
|
rows: height,
|
|
3629
3653
|
});
|
|
3630
3654
|
}
|
|
3631
|
-
this.#fullRedrawCount += 1;
|
|
3655
|
+
if (full) this.#fullRedrawCount += 1;
|
|
3632
3656
|
}
|
|
3633
3657
|
}
|