pi-ui-extend 0.1.31 → 0.1.33
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 +11 -34
- package/dist/app/model/model-usage-status.d.ts +1 -0
- package/dist/app/model/model-usage-status.js +49 -16
- 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 +7 -1
- package/dist/app/rendering/status-line-renderer.js +21 -0
- 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 +473 -29
- 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 +16 -16
- package/external/pi-tools-suite/src/dcp/index.ts +31 -43
- package/external/pi-tools-suite/src/dcp/prompts.ts +5 -0
- package/external/pi-tools-suite/src/dcp/pruner-metadata.ts +2 -2
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +2 -2
- 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 +6 -7
- 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
package/README.md
CHANGED
|
@@ -212,7 +212,7 @@ Type `/` in the prompt to open the command picker. Commands that accept argument
|
|
|
212
212
|
| `/import` | `<path.jsonl>` | Import and resume a session from a JSONL file. |
|
|
213
213
|
| `/share` | — | Share the session as a private GitHub gist (requires `gh` CLI). |
|
|
214
214
|
| `/copy` | — | Copy the last agent message to the clipboard. |
|
|
215
|
-
| `/name` | `[name]` |
|
|
215
|
+
| `/name` | `[name]` | Set the session display name. Without arguments, generate one automatically using the session-title logic. |
|
|
216
216
|
| `/session` | — | Show session info: message counts, token usage, and cost. |
|
|
217
217
|
| `/usage` | — | Show local account quota usage and context window utilization. |
|
|
218
218
|
| `/changelog` | — | Show the Pi package changelog. |
|
package/dist/app/app.d.ts
CHANGED
|
@@ -109,6 +109,8 @@ export declare class PiUiExtendApp {
|
|
|
109
109
|
private render;
|
|
110
110
|
private scheduleRender;
|
|
111
111
|
private syncScrollAfterInputEditorChange;
|
|
112
|
+
private conversationQuickScrollDirections;
|
|
113
|
+
private scrollConversationQuick;
|
|
112
114
|
private renderStatusLine;
|
|
113
115
|
private terminalColumns;
|
|
114
116
|
private terminalRows;
|
package/dist/app/app.js
CHANGED
|
@@ -183,10 +183,13 @@ export class PiUiExtendApp {
|
|
|
183
183
|
loadSessionHistoryAsync: (options) => this.loadSessionHistoryAsync(options),
|
|
184
184
|
captureSessionView: () => this.captureSessionView(),
|
|
185
185
|
restoreSessionView: (view) => this.restoreSessionView(view),
|
|
186
|
+
restoreScrollState: (state) => this.scrollController.restoreState(state),
|
|
186
187
|
syncUserSessionEntryMetadata: () => this.workspaceActions.syncUserSessionEntryMetadata(),
|
|
187
188
|
captureInputState: () => this.inputEditor.draftState,
|
|
188
189
|
restoreInputState: (state) => this.restoreTabInputState(state),
|
|
189
190
|
closeMenusForTabSwitch: () => this.popupMenus.closeMenusForTabSwitch(),
|
|
191
|
+
captureAutoUserMessages: () => this.queuedMessages.captureAutoUserMessages(),
|
|
192
|
+
restoreAutoUserMessages: (messages) => this.queuedMessages.restoreAutoUserMessages(messages),
|
|
190
193
|
captureDeferredUserMessages: () => this.queuedMessages.captureDeferredUserMessages(),
|
|
191
194
|
restoreDeferredUserMessages: (messages) => this.queuedMessages.restoreDeferredUserMessages(messages),
|
|
192
195
|
addEntry: (entry) => this.addEntry(entry),
|
|
@@ -283,6 +286,7 @@ export class PiUiExtendApp {
|
|
|
283
286
|
terminalBellSoundStatusWidgetEnabled: () => this.terminalBellSoundController.isEnabled(),
|
|
284
287
|
voiceStatusWidgetText: () => this.voiceController.statusWidgetText(),
|
|
285
288
|
voiceStatusWidgetActive: () => this.voiceController.statusWidgetActive(),
|
|
289
|
+
conversationQuickScrollDirections: () => this.conversationQuickScrollDirections(),
|
|
286
290
|
queueableInputActive: () => this.inputEditor.promptText.trimEnd().length > 0 || this.inputEditor.images.length > 0,
|
|
287
291
|
userMessageJumpMenuActive: () => this.popupMenus.directMenu === "user-message-jump",
|
|
288
292
|
allThinkingExpandedActive: () => this.allThinkingExpanded,
|
|
@@ -364,6 +368,7 @@ export class PiUiExtendApp {
|
|
|
364
368
|
setSessionStatus: (session) => this.setSessionStatus(session),
|
|
365
369
|
setSessionActivity: (activity) => this.setSessionActivity(activity),
|
|
366
370
|
updateQueuedMessageStatus: () => this.queuedMessages.updateQueuedMessageStatus(),
|
|
371
|
+
flushAutoUserMessages: () => { void this.queuedMessages.flushAutoUserMessages(); },
|
|
367
372
|
prepareWorkspaceMutation: (toolName, args) => this.workspaceActions.prepareWorkspaceMutation(toolName, args),
|
|
368
373
|
workspaceMutationFromToolExecution: (input) => this.workspaceActions.workspaceMutationFromToolExecution(input),
|
|
369
374
|
recordWorkspaceMutationForUserEntry: (entryId, mutation) => this.workspaceActions.recordWorkspaceMutationForUserEntry(entryId, mutation),
|
|
@@ -420,6 +425,7 @@ export class PiUiExtendApp {
|
|
|
420
425
|
colors: this.theme.colors,
|
|
421
426
|
pixConfig: this.pixConfig,
|
|
422
427
|
outputFilters: this.outputFilters,
|
|
428
|
+
availableThinkingLevels: () => this.runtime?.session.getAvailableThinkingLevels(),
|
|
423
429
|
hasDynamicConversationBlock: () => this.popupMenus.hasDynamicConversationBlock(),
|
|
424
430
|
isDynamicConversationBlock: (entry) => this.popupMenus.isDynamicConversationBlock(entry),
|
|
425
431
|
renderInlineUserMessageMenu: (entry, context) => this.popupMenus.renderInlineUserMessageMenu(entry, context),
|
|
@@ -433,6 +439,9 @@ export class PiUiExtendApp {
|
|
|
433
439
|
hasOlderSessionHistory: () => this.sessionEvents.hasOlderSessionHistory(),
|
|
434
440
|
isLoadingOlderSessionHistory: () => this.sessionEvents.isLoadingOlderSessionHistory(),
|
|
435
441
|
loadOlderSessionHistory: (options) => this.sessionEvents.loadOlderSessionHistory(options),
|
|
442
|
+
hasNewerSessionHistory: () => this.sessionEvents.hasNewerSessionHistory(),
|
|
443
|
+
isLoadingNewerSessionHistory: () => this.sessionEvents.isLoadingNewerSessionHistory(),
|
|
444
|
+
loadNewerSessionHistory: (options) => this.sessionEvents.loadNewerSessionHistory(options),
|
|
436
445
|
render: () => this.render(),
|
|
437
446
|
});
|
|
438
447
|
this.commandController = new AppCommandController({
|
|
@@ -564,6 +573,7 @@ export class PiUiExtendApp {
|
|
|
564
573
|
this.render();
|
|
565
574
|
});
|
|
566
575
|
},
|
|
576
|
+
scrollConversationQuick: (direction) => this.scrollConversationQuick(direction),
|
|
567
577
|
toggleAllThinkingExpanded: () => {
|
|
568
578
|
this.allThinkingExpanded = !this.allThinkingExpanded;
|
|
569
579
|
this.render();
|
|
@@ -904,12 +914,14 @@ export class PiUiExtendApp {
|
|
|
904
914
|
return {
|
|
905
915
|
entries: [...this.entries],
|
|
906
916
|
eventState: this.sessionEvents.snapshotState(),
|
|
917
|
+
scrollState: this.scrollController.captureState(),
|
|
907
918
|
};
|
|
908
919
|
}
|
|
909
920
|
restoreSessionView(view) {
|
|
910
921
|
this.entries.splice(0, this.entries.length, ...view.entries);
|
|
911
922
|
this.sessionEvents.restoreState(view.eventState);
|
|
912
923
|
this.conversationViewport.clear();
|
|
924
|
+
this.scrollController.restoreState(view.scrollState);
|
|
913
925
|
this.workspaceActions.syncUserSessionEntryMetadata();
|
|
914
926
|
}
|
|
915
927
|
loadSessionHistory() {
|
|
@@ -1109,6 +1121,22 @@ export class PiUiExtendApp {
|
|
|
1109
1121
|
this.lastInputEditorContentVersion = contentVersion;
|
|
1110
1122
|
this.scrollController.scrollToBottom();
|
|
1111
1123
|
}
|
|
1124
|
+
conversationQuickScrollDirections() {
|
|
1125
|
+
const columns = this.terminalColumns();
|
|
1126
|
+
const terminalRows = this.terminalRows();
|
|
1127
|
+
const rows = Math.max(1, terminalRows - this.tabLineRenderer.panelRows(terminalRows));
|
|
1128
|
+
const { bodyHeight } = this.editorLayoutRenderer.computeLayout(columns, rows);
|
|
1129
|
+
if (bodyHeight <= 0)
|
|
1130
|
+
return { up: false, down: false };
|
|
1131
|
+
return this.scrollController.quickScrollDirections(columns, bodyHeight);
|
|
1132
|
+
}
|
|
1133
|
+
async scrollConversationQuick(direction) {
|
|
1134
|
+
const changed = direction === "up"
|
|
1135
|
+
? await this.scrollController.scrollToAbsoluteTop()
|
|
1136
|
+
: await this.scrollController.scrollToAbsoluteBottom();
|
|
1137
|
+
if (changed)
|
|
1138
|
+
this.render();
|
|
1139
|
+
}
|
|
1112
1140
|
renderStatusLine() {
|
|
1113
1141
|
this.renderController.renderStatusLine();
|
|
1114
1142
|
}
|
|
@@ -10,6 +10,8 @@ import { copyTextToClipboard } from "../screen/clipboard.js";
|
|
|
10
10
|
import { formatAccountUsageReport, queryAccountUsageReport } from "../model/model-usage-status.js";
|
|
11
11
|
import { checkPixUpdate, formatPixUpdateCheck, parsePixUpdateArgs, pixUpdateUsage } from "../cli/update.js";
|
|
12
12
|
import { createStartupInfoMessage } from "../cli/startup-info.js";
|
|
13
|
+
import { loadSessionTitleConfig } from "../../bundled-extensions/session-title/config.js";
|
|
14
|
+
import { fallbackSessionTitleFromInput, firstUserMessageText, generateSessionTitle, sessionTitleModelRefs, } from "../../bundled-extensions/session-title/title-generation.js";
|
|
13
15
|
export class SessionCommandActions {
|
|
14
16
|
host;
|
|
15
17
|
constructor(host) {
|
|
@@ -100,8 +102,34 @@ export class SessionCommandActions {
|
|
|
100
102
|
return;
|
|
101
103
|
const name = argumentsText.trim();
|
|
102
104
|
if (!name) {
|
|
103
|
-
|
|
105
|
+
const branch = runtime.session.sessionManager.getBranch();
|
|
106
|
+
const firstPrompt = firstUserMessageText(branch);
|
|
107
|
+
if (!firstPrompt)
|
|
108
|
+
throw new Error("Cannot auto-name this session yet: no user messages found.");
|
|
109
|
+
const config = loadSessionTitleConfig(runtime.cwd);
|
|
110
|
+
const fallbackTitle = fallbackSessionTitleFromInput(firstPrompt, config.maxTitleChars);
|
|
111
|
+
const modelRefs = sessionTitleModelRefs(config);
|
|
112
|
+
let generatedName;
|
|
113
|
+
this.host.setStatus("generating session name");
|
|
114
|
+
this.host.render();
|
|
115
|
+
if (config.enabled) {
|
|
116
|
+
for (const modelRef of modelRefs) {
|
|
117
|
+
for (let attempt = 0; attempt < config.generationAttempts; attempt++) {
|
|
118
|
+
generatedName = await generateSessionTitle(firstPrompt.slice(0, config.maxInputChars).trim(), runtime.services.modelRegistry, config, modelRef, AbortSignal.timeout(config.timeoutMs));
|
|
119
|
+
if (generatedName)
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
if (generatedName)
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const nextName = generatedName ?? fallbackTitle;
|
|
127
|
+
if (!nextName)
|
|
128
|
+
throw new Error("Could not generate a session name for this session.");
|
|
129
|
+
runtime.session.setSessionName(nextName);
|
|
130
|
+
this.host.addEntry({ id: createId("system"), kind: "system", text: `Session name set: ${nextName}` });
|
|
104
131
|
this.host.setSessionStatus(runtime.session);
|
|
132
|
+
this.host.render();
|
|
105
133
|
return;
|
|
106
134
|
}
|
|
107
135
|
runtime.session.setSessionName(name);
|
package/dist/app/constants.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ResolvedToolRule } from "../config.js";
|
|
2
2
|
export declare const THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
3
3
|
export declare const THINKING_MENU_MAX_ROWS: number;
|
|
4
|
-
export declare const PI_FAVORITE_MODEL_REFS: readonly ["amazon-bedrock/us.anthropic.claude-opus-4-6-v1", "anthropic/claude-opus-4-8", "openai/gpt-5.4", "azure-openai-responses/gpt-5.4", "openai-codex/gpt-5.5", "deepseek/deepseek-v4-pro", "google/gemini-3.1-pro-preview", "google-vertex/gemini-3.1-pro-preview", "github-copilot/gpt-5.4", "openrouter/moonshotai/kimi-k2.6", "vercel-ai-gateway/zai/glm-5.
|
|
4
|
+
export declare const PI_FAVORITE_MODEL_REFS: readonly ["amazon-bedrock/us.anthropic.claude-opus-4-6-v1", "anthropic/claude-opus-4-8", "openai/gpt-5.4", "azure-openai-responses/gpt-5.4", "openai-codex/gpt-5.5", "deepseek/deepseek-v4-pro", "google/gemini-3.1-pro-preview", "google-vertex/gemini-3.1-pro-preview", "github-copilot/gpt-5.4", "openrouter/moonshotai/kimi-k2.6", "vercel-ai-gateway/zai/glm-5.2", "xai/grok-4.20-0309-reasoning", "groq/openai/gpt-oss-120b", "cerebras/zai-glm-4.7", "zai/glm-5.2", "mistral/devstral-medium-latest", "minimax/MiniMax-M2.7", "minimax-cn/MiniMax-M2.7", "moonshotai/kimi-k2.6", "moonshotai-cn/kimi-k2.6", "huggingface/moonshotai/Kimi-K2.6", "fireworks/accounts/fireworks/models/kimi-k2p6", "together/moonshotai/Kimi-K2.6", "opencode/kimi-k2.6", "opencode-go/kimi-k2.6", "kimi-coding/kimi-for-coding", "cloudflare-workers-ai/@cf/moonshotai/kimi-k2.6", "cloudflare-ai-gateway/workers-ai/@cf/moonshotai/kimi-k2.6", "xiaomi/mimo-v2.5-pro", "xiaomi-token-plan-cn/mimo-v2.5-pro", "xiaomi-token-plan-ams/mimo-v2.5-pro", "xiaomi-token-plan-sgp/mimo-v2.5-pro"];
|
|
5
5
|
export declare const SLASH_COMMAND_MENU_MAX_ROWS = 6;
|
|
6
6
|
export declare const RESUME_MENU_MAX_ROWS = 20;
|
|
7
7
|
export declare const RESUME_MENU_INITIAL_SESSION_ROWS = 30;
|
package/dist/app/constants.js
CHANGED
|
@@ -12,11 +12,11 @@ export const PI_FAVORITE_MODEL_REFS = [
|
|
|
12
12
|
"google-vertex/gemini-3.1-pro-preview",
|
|
13
13
|
"github-copilot/gpt-5.4",
|
|
14
14
|
"openrouter/moonshotai/kimi-k2.6",
|
|
15
|
-
"vercel-ai-gateway/zai/glm-5.
|
|
15
|
+
"vercel-ai-gateway/zai/glm-5.2",
|
|
16
16
|
"xai/grok-4.20-0309-reasoning",
|
|
17
17
|
"groq/openai/gpt-oss-120b",
|
|
18
18
|
"cerebras/zai-glm-4.7",
|
|
19
|
-
"zai/glm-5.
|
|
19
|
+
"zai/glm-5.2",
|
|
20
20
|
"mistral/devstral-medium-latest",
|
|
21
21
|
"minimax/MiniMax-M2.7",
|
|
22
22
|
"minimax-cn/MiniMax-M2.7",
|
package/dist/app/icons.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import { type AppIconThemeName } from "../icon-theme.js";
|
|
2
|
+
export { appIconThemeFromFallbackFlag, appIconThemeOverrideFromEnv, parseAppIconThemeName, resolveAppIconThemeNameFromEnv, PIX_ICON_THEME_ENV, PIX_USE_FALLBACK_ICONS_ENV, type AppIconThemeName, } from "../icon-theme.js";
|
|
3
3
|
declare const NERD_FONT_ICONS: {
|
|
4
4
|
readonly alert: "";
|
|
5
5
|
readonly autoFix: "";
|
|
@@ -28,17 +28,12 @@ declare const NERD_FONT_ICONS: {
|
|
|
28
28
|
readonly toolBodyEnd: "└";
|
|
29
29
|
readonly toolBodyGutter: "│";
|
|
30
30
|
readonly toolPreviewTruncated: "⊞";
|
|
31
|
-
readonly
|
|
31
|
+
readonly up: "↑";
|
|
32
|
+
readonly down: "↓";
|
|
32
33
|
};
|
|
33
34
|
export type AppIconName = keyof typeof NERD_FONT_ICONS;
|
|
34
35
|
export type AppIconMap = Record<AppIconName, string>;
|
|
35
|
-
export type AppIconThemeName = "nerdFont" | "fallback";
|
|
36
36
|
export declare const APP_ICON_THEMES: Record<AppIconThemeName, AppIconMap>;
|
|
37
37
|
export declare const APP_ICONS: AppIconMap;
|
|
38
38
|
export declare function currentAppIconTheme(): AppIconThemeName;
|
|
39
|
-
export declare function parseAppIconThemeName(value: unknown): AppIconThemeName | undefined;
|
|
40
|
-
export declare function appIconThemeFromFallbackFlag(value: unknown): AppIconThemeName | undefined;
|
|
41
|
-
export declare function resolveAppIconThemeNameFromEnv(env?: NodeJS.ProcessEnv): AppIconThemeName;
|
|
42
|
-
export declare function appIconThemeOverrideFromEnv(env?: NodeJS.ProcessEnv): AppIconThemeName | undefined;
|
|
43
39
|
export declare function setAppIconTheme(themeName: AppIconThemeName): void;
|
|
44
|
-
export {};
|
package/dist/app/icons.js
CHANGED
|
@@ -4,8 +4,13 @@
|
|
|
4
4
|
//
|
|
5
5
|
// Use codepoint escapes for private-use characters so editors cannot silently
|
|
6
6
|
// substitute visually similar glyphs.
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
//
|
|
8
|
+
// Theme-name parsing/resolution lives in the dependency-free src/icon-theme.ts so
|
|
9
|
+
// configuration loading can resolve the theme without importing this app/ module
|
|
10
|
+
// (breaks the src/config.ts <-> src/app/icons.ts import cycle).
|
|
11
|
+
import { resolveAppIconThemeNameFromEnv, } from "../icon-theme.js";
|
|
12
|
+
// Re-exported for existing importers; the canonical home is src/icon-theme.ts.
|
|
13
|
+
export { appIconThemeFromFallbackFlag, appIconThemeOverrideFromEnv, parseAppIconThemeName, resolveAppIconThemeNameFromEnv, PIX_ICON_THEME_ENV, PIX_USE_FALLBACK_ICONS_ENV, } from "../icon-theme.js";
|
|
9
14
|
const NERD_FONT_ICONS = {
|
|
10
15
|
alert: "\u{f0026}",
|
|
11
16
|
autoFix: "\u{f0068}",
|
|
@@ -34,7 +39,8 @@ const NERD_FONT_ICONS = {
|
|
|
34
39
|
toolBodyEnd: "└",
|
|
35
40
|
toolBodyGutter: "│",
|
|
36
41
|
toolPreviewTruncated: "⊞",
|
|
37
|
-
|
|
42
|
+
up: "↑",
|
|
43
|
+
down: "↓",
|
|
38
44
|
};
|
|
39
45
|
const FALLBACK_ICONS = {
|
|
40
46
|
alert: "!",
|
|
@@ -64,7 +70,8 @@ const FALLBACK_ICONS = {
|
|
|
64
70
|
toolBodyEnd: "`",
|
|
65
71
|
toolBodyGutter: "|",
|
|
66
72
|
toolPreviewTruncated: "+",
|
|
67
|
-
|
|
73
|
+
up: "↑",
|
|
74
|
+
down: "↓",
|
|
68
75
|
};
|
|
69
76
|
export const APP_ICON_THEMES = {
|
|
70
77
|
nerdFont: NERD_FONT_ICONS,
|
|
@@ -75,36 +82,6 @@ export const APP_ICONS = { ...APP_ICON_THEMES[currentAppIconThemeName] };
|
|
|
75
82
|
export function currentAppIconTheme() {
|
|
76
83
|
return currentAppIconThemeName;
|
|
77
84
|
}
|
|
78
|
-
export function parseAppIconThemeName(value) {
|
|
79
|
-
if (typeof value !== "string")
|
|
80
|
-
return undefined;
|
|
81
|
-
const normalized = value.trim().toLowerCase().replace(/[\s_-]+/gu, "");
|
|
82
|
-
if (normalized === "fallback" || normalized === "plain" || normalized === "ascii")
|
|
83
|
-
return "fallback";
|
|
84
|
-
if (normalized === "nerdfont" || normalized === "font" || normalized === "icons")
|
|
85
|
-
return "nerdFont";
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
export function appIconThemeFromFallbackFlag(value) {
|
|
89
|
-
if (typeof value === "boolean")
|
|
90
|
-
return value ? "fallback" : "nerdFont";
|
|
91
|
-
if (typeof value !== "string")
|
|
92
|
-
return undefined;
|
|
93
|
-
const normalized = value.trim().toLowerCase();
|
|
94
|
-
if (["1", "true", "yes", "on", "fallback"].includes(normalized))
|
|
95
|
-
return "fallback";
|
|
96
|
-
if (["0", "false", "no", "off", "nerdfont", "nerd-font"].includes(normalized))
|
|
97
|
-
return "nerdFont";
|
|
98
|
-
return undefined;
|
|
99
|
-
}
|
|
100
|
-
export function resolveAppIconThemeNameFromEnv(env = process.env) {
|
|
101
|
-
return appIconThemeOverrideFromEnv(env) ?? "nerdFont";
|
|
102
|
-
}
|
|
103
|
-
export function appIconThemeOverrideFromEnv(env = process.env) {
|
|
104
|
-
return appIconThemeFromFallbackFlag(env[PIX_USE_FALLBACK_ICONS_ENV])
|
|
105
|
-
?? parseAppIconThemeName(env[PIX_ICON_THEME_ENV])
|
|
106
|
-
?? undefined;
|
|
107
|
-
}
|
|
108
85
|
export function setAppIconTheme(themeName) {
|
|
109
86
|
currentAppIconThemeName = themeName;
|
|
110
87
|
Object.assign(APP_ICONS, APP_ICON_THEMES[themeName]);
|
|
@@ -8,6 +8,7 @@ export type ModelUsageDescriptor = BaseModelUsageDescriptor & ({
|
|
|
8
8
|
readonly kind: "google-antigravity";
|
|
9
9
|
readonly quotaModelKey: string;
|
|
10
10
|
readonly account: AntigravityQuotaAccount;
|
|
11
|
+
readonly accounts?: readonly AntigravityQuotaAccount[];
|
|
11
12
|
});
|
|
12
13
|
export type ModelUsageLimitWindow = {
|
|
13
14
|
readonly remainingPercent: number;
|
|
@@ -35,14 +35,16 @@ export function modelUsageDescriptor(model) {
|
|
|
35
35
|
}
|
|
36
36
|
if (ANTIGRAVITY_QUOTA_PROVIDERS.has(provider)) {
|
|
37
37
|
const quotaModelKey = resolveAntigravityQuotaModelKey(model);
|
|
38
|
-
const
|
|
38
|
+
const accounts = readAllAntigravityQuotaAccounts();
|
|
39
|
+
const account = readActiveAntigravityQuotaAccount(accounts);
|
|
39
40
|
if (!quotaModelKey || !account)
|
|
40
41
|
return undefined;
|
|
41
42
|
return {
|
|
42
43
|
kind: "google-antigravity",
|
|
43
|
-
modelKey: `${model.provider}/${model.id}
|
|
44
|
+
modelKey: `${model.provider}/${model.id}@all:${accounts.map((item) => item.cacheKey).join(",")}`,
|
|
44
45
|
quotaModelKey,
|
|
45
46
|
account,
|
|
47
|
+
accounts,
|
|
46
48
|
};
|
|
47
49
|
}
|
|
48
50
|
return undefined;
|
|
@@ -384,15 +386,9 @@ export function resolveAntigravityQuotaModelKey(model) {
|
|
|
384
386
|
return undefined;
|
|
385
387
|
}
|
|
386
388
|
export function googleAntigravityUsageStatusFromResponse(data, descriptor, now = Date.now()) {
|
|
387
|
-
const
|
|
388
|
-
if (!
|
|
389
|
+
const window = googleAntigravityWindowFromResponse(data, descriptor.quotaModelKey, now);
|
|
390
|
+
if (!window)
|
|
389
391
|
return undefined;
|
|
390
|
-
const resetAt = parseResetTime(quotaInfo.resetTime, now);
|
|
391
|
-
const window = {
|
|
392
|
-
remainingPercent: quotaRemainingPercent(quotaInfo),
|
|
393
|
-
resetAt,
|
|
394
|
-
windowSeconds: Math.max(0, Math.round((resetAt - now) / 1000)),
|
|
395
|
-
};
|
|
396
392
|
const weekly = window.windowSeconds >= DAY_SECONDS ? window : undefined;
|
|
397
393
|
const hourly = weekly ? undefined : window;
|
|
398
394
|
return {
|
|
@@ -404,10 +400,48 @@ export function googleAntigravityUsageStatusFromResponse(data, descriptor, now =
|
|
|
404
400
|
...(hourly ? { hourly } : {}),
|
|
405
401
|
};
|
|
406
402
|
}
|
|
403
|
+
function googleAntigravityWindowFromResponse(data, quotaModelKey, now) {
|
|
404
|
+
const quotaInfo = data.models[quotaModelKey]?.quotaInfo;
|
|
405
|
+
if (!quotaInfo)
|
|
406
|
+
return undefined;
|
|
407
|
+
const resetAt = parseResetTime(quotaInfo.resetTime, now);
|
|
408
|
+
return {
|
|
409
|
+
remainingPercent: quotaRemainingPercent(quotaInfo),
|
|
410
|
+
resetAt,
|
|
411
|
+
windowSeconds: Math.max(0, Math.round((resetAt - now) / 1000)),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
407
414
|
async function queryGoogleAntigravityModelUsage(descriptor) {
|
|
408
415
|
const now = Date.now();
|
|
409
|
-
const
|
|
410
|
-
|
|
416
|
+
const accounts = descriptor.accounts?.length ? descriptor.accounts : [descriptor.account];
|
|
417
|
+
const windows = (await Promise.all(accounts.map(async (account) => {
|
|
418
|
+
try {
|
|
419
|
+
const response = await fetchGoogleAntigravityQuotaForAccount(account, now);
|
|
420
|
+
return googleAntigravityWindowFromResponse(response, descriptor.quotaModelKey, now);
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
}))).filter((window) => window !== undefined);
|
|
426
|
+
if (windows.length === 0)
|
|
427
|
+
return undefined;
|
|
428
|
+
const resetAt = Math.min(...windows.map((window) => window.resetAt));
|
|
429
|
+
const windowSeconds = Math.max(0, Math.round((resetAt - now) / 1000));
|
|
430
|
+
const aggregateWindow = {
|
|
431
|
+
remainingPercent: clampPercent(Math.round(windows.reduce((sum, window) => sum + window.remainingPercent, 0) / windows.length)),
|
|
432
|
+
resetAt,
|
|
433
|
+
windowSeconds,
|
|
434
|
+
};
|
|
435
|
+
const weekly = aggregateWindow.windowSeconds >= DAY_SECONDS ? aggregateWindow : undefined;
|
|
436
|
+
const hourly = weekly ? undefined : aggregateWindow;
|
|
437
|
+
return {
|
|
438
|
+
modelKey: descriptor.modelKey,
|
|
439
|
+
provider: "google-antigravity",
|
|
440
|
+
updatedAt: now,
|
|
441
|
+
accountEmail: "Σ",
|
|
442
|
+
...(weekly ? { weekly } : {}),
|
|
443
|
+
...(hourly ? { hourly } : {}),
|
|
444
|
+
};
|
|
411
445
|
}
|
|
412
446
|
const GOOGLE_ACCOUNT_QUOTA_WINDOWS = [
|
|
413
447
|
{ label: "Claude Opus", quotaModelKey: "claude-opus-4-6-thinking" },
|
|
@@ -440,8 +474,7 @@ async function queryGoogleAntigravityAccountUsage(now) {
|
|
|
440
474
|
}));
|
|
441
475
|
return results;
|
|
442
476
|
}
|
|
443
|
-
function readActiveAntigravityQuotaAccount() {
|
|
444
|
-
const accounts = readAllAntigravityQuotaAccounts();
|
|
477
|
+
function readActiveAntigravityQuotaAccount(accounts = readAllAntigravityQuotaAccounts()) {
|
|
445
478
|
const credential = readPiAuthSync().antigravity;
|
|
446
479
|
return accounts[clampAccountIndex(credential?.activeIndex, accounts.length)];
|
|
447
480
|
}
|
|
@@ -564,9 +597,9 @@ function googleQuotaResponseFromCachedQuota(cachedQuota, cachedQuotaUpdatedAt, n
|
|
|
564
597
|
return Object.keys(models).length > 0 ? { models } : undefined;
|
|
565
598
|
}
|
|
566
599
|
function addCachedQuotaModels(models, quota, quotaModelKeys, cachedQuotaUpdatedAt, now) {
|
|
567
|
-
if (!quota
|
|
600
|
+
if (!quota)
|
|
568
601
|
return;
|
|
569
|
-
const remainingFraction = quota.remainingFraction;
|
|
602
|
+
const remainingFraction = Number.isFinite(quota.remainingFraction) ? quota.remainingFraction : 0;
|
|
570
603
|
const resetTime = cachedQuotaResetTimeForDisplay(quota.resetTime, cachedQuotaUpdatedAt, now);
|
|
571
604
|
for (const quotaModelKey of quotaModelKeys) {
|
|
572
605
|
models[quotaModelKey] = {
|
|
@@ -11,6 +11,7 @@ export type ConversationEntryRenderOptions = {
|
|
|
11
11
|
colors: Theme["colors"];
|
|
12
12
|
pixConfig: PixConfig;
|
|
13
13
|
outputFilters: readonly RegExp[];
|
|
14
|
+
availableThinkingLevels?: readonly string[];
|
|
14
15
|
superCompactTools?: boolean;
|
|
15
16
|
allThinkingExpanded?: boolean;
|
|
16
17
|
renderInlineUserMessageMenu: (entry: Extract<Entry, {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { resolveColor, resolveToolRule } from "../../config.js";
|
|
2
2
|
import { formatMarkdownTables, markdownSyntaxHighlightsForText } from "../../markdown-format.js";
|
|
3
3
|
import { renderToolDisplay } from "../../tool-renderers/index.js";
|
|
4
|
-
import {
|
|
4
|
+
import { SUBAGENT_STATUSES, THINKING_TOOL_NAME, TODO_TOOL_NAME } from "../constants.js";
|
|
5
5
|
import { attachImageClickTargets } from "../screen/image-click-targets.js";
|
|
6
6
|
import { formatStructuredText } from "./message-content.js";
|
|
7
7
|
import { formatSubagentTimestamp, isSubagentRunRenderDetails, isSubagentsToolName, subagentRunName, subagentStatusIcon, taskPreviewMap, } from "../subagents/subagents-model.js";
|
|
8
8
|
import { formatTodoTaskLine, isTodoDetails, visibleTodoTasks } from "../todo/todo-model.js";
|
|
9
9
|
import { renderToolBlock } from "./tool-block-renderer.js";
|
|
10
|
+
import { thinkingLevelThemeColor } from "./status-line-renderer.js";
|
|
10
11
|
export function renderConversationToolEntry(entry, width, options) {
|
|
11
12
|
const todoLines = renderTodoToolEntry(entry, width, options);
|
|
12
13
|
if (todoLines)
|
|
@@ -46,12 +47,15 @@ export function renderConversationToolEntry(entry, width, options) {
|
|
|
46
47
|
return attachImageClickTargets(lines, entry.id, entry.images, { foreground: options.colors.info, underline: true });
|
|
47
48
|
}
|
|
48
49
|
export function renderThinkingEntry(entry, width, options) {
|
|
49
|
-
const rule =
|
|
50
|
+
const rule = resolveToolRule(THINKING_TOOL_NAME, options.pixConfig.toolRenderer);
|
|
50
51
|
const markdownText = entry.text ? formatMarkdownTables(entry.text, Math.max(1, width - 2)) : "";
|
|
51
52
|
const expandedText = trimTrailingBlankLines(markdownText);
|
|
52
53
|
const forceExpanded = Boolean(options.allThinkingExpanded);
|
|
53
54
|
const compactExpandedText = options.superCompactTools && forceExpanded ? removeBlankLines(expandedText) : expandedText;
|
|
54
55
|
const expanded = forceExpanded || (entry.expanded && expandedText.trim().length > 0);
|
|
56
|
+
const headerColorOverride = entry.level
|
|
57
|
+
? thinkingLevelThemeColor(entry.level, options.colors, options.availableThinkingLevels)
|
|
58
|
+
: undefined;
|
|
55
59
|
return renderToolBlock({
|
|
56
60
|
id: entry.id,
|
|
57
61
|
toolName: THINKING_TOOL_NAME,
|
|
@@ -63,7 +67,12 @@ export function renderThinkingEntry(entry, width, options) {
|
|
|
63
67
|
expandedText: compactExpandedText || "(empty)",
|
|
64
68
|
bodyWrap: "word",
|
|
65
69
|
syntaxHighlight: compactExpandedText ? markdownSyntaxHighlightsForText(compactExpandedText) : undefined,
|
|
66
|
-
}, rule, width, options.colors, {
|
|
70
|
+
}, rule, width, options.colors, {
|
|
71
|
+
superCompact: Boolean(options.superCompactTools && !forceExpanded),
|
|
72
|
+
backgroundOverride: options.colors.thinkingMessageBackground,
|
|
73
|
+
showGutter: true,
|
|
74
|
+
...(headerColorOverride === undefined ? {} : { headerColorOverride }),
|
|
75
|
+
});
|
|
67
76
|
}
|
|
68
77
|
function trimTrailingBlankLines(text) {
|
|
69
78
|
return text.replace(/(?:\r?\n[ \t]*)+$/u, "");
|
|
@@ -199,18 +208,3 @@ function formatSubagentToolLine(agent, preview) {
|
|
|
199
208
|
parts.push(`retry:${agent.retryCount}`);
|
|
200
209
|
return parts.join(" ");
|
|
201
210
|
}
|
|
202
|
-
function resolveThinkingToolRule(pixConfig) {
|
|
203
|
-
const configured = pixConfig.toolRenderer.tools[THINKING_TOOL_NAME];
|
|
204
|
-
if (!configured)
|
|
205
|
-
return DEFAULT_THINKING_TOOL_RULE;
|
|
206
|
-
const rule = {
|
|
207
|
-
previewLines: configured.previewLines ?? DEFAULT_THINKING_TOOL_RULE.previewLines,
|
|
208
|
-
direction: configured.direction ?? DEFAULT_THINKING_TOOL_RULE.direction,
|
|
209
|
-
color: configured.color ?? DEFAULT_THINKING_TOOL_RULE.color,
|
|
210
|
-
};
|
|
211
|
-
if (configured.compactHidden != null)
|
|
212
|
-
rule.compactHidden = configured.compactHidden;
|
|
213
|
-
if (configured.hidden != null)
|
|
214
|
-
rule.hidden = configured.hidden;
|
|
215
|
-
return rule;
|
|
216
|
-
}
|
|
@@ -9,6 +9,7 @@ export type ConversationViewportHost = {
|
|
|
9
9
|
readonly colors: Theme["colors"];
|
|
10
10
|
readonly pixConfig: PixConfig;
|
|
11
11
|
readonly outputFilters: readonly RegExp[];
|
|
12
|
+
availableThinkingLevels?(): readonly string[] | undefined;
|
|
12
13
|
readonly superCompactTools?: boolean;
|
|
13
14
|
readonly allThinkingExpanded?: boolean;
|
|
14
15
|
hasDynamicConversationBlock?(): boolean;
|
|
@@ -36,11 +37,14 @@ export declare class ConversationViewport {
|
|
|
36
37
|
entries(): Entry[];
|
|
37
38
|
blockForEntry(entry: Entry, width: number): ConversationBlockCache;
|
|
38
39
|
entryBlockPositions(width: number): ConversationEntryBlockPosition[];
|
|
40
|
+
entryBlockPositionById(width: number, entryId: string): ConversationEntryBlockPosition | undefined;
|
|
39
41
|
measuredLineCountForEntries(width: number, entryIds: readonly string[]): number;
|
|
40
42
|
private layoutForWidth;
|
|
41
43
|
private buildLayout;
|
|
42
44
|
private previousMeasuredLineCount;
|
|
43
45
|
private layoutStructureChanged;
|
|
46
|
+
private syncLayoutStructure;
|
|
47
|
+
private rebuildOffsets;
|
|
44
48
|
private refreshDirtyLayoutEntries;
|
|
45
49
|
private blockCacheForWidth;
|
|
46
50
|
private refreshDynamicLayoutEntries;
|