@timurproko/a1 0.2.5-dev.683 → 0.2.5-dev.704
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/dist/app/session-shell/prompt-suggestion-controller.d.ts +2 -0
- package/dist/app/session-shell/prompt-suggestion-controller.js +10 -0
- package/dist/app/session-shell/session-shell-root.js +15 -2
- package/dist/app/session-shell/session-shell.js +80 -23
- package/dist/app/session-shell/share-operation.d.ts +3 -0
- package/dist/app/session-shell/share-operation.js +11 -0
- package/dist/composition/owned-ui.js +2 -0
- package/dist/composition/settings-route-host.js +1 -1
- package/dist/contracts/presentation/index.d.ts +11 -1
- package/dist/contracts/presentation/index.js +6 -2
- package/dist/features/owned-ui/project-trust-dialog.js +7 -5
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -2
- package/dist/features/owned-ui/reference-screen-app.js +10 -6
- package/dist/features/owned-ui/settings-app.d.ts +1 -1
- package/dist/features/owned-ui/settings-app.js +342 -66
- package/dist/integrations/pi/components/index.d.ts +3 -2
- package/dist/integrations/pi/components/index.js +2 -1
- package/dist/integrations/pi/components/modal-frame.d.ts +11 -1
- package/dist/integrations/pi/components/modal-frame.js +29 -1
- package/dist/integrations/pi/components/models-dialog.js +19 -19
- package/dist/integrations/pi/components/share-operation-dialog.d.ts +6 -0
- package/dist/integrations/pi/components/share-operation-dialog.js +40 -0
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +55 -8
- package/dist/integrations/pi/components/shell-extension-ui.d.ts +3 -0
- package/dist/integrations/pi/components/shell-extension-ui.js +8 -4
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +0 -4
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +56 -34
- package/dist/integrations/pi/components/shell-session-info-reference.js +35 -2
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +3 -1
- package/dist/integrations/pi/components/shell-shared-facade.js +13 -1
- package/dist/integrations/pi/components/skills-dialog.js +21 -8
- package/dist/integrations/pi/components/theme.d.ts +8 -1
- package/dist/integrations/pi/components/theme.js +28 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +10 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +20 -6
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +2 -2
- package/dist/integrations/pi/components/upstream/components/extension-input.js +4 -5
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +2 -3
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +4 -2
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +48 -12
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +3 -2
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +4 -15
- package/dist/integrations/pi/components/upstream/components/session-selector.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/components/session-selector.js +137 -110
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +9 -5
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +65 -26
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +31 -21
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +255 -214
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +13 -15
- package/dist/integrations/pi/engine/adapter.js +21 -2
- package/dist/integrations/pi/engine/workflow-runner.js +2 -1
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/ui/apps/host.d.ts +4 -3
- package/dist/ui/apps/host.js +9 -4
- package/dist/ui/components/dialog-panel.d.ts +15 -0
- package/dist/ui/components/dialog-panel.js +55 -9
- package/dist/ui/components/index.d.ts +3 -3
- package/dist/ui/components/index.js +2 -2
- package/dist/ui/components/line-input.d.ts +2 -0
- package/dist/ui/components/line-input.js +2 -2
- package/dist/ui/components/list-view.d.ts +3 -3
- package/dist/ui/components/list-view.js +8 -9
- package/dist/ui/components/prompt-input.d.ts +2 -2
- package/dist/ui/components/prompt-input.js +5 -5
- package/dist/ui/components/shortcut-hints.d.ts +10 -3
- package/dist/ui/components/shortcut-hints.js +42 -6
- package/dist/ui/components/shortcuts.d.ts +1 -1
- package/dist/ui/components/shortcuts.js +4 -0
- package/dist/ui/components/theme.d.ts +1 -1
- package/dist/ui/components/value-menu.js +3 -1
- package/dist/ui/settings/manager.d.ts +1 -0
- package/dist/ui/settings/manager.js +9 -3
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DIALOG_BACK_SHORTCUT_HINT, DIALOG_CLOSE_SHORTCUT_HINT } from "../../contracts/presentation/index.js";
|
|
2
|
+
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, assertNoShortcutConflicts, blockJumpTarget, numericValues, RAIL_COLUMNS, renderDialogPanel, renderSteppedDialogPanel, renderEmptyState, renderGroupHeader, renderInputRow, renderListRow, renderNote, renderShortcutHintsWithClose, menuRowAt, regionAt, renderValueMenu, withScrollbarRail, stepperEnds, steppedValue, truncateToWidth, valueColumnFor, valueMenuFrame, blockRowSpan, displayWidth, handleLineInputKey, humanizeLabel, humanizeTitle, indexOfKey, isThumbRow, layoutList, moveSelection, rowKey, scrollForSelection, scrollForTrackPage, scrollbarGeometry, scrollbarPresentation, ScrollbarRails, scrollbarWheelRows, selectableIndexes, } from "../../ui/components/index.js";
|
|
2
3
|
import { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
3
4
|
export { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
4
5
|
const SCOPE = SETTINGS_APP_ID;
|
|
@@ -10,6 +11,8 @@ const SETTINGS_STATUS_ROWS = 1;
|
|
|
10
11
|
const SETTINGS_CONTENT_INSET = 1;
|
|
11
12
|
/** The panel a setting with parts opens: its own keys, its own hint. */
|
|
12
13
|
const DIALOG_SCOPE = `${SETTINGS_APP_ID}-parts`;
|
|
14
|
+
const MODEL_SCOPE = `${SETTINGS_APP_ID}-models`;
|
|
15
|
+
const MODEL_LEVEL_SCOPE = `${SETTINGS_APP_ID}-model-levels`;
|
|
13
16
|
const SCROLLBAR_TOP_INSET = 0;
|
|
14
17
|
/** Identity of the settings list rail in the shared rail state. */
|
|
15
18
|
const RAIL_KEY = "settings";
|
|
@@ -20,29 +23,43 @@ const SEARCH_PLACEHOLDER = "search settings";
|
|
|
20
23
|
/** What a structured value offers instead of printing itself. */
|
|
21
24
|
const CONFIGURE = "configure";
|
|
22
25
|
export const SETTINGS_SHORTCUTS = new ShortcutRegistry();
|
|
23
|
-
SETTINGS_SHORTCUTS.declare({ key: "/", scope: SCOPE, description: "Search settings", section: "Change", hint: { keys: "/", does: "
|
|
24
|
-
SETTINGS_SHORTCUTS.declare({ key: "up", scope: SCOPE, description: "Previous setting", section: "Navigate", hint: { keys: "↑↓", does: "
|
|
25
|
-
SETTINGS_SHORTCUTS.declare({ key: "down", scope: SCOPE, description: "Next setting", section: "Navigate", hint: { keys: "↑↓", does: "
|
|
26
|
-
SETTINGS_SHORTCUTS.declare({ key: "shift+up", scope: SCOPE, description: "Previous section", section: "Navigate", hint: { keys: "Shift+↑↓", does: "
|
|
27
|
-
SETTINGS_SHORTCUTS.declare({ key: "shift+down", scope: SCOPE, description: "Next section", section: "Navigate", hint: { keys: "Shift+↑↓", does: "
|
|
26
|
+
SETTINGS_SHORTCUTS.declare({ key: "/", scope: SCOPE, description: "Search settings", section: "Change", hint: { keys: "/", does: "search" } }, "open-filter");
|
|
27
|
+
SETTINGS_SHORTCUTS.declare({ key: "up", scope: SCOPE, description: "Previous setting", section: "Navigate", hint: { keys: "↑↓", does: "navigate" } }, "move-up");
|
|
28
|
+
SETTINGS_SHORTCUTS.declare({ key: "down", scope: SCOPE, description: "Next setting", section: "Navigate", hint: { keys: "↑↓", does: "navigate" } }, "move-down");
|
|
29
|
+
SETTINGS_SHORTCUTS.declare({ key: "shift+up", scope: SCOPE, description: "Previous section", section: "Navigate", hint: { keys: "Shift+↑↓", does: "jump" } }, "block-up");
|
|
30
|
+
SETTINGS_SHORTCUTS.declare({ key: "shift+down", scope: SCOPE, description: "Next section", section: "Navigate", hint: { keys: "Shift+↑↓", does: "jump" } }, "block-down");
|
|
28
31
|
SETTINGS_SHORTCUTS.declare({ key: "pageUp", scope: SCOPE, description: "Up a page", section: "Navigate" }, "page-up");
|
|
29
32
|
SETTINGS_SHORTCUTS.declare({ key: "pageDown", scope: SCOPE, description: "Down a page", section: "Navigate" }, "page-down");
|
|
30
33
|
// Compatibility: the same chords the transcript uses for its content boundaries; plain
|
|
31
34
|
// Home and End stay with the search input's cursor.
|
|
32
35
|
SETTINGS_SHORTCUTS.declare({ key: "ctrl+home", scope: SCOPE, description: "First setting", section: "Navigate" }, "first");
|
|
33
36
|
SETTINGS_SHORTCUTS.declare({ key: "ctrl+end", scope: SCOPE, description: "Last setting", section: "Navigate" }, "last");
|
|
34
|
-
SETTINGS_SHORTCUTS.declare({ key: "enter", scope: SCOPE, description: "Change value", section: "Change", hint: { keys: "Enter
|
|
35
|
-
SETTINGS_SHORTCUTS.declare({ key: "
|
|
36
|
-
SETTINGS_SHORTCUTS.declare({ key: "
|
|
37
|
-
SETTINGS_SHORTCUTS.declare({ key: "
|
|
38
|
-
SETTINGS_SHORTCUTS.declare({ key: "
|
|
39
|
-
SETTINGS_SHORTCUTS.declare({ key: "enter", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts", hint: { keys: "Enter/Space", does: "to change" } }, "part-change");
|
|
40
|
-
SETTINGS_SHORTCUTS.declare({ key: "space", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts", hint: { keys: "Enter/Space", does: "to change" } }, "part-change");
|
|
37
|
+
SETTINGS_SHORTCUTS.declare({ key: "enter", scope: SCOPE, description: "Change value", section: "Change", hint: { keys: "Enter", does: "change" } }, "activate");
|
|
38
|
+
SETTINGS_SHORTCUTS.declare({ key: "left", scope: SCOPE, description: "Previous value", section: "Change", hint: { keys: "←→", does: "adjust" } }, "previous-value");
|
|
39
|
+
SETTINGS_SHORTCUTS.declare({ key: "right", scope: SCOPE, description: "Next value", section: "Change", hint: { keys: "←→", does: "adjust" } }, "next-value");
|
|
40
|
+
SETTINGS_SHORTCUTS.declare({ key: "ctrl+z", scope: SCOPE, description: "Undo setting change", section: "Change", hint: { keys: "Ctrl+Z", does: "undo" } }, "undo");
|
|
41
|
+
SETTINGS_SHORTCUTS.declare({ key: "enter", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts", hint: { keys: "Enter", does: "change" } }, "part-change");
|
|
41
42
|
SETTINGS_SHORTCUTS.declare({ key: "left", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts" }, "part-change");
|
|
42
43
|
SETTINGS_SHORTCUTS.declare({ key: "right", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts" }, "part-change");
|
|
43
44
|
SETTINGS_SHORTCUTS.declare({ key: "up", scope: DIALOG_SCOPE, description: "Previous part", section: "Parts" }, "part-previous");
|
|
44
45
|
SETTINGS_SHORTCUTS.declare({ key: "down", scope: DIALOG_SCOPE, description: "Next part", section: "Parts" }, "part-next");
|
|
46
|
+
SETTINGS_SHORTCUTS.declare({ key: "ctrl+z", scope: DIALOG_SCOPE, description: "Undo setting change", section: "Parts", hint: { keys: "Ctrl+Z", does: "undo" } }, "undo");
|
|
47
|
+
SETTINGS_SHORTCUTS.declare({
|
|
48
|
+
key: "escape", scope: GLOBAL_SCOPE, description: "Close", section: "Screen",
|
|
49
|
+
hint: { keys: DIALOG_CLOSE_SHORTCUT_HINT.key, does: DIALOG_CLOSE_SHORTCUT_HINT.action },
|
|
50
|
+
}, "close");
|
|
45
51
|
assertNoShortcutConflicts(SETTINGS_SHORTCUTS.assemble());
|
|
52
|
+
const MODEL_SHORTCUTS = new ShortcutRegistry();
|
|
53
|
+
MODEL_SHORTCUTS.declare({ key: "edit", scope: MODEL_SCOPE, description: "Search models", section: "Choose", hint: { keys: "Type", does: "search" } }, "edit-filter");
|
|
54
|
+
MODEL_SHORTCUTS.declare({ key: "up", scope: MODEL_SCOPE, description: "Previous model", section: "Choose" }, "previous");
|
|
55
|
+
MODEL_SHORTCUTS.declare({ key: "down", scope: MODEL_SCOPE, description: "Next model", section: "Choose" }, "next");
|
|
56
|
+
MODEL_SHORTCUTS.declare({ key: "enter", scope: MODEL_SCOPE, description: "Select model", section: "Choose", hint: { keys: "Enter", does: "select" } }, "select");
|
|
57
|
+
MODEL_SHORTCUTS.declare({ key: "escape", scope: MODEL_SCOPE, description: "Close selector", section: "Choose", hint: { keys: DIALOG_CLOSE_SHORTCUT_HINT.key, does: DIALOG_CLOSE_SHORTCUT_HINT.action } }, "close");
|
|
58
|
+
MODEL_SHORTCUTS.declare({ key: "up", scope: MODEL_LEVEL_SCOPE, description: "Previous level", section: "Choose", hint: { keys: "↑↓", does: "navigate" } }, "previous");
|
|
59
|
+
MODEL_SHORTCUTS.declare({ key: "down", scope: MODEL_LEVEL_SCOPE, description: "Next level", section: "Choose", hint: { keys: "↑↓", does: "navigate" } }, "next");
|
|
60
|
+
MODEL_SHORTCUTS.declare({ key: "enter", scope: MODEL_LEVEL_SCOPE, description: "Select level", section: "Choose", hint: { keys: "Enter", does: "select" } }, "select");
|
|
61
|
+
MODEL_SHORTCUTS.declare({ key: "escape", scope: MODEL_LEVEL_SCOPE, description: "Return to models", section: "Choose", hint: { keys: DIALOG_BACK_SHORTCUT_HINT.key, does: DIALOG_BACK_SHORTCUT_HINT.action } }, "back");
|
|
62
|
+
assertNoShortcutConflicts(MODEL_SHORTCUTS.assemble());
|
|
46
63
|
const KEYS = {
|
|
47
64
|
"\u001b[A": "up",
|
|
48
65
|
"\u001b[B": "down",
|
|
@@ -62,6 +79,7 @@ const KEYS = {
|
|
|
62
79
|
"\n": "enter",
|
|
63
80
|
" ": "space",
|
|
64
81
|
"/": "/",
|
|
82
|
+
"\u001a": "ctrl+z",
|
|
65
83
|
};
|
|
66
84
|
/**
|
|
67
85
|
* The settings screen. Rows, sticky headers, scrolling, and the keymap come from
|
|
@@ -84,10 +102,13 @@ export class SettingsApp {
|
|
|
84
102
|
#interruptArmed = false;
|
|
85
103
|
// Invariant: pending values remain visible until the source reflects them.
|
|
86
104
|
#pending = new Map();
|
|
87
|
-
#
|
|
105
|
+
#undoHistory = [];
|
|
106
|
+
#editSequence = 0;
|
|
107
|
+
#undoRequests = 0;
|
|
108
|
+
#undoActive = false;
|
|
109
|
+
#closed = false;
|
|
88
110
|
#bodyTopForFrame = SETTINGS_TOP_RULE_ROWS + SETTINGS_TITLE_ROWS;
|
|
89
111
|
#bodyHeightForFrame = 0;
|
|
90
|
-
#panelTop = 0;
|
|
91
112
|
#panelTopForFrame = 0;
|
|
92
113
|
#hoverKey = null;
|
|
93
114
|
#hoverRegion = "label";
|
|
@@ -105,9 +126,13 @@ export class SettingsApp {
|
|
|
105
126
|
this.#session = session;
|
|
106
127
|
}
|
|
107
128
|
onActivate(host) {
|
|
129
|
+
this.#closed = false;
|
|
108
130
|
void this.#session.load().then(() => host.requestRender());
|
|
109
131
|
}
|
|
110
132
|
onClose(_host) {
|
|
133
|
+
this.#closed = true;
|
|
134
|
+
this.#undoHistory.length = 0;
|
|
135
|
+
this.#undoRequests = 0;
|
|
111
136
|
this.#clearActivityTimer();
|
|
112
137
|
this.#rails.clear();
|
|
113
138
|
}
|
|
@@ -117,7 +142,9 @@ export class SettingsApp {
|
|
|
117
142
|
const rows = this.#rows();
|
|
118
143
|
const selected = indexOfKey(rows, this.#selectedKey);
|
|
119
144
|
const footer = this.#footerLines(rect.width, theme);
|
|
120
|
-
|
|
145
|
+
// Invariant: the shared search input and structured panel each begin with their own standard rule.
|
|
146
|
+
// That rule replaces the ordinary content/footer divider instead of stacking beneath it.
|
|
147
|
+
const dividerRows = this.#filter === null && this.#structured === null ? SETTINGS_FOOTER_DIVIDER_ROWS : 0;
|
|
121
148
|
const topRows = Math.min(SETTINGS_TOP_RULE_ROWS, rect.height);
|
|
122
149
|
const contentHeight = Math.max(0, rect.height - topRows - dividerRows - footer.length);
|
|
123
150
|
let titleRows = this.#scroll <= 0 ? Math.min(SETTINGS_TITLE_ROWS, contentHeight) : 0;
|
|
@@ -140,7 +167,6 @@ export class SettingsApp {
|
|
|
140
167
|
this.#bodyTopForFrame = topRows + titleRows;
|
|
141
168
|
this.#bodyHeightForFrame = bodyHeight;
|
|
142
169
|
this.#panelTopForFrame = topRows + contentHeight + dividerRows;
|
|
143
|
-
this.#panelTop = this.#panelTopForFrame;
|
|
144
170
|
this.#scroll = layout.scroll;
|
|
145
171
|
const now = Date.now();
|
|
146
172
|
// Rationale: every way of scrolling ends in this frame, so a moved list is noticed here
|
|
@@ -274,6 +300,9 @@ export class SettingsApp {
|
|
|
274
300
|
case "next-value":
|
|
275
301
|
this.#cycle(rows, selected, action === "next-value" ? 1 : -1);
|
|
276
302
|
return { consumed: true };
|
|
303
|
+
case "undo":
|
|
304
|
+
this.#undo();
|
|
305
|
+
return { consumed: true };
|
|
277
306
|
default:
|
|
278
307
|
return { consumed: false };
|
|
279
308
|
}
|
|
@@ -314,30 +343,9 @@ export class SettingsApp {
|
|
|
314
343
|
this.#apply(menu.entry, value);
|
|
315
344
|
return { consumed: true };
|
|
316
345
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
//
|
|
320
|
-
// The panel's rows begin one line below its rule.
|
|
321
|
-
const panel = { firstRow: this.#panelTop + 1, rows: open.flags.length, valueColumn: this.#dialogValueColumn };
|
|
322
|
-
const row = event.row - 1 - panel.firstRow;
|
|
323
|
-
if (row < 0 || row >= panel.rows)
|
|
324
|
-
return { consumed: true, render: false };
|
|
325
|
-
if (event.kind === "motion") {
|
|
326
|
-
if (open.index === row)
|
|
327
|
-
return { consumed: true, render: false };
|
|
328
|
-
open.index = row;
|
|
329
|
-
return { consumed: true, render: true };
|
|
330
|
-
}
|
|
331
|
-
if (event.kind === "press") {
|
|
332
|
-
open.index = row;
|
|
333
|
-
// Rationale: pointing at the label picks the row; the value is what changes it,
|
|
334
|
-
// exactly as in the list behind the dialog.
|
|
335
|
-
const key = open.flags[row] ?? "";
|
|
336
|
-
const width = displayWidth((open.record[key] ?? false) ? "true" : "false");
|
|
337
|
-
if (dialogRowAt(panel, event.row - 1, event.column, width) !== null)
|
|
338
|
-
this.#toggleFlag(row);
|
|
339
|
-
return { consumed: true };
|
|
340
|
-
}
|
|
346
|
+
if (this.#structured !== null) {
|
|
347
|
+
// Invariant: the structured surface is keyboard-only. It owns every pointer report so
|
|
348
|
+
// neither its selection nor the Settings list behind it can react.
|
|
341
349
|
return { consumed: true, render: false };
|
|
342
350
|
}
|
|
343
351
|
if (event.kind === "wheel-up" || event.kind === "wheel-down") {
|
|
@@ -451,8 +459,9 @@ export class SettingsApp {
|
|
|
451
459
|
return;
|
|
452
460
|
}
|
|
453
461
|
const current = shown === null ? 0 : Math.max(0, entry.choices.indexOf(shown));
|
|
454
|
-
//
|
|
455
|
-
|
|
462
|
+
// Invariant: the opening press targeted the setting value, not an option. Keep the
|
|
463
|
+
// effective value as the keyboard origin without painting it as pointer-picked.
|
|
464
|
+
this.#menu = { entry, current, anchorKey: `${entry.backend}:${entry.id}`, choices: entry.choices, index: -1 };
|
|
456
465
|
}
|
|
457
466
|
// Rationale: a structured setting opens as its own flag list rather than a value menu.
|
|
458
467
|
#openStructured(entry) {
|
|
@@ -477,12 +486,25 @@ export class SettingsApp {
|
|
|
477
486
|
this.#hoverKey = null;
|
|
478
487
|
this.#hoverRegion = "label";
|
|
479
488
|
this.#rails.clear();
|
|
480
|
-
|
|
489
|
+
const modelDialog = entry.backend === "agent" && entry.id === "modelThinkingLevels";
|
|
490
|
+
this.#structured = {
|
|
491
|
+
entry,
|
|
492
|
+
flags: entry.flags.map(flag => flag.key),
|
|
493
|
+
modelDialog,
|
|
494
|
+
filter: modelDialog ? new LineInput("") : null,
|
|
495
|
+
step: "model",
|
|
496
|
+
modelKey: null,
|
|
497
|
+
modelIndex: 0,
|
|
498
|
+
index: 0,
|
|
499
|
+
record,
|
|
500
|
+
};
|
|
481
501
|
}
|
|
482
502
|
#structuredKey(data) {
|
|
483
503
|
const open = this.#structured;
|
|
484
504
|
if (open === null)
|
|
485
505
|
return { consumed: false };
|
|
506
|
+
if (open.modelDialog)
|
|
507
|
+
return this.#modelDialogKey(open, data);
|
|
486
508
|
switch (SETTINGS_SHORTCUTS.resolve(KEYS[data] ?? data, DIALOG_SCOPE)) {
|
|
487
509
|
case "close":
|
|
488
510
|
this.#structured = null;
|
|
@@ -496,15 +518,94 @@ export class SettingsApp {
|
|
|
496
518
|
case "part-change":
|
|
497
519
|
this.#toggleFlag(open.index);
|
|
498
520
|
return { consumed: true };
|
|
521
|
+
case "undo":
|
|
522
|
+
this.#undo();
|
|
523
|
+
return { consumed: true };
|
|
499
524
|
default:
|
|
500
525
|
return { consumed: true, render: false };
|
|
501
526
|
}
|
|
502
527
|
}
|
|
528
|
+
#modelDialogKey(open, data) {
|
|
529
|
+
const key = KEYS[data] ?? data;
|
|
530
|
+
if (open.step === "model") {
|
|
531
|
+
const flags = this.#filteredModelFlags(open);
|
|
532
|
+
const action = MODEL_SHORTCUTS.resolve(key, MODEL_SCOPE) ?? "edit-filter";
|
|
533
|
+
if (action === "close") {
|
|
534
|
+
this.#structured = null;
|
|
535
|
+
return { consumed: true };
|
|
536
|
+
}
|
|
537
|
+
if (action === "previous" || action === "next") {
|
|
538
|
+
open.index = Math.min(Math.max(0, flags.length - 1), Math.max(0, open.index + (action === "next" ? 1 : -1)));
|
|
539
|
+
return { consumed: true };
|
|
540
|
+
}
|
|
541
|
+
if (action === "select") {
|
|
542
|
+
const selected = flags[open.index];
|
|
543
|
+
if (selected === undefined)
|
|
544
|
+
return { consumed: true, render: false };
|
|
545
|
+
open.modelIndex = open.index;
|
|
546
|
+
open.modelKey = selected.key;
|
|
547
|
+
open.step = "level";
|
|
548
|
+
const options = this.#modelLevelOptions(open, selected);
|
|
549
|
+
const current = structuredValue(open.entry, open.record)[selected.key];
|
|
550
|
+
open.index = Math.max(0, options.findIndex(option => option.value === current));
|
|
551
|
+
return { consumed: true };
|
|
552
|
+
}
|
|
553
|
+
const input = open.filter;
|
|
554
|
+
if (input === null)
|
|
555
|
+
return { consumed: true, render: false };
|
|
556
|
+
handleLineInputKey(input, data);
|
|
557
|
+
open.index = 0;
|
|
558
|
+
return { consumed: true };
|
|
559
|
+
}
|
|
560
|
+
const selected = open.entry.flags.find(flag => flag.key === open.modelKey);
|
|
561
|
+
const choices = selected === undefined ? [] : this.#modelLevelOptions(open, selected);
|
|
562
|
+
const action = MODEL_SHORTCUTS.resolve(key, MODEL_LEVEL_SCOPE);
|
|
563
|
+
if (action === "back") {
|
|
564
|
+
open.step = "model";
|
|
565
|
+
open.modelKey = null;
|
|
566
|
+
open.index = open.modelIndex;
|
|
567
|
+
return { consumed: true };
|
|
568
|
+
}
|
|
569
|
+
if (action === "previous" || action === "next") {
|
|
570
|
+
open.index = Math.min(Math.max(0, choices.length - 1), Math.max(0, open.index + (action === "next" ? 1 : -1)));
|
|
571
|
+
return { consumed: true };
|
|
572
|
+
}
|
|
573
|
+
if (action === "select") {
|
|
574
|
+
const choice = choices[open.index];
|
|
575
|
+
if (selected === undefined || choice === undefined)
|
|
576
|
+
return { consumed: true, render: false };
|
|
577
|
+
const previous = { ...open.record };
|
|
578
|
+
open.record[selected.key] = choice.value;
|
|
579
|
+
const forward = { ...open.record };
|
|
580
|
+
this.#saveStructured(open, previous, forward);
|
|
581
|
+
open.step = "model";
|
|
582
|
+
open.modelKey = null;
|
|
583
|
+
open.index = open.modelIndex;
|
|
584
|
+
return { consumed: true };
|
|
585
|
+
}
|
|
586
|
+
return { consumed: true, render: false };
|
|
587
|
+
}
|
|
588
|
+
#filteredModelFlags(open) {
|
|
589
|
+
const needle = open.filter?.value.trim().toLowerCase() ?? "";
|
|
590
|
+
return open.entry.flags.filter(flag => needle.length === 0
|
|
591
|
+
|| (flag.label ?? humanizeLabel(flag.key)).toLowerCase().includes(needle)
|
|
592
|
+
|| flag.key.toLowerCase().includes(needle));
|
|
593
|
+
}
|
|
594
|
+
#modelLevelOptions(open, selected) {
|
|
595
|
+
const fallback = String(selected.fallback);
|
|
596
|
+
const supported = (selected.choices ?? [])
|
|
597
|
+
.filter(choice => choice !== fallback)
|
|
598
|
+
.map(choice => ({ value: choice, label: choice, description: thinkingLevelDescription(choice) }));
|
|
599
|
+
return structuredValue(open.entry, open.record)[selected.key] === undefined
|
|
600
|
+
? supported
|
|
601
|
+
: [...supported, { value: fallback, label: "(clear override)", description: "Revert to global default" }];
|
|
602
|
+
}
|
|
503
603
|
#toggleFlag(index) {
|
|
504
604
|
const open = this.#structured;
|
|
505
605
|
const flag = open?.flags[index];
|
|
506
606
|
if (open === null || open === undefined || flag === undefined)
|
|
507
607
|
return;
|
|
608
|
+
const previous = { ...open.record };
|
|
508
609
|
const declared = open.entry.flags.find(candidate => candidate.key === flag);
|
|
509
610
|
if (declared?.choices === undefined)
|
|
510
611
|
open.record[flag] = !(open.record[flag] ?? false);
|
|
@@ -513,13 +614,24 @@ export class SettingsApp {
|
|
|
513
614
|
const at = declared.choices.indexOf(String(open.record[flag] ?? declared.fallback));
|
|
514
615
|
open.record[flag] = declared.choices[(at + 1) % declared.choices.length] ?? declared.fallback;
|
|
515
616
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
void this.#session.changeStructured(open.entry.backend, open.entry.id,
|
|
522
|
-
|
|
617
|
+
const forward = { ...open.record };
|
|
618
|
+
this.#saveStructured(open, previous, forward);
|
|
619
|
+
}
|
|
620
|
+
#saveStructured(open, previous, forward) {
|
|
621
|
+
const sequence = ++this.#editSequence;
|
|
622
|
+
void this.#session.changeStructured(open.entry.backend, open.entry.id, structuredValue(open.entry, forward)).then(outcome => {
|
|
623
|
+
const failure = changeFailure(outcome);
|
|
624
|
+
if (failure === null) {
|
|
625
|
+
this.#recordUndo({ kind: "structured", sequence, entry: open.entry, previous, forward });
|
|
626
|
+
this.#notice = outcome.status === "deferred" && outcome.application !== null
|
|
627
|
+
? `${labelOf(open.entry)} is stored and applies ${applicationLabel(outcome.application)}`
|
|
628
|
+
: null;
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
// Concurrency: only roll back the dialog if no later press has moved the record on.
|
|
632
|
+
if (this.#structured === open && sameRecord(open.record, forward))
|
|
633
|
+
replaceRecord(open.record, previous);
|
|
634
|
+
this.#notice = `Could not save ${labelOf(open.entry)}: ${failure}`;
|
|
523
635
|
});
|
|
524
636
|
}
|
|
525
637
|
#menuKey(data) {
|
|
@@ -527,6 +639,11 @@ export class SettingsApp {
|
|
|
527
639
|
if (menu === null)
|
|
528
640
|
return { consumed: false };
|
|
529
641
|
const key = KEYS[data] ?? data;
|
|
642
|
+
if (SETTINGS_SHORTCUTS.resolve(key, SCOPE) === "undo") {
|
|
643
|
+
this.#menu = null;
|
|
644
|
+
this.#undo();
|
|
645
|
+
return { consumed: true };
|
|
646
|
+
}
|
|
530
647
|
if (key === "escape") {
|
|
531
648
|
this.#menu = null;
|
|
532
649
|
return { consumed: true };
|
|
@@ -550,6 +667,10 @@ export class SettingsApp {
|
|
|
550
667
|
if (input === null)
|
|
551
668
|
return { consumed: false };
|
|
552
669
|
const key = KEYS[data];
|
|
670
|
+
if (SETTINGS_SHORTCUTS.resolve(key ?? data, SCOPE) === "undo") {
|
|
671
|
+
this.#undo();
|
|
672
|
+
return { consumed: true };
|
|
673
|
+
}
|
|
553
674
|
// Rationale: the boundary chords jump through the results; plain Home and End stay with
|
|
554
675
|
// the search cursor, which the shared line input moves below.
|
|
555
676
|
if (key === "ctrl+home" || key === "ctrl+end") {
|
|
@@ -627,20 +748,21 @@ export class SettingsApp {
|
|
|
627
748
|
}
|
|
628
749
|
#apply(entry, value) {
|
|
629
750
|
const key = `${entry.backend}:${entry.id}`;
|
|
751
|
+
const previous = this.#shownValue(entry);
|
|
752
|
+
const sequence = ++this.#editSequence;
|
|
630
753
|
// Invariant: shown immediately so the row never lags a keypress, and so the next press
|
|
631
754
|
// steps from here rather than from a value the source has not caught up to.
|
|
632
755
|
this.#pending.set(key, value);
|
|
633
756
|
void this.#session.change(entry.backend, entry.id, value).then(outcome => {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
this.#
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
if (outcome.status === "unavailable" || outcome.limitationReason !== null) {
|
|
640
|
-
this.#pending.delete(key);
|
|
641
|
-
this.#notice = outcome.limitationReason ?? `${labelOf(entry)} is unavailable`;
|
|
757
|
+
const failure = changeFailure(outcome);
|
|
758
|
+
if (failure !== null) {
|
|
759
|
+
if (this.#pending.get(key) === value)
|
|
760
|
+
this.#pending.delete(key);
|
|
761
|
+
this.#notice = `Could not save ${labelOf(entry)}: ${failure}`;
|
|
642
762
|
return;
|
|
643
763
|
}
|
|
764
|
+
if (previous !== null && previous !== value)
|
|
765
|
+
this.#recordUndo({ kind: "scalar", sequence, entry, previous });
|
|
644
766
|
// Concurrency: a later press may have moved on; only the last request clears itself.
|
|
645
767
|
if (this.#pending.get(key) === value)
|
|
646
768
|
this.#pending.delete(key);
|
|
@@ -652,6 +774,64 @@ export class SettingsApp {
|
|
|
652
774
|
#shownValue(entry) {
|
|
653
775
|
return this.#pending.get(`${entry.backend}:${entry.id}`) ?? entry.value;
|
|
654
776
|
}
|
|
777
|
+
#recordUndo(record) {
|
|
778
|
+
if (this.#closed)
|
|
779
|
+
return;
|
|
780
|
+
const after = this.#undoHistory.findIndex(candidate => candidate.sequence > record.sequence);
|
|
781
|
+
if (after < 0)
|
|
782
|
+
this.#undoHistory.push(record);
|
|
783
|
+
else
|
|
784
|
+
this.#undoHistory.splice(after, 0, record);
|
|
785
|
+
}
|
|
786
|
+
#undo() {
|
|
787
|
+
this.#undoRequests++;
|
|
788
|
+
this.#drainUndo();
|
|
789
|
+
}
|
|
790
|
+
#drainUndo() {
|
|
791
|
+
if (this.#undoActive || this.#undoRequests === 0)
|
|
792
|
+
return;
|
|
793
|
+
const record = this.#undoHistory.pop();
|
|
794
|
+
if (record === undefined) {
|
|
795
|
+
this.#undoRequests = 0;
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
this.#undoRequests--;
|
|
799
|
+
this.#undoActive = true;
|
|
800
|
+
if (record.kind === "scalar") {
|
|
801
|
+
const key = `${record.entry.backend}:${record.entry.id}`;
|
|
802
|
+
this.#pending.set(key, record.previous);
|
|
803
|
+
void this.#session.change(record.entry.backend, record.entry.id, record.previous).then(outcome => {
|
|
804
|
+
if (this.#pending.get(key) === record.previous)
|
|
805
|
+
this.#pending.delete(key);
|
|
806
|
+
this.#finishUndo(record, outcome);
|
|
807
|
+
});
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const open = this.#structured;
|
|
811
|
+
if (open !== null && sameEntry(open.entry, record.entry))
|
|
812
|
+
replaceRecord(open.record, record.previous);
|
|
813
|
+
void this.#session.changeStructured(record.entry.backend, record.entry.id, structuredValue(record.entry, record.previous)).then(outcome => {
|
|
814
|
+
const failure = changeFailure(outcome);
|
|
815
|
+
if (failure !== null && this.#structured === open && open !== null && sameRecord(open.record, record.previous)) {
|
|
816
|
+
replaceRecord(open.record, record.forward);
|
|
817
|
+
}
|
|
818
|
+
this.#finishUndo(record, outcome);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
#finishUndo(record, outcome) {
|
|
822
|
+
const failure = changeFailure(outcome);
|
|
823
|
+
if (failure !== null) {
|
|
824
|
+
this.#recordUndo(record);
|
|
825
|
+
this.#notice = `Could not restore ${labelOf(record.entry)}: ${failure}`;
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
this.#notice = outcome.status === "deferred" && outcome.application !== null
|
|
829
|
+
? `${labelOf(record.entry)} is restored and applies ${applicationLabel(outcome.application)}`
|
|
830
|
+
: null;
|
|
831
|
+
}
|
|
832
|
+
this.#undoActive = false;
|
|
833
|
+
this.#drainUndo();
|
|
834
|
+
}
|
|
655
835
|
#scrollbarSpeed() {
|
|
656
836
|
const value = this.#scrollSetting("scrollbarSpeed");
|
|
657
837
|
return isScrollbarSpeed(value) ? value : "normal";
|
|
@@ -739,15 +919,16 @@ export class SettingsApp {
|
|
|
739
919
|
return ` ${renderListRow(this.#viewRow(entry), { selected, hovered, region: this.#hoverRegion }, valueColumn, innerWidth, theme)}`;
|
|
740
920
|
}
|
|
741
921
|
#viewRow(entry) {
|
|
922
|
+
const key = `${entry.backend}:${entry.id}`;
|
|
742
923
|
const shown = this.#shownValue(entry);
|
|
743
924
|
const value = entry.structured
|
|
744
925
|
? CONFIGURE
|
|
745
926
|
: shown === null
|
|
746
927
|
? describeRaw(entry.rawValue)
|
|
747
|
-
: effectiveDisplay(entry, shown);
|
|
928
|
+
: this.#pending.has(key) ? displayValue(shown) : effectiveDisplay(entry, shown);
|
|
748
929
|
const range = rangeOf(entry);
|
|
749
930
|
return {
|
|
750
|
-
key
|
|
931
|
+
key,
|
|
751
932
|
label: labelOf(entry),
|
|
752
933
|
value,
|
|
753
934
|
...(typeof shown === "number" && entry.editable ? { stepper: stepperEnds(range, shown) } : {}),
|
|
@@ -765,7 +946,10 @@ export class SettingsApp {
|
|
|
765
946
|
current: this.#shownValue(menu.entry) === null ? null : displayValue(this.#shownValue(menu.entry)),
|
|
766
947
|
index: menu.index,
|
|
767
948
|
};
|
|
768
|
-
const frame = valueMenuFrame(state, {
|
|
949
|
+
const frame = valueMenuFrame(state, {
|
|
950
|
+
screenRow: anchor.screenRow,
|
|
951
|
+
valueColumn: valueColumn + SETTINGS_CONTENT_INSET,
|
|
952
|
+
}, {
|
|
769
953
|
bodyTop: this.#bodyTopForFrame,
|
|
770
954
|
bodyHeight: this.#bodyHeightForFrame,
|
|
771
955
|
surfaceWidth: rect.width,
|
|
@@ -775,6 +959,8 @@ export class SettingsApp {
|
|
|
775
959
|
return renderValueMenu(lines, state, frame, theme);
|
|
776
960
|
}
|
|
777
961
|
#dialogLines(open, width, theme) {
|
|
962
|
+
if (open.modelDialog)
|
|
963
|
+
return this.#modelDialogLines(open, width, theme);
|
|
778
964
|
const rows = open.flags.map(key => {
|
|
779
965
|
const declared = open.entry.flags.find(flag => flag.key === key);
|
|
780
966
|
return {
|
|
@@ -784,9 +970,46 @@ export class SettingsApp {
|
|
|
784
970
|
...(declared?.description === undefined ? {} : { description: declared.description }),
|
|
785
971
|
};
|
|
786
972
|
});
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
973
|
+
return renderDialogPanel({ title: labelOf(open.entry), rows, index: open.index, hint: SETTINGS_SHORTCUTS.hintEntries(DIALOG_SCOPE) }, width, theme);
|
|
974
|
+
}
|
|
975
|
+
#modelDialogLines(open, width, theme) {
|
|
976
|
+
if (open.step === "model") {
|
|
977
|
+
const flags = this.#filteredModelFlags(open);
|
|
978
|
+
const stored = structuredValue(open.entry, open.record);
|
|
979
|
+
const allRows = flags.length === 0
|
|
980
|
+
? [{ label: "No models found", value: "" }]
|
|
981
|
+
: flags.map(flag => ({
|
|
982
|
+
...modelLabelParts(flag.label ?? humanizeLabel(flag.key)),
|
|
983
|
+
value: stored[flag.key] === undefined ? "" : String(stored[flag.key]),
|
|
984
|
+
}));
|
|
985
|
+
const visible = dialogWindow(allRows, open.index, 10);
|
|
986
|
+
return renderSteppedDialogPanel({
|
|
987
|
+
title: "Thinking Level",
|
|
988
|
+
step: 1,
|
|
989
|
+
steps: 2,
|
|
990
|
+
description: "Select a model to configure",
|
|
991
|
+
...(open.filter === null ? {} : { input: open.filter }),
|
|
992
|
+
rows: visible.rows,
|
|
993
|
+
index: visible.index,
|
|
994
|
+
hint: MODEL_SHORTCUTS.hintEntries(MODEL_SCOPE),
|
|
995
|
+
}, width, theme);
|
|
996
|
+
}
|
|
997
|
+
const selected = open.entry.flags.find(flag => flag.key === open.modelKey);
|
|
998
|
+
const current = selected === undefined ? undefined : structuredValue(open.entry, open.record)[selected.key];
|
|
999
|
+
const allRows = (selected === undefined ? [] : this.#modelLevelOptions(open, selected)).map(choice => ({
|
|
1000
|
+
label: choice.value === current ? `✓ ${choice.label}` : choice.label,
|
|
1001
|
+
value: choice.description,
|
|
1002
|
+
}));
|
|
1003
|
+
const visible = dialogWindow(allRows, open.index, 10);
|
|
1004
|
+
return renderSteppedDialogPanel({
|
|
1005
|
+
title: "Thinking Level",
|
|
1006
|
+
step: 2,
|
|
1007
|
+
steps: 2,
|
|
1008
|
+
description: `Select default thinking level for ${selected?.label ?? open.modelKey ?? "model"}`,
|
|
1009
|
+
rows: visible.rows,
|
|
1010
|
+
index: visible.index,
|
|
1011
|
+
hint: MODEL_SHORTCUTS.hintEntries(MODEL_LEVEL_SCOPE),
|
|
1012
|
+
}, width, theme);
|
|
790
1013
|
}
|
|
791
1014
|
#footerLines(width, theme) {
|
|
792
1015
|
const open = this.#structured;
|
|
@@ -797,7 +1020,7 @@ export class SettingsApp {
|
|
|
797
1020
|
? notice
|
|
798
1021
|
: this.#interruptArmed ? "press ctrl+c again to exit a1" : null;
|
|
799
1022
|
const status = plainStatus === null
|
|
800
|
-
?
|
|
1023
|
+
? renderShortcutHintsWithClose(SETTINGS_SHORTCUTS.hintEntries(SCOPE), theme, width, width > 0 ? 1 : 0)
|
|
801
1024
|
: truncateToWidth(`${width > 0 ? " " : ""}${theme.fg("dim", plainStatus)}`, width);
|
|
802
1025
|
const input = this.#filter;
|
|
803
1026
|
if (input === null)
|
|
@@ -805,6 +1028,59 @@ export class SettingsApp {
|
|
|
805
1028
|
return [...renderInputRow(input, width, { placeholder: SEARCH_PLACEHOLDER, theme }).lines, status];
|
|
806
1029
|
}
|
|
807
1030
|
}
|
|
1031
|
+
function modelLabelParts(label) {
|
|
1032
|
+
const match = /^(.*?)(\s+\[[^\]]+\])$/u.exec(label);
|
|
1033
|
+
return match === null ? { label } : { label: match[1] ?? label, labelSuffix: match[2] ?? "" };
|
|
1034
|
+
}
|
|
1035
|
+
function dialogWindow(rows, index, maximum) {
|
|
1036
|
+
if (rows.length <= maximum)
|
|
1037
|
+
return { rows, index: Math.min(Math.max(0, rows.length - 1), Math.max(0, index)) };
|
|
1038
|
+
const start = Math.min(rows.length - maximum, Math.max(0, index - Math.floor(maximum / 2)));
|
|
1039
|
+
return { rows: rows.slice(start, start + maximum), index: index - start };
|
|
1040
|
+
}
|
|
1041
|
+
function thinkingLevelDescription(level) {
|
|
1042
|
+
switch (level) {
|
|
1043
|
+
case "default": return "global default";
|
|
1044
|
+
case "off": return "No reasoning";
|
|
1045
|
+
case "minimal": return "Very brief reasoning (~1k tokens)";
|
|
1046
|
+
case "low": return "Light reasoning (~2k tokens)";
|
|
1047
|
+
case "medium": return "Moderate reasoning (~8k tokens)";
|
|
1048
|
+
case "high": return "Deep reasoning (~16k tokens)";
|
|
1049
|
+
case "xhigh": return "Extra-high reasoning (~32k tokens)";
|
|
1050
|
+
case "max": return "Maximum reasoning";
|
|
1051
|
+
default: return "";
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
function structuredValue(entry, record) {
|
|
1055
|
+
// Invariant: a choice part at its fallback is unset, so the engine's default applies.
|
|
1056
|
+
return Object.fromEntries(Object.entries(record).filter(([key, value]) => {
|
|
1057
|
+
const part = entry.flags.find(candidate => candidate.key === key);
|
|
1058
|
+
return part?.choices === undefined || value !== part.fallback;
|
|
1059
|
+
}));
|
|
1060
|
+
}
|
|
1061
|
+
function sameEntry(left, right) {
|
|
1062
|
+
return left.backend === right.backend && left.id === right.id;
|
|
1063
|
+
}
|
|
1064
|
+
function sameRecord(left, right) {
|
|
1065
|
+
const leftEntries = Object.entries(left);
|
|
1066
|
+
const rightEntries = Object.entries(right);
|
|
1067
|
+
return leftEntries.length === rightEntries.length
|
|
1068
|
+
&& leftEntries.every(([key, value]) => right[key] === value);
|
|
1069
|
+
}
|
|
1070
|
+
function replaceRecord(target, source) {
|
|
1071
|
+
for (const key of Object.keys(target))
|
|
1072
|
+
delete target[key];
|
|
1073
|
+
Object.assign(target, source);
|
|
1074
|
+
}
|
|
1075
|
+
function changeFailure(outcome) {
|
|
1076
|
+
if (outcome.failure !== null)
|
|
1077
|
+
return outcome.failure;
|
|
1078
|
+
if (outcome.status === "failed")
|
|
1079
|
+
return "the effect failed";
|
|
1080
|
+
if (outcome.status === "unavailable")
|
|
1081
|
+
return outcome.limitationReason ?? "the setting is unavailable";
|
|
1082
|
+
return outcome.limitationReason;
|
|
1083
|
+
}
|
|
808
1084
|
/** The source's own wording when it has one, otherwise the id made readable. */
|
|
809
1085
|
function labelOf(entry) {
|
|
810
1086
|
return entry.label ?? humanizeLabel(entry.id);
|
|
@@ -2,10 +2,11 @@ export { adaptPiAssistantMessage, adaptPiToolExecution, adaptPiUserMessage } fro
|
|
|
2
2
|
export { loadHistoryEditor, type HistoryEditorConstructor } from "./history-editor-loader.js";
|
|
3
3
|
export { PiComponentConformanceError, runPiComponentConformance } from "./conformance.js";
|
|
4
4
|
export type { PiComponentConformanceReport, PiComponentConformanceResult } from "./conformance.js";
|
|
5
|
-
export {
|
|
5
|
+
export { createPiShellOperationLoader, createPiShellShareOperationDialog, type PiShellOperationLoaderPort, } from "./share-operation-dialog.js";
|
|
6
|
+
export { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, componentFromPort, componentPort, createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellShowImagesSelector, createPiShellSkillsSelector, createPiShellStatus, createPiShellThemeSelector, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, createTuiFacade, ensureTheme, formatSessionTokens, isAutocompleteProvider, isPiPromptStyleCompaction, isRecord, paintPiSubmittedPromptTimestamp, piShellHyperlink, piShellTruncateToWidth, piShellVisibleWidth, renderPiShellChangelogLines, renderPiShellCommandMessage, renderPiShellHotkeysLines, renderPiShellPackageUpdateNotice, renderPiShellReleaseUpdateBanner, renderPiShellReleaseUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, validatedAssistantMessage, } from "./shell-components.js";
|
|
6
7
|
export { renderPiShellHotkeySections } from "./shell-hotkey-sections.js";
|
|
7
8
|
export type { PiShellHotkeySection } from "./shell-hotkey-sections.js";
|
|
8
|
-
export type { PiExtensionUiBridge, PiExtensionUiBridgeHost, PiShellAuthProviderOption, PiShellAutocompleteCommand, PiShellClipboardContent, PiShellCommandMessagePresentation, PiShellComponentPort, PiShellEditorBodyGeometry, PiShellEditorOptions, PiShellEditorPointerEvent, PiShellEditorPort, PiShellEditorTextRange, PiShellExtensionRendererResolver, PiShellHeaderOptions, PiShellHeaderPort, PiShellHotkeysPresentation, PiShellImageAssetResolver, PiShellLoadedResourcesPort, PiShellLoginDialogPort, PiShellModelSelectorOptions, PiShellModelsDialogOptions, PiShellModelsDialogPort,
|
|
9
|
+
export type { PiExtensionUiBridge, PiExtensionUiBridgeHost, PiShellAuthProviderOption, PiShellAutocompleteCommand, PiShellClipboardContent, PiShellCommandMessagePresentation, PiShellComponentPort, PiShellEditorBodyGeometry, PiShellEditorOptions, PiShellEditorPointerEvent, PiShellEditorPort, PiShellEditorTextRange, PiShellExtensionRendererResolver, PiShellHeaderOptions, PiShellHeaderPort, PiShellHotkeysPresentation, PiShellImageAssetResolver, PiShellLoadedResourcesPort, PiShellLoginDialogPort, PiShellModelSelectorOptions, PiShellModelsDialogOptions, PiShellModelsDialogPort, PiShellPasteReservation, PiShellQueuedInputPort, PiShellResourceEntry, PiShellResourceSection, PiShellScopedModelDescriptor, PiShellScopedModelsSelectorOptions, PiShellScopedModelsSelectorPort, PiShellSelectorOption, PiShellSelectorOptions, PiShellSessionInfoPresentation, PiShellSettingsSelectorOptions, PiShellStartupNotice, PiShellStatusPlacement, PiShellStatusPort, PiShellSubmittedPromptComposer, PiShellTranscriptComponentPort, PiShellViewComponentPort, } from "./shell-components.js";
|
|
9
10
|
export { PINNED_PI_LAYOUT, applyConfiguredPiTheme, applyPiTheme, applyPiThemeInstance, currentPiThemeName, detectPiTerminalBackgroundFromEnv, detectPiTerminalBackgroundTheme, detectPiTerminalThemeForAuto, ensurePiTheme, getAvailablePiThemes, loadPiTheme, onPiThemeChange, parsePiAutoThemeSetting, piTheme, resolvePiThemeSetting, stopPiThemeWatcher, } from "./theme.js";
|
|
10
11
|
export type { PiColorMode, PiTerminalTheme, PiTerminalThemeDetection, PiTerminalThemeDetector, PiThemeBackground, PiThemeResult } from "./theme.js";
|
|
11
12
|
export { OwnedPiThemeController } from "./upstream/theme/theme-controller.js";
|