@agi-fans/dsh-tui 0.7.0 → 0.9.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/lib/CHANGELOG.md +44 -1
- package/lib/chrome/box.d.ts +0 -7
- package/lib/chrome/box.js +3 -22
- package/lib/chrome/box.js.map +1 -1
- package/lib/chrome/code-highlight.d.ts +45 -0
- package/lib/chrome/code-highlight.js +155 -0
- package/lib/chrome/code-highlight.js.map +1 -0
- package/lib/chrome/diff-render.d.ts +3 -1
- package/lib/chrome/diff-render.js +73 -9
- package/lib/chrome/diff-render.js.map +1 -1
- package/lib/chrome/main-screen-renderer.d.ts +55 -0
- package/lib/chrome/main-screen-renderer.js +343 -0
- package/lib/chrome/main-screen-renderer.js.map +1 -0
- package/lib/chrome/markdown.d.ts +3 -6
- package/lib/chrome/markdown.js +5 -59
- package/lib/chrome/markdown.js.map +1 -1
- package/lib/chrome/md-style.d.ts +31 -0
- package/lib/chrome/md-style.js +58 -0
- package/lib/chrome/md-style.js.map +1 -0
- package/lib/chrome/renderer.d.ts +8 -31
- package/lib/chrome/renderer.js.map +1 -1
- package/lib/chrome/welcome-tips.js +2 -2
- package/lib/chrome/welcome-tips.js.map +1 -1
- package/lib/chrome/width.d.ts +15 -0
- package/lib/chrome/width.js +83 -0
- package/lib/chrome/width.js.map +1 -1
- package/lib/commands/auth.d.ts +2 -1
- package/lib/commands/auth.js +318 -38
- package/lib/commands/auth.js.map +1 -1
- package/lib/commands/permission.js +1 -6
- package/lib/commands/permission.js.map +1 -1
- package/lib/definition.d.ts +1 -1
- package/lib/input/keys.d.ts +1 -28
- package/lib/input/keys.js +15 -31
- package/lib/input/keys.js.map +1 -1
- package/lib/runtime/provider-local.d.ts +7 -5
- package/lib/runtime/provider-local.js +134 -208
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/session/authorization-interaction.d.ts +12 -0
- package/lib/session/authorization-interaction.js +70 -0
- package/lib/session/authorization-interaction.js.map +1 -0
- package/lib/session/session-controller.d.ts +8 -4
- package/lib/session/session-controller.js +13 -12
- package/lib/session/session-controller.js.map +1 -1
- package/lib/views/autocomplete.d.ts +0 -2
- package/lib/views/autocomplete.js +0 -8
- package/lib/views/autocomplete.js.map +1 -1
- package/lib/views/copy-selector.d.ts +0 -4
- package/lib/views/copy-selector.js +0 -17
- package/lib/views/copy-selector.js.map +1 -1
- package/lib/views/event-views.d.ts +3 -16
- package/lib/views/event-views.js +127 -93
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/history-search.d.ts +0 -5
- package/lib/views/history-search.js +0 -16
- package/lib/views/history-search.js.map +1 -1
- package/lib/views/hotkeys.js +0 -1
- package/lib/views/hotkeys.js.map +1 -1
- package/lib/views/prompt-selector.d.ts +0 -5
- package/lib/views/prompt-selector.js +0 -13
- package/lib/views/prompt-selector.js.map +1 -1
- package/lib/views/settings-list.d.ts +0 -5
- package/lib/views/settings-list.js +0 -23
- package/lib/views/settings-list.js.map +1 -1
- package/package.json +29 -27
package/lib/views/event-views.js
CHANGED
|
@@ -24,6 +24,10 @@ import { renderTool } from "../chrome/tool-renderers.js";
|
|
|
24
24
|
import { renderToolsPanel } from "../chrome/tools-list.js";
|
|
25
25
|
import { renderCommandOutput, renderCommandSeparator } from "../chrome/command-output.js";
|
|
26
26
|
import { renderPathMentionRows } from "../chrome/path-mentions.js";
|
|
27
|
+
/** True for blocks whose rendered text may still change. */
|
|
28
|
+
function isBlockPending(block) {
|
|
29
|
+
return (block.kind === 'assistant' && block.streaming) || (block.kind === 'tool' && block.status === 'running');
|
|
30
|
+
}
|
|
27
31
|
/** Empty starting state. */
|
|
28
32
|
export function initialTranscript() {
|
|
29
33
|
return {
|
|
@@ -66,12 +70,41 @@ function prettyArgs(raw) {
|
|
|
66
70
|
return raw;
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
function isRetryNotice(block) {
|
|
74
|
+
return block?.kind === 'notice' && block.level === 'info' && block.text.startsWith('retrying ');
|
|
75
|
+
}
|
|
76
|
+
function formatRetryNotice(event) {
|
|
77
|
+
const budget = event.data.mode === 'always'
|
|
78
|
+
? `${event.data.retry}`
|
|
79
|
+
: `${event.data.retry}/${event.data.maxRetries}`;
|
|
80
|
+
return `retrying ${event.data.failure.code} (${budget})`;
|
|
81
|
+
}
|
|
82
|
+
function dropRetryNotice(blocks) {
|
|
83
|
+
if (isRetryNotice(blocks[blocks.length - 1]))
|
|
84
|
+
blocks.pop();
|
|
85
|
+
}
|
|
86
|
+
function isMutableAttemptBlock(block, turn, step) {
|
|
87
|
+
if (block.kind === 'assistant') {
|
|
88
|
+
return block.streaming && block.turn === turn && (step === undefined || block.step === step);
|
|
89
|
+
}
|
|
90
|
+
return block.kind === 'tool' && (block.status === 'running' || block.partial === true);
|
|
91
|
+
}
|
|
92
|
+
/** Drop trailing live mutable rows from a failed attempt and keep replay indexes aligned. */
|
|
93
|
+
function hideFailedAttempt(blocks, turn, step, indexes) {
|
|
94
|
+
while (blocks.length > 0) {
|
|
95
|
+
const last = blocks[blocks.length - 1];
|
|
96
|
+
if (last === undefined)
|
|
97
|
+
break;
|
|
98
|
+
if (isRetryNotice(last)) {
|
|
99
|
+
blocks.pop();
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!isMutableAttemptBlock(last, turn, step))
|
|
103
|
+
break;
|
|
104
|
+
blocks.pop();
|
|
105
|
+
if (last.kind === 'tool')
|
|
106
|
+
indexes?.toolByCallId.delete(last.callId);
|
|
107
|
+
}
|
|
75
108
|
}
|
|
76
109
|
/** Replace the trailing streaming block with a settled one, or append. */
|
|
77
110
|
function editableBlocks(state, mutable) {
|
|
@@ -79,6 +112,7 @@ function editableBlocks(state, mutable) {
|
|
|
79
112
|
}
|
|
80
113
|
function settleAssistant(state, turn, step, text, reasoning, interrupted, mutable) {
|
|
81
114
|
const blocks = editableBlocks(state, mutable);
|
|
115
|
+
dropRetryNotice(blocks);
|
|
82
116
|
const last = blocks[blocks.length - 1];
|
|
83
117
|
const settled = {
|
|
84
118
|
kind: 'assistant',
|
|
@@ -122,22 +156,38 @@ function foldEvent(state, event, presentation, mutable, indexes) {
|
|
|
122
156
|
switch (event.type) {
|
|
123
157
|
case 'turn/start':
|
|
124
158
|
return { ...state, status: 'running', turn: event.data.turn, todos: [], compactCommandId: undefined };
|
|
159
|
+
case 'llm/retry': {
|
|
160
|
+
const blocks = editableBlocks(state, mutable);
|
|
161
|
+
hideFailedAttempt(blocks, event.data.turn, event.data.step, indexes);
|
|
162
|
+
const notice = { kind: 'notice', level: 'info', text: formatRetryNotice(event) };
|
|
163
|
+
if (isRetryNotice(blocks[blocks.length - 1]))
|
|
164
|
+
blocks[blocks.length - 1] = notice;
|
|
165
|
+
else
|
|
166
|
+
blocks.push(notice);
|
|
167
|
+
return { ...state, blocks, status: 'running', turn: event.data.turn };
|
|
168
|
+
}
|
|
125
169
|
case 'turn/end': {
|
|
126
170
|
const last = state.blocks[state.blocks.length - 1];
|
|
127
171
|
const reason = event.data.reason;
|
|
128
172
|
const changesBlocks = (last?.kind === 'assistant' && last.streaming)
|
|
173
|
+
|| (last?.kind === 'tool' && (last.status === 'running' || last.partial === true))
|
|
174
|
+
|| isRetryNotice(last)
|
|
129
175
|
|| reason.kind === 'error'
|
|
130
176
|
|| reason.kind === 'aborted';
|
|
131
177
|
const blocks = changesBlocks ? editableBlocks(state, mutable) : state.blocks;
|
|
132
|
-
if (
|
|
133
|
-
blocks
|
|
178
|
+
if (reason.kind === 'error')
|
|
179
|
+
hideFailedAttempt(blocks, event.data.turn, undefined, indexes);
|
|
180
|
+
dropRetryNotice(blocks);
|
|
181
|
+
const settledLast = blocks[blocks.length - 1];
|
|
182
|
+
if (settledLast?.kind === 'assistant' && settledLast.streaming) {
|
|
183
|
+
blocks[blocks.length - 1] = { ...settledLast, streaming: false };
|
|
134
184
|
}
|
|
135
185
|
if (reason.kind === 'error') {
|
|
136
186
|
blocks.push({ kind: 'notice', level: 'error', text: 'error: ' + reason.error.code + ': ' + reason.error.message });
|
|
137
187
|
}
|
|
138
188
|
else if (reason.kind === 'aborted') {
|
|
139
|
-
//
|
|
140
|
-
// block
|
|
189
|
+
// A cancelled turn that already delivered a prefix finalizes it as an
|
|
190
|
+
// assistant block marked interrupted; the bare notice only covers a
|
|
141
191
|
// turn that aborted before any visible content.
|
|
142
192
|
const settledLast = blocks[blocks.length - 1];
|
|
143
193
|
if (settledLast?.kind !== 'assistant' || settledLast.interrupted !== true) {
|
|
@@ -163,12 +213,10 @@ function foldEvent(state, event, presentation, mutable, indexes) {
|
|
|
163
213
|
const { turn, step, chunk } = event.data;
|
|
164
214
|
if (chunk.type === 'text-delta') {
|
|
165
215
|
const blocks = editableBlocks(state, mutable);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (found?.kind === 'assistant')
|
|
171
|
-
blocks[idx] = { ...found, text: found.text + chunk.text };
|
|
216
|
+
dropRetryNotice(blocks);
|
|
217
|
+
const last = blocks[blocks.length - 1];
|
|
218
|
+
if (last?.kind === 'assistant' && last.streaming && last.turn === turn && last.step === step) {
|
|
219
|
+
blocks[blocks.length - 1] = { ...last, text: last.text + chunk.text };
|
|
172
220
|
}
|
|
173
221
|
else {
|
|
174
222
|
blocks.push({ kind: 'assistant', turn, step, text: chunk.text, reasoning: '', streaming: true });
|
|
@@ -177,12 +225,10 @@ function foldEvent(state, event, presentation, mutable, indexes) {
|
|
|
177
225
|
}
|
|
178
226
|
if (chunk.type === 'reasoning-delta') {
|
|
179
227
|
const blocks = editableBlocks(state, mutable);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (found?.kind === 'assistant')
|
|
185
|
-
blocks[idx] = { ...found, reasoning: found.reasoning + chunk.text };
|
|
228
|
+
dropRetryNotice(blocks);
|
|
229
|
+
const last = blocks[blocks.length - 1];
|
|
230
|
+
if (last?.kind === 'assistant' && last.streaming && last.turn === turn && last.step === step) {
|
|
231
|
+
blocks[blocks.length - 1] = { ...last, reasoning: last.reasoning + chunk.text };
|
|
186
232
|
}
|
|
187
233
|
else {
|
|
188
234
|
blocks.push({ kind: 'assistant', turn, step, text: '', reasoning: chunk.text, streaming: true });
|
|
@@ -191,6 +237,7 @@ function foldEvent(state, event, presentation, mutable, indexes) {
|
|
|
191
237
|
}
|
|
192
238
|
if (chunk.type === 'tool-call-delta') {
|
|
193
239
|
const blocks = editableBlocks(state, mutable);
|
|
240
|
+
dropRetryNotice(blocks);
|
|
194
241
|
const index = indexes === undefined
|
|
195
242
|
? blocks.findIndex(block => block.kind === 'tool' && block.callId === chunk.id)
|
|
196
243
|
: indexes.toolByCallId.get(chunk.id) ?? -1;
|
|
@@ -229,6 +276,7 @@ function foldEvent(state, event, presentation, mutable, indexes) {
|
|
|
229
276
|
...(presentation === undefined ? {} : { presentation }),
|
|
230
277
|
};
|
|
231
278
|
const blocks = editableBlocks(state, mutable);
|
|
279
|
+
dropRetryNotice(blocks);
|
|
232
280
|
const partial = indexes === undefined
|
|
233
281
|
? blocks.findIndex(item => item.kind === 'tool' && item.callId === event.data.callId)
|
|
234
282
|
: indexes.toolByCallId.get(event.data.callId) ?? -1;
|
|
@@ -483,12 +531,17 @@ export function blockLines(block, theme, width, spinnerFrame = 0, toolsExpanded
|
|
|
483
531
|
applyBg: false,
|
|
484
532
|
}, theme);
|
|
485
533
|
}
|
|
486
|
-
function fitFrame(lines, width) {
|
|
487
|
-
|
|
534
|
+
function fitFrame(lines, width, stablePrefix = 0) {
|
|
535
|
+
let fitted;
|
|
536
|
+
const start = Math.max(0, Math.min(lines.length, stablePrefix));
|
|
537
|
+
for (let index = start; index < lines.length; index += 1) {
|
|
538
|
+
const line = lines[index];
|
|
488
539
|
if (visibleWidth(line) <= width)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
540
|
+
continue;
|
|
541
|
+
fitted ??= lines.slice();
|
|
542
|
+
fitted[index] = truncateToWidth(line, width);
|
|
543
|
+
}
|
|
544
|
+
return fitted ?? lines;
|
|
492
545
|
}
|
|
493
546
|
/**
|
|
494
547
|
* Scroll, activity, inbox, and composer changes do not alter transcript blocks.
|
|
@@ -582,8 +635,6 @@ function commandSurfaceName(block) {
|
|
|
582
635
|
}
|
|
583
636
|
/** Rows moved per Shift+Arrow (OMP ScrollView `fastScrollLines`). */
|
|
584
637
|
export const TRANSCRIPT_FAST_SCROLL = 5;
|
|
585
|
-
/** Rows moved per mouse-wheel notch. */
|
|
586
|
-
export const TRANSCRIPT_WHEEL_SCROLL = 3;
|
|
587
638
|
function earlierLabel(count) {
|
|
588
639
|
return '… ↑ ' + count + ' earlier line' + (count === 1 ? '' : 's') + ' ⟨Pg↑⟩';
|
|
589
640
|
}
|
|
@@ -791,10 +842,10 @@ function subagentRowText(agent) {
|
|
|
791
842
|
return detail === '' ? indent + agent.label : `${indent}${agent.label} · ${detail}`;
|
|
792
843
|
}
|
|
793
844
|
/** Compact, unframed descendant-subagent tree placed above Todos. */
|
|
794
|
-
export function renderSubagents(roster, theme, width, spinnerFrame = 0, inspectedId) {
|
|
845
|
+
export function renderSubagents(roster, theme, width, spinnerFrame = 0, inspectedId, launcherFocused = false) {
|
|
795
846
|
const agents = roster?.agents ?? [];
|
|
796
847
|
if (agents.length === 0 || width <= 0)
|
|
797
|
-
return
|
|
848
|
+
return [];
|
|
798
849
|
const running = agents.filter(agent => agent.phase === 'running' || agent.phase === 'starting').length;
|
|
799
850
|
const failed = agents.filter(agent => agent.phase === 'error').length;
|
|
800
851
|
const done = agents.filter(agent => agent.phase === 'completed' || agent.phase === 'waiting').length;
|
|
@@ -803,8 +854,10 @@ export function renderSubagents(roster, theme, width, spinnerFrame = 0, inspecte
|
|
|
803
854
|
done === 0 ? undefined : `${done} done`,
|
|
804
855
|
failed === 0 ? undefined : `${failed} failed`,
|
|
805
856
|
].filter((part) => part !== undefined);
|
|
806
|
-
const
|
|
807
|
-
+ (counts.length === 0 ? '' : theme.fg('dim', ` · ${counts.join(' · ')}`))
|
|
857
|
+
const headerBody = theme.bold(theme.fg('accent', 'Agents'))
|
|
858
|
+
+ (counts.length === 0 ? '' : theme.fg('dim', ` · ${counts.join(' · ')}`))
|
|
859
|
+
+ theme.fg('dim', launcherFocused ? ' · Enter open · Esc return' : ' · ↓ select · Alt+A open');
|
|
860
|
+
const header = ' ' + (launcherFocused ? theme.inverse(headerBody) : headerBody);
|
|
808
861
|
const start = subagentPreviewStart(agents);
|
|
809
862
|
const end = Math.min(agents.length, start + SUBAGENT_PREVIEW);
|
|
810
863
|
const rows = [
|
|
@@ -812,12 +865,10 @@ export function renderSubagents(roster, theme, width, spinnerFrame = 0, inspecte
|
|
|
812
865
|
...agents.slice(start, end),
|
|
813
866
|
...(end === agents.length ? [] : [`… ${agents.length - end} more`]),
|
|
814
867
|
];
|
|
815
|
-
const items = [];
|
|
816
868
|
const lines = [header, ...rows.map((row, index) => {
|
|
817
869
|
const branch = ' ' + theme.fg('dim', index === rows.length - 1 ? '└─' : '├─') + ' ';
|
|
818
870
|
if (typeof row === 'string')
|
|
819
871
|
return branch + theme.fg('dim', row);
|
|
820
|
-
items.push({ id: row.id, row: index + 1 });
|
|
821
872
|
const selected = inspectedId === row.id;
|
|
822
873
|
const paint = row.phase === 'completed'
|
|
823
874
|
? (text) => theme.fg('dim', theme.strikethrough(text))
|
|
@@ -830,10 +881,7 @@ export function renderSubagents(roster, theme, width, spinnerFrame = 0, inspecte
|
|
|
830
881
|
const body = marker + subagentPhaseGlyph(row.phase, theme, spinnerFrame) + ' ' + paint(subagentRowText(row));
|
|
831
882
|
return branch + (selected ? theme.bold(body) : body);
|
|
832
883
|
})];
|
|
833
|
-
return
|
|
834
|
-
lines: lines.map(line => truncateToWidth(line, width)),
|
|
835
|
-
items,
|
|
836
|
-
};
|
|
884
|
+
return lines.map(line => truncateToWidth(line, width));
|
|
837
885
|
}
|
|
838
886
|
/** Persistent inspect chrome: stays visible while the child transcript scrolls. */
|
|
839
887
|
export function renderInspectBanner(inspected, theme, width, spinnerFrame = 0) {
|
|
@@ -845,10 +893,6 @@ export function renderInspectBanner(inspected, theme, width, spinnerFrame = 0) {
|
|
|
845
893
|
+ theme.fg('dim', ` · ${guidance}`);
|
|
846
894
|
return [truncateToWidth(line, width)];
|
|
847
895
|
}
|
|
848
|
-
/** Hit a painted roster row, or `undefined` when the click is on overflow chrome. */
|
|
849
|
-
export function hitTestSubagentRoster(items, localRow) {
|
|
850
|
-
return items.find(item => item.row === localRow)?.id;
|
|
851
|
-
}
|
|
852
896
|
function queuedSubmissionLabel(submission) {
|
|
853
897
|
const text = submission.text.replaceAll('\r\n', '\n').replaceAll('\r', '\n')
|
|
854
898
|
.replaceAll('\n', ' ↵ ')
|
|
@@ -925,7 +969,6 @@ export function renderView(state, options) {
|
|
|
925
969
|
lines: fitFrame(settings.lines, width),
|
|
926
970
|
cursor: settings.cursor,
|
|
927
971
|
cursorVisible: false,
|
|
928
|
-
overlay: { kind: 'settings', start: 0, itemRows: settings.itemRows },
|
|
929
972
|
};
|
|
930
973
|
}
|
|
931
974
|
if (options.promptSelector?.request.presentation === 'fullscreen-list') {
|
|
@@ -934,12 +977,6 @@ export function renderView(state, options) {
|
|
|
934
977
|
lines: fitFrame(selector.lines, width),
|
|
935
978
|
cursor: selector.cursor,
|
|
936
979
|
cursorVisible: true,
|
|
937
|
-
...(selector.editor === undefined ? {} : { editor: selector.editor }),
|
|
938
|
-
overlay: {
|
|
939
|
-
kind: 'prompt',
|
|
940
|
-
start: 0,
|
|
941
|
-
...(selector.itemRows === undefined ? {} : { itemRows: selector.itemRows }),
|
|
942
|
-
},
|
|
943
980
|
};
|
|
944
981
|
}
|
|
945
982
|
if (options.promptSelector?.request.presentation === 'plan-review') {
|
|
@@ -948,12 +985,7 @@ export function renderView(state, options) {
|
|
|
948
985
|
lines: fitFrame(review.lines, width),
|
|
949
986
|
cursor: review.cursor,
|
|
950
987
|
cursorVisible: review.cursorVisible === true,
|
|
951
|
-
...(review.
|
|
952
|
-
overlay: {
|
|
953
|
-
kind: 'prompt',
|
|
954
|
-
start: 0,
|
|
955
|
-
...(review.document === undefined ? {} : { document: review.document }),
|
|
956
|
-
},
|
|
988
|
+
...(review.document === undefined ? {} : { promptDocument: review.document }),
|
|
957
989
|
};
|
|
958
990
|
}
|
|
959
991
|
const welcome = renderWelcome({
|
|
@@ -1033,10 +1065,9 @@ export function renderView(state, options) {
|
|
|
1033
1065
|
: renderQueuedSubmissions(options.queuedSubmissions ?? [], theme, width, state.nextTurnInbox);
|
|
1034
1066
|
const todos = editor === undefined || options.inspected !== undefined ? [] : renderTodos(state.todos, theme, width);
|
|
1035
1067
|
const inspect = editor === undefined ? [] : renderInspectBanner(options.inspected, theme, width, spinnerFrame);
|
|
1036
|
-
const
|
|
1037
|
-
?
|
|
1038
|
-
: renderSubagents(options.subagents, theme, width, spinnerFrame, options.inspected?.id);
|
|
1039
|
-
const subagents = roster.lines;
|
|
1068
|
+
const subagents = editor === undefined
|
|
1069
|
+
? []
|
|
1070
|
+
: renderSubagents(options.subagents, theme, width, spinnerFrame, options.inspected?.id, options.subagentLauncherFocused);
|
|
1040
1071
|
const autocomplete = promptSelector !== undefined || settings !== undefined || copySelector !== undefined || search !== undefined
|
|
1041
1072
|
|| options.autocomplete === undefined
|
|
1042
1073
|
? []
|
|
@@ -1052,8 +1083,13 @@ export function renderView(state, options) {
|
|
|
1052
1083
|
const requestedStart = focusStart === undefined
|
|
1053
1084
|
? (options.scrollStart ?? Number.POSITIVE_INFINITY)
|
|
1054
1085
|
: transcriptStart + focusStart;
|
|
1055
|
-
const
|
|
1056
|
-
const
|
|
1086
|
+
const hasOverlay = promptSelector !== undefined || settings !== undefined || copySelector !== undefined || search !== undefined;
|
|
1087
|
+
const isFollowing = requestedStart === Number.POSITIVE_INFINITY && !hasOverlay;
|
|
1088
|
+
const livePinned = state.blocks.some(block => block.kind === 'tool' && block.status === 'running');
|
|
1089
|
+
const windowed = isFollowing
|
|
1090
|
+
? undefined
|
|
1091
|
+
: windowTranscript(body, budget, requestedStart, theme);
|
|
1092
|
+
const visible = windowed?.lines ?? body;
|
|
1057
1093
|
const lines = [...visible];
|
|
1058
1094
|
if (visible.length > 0)
|
|
1059
1095
|
lines.push('');
|
|
@@ -1061,9 +1097,7 @@ export function renderView(state, options) {
|
|
|
1061
1097
|
const fill = Math.max(0, height - lines.length - bottomRows);
|
|
1062
1098
|
lines.push(...Array.from({ length: fill }, () => ''));
|
|
1063
1099
|
lines.push(...working);
|
|
1064
|
-
const inspectStart = lines.length;
|
|
1065
1100
|
lines.push(...inspect);
|
|
1066
|
-
const subagentStart = lines.length;
|
|
1067
1101
|
lines.push(...subagents);
|
|
1068
1102
|
lines.push(...todos);
|
|
1069
1103
|
lines.push(...queuedSubmissions);
|
|
@@ -1071,7 +1105,27 @@ export function renderView(state, options) {
|
|
|
1071
1105
|
lines.push(...inputLines);
|
|
1072
1106
|
lines.push(...autocomplete);
|
|
1073
1107
|
lines.push(...statusFooter);
|
|
1074
|
-
|
|
1108
|
+
let liveStart;
|
|
1109
|
+
if (isFollowing) {
|
|
1110
|
+
const firstPending = state.blocks.findIndex(isBlockPending);
|
|
1111
|
+
if (firstPending >= 0) {
|
|
1112
|
+
liveStart = transcriptStart + transcript.blockStarts[firstPending];
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
liveStart = lines.length - bottomRows;
|
|
1116
|
+
}
|
|
1117
|
+
// liveStart marks the first row that is still live/mutable. Rows above it
|
|
1118
|
+
// are committed. Off-screen live rows are bounded by the renderer: it only
|
|
1119
|
+
// ever writes the live viewport, so pending rows above the visible window
|
|
1120
|
+
// are not pushed into native scrollback until they become committed.
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
liveStart = 0;
|
|
1124
|
+
}
|
|
1125
|
+
// Every settled block was already rendered against this width. Mirroring
|
|
1126
|
+
// OMP's stable-prefix preparation, only validate the mutable suffix instead
|
|
1127
|
+
// of measuring the complete native-scrollback history on every frame.
|
|
1128
|
+
const trimmed = fitFrame(lines, width, isFollowing ? liveStart : 0);
|
|
1075
1129
|
const caret = promptSelector?.cursor ?? settings?.cursor ?? copySelector?.cursor ?? search?.cursor ?? editor?.cursor ?? { row: 0, column: 0 };
|
|
1076
1130
|
return {
|
|
1077
1131
|
lines: trimmed,
|
|
@@ -1083,35 +1137,15 @@ export function renderView(state, options) {
|
|
|
1083
1137
|
|| (options.inspected !== undefined && options.inspected.writable !== true)
|
|
1084
1138
|
? false
|
|
1085
1139
|
: promptSelector?.cursorVisible ?? (settings === undefined && copySelector === undefined),
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
? { overlay: { kind: 'search', start: editorStart, resultsRow: search.resultsRow } }
|
|
1095
|
-
: autocomplete.length > 0
|
|
1096
|
-
? { overlay: { kind: 'autocomplete', start: editorStart + (editor?.lines.length ?? 0) } }
|
|
1097
|
-
: {}),
|
|
1098
|
-
transcript: {
|
|
1099
|
-
start: windowed.start,
|
|
1100
|
-
maxStart: windowed.maxStart,
|
|
1101
|
-
budget: windowed.budget,
|
|
1102
|
-
hiddenAbove: windowed.hiddenAbove,
|
|
1103
|
-
hiddenBelow: windowed.hiddenBelow,
|
|
1140
|
+
liveStart,
|
|
1141
|
+
livePinned,
|
|
1142
|
+
transcript: windowed ?? {
|
|
1143
|
+
start: 0,
|
|
1144
|
+
maxStart: 0,
|
|
1145
|
+
budget,
|
|
1146
|
+
hiddenAbove: 0,
|
|
1147
|
+
hiddenBelow: 0,
|
|
1104
1148
|
},
|
|
1105
|
-
...(inspect.length === 0 && subagents.length === 0
|
|
1106
|
-
? {}
|
|
1107
|
-
: {
|
|
1108
|
-
chrome: {
|
|
1109
|
-
...(inspect.length === 0 ? {} : { inspect: { start: inspectStart, rows: inspect.length } }),
|
|
1110
|
-
...(subagents.length === 0
|
|
1111
|
-
? {}
|
|
1112
|
-
: { subagents: { start: subagentStart, headerRows: 1, rows: subagents.length, items: roster.items } }),
|
|
1113
|
-
},
|
|
1114
|
-
}),
|
|
1115
1149
|
};
|
|
1116
1150
|
}
|
|
1117
1151
|
//# sourceMappingURL=event-views.js.map
|