pi-ui-extend 1.0.41 → 1.0.45
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 +50 -13
- package/dist/app/app.d.ts +13 -0
- package/dist/app/app.js +158 -8
- package/dist/app/cli/install.js +2 -2
- package/dist/app/commands/command-controller.d.ts +4 -0
- package/dist/app/commands/command-controller.js +11 -0
- package/dist/app/commands/command-git-actions.d.ts +25 -0
- package/dist/app/commands/command-git-actions.js +381 -0
- package/dist/app/commands/command-host.d.ts +4 -0
- package/dist/app/commands/command-host.js +5 -2
- package/dist/app/commands/command-model-actions.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +57 -35
- package/dist/app/commands/command-navigation-actions.d.ts +1 -0
- package/dist/app/commands/command-navigation-actions.js +16 -3
- package/dist/app/commands/command-registry.d.ts +2 -0
- package/dist/app/commands/command-registry.js +15 -1
- package/dist/app/commands/command-session-actions.js +9 -3
- package/dist/app/commands/reload-context-inventory.d.ts +11 -0
- package/dist/app/commands/reload-context-inventory.js +70 -0
- package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
- package/dist/app/extensions/extension-actions-controller.js +6 -0
- package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
- package/dist/app/extensions/subagent-catalog-state.js +23 -0
- package/dist/app/input/autocomplete-controller.js +61 -34
- package/dist/app/input/input-action-controller.d.ts +2 -0
- package/dist/app/input/input-action-controller.js +8 -1
- package/dist/app/input/input-controller.d.ts +2 -1
- package/dist/app/input/input-controller.js +7 -2
- package/dist/app/input/prompt-enhancer-controller.js +53 -35
- package/dist/app/input/voice-controller.d.ts +41 -45
- package/dist/app/input/voice-controller.js +351 -419
- package/dist/app/model/model-usage-controller.js +17 -7
- package/dist/app/model/model-usage-status.d.ts +4 -1
- package/dist/app/model/model-usage-status.js +270 -46
- package/dist/app/popup/menu-items-controller.d.ts +13 -3
- package/dist/app/popup/menu-items-controller.js +37 -21
- package/dist/app/popup/popup-action-controller.d.ts +12 -2
- package/dist/app/popup/popup-action-controller.js +77 -24
- package/dist/app/popup/popup-menu-controller.d.ts +36 -14
- package/dist/app/popup/popup-menu-controller.js +239 -69
- package/dist/app/rendering/dcp-stats.d.ts +9 -4
- package/dist/app/rendering/dcp-stats.js +40 -425
- package/dist/app/rendering/editor-panels.js +10 -4
- package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
- package/dist/app/rendering/popup-menu-renderer.js +42 -37
- package/dist/app/rendering/render-controller.js +23 -2
- package/dist/app/rendering/status-line-renderer.d.ts +5 -0
- package/dist/app/rendering/status-line-renderer.js +41 -5
- package/dist/app/rendering/tab-line-renderer.js +26 -20
- package/dist/app/runtime.d.ts +12 -1
- package/dist/app/runtime.js +120 -12
- package/dist/app/screen/mouse-controller.d.ts +2 -0
- package/dist/app/screen/mouse-controller.js +17 -7
- package/dist/app/screen/status-controller.d.ts +4 -0
- package/dist/app/screen/status-controller.js +5 -0
- package/dist/app/session/lazy-session-manager.js +34 -0
- package/dist/app/session/session-event-controller.d.ts +1 -0
- package/dist/app/session/session-event-controller.js +10 -1
- package/dist/app/session/session-history.d.ts +1 -0
- package/dist/app/session/session-history.js +12 -1
- package/dist/app/session/session-lifecycle-controller.d.ts +7 -1
- package/dist/app/session/session-lifecycle-controller.js +16 -1
- package/dist/app/session/tabs-controller.d.ts +26 -1
- package/dist/app/session/tabs-controller.js +454 -147
- package/dist/app/subagents/subagents-files.js +60 -1
- package/dist/app/subagents/subagents-model.d.ts +1 -0
- package/dist/app/subagents/subagents-model.js +18 -2
- package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
- package/dist/app/subagents/subagents-widget-controller.js +6 -0
- package/dist/app/types.d.ts +16 -1
- package/dist/app/workspace/workspace-actions-controller.js +10 -2
- package/dist/app/workspace/workspace-undo.d.ts +1 -0
- package/dist/app/workspace/workspace-undo.js +1 -0
- package/dist/bundled-extensions/question/index.js +9 -1
- package/dist/bundled-extensions/question/remote.d.ts +4 -0
- package/dist/bundled-extensions/question/remote.js +33 -0
- package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
- package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
- package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
- package/dist/bundled-extensions/telegram-connector/config.js +87 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
- package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
- package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
- package/dist/bundled-extensions/telegram-connector/index.js +195 -0
- package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
- package/dist/bundled-extensions/terminal-bell/index.js +0 -76
- package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
- package/dist/bundled-extensions/workspace-undo/index.js +191 -0
- package/dist/config.d.ts +21 -2
- package/dist/config.js +159 -32
- package/dist/default-pix-config.js +25 -5
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +88 -62
- package/dist/schemas/pi-tools-suite-schema.js +54 -83
- package/dist/schemas/pix-schema.d.ts +19 -2
- package/dist/schemas/pix-schema.js +47 -5
- package/dist/schemas/tasks-schema.d.ts +18 -0
- package/dist/schemas/tasks-schema.js +41 -0
- package/docs/concurrency.md +9 -1
- package/docs/desktop-mvp.md +22 -6
- package/docs/desktop-task-manager.md +148 -84
- package/docs/release.md +30 -6
- package/external/pi-tools-suite/README.md +197 -84
- package/external/pi-tools-suite/docs/evals.md +1 -1
- package/external/pi-tools-suite/docs/session-recovery.md +47 -14
- package/external/pi-tools-suite/docs/subagent-model-pools.md +48 -30
- package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
- package/external/pi-tools-suite/package.json +6 -1
- package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
- package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
- package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
- package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
- package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
- package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
- package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
- package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
- package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/research.md +5 -3
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
- package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
- package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
- package/external/pi-tools-suite/src/async-subagents/commands.ts +15 -71
- package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +5 -4
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +8 -5
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +160 -327
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
- package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +21 -5
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +40 -26
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
- package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
- package/external/pi-tools-suite/src/async-subagents/index.ts +69 -5
- package/external/pi-tools-suite/src/async-subagents/lib.ts +16 -9
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +8 -5
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +5 -4
- package/external/pi-tools-suite/src/async-subagents/types.ts +1 -0
- package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
- package/external/pi-tools-suite/src/config.ts +55 -1
- package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +77 -3
- package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +222 -0
- package/external/pi-tools-suite/src/context-gateway/index.ts +206 -19
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +7 -7
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +101 -28
- package/external/pi-tools-suite/src/context-gateway/types.ts +16 -3
- package/external/pi-tools-suite/src/context-inventory.ts +99 -0
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +128 -49
- package/external/pi-tools-suite/src/dcp/commands.ts +32 -156
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +177 -46
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +6 -58
- package/external/pi-tools-suite/src/dcp/compression-preview.ts +9 -0
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
- package/external/pi-tools-suite/src/dcp/config.ts +114 -17
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
- package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
- package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
- package/external/pi-tools-suite/src/dcp/index.ts +338 -66
- package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
- package/external/pi-tools-suite/src/dcp/prompts.ts +83 -192
- package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +93 -3
- package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +6 -10
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
- package/external/pi-tools-suite/src/dcp/pruner-tools.ts +6 -3
- package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
- package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
- package/external/pi-tools-suite/src/dcp/state.ts +9 -0
- package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
- package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +78 -22
- package/external/pi-tools-suite/src/index.ts +7 -1
- package/external/pi-tools-suite/src/lib/project.ts +36 -1
- package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
- package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
- package/external/pi-tools-suite/src/resource-registry/index.ts +2551 -0
- package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
- package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
- package/external/pi-tools-suite/src/todo/index.ts +21 -0
- package/external/pi-tools-suite/src/todo/todo.ts +19 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +47 -19
- package/package.json +10 -9
- package/schemas/pi-tools-suite.json +466 -287
- package/schemas/pix.json +129 -11
- package/schemas/tasks.json +131 -0
- package/skills/simplify/SKILL.md +33 -5
- package/docs/desktop-markdown-media.md +0 -77
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -177
- package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
- package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -54
- package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
- package/skills/playwright-cli/SKILL.md +0 -420
- package/skills/playwright-cli/references/element-attributes.md +0 -23
- package/skills/playwright-cli/references/playwright-tests.md +0 -50
- package/skills/playwright-cli/references/request-mocking.md +0 -87
- package/skills/playwright-cli/references/running-code.md +0 -241
- package/skills/playwright-cli/references/session-management.md +0 -273
- package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
- package/skills/playwright-cli/references/storage-state.md +0 -290
- package/skills/playwright-cli/references/test-generation.md +0 -142
- package/skills/playwright-cli/references/tracing.md +0 -154
- package/skills/playwright-cli/references/video-recording.md +0 -147
- package/skills/spec-lite/SKILL.md +0 -140
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
- /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { colorLine } from "../../theme.js";
|
|
2
2
|
import { stringDisplayWidth } from "../../terminal-width.js";
|
|
3
3
|
import { resolveColor, resolveModelColor } from "../../config.js";
|
|
4
|
-
import { SLASH_COMMAND_DESCRIPTION_COLUMN,
|
|
4
|
+
import { SLASH_COMMAND_DESCRIPTION_COLUMN, } from "../constants.js";
|
|
5
5
|
import { APP_ICONS } from "../icons.js";
|
|
6
6
|
import { ellipsizeDisplay, padOrTrimPlain, sanitizeText } from "./render-text.js";
|
|
7
7
|
import { modelProviderThemeColor, thinkingLevelThemeColor } from "./status-line-renderer.js";
|
|
@@ -96,8 +96,8 @@ export class PopupMenuRenderer {
|
|
|
96
96
|
}
|
|
97
97
|
return lines;
|
|
98
98
|
}
|
|
99
|
-
renderModelMenu(width, menu) {
|
|
100
|
-
const lines = [this.popupMenuHeader("Select model", width)];
|
|
99
|
+
renderModelMenu(width, menu, state) {
|
|
100
|
+
const lines = [this.popupMenuHeader(state.visibilityMode ? "Manage visible models" : "Select model & thinking", width)];
|
|
101
101
|
const visibleItems = menu.visibleItems();
|
|
102
102
|
if (!this.hasPopupActionItems(menu.items)) {
|
|
103
103
|
lines.push({
|
|
@@ -106,37 +106,55 @@ export class PopupMenuRenderer {
|
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
108
|
for (const item of visibleItems) {
|
|
109
|
-
const
|
|
110
|
-
const
|
|
109
|
+
const selectionMarker = item.selected ? "▶ " : " ";
|
|
110
|
+
const visibilityMarker = state.visibilityMode ? `${item.value.visible === false ? "○" : APP_ICONS.check} ` : "";
|
|
111
|
+
const marker = `${selectionMarker}${visibilityMarker}`;
|
|
112
|
+
const text = `${marker}${this.labelDescriptionText(item.label, item.description, width - marker.length)}`;
|
|
111
113
|
lines.push({
|
|
112
114
|
text,
|
|
113
115
|
variant: this.selectableItemVariant(item.value),
|
|
114
|
-
segments: [
|
|
116
|
+
segments: [
|
|
117
|
+
...this.modelMenuItemSegments(item.value, marker.length),
|
|
118
|
+
...this.itemHighlightSegments(item, text, marker.length),
|
|
119
|
+
],
|
|
115
120
|
target: { kind: "popup-menu", index: item.index },
|
|
116
121
|
});
|
|
117
122
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
if (state.visibilityMode && menu.selectedItem()) {
|
|
124
|
+
const selected = menu.selectedItem().value;
|
|
125
|
+
lines.push({
|
|
126
|
+
text: selected.current
|
|
127
|
+
? " Current model stays visible until another model is selected"
|
|
128
|
+
: " Enter toggles whether this model appears in model pickers",
|
|
129
|
+
variant: "muted",
|
|
130
|
+
});
|
|
131
|
+
lines.push({
|
|
132
|
+
text: " Clear all",
|
|
133
|
+
variant: "error",
|
|
134
|
+
target: { kind: "model-visibility-clear" },
|
|
135
|
+
});
|
|
136
|
+
lines.push({ text: " ↑/↓ model · Enter show/hide · Shift+Tab select", variant: "muted" });
|
|
125
137
|
}
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
const
|
|
138
|
+
else if (menu.selectedItem()) {
|
|
139
|
+
const thinkingPrefix = " Thinking ← ";
|
|
140
|
+
const thinkingSuffix = " →";
|
|
129
141
|
lines.push({
|
|
130
|
-
text
|
|
131
|
-
variant:
|
|
132
|
-
segments:
|
|
133
|
-
|
|
142
|
+
text: `${thinkingPrefix}${state.thinkingLevel}${thinkingSuffix}`,
|
|
143
|
+
variant: "normal",
|
|
144
|
+
segments: [{
|
|
145
|
+
start: thinkingPrefix.length,
|
|
146
|
+
end: thinkingPrefix.length + state.thinkingLevel.length,
|
|
147
|
+
foreground: thinkingLevelThemeColor(state.thinkingLevel, this.host.theme.colors, state.availableThinkingLevels),
|
|
148
|
+
bold: true,
|
|
149
|
+
}],
|
|
134
150
|
});
|
|
151
|
+
lines.push({ text: " ↑/↓ model · ←/→ thinking · Enter apply · Shift+Tab manage", variant: "muted" });
|
|
135
152
|
}
|
|
136
153
|
return lines;
|
|
137
154
|
}
|
|
138
155
|
renderResumeMenu(width, menu, state) {
|
|
139
|
-
const
|
|
156
|
+
const titleBase = state.draft ? "Open a conversation" : "Resume session";
|
|
157
|
+
const title = this.host.resumeLoading ? `${titleBase} ${APP_ICONS.timerSand}` : titleBase;
|
|
140
158
|
const lines = [this.popupMenuHeader(title, width)];
|
|
141
159
|
const visibleItems = menu.visibleItems();
|
|
142
160
|
if (!this.host.resumeLoading && !this.hasPopupActionItems(menu.items)) {
|
|
@@ -261,16 +279,7 @@ export class PopupMenuRenderer {
|
|
|
261
279
|
selectableItemVariant(value) {
|
|
262
280
|
return value.current ? "muted" : "normal";
|
|
263
281
|
}
|
|
264
|
-
|
|
265
|
-
const markerOffset = 2; // "▶ " or " "
|
|
266
|
-
return [{
|
|
267
|
-
start: markerOffset,
|
|
268
|
-
end: markerOffset + value.level.length,
|
|
269
|
-
foreground: thinkingLevelThemeColor(value.level, this.host.theme.colors, this.availableThinkingLevels()),
|
|
270
|
-
}];
|
|
271
|
-
}
|
|
272
|
-
modelMenuItemSegments(value) {
|
|
273
|
-
const markerOffset = 2; // "▶ " or " "
|
|
282
|
+
modelMenuItemSegments(value, markerOffset = 2) {
|
|
274
283
|
return [{
|
|
275
284
|
start: markerOffset,
|
|
276
285
|
end: markerOffset + value.ref.length,
|
|
@@ -285,10 +294,6 @@ export class PopupMenuRenderer {
|
|
|
285
294
|
? resolveColor(configuredColor, this.host.theme.colors)
|
|
286
295
|
: modelProviderThemeColor(value.model.provider, this.host.theme.colors);
|
|
287
296
|
}
|
|
288
|
-
availableThinkingLevels() {
|
|
289
|
-
const levels = this.host.session?.getAvailableThinkingLevels();
|
|
290
|
-
return Array.isArray(levels) && levels.length > 0 ? levels.map(String) : [...THINKING_LEVELS];
|
|
291
|
-
}
|
|
292
297
|
queueMessageItemVariant(value) {
|
|
293
298
|
return value === "cancel" ? "error" : "normal";
|
|
294
299
|
}
|
|
@@ -301,8 +306,8 @@ export class PopupMenuRenderer {
|
|
|
301
306
|
...this.descriptionHighlightSegments(item.description, item.descriptionHighlightRanges ?? item.value.descriptionHighlightRanges ?? [], text),
|
|
302
307
|
];
|
|
303
308
|
}
|
|
304
|
-
itemHighlightSegments(item, text) {
|
|
305
|
-
return this.highlightSegments(item.labelHighlightRanges ?? [], text,
|
|
309
|
+
itemHighlightSegments(item, text, markerOffset = 2) {
|
|
310
|
+
return this.highlightSegments(item.labelHighlightRanges ?? [], text, markerOffset);
|
|
306
311
|
}
|
|
307
312
|
highlightSegments(ranges, text, markerOffset) {
|
|
308
313
|
if (ranges.length === 0)
|
|
@@ -52,6 +52,7 @@ export class AppRenderController {
|
|
|
52
52
|
const defaultOverlayLines = menuLines.slice(0, Math.max(0, inputSeparatorRow - 1));
|
|
53
53
|
const underTabsOverlayStartRow = Math.min(rows, topReservedRows + 1);
|
|
54
54
|
const underTabsOverlayLines = menuLines.slice(0, Math.max(0, statusRow - underTabsOverlayStartRow));
|
|
55
|
+
const draftSurfaceLines = menuLines.slice(0, Math.max(0, bodyHeight));
|
|
55
56
|
const { lines: visible, metrics: scrollMetrics } = this.deps.scrollController.conversationView(columns, bodyHeight);
|
|
56
57
|
const conversationColumns = Math.max(1, Math.min(columns, scrollMetrics.viewportColumns));
|
|
57
58
|
this.deps.mouseController.syncConversationSelectionForRender(scrollMetrics.start, bodyHeight, topReservedRows, conversationColumns);
|
|
@@ -104,9 +105,27 @@ export class AppRenderController {
|
|
|
104
105
|
.filter((target) => target.kind === "new-tab")
|
|
105
106
|
.map((target) => ({ ...target, row: tabRow })));
|
|
106
107
|
}
|
|
108
|
+
const draftSurfaceMenu = popupMenuPlacement === "draft-surface"
|
|
109
|
+
? this.deps.popupMenus.getActivePopupMenu(activePopupMenu ?? this.deps.popupMenus.syncActivePopupMenu() ?? "slash")
|
|
110
|
+
: undefined;
|
|
107
111
|
for (let index = 0; index < bodyHeight; index += 1) {
|
|
108
|
-
const rendered = visible[index];
|
|
109
112
|
const row = toScreenRow(index + 1);
|
|
113
|
+
if (draftSurfaceMenu) {
|
|
114
|
+
const line = draftSurfaceLines[index];
|
|
115
|
+
if (line) {
|
|
116
|
+
const fallbackTarget = { kind: "popup-menu", index: draftSurfaceMenu.selectedIndex };
|
|
117
|
+
this.deps.mouseController.renderedTargets.set(row, line.target ?? fallbackTarget);
|
|
118
|
+
this.deps.mouseController.renderedRowTexts.set(row, this.deps.popupMenus.overlayPlainText(line, columns));
|
|
119
|
+
setRenderedBackground(row, line.backgroundOverride);
|
|
120
|
+
appendFrameOutput(row, this.renderFrameRow(row, this.deps.popupMenus.styleOverlayLine(row, line, columns)));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
this.deps.mouseController.renderedRowTexts.set(row, "");
|
|
124
|
+
appendFrameOutput(row, this.renderFrameRow(row, this.deps.screenStyler.styleBaseLine(row, undefined, columns)));
|
|
125
|
+
}
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const rendered = visible[index];
|
|
110
129
|
if (rendered?.target)
|
|
111
130
|
this.deps.mouseController.renderedTargets.set(row, rendered.target);
|
|
112
131
|
if (rendered?.imageTargets?.length)
|
|
@@ -117,7 +136,9 @@ export class AppRenderController {
|
|
|
117
136
|
setRenderedBackground(row, rendered?.backgroundOverride);
|
|
118
137
|
appendFrameOutput(row, this.renderFrameRow(row, this.deps.screenStyler.styleBaseLine(row, rendered, conversationColumns)));
|
|
119
138
|
}
|
|
120
|
-
const loadingConversationOverlay =
|
|
139
|
+
const loadingConversationOverlay = popupMenuPlacement === "draft-surface"
|
|
140
|
+
? undefined
|
|
141
|
+
: this.renderConversationLoadingOverlay(this.deps.loadingConversationOverlayText?.(), conversationColumns, topReservedRows, bodyHeight);
|
|
121
142
|
if (loadingConversationOverlay) {
|
|
122
143
|
this.deps.mouseController.renderedRowTexts.set(loadingConversationOverlay.row, loadingConversationOverlay.text);
|
|
123
144
|
appendFrameOutput(loadingConversationOverlay.row, this.renderFrameRow(loadingConversationOverlay.row, loadingConversationOverlay.output));
|
|
@@ -7,6 +7,10 @@ export type StatusLineRendererHost = {
|
|
|
7
7
|
readonly theme: Theme;
|
|
8
8
|
readonly screenStyler: ScreenStyler;
|
|
9
9
|
readonly session: AgentSession | undefined;
|
|
10
|
+
draftModelStatus?(): {
|
|
11
|
+
modelLabel: string;
|
|
12
|
+
thinkingLabel: string;
|
|
13
|
+
} | undefined;
|
|
10
14
|
readonly modelColors?: ModelColorsConfig;
|
|
11
15
|
readonly sessionActivity: SessionActivity;
|
|
12
16
|
readonly statusDotBright: boolean;
|
|
@@ -76,6 +80,7 @@ export declare class StatusLineRenderer {
|
|
|
76
80
|
private pushContextBarSegments;
|
|
77
81
|
private modelUsageProgressColor;
|
|
78
82
|
private modelProviderColor;
|
|
83
|
+
private modelRefColor;
|
|
79
84
|
private thinkingLevelColor;
|
|
80
85
|
private statusThinkingDisplayLabel;
|
|
81
86
|
private availableThinkingLevels;
|
|
@@ -180,8 +180,16 @@ export class StatusLineRenderer {
|
|
|
180
180
|
}
|
|
181
181
|
modelTarget(statusText, row) {
|
|
182
182
|
const session = this.host.session;
|
|
183
|
-
if (!session)
|
|
184
|
-
|
|
183
|
+
if (!session) {
|
|
184
|
+
const draft = this.host.draftModelStatus?.();
|
|
185
|
+
if (!draft)
|
|
186
|
+
return undefined;
|
|
187
|
+
const marker = `${draft.modelLabel} ${APP_ICONS.lightbulb} ${draft.thinkingLabel}`;
|
|
188
|
+
const startIndex = statusText.indexOf(marker);
|
|
189
|
+
if (startIndex < 0)
|
|
190
|
+
return undefined;
|
|
191
|
+
return { row, startColumn: startIndex + 1, endColumn: startIndex + draft.modelLabel.length + 1 };
|
|
192
|
+
}
|
|
185
193
|
const label = this.host.statusModelLabel(session);
|
|
186
194
|
const marker = `${label} ${this.statusThinkingDisplayLabel(session)} `;
|
|
187
195
|
const startIndex = statusText.indexOf(marker);
|
|
@@ -191,8 +199,17 @@ export class StatusLineRenderer {
|
|
|
191
199
|
}
|
|
192
200
|
thinkingTarget(statusText, row) {
|
|
193
201
|
const session = this.host.session;
|
|
194
|
-
if (!session)
|
|
195
|
-
|
|
202
|
+
if (!session) {
|
|
203
|
+
const draft = this.host.draftModelStatus?.();
|
|
204
|
+
if (!draft)
|
|
205
|
+
return undefined;
|
|
206
|
+
const marker = `${APP_ICONS.lightbulb} ${draft.thinkingLabel}`;
|
|
207
|
+
const markerIndex = statusText.indexOf(marker);
|
|
208
|
+
if (markerIndex < 0)
|
|
209
|
+
return undefined;
|
|
210
|
+
const startIndex = markerIndex + APP_ICONS.lightbulb.length + 1;
|
|
211
|
+
return { row, startColumn: startIndex + 1, endColumn: startIndex + draft.thinkingLabel.length + 1 };
|
|
212
|
+
}
|
|
196
213
|
const label = this.statusThinkingDisplayLabel(session);
|
|
197
214
|
const marker = ` ${label} ${this.host.formatContextUsagePercent(session)}`;
|
|
198
215
|
const markerIndex = statusText.indexOf(marker);
|
|
@@ -327,8 +344,17 @@ export class StatusLineRenderer {
|
|
|
327
344
|
if (layout.modelUsageLabel)
|
|
328
345
|
this.pushModelUsageSegments(segments, statusText, layout.modelUsageLabel);
|
|
329
346
|
const session = this.host.session;
|
|
330
|
-
if (!session)
|
|
347
|
+
if (!session) {
|
|
348
|
+
const draft = this.host.draftModelStatus?.();
|
|
349
|
+
if (!draft)
|
|
350
|
+
return segments;
|
|
351
|
+
const modelStart = statusText.indexOf(`${draft.modelLabel} ${APP_ICONS.lightbulb} ${draft.thinkingLabel}`);
|
|
352
|
+
this.pushSegment(segments, modelStart, draft.modelLabel.length, this.modelRefColor(draft.modelLabel));
|
|
353
|
+
const thinkingMarkerStart = statusText.indexOf(`${APP_ICONS.lightbulb} ${draft.thinkingLabel}`);
|
|
354
|
+
const thinkingStart = thinkingMarkerStart >= 0 ? thinkingMarkerStart + APP_ICONS.lightbulb.length + 1 : -1;
|
|
355
|
+
this.pushSegment(segments, thinkingStart, draft.thinkingLabel.length, this.thinkingLevelColor(draft.thinkingLabel));
|
|
331
356
|
return segments;
|
|
357
|
+
}
|
|
332
358
|
const modelLabel = this.host.statusModelLabel(session);
|
|
333
359
|
const thinkingLabel = this.host.statusThinkingLabel(session);
|
|
334
360
|
const thinkingDisplayLabel = this.statusThinkingDisplayLabel(session);
|
|
@@ -511,6 +537,16 @@ export class StatusLineRenderer {
|
|
|
511
537
|
? resolveColor(configuredColor, this.host.theme.colors)
|
|
512
538
|
: modelProviderThemeColor(provider, this.host.theme.colors);
|
|
513
539
|
}
|
|
540
|
+
modelRefColor(ref) {
|
|
541
|
+
const slash = ref.indexOf("/");
|
|
542
|
+
const provider = slash > 0 ? ref.slice(0, slash) : undefined;
|
|
543
|
+
if (!provider)
|
|
544
|
+
return this.host.theme.colors.selectionForeground;
|
|
545
|
+
const configuredColor = this.host.modelColors ? resolveModelColor(ref, this.host.modelColors) : undefined;
|
|
546
|
+
return configuredColor
|
|
547
|
+
? resolveColor(configuredColor, this.host.theme.colors)
|
|
548
|
+
: modelProviderThemeColor(provider, this.host.theme.colors);
|
|
549
|
+
}
|
|
514
550
|
thinkingLevelColor(label) {
|
|
515
551
|
return thinkingLevelThemeColor(label, this.host.theme.colors, this.availableThinkingLevels());
|
|
516
552
|
}
|
|
@@ -29,13 +29,15 @@ export class TabLineRenderer {
|
|
|
29
29
|
const newTabPrefix = tabs.length > 0 ? separator : EMPTY_NEW_TAB_PREFIX;
|
|
30
30
|
const newTabPrefixWidth = stringDisplayWidth(newTabPrefix);
|
|
31
31
|
const tabsWidth = Math.max(0, width - newTabWidth - newTabPrefixWidth);
|
|
32
|
-
const naturalButtons = tabs.map((tab) => this.buttonLayout(tab));
|
|
32
|
+
const naturalButtons = tabs.map((tab) => this.buttonLayout(tab, undefined, tabs.length > 1 || tab.draft !== true));
|
|
33
33
|
const naturalWidth = naturalButtons.reduce((sum, button) => sum + stringDisplayWidth(button.text), 0)
|
|
34
34
|
+ separatorCount * separatorWidth;
|
|
35
35
|
const buttonMaxWidth = naturalWidth <= tabsWidth
|
|
36
36
|
? undefined
|
|
37
37
|
: Math.max(7, Math.floor(Math.max(1, tabsWidth - separatorCount * separatorWidth) / tabs.length));
|
|
38
|
-
const buttons = buttonMaxWidth === undefined
|
|
38
|
+
const buttons = buttonMaxWidth === undefined
|
|
39
|
+
? naturalButtons
|
|
40
|
+
: tabs.map((tab) => this.buttonLayout(tab, buttonMaxWidth, tabs.length > 1 || tab.draft !== true));
|
|
39
41
|
const segments = [];
|
|
40
42
|
const targets = [];
|
|
41
43
|
const separatorColumns = [];
|
|
@@ -61,15 +63,17 @@ export class TabLineRenderer {
|
|
|
61
63
|
const buttonWidth = stringDisplayWidth(button.text);
|
|
62
64
|
text += button.text;
|
|
63
65
|
this.addButtonSegments(tab, button, textOffset, segments);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
if (button.closable) {
|
|
67
|
+
const closeColumnOffset = stringDisplayWidth(button.text.slice(0, button.closeStart));
|
|
68
|
+
// Keep the more specific close target before the tab target because the
|
|
69
|
+
// tab target intentionally spans the whole button, including the close icon.
|
|
70
|
+
targets.push({
|
|
71
|
+
kind: "close",
|
|
72
|
+
tabId: tab.id,
|
|
73
|
+
startColumn: displayColumn + closeColumnOffset,
|
|
74
|
+
endColumn: displayColumn + closeColumnOffset + stringDisplayWidth(button.text.slice(button.closeStart, button.closeEnd)),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
73
77
|
targets.push({
|
|
74
78
|
kind: "tab",
|
|
75
79
|
tabId: tab.id,
|
|
@@ -142,31 +146,33 @@ export class TabLineRenderer {
|
|
|
142
146
|
}
|
|
143
147
|
return chars.join("");
|
|
144
148
|
}
|
|
145
|
-
buttonLayout(tab, maxWidth) {
|
|
149
|
+
buttonLayout(tab, maxWidth, closable = true) {
|
|
146
150
|
const statusText = this.statusIndicatorIcon(tab);
|
|
147
151
|
const prefix = `${statusText} `;
|
|
148
|
-
const suffix = ` ${APP_ICONS.close}
|
|
152
|
+
const suffix = closable ? ` ${APP_ICONS.close}` : "";
|
|
149
153
|
const title = this.displayTitle(tab);
|
|
150
154
|
const naturalText = `${prefix}${title}${suffix}`;
|
|
151
155
|
const naturalWidth = stringDisplayWidth(naturalText);
|
|
152
156
|
if (maxWidth === undefined || naturalWidth <= maxWidth)
|
|
153
|
-
return this.buttonLayoutFromText(naturalText, 0, statusText.length);
|
|
157
|
+
return this.buttonLayoutFromText(naturalText, 0, statusText.length, closable);
|
|
154
158
|
const titleWidth = maxWidth - stringDisplayWidth(prefix) - stringDisplayWidth(suffix);
|
|
155
|
-
if (titleWidth <= 0)
|
|
156
|
-
return this.buttonLayoutFromText(ellipsizeDisplay(`${statusText}${APP_ICONS.close}`, maxWidth), 0, statusText.length);
|
|
157
|
-
|
|
159
|
+
if (titleWidth <= 0) {
|
|
160
|
+
return this.buttonLayoutFromText(ellipsizeDisplay(`${statusText}${closable ? APP_ICONS.close : ""}`, maxWidth), 0, statusText.length, closable);
|
|
161
|
+
}
|
|
162
|
+
return this.buttonLayoutFromText(`${prefix}${ellipsizeDisplay(title, titleWidth)}${suffix}`, 0, statusText.length, closable);
|
|
158
163
|
}
|
|
159
164
|
displayTitle(tab) {
|
|
160
165
|
return tab.isFork ? `${APP_ICONS.fork}${tab.title}` : tab.title;
|
|
161
166
|
}
|
|
162
|
-
buttonLayoutFromText(text, statusStart, statusLength) {
|
|
163
|
-
const closeStart = Math.max(0, text.lastIndexOf(APP_ICONS.close));
|
|
167
|
+
buttonLayoutFromText(text, statusStart, statusLength, closable) {
|
|
168
|
+
const closeStart = closable ? Math.max(0, text.lastIndexOf(APP_ICONS.close)) : text.length;
|
|
164
169
|
return {
|
|
165
170
|
text,
|
|
166
171
|
statusStart,
|
|
167
172
|
statusEnd: Math.min(text.length, statusStart + statusLength),
|
|
168
173
|
closeStart,
|
|
169
|
-
closeEnd: closeStart + APP_ICONS.close.length,
|
|
174
|
+
closeEnd: closable ? closeStart + APP_ICONS.close.length : closeStart,
|
|
175
|
+
closable,
|
|
170
176
|
};
|
|
171
177
|
}
|
|
172
178
|
addButtonSegments(tab, button, textOffset, segments) {
|
package/dist/app/runtime.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SessionManager, type EventBus, type AgentSessionRuntime, type AgentSessionServices, type LoadExtensionsResult, type SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { type PixConfig } from "../config.js";
|
|
3
|
-
import type { AppOptions, ThinkingLevel } from "./types.js";
|
|
3
|
+
import type { AppOptions, SessionModel, ThinkingLevel } from "./types.js";
|
|
4
4
|
export type PiToolsSuiteInstallAction = "installed" | "already-installed" | "existing-kept" | "missing-source";
|
|
5
5
|
export type PiToolsSuiteInstallResult = {
|
|
6
6
|
action: PiToolsSuiteInstallAction;
|
|
@@ -28,6 +28,7 @@ export type BundledSkillsInstallOptions = {
|
|
|
28
28
|
export declare function bundledQuestionExtensionPath(): string;
|
|
29
29
|
export declare function bundledSessionTitleExtensionPath(): string;
|
|
30
30
|
export declare function bundledTerminalBellExtensionPath(): string;
|
|
31
|
+
export declare function bundledTelegramConnectorExtensionPath(): string;
|
|
31
32
|
export declare function piToolsSuiteExtensionSourcePath(): string;
|
|
32
33
|
export declare function piToolsSuiteExtensionInstallPath(agentDir?: string): string;
|
|
33
34
|
export declare function bundledSkillsSourcePath(): string;
|
|
@@ -44,8 +45,18 @@ export type CreatePixRuntimeOptions = {
|
|
|
44
45
|
};
|
|
45
46
|
type RuntimeSessionManagerModelState = Pick<SessionManager, "getEntries" | "getBranch">;
|
|
46
47
|
export declare function resolvePixRuntimeModelRef(options: Pick<AppOptions, "modelRef">, sessionManager: RuntimeSessionManagerModelState, config?: PixConfig): string | undefined;
|
|
48
|
+
export declare function resolvePixRuntimeModelRefs(options: Pick<AppOptions, "modelRef">, sessionManager: RuntimeSessionManagerModelState, config?: PixConfig): string[];
|
|
47
49
|
export declare function resolvePixRuntimeInitialThinkingLevel(options: Pick<AppOptions, "modelRef">, sessionManager: RuntimeSessionManagerModelState, config: PixConfig): ThinkingLevel | undefined;
|
|
48
50
|
export declare function resolveSessionModelRefFromTail(entries: readonly SessionEntry[]): string | undefined;
|
|
49
51
|
export declare function refreshPixModelRuntimeForStartup(modelRuntime: Pick<AgentSessionServices["modelRuntime"], "refresh">): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Build the model catalogue used by UI-only draft tabs without allocating an
|
|
54
|
+
* AgentSession or session file. Drafts can therefore expose model selection
|
|
55
|
+
* while preserving lazy session materialization until the first prompt.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createPixDraftModelCatalog(options: {
|
|
58
|
+
cwd: string;
|
|
59
|
+
agentDir?: string;
|
|
60
|
+
}): Promise<SessionModel[]>;
|
|
50
61
|
export declare function createPixRuntime(options: AppOptions, runtimeOptions?: CreatePixRuntimeOptions): Promise<AgentSessionRuntime>;
|
|
51
62
|
export {};
|
package/dist/app/runtime.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { access, cp, lstat, mkdir, readdir, readlink, realpath, rm, symlink } from "node:fs/promises";
|
|
2
|
+
import { access, cp, lstat, mkdir, readFile, readdir, readlink, realpath, rm, symlink } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, SessionManager, } from "@earendil-works/pi-coding-agent";
|
|
6
|
+
import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, ModelRuntime, SessionManager, } from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import { loadPixConfig, resolveDefaultModelRef } from "../config.js";
|
|
8
8
|
import { isThinkingLevel, parseModelRef, parseScopedModelRef } from "./model/model-ref.js";
|
|
9
9
|
import { openLazySessionManager } from "./session/lazy-session-manager.js";
|
|
@@ -13,6 +13,7 @@ const BUNDLED_EXTENSIONS_DIR = resolve(dirname(fileURLToPath(import.meta.url)),
|
|
|
13
13
|
const BUNDLED_QUESTION_EXTENSION_DIR = resolve(BUNDLED_EXTENSIONS_DIR, BUNDLED_QUESTION_EXTENSION_NAME);
|
|
14
14
|
const BUNDLED_SESSION_TITLE_EXTENSION_DIR = resolve(BUNDLED_EXTENSIONS_DIR, "session-title");
|
|
15
15
|
const BUNDLED_TERMINAL_BELL_EXTENSION_DIR = resolve(BUNDLED_EXTENSIONS_DIR, "terminal-bell");
|
|
16
|
+
const BUNDLED_TELEGRAM_CONNECTOR_EXTENSION_DIR = resolve(BUNDLED_EXTENSIONS_DIR, "telegram-connector");
|
|
16
17
|
const PI_TOOLS_SUITE_SOURCE_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "../..", "external", PI_TOOLS_SUITE_EXTENSION_NAME);
|
|
17
18
|
const BUNDLED_SKILLS_SOURCE_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "../..", "skills");
|
|
18
19
|
export function bundledQuestionExtensionPath() {
|
|
@@ -24,6 +25,9 @@ export function bundledSessionTitleExtensionPath() {
|
|
|
24
25
|
export function bundledTerminalBellExtensionPath() {
|
|
25
26
|
return BUNDLED_TERMINAL_BELL_EXTENSION_DIR;
|
|
26
27
|
}
|
|
28
|
+
export function bundledTelegramConnectorExtensionPath() {
|
|
29
|
+
return BUNDLED_TELEGRAM_CONNECTOR_EXTENSION_DIR;
|
|
30
|
+
}
|
|
27
31
|
export function piToolsSuiteExtensionSourcePath() {
|
|
28
32
|
return PI_TOOLS_SUITE_SOURCE_DIR;
|
|
29
33
|
}
|
|
@@ -60,8 +64,22 @@ export async function ensurePiToolsSuiteExtensionInstalled(options = {}) {
|
|
|
60
64
|
if (await pathsReferToSameEntry(targetPath, sourcePath)) {
|
|
61
65
|
return { action: "already-installed", sourcePath, targetPath };
|
|
62
66
|
}
|
|
67
|
+
if (targetStat.isDirectory() && await isLegacyManagedPiToolsSuite(targetPath)) {
|
|
68
|
+
await rm(targetPath, { recursive: true, force: true });
|
|
69
|
+
await symlink(sourcePath, targetPath, extensionSymlinkType());
|
|
70
|
+
return { action: "installed", sourcePath, targetPath };
|
|
71
|
+
}
|
|
63
72
|
return { action: "existing-kept", sourcePath, targetPath };
|
|
64
73
|
}
|
|
74
|
+
async function isLegacyManagedPiToolsSuite(targetPath) {
|
|
75
|
+
try {
|
|
76
|
+
const packageJson = JSON.parse(await readFile(join(targetPath, "package.json"), "utf8"));
|
|
77
|
+
return packageJson.name === "pi-tools-suite-local";
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
65
83
|
export async function ensureBundledSkillsInstalled(options = {}) {
|
|
66
84
|
const sourcePath = resolve(options.sourcePath ?? bundledSkillsSourcePath());
|
|
67
85
|
const targetPath = resolve(options.targetPath ?? bundledSkillsInstallPath(options.homeDir));
|
|
@@ -98,6 +116,7 @@ export function getBundledExtensionPaths() {
|
|
|
98
116
|
bundledQuestionExtensionPath(),
|
|
99
117
|
bundledSessionTitleExtensionPath(),
|
|
100
118
|
bundledTerminalBellExtensionPath(),
|
|
119
|
+
bundledTelegramConnectorExtensionPath(),
|
|
101
120
|
].filter(extensionEntryExists);
|
|
102
121
|
}
|
|
103
122
|
export async function getBundledExtensionPathsAsync() {
|
|
@@ -105,6 +124,7 @@ export async function getBundledExtensionPathsAsync() {
|
|
|
105
124
|
bundledQuestionExtensionPath(),
|
|
106
125
|
bundledSessionTitleExtensionPath(),
|
|
107
126
|
bundledTerminalBellExtensionPath(),
|
|
127
|
+
bundledTelegramConnectorExtensionPath(),
|
|
108
128
|
].map(async (extensionPath) => await extensionEntryExistsAsync(extensionPath) ? extensionPath : undefined));
|
|
109
129
|
return paths.filter((path) => path !== undefined);
|
|
110
130
|
}
|
|
@@ -199,12 +219,32 @@ async function ensurePiToolsSuiteExtensionInstalledOnce(options = {}) {
|
|
|
199
219
|
return await pending;
|
|
200
220
|
}
|
|
201
221
|
export function resolvePixRuntimeModelRef(options, sessionManager, config = loadPixConfig()) {
|
|
222
|
+
return resolvePixRuntimeModelRefs(options, sessionManager, config)[0];
|
|
223
|
+
}
|
|
224
|
+
export function resolvePixRuntimeModelRefs(options, sessionManager, config = loadPixConfig()) {
|
|
202
225
|
if (options.modelRef)
|
|
203
|
-
return options.modelRef;
|
|
226
|
+
return [options.modelRef];
|
|
204
227
|
const existingEntryCount = sessionManager.getEntries().length;
|
|
205
|
-
if (existingEntryCount > 0)
|
|
206
|
-
|
|
207
|
-
|
|
228
|
+
if (existingEntryCount > 0) {
|
|
229
|
+
const sessionRef = resolveSessionModelRefFromTail(sessionManager.getBranch());
|
|
230
|
+
return sessionRef ? [sessionRef] : [];
|
|
231
|
+
}
|
|
232
|
+
const primary = resolveDefaultModelRef(config);
|
|
233
|
+
if (!primary)
|
|
234
|
+
return [];
|
|
235
|
+
const defaultThinking = config.defaultModel?.thinking;
|
|
236
|
+
const fallbacks = (config.defaultModel?.fallbackModels ?? []).map((modelRef) => {
|
|
237
|
+
const trimmed = modelRef.trim();
|
|
238
|
+
if (!trimmed || !defaultThinking)
|
|
239
|
+
return trimmed;
|
|
240
|
+
try {
|
|
241
|
+
return parseModelRef(trimmed).thinkingLevel === undefined ? `${trimmed}:${defaultThinking}` : trimmed;
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return trimmed;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
return [...new Set([primary, ...fallbacks].map((ref) => ref.trim()).filter(Boolean))];
|
|
208
248
|
}
|
|
209
249
|
export function resolvePixRuntimeInitialThinkingLevel(options, sessionManager, config) {
|
|
210
250
|
const effectiveModelRef = resolvePixRuntimeModelRef(options, sessionManager, config);
|
|
@@ -239,14 +279,52 @@ export async function refreshPixModelRuntimeForStartup(modelRuntime) {
|
|
|
239
279
|
// refreshes belong to explicit model-management flows and must not block boot.
|
|
240
280
|
await modelRuntime.refresh({ allowNetwork: false });
|
|
241
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Build the model catalogue used by UI-only draft tabs without allocating an
|
|
284
|
+
* AgentSession or session file. Drafts can therefore expose model selection
|
|
285
|
+
* while preserving lazy session materialization until the first prompt.
|
|
286
|
+
*/
|
|
287
|
+
export async function createPixDraftModelCatalog(options) {
|
|
288
|
+
const agentDir = options.agentDir ?? getAgentDir();
|
|
289
|
+
await ensurePiToolsSuiteExtensionInstalledOnce({ agentDir });
|
|
290
|
+
const bundledExtensionPaths = await getBundledExtensionPathsAsync();
|
|
291
|
+
const modelRuntime = await ModelRuntime.create({
|
|
292
|
+
authPath: join(agentDir, "auth.json"),
|
|
293
|
+
modelsPath: join(agentDir, "models.json"),
|
|
294
|
+
allowModelNetwork: false,
|
|
295
|
+
refreshOnCreate: false,
|
|
296
|
+
});
|
|
297
|
+
const services = await createAgentSessionServices({
|
|
298
|
+
cwd: options.cwd,
|
|
299
|
+
agentDir,
|
|
300
|
+
modelRuntime,
|
|
301
|
+
resourceLoaderOptions: {
|
|
302
|
+
noContextFiles: true,
|
|
303
|
+
noSkills: true,
|
|
304
|
+
noPromptTemplates: true,
|
|
305
|
+
noThemes: true,
|
|
306
|
+
...(bundledExtensionPaths.length === 0 ? {} : {
|
|
307
|
+
additionalExtensionPaths: bundledExtensionPaths,
|
|
308
|
+
extensionsOverride: prioritizeBundledQuestionExtension,
|
|
309
|
+
}),
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
try {
|
|
313
|
+
return [...services.modelRuntime.getAvailableSnapshot()];
|
|
314
|
+
}
|
|
315
|
+
finally {
|
|
316
|
+
// Draft discovery needs extension provider registrations, but it does not
|
|
317
|
+
// own a session. Invalidate the temporary extension runtime so event-bus
|
|
318
|
+
// subscriptions and captured ctx/pi handles cannot outlive discovery.
|
|
319
|
+
services.resourceLoader.getExtensions().runtime.invalidate("Draft model catalog discovery completed");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
242
322
|
export async function createPixRuntime(options, runtimeOptions = {}) {
|
|
243
323
|
const agentDir = getAgentDir();
|
|
244
324
|
const reusableServices = reusableRuntimeServices(runtimeOptions.reuseServicesFrom, options.cwd, agentDir);
|
|
245
325
|
const createRuntime = async ({ cwd, sessionManager, sessionStartEvent }) => {
|
|
246
326
|
const config = runtimeOptions.config ?? loadPixConfig(cwd);
|
|
247
|
-
const
|
|
248
|
-
const parsedModel = effectiveModelRef ? parseModelRef(effectiveModelRef) : undefined;
|
|
249
|
-
const initialThinkingLevel = resolvePixRuntimeInitialThinkingLevel(options, sessionManager, config);
|
|
327
|
+
const modelRefs = resolvePixRuntimeModelRefs(options, sessionManager, config);
|
|
250
328
|
// Only reuse services for the initial session. Session replacements
|
|
251
329
|
// (switchSession/newSession/fork) must get fresh services so extensions
|
|
252
330
|
// are re-loaded with a fresh pi — otherwise handlers capture the old,
|
|
@@ -261,10 +339,36 @@ export async function createPixRuntime(options, runtimeOptions = {}) {
|
|
|
261
339
|
...(runtimeOptions.eventBus === undefined ? {} : { eventBus: runtimeOptions.eventBus }),
|
|
262
340
|
});
|
|
263
341
|
await refreshPixModelRuntimeForStartup(services.modelRuntime);
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
342
|
+
let model;
|
|
343
|
+
let selectedRef;
|
|
344
|
+
let selectedThinkingLevel;
|
|
345
|
+
let primaryError;
|
|
346
|
+
for (let index = 0; index < modelRefs.length; index++) {
|
|
347
|
+
const modelRef = modelRefs[index];
|
|
348
|
+
let parsedModel;
|
|
349
|
+
try {
|
|
350
|
+
parsedModel = parseModelRef(modelRef);
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
if (index === 0)
|
|
354
|
+
throw error;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
const candidate = services.modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
|
|
358
|
+
if (!candidate) {
|
|
359
|
+
if (index === 0)
|
|
360
|
+
primaryError = new Error(`Model not found: ${parsedModel.provider}/${parsedModel.modelId}`);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
model = candidate;
|
|
364
|
+
selectedRef = modelRef;
|
|
365
|
+
selectedThinkingLevel = parsedModel.thinkingLevel;
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
if (modelRefs.length > 0 && !model) {
|
|
369
|
+
throw primaryError ?? new Error(`No configured model is available: ${modelRefs.join(", ")}`);
|
|
267
370
|
}
|
|
371
|
+
const initialThinkingLevel = selectedThinkingLevel;
|
|
268
372
|
const enabledModelRefs = services.settingsManager.getEnabledModels();
|
|
269
373
|
const scopedModels = (enabledModelRefs ?? []).flatMap((modelRef) => {
|
|
270
374
|
const scoped = parseScopedModelRef(modelRef);
|
|
@@ -288,9 +392,13 @@ export async function createPixRuntime(options, runtimeOptions = {}) {
|
|
|
288
392
|
...(initialThinkingLevel === undefined ? {} : { thinkingLevel: initialThinkingLevel }),
|
|
289
393
|
...(scopedModels.length === 0 ? {} : { scopedModels }),
|
|
290
394
|
});
|
|
395
|
+
const modelFallbackMessage = selectedRef && selectedRef !== modelRefs[0]
|
|
396
|
+
? `Default model ${modelRefs[0]} is unavailable; using fallback ${selectedRef}.`
|
|
397
|
+
: undefined;
|
|
291
398
|
return {
|
|
292
399
|
...created,
|
|
293
400
|
services,
|
|
401
|
+
...(modelFallbackMessage ? { modelFallbackMessage } : {}),
|
|
294
402
|
// Snapshot diagnostics per-runtime. When services are reused across
|
|
295
403
|
// tabs (reuseServicesFrom), services.diagnostics is a shared array —
|
|
296
404
|
// giving each runtime its own copy prevents one tab's creation
|