@linxiraos/pi-tui 1.2.1 → 1.3.1
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/CHANGELOG.md +245 -224
- package/README.md +36 -0
- package/THIRD-PARTY-NOTICES.txt +55 -5
- package/dist/types/app-keybindings.d.ts +18 -8
- package/dist/types/apps/git/diff-pane.d.ts +5 -0
- package/dist/types/apps/git/git-tui.d.ts +16 -2
- package/dist/types/apps/git/state.d.ts +11 -0
- package/dist/types/autocomplete.d.ts +2 -0
- package/dist/types/charts/chart-svg.d.ts +7 -13
- package/dist/types/chat/advisor-message.d.ts +4 -1
- package/dist/types/chat/assistant-message.d.ts +9 -4
- package/dist/types/chat/figure-markdown.d.ts +7 -2
- package/dist/types/chat/messages.d.ts +3 -1
- package/dist/types/chat/read-tool-group.d.ts +2 -2
- package/dist/types/chat/table-chart.d.ts +11 -15
- package/dist/types/chat/tool-execution.d.ts +32 -20
- package/dist/types/chat/user-message.d.ts +3 -2
- package/dist/types/chrome/countdown-timer.d.ts +3 -2
- package/dist/types/chrome/diff.d.ts +2 -3
- package/dist/types/chrome/status-notice.d.ts +2 -0
- package/dist/types/chrome/transcript-container.d.ts +2 -0
- package/dist/types/components/image.d.ts +2 -0
- package/dist/types/components/markdown.d.ts +49 -3
- package/dist/types/components/text.d.ts +2 -0
- package/dist/types/debug-server.d.ts +2 -0
- package/dist/types/keybinding-matchers.d.ts +6 -0
- package/dist/types/multiplexers/tmux.d.ts +1 -0
- package/dist/types/multiplexers/types.d.ts +6 -0
- package/dist/types/native/backend.d.ts +5 -4
- package/dist/types/native/blobs.d.ts +24 -12
- package/dist/types/overlays/agent-hub-projection.d.ts +10 -5
- package/dist/types/overlays/annotation-overlay.d.ts +19 -0
- package/dist/types/overlays/approval-dialog.d.ts +79 -0
- package/dist/types/overlays/ask-dialog.d.ts +11 -6
- package/dist/types/overlays/btw-history-panel.d.ts +2 -6
- package/dist/types/overlays/hook-editor.d.ts +7 -2
- package/dist/types/overlays/hook-input.d.ts +12 -4
- package/dist/types/overlays/job-tree.d.ts +50 -0
- package/dist/types/overlays/jobs-panel.d.ts +25 -11
- package/dist/types/overlays/login-dialog.d.ts +8 -3
- package/dist/types/overlays/mcp-add-wizard.d.ts +9 -1
- package/dist/types/overlays/model-browser.d.ts +6 -1
- package/dist/types/overlays/model-picker.d.ts +2 -0
- package/dist/types/overlays/pause-screen.d.ts +5 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +4 -0
- package/dist/types/overlays/report-panel.d.ts +5 -1
- package/dist/types/overlays/reset-usage-selector.d.ts +7 -5
- package/dist/types/overlays/session-account-selector.d.ts +4 -0
- package/dist/types/overlays/session-info-overlay.d.ts +7 -3
- package/dist/types/overlays/session-selector.d.ts +3 -1
- package/dist/types/overlays/usage-dashboard.d.ts +6 -6
- package/dist/types/prompt/composer.d.ts +23 -20
- package/dist/types/prompt/custom-editor.d.ts +20 -10
- package/dist/types/prompt/image-references.d.ts +22 -0
- package/dist/types/prompt/internal-url-autocomplete.d.ts +1 -0
- package/dist/types/prompt/macos-spelling.d.ts +2 -1
- package/dist/types/prompt/prose-gate.d.ts +3 -0
- package/dist/types/prompt/queued-messages.d.ts +1 -1
- package/dist/types/prompt/typing-word.d.ts +25 -0
- package/dist/types/prompt/welcome.d.ts +26 -6
- package/dist/types/render/hanging-wrap.d.ts +7 -0
- package/dist/types/render/hyperlink.d.ts +2 -0
- package/dist/types/render/render-utils.d.ts +9 -1
- package/dist/types/render/utils.d.ts +1 -1
- package/dist/types/setup/scenes/splash.d.ts +6 -5
- package/dist/types/status-line/context-usage.d.ts +4 -1
- package/dist/types/status-line/host.d.ts +6 -4
- package/dist/types/status-line/startup.d.ts +6 -6
- package/dist/types/status-line/types.d.ts +3 -0
- package/dist/types/stdin-buffer.d.ts +7 -0
- package/dist/types/terminal-capabilities.d.ts +16 -1
- package/dist/types/terminal-multiplexer.d.ts +7 -0
- package/dist/types/terminal.d.ts +8 -4
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme.d.ts +11 -0
- package/dist/types/thinking.d.ts +5 -0
- package/dist/types/tmux.d.ts +39 -4
- package/dist/types/tools/ast-edit.d.ts +2 -2
- package/dist/types/tools/ast-grep.d.ts +2 -2
- package/dist/types/tools/bash.d.ts +6 -1
- package/dist/types/tools/edit.d.ts +2 -0
- package/dist/types/tools/eval.d.ts +53 -4
- package/dist/types/tools/find.d.ts +14 -4
- package/dist/types/tools/glob.d.ts +3 -3
- package/dist/types/tools/grep.d.ts +2 -2
- package/dist/types/tools/grouped-file-output.d.ts +9 -4
- package/dist/types/tools/native-view.d.ts +1 -1
- package/dist/types/tools/read.d.ts +32 -10
- package/dist/types/tools/renderer.d.ts +2 -0
- package/dist/types/tools/task.d.ts +31 -0
- package/dist/types/tools/web-search-types.d.ts +1 -0
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/tui.d.ts +20 -3
- package/package.json +10 -10
- package/src/app-keybindings.d.ts +18 -8
- package/src/app-keybindings.ts +20 -8
- package/src/apps/autoresearch-dashboard.ts +444 -27
- package/src/apps/debug/raw-sse.ts +2 -2
- package/src/apps/git/diff-pane.ts +39 -41
- package/src/apps/git/git-tui.ts +80 -14
- package/src/apps/git/sidebar.ts +10 -1
- package/src/apps/git/state.ts +12 -0
- package/src/autocomplete.d.ts +2 -0
- package/src/autocomplete.ts +21 -19
- package/src/bracketed-paste.ts +9 -2
- package/src/charts/chart-svg.d.ts +7 -13
- package/src/charts/chart-svg.ts +19 -22
- package/src/charts/table-data.ts +17 -6
- package/src/chat/advisor-message.d.ts +4 -1
- package/src/chat/advisor-message.ts +77 -24
- package/src/chat/assistant-message.d.ts +9 -4
- package/src/chat/assistant-message.ts +127 -31
- package/src/chat/bash-execution.ts +7 -2
- package/src/chat/figure-markdown.d.ts +7 -2
- package/src/chat/figure-markdown.ts +10 -3
- package/src/chat/image-loading.ts +9 -6
- package/src/chat/messages.d.ts +3 -1
- package/src/chat/messages.ts +4 -1
- package/src/chat/read-tool-group.d.ts +2 -2
- package/src/chat/read-tool-group.ts +97 -42
- package/src/chat/svg-figure.ts +3 -1
- package/src/chat/svg-source.ts +6 -3
- package/src/chat/table-chart.d.ts +11 -15
- package/src/chat/table-chart.ts +24 -57
- package/src/chat/tool-execution.d.ts +32 -20
- package/src/chat/tool-execution.ts +103 -36
- package/src/chat/user-message.d.ts +3 -2
- package/src/chat/user-message.ts +54 -34
- package/src/chrome/countdown-timer.ts +3 -3
- package/src/chrome/diff.d.ts +2 -3
- package/src/chrome/diff.ts +4 -9
- package/src/chrome/status-notice.ts +5 -0
- package/src/chrome/transcript-container.d.ts +2 -0
- package/src/chrome/transcript-container.ts +212 -28
- package/src/components/editor.ts +12 -12
- package/src/components/image.d.ts +2 -0
- package/src/components/image.ts +54 -20
- package/src/components/markdown.d.ts +49 -3
- package/src/components/markdown.ts +482 -12
- package/src/components/settings-list.ts +2 -4
- package/src/components/text.d.ts +2 -0
- package/src/components/text.ts +11 -1
- package/src/debug-server.d.ts +2 -0
- package/src/debug-server.ts +51 -69
- package/src/hotkeys-markdown.ts +2 -0
- package/src/keybinding-matchers.d.ts +6 -0
- package/src/keybinding-matchers.ts +19 -0
- package/src/multiplexers/tmux.d.ts +1 -0
- package/src/multiplexers/tmux.ts +3 -0
- package/src/multiplexers/types.d.ts +6 -0
- package/src/multiplexers/types.ts +6 -0
- package/src/native/backend.d.ts +5 -4
- package/src/native/backend.ts +13 -5
- package/src/native/blobs.d.ts +24 -12
- package/src/native/blobs.ts +56 -7
- package/src/native/reconcile.ts +43 -21
- package/src/overlays/advisor-config.ts +259 -8
- package/src/overlays/agent-hub-projection.d.ts +10 -5
- package/src/overlays/agent-hub-projection.ts +63 -12
- package/src/overlays/annotation-overlay.ts +422 -168
- package/src/overlays/approval-dialog.ts +389 -0
- package/src/overlays/ask-dialog.ts +244 -105
- package/src/overlays/btw-history-panel.ts +208 -147
- package/src/overlays/extensions/extension-list.ts +4 -6
- package/src/overlays/hook-editor.ts +90 -32
- package/src/overlays/hook-input.ts +105 -19
- package/src/overlays/job-tree.ts +177 -0
- package/src/overlays/jobs-panel.ts +222 -142
- package/src/overlays/login-dialog.ts +201 -91
- package/src/overlays/mcp-add-wizard.ts +562 -279
- package/src/overlays/model-browser.ts +32 -7
- package/src/overlays/model-hub.ts +4 -10
- package/src/overlays/model-picker.ts +58 -21
- package/src/overlays/pause-screen.ts +81 -23
- package/src/overlays/plan-review-overlay.ts +16 -0
- package/src/overlays/plugin-selector.ts +17 -1
- package/src/overlays/queue-mode-selector.ts +10 -0
- package/src/overlays/report-panel.ts +6 -2
- package/src/overlays/reset-usage-selector.ts +130 -21
- package/src/overlays/session-account-selector.ts +36 -0
- package/src/overlays/session-info-overlay.ts +199 -76
- package/src/overlays/session-selector.ts +15 -10
- package/src/overlays/settings-selector.ts +3 -0
- package/src/overlays/show-images-selector.ts +1 -0
- package/src/overlays/snapcompact-shape-preview.ts +13 -6
- package/src/overlays/theme-selector.ts +6 -1
- package/src/overlays/thinking-selector.ts +8 -4
- package/src/overlays/tree-selector.ts +117 -2
- package/src/overlays/usage-dashboard.ts +498 -144
- package/src/prompt/composer-cache.ts +4 -1
- package/src/prompt/composer.ts +200 -74
- package/src/prompt/custom-editor.ts +168 -65
- package/src/prompt/image-references.d.ts +22 -0
- package/src/prompt/image-references.ts +79 -2
- package/src/prompt/internal-url-autocomplete.ts +1 -0
- package/src/prompt/macos-spelling.ts +28 -5
- package/src/prompt/prose-gate.ts +3 -0
- package/src/prompt/queued-messages.ts +9 -2
- package/src/prompt/tips.txt +1 -2
- package/src/prompt/typing-word.ts +59 -0
- package/src/prompt/welcome.ts +97 -45
- package/src/render/code-cell.ts +18 -5
- package/src/render/hanging-wrap.d.ts +7 -0
- package/src/render/hanging-wrap.ts +58 -0
- package/src/render/hyperlink.d.ts +2 -0
- package/src/render/hyperlink.ts +5 -0
- package/src/render/render-utils.d.ts +9 -1
- package/src/render/render-utils.ts +16 -2
- package/src/render/utils.d.ts +1 -1
- package/src/render/utils.ts +1 -1
- package/src/render/width-aware-text.ts +6 -5
- package/src/setup/scenes/splash.ts +22 -8
- package/src/status-line/component.ts +79 -11
- package/src/status-line/context-usage.ts +176 -73
- package/src/status-line/footer.ts +18 -35
- package/src/status-line/host.ts +6 -1
- package/src/status-line/segments.ts +16 -5
- package/src/status-line/startup.ts +6 -6
- package/src/status-line/types.ts +1 -0
- package/src/stdin-buffer.d.ts +7 -0
- package/src/stdin-buffer.ts +300 -62
- package/src/terminal-capabilities.d.ts +16 -1
- package/src/terminal-capabilities.ts +66 -28
- package/src/terminal-multiplexer.d.ts +7 -0
- package/src/terminal-multiplexer.ts +14 -0
- package/src/terminal.d.ts +8 -4
- package/src/terminal.ts +190 -63
- package/src/theme/symbols.d.ts +1 -1
- package/src/theme/symbols.ts +1 -0
- package/src/theme/theme-class.ts +1 -0
- package/src/theme/theme.d.ts +11 -0
- package/src/theme/theme.ts +46 -14
- package/src/thinking.d.ts +5 -0
- package/src/thinking.ts +9 -1
- package/src/tmux.d.ts +39 -4
- package/src/tmux.ts +110 -16
- package/src/tools/ask.ts +20 -9
- package/src/tools/ast-edit.d.ts +2 -2
- package/src/tools/ast-edit.ts +30 -7
- package/src/tools/ast-grep.d.ts +2 -2
- package/src/tools/ast-grep.ts +39 -35
- package/src/tools/bash.d.ts +6 -1
- package/src/tools/bash.ts +15 -9
- package/src/tools/debug.ts +2 -1
- package/src/tools/default-renderer.ts +3 -2
- package/src/tools/edit.d.ts +2 -0
- package/src/tools/edit.ts +100 -21
- package/src/tools/eval.d.ts +53 -4
- package/src/tools/eval.ts +173 -137
- package/src/tools/find.d.ts +14 -4
- package/src/tools/find.ts +71 -18
- package/src/tools/glob.d.ts +3 -3
- package/src/tools/glob.ts +51 -17
- package/src/tools/grep.d.ts +2 -2
- package/src/tools/grep.ts +99 -22
- package/src/tools/grouped-file-output.d.ts +9 -4
- package/src/tools/grouped-file-output.ts +21 -6
- package/src/tools/lsp.ts +30 -18
- package/src/tools/mcp.ts +2 -2
- package/src/tools/native-view.d.ts +1 -1
- package/src/tools/native-view.ts +2 -2
- package/src/tools/read.d.ts +32 -10
- package/src/tools/read.ts +89 -43
- package/src/tools/renderer.d.ts +2 -0
- package/src/tools/renderer.ts +2 -0
- package/src/tools/task.d.ts +31 -0
- package/src/tools/task.ts +40 -7
- package/src/tools/todo.ts +3 -2
- package/src/tools/wait.ts +16 -30
- package/src/tools/web-search-types.d.ts +1 -0
- package/src/tools/web-search-types.ts +1 -0
- package/src/tools/web-search.ts +2 -1
- package/src/tools/write.d.ts +2 -0
- package/src/tools/write.ts +36 -12
- package/src/tools/yield.ts +2 -2
- package/src/tui.d.ts +20 -3
- package/src/tui.ts +160 -43
- package/src/utils.ts +5 -3
- package/dist/types/tools/eval-format/code-mode-declarations.d.ts +0 -5
- package/src/tools/eval-format/code-mode-declarations.ts +0 -61
|
@@ -1338,6 +1338,8 @@ export interface SessionSelectorOptions<T extends SessionSelectorEntry = Session
|
|
|
1338
1338
|
allSessions?: T[];
|
|
1339
1339
|
/** Picker heading; defaults to "Resume Session". */
|
|
1340
1340
|
title?: string;
|
|
1341
|
+
/** Primary action label; defaults to "Resume" (ANSI footer defaults to "select"). */
|
|
1342
|
+
actionLabel?: string;
|
|
1341
1343
|
/** Fixed scope label, or false to omit the scope suffix. */
|
|
1342
1344
|
scopeLabel?: string | false;
|
|
1343
1345
|
/**
|
|
@@ -1363,7 +1365,7 @@ export interface SessionSelectorOptions<T extends SessionSelectorEntry = Session
|
|
|
1363
1365
|
/** Path of the live session, or a getter so detach/newSession stays accurate. */
|
|
1364
1366
|
currentSessionPath?: string | (() => string | undefined);
|
|
1365
1367
|
/**
|
|
1366
|
-
* The picker is the whole program (`
|
|
1368
|
+
* The picker is the whole program (`zetacode --resume`): the native picker
|
|
1367
1369
|
* fills the screen surface (`size:"screen"`) instead of floating as a
|
|
1368
1370
|
* sheet over the transcript.
|
|
1369
1371
|
*/
|
|
@@ -1405,6 +1407,7 @@ export class SessionSelectorComponent<T extends SessionSelectorEntry = SessionSe
|
|
|
1405
1407
|
readonly #getTerminalRows: () => number;
|
|
1406
1408
|
readonly #fillHeight: boolean;
|
|
1407
1409
|
readonly #title: string;
|
|
1410
|
+
readonly #actionLabel: string;
|
|
1408
1411
|
readonly #scopeLabel: string | false | undefined;
|
|
1409
1412
|
/** What `#messageContainer` shows, for the native description. */
|
|
1410
1413
|
#message: SessionPickerMessage | undefined;
|
|
@@ -1462,6 +1465,7 @@ export class SessionSelectorComponent<T extends SessionSelectorEntry = SessionSe
|
|
|
1462
1465
|
this.#getTerminalRows = options.getTerminalRows ?? (() => 24);
|
|
1463
1466
|
this.#fillHeight = options.fillHeight ?? false;
|
|
1464
1467
|
this.#title = options.title ?? "Resume Session";
|
|
1468
|
+
this.#actionLabel = options.actionLabel ?? "Resume";
|
|
1465
1469
|
this.#pickerTitle = options.title;
|
|
1466
1470
|
this.#standalone = options.standalone ?? false;
|
|
1467
1471
|
this.#scopeLabel = options.scopeLabel;
|
|
@@ -1496,9 +1500,11 @@ export class SessionSelectorComponent<T extends SessionSelectorEntry = SessionSe
|
|
|
1496
1500
|
onExit();
|
|
1497
1501
|
};
|
|
1498
1502
|
this.#sessionList.onRequestRender = () => this.#onRequestRender?.();
|
|
1499
|
-
this.#
|
|
1500
|
-
this.#
|
|
1501
|
-
|
|
1503
|
+
if (this.#onDelete) {
|
|
1504
|
+
this.#sessionList.onDeleteRequest = (session: T) => {
|
|
1505
|
+
this.#showDeleteConfirmation(session);
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1502
1508
|
if (this.#loadAllSessions || this.#globalSessions) {
|
|
1503
1509
|
this.#sessionList.onToggleScope = () => {
|
|
1504
1510
|
void this.#toggleScope();
|
|
@@ -1676,7 +1682,7 @@ export class SessionSelectorComponent<T extends SessionSelectorEntry = SessionSe
|
|
|
1676
1682
|
const cancel = interruptKey();
|
|
1677
1683
|
const hint = theme.fg(
|
|
1678
1684
|
"muted",
|
|
1679
|
-
`[${formatKeyHints(["delete", "backspace"])} delete · ${formatKeyHint("enter")} select · ${formatKeyHint("tab")} ${scopeHint} · ${cancel} cancel]`,
|
|
1685
|
+
`[${this.#onDelete ? `${formatKeyHints(["delete", "backspace"])} delete · ` : ""}${formatKeyHint("enter")} select · ${formatKeyHint("tab")} ${scopeHint} · ${cancel} cancel]`,
|
|
1680
1686
|
);
|
|
1681
1687
|
return [row("", width), row(hint, width), row("", width), bottomBorder(width)];
|
|
1682
1688
|
}
|
|
@@ -1724,10 +1730,9 @@ export class SessionSelectorComponent<T extends SessionSelectorEntry = SessionSe
|
|
|
1724
1730
|
} else {
|
|
1725
1731
|
children.push(this.#sessionList.searchInput, list);
|
|
1726
1732
|
}
|
|
1727
|
-
const hints: (NativeHint | undefined)[] = [
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
];
|
|
1733
|
+
const hints: (NativeHint | undefined)[] = [];
|
|
1734
|
+
if (this.#onDelete) hints.push({ keys: ["delete", "backspace"], label: "delete" });
|
|
1735
|
+
hints.push({ keys: ["enter"], label: "select" });
|
|
1731
1736
|
if (this.#sessionList.onToggleScope) {
|
|
1732
1737
|
hints.push({ keys: ["tab"], label: this.#scope === "all" ? "current folder" : "all projects" });
|
|
1733
1738
|
}
|
|
@@ -1774,7 +1779,7 @@ export class SessionSelectorComponent<T extends SessionSelectorEntry = SessionSe
|
|
|
1774
1779
|
}
|
|
1775
1780
|
const loading = message?.kind === "loading";
|
|
1776
1781
|
const toggle = list.onToggleScope !== undefined;
|
|
1777
|
-
const actions = [pickerAction("resume",
|
|
1782
|
+
const actions = [pickerAction("resume", this.#actionLabel, "enter", { primary: true })];
|
|
1778
1783
|
if (this.#onDelete) actions.push(pickerAction("delete", "Delete", "backspace"));
|
|
1779
1784
|
if (toggle) {
|
|
1780
1785
|
actions.push(pickerAction("scope", this.#scope === "all" ? "This folder" : "All projects", "tab"));
|
|
@@ -1102,6 +1102,9 @@ export class SettingsSelectorComponent implements Component {
|
|
|
1102
1102
|
const open = list.openSubmenu;
|
|
1103
1103
|
if (open?.id === id && open.component instanceof MultiSelectSubmenu) {
|
|
1104
1104
|
open.component.setValues(value);
|
|
1105
|
+
// The native page applies a chip toggle without closing its
|
|
1106
|
+
// editor, so the row and its tab badge only update here.
|
|
1107
|
+
this.#refreshItems();
|
|
1105
1108
|
return;
|
|
1106
1109
|
}
|
|
1107
1110
|
const next = [...value];
|
|
@@ -46,6 +46,7 @@ export class ShowImagesSelectorComponent extends OverlayPanel {
|
|
|
46
46
|
this.addChild(this.#selectList);
|
|
47
47
|
this.#sheet = new SelectListSheet(this.#selectList, {
|
|
48
48
|
title: "Show images",
|
|
49
|
+
icon: "image",
|
|
49
50
|
noun: "options",
|
|
50
51
|
current: [currentValue ? "yes" : "no"],
|
|
51
52
|
});
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
SHAPE_VARIANT_NAMES,
|
|
25
25
|
SHAPE_VARIANTS,
|
|
26
26
|
type Shape,
|
|
27
|
+
type ShapeGeometry,
|
|
27
28
|
type ShapeTarget,
|
|
28
29
|
type ShapeVariantName,
|
|
29
30
|
} from "@linxiraos/pi-snapcompact";
|
|
@@ -90,7 +91,7 @@ export class SnapcompactShapePreview implements Component {
|
|
|
90
91
|
|
|
91
92
|
describe(cx: DescribeContext): NativeNode {
|
|
92
93
|
const shape = resolveShape(this.#model, this.#variant);
|
|
93
|
-
const name = resolvedVariantName(shape);
|
|
94
|
+
const name = this.#variant === "auto" ? resolvedVariantName(shape) : this.#variant;
|
|
94
95
|
const entry = cx.supports("image") ? this.#ensureEntry(name, shape) : undefined;
|
|
95
96
|
const memo = this.#native;
|
|
96
97
|
if (memo !== undefined && memo.variant === this.#variant && memo.entry === entry) return memo.node;
|
|
@@ -128,7 +129,7 @@ export class SnapcompactShapePreview implements Component {
|
|
|
128
129
|
|
|
129
130
|
render(width: number): readonly string[] {
|
|
130
131
|
const shape = resolveShape(this.#model, this.#variant);
|
|
131
|
-
const name = resolvedVariantName(shape);
|
|
132
|
+
const name = this.#variant === "auto" ? resolvedVariantName(shape) : this.#variant;
|
|
132
133
|
const { label, stats } = this.#caption(shape, name);
|
|
133
134
|
const lines: string[] = [theme.fg("muted", ` Sample (zoomed) · ${label} · ${stats}`), ""];
|
|
134
135
|
|
|
@@ -215,17 +216,23 @@ export class SnapcompactShapePreview implements Component {
|
|
|
215
216
|
}
|
|
216
217
|
}
|
|
217
218
|
|
|
218
|
-
/**
|
|
219
|
+
/**
|
|
220
|
+
* Research name of the geometry `resolveShape` picked for `auto`. The frame
|
|
221
|
+
* edge is not compared: `auto` widens it per model line and hosts cap it
|
|
222
|
+
* (catalog `image-max-edge`), and the sample renders a fixed mini-page anyway.
|
|
223
|
+
*/
|
|
219
224
|
function resolvedVariantName(shape: Shape): ShapeVariantName {
|
|
220
225
|
for (const name of SHAPE_VARIANT_NAMES) {
|
|
221
|
-
const candidate = SHAPE_VARIANTS[name];
|
|
226
|
+
const candidate: ShapeGeometry = SHAPE_VARIANTS[name];
|
|
222
227
|
if (
|
|
223
228
|
candidate.font === shape.font &&
|
|
224
229
|
candidate.cellWidth === shape.cellWidth &&
|
|
225
230
|
candidate.cellHeight === shape.cellHeight &&
|
|
231
|
+
candidate.stretch === shape.stretch &&
|
|
226
232
|
candidate.variant === shape.variant &&
|
|
227
|
-
candidate.
|
|
228
|
-
candidate.
|
|
233
|
+
candidate.stopwordDim === shape.stopwordDim &&
|
|
234
|
+
candidate.columns === shape.columns &&
|
|
235
|
+
candidate.lineRepeat === shape.lineRepeat
|
|
229
236
|
) {
|
|
230
237
|
return name;
|
|
231
238
|
}
|
|
@@ -71,7 +71,12 @@ export class ThemeSelectorComponent extends OverlayPanel {
|
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
this.addChild(this.#selectList);
|
|
74
|
-
|
|
74
|
+
// The picker checks the current theme, so its "(current)" text stays in the terminal list.
|
|
75
|
+
const options = themePickerOptions("Theme", currentTheme);
|
|
76
|
+
this.#sheet = new SelectListSheet(this.#selectList, {
|
|
77
|
+
...options,
|
|
78
|
+
decorate: item => ({ ...options.decorate?.(item), detail: "" }),
|
|
79
|
+
});
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
override describe(cx: DescribeContext): NativeNode | null {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { THINKING_EFFORTS } from "@linxiraos/pi-catalog/effort";
|
|
1
2
|
import { AUTO_THINKING, type ConfiguredThinkingLevel, getConfiguredThinkingLevelMetadata } from "../thinking";
|
|
2
3
|
import type { Effort } from "@linxiraos/pi-ai";
|
|
3
4
|
import { tuiText } from "../i18n";
|
|
@@ -48,10 +49,13 @@ export class ThinkingSelectorComponent extends OverlayPanel {
|
|
|
48
49
|
icon: "brain",
|
|
49
50
|
noun: "levels",
|
|
50
51
|
current: currentLevel ? [currentLevel] : [],
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
// How hard each level thinks, as a meter from off (empty) to the deepest effort (full); auto has none.
|
|
53
|
+
columns: [{ id: "depth", format: "bar" }],
|
|
54
|
+
decorate: item => {
|
|
55
|
+
if (item.value === AUTO_THINKING) return undefined;
|
|
56
|
+
const effort = THINKING_EFFORTS.indexOf(item.value as (typeof THINKING_EFFORTS)[number]);
|
|
57
|
+
return { facts: { depth: (effort + 1) / THINKING_EFFORTS.length } };
|
|
58
|
+
},
|
|
55
59
|
});
|
|
56
60
|
}
|
|
57
61
|
|
|
@@ -56,7 +56,8 @@ import { resolveAssistantErrorPresentation } from "../chat/transcript-render-hel
|
|
|
56
56
|
import { OverlayPanel, PanelDivider } from "../chrome/overlay-box";
|
|
57
57
|
import { TreeView, type TreeAncestor, type TreeRow } from "../components/tree-view";
|
|
58
58
|
import { formatKeyHint, formatKeyHints } from "../app-keybindings";
|
|
59
|
-
import { boundKeys, editorKeys, interruptKey } from "../chrome/keybinding-hints";
|
|
59
|
+
import { boundKeys, editorKey, editorKeys, interruptKey } from "../chrome/keybinding-hints";
|
|
60
|
+
import { getKeybindings } from "../keybindings";
|
|
60
61
|
import type { TspPickerItem, TspPickerProps, TspSpan, TspText } from "@linxiraos/pi-wire";
|
|
61
62
|
import type { ThemeColor } from "../theme/schema";
|
|
62
63
|
import { col, keyed, node, span, text } from "../native/describe";
|
|
@@ -204,6 +205,7 @@ class TreeList implements Component {
|
|
|
204
205
|
#roots: TreeSelectorNode[] = [];
|
|
205
206
|
#rootIds: Set<string> = new Set();
|
|
206
207
|
#nodeById: Map<string, TreeSelectorNode> = new Map();
|
|
208
|
+
#parentById: Map<string, string | null> = new Map();
|
|
207
209
|
#filterMode: FilterMode;
|
|
208
210
|
/** The search field; its value is the fuzzy query. */
|
|
209
211
|
readonly searchInput = new Input();
|
|
@@ -236,6 +238,14 @@ class TreeList implements Component {
|
|
|
236
238
|
| { rows: readonly TreeRow<TreeSelectorNode, string>[]; labels: number; items: TspPickerItem[] }
|
|
237
239
|
| undefined;
|
|
238
240
|
#pickerOrder: { rows: readonly TreeRow<TreeSelectorNode, string>[]; order: string[] } | undefined;
|
|
241
|
+
/** Branch-navigation targets for one filtered rows snapshot; filtering replaces the rows array. */
|
|
242
|
+
#branchTargets:
|
|
243
|
+
| {
|
|
244
|
+
rows: readonly TreeRow<TreeSelectorNode, string>[];
|
|
245
|
+
targets: readonly TreeSelectorNode[];
|
|
246
|
+
targetIndexByRootId: ReadonlyMap<string, number>;
|
|
247
|
+
}
|
|
248
|
+
| undefined;
|
|
239
249
|
#previewMemo: { node: TreeSelectorNode | undefined; labels: number; preview: NativeChild[] } | undefined;
|
|
240
250
|
|
|
241
251
|
constructor(
|
|
@@ -293,8 +303,9 @@ class TreeList implements Component {
|
|
|
293
303
|
this.#containsActive.clear();
|
|
294
304
|
this.#nodeById.clear();
|
|
295
305
|
this.#activePathIds.clear();
|
|
306
|
+
this.#parentById.clear();
|
|
296
307
|
|
|
297
|
-
const parentIds =
|
|
308
|
+
const parentIds = this.#parentById;
|
|
298
309
|
const allNodes: TreeSelectorNode[] = [];
|
|
299
310
|
const visitStack: TreeSelectorNode[] = [...roots];
|
|
300
311
|
while (visitStack.length > 0) {
|
|
@@ -367,6 +378,100 @@ class TreeList implements Component {
|
|
|
367
378
|
return [...children].sort((a, b) => Number(this.#containsActive.get(b)) - Number(this.#containsActive.get(a)));
|
|
368
379
|
}
|
|
369
380
|
|
|
381
|
+
/** Visible branch targets in rendered order, keyed by every raw branch head. */
|
|
382
|
+
#visibleBranchProjection(rows: readonly TreeRow<TreeSelectorNode, string>[]): {
|
|
383
|
+
targets: readonly TreeSelectorNode[];
|
|
384
|
+
targetIndexByRootId: ReadonlyMap<string, number>;
|
|
385
|
+
} {
|
|
386
|
+
const visibleIndex = new Map<string, number>();
|
|
387
|
+
for (let index = 0; index < rows.length; index++) visibleIndex.set(rows[index]!.key, index);
|
|
388
|
+
const nodes: TreeSelectorNode[] = [];
|
|
389
|
+
const stack = [...this.#roots].reverse();
|
|
390
|
+
while (stack.length > 0) {
|
|
391
|
+
const node = stack.pop()!;
|
|
392
|
+
nodes.push(node);
|
|
393
|
+
const children = this.#orderedChildren(node);
|
|
394
|
+
for (let index = children.length - 1; index >= 0; index--) stack.push(children[index]!);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// One bottom-up pass makes filtered-head promotion O(nodes), rather than
|
|
398
|
+
// rescanning a branch subtree for every fork.
|
|
399
|
+
const firstVisibleById = new Map<string, TreeSelectorNode>();
|
|
400
|
+
for (let index = nodes.length - 1; index >= 0; index--) {
|
|
401
|
+
const node = nodes[index]!;
|
|
402
|
+
let target = visibleIndex.has(node.entry.id) ? node : undefined;
|
|
403
|
+
if (!target) {
|
|
404
|
+
for (const child of this.#orderedChildren(node)) {
|
|
405
|
+
target = firstVisibleById.get(child.entry.id);
|
|
406
|
+
if (target) break;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (target) firstVisibleById.set(node.entry.id, target);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const byTargetId = new Map<string, { rootIds: string[]; target: TreeSelectorNode }>();
|
|
413
|
+
const addFork = (branches: readonly TreeSelectorNode[]) => {
|
|
414
|
+
if (branches.length < 2) return;
|
|
415
|
+
for (const branch of branches) {
|
|
416
|
+
const target = firstVisibleById.get(branch.entry.id);
|
|
417
|
+
if (!target) continue;
|
|
418
|
+
const existing = byTargetId.get(target.entry.id);
|
|
419
|
+
if (existing) existing.rootIds.push(branch.entry.id);
|
|
420
|
+
else byTargetId.set(target.entry.id, { rootIds: [branch.entry.id], target });
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
addFork(this.#roots);
|
|
424
|
+
for (const node of nodes) addFork(this.#orderedChildren(node));
|
|
425
|
+
|
|
426
|
+
const ordered = [...byTargetId.values()].sort(
|
|
427
|
+
(a, b) => visibleIndex.get(a.target.entry.id)! - visibleIndex.get(b.target.entry.id)!,
|
|
428
|
+
);
|
|
429
|
+
const targetIndexByRootId = new Map<string, number>();
|
|
430
|
+
for (let index = 0; index < ordered.length; index++) {
|
|
431
|
+
for (const rootId of ordered[index]!.rootIds) targetIndexByRootId.set(rootId, index);
|
|
432
|
+
}
|
|
433
|
+
return { targets: ordered.map(entry => entry.target), targetIndexByRootId };
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** Raw branch root containing `entryId` at its nearest ancestor fork. */
|
|
437
|
+
#nearestBranchRootId(entryId: string): string | undefined {
|
|
438
|
+
let branchId = entryId;
|
|
439
|
+
let parentId = this.#parentById.get(branchId);
|
|
440
|
+
while (parentId !== undefined) {
|
|
441
|
+
const siblings = parentId === null ? this.#roots : this.#orderedChildren(this.#nodeById.get(parentId)!);
|
|
442
|
+
if (siblings.length > 1) return branchId;
|
|
443
|
+
if (parentId === null) break;
|
|
444
|
+
branchId = parentId;
|
|
445
|
+
parentId = this.#parentById.get(parentId);
|
|
446
|
+
}
|
|
447
|
+
return undefined;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Move through every visible branch in rendered order, crossing nested fork
|
|
452
|
+
* depths. Raw ancestry identifies branch membership; visibility only chooses
|
|
453
|
+
* the first selectable descendant when a branch head is filtered.
|
|
454
|
+
*/
|
|
455
|
+
#moveBranch(direction: -1 | 1): void {
|
|
456
|
+
const selected = this.#tree.selectedItem;
|
|
457
|
+
if (!selected) return;
|
|
458
|
+
// Projection is O(nodes); reuse it across presses until filtering replaces the rows.
|
|
459
|
+
const rows = this.#tree.rows;
|
|
460
|
+
if (this.#branchTargets?.rows !== rows) this.#branchTargets = { rows, ...this.#visibleBranchProjection(rows) };
|
|
461
|
+
const { targets, targetIndexByRootId } = this.#branchTargets;
|
|
462
|
+
|
|
463
|
+
if (targets.length === 0) return;
|
|
464
|
+
const currentRootId = this.#nearestBranchRootId(selected.entry.id);
|
|
465
|
+
const currentIndex = currentRootId === undefined ? -1 : (targetIndexByRootId.get(currentRootId) ?? -1);
|
|
466
|
+
const nextIndex =
|
|
467
|
+
currentIndex < 0
|
|
468
|
+
? direction > 0
|
|
469
|
+
? 0
|
|
470
|
+
: targets.length - 1
|
|
471
|
+
: (currentIndex + direction + targets.length) % targets.length;
|
|
472
|
+
this.#tree.setSelectedKey(targets[nextIndex]!.entry.id);
|
|
473
|
+
}
|
|
474
|
+
|
|
370
475
|
#applyFilter(): void {
|
|
371
476
|
// TreeView retains the nearest visible selection (including an anchor
|
|
372
477
|
// through empty filter results) when the predicate is replaced.
|
|
@@ -1210,6 +1315,10 @@ class TreeList implements Component {
|
|
|
1210
1315
|
(node.entry.message.role === "user" || node.entry.message.role === "assistant"),
|
|
1211
1316
|
1,
|
|
1212
1317
|
);
|
|
1318
|
+
} else if (getKeybindings().matches(keyData, "app.tree.previousBranch")) {
|
|
1319
|
+
this.#moveBranch(-1);
|
|
1320
|
+
} else if (getKeybindings().matches(keyData, "app.tree.nextBranch")) {
|
|
1321
|
+
this.#moveBranch(1);
|
|
1213
1322
|
} else if (matchesKey(keyData, "home")) {
|
|
1214
1323
|
this.#tree.setSelectionIndex(0);
|
|
1215
1324
|
} else if (matchesKey(keyData, "end")) {
|
|
@@ -1398,6 +1507,10 @@ export class TreeSelectorComponent extends OverlayPanel {
|
|
|
1398
1507
|
this.#treeContainer.addChild(this.#treeList);
|
|
1399
1508
|
|
|
1400
1509
|
this.#labelInputContainer = new Container();
|
|
1510
|
+
// Either action may be unbound; hint only the keys that still do something.
|
|
1511
|
+
const branchKeys = [editorKey("app.tree.previousBranch"), editorKey("app.tree.nextBranch")]
|
|
1512
|
+
.filter(Boolean)
|
|
1513
|
+
.join("/");
|
|
1401
1514
|
|
|
1402
1515
|
this.addChild(new Spacer(1));
|
|
1403
1516
|
this.addChild(
|
|
@@ -1407,6 +1520,7 @@ export class TreeSelectorComponent extends OverlayPanel {
|
|
|
1407
1520
|
[
|
|
1408
1521
|
`${formatKeyHint("enter")}: switch.`,
|
|
1409
1522
|
`${formatKeyHints(["alt+up", "alt+down"])}: previous/next turn.`,
|
|
1523
|
+
...(branchKeys ? [`${branchKeys}: previous/next branch.`] : []),
|
|
1410
1524
|
`${editorKeys("tui.select.pageUp", "tui.select.pageDown")} (${formatKeyHints(["left", "right"])}): page.`,
|
|
1411
1525
|
`${formatKeyHints(["home", "end"])}: first/last item.`,
|
|
1412
1526
|
`${formatKeyHint("shift+enter")}: summarize & switch.`,
|
|
@@ -1563,6 +1677,7 @@ export class TreeSelectorComponent extends OverlayPanel {
|
|
|
1563
1677
|
hintsRow([
|
|
1564
1678
|
{ keys: ["enter"], label: "switch" },
|
|
1565
1679
|
{ keys: ["alt+up", "alt+down"], label: "previous/next turn" },
|
|
1680
|
+
actionHint(["app.tree.previousBranch", "app.tree.nextBranch"], "previous/next branch"),
|
|
1566
1681
|
actionHint(["tui.select.pageUp", "tui.select.pageDown"], "page"),
|
|
1567
1682
|
{ keys: ["home", "end"], label: "first/last" },
|
|
1568
1683
|
{ keys: ["shift+enter"], label: "summarize & switch" },
|