pi-ui-extend 0.1.13 → 0.1.17
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 +7 -0
- package/dist/app/app.js +102 -17
- package/dist/app/commands/command-controller.js +2 -0
- package/dist/app/commands/command-host.d.ts +5 -0
- package/dist/app/commands/command-model-actions.d.ts +2 -0
- package/dist/app/commands/command-model-actions.js +40 -4
- package/dist/app/commands/command-navigation-actions.d.ts +9 -0
- package/dist/app/commands/command-navigation-actions.js +62 -0
- package/dist/app/commands/command-registry.d.ts +2 -0
- package/dist/app/commands/command-registry.js +16 -0
- package/dist/app/constants.d.ts +0 -1
- package/dist/app/constants.js +0 -1
- package/dist/app/extensions/extension-ui-controller.d.ts +16 -5
- package/dist/app/extensions/extension-ui-controller.js +99 -61
- package/dist/app/icons.d.ts +1 -0
- package/dist/app/icons.js +2 -0
- package/dist/app/input/input-action-controller.d.ts +2 -0
- package/dist/app/input/input-action-controller.js +8 -1
- package/dist/app/logger.d.ts +25 -0
- package/dist/app/logger.js +90 -0
- package/dist/app/model/model-usage-status.js +30 -15
- package/dist/app/popup/menu-items-controller.d.ts +4 -0
- package/dist/app/popup/menu-items-controller.js +68 -6
- package/dist/app/popup/popup-action-controller.d.ts +2 -1
- package/dist/app/popup/popup-action-controller.js +7 -4
- package/dist/app/popup/popup-menu-controller.d.ts +36 -23
- package/dist/app/popup/popup-menu-controller.js +97 -326
- package/dist/app/rendering/conversation-entry-renderer.js +3 -3
- package/dist/app/rendering/conversation-viewport.d.ts +10 -2
- package/dist/app/rendering/conversation-viewport.js +157 -16
- package/dist/app/rendering/editor-panels.js +22 -9
- package/dist/app/rendering/popup-menu-renderer.d.ts +62 -0
- package/dist/app/rendering/popup-menu-renderer.js +405 -0
- package/dist/app/rendering/render-controller.js +30 -28
- package/dist/app/rendering/render-text.js +5 -2
- package/dist/app/rendering/status-line-renderer.d.ts +8 -1
- package/dist/app/rendering/status-line-renderer.js +217 -117
- package/dist/app/rendering/toast-controller.d.ts +12 -3
- package/dist/app/rendering/toast-controller.js +70 -12
- package/dist/app/runtime.d.ts +2 -1
- package/dist/app/runtime.js +20 -10
- package/dist/app/screen/mouse-controller.d.ts +2 -2
- package/dist/app/screen/mouse-controller.js +27 -48
- package/dist/app/screen/screen-styler.d.ts +1 -1
- package/dist/app/screen/screen-styler.js +9 -7
- package/dist/app/screen/scroll-controller.d.ts +12 -9
- package/dist/app/screen/scroll-controller.js +56 -45
- package/dist/app/screen/status-controller.js +2 -1
- package/dist/app/session/lazy-session-manager.d.ts +11 -0
- package/dist/app/session/lazy-session-manager.js +539 -0
- package/dist/app/session/pix-system-message.d.ts +16 -0
- package/dist/app/session/pix-system-message.js +64 -0
- package/dist/app/session/request-history.d.ts +4 -0
- package/dist/app/session/request-history.js +11 -0
- package/dist/app/session/session-event-controller.d.ts +11 -0
- package/dist/app/session/session-event-controller.js +58 -2
- package/dist/app/session/session-history.d.ts +18 -0
- package/dist/app/session/session-history.js +72 -3
- package/dist/app/session/session-lifecycle-controller.d.ts +6 -2
- package/dist/app/session/session-lifecycle-controller.js +7 -2
- package/dist/app/session/session-search.js +10 -0
- package/dist/app/session/tabs-controller.d.ts +17 -5
- package/dist/app/session/tabs-controller.js +308 -29
- package/dist/app/todo/todo-model.d.ts +4 -2
- package/dist/app/todo/todo-model.js +23 -13
- package/dist/app/types.d.ts +17 -6
- package/dist/app/workspace/workspace-actions-controller.d.ts +2 -0
- package/dist/app/workspace/workspace-actions-controller.js +12 -0
- package/dist/config.d.ts +6 -1
- package/dist/config.js +82 -25
- package/dist/default-pix-config.js +4 -0
- package/dist/fuzzy.d.ts +2 -0
- package/dist/fuzzy.js +27 -7
- package/dist/input-editor.d.ts +9 -0
- package/dist/input-editor.js +52 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +1 -0
- package/dist/schemas/pi-tools-suite-schema.js +1 -0
- package/dist/schemas/pix-schema.d.ts +3 -1
- package/dist/schemas/pix-schema.js +6 -4
- package/dist/terminal-width.d.ts +2 -0
- package/dist/terminal-width.js +64 -3
- package/dist/theme.js +6 -6
- package/dist/ui.d.ts +8 -0
- package/external/pi-tools-suite/README.md +3 -2
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +52 -8
- package/external/pi-tools-suite/src/antigravity-auth/commands.ts +3 -41
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +0 -2
- package/external/pi-tools-suite/src/antigravity-auth/index.ts +11 -18
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +129 -61
- package/external/pi-tools-suite/src/antigravity-auth/status.ts +82 -3
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +20 -7
- package/external/pi-tools-suite/src/antigravity-auth/types.ts +21 -0
- package/external/pi-tools-suite/src/config.ts +8 -0
- package/external/pi-tools-suite/src/dcp/index.ts +16 -1
- package/external/pi-tools-suite/src/dcp/state.ts +35 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +3 -0
- package/external/pi-tools-suite/src/todo/index.ts +123 -14
- package/external/pi-tools-suite/src/todo/state/persistence.ts +0 -1
- package/external/pi-tools-suite/src/todo/state/state-reducer.ts +26 -43
- package/external/pi-tools-suite/src/todo/todo.ts +12 -23
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +34 -16
- package/external/pi-tools-suite/src/todo/tool/types.ts +7 -28
- package/external/pi-tools-suite/src/todo/view/format.ts +2 -3
- package/external/pi-tools-suite/src/tool-descriptions.ts +6 -4
- package/external/pi-tools-suite/src/usage/index.ts +5 -2
- package/external/pi-tools-suite/src/usage/lib/google.ts +53 -40
- package/external/pi-tools-suite/src/usage/lib/types.ts +12 -2
- package/package.json +1 -1
- package/schemas/pi-tools-suite.json +4 -0
- package/schemas/pix.json +11 -2
package/dist/app/runtime.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentS
|
|
|
7
7
|
import { loadPixConfig, resolveDefaultModelRef } from "../config.js";
|
|
8
8
|
import { PI_FAVORITE_MODEL_REFS } from "./constants.js";
|
|
9
9
|
import { isThinkingLevel, parseModelRef, parseScopedModelRef } from "./model/model-ref.js";
|
|
10
|
+
import { openLazySessionManager } from "./session/lazy-session-manager.js";
|
|
10
11
|
const BUNDLED_QUESTION_EXTENSION_NAME = "question";
|
|
11
12
|
const PI_TOOLS_SUITE_EXTENSION_NAME = "pi-tools-suite";
|
|
12
13
|
const BUNDLED_EXTENSIONS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "../..", "extensions");
|
|
@@ -140,6 +141,11 @@ export function resolvePixRuntimeModelRef(options, sessionManager, config = load
|
|
|
140
141
|
return resolveSessionModelRefFromTail(sessionManager.getBranch());
|
|
141
142
|
return resolveDefaultModelRef(config);
|
|
142
143
|
}
|
|
144
|
+
export function resolvePixRuntimeInitialThinkingLevel(options, sessionManager, config) {
|
|
145
|
+
const effectiveModelRef = resolvePixRuntimeModelRef(options, sessionManager, config);
|
|
146
|
+
const parsedModel = effectiveModelRef ? parseModelRef(effectiveModelRef) : undefined;
|
|
147
|
+
return parsedModel?.thinkingLevel;
|
|
148
|
+
}
|
|
143
149
|
export function resolveSessionModelRefFromTail(entries) {
|
|
144
150
|
let modelRef;
|
|
145
151
|
let thinkingLevel;
|
|
@@ -166,8 +172,10 @@ export function resolveSessionModelRefFromTail(entries) {
|
|
|
166
172
|
export async function createPixRuntime(options, runtimeOptions = {}) {
|
|
167
173
|
const agentDir = getAgentDir();
|
|
168
174
|
const createRuntime = async ({ cwd, sessionManager, sessionStartEvent }) => {
|
|
169
|
-
const
|
|
175
|
+
const config = loadPixConfig(cwd);
|
|
176
|
+
const effectiveModelRef = resolvePixRuntimeModelRef(options, sessionManager, config);
|
|
170
177
|
const parsedModel = effectiveModelRef ? parseModelRef(effectiveModelRef) : undefined;
|
|
178
|
+
const initialThinkingLevel = resolvePixRuntimeInitialThinkingLevel(options, sessionManager, config);
|
|
171
179
|
await ensureBundledSkillsInstalled();
|
|
172
180
|
await ensurePiToolsSuiteExtensionInstalled({ agentDir });
|
|
173
181
|
const bundledExtensionPaths = getBundledExtensionPaths();
|
|
@@ -175,6 +183,7 @@ export async function createPixRuntime(options, runtimeOptions = {}) {
|
|
|
175
183
|
cwd,
|
|
176
184
|
agentDir,
|
|
177
185
|
resourceLoaderOptions: {
|
|
186
|
+
...(config.ignoreContextFiles ? { noContextFiles: true } : {}),
|
|
178
187
|
...(runtimeOptions.eventBus === undefined ? {} : { eventBus: runtimeOptions.eventBus }),
|
|
179
188
|
...(bundledExtensionPaths.length === 0 ? {} : {
|
|
180
189
|
additionalExtensionPaths: bundledExtensionPaths,
|
|
@@ -203,15 +212,16 @@ export async function createPixRuntime(options, runtimeOptions = {}) {
|
|
|
203
212
|
},
|
|
204
213
|
];
|
|
205
214
|
});
|
|
215
|
+
const created = await createAgentSessionFromServices({
|
|
216
|
+
services,
|
|
217
|
+
sessionManager,
|
|
218
|
+
...(sessionStartEvent === undefined ? {} : { sessionStartEvent }),
|
|
219
|
+
...(model === undefined ? {} : { model }),
|
|
220
|
+
...(initialThinkingLevel === undefined ? {} : { thinkingLevel: initialThinkingLevel }),
|
|
221
|
+
...(scopedModels.length === 0 ? {} : { scopedModels }),
|
|
222
|
+
});
|
|
206
223
|
return {
|
|
207
|
-
...
|
|
208
|
-
services,
|
|
209
|
-
sessionManager,
|
|
210
|
-
...(sessionStartEvent === undefined ? {} : { sessionStartEvent }),
|
|
211
|
-
...(model === undefined ? {} : { model }),
|
|
212
|
-
...(parsedModel?.thinkingLevel === undefined ? {} : { thinkingLevel: parsedModel.thinkingLevel }),
|
|
213
|
-
...(scopedModels.length === 0 ? {} : { scopedModels }),
|
|
214
|
-
})),
|
|
224
|
+
...created,
|
|
215
225
|
services,
|
|
216
226
|
diagnostics: services.diagnostics,
|
|
217
227
|
};
|
|
@@ -222,7 +232,7 @@ export async function createPixRuntime(options, runtimeOptions = {}) {
|
|
|
222
232
|
sessionManager: options.noSession
|
|
223
233
|
? SessionManager.inMemory(options.cwd)
|
|
224
234
|
: options.sessionPath
|
|
225
|
-
?
|
|
235
|
+
? openLazySessionManager(options.sessionPath, { cwdOverride: options.cwd })
|
|
226
236
|
: SessionManager.create(options.cwd),
|
|
227
237
|
});
|
|
228
238
|
}
|
|
@@ -56,6 +56,7 @@ export type AppMouseControllerHost = {
|
|
|
56
56
|
}): void;
|
|
57
57
|
dismissToast(toastId: number): void;
|
|
58
58
|
refreshModelUsageStatus(): void | Promise<void>;
|
|
59
|
+
refreshUserMessageJumpMenuItems?(): Promise<void>;
|
|
59
60
|
queueInputFromStatus?(): void | Promise<void>;
|
|
60
61
|
toggleAllThinkingExpanded?(): void;
|
|
61
62
|
toggleSuperCompactTools?(): void;
|
|
@@ -111,7 +112,6 @@ export declare class AppMouseController {
|
|
|
111
112
|
statusVoiceLanguageTarget: StatusVoiceLanguageTarget | undefined;
|
|
112
113
|
readonly tabLineTargets: TabLineMouseTarget[];
|
|
113
114
|
mouseSelection: MouseSelection | undefined;
|
|
114
|
-
private scrollBarDragActive;
|
|
115
115
|
private inputScrollBarDragActive;
|
|
116
116
|
private autoScrollTimer;
|
|
117
117
|
private autoScrollDirection;
|
|
@@ -142,7 +142,6 @@ export declare class AppMouseController {
|
|
|
142
142
|
private statusTargetAt;
|
|
143
143
|
private handleImageClick;
|
|
144
144
|
private handleFileLinkClick;
|
|
145
|
-
private handleConversationScrollBar;
|
|
146
145
|
private handleInputScrollBar;
|
|
147
146
|
private finishInputScrollBarDrag;
|
|
148
147
|
private handleInputWheel;
|
|
@@ -155,6 +154,7 @@ export declare class AppMouseController {
|
|
|
155
154
|
private handleStatusContextClick;
|
|
156
155
|
private handleStatusModelUsageClick;
|
|
157
156
|
private handleStatusUserJumpClick;
|
|
157
|
+
private openStatusUserJumpMenu;
|
|
158
158
|
private handleStatusDraftQueueClick;
|
|
159
159
|
private handleStatusThinkingExpandClick;
|
|
160
160
|
private handleStatusCompactToolsClick;
|
|
@@ -3,7 +3,7 @@ import { stringifyUnknown } from "../rendering/message-content.js";
|
|
|
3
3
|
import { horizontalPaddingLayout } from "../rendering/render-text.js";
|
|
4
4
|
import { orderedSelection, samePoint } from "./screen-selection.js";
|
|
5
5
|
import { openImageContent as openSystemImageContent } from "./image-opener.js";
|
|
6
|
-
import { stringDisplayWidth } from "../../terminal-width.js";
|
|
6
|
+
import { sliceByDisplayColumns, stringDisplayWidth } from "../../terminal-width.js";
|
|
7
7
|
import { formatDcpStatsToast } from "../rendering/dcp-stats.js";
|
|
8
8
|
import { detectFileLinks } from "./file-links.js";
|
|
9
9
|
import { openFileLink as openDetectedFileLink } from "./file-link-opener.js";
|
|
@@ -34,7 +34,6 @@ export class AppMouseController {
|
|
|
34
34
|
statusVoiceLanguageTarget;
|
|
35
35
|
tabLineTargets = [];
|
|
36
36
|
mouseSelection;
|
|
37
|
-
scrollBarDragActive = false;
|
|
38
37
|
inputScrollBarDragActive = false;
|
|
39
38
|
autoScrollTimer;
|
|
40
39
|
autoScrollDirection;
|
|
@@ -57,8 +56,6 @@ export class AppMouseController {
|
|
|
57
56
|
handleMouse(event) {
|
|
58
57
|
if (this.handleInputScrollBar(event))
|
|
59
58
|
return;
|
|
60
|
-
if (this.handleConversationScrollBar(event))
|
|
61
|
-
return;
|
|
62
59
|
this.showClickFlashOnPress(event);
|
|
63
60
|
if (this.handleMouseSelection(event))
|
|
64
61
|
return;
|
|
@@ -339,39 +336,6 @@ export class AppMouseController {
|
|
|
339
336
|
this.host.showToast("Could not open file link. Install the Zed CLI or set ZED_CLI.", "warning");
|
|
340
337
|
return true;
|
|
341
338
|
}
|
|
342
|
-
handleConversationScrollBar(event) {
|
|
343
|
-
if (!this.scrollBarDragActive && this.tabLineTargetAt(event))
|
|
344
|
-
return false;
|
|
345
|
-
const columns = this.host.terminalColumns();
|
|
346
|
-
const terminalRows = this.host.terminalRows();
|
|
347
|
-
const tabPanelRows = this.host.tabPanelRows(terminalRows);
|
|
348
|
-
const rows = editorLayoutRows(terminalRows, tabPanelRows);
|
|
349
|
-
const topOffset = editorLayoutTopOffset(tabPanelRows);
|
|
350
|
-
if (columns <= 0 || rows <= 0)
|
|
351
|
-
return false;
|
|
352
|
-
const { bodyHeight } = this.host.editorLayoutRenderer().computeLayout(columns, rows);
|
|
353
|
-
const localY = event.y - topOffset;
|
|
354
|
-
const insideBody = localY >= 1 && localY <= bodyHeight;
|
|
355
|
-
const onScrollBar = insideBody && event.x === columns && !!this.scrollController.scrollBarMetrics(columns, bodyHeight);
|
|
356
|
-
const baseButton = event.button & 3;
|
|
357
|
-
const draggingLeftButton = (event.button & 32) !== 0 && baseButton === 0;
|
|
358
|
-
if (event.released) {
|
|
359
|
-
if (!this.scrollBarDragActive)
|
|
360
|
-
return false;
|
|
361
|
-
this.scrollBarDragActive = false;
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
if (event.button === 0 && onScrollBar) {
|
|
365
|
-
this.scrollBarDragActive = true;
|
|
366
|
-
this.scrollController.scrollToScrollbarPosition(localY - 1);
|
|
367
|
-
return true;
|
|
368
|
-
}
|
|
369
|
-
if (!draggingLeftButton || !this.scrollBarDragActive)
|
|
370
|
-
return false;
|
|
371
|
-
const bodyRow = Math.max(0, Math.min(Math.max(0, bodyHeight - 1), localY - 1));
|
|
372
|
-
this.scrollController.scrollToScrollbarPosition(bodyRow);
|
|
373
|
-
return true;
|
|
374
|
-
}
|
|
375
339
|
handleInputScrollBar(event) {
|
|
376
340
|
if (!this.inputScrollBarDragActive && this.tabLineTargetAt(event))
|
|
377
341
|
return false;
|
|
@@ -509,10 +473,24 @@ export class AppMouseController {
|
|
|
509
473
|
return false;
|
|
510
474
|
if (event.y !== target.row || event.x < target.startColumn || event.x >= target.endColumn)
|
|
511
475
|
return false;
|
|
512
|
-
this.
|
|
513
|
-
this.host.render();
|
|
476
|
+
void this.openStatusUserJumpMenu();
|
|
514
477
|
return true;
|
|
515
478
|
}
|
|
479
|
+
async openStatusUserJumpMenu() {
|
|
480
|
+
try {
|
|
481
|
+
const refreshPromise = this.host.refreshUserMessageJumpMenuItems?.();
|
|
482
|
+
this.popupMenus.openDirectPopupMenu("user-message-jump", { preserveStatus: true });
|
|
483
|
+
this.host.render();
|
|
484
|
+
if (this.host.refreshUserMessageJumpMenuItems) {
|
|
485
|
+
await refreshPromise;
|
|
486
|
+
this.host.render();
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
this.host.showToast(`Could not load jump messages: ${error instanceof Error ? error.message : stringifyUnknown(error)}`, "error");
|
|
491
|
+
this.host.render();
|
|
492
|
+
}
|
|
493
|
+
}
|
|
516
494
|
handleStatusDraftQueueClick(event) {
|
|
517
495
|
const target = this.statusDraftQueueTarget;
|
|
518
496
|
if (!target)
|
|
@@ -829,9 +807,7 @@ export class AppMouseController {
|
|
|
829
807
|
const line = range.start.line + index;
|
|
830
808
|
const startColumn = line === range.start.line ? range.start.x : 1;
|
|
831
809
|
const endColumn = line === range.end.line ? range.end.x : text.length + 1;
|
|
832
|
-
|
|
833
|
-
const endIndex = Math.max(startIndex, Math.min(text.length, endColumn - 1));
|
|
834
|
-
lines.push(text.slice(startIndex, endIndex).trimEnd());
|
|
810
|
+
lines.push(sliceByDisplayColumns(text, startColumn, endColumn).trimEnd());
|
|
835
811
|
}
|
|
836
812
|
return lines.join("\n").replace(/\s+$/u, "");
|
|
837
813
|
}
|
|
@@ -839,10 +815,10 @@ export class AppMouseController {
|
|
|
839
815
|
const area = this.conversationArea();
|
|
840
816
|
if (!area || area.bodyHeight <= 0)
|
|
841
817
|
return undefined;
|
|
842
|
-
if (!clampToViewport && (event.y < area.topRow || event.y > area.bottomRow
|
|
818
|
+
if (!clampToViewport && (event.y < area.topRow || event.y > area.bottomRow))
|
|
843
819
|
return undefined;
|
|
844
820
|
const screenY = Math.max(area.topRow, Math.min(area.bottomRow, event.y));
|
|
845
|
-
const screenX =
|
|
821
|
+
const screenX = viewportSelectionColumn(event.x, area.viewportColumns);
|
|
846
822
|
return {
|
|
847
823
|
conversation: {
|
|
848
824
|
line: area.metrics.start + (screenY - area.topRow),
|
|
@@ -945,7 +921,7 @@ export class AppMouseController {
|
|
|
945
921
|
if (!area)
|
|
946
922
|
return;
|
|
947
923
|
const screenY = this.autoScrollDirection < 0 ? area.topRow : area.bottomRow;
|
|
948
|
-
const screenX =
|
|
924
|
+
const screenX = viewportSelectionColumn(this.autoScrollCursorX, area.viewportColumns);
|
|
949
925
|
selection.current = { x: screenX, y: screenY };
|
|
950
926
|
selection.conversationCurrent = {
|
|
951
927
|
line: area.metrics.start + (screenY - area.topRow),
|
|
@@ -971,13 +947,16 @@ export function screenSelectionLineText(row, text, startColumn, endColumn, input
|
|
|
971
947
|
copyStartColumn = Math.max(copyStartColumn, inputFrame.contentStartColumn);
|
|
972
948
|
copyEndColumn = Math.min(copyEndColumn, inputFrame.contentEndColumn);
|
|
973
949
|
}
|
|
974
|
-
|
|
975
|
-
const endIndex = Math.max(startIndex, Math.min(text.length, copyEndColumn - 1));
|
|
976
|
-
return text.slice(startIndex, endIndex);
|
|
950
|
+
return sliceByDisplayColumns(text, copyStartColumn, copyEndColumn);
|
|
977
951
|
}
|
|
978
952
|
function sameConversationPoint(left, right) {
|
|
979
953
|
return !!left && left.line === right.line && left.x === right.x;
|
|
980
954
|
}
|
|
955
|
+
function viewportSelectionColumn(mouseX, viewportColumns) {
|
|
956
|
+
if (mouseX >= viewportColumns)
|
|
957
|
+
return viewportColumns + 1;
|
|
958
|
+
return Math.max(1, Math.min(viewportColumns + 1, mouseX));
|
|
959
|
+
}
|
|
981
960
|
function toastTargetContainsEvent(target, event) {
|
|
982
961
|
if (target.startColumn === undefined || target.endColumn === undefined)
|
|
983
962
|
return true;
|
|
@@ -29,7 +29,7 @@ export declare class ScreenStyler {
|
|
|
29
29
|
end: number;
|
|
30
30
|
}[] | undefined, width: number, tagColor: string, suggestionColor: string, frameColor?: string): string;
|
|
31
31
|
private styleAnsiLine;
|
|
32
|
-
selectionRangeForRow(row: number, width: number): {
|
|
32
|
+
selectionRangeForRow(row: number, width: number, text?: string): {
|
|
33
33
|
startIndex: number;
|
|
34
34
|
endIndex: number;
|
|
35
35
|
} | undefined;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ANSI_RESET, colorize } from "../../theme.js";
|
|
2
2
|
import { renderMarkdownLine } from "../../markdown-format.js";
|
|
3
3
|
import { syntaxHighlightSegmentsForLine } from "../../syntax-highlight.js";
|
|
4
|
+
import { displayIndexForColumn } from "../../terminal-width.js";
|
|
4
5
|
import { padOrTrimPlain } from "../rendering/render-text.js";
|
|
5
6
|
import { orderedSelection } from "./screen-selection.js";
|
|
6
7
|
export class ScreenStyler {
|
|
@@ -19,7 +20,7 @@ export class ScreenStyler {
|
|
|
19
20
|
? renderMarkdownDisplayLine(line.text, width, line.syntaxHighlight.start)
|
|
20
21
|
: undefined;
|
|
21
22
|
const text = markdownLine?.text ?? line?.text ?? "";
|
|
22
|
-
if (line?.syntaxHighlight && !this.selectionRangeForRow(row, width)) {
|
|
23
|
+
if (line?.syntaxHighlight && !this.selectionRangeForRow(row, width, text)) {
|
|
23
24
|
const syntaxHighlight = markdownLine ? { ...line.syntaxHighlight, start: Math.min(line.syntaxHighlight.start, markdownLine.text.length) } : line.syntaxHighlight;
|
|
24
25
|
const segments = [
|
|
25
26
|
...syntaxHighlightSegmentsForLine(text, syntaxHighlight, colors),
|
|
@@ -35,7 +36,7 @@ export class ScreenStyler {
|
|
|
35
36
|
return this.styleLine(row, text, width, options);
|
|
36
37
|
}
|
|
37
38
|
styleLineSegments(row, text, width, baseOptions, segments) {
|
|
38
|
-
if (this.selectionRangeForRow(row, width))
|
|
39
|
+
if (this.selectionRangeForRow(row, width, text))
|
|
39
40
|
return this.styleLine(row, text, width, baseOptions);
|
|
40
41
|
const plain = padOrTrimPlain(text, width);
|
|
41
42
|
const chunks = [];
|
|
@@ -56,7 +57,7 @@ export class ScreenStyler {
|
|
|
56
57
|
}
|
|
57
58
|
styleLine(row, text, width, options) {
|
|
58
59
|
const plain = padOrTrimPlain(text, width);
|
|
59
|
-
const range = this.selectionRangeForRow(row, width);
|
|
60
|
+
const range = this.selectionRangeForRow(row, width, plain);
|
|
60
61
|
if (!range)
|
|
61
62
|
return colorize(plain, options);
|
|
62
63
|
const before = plain.slice(0, range.startIndex);
|
|
@@ -75,7 +76,7 @@ export class ScreenStyler {
|
|
|
75
76
|
styleInputLine(row, text, tagSpans, suggestionSpans, width, tagColor, suggestionColor, frameColor) {
|
|
76
77
|
const colors = this.host.theme.colors;
|
|
77
78
|
const baseOptions = { foreground: colors.inputForeground };
|
|
78
|
-
if (this.selectionRangeForRow(row, width))
|
|
79
|
+
if (this.selectionRangeForRow(row, width, text))
|
|
79
80
|
return this.styleLine(row, text, width, baseOptions);
|
|
80
81
|
const plain = padOrTrimPlain(text, width);
|
|
81
82
|
const frameSpans = inputFrameSpans(plain, width, frameColor);
|
|
@@ -109,7 +110,7 @@ export class ScreenStyler {
|
|
|
109
110
|
return text;
|
|
110
111
|
return `${prefix}${text.replaceAll(ANSI_RESET, `${ANSI_RESET}${prefix}`)}${ANSI_RESET}`;
|
|
111
112
|
}
|
|
112
|
-
selectionRangeForRow(row, width) {
|
|
113
|
+
selectionRangeForRow(row, width, text) {
|
|
113
114
|
if (!this.host.mouseSelection)
|
|
114
115
|
return undefined;
|
|
115
116
|
const anchor = this.host.mouseSelection.screenAnchor ?? this.host.mouseSelection.anchor;
|
|
@@ -119,8 +120,9 @@ export class ScreenStyler {
|
|
|
119
120
|
return undefined;
|
|
120
121
|
const startColumn = row === start.y ? start.x : 1;
|
|
121
122
|
const endColumn = row === end.y ? end.x : width + 1;
|
|
122
|
-
const
|
|
123
|
-
const
|
|
123
|
+
const plain = text ?? " ".repeat(Math.max(0, width));
|
|
124
|
+
const startIndex = Math.max(0, Math.min(plain.length, displayIndexForColumn(plain, startColumn)));
|
|
125
|
+
const endIndex = Math.max(startIndex, Math.min(plain.length, displayIndexForColumn(plain, endColumn)));
|
|
124
126
|
return endIndex > startIndex ? { startIndex, endIndex } : undefined;
|
|
125
127
|
}
|
|
126
128
|
baseLineForeground(variant) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConversationViewport } from "../rendering/conversation-viewport.js";
|
|
2
2
|
import type { EditorLayoutRenderer } from "../rendering/editor-layout-renderer.js";
|
|
3
|
-
import type { RenderedLine } from "../types.js";
|
|
3
|
+
import type { Entry, RenderedLine } from "../types.js";
|
|
4
4
|
export type AppScrollMetrics = {
|
|
5
5
|
bodyHeight: number;
|
|
6
6
|
viewportColumns: number;
|
|
@@ -8,10 +8,6 @@ export type AppScrollMetrics = {
|
|
|
8
8
|
maxScroll: number;
|
|
9
9
|
start: number;
|
|
10
10
|
};
|
|
11
|
-
export type AppScrollBarMetrics = {
|
|
12
|
-
thumbStartRow: number;
|
|
13
|
-
thumbEndRow: number;
|
|
14
|
-
};
|
|
15
11
|
export type ConversationTextScrollTarget = {
|
|
16
12
|
entryId?: string;
|
|
17
13
|
needles: readonly string[];
|
|
@@ -22,30 +18,37 @@ export type AppScrollControllerHost = {
|
|
|
22
18
|
terminalColumns(): number;
|
|
23
19
|
terminalRows(): number;
|
|
24
20
|
tabPanelRows(terminalRows: number): number;
|
|
21
|
+
hasOlderSessionHistory?(): boolean;
|
|
22
|
+
isLoadingOlderSessionHistory?(): boolean;
|
|
23
|
+
loadOlderSessionHistory?(options?: {
|
|
24
|
+
render?: boolean;
|
|
25
|
+
onPrependedEntries?: (entries: readonly Entry[]) => void;
|
|
26
|
+
}): Promise<boolean>;
|
|
25
27
|
render(): void;
|
|
26
28
|
};
|
|
27
29
|
export declare class AppScrollController {
|
|
28
30
|
private readonly host;
|
|
29
31
|
private scrollFromBottom;
|
|
30
32
|
private detachedScrollStart;
|
|
33
|
+
private readonly olderHistoryThresholdLines;
|
|
31
34
|
constructor(host: AppScrollControllerHost);
|
|
32
35
|
reset(): void;
|
|
36
|
+
scrollToBottom(): boolean;
|
|
33
37
|
conversationView(columns: number, bodyHeight: number): {
|
|
34
38
|
lines: RenderedLine[];
|
|
35
39
|
metrics: AppScrollMetrics;
|
|
36
40
|
};
|
|
37
41
|
visibleConversationLines(columns: number, bodyHeight: number): RenderedLine[];
|
|
38
42
|
scrollMetrics(columns: number, bodyHeight: number): AppScrollMetrics;
|
|
39
|
-
scrollBarForMetrics(metrics: AppScrollMetrics): AppScrollBarMetrics | undefined;
|
|
40
|
-
scrollBarMetrics(columns: number, bodyHeight: number): AppScrollBarMetrics | undefined;
|
|
41
43
|
scrollByPage(direction: -1 | 1): void;
|
|
42
44
|
scrollByLines(delta: number, options?: {
|
|
43
45
|
render?: boolean;
|
|
44
46
|
}): boolean;
|
|
45
|
-
|
|
47
|
+
private shouldLoadOlderHistory;
|
|
48
|
+
private loadOlderHistoryAnchored;
|
|
49
|
+
adjustForHistoryWindowPrune(edge: "top" | "bottom", lineCount: number): void;
|
|
46
50
|
scrollToConversationEntry(entryId: string): boolean;
|
|
47
51
|
scrollToConversationText(target: ConversationTextScrollTarget): boolean;
|
|
48
|
-
private scrollToStart;
|
|
49
52
|
private setScrollStart;
|
|
50
53
|
private viewportColumns;
|
|
51
54
|
}
|
|
@@ -3,6 +3,7 @@ export class AppScrollController {
|
|
|
3
3
|
host;
|
|
4
4
|
scrollFromBottom = 0;
|
|
5
5
|
detachedScrollStart;
|
|
6
|
+
olderHistoryThresholdLines = 8;
|
|
6
7
|
constructor(host) {
|
|
7
8
|
this.host = host;
|
|
8
9
|
}
|
|
@@ -10,6 +11,12 @@ export class AppScrollController {
|
|
|
10
11
|
this.scrollFromBottom = 0;
|
|
11
12
|
this.detachedScrollStart = undefined;
|
|
12
13
|
}
|
|
14
|
+
scrollToBottom() {
|
|
15
|
+
const changed = this.scrollFromBottom !== 0 || this.detachedScrollStart !== undefined;
|
|
16
|
+
this.scrollFromBottom = 0;
|
|
17
|
+
this.detachedScrollStart = undefined;
|
|
18
|
+
return changed;
|
|
19
|
+
}
|
|
13
20
|
conversationView(columns, bodyHeight) {
|
|
14
21
|
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
15
22
|
return {
|
|
@@ -37,20 +44,6 @@ export class AppScrollController {
|
|
|
37
44
|
}
|
|
38
45
|
return { bodyHeight, viewportColumns, conversationLineCount, maxScroll, start };
|
|
39
46
|
}
|
|
40
|
-
scrollBarForMetrics(metrics) {
|
|
41
|
-
if (metrics.bodyHeight <= 0 || metrics.maxScroll <= 0 || metrics.conversationLineCount <= metrics.bodyHeight)
|
|
42
|
-
return undefined;
|
|
43
|
-
const thumbSize = Math.max(1, Math.min(metrics.bodyHeight, Math.round((metrics.bodyHeight * metrics.bodyHeight) / metrics.conversationLineCount)));
|
|
44
|
-
const travel = Math.max(0, metrics.bodyHeight - thumbSize);
|
|
45
|
-
const thumbOffset = travel === 0 ? 0 : Math.round((metrics.start / metrics.maxScroll) * travel);
|
|
46
|
-
return {
|
|
47
|
-
thumbStartRow: thumbOffset + 1,
|
|
48
|
-
thumbEndRow: thumbOffset + thumbSize,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
scrollBarMetrics(columns, bodyHeight) {
|
|
52
|
-
return this.scrollBarForMetrics(this.scrollMetrics(columns, bodyHeight));
|
|
53
|
-
}
|
|
54
47
|
scrollByPage(direction) {
|
|
55
48
|
const rows = this.host.terminalRows();
|
|
56
49
|
this.scrollByLines(direction * Math.max(1, editorLayoutRows(rows, this.host.tabPanelRows(rows)) - 4));
|
|
@@ -62,37 +55,64 @@ export class AppScrollController {
|
|
|
62
55
|
const rows = editorLayoutRows(terminalRows, this.host.tabPanelRows(terminalRows));
|
|
63
56
|
const { bodyHeight } = this.host.editorLayoutRenderer().computeLayout(columns, rows);
|
|
64
57
|
const metrics = this.scrollMetrics(columns, bodyHeight);
|
|
58
|
+
const shouldLoadOlderHistory = this.shouldLoadOlderHistory(delta, metrics);
|
|
65
59
|
const { conversationLineCount, maxScroll } = metrics;
|
|
66
60
|
const nextScrollFromBottom = Math.max(0, Math.min(maxScroll, this.scrollFromBottom + -delta));
|
|
61
|
+
let changed = false;
|
|
67
62
|
if (nextScrollFromBottom === this.scrollFromBottom) {
|
|
68
63
|
if (nextScrollFromBottom === 0 && this.detachedScrollStart !== undefined && delta > 0) {
|
|
69
64
|
this.detachedScrollStart = undefined;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
changed = true;
|
|
66
|
+
}
|
|
67
|
+
else if (!shouldLoadOlderHistory) {
|
|
68
|
+
return false;
|
|
73
69
|
}
|
|
74
|
-
return false;
|
|
75
70
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
else {
|
|
72
|
+
this.scrollFromBottom = nextScrollFromBottom;
|
|
73
|
+
this.detachedScrollStart = nextScrollFromBottom === 0
|
|
74
|
+
? undefined
|
|
75
|
+
: Math.max(0, conversationLineCount - bodyHeight - nextScrollFromBottom);
|
|
76
|
+
changed = true;
|
|
77
|
+
}
|
|
78
|
+
if (shouldLoadOlderHistory)
|
|
79
|
+
this.loadOlderHistoryAnchored(metrics, { render: shouldRender });
|
|
80
80
|
if (shouldRender)
|
|
81
81
|
this.host.render();
|
|
82
|
-
return
|
|
82
|
+
return changed || shouldLoadOlderHistory;
|
|
83
83
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (!this.scrollBarForMetrics(metrics))
|
|
84
|
+
shouldLoadOlderHistory(delta, metrics) {
|
|
85
|
+
if (delta >= 0)
|
|
86
|
+
return false;
|
|
87
|
+
if (metrics.start > this.olderHistoryThresholdLines)
|
|
88
|
+
return false;
|
|
89
|
+
if (this.host.hasOlderSessionHistory?.() !== true)
|
|
91
90
|
return false;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
if (this.host.isLoadingOlderSessionHistory?.() === true)
|
|
92
|
+
return false;
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
loadOlderHistoryAnchored(metrics, options) {
|
|
96
|
+
void this.host.loadOlderSessionHistory?.({
|
|
97
|
+
render: false,
|
|
98
|
+
onPrependedEntries: (entries) => {
|
|
99
|
+
const prependedLineCount = this.host.conversationViewport().measuredLineCountForEntries(metrics.viewportColumns, entries.map((entry) => entry.id));
|
|
100
|
+
if (prependedLineCount > 0 && this.detachedScrollStart !== undefined)
|
|
101
|
+
this.detachedScrollStart += prependedLineCount;
|
|
102
|
+
},
|
|
103
|
+
}).then((loaded) => {
|
|
104
|
+
if (loaded && options.render)
|
|
105
|
+
this.host.render();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
adjustForHistoryWindowPrune(edge, lineCount) {
|
|
109
|
+
if (lineCount <= 0)
|
|
110
|
+
return;
|
|
111
|
+
if (edge !== "top")
|
|
112
|
+
return;
|
|
113
|
+
if (this.detachedScrollStart === undefined)
|
|
114
|
+
return;
|
|
115
|
+
this.detachedScrollStart = Math.max(0, this.detachedScrollStart - lineCount);
|
|
96
116
|
}
|
|
97
117
|
scrollToConversationEntry(entryId) {
|
|
98
118
|
const columns = this.host.terminalColumns();
|
|
@@ -143,12 +163,6 @@ export class AppScrollController {
|
|
|
143
163
|
}
|
|
144
164
|
return false;
|
|
145
165
|
}
|
|
146
|
-
scrollToStart(start, metrics) {
|
|
147
|
-
if (!this.setScrollStart(start, metrics))
|
|
148
|
-
return false;
|
|
149
|
-
this.host.render();
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
166
|
setScrollStart(start, metrics) {
|
|
153
167
|
const nextStart = Math.max(0, Math.min(metrics.maxScroll, start));
|
|
154
168
|
const nextScrollFromBottom = Math.max(0, metrics.conversationLineCount - metrics.bodyHeight - nextStart);
|
|
@@ -158,12 +172,9 @@ export class AppScrollController {
|
|
|
158
172
|
this.detachedScrollStart = nextDetachedScrollStart;
|
|
159
173
|
return changed;
|
|
160
174
|
}
|
|
161
|
-
viewportColumns(columns,
|
|
175
|
+
viewportColumns(columns, _bodyHeight) {
|
|
162
176
|
const safeColumns = Math.max(1, columns);
|
|
163
|
-
|
|
164
|
-
return safeColumns;
|
|
165
|
-
const lineCountWithoutScrollbar = this.host.conversationViewport().lineCount(safeColumns);
|
|
166
|
-
return lineCountWithoutScrollbar > bodyHeight ? safeColumns - 1 : safeColumns;
|
|
177
|
+
return safeColumns;
|
|
167
178
|
}
|
|
168
179
|
}
|
|
169
180
|
function editorLayoutRows(terminalRows, tabPanelRows) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { basename } from "node:path";
|
|
2
2
|
import { GIT_BRANCH_CACHE_MS } from "../constants.js";
|
|
3
3
|
import { runProcess } from "../process.js";
|
|
4
|
+
import { APP_ICONS } from "../icons.js";
|
|
4
5
|
const STATUS_DOT_BLINK_KEY = "status-dot";
|
|
5
6
|
export class AppStatusController {
|
|
6
7
|
host;
|
|
@@ -47,7 +48,7 @@ export class AppStatusController {
|
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
formatSessionStatus(session) {
|
|
50
|
-
return `${this.statusModelLabel(session)} ${this.statusThinkingLabel(session)} ${this.formatContextUsagePercent(session)}`;
|
|
51
|
+
return `${this.statusModelLabel(session)} ${APP_ICONS.lightbulb} ${this.statusThinkingLabel(session)} ${this.formatContextUsagePercent(session)}`;
|
|
51
52
|
}
|
|
52
53
|
statusModelLabel(session) {
|
|
53
54
|
return session.model ? `${session.model.provider}/${session.model.id}` : "no model";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SessionManager, type SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
export type LazySessionManagerOptions = {
|
|
3
|
+
cwdOverride?: string;
|
|
4
|
+
sessionDir?: string;
|
|
5
|
+
tailEntryCount?: number;
|
|
6
|
+
};
|
|
7
|
+
export type LazySessionHistoryReader = {
|
|
8
|
+
hasOlder(): boolean;
|
|
9
|
+
readOlder(limit: number): Promise<SessionEntry[]>;
|
|
10
|
+
};
|
|
11
|
+
export declare function openLazySessionManager(sessionPath: string, options?: LazySessionManagerOptions): SessionManager;
|