@steerable/agent-cli 0.6.63 → 0.6.64
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/tui/view.d.ts +11 -0
- package/dist/tui/view.js +59 -3
- package/package.json +4 -4
package/dist/tui/view.d.ts
CHANGED
|
@@ -20,10 +20,21 @@ export declare class OpenTuiView {
|
|
|
20
20
|
private bodyKey;
|
|
21
21
|
private overlayKey;
|
|
22
22
|
private picksKey;
|
|
23
|
+
private chatListOpen;
|
|
24
|
+
private transcriptPinned;
|
|
25
|
+
private transcriptScroll;
|
|
26
|
+
private revealId;
|
|
27
|
+
private restoreTranscript;
|
|
28
|
+
private readonly onFrame;
|
|
23
29
|
constructor(renderer: CliRenderer);
|
|
24
30
|
scrollPage(direction: -1 | 1): void;
|
|
25
31
|
scrollEdge(edge: 'top' | 'bottom'): void;
|
|
26
32
|
apply(screen: TuiScreen): void;
|
|
33
|
+
/** Transcript stays pinned to the bottom. The chat list follows the selected row instead. */
|
|
34
|
+
private followChats;
|
|
35
|
+
private atBottom;
|
|
36
|
+
private maxScrollTop;
|
|
37
|
+
private viewportRows;
|
|
27
38
|
private paintOverlay;
|
|
28
39
|
private paintPicks;
|
|
29
40
|
private replaceBody;
|
package/dist/tui/view.js
CHANGED
|
@@ -34,8 +34,31 @@ export class OpenTuiView {
|
|
|
34
34
|
bodyKey = '';
|
|
35
35
|
overlayKey = '';
|
|
36
36
|
picksKey = '';
|
|
37
|
+
chatListOpen = false;
|
|
38
|
+
transcriptPinned = true;
|
|
39
|
+
transcriptScroll = 0;
|
|
40
|
+
revealId = null;
|
|
41
|
+
restoreTranscript = false;
|
|
42
|
+
onFrame = () => {
|
|
43
|
+
if (this.restoreTranscript) {
|
|
44
|
+
this.restoreTranscript = false;
|
|
45
|
+
this.body.stickyScroll = true;
|
|
46
|
+
const max = this.maxScrollTop();
|
|
47
|
+
this.body.scrollTop = this.transcriptPinned ? max : Math.min(this.transcriptScroll, max);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!this.revealId)
|
|
51
|
+
return;
|
|
52
|
+
const id = this.revealId;
|
|
53
|
+
this.revealId = null;
|
|
54
|
+
this.body.scrollChildIntoView(id);
|
|
55
|
+
};
|
|
37
56
|
constructor(renderer) {
|
|
38
57
|
this.renderer = renderer;
|
|
58
|
+
renderer.on('frame', this.onFrame);
|
|
59
|
+
renderer.once('destroy', () => {
|
|
60
|
+
renderer.off('frame', this.onFrame);
|
|
61
|
+
});
|
|
39
62
|
const shell = new BoxRenderable(renderer, {
|
|
40
63
|
width: '100%',
|
|
41
64
|
height: '100%',
|
|
@@ -173,12 +196,44 @@ export class OpenTuiView {
|
|
|
173
196
|
this.body.scrollChildIntoView(`line-${screen.searchFocus}`);
|
|
174
197
|
this.paintOverlay(screen);
|
|
175
198
|
this.paintPicks(screen);
|
|
199
|
+
this.followChats(screen);
|
|
176
200
|
const key = bodyKey(screen);
|
|
177
201
|
if (key === this.bodyKey)
|
|
178
202
|
return;
|
|
179
203
|
this.bodyKey = key;
|
|
180
204
|
this.replaceBody(screen);
|
|
181
205
|
}
|
|
206
|
+
/** Transcript stays pinned to the bottom. The chat list follows the selected row instead. */
|
|
207
|
+
followChats(screen) {
|
|
208
|
+
const chats = screen.chats;
|
|
209
|
+
if (chats && !this.chatListOpen) {
|
|
210
|
+
this.transcriptPinned = this.atBottom();
|
|
211
|
+
this.transcriptScroll = this.body.scrollTop;
|
|
212
|
+
this.body.stickyScroll = false;
|
|
213
|
+
this.body.scrollTop = 0;
|
|
214
|
+
this.chatListOpen = true;
|
|
215
|
+
}
|
|
216
|
+
else if (!chats && this.chatListOpen) {
|
|
217
|
+
this.chatListOpen = false;
|
|
218
|
+
this.revealId = null;
|
|
219
|
+
this.restoreTranscript = true;
|
|
220
|
+
this.body.stickyScroll = false;
|
|
221
|
+
}
|
|
222
|
+
if (!chats)
|
|
223
|
+
return;
|
|
224
|
+
const index = chats.findIndex((chat) => chat.selected);
|
|
225
|
+
this.revealId = index < 0 ? null : index === 0 ? 'chat-heading' : `chat-${index}`;
|
|
226
|
+
}
|
|
227
|
+
atBottom() {
|
|
228
|
+
return this.body.scrollTop >= this.maxScrollTop() - 1;
|
|
229
|
+
}
|
|
230
|
+
maxScrollTop() {
|
|
231
|
+
return Math.max(0, this.body.scrollHeight - this.viewportRows());
|
|
232
|
+
}
|
|
233
|
+
viewportRows() {
|
|
234
|
+
const height = this.body.viewport.height;
|
|
235
|
+
return typeof height === 'number' ? height : 0;
|
|
236
|
+
}
|
|
182
237
|
paintOverlay(screen) {
|
|
183
238
|
const lines = screen.approval
|
|
184
239
|
? approvalLines(screen.approval)
|
|
@@ -239,9 +294,10 @@ export class OpenTuiView {
|
|
|
239
294
|
return;
|
|
240
295
|
}
|
|
241
296
|
if (screen.chats) {
|
|
242
|
-
this.body.add(text(renderer, dim, '会话'));
|
|
243
|
-
|
|
297
|
+
this.body.add(text(renderer, dim, '会话', 'chat-heading'));
|
|
298
|
+
screen.chats.forEach((chat, index) => {
|
|
244
299
|
const row = new BoxRenderable(renderer, {
|
|
300
|
+
id: `chat-${index}`,
|
|
245
301
|
width: '100%',
|
|
246
302
|
height: 1,
|
|
247
303
|
backgroundColor: chat.selected ? selected : canvas,
|
|
@@ -249,7 +305,7 @@ export class OpenTuiView {
|
|
|
249
305
|
});
|
|
250
306
|
row.add(text(renderer, chat.selected ? ink : dim, chatText(chat)));
|
|
251
307
|
this.body.add(row);
|
|
252
|
-
}
|
|
308
|
+
});
|
|
253
309
|
return;
|
|
254
310
|
}
|
|
255
311
|
screen.lines.forEach((line, index) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steerable/agent-cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.64",
|
|
4
4
|
"description": "Product-neutral command line for a Steerable host. Products supply the bin name and brand.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://steerableframework.com/",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@earendil-works/pi-tui": "0.87.1",
|
|
40
40
|
"@opentui/core": "0.5.12",
|
|
41
|
-
"@steerable/agent-client": "0.6.
|
|
42
|
-
"@steerable/agent-protocol": "0.6.
|
|
43
|
-
"@steerable/agent-shell": "0.6.
|
|
41
|
+
"@steerable/agent-client": "0.6.64",
|
|
42
|
+
"@steerable/agent-protocol": "0.6.64",
|
|
43
|
+
"@steerable/agent-shell": "0.6.64"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^22.10.5",
|