pi-ui-extend 0.1.32 → 0.1.34
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 +1 -1
- package/dist/app/app.d.ts +2 -0
- package/dist/app/app.js +28 -0
- package/dist/app/commands/command-session-actions.js +29 -1
- package/dist/app/constants.d.ts +1 -1
- package/dist/app/constants.js +2 -2
- package/dist/app/icons.d.ts +4 -9
- package/dist/app/icons.js +12 -35
- package/dist/app/model/model-usage-status.d.ts +2 -1
- package/dist/app/model/model-usage-status.js +33 -25
- package/dist/app/rendering/conversation-entry-renderer.d.ts +1 -0
- package/dist/app/rendering/conversation-tool-renderer.d.ts +1 -0
- package/dist/app/rendering/conversation-tool-renderer.js +12 -18
- package/dist/app/rendering/conversation-viewport.d.ts +4 -0
- package/dist/app/rendering/conversation-viewport.js +144 -13
- package/dist/app/rendering/dcp-stats.js +42 -16
- package/dist/app/rendering/render-controller.js +4 -0
- package/dist/app/rendering/status-line-renderer.d.ts +8 -1
- package/dist/app/rendering/status-line-renderer.js +36 -1
- package/dist/app/rendering/tab-line-renderer.js +2 -2
- package/dist/app/rendering/tool-block-renderer.d.ts +1 -0
- package/dist/app/rendering/tool-block-renderer.js +37 -11
- package/dist/app/runtime.js +1 -1
- package/dist/app/screen/mouse-controller.d.ts +5 -1
- package/dist/app/screen/mouse-controller.js +16 -0
- package/dist/app/screen/scroll-controller.d.ts +20 -0
- package/dist/app/screen/scroll-controller.js +127 -10
- package/dist/app/session/lazy-session-manager.js +35 -5
- package/dist/app/session/pix-system-message.d.ts +1 -0
- package/dist/app/session/pix-system-message.js +14 -3
- package/dist/app/session/queued-message-controller.d.ts +11 -4
- package/dist/app/session/queued-message-controller.js +74 -59
- package/dist/app/session/queued-message-entries.d.ts +2 -1
- package/dist/app/session/queued-message-entries.js +12 -1
- package/dist/app/session/session-event-controller.d.ts +42 -1
- package/dist/app/session/session-event-controller.js +500 -31
- package/dist/app/session/session-history.js +23 -4
- package/dist/app/session/tabs-controller.d.ts +11 -1
- package/dist/app/session/tabs-controller.js +102 -21
- package/dist/app/types.d.ts +14 -1
- package/dist/bundled-extensions/question/contract.d.ts +25 -0
- package/dist/bundled-extensions/question/contract.js +94 -0
- package/dist/bundled-extensions/question/index.d.ts +7 -0
- package/dist/bundled-extensions/question/index.js +28 -0
- package/dist/bundled-extensions/question/render.d.ts +4 -0
- package/dist/bundled-extensions/question/render.js +27 -0
- package/dist/bundled-extensions/question/result.d.ts +6 -0
- package/dist/bundled-extensions/question/result.js +84 -0
- package/dist/bundled-extensions/question/tool-description.d.ts +7 -0
- package/dist/bundled-extensions/question/tool-description.js +11 -0
- package/dist/bundled-extensions/question/tui.d.ts +2 -0
- package/dist/bundled-extensions/question/tui.js +577 -0
- package/dist/bundled-extensions/question/types.d.ts +103 -0
- package/dist/bundled-extensions/question/types.js +1 -0
- package/dist/bundled-extensions/session-title/config.d.ts +17 -0
- package/dist/bundled-extensions/session-title/config.js +150 -0
- package/dist/bundled-extensions/session-title/index.d.ts +5 -0
- package/dist/bundled-extensions/session-title/index.js +384 -0
- package/dist/bundled-extensions/session-title/title-generation.d.ts +26 -0
- package/dist/bundled-extensions/session-title/title-generation.js +141 -0
- package/dist/bundled-extensions/terminal-bell/index.d.ts +14 -0
- package/dist/bundled-extensions/terminal-bell/index.js +491 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -1
- package/dist/default-pix-config.js +2 -1
- package/dist/icon-theme.d.ts +7 -0
- package/dist/icon-theme.js +36 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +4 -0
- package/dist/schemas/pi-tools-suite-schema.js +5 -0
- package/dist/schemas/pix-schema.d.ts +1 -0
- package/dist/schemas/pix-schema.js +1 -0
- package/external/pi-tools-suite/README.md +7 -7
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +16 -16
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +18 -4
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +4 -0
- package/external/pi-tools-suite/src/async-subagents/tools/result.ts +14 -26
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +0 -1
- package/external/pi-tools-suite/src/dcp/config.ts +14 -14
- package/external/pi-tools-suite/src/dcp/index.ts +31 -43
- package/external/pi-tools-suite/src/dcp/state-persistence.ts +151 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +25 -18
- package/external/pi-tools-suite/src/tool-descriptions.ts +34 -54
- package/package.json +3 -2
- package/schemas/pi-tools-suite.json +14 -0
- package/schemas/pix.json +7 -0
- package/extensions/question/contract.ts +0 -100
- package/extensions/question/index.ts +0 -34
- package/extensions/question/render.ts +0 -28
- package/extensions/question/result.ts +0 -86
- package/extensions/question/tool-description.ts +0 -11
- package/extensions/question/tui.ts +0 -629
- package/extensions/question/types.ts +0 -123
- package/extensions/session-title/config.ts +0 -164
- package/extensions/session-title/index.ts +0 -502
- package/extensions/terminal-bell/index.ts +0 -345
|
@@ -28,6 +28,8 @@ export class AppMouseController {
|
|
|
28
28
|
statusDraftQueueTarget;
|
|
29
29
|
statusThinkingExpandTarget;
|
|
30
30
|
statusCompactToolsTarget;
|
|
31
|
+
statusQuickScrollUpTarget;
|
|
32
|
+
statusQuickScrollDownTarget;
|
|
31
33
|
statusTerminalBellSoundTarget;
|
|
32
34
|
statusSessionTarget;
|
|
33
35
|
statusPromptEnhancerTarget;
|
|
@@ -78,6 +80,8 @@ export class AppMouseController {
|
|
|
78
80
|
return;
|
|
79
81
|
if (event.button === 0 && this.withClickFlash(event, () => this.handleStatusModelUsageClick(event)))
|
|
80
82
|
return;
|
|
83
|
+
if (event.button === 0 && this.withClickFlash(event, () => this.handleStatusQuickScrollClick(event)))
|
|
84
|
+
return;
|
|
81
85
|
if (event.button === 0 && this.withClickFlash(event, () => this.handleStatusSessionClick(event)))
|
|
82
86
|
return;
|
|
83
87
|
if (event.button === 0 && this.withClickFlash(event, () => this.handleExtensionInputClick(event)))
|
|
@@ -316,6 +320,8 @@ export class AppMouseController {
|
|
|
316
320
|
this.statusUserJumpTarget,
|
|
317
321
|
this.statusThinkingExpandTarget,
|
|
318
322
|
this.statusCompactToolsTarget,
|
|
323
|
+
this.statusQuickScrollUpTarget,
|
|
324
|
+
this.statusQuickScrollDownTarget,
|
|
319
325
|
this.statusTerminalBellSoundTarget,
|
|
320
326
|
this.statusSessionTarget,
|
|
321
327
|
this.statusPromptEnhancerTarget,
|
|
@@ -600,6 +606,16 @@ export class AppMouseController {
|
|
|
600
606
|
this.host.toggleVoiceLanguage();
|
|
601
607
|
return true;
|
|
602
608
|
}
|
|
609
|
+
handleStatusQuickScrollClick(event) {
|
|
610
|
+
const target = [this.statusQuickScrollUpTarget, this.statusQuickScrollDownTarget].find((candidate) => !!candidate
|
|
611
|
+
&& event.y === candidate.row
|
|
612
|
+
&& event.x >= candidate.startColumn
|
|
613
|
+
&& event.x < candidate.endColumn);
|
|
614
|
+
if (!target)
|
|
615
|
+
return false;
|
|
616
|
+
this.host.scrollConversationQuick(target.direction);
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
603
619
|
handleInputClick(event) {
|
|
604
620
|
const columns = this.host.terminalColumns();
|
|
605
621
|
const terminalRows = this.host.terminalRows();
|
|
@@ -12,6 +12,10 @@ export type ConversationTextScrollTarget = {
|
|
|
12
12
|
entryId?: string;
|
|
13
13
|
needles: readonly string[];
|
|
14
14
|
};
|
|
15
|
+
export type AppScrollState = {
|
|
16
|
+
scrollFromBottom: number;
|
|
17
|
+
detachedScrollStart?: number;
|
|
18
|
+
};
|
|
15
19
|
export type AppScrollControllerHost = {
|
|
16
20
|
conversationViewport(): ConversationViewport;
|
|
17
21
|
editorLayoutRenderer(): EditorLayoutRenderer;
|
|
@@ -24,6 +28,11 @@ export type AppScrollControllerHost = {
|
|
|
24
28
|
render?: boolean;
|
|
25
29
|
onPrependedEntries?: (entries: readonly Entry[]) => void;
|
|
26
30
|
}): Promise<boolean>;
|
|
31
|
+
hasNewerSessionHistory?(): boolean;
|
|
32
|
+
isLoadingNewerSessionHistory?(): boolean;
|
|
33
|
+
loadNewerSessionHistory?(options?: {
|
|
34
|
+
render?: boolean;
|
|
35
|
+
}): Promise<boolean>;
|
|
27
36
|
render(): void;
|
|
28
37
|
};
|
|
29
38
|
export declare class AppScrollController {
|
|
@@ -34,6 +43,15 @@ export declare class AppScrollController {
|
|
|
34
43
|
constructor(host: AppScrollControllerHost);
|
|
35
44
|
reset(): void;
|
|
36
45
|
scrollToBottom(): boolean;
|
|
46
|
+
scrollToTop(): boolean;
|
|
47
|
+
scrollToAbsoluteTop(): Promise<boolean>;
|
|
48
|
+
scrollToAbsoluteBottom(): Promise<boolean>;
|
|
49
|
+
quickScrollDirections(columns: number, bodyHeight: number): {
|
|
50
|
+
up: boolean;
|
|
51
|
+
down: boolean;
|
|
52
|
+
};
|
|
53
|
+
captureState(): AppScrollState;
|
|
54
|
+
restoreState(state: AppScrollState): void;
|
|
37
55
|
conversationView(columns: number, bodyHeight: number): {
|
|
38
56
|
lines: RenderedLine[];
|
|
39
57
|
metrics: AppScrollMetrics;
|
|
@@ -45,7 +63,9 @@ export declare class AppScrollController {
|
|
|
45
63
|
render?: boolean;
|
|
46
64
|
}): boolean;
|
|
47
65
|
private shouldLoadOlderHistory;
|
|
66
|
+
private shouldLoadNewerHistory;
|
|
48
67
|
private loadOlderHistoryAnchored;
|
|
68
|
+
private loadNewerHistoryAnchored;
|
|
49
69
|
adjustForHistoryWindowPrune(edge: "top" | "bottom", lineCount: number): void;
|
|
50
70
|
scrollToConversationEntry(entryId: string): boolean;
|
|
51
71
|
scrollToConversationText(target: ConversationTextScrollTarget): boolean;
|
|
@@ -17,6 +17,59 @@ export class AppScrollController {
|
|
|
17
17
|
this.detachedScrollStart = undefined;
|
|
18
18
|
return changed;
|
|
19
19
|
}
|
|
20
|
+
scrollToTop() {
|
|
21
|
+
const columns = this.host.terminalColumns();
|
|
22
|
+
const terminalRows = this.host.terminalRows();
|
|
23
|
+
const rows = editorLayoutRows(terminalRows, this.host.tabPanelRows(terminalRows));
|
|
24
|
+
const { bodyHeight } = this.host.editorLayoutRenderer().computeLayout(columns, rows);
|
|
25
|
+
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
26
|
+
return this.setScrollStart(0, metrics);
|
|
27
|
+
}
|
|
28
|
+
async scrollToAbsoluteTop() {
|
|
29
|
+
let loadedOlder = false;
|
|
30
|
+
while (this.host.hasOlderSessionHistory?.() === true && this.host.isLoadingOlderSessionHistory?.() !== true) {
|
|
31
|
+
const loaded = await this.host.loadOlderSessionHistory?.({ render: false });
|
|
32
|
+
if (!loaded)
|
|
33
|
+
break;
|
|
34
|
+
loadedOlder = true;
|
|
35
|
+
this.host.render();
|
|
36
|
+
await yieldToEventLoop();
|
|
37
|
+
}
|
|
38
|
+
return this.scrollToTop() || loadedOlder;
|
|
39
|
+
}
|
|
40
|
+
async scrollToAbsoluteBottom() {
|
|
41
|
+
let loadedNewer = false;
|
|
42
|
+
while (this.host.hasNewerSessionHistory?.() === true && this.host.isLoadingNewerSessionHistory?.() !== true) {
|
|
43
|
+
const loaded = await this.host.loadNewerSessionHistory?.({ render: false });
|
|
44
|
+
if (!loaded)
|
|
45
|
+
break;
|
|
46
|
+
loadedNewer = true;
|
|
47
|
+
this.host.render();
|
|
48
|
+
await yieldToEventLoop();
|
|
49
|
+
}
|
|
50
|
+
return this.scrollToBottom() || loadedNewer;
|
|
51
|
+
}
|
|
52
|
+
quickScrollDirections(columns, bodyHeight) {
|
|
53
|
+
if (bodyHeight <= 0)
|
|
54
|
+
return { up: false, down: false };
|
|
55
|
+
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
56
|
+
return {
|
|
57
|
+
up: metrics.start > 0 || this.host.hasOlderSessionHistory?.() === true,
|
|
58
|
+
down: metrics.start < metrics.maxScroll || this.host.hasNewerSessionHistory?.() === true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
captureState() {
|
|
62
|
+
return {
|
|
63
|
+
scrollFromBottom: this.scrollFromBottom,
|
|
64
|
+
...(this.detachedScrollStart === undefined ? {} : { detachedScrollStart: this.detachedScrollStart }),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
restoreState(state) {
|
|
68
|
+
this.scrollFromBottom = Math.max(0, state.scrollFromBottom);
|
|
69
|
+
this.detachedScrollStart = state.detachedScrollStart === undefined
|
|
70
|
+
? undefined
|
|
71
|
+
: Math.max(0, state.detachedScrollStart);
|
|
72
|
+
}
|
|
20
73
|
conversationView(columns, bodyHeight) {
|
|
21
74
|
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
22
75
|
return {
|
|
@@ -55,16 +108,23 @@ export class AppScrollController {
|
|
|
55
108
|
const rows = editorLayoutRows(terminalRows, this.host.tabPanelRows(terminalRows));
|
|
56
109
|
const { bodyHeight } = this.host.editorLayoutRenderer().computeLayout(columns, rows);
|
|
57
110
|
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
58
|
-
const shouldLoadOlderHistory = this.shouldLoadOlderHistory(delta, metrics);
|
|
59
111
|
const { conversationLineCount, maxScroll } = metrics;
|
|
60
112
|
const nextScrollFromBottom = Math.max(0, Math.min(maxScroll, this.scrollFromBottom + -delta));
|
|
113
|
+
const nextStart = Math.max(0, maxScroll - nextScrollFromBottom);
|
|
114
|
+
const shouldLoadOlderHistory = this.shouldLoadOlderHistory(delta, metrics, nextStart);
|
|
115
|
+
const shouldLoadNewerHistory = this.shouldLoadNewerHistory(delta, metrics, nextStart);
|
|
116
|
+
const pinToTopAfterOlderHistoryLoad = shouldLoadOlderHistory && nextStart === 0;
|
|
61
117
|
let changed = false;
|
|
62
118
|
if (nextScrollFromBottom === this.scrollFromBottom) {
|
|
63
119
|
if (nextScrollFromBottom === 0 && this.detachedScrollStart !== undefined && delta > 0) {
|
|
64
120
|
this.detachedScrollStart = undefined;
|
|
65
121
|
changed = true;
|
|
66
122
|
}
|
|
67
|
-
else if (
|
|
123
|
+
else if (pinToTopAfterOlderHistoryLoad && this.detachedScrollStart !== 0) {
|
|
124
|
+
this.detachedScrollStart = 0;
|
|
125
|
+
changed = true;
|
|
126
|
+
}
|
|
127
|
+
else if (!shouldLoadOlderHistory && !shouldLoadNewerHistory) {
|
|
68
128
|
return false;
|
|
69
129
|
}
|
|
70
130
|
}
|
|
@@ -76,15 +136,17 @@ export class AppScrollController {
|
|
|
76
136
|
changed = true;
|
|
77
137
|
}
|
|
78
138
|
if (shouldLoadOlderHistory)
|
|
79
|
-
this.loadOlderHistoryAnchored(metrics, { render: shouldRender });
|
|
139
|
+
this.loadOlderHistoryAnchored(metrics, { render: shouldRender, pinToTop: pinToTopAfterOlderHistoryLoad });
|
|
140
|
+
if (shouldLoadNewerHistory)
|
|
141
|
+
this.loadNewerHistoryAnchored({ render: shouldRender, pinToBottom: nextScrollFromBottom === 0 });
|
|
80
142
|
if (shouldRender)
|
|
81
143
|
this.host.render();
|
|
82
|
-
return changed || shouldLoadOlderHistory;
|
|
144
|
+
return changed || shouldLoadOlderHistory || shouldLoadNewerHistory;
|
|
83
145
|
}
|
|
84
|
-
shouldLoadOlderHistory(delta, metrics) {
|
|
146
|
+
shouldLoadOlderHistory(delta, metrics, nextStart = metrics.start) {
|
|
85
147
|
if (delta >= 0)
|
|
86
148
|
return false;
|
|
87
|
-
if (metrics.start > this.olderHistoryThresholdLines)
|
|
149
|
+
if (metrics.start > this.olderHistoryThresholdLines && nextStart > this.olderHistoryThresholdLines)
|
|
88
150
|
return false;
|
|
89
151
|
if (this.host.hasOlderSessionHistory?.() !== true)
|
|
90
152
|
return false;
|
|
@@ -92,12 +154,29 @@ export class AppScrollController {
|
|
|
92
154
|
return false;
|
|
93
155
|
return true;
|
|
94
156
|
}
|
|
157
|
+
shouldLoadNewerHistory(delta, metrics, nextStart = metrics.start) {
|
|
158
|
+
if (delta <= 0)
|
|
159
|
+
return false;
|
|
160
|
+
if (metrics.maxScroll - metrics.start > this.olderHistoryThresholdLines && metrics.maxScroll - nextStart > this.olderHistoryThresholdLines)
|
|
161
|
+
return false;
|
|
162
|
+
if (this.host.hasNewerSessionHistory?.() !== true)
|
|
163
|
+
return false;
|
|
164
|
+
if (this.host.isLoadingNewerSessionHistory?.() === true)
|
|
165
|
+
return false;
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
95
168
|
loadOlderHistoryAnchored(metrics, options) {
|
|
96
169
|
void this.host.loadOlderSessionHistory?.({
|
|
97
170
|
render: false,
|
|
98
171
|
onPrependedEntries: (entries) => {
|
|
172
|
+
if (this.detachedScrollStart === undefined)
|
|
173
|
+
return;
|
|
174
|
+
if (options.pinToTop) {
|
|
175
|
+
this.detachedScrollStart = 0;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
99
178
|
const prependedLineCount = this.host.conversationViewport().measuredLineCountForEntries(metrics.viewportColumns, entries.map((entry) => entry.id));
|
|
100
|
-
if (prependedLineCount > 0
|
|
179
|
+
if (prependedLineCount > 0)
|
|
101
180
|
this.detachedScrollStart += prependedLineCount;
|
|
102
181
|
},
|
|
103
182
|
}).then((loaded) => {
|
|
@@ -105,6 +184,14 @@ export class AppScrollController {
|
|
|
105
184
|
this.host.render();
|
|
106
185
|
});
|
|
107
186
|
}
|
|
187
|
+
loadNewerHistoryAnchored(options) {
|
|
188
|
+
void this.host.loadNewerSessionHistory?.({ render: false }).then((loaded) => {
|
|
189
|
+
if (loaded && options.pinToBottom)
|
|
190
|
+
this.scrollToBottom();
|
|
191
|
+
if (loaded && options.render)
|
|
192
|
+
this.host.render();
|
|
193
|
+
});
|
|
194
|
+
}
|
|
108
195
|
adjustForHistoryWindowPrune(edge, lineCount) {
|
|
109
196
|
if (lineCount <= 0)
|
|
110
197
|
return;
|
|
@@ -121,7 +208,7 @@ export class AppScrollController {
|
|
|
121
208
|
const conversationViewport = this.host.conversationViewport();
|
|
122
209
|
const { bodyHeight } = this.host.editorLayoutRenderer().computeLayout(columns, rows);
|
|
123
210
|
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
124
|
-
const position = conversationViewport.
|
|
211
|
+
const position = conversationViewport.entryBlockPositionById(metrics.viewportColumns, entryId);
|
|
125
212
|
if (!position)
|
|
126
213
|
return false;
|
|
127
214
|
this.setScrollStart(position.offset, metrics);
|
|
@@ -138,9 +225,8 @@ export class AppScrollController {
|
|
|
138
225
|
const conversationViewport = this.host.conversationViewport();
|
|
139
226
|
const { bodyHeight } = this.host.editorLayoutRenderer().computeLayout(columns, rows);
|
|
140
227
|
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
141
|
-
const positions = conversationViewport.entryBlockPositions(metrics.viewportColumns);
|
|
142
228
|
const targetPosition = target.entryId
|
|
143
|
-
?
|
|
229
|
+
? conversationViewport.entryBlockPositionById(metrics.viewportColumns, target.entryId)
|
|
144
230
|
: undefined;
|
|
145
231
|
const targetMatch = targetPosition ? lineMatchInPosition(targetPosition, needles) : undefined;
|
|
146
232
|
if (targetMatch) {
|
|
@@ -153,6 +239,18 @@ export class AppScrollController {
|
|
|
153
239
|
this.host.render();
|
|
154
240
|
return true;
|
|
155
241
|
}
|
|
242
|
+
for (const entry of conversationViewport.entries()) {
|
|
243
|
+
if (!entryMatchesNeedles(entry, needles))
|
|
244
|
+
continue;
|
|
245
|
+
const position = conversationViewport.entryBlockPositionById(metrics.viewportColumns, entry.id);
|
|
246
|
+
const match = position ? lineMatchInPosition(position, needles) : undefined;
|
|
247
|
+
if (!match)
|
|
248
|
+
continue;
|
|
249
|
+
this.setScrollStart(match.start, metrics);
|
|
250
|
+
this.host.render();
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
const positions = conversationViewport.entryBlockPositions(metrics.viewportColumns);
|
|
156
254
|
const anyMatch = positions
|
|
157
255
|
.map((position) => lineMatchInPosition(position, needles))
|
|
158
256
|
.find((match) => match !== undefined);
|
|
@@ -177,6 +275,9 @@ export class AppScrollController {
|
|
|
177
275
|
return safeColumns;
|
|
178
276
|
}
|
|
179
277
|
}
|
|
278
|
+
async function yieldToEventLoop() {
|
|
279
|
+
await new Promise((resolve) => { setTimeout(resolve, 0); });
|
|
280
|
+
}
|
|
180
281
|
function editorLayoutRows(terminalRows, tabPanelRows) {
|
|
181
282
|
return Math.max(1, terminalRows - tabPanelRows);
|
|
182
283
|
}
|
|
@@ -195,6 +296,22 @@ function normalizeLineSearchNeedles(needles) {
|
|
|
195
296
|
function normalizeLineSearchText(text) {
|
|
196
297
|
return sanitizeText(text).replace(/…/gu, " ").replace(/\s+/gu, " ").trim().toLocaleLowerCase();
|
|
197
298
|
}
|
|
299
|
+
function entryMatchesNeedles(entry, needles) {
|
|
300
|
+
const text = normalizeLineSearchText(entrySearchText(entry));
|
|
301
|
+
return needles.some((needle) => text.includes(needle));
|
|
302
|
+
}
|
|
303
|
+
function entrySearchText(entry) {
|
|
304
|
+
switch (entry.kind) {
|
|
305
|
+
case "shell":
|
|
306
|
+
return [entry.command, entry.output, entry.status, entry.error ?? ""].join("\n");
|
|
307
|
+
case "tool":
|
|
308
|
+
return [entry.toolName, entry.argsText, entry.output, entry.status].join("\n");
|
|
309
|
+
case "custom":
|
|
310
|
+
return [entry.customType, entry.text].join("\n");
|
|
311
|
+
default:
|
|
312
|
+
return "text" in entry ? entry.text : "";
|
|
313
|
+
}
|
|
314
|
+
}
|
|
198
315
|
function lineMatchInPosition(position, needles) {
|
|
199
316
|
const lineIndex = lineIndexForNeedles(position.block.lines, needles);
|
|
200
317
|
return lineIndex === undefined ? undefined : { start: position.offset + lineIndex };
|
|
@@ -426,7 +426,7 @@ async function readTailSessionEntriesWithByteCount(filePath, byteCount, limit, s
|
|
|
426
426
|
const firstNewline = buffer.indexOf(10);
|
|
427
427
|
parseStart = firstNewline >= 0 ? firstNewline + 1 : buffer.length;
|
|
428
428
|
}
|
|
429
|
-
return selectLastSessionEntries(parseSessionEntryBufferLines(buffer.subarray(parseStart), start + parseStart), limit, size);
|
|
429
|
+
return selectLastSessionEntries(parseSessionEntryBufferLines(buffer.subarray(parseStart), start + parseStart), limit, start, size);
|
|
430
430
|
}
|
|
431
431
|
catch {
|
|
432
432
|
return { entries: [], startOffset: 0 };
|
|
@@ -445,12 +445,41 @@ async function readSessionEntriesBeforeOffset(filePath, endOffset, limit) {
|
|
|
445
445
|
const maxBytes = Math.min(endOffset, MAX_TAIL_BYTES);
|
|
446
446
|
while (byteCount <= maxBytes) {
|
|
447
447
|
const result = await readSessionEntriesBeforeOffsetWithByteCount(filePath, endOffset, byteCount, limit);
|
|
448
|
-
if (result.entries.length >= limit || byteCount >=
|
|
448
|
+
if (result.entries.length >= limit || byteCount >= endOffset)
|
|
449
449
|
return result;
|
|
450
|
+
if (byteCount >= maxBytes)
|
|
451
|
+
return await readSessionEntriesBeforeOffsetStreaming(filePath, endOffset, limit);
|
|
450
452
|
byteCount = Math.min(endOffset, Math.max(byteCount + 1, byteCount * 2));
|
|
451
453
|
}
|
|
452
454
|
return { entries: [], startOffset: 0 };
|
|
453
455
|
}
|
|
456
|
+
async function readSessionEntriesBeforeOffsetStreaming(filePath, endOffset, limit) {
|
|
457
|
+
const selected = [];
|
|
458
|
+
let offset = 0;
|
|
459
|
+
const stream = createReadStream(filePath, { encoding: "utf8", start: 0, end: Math.max(0, endOffset - 1) });
|
|
460
|
+
const lines = createInterface({ input: stream, crlfDelay: Infinity });
|
|
461
|
+
try {
|
|
462
|
+
for await (const line of lines) {
|
|
463
|
+
const lineOffset = offset;
|
|
464
|
+
offset += Buffer.byteLength(line, "utf8") + 1;
|
|
465
|
+
if (lineOffset >= endOffset)
|
|
466
|
+
break;
|
|
467
|
+
const entry = parseSessionEntryLine(line);
|
|
468
|
+
if (!entry)
|
|
469
|
+
continue;
|
|
470
|
+
selected.push({ entry, offset: lineOffset });
|
|
471
|
+
if (selected.length > limit)
|
|
472
|
+
selected.shift();
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
finally {
|
|
476
|
+
stream.destroy();
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
entries: selected.map((item) => item.entry),
|
|
480
|
+
startOffset: selected[0]?.offset ?? 0,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
454
483
|
async function readSessionEntriesBeforeOffsetWithByteCount(filePath, endOffset, byteCount, limit) {
|
|
455
484
|
let file;
|
|
456
485
|
try {
|
|
@@ -463,7 +492,7 @@ async function readSessionEntriesBeforeOffsetWithByteCount(filePath, endOffset,
|
|
|
463
492
|
const firstNewline = buffer.indexOf(10);
|
|
464
493
|
parseStart = firstNewline >= 0 ? firstNewline + 1 : buffer.length;
|
|
465
494
|
}
|
|
466
|
-
return selectLastSessionEntries(parseSessionEntryBufferLines(buffer.subarray(parseStart), start + parseStart), limit, start);
|
|
495
|
+
return selectLastSessionEntries(parseSessionEntryBufferLines(buffer.subarray(parseStart), start + parseStart), limit, start, start);
|
|
467
496
|
}
|
|
468
497
|
catch {
|
|
469
498
|
return { entries: [], startOffset: 0 };
|
|
@@ -472,11 +501,12 @@ async function readSessionEntriesBeforeOffsetWithByteCount(filePath, endOffset,
|
|
|
472
501
|
await file?.close();
|
|
473
502
|
}
|
|
474
503
|
}
|
|
475
|
-
function selectLastSessionEntries(parsedEntries, limit, emptyStartOffset) {
|
|
504
|
+
function selectLastSessionEntries(parsedEntries, limit, windowStartOffset, emptyStartOffset) {
|
|
476
505
|
const selected = parsedEntries.slice(-limit);
|
|
506
|
+
const hasOlderEntriesBeforeSelected = windowStartOffset > 0 || parsedEntries.length > selected.length;
|
|
477
507
|
return {
|
|
478
508
|
entries: selected.map((item) => item.entry),
|
|
479
|
-
startOffset: selected[0]?.offset ?? emptyStartOffset,
|
|
509
|
+
startOffset: hasOlderEntriesBeforeSelected ? selected[0]?.offset ?? emptyStartOffset : 0,
|
|
480
510
|
};
|
|
481
511
|
}
|
|
482
512
|
function parseSessionEntryBufferLines(buffer, baseOffset) {
|
|
@@ -2,6 +2,7 @@ import type { AgentSession, SessionEntry } from "@earendil-works/pi-coding-agent
|
|
|
2
2
|
export declare const PIX_SYSTEM_MESSAGE_CUSTOM_TYPE = "pix-system";
|
|
3
3
|
export declare const PIX_SYSTEM_DISPLAY_ENTRY_CUSTOM_TYPE = "pix:system_message";
|
|
4
4
|
export declare const PIX_SESSION_ENTRY_ID_FIELD = "__pixSessionEntryId";
|
|
5
|
+
export declare const PIX_THINKING_LEVEL_FIELD = "__pixThinkingLevel";
|
|
5
6
|
export declare function appendPixSystemDisplayEntry(session: AgentSession, text: string): void;
|
|
6
7
|
export declare function sessionHistoryDisplayMessages(session: AgentSession): readonly unknown[];
|
|
7
8
|
export type SessionHistoryOlderMessagesReader = {
|
|
@@ -2,6 +2,7 @@ import { isRecord } from "../guards.js";
|
|
|
2
2
|
export const PIX_SYSTEM_MESSAGE_CUSTOM_TYPE = "pix-system";
|
|
3
3
|
export const PIX_SYSTEM_DISPLAY_ENTRY_CUSTOM_TYPE = "pix:system_message";
|
|
4
4
|
export const PIX_SESSION_ENTRY_ID_FIELD = "__pixSessionEntryId";
|
|
5
|
+
export const PIX_THINKING_LEVEL_FIELD = "__pixThinkingLevel";
|
|
5
6
|
export function appendPixSystemDisplayEntry(session, text) {
|
|
6
7
|
const trimmed = text.trim();
|
|
7
8
|
if (!trimmed)
|
|
@@ -25,9 +26,13 @@ export function sessionHistoryOlderMessagesReader(session) {
|
|
|
25
26
|
}
|
|
26
27
|
export function sessionHistoryDisplayMessagesFromEntries(branch) {
|
|
27
28
|
const messages = [];
|
|
29
|
+
let currentThinkingLevel;
|
|
28
30
|
for (const entry of branch) {
|
|
29
31
|
if (entry.type === "message") {
|
|
30
|
-
messages.push(
|
|
32
|
+
messages.push(withSessionHistoryMetadata(entry.message, entry.id, currentThinkingLevel));
|
|
33
|
+
}
|
|
34
|
+
else if (entry.type === "thinking_level_change") {
|
|
35
|
+
currentThinkingLevel = typeof entry.thinkingLevel === "string" ? entry.thinkingLevel : currentThinkingLevel;
|
|
31
36
|
}
|
|
32
37
|
else if (entry.type === "custom_message") {
|
|
33
38
|
messages.push({
|
|
@@ -52,8 +57,14 @@ export async function sessionHistoryFullBranchEntries(session) {
|
|
|
52
57
|
const reader = session.sessionManager;
|
|
53
58
|
return await reader.readFullBranchEntries?.() ?? session.sessionManager.getBranch();
|
|
54
59
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
60
|
+
function withSessionHistoryMetadata(message, entryId, thinkingLevel) {
|
|
61
|
+
if (!isRecord(message))
|
|
62
|
+
return message;
|
|
63
|
+
return {
|
|
64
|
+
...message,
|
|
65
|
+
[PIX_SESSION_ENTRY_ID_FIELD]: entryId,
|
|
66
|
+
...(thinkingLevel === undefined ? {} : { [PIX_THINKING_LEVEL_FIELD]: thinkingLevel }),
|
|
67
|
+
};
|
|
57
68
|
}
|
|
58
69
|
function isPixSystemDisplayEntry(entry) {
|
|
59
70
|
return entry.type === "custom"
|
|
@@ -23,12 +23,14 @@ export type AppQueuedMessageControllerHost = {
|
|
|
23
23
|
};
|
|
24
24
|
export declare class AppQueuedMessageController {
|
|
25
25
|
private readonly host;
|
|
26
|
+
readonly autoUserMessages: SubmittedUserMessage[];
|
|
26
27
|
readonly deferredUserMessages: SubmittedUserMessage[];
|
|
27
|
-
private
|
|
28
|
-
private flushingDeferredUserMessages;
|
|
28
|
+
private promptSubmissionInFlightSession;
|
|
29
29
|
private immediateSendInProgress;
|
|
30
30
|
constructor(host: AppQueuedMessageControllerHost);
|
|
31
31
|
reset(): void;
|
|
32
|
+
captureAutoUserMessages(): SubmittedUserMessage[];
|
|
33
|
+
restoreAutoUserMessages(messages: readonly SubmittedUserMessage[]): void;
|
|
32
34
|
captureDeferredUserMessages(): SubmittedUserMessage[];
|
|
33
35
|
restoreDeferredUserMessages(messages: readonly SubmittedUserMessage[]): void;
|
|
34
36
|
createSubmittedUserMessage(promptText: string, displayText: string, images: ImageContent[]): SubmittedUserMessage;
|
|
@@ -36,7 +38,7 @@ export declare class AppQueuedMessageController {
|
|
|
36
38
|
sendUserMessageToSession(message: SubmittedUserMessage, options?: {
|
|
37
39
|
streamingBehavior?: "steer" | "followUp";
|
|
38
40
|
}): Promise<void>;
|
|
39
|
-
|
|
41
|
+
flushAutoUserMessages(): Promise<void>;
|
|
40
42
|
queuedMessageCounts(): {
|
|
41
43
|
steering: number;
|
|
42
44
|
followUp: number;
|
|
@@ -54,10 +56,14 @@ export declare class AppQueuedMessageController {
|
|
|
54
56
|
queuedEntries(): Extract<Entry, {
|
|
55
57
|
kind: "queued";
|
|
56
58
|
}>[];
|
|
59
|
+
autoQueuedEntries(): Extract<Entry, {
|
|
60
|
+
kind: "queued";
|
|
61
|
+
}>[];
|
|
57
62
|
deferredQueuedEntries(): Extract<Entry, {
|
|
58
63
|
kind: "queued";
|
|
59
64
|
}>[];
|
|
60
|
-
private
|
|
65
|
+
private shouldQueueUserMessageAsSteering;
|
|
66
|
+
private queueUserMessageAsSteering;
|
|
61
67
|
deferUserMessage(message: SubmittedUserMessage): void;
|
|
62
68
|
private rewriteSdkQueuedMessages;
|
|
63
69
|
private takeQueuedEntryForInterruptedSend;
|
|
@@ -71,4 +77,5 @@ export declare class AppQueuedMessageController {
|
|
|
71
77
|
private restorableSubmittedMessageText;
|
|
72
78
|
private cloneSubmittedUserMessage;
|
|
73
79
|
private notifyDeferredUserMessagesChanged;
|
|
80
|
+
private notifyAutoUserMessagesChanged;
|
|
74
81
|
}
|