@timurproko/a1 0.2.7-dev.820 → 0.2.7-dev.831
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 +7 -1
- package/bin/automatic-update.js +7 -0
- package/bin/ui.js +1 -0
- package/dist/app/session-shell/session-shell-root.d.ts +8 -1
- package/dist/app/session-shell/session-shell.js +68 -18
- package/dist/app/session-shell/transcript-document.js +1 -1
- package/dist/composition/owned-ui.d.ts +3 -11
- package/dist/composition/owned-ui.js +93 -42
- package/dist/composition/resident-tab-bridge.d.ts +10 -1
- package/dist/composition/resident-tab-bridge.js +21 -0
- package/dist/composition/settings-route-host.d.ts +12 -2
- package/dist/composition/settings-route-host.js +27 -9
- package/dist/composition/settings-search-input.d.ts +9 -0
- package/dist/composition/settings-search-input.js +58 -0
- package/dist/contracts/owned-ui/session-backend.d.ts +2 -0
- package/dist/contracts/owned-ui/session-workflows.d.ts +7 -3
- package/dist/contracts/presentation/index.d.ts +11 -0
- package/dist/contracts/presentation/index.js +12 -0
- package/dist/features/launch/development-launch.js +6 -0
- package/dist/features/launch/profile-paths.js +4 -0
- package/dist/features/owned-ui/plus-menu-dialog.d.ts +22 -0
- package/dist/features/owned-ui/plus-menu-dialog.js +76 -0
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
- package/dist/features/owned-ui/reference-screen-app.js +12 -2
- package/dist/features/owned-ui/settings-app.d.ts +10 -3
- package/dist/features/owned-ui/settings-app.js +98 -45
- package/dist/features/owned-ui/settings-search-input.d.ts +29 -0
- package/dist/features/owned-ui/settings-search-input.js +1 -0
- package/dist/features/prompt-history/index.d.ts +1 -1
- package/dist/features/prompt-history/paths.d.ts +2 -1
- package/dist/features/prompt-history/paths.js +10 -2
- package/dist/features/prompt-history/service.d.ts +5 -0
- package/dist/features/prompt-history/service.js +1 -1
- package/dist/features/resident-tab/shortcut-declarations.d.ts +1 -1
- package/dist/features/resident-tab/shortcut-declarations.js +2 -0
- package/dist/foundation/launch-context/index.d.ts +2 -0
- package/dist/foundation/launch-context/index.js +1 -0
- package/dist/foundation/release/automatic-update.d.ts +37 -0
- package/dist/foundation/release/automatic-update.js +265 -0
- package/dist/foundation/release/bootstrap.d.ts +1 -9
- package/dist/foundation/release/bootstrap.js +7 -3
- package/dist/foundation/release/index.d.ts +1 -1
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/latest-release.d.ts +3 -2
- package/dist/foundation/release/latest-release.js +1 -1
- package/dist/foundation/release/update-execution-lease.d.ts +36 -0
- package/dist/foundation/release/update-execution-lease.js +145 -0
- package/dist/foundation/release/update.d.ts +8 -6
- package/dist/foundation/release/update.js +232 -167
- package/dist/foundation/resident-tabs/bridge-client.d.ts +8 -2
- package/dist/foundation/resident-tabs/bridge-client.js +13 -6
- package/dist/foundation/resident-tabs/routes.d.ts +5 -0
- package/dist/foundation/resident-tabs/routes.js +5 -0
- package/dist/integrations/pi/components/editor-interaction.d.ts +2 -0
- package/dist/integrations/pi/components/modal-frame.d.ts +17 -1
- package/dist/integrations/pi/components/modal-frame.js +48 -9
- package/dist/integrations/pi/components/models-dialog.js +4 -52
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +3 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +75 -4
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +57 -37
- package/dist/integrations/pi/components/shell-footer-status.js +19 -3
- package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +4 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +9 -2
- package/dist/integrations/pi/components/skills-dialog.js +2 -2
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +7 -5
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +15 -8
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +3 -3
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +2 -2
- package/dist/integrations/pi/components/upstream/components/session-footer.js +26 -23
- package/dist/integrations/pi/components/upstream/components/session-selector.js +7 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +7 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +9 -8
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +6 -4
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +8 -8
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +10 -10
- package/dist/integrations/pi/components/upstream/history/editor-core.js +2 -0
- package/dist/integrations/pi/engine/adapter.js +7 -2
- package/dist/integrations/pi/engine/ports.d.ts +1 -1
- package/dist/integrations/pi/engine/ports.js +4 -0
- package/dist/integrations/pi/engine/workflow-runner.js +9 -2
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-arm64/terminal-host.node +0 -0
- package/dist/native/darwin-x64/manifest.json +1 -1
- package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-x64/terminal-host.node +0 -0
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
- package/dist/native/linux-x64/terminal-host.node +0 -0
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.node +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
- package/dist/native/win32-x64/terminal-host.node +0 -0
- package/dist/product-identity.d.ts +1 -1
- package/dist/product-identity.js +1 -1
- package/dist/product-identity.json +1 -0
- package/dist/ui/apps/host.d.ts +2 -0
- package/dist/ui/apps/host.js +7 -1
- package/dist/ui/components/dialog-panel.js +35 -30
- package/dist/ui/components/line-input.d.ts +3 -0
- package/dist/ui/components/line-input.js +3 -1
- package/dist/ui/components/prompt-input.d.ts +3 -2
- package/dist/ui/components/prompt-input.js +6 -4
- package/dist/ui/components/surface.js +4 -2
- package/dist/ui/settings/declarations.d.ts +54 -8
- package/dist/ui/settings/declarations.js +36 -7
- package/dist/ui/settings/manager.js +7 -3
- package/dist/ui/settings/migrations.js +15 -0
- package/dist/ui/settings/sections.d.ts +4 -0
- package/dist/ui/settings/sections.js +9 -3
- package/docs/architecture/resident-tabs.md +35 -7
- package/docs/architecture/tool-image-presentation.md +2 -1
- package/docs/features/prompt-history.md +41 -20
- package/package.json +1 -1
package/dist/product-identity.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import rawIdentity from "./product-identity.json" with { type: "json" };
|
|
2
2
|
const ENVIRONMENT_KEYS = [
|
|
3
|
-
"clipboardDiagnostics", "configDir", "dataDir", "databasePath", "developmentInstanceId", "developmentRoot", "endpoint", "exitNoticePath",
|
|
3
|
+
"clipboardDiagnostics", "configDir", "dataDir", "databasePath", "developmentHistoryDataDir", "developmentInstanceId", "developmentRoot", "endpoint", "exitNoticePath",
|
|
4
4
|
"paneId", "probeTrace", "processGuardianPath", "prFooterPreview", "profileHome", "residentFixtureControlDir", "residentProgressObservationDir", "residentProgressRunId", "residentProgressTabId", "residentProgressTabIncarnation", "runtimeDir", "sessionRuntimeId", "skipVersionCheck", "startupTrace", "suggestionDiagnostics", "tabEndpoint", "tabId", "tabToken", "tabsEndpoint", "terminalHostPath", "terminalSessionId",
|
|
5
5
|
];
|
|
6
6
|
const FILESYSTEM_KEYS = ["slug", "windowsDirectory", "unixDirectory", "temporaryPrefix"];
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"configDir": "A1_CONFIG_DIR",
|
|
15
15
|
"dataDir": "A1_DATA_DIR",
|
|
16
16
|
"databasePath": "A1_DATABASE_PATH",
|
|
17
|
+
"developmentHistoryDataDir": "A1_DEV_HISTORY_DATA_DIR",
|
|
17
18
|
"developmentInstanceId": "A1_DEV_INSTANCE_ID",
|
|
18
19
|
"developmentRoot": "A1_DEV_ROOT",
|
|
19
20
|
"endpoint": "A1_ENDPOINT",
|
package/dist/ui/apps/host.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface AppHostOptions {
|
|
|
20
20
|
readonly closeOnInterrupt: boolean;
|
|
21
21
|
/** Colours handed to every presented app. Absent renders plain text. */
|
|
22
22
|
readonly theme?: UiTheme;
|
|
23
|
+
/** Lets a focused app claim the first interrupt for an editor selection before host close/exit policy. */
|
|
24
|
+
readonly appInputBeforeInterrupt?: boolean;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
27
|
* Presents at most one app. An opted-in interrupt closes at the host boundary;
|
package/dist/ui/apps/host.js
CHANGED
|
@@ -15,6 +15,7 @@ export class UiAppHost {
|
|
|
15
15
|
#surface;
|
|
16
16
|
#closeOnInterrupt;
|
|
17
17
|
#theme;
|
|
18
|
+
#appInputBeforeInterrupt;
|
|
18
19
|
// Invariant: the first interrupt timestamp is null whenever the chord is disarmed.
|
|
19
20
|
#interruptArmedAt = null;
|
|
20
21
|
#renderedInterruptArmed;
|
|
@@ -25,6 +26,7 @@ export class UiAppHost {
|
|
|
25
26
|
this.#surface = options.surface;
|
|
26
27
|
this.#closeOnInterrupt = options.closeOnInterrupt;
|
|
27
28
|
this.#theme = options.theme;
|
|
29
|
+
this.#appInputBeforeInterrupt = options.appInputBeforeInterrupt === true;
|
|
28
30
|
}
|
|
29
31
|
get presented() {
|
|
30
32
|
return this.#app;
|
|
@@ -71,7 +73,7 @@ export class UiAppHost {
|
|
|
71
73
|
const app = this.#app;
|
|
72
74
|
if (app === null)
|
|
73
75
|
return { consumed: false };
|
|
74
|
-
if (data === INTERRUPT && this.#closeOnInterrupt) {
|
|
76
|
+
if (data === INTERRUPT && this.#closeOnInterrupt && !this.#appInputBeforeInterrupt) {
|
|
75
77
|
this.close();
|
|
76
78
|
return { consumed: true, render: true };
|
|
77
79
|
}
|
|
@@ -83,6 +85,10 @@ export class UiAppHost {
|
|
|
83
85
|
this.render();
|
|
84
86
|
return result;
|
|
85
87
|
}
|
|
88
|
+
if (data === INTERRUPT && this.#closeOnInterrupt) {
|
|
89
|
+
this.close();
|
|
90
|
+
return { consumed: true, render: true };
|
|
91
|
+
}
|
|
86
92
|
if (data === INTERRUPT)
|
|
87
93
|
return this.#interrupt();
|
|
88
94
|
return { consumed: false };
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
import { dialogFrameGeometry, insetDialogContent } from "../../contracts/presentation/index.js";
|
|
1
2
|
import { LineInput, renderInputRow } from "./line-input.js";
|
|
2
|
-
import {
|
|
3
|
+
import { renderShortcutHintsWithClose } from "./shortcut-hints.js";
|
|
3
4
|
import { displayWidth, truncateToWidth } from "./text.js";
|
|
4
5
|
const LABEL_COLUMN_CAP = 30;
|
|
5
6
|
const STEPPED_LABEL_COLUMN_CAP = 46;
|
|
7
|
+
/** One frame path for every semantic row, regardless of which dialog supplies the content. */
|
|
8
|
+
function dialogPanelLayout(width, theme) {
|
|
9
|
+
const geometry = dialogFrameGeometry(width);
|
|
10
|
+
return {
|
|
11
|
+
rule: theme.fg("border", "─".repeat(geometry.frameWidth)),
|
|
12
|
+
contentWidth: geometry.contentWidth,
|
|
13
|
+
contentRow: (painted, raw = painted) => insetDialogContent(pad(truncateToWidth(painted, geometry.contentWidth), geometry.contentWidth, raw), geometry),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
6
16
|
/** The column values start at: past the widest label, capped so one long name cannot push them off. */
|
|
7
17
|
export function dialogValueColumn(rows) {
|
|
8
18
|
const widest = Math.min(LABEL_COLUMN_CAP, Math.max(0, ...rows.map(row => displayWidth(row.label))));
|
|
@@ -14,11 +24,7 @@ export function dialogValueColumn(rows) {
|
|
|
14
24
|
*/
|
|
15
25
|
export function renderDialogPanel(state, width, theme) {
|
|
16
26
|
const labelColumn = Math.min(LABEL_COLUMN_CAP, Math.max(0, ...state.rows.map(row => displayWidth(row.label))));
|
|
17
|
-
const
|
|
18
|
-
const contentPadding = Math.min(1, Math.max(0, width));
|
|
19
|
-
const contentWidth = Math.max(0, width - contentPadding);
|
|
20
|
-
const inset = " ".repeat(contentPadding);
|
|
21
|
-
const contentRow = (painted, raw) => `${inset}${pad(truncateToWidth(painted, contentWidth), contentWidth, raw)}`;
|
|
27
|
+
const layout = dialogPanelLayout(width, theme);
|
|
22
28
|
const rows = state.rows.map((row, index) => {
|
|
23
29
|
const selected = index === state.index;
|
|
24
30
|
const padded = `${row.label}${" ".repeat(Math.max(0, labelColumn - displayWidth(row.label)))}`;
|
|
@@ -28,31 +34,27 @@ export function renderDialogPanel(state, width, theme) {
|
|
|
28
34
|
? `${theme.fg("accent", cursor)}${theme.fg("text", padded)} ${theme.fg("muted", row.value)}`
|
|
29
35
|
: `${cursor}${padded} ${theme.fg("muted", row.value)}`;
|
|
30
36
|
const painted = selected ? theme.highlight(content) : content;
|
|
31
|
-
return contentRow(painted, raw);
|
|
37
|
+
return layout.contentRow(painted, raw);
|
|
32
38
|
});
|
|
33
39
|
const description = state.rows[state.index]?.description ?? "";
|
|
34
40
|
const hint = typeof state.hint === "string"
|
|
35
41
|
? theme.fg("dim", state.hint)
|
|
36
|
-
: renderShortcutHintsWithClose(state.hint, theme, contentWidth, 0);
|
|
42
|
+
: renderShortcutHintsWithClose(state.hint, theme, layout.contentWidth, 0);
|
|
37
43
|
const plainHint = typeof state.hint === "string" ? state.hint : " ".repeat(displayWidth(hint));
|
|
38
44
|
return [
|
|
39
|
-
rule,
|
|
40
|
-
contentRow(theme.bold(theme.fg("accent", state.title)), state.title),
|
|
41
|
-
contentRow(theme.fg("dim", description), description),
|
|
45
|
+
layout.rule,
|
|
46
|
+
layout.contentRow(theme.bold(theme.fg("accent", state.title)), state.title),
|
|
47
|
+
layout.contentRow(theme.fg("dim", description), description),
|
|
42
48
|
"",
|
|
43
49
|
...rows,
|
|
44
50
|
"",
|
|
45
|
-
contentRow(hint, plainHint),
|
|
46
|
-
rule,
|
|
51
|
+
layout.contentRow(hint, plainHint),
|
|
52
|
+
layout.rule,
|
|
47
53
|
];
|
|
48
54
|
}
|
|
49
55
|
/** Owned stepped-selector composition for structured settings with nested choices. */
|
|
50
56
|
export function renderSteppedDialogPanel(state, width, theme) {
|
|
51
|
-
const
|
|
52
|
-
const contentPadding = Math.min(1, Math.max(0, width));
|
|
53
|
-
const contentWidth = Math.max(0, width - contentPadding);
|
|
54
|
-
const inset = " ".repeat(contentPadding);
|
|
55
|
-
const contentRow = (painted, raw) => `${inset}${pad(truncateToWidth(painted, contentWidth), contentWidth, raw)}`;
|
|
57
|
+
const layout = dialogPanelLayout(width, theme);
|
|
56
58
|
const labelColumn = Math.min(STEPPED_LABEL_COLUMN_CAP, Math.max(0, ...state.rows.map(row => displayWidth(`${row.label}${row.labelSuffix ?? ""}`))));
|
|
57
59
|
const rows = state.rows.map((row, index) => {
|
|
58
60
|
const selected = index === state.index;
|
|
@@ -65,31 +67,34 @@ export function renderSteppedDialogPanel(state, width, theme) {
|
|
|
65
67
|
const content = selected
|
|
66
68
|
? `${theme.fg("accent", cursor)}${label}${theme.fg("muted", suffix)}`
|
|
67
69
|
: `${cursor}${label}${theme.fg("muted", suffix)}`;
|
|
68
|
-
return contentRow(selected ? theme.highlight(content) : content, raw);
|
|
70
|
+
return layout.contentRow(selected ? theme.highlight(content) : content, raw);
|
|
69
71
|
});
|
|
70
72
|
const input = state.input === undefined
|
|
71
73
|
? []
|
|
72
|
-
: [
|
|
74
|
+
: [
|
|
75
|
+
...renderInputRow(state.input, layout.contentWidth, {
|
|
76
|
+
ruled: false,
|
|
77
|
+
promptGlyph: "> ",
|
|
78
|
+
promptRole: "accent",
|
|
79
|
+
theme,
|
|
80
|
+
}).lines.map(row => layout.contentRow(row)),
|
|
81
|
+
"",
|
|
82
|
+
];
|
|
73
83
|
const step = `(step ${state.step}/${state.steps})`;
|
|
74
84
|
const title = `${state.title} ${step}`;
|
|
75
85
|
const paintedTitle = `${theme.bold(theme.fg("accent", state.title))} ${theme.fg("dim", step)}`;
|
|
76
86
|
return [
|
|
77
|
-
rule,
|
|
78
|
-
contentRow(paintedTitle, title),
|
|
79
|
-
contentRow(theme.fg("dim", state.description), state.description),
|
|
87
|
+
layout.rule,
|
|
88
|
+
layout.contentRow(paintedTitle, title),
|
|
89
|
+
layout.contentRow(theme.fg("dim", state.description), state.description),
|
|
80
90
|
"",
|
|
81
91
|
...input,
|
|
82
92
|
...rows,
|
|
83
93
|
"",
|
|
84
|
-
|
|
85
|
-
rule,
|
|
94
|
+
layout.contentRow(renderShortcutHintsWithClose(state.hint, theme, layout.contentWidth)),
|
|
95
|
+
layout.rule,
|
|
86
96
|
];
|
|
87
97
|
}
|
|
88
|
-
function renderSteppedHint(entries, width, theme) {
|
|
89
|
-
const raw = shortcutHintsText(entries, 1, " · ");
|
|
90
|
-
const painted = renderShortcutHints(entries, theme, 1, theme.fg("dim", " · "));
|
|
91
|
-
return `${truncateToWidth(painted, width)}${" ".repeat(Math.max(0, width - displayWidth(raw)))}`;
|
|
92
|
-
}
|
|
93
98
|
/** The row a pointer report lands on, or null when it is not on one. */
|
|
94
99
|
export function dialogRowAt(frame, row, column, valueWidth) {
|
|
95
100
|
const at = row - frame.firstRow;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PromptMarkerRole } from "./prompt-input.js";
|
|
1
2
|
import type { UiTheme } from "./theme.js";
|
|
2
3
|
export type LineInputOutcome = {
|
|
3
4
|
readonly kind: "editing";
|
|
@@ -60,6 +61,8 @@ export interface InputRowOptions {
|
|
|
60
61
|
readonly ruled?: boolean;
|
|
61
62
|
/** Prompt marker including any following spacing. Defaults to the shared prompt glyph. */
|
|
62
63
|
readonly promptGlyph?: string;
|
|
64
|
+
/** Semantic foreground for a configured prompt marker. */
|
|
65
|
+
readonly promptRole?: PromptMarkerRole;
|
|
63
66
|
readonly theme?: Pick<UiTheme, "fg">;
|
|
64
67
|
}
|
|
65
68
|
export interface InputRow {
|
|
@@ -220,5 +220,7 @@ export function renderInputRow(input, width, options = {}) {
|
|
|
220
220
|
const body = empty
|
|
221
221
|
? `${caretCell(placeholder.slice(0, 1))}${faint(placeholder.slice(1))}`
|
|
222
222
|
: `${before}${caretCell(under)}${after}`;
|
|
223
|
-
return {
|
|
223
|
+
return {
|
|
224
|
+
lines: presentation.render(width, () => ({ rows: [body] }), options.ruled, 0, options.promptGlyph, options.promptRole),
|
|
225
|
+
};
|
|
224
226
|
}
|
|
@@ -4,7 +4,8 @@ export declare const PROMPT_PREFIX_WIDTH = 0;
|
|
|
4
4
|
type RuleTheme = Pick<UiTheme, "fg">;
|
|
5
5
|
export declare function promptRuleText(text: string, theme: RuleTheme): string;
|
|
6
6
|
export declare function promptRule(width: number, theme: RuleTheme): string;
|
|
7
|
-
export
|
|
7
|
+
export type PromptMarkerRole = "muted" | "accent";
|
|
8
|
+
export declare function promptArrow(text: string, theme: RuleTheme, role?: PromptMarkerRole): string;
|
|
8
9
|
export interface PromptInputBody {
|
|
9
10
|
readonly rows: readonly string[];
|
|
10
11
|
/** Semantic border fragments retain editor history and scroll annotations. */
|
|
@@ -31,6 +32,6 @@ export declare class PromptInput {
|
|
|
31
32
|
contentWidth: number;
|
|
32
33
|
layoutWidth: number;
|
|
33
34
|
};
|
|
34
|
-
render(width: number, renderBody: (innerWidth: number) => PromptInputBody, ruled?: boolean, padding?: number, promptGlyph?: string): string[];
|
|
35
|
+
render(width: number, renderBody: (innerWidth: number) => PromptInputBody, ruled?: boolean, padding?: number, promptGlyph?: string, promptRole?: PromptMarkerRole): string[];
|
|
35
36
|
}
|
|
36
37
|
export {};
|
|
@@ -8,8 +8,10 @@ export function promptRuleText(text, theme) {
|
|
|
8
8
|
export function promptRule(width, theme) {
|
|
9
9
|
return promptRuleText("─".repeat(Math.max(0, width)), theme);
|
|
10
10
|
}
|
|
11
|
-
export function promptArrow(text, theme) {
|
|
12
|
-
|
|
11
|
+
export function promptArrow(text, theme, role = "muted") {
|
|
12
|
+
if (role === "accent" && text.startsWith(">"))
|
|
13
|
+
return `${theme.fg(role, ">")}${text.slice(1)}`;
|
|
14
|
+
return theme.fg(role, text);
|
|
13
15
|
}
|
|
14
16
|
/** Composes shared input chrome around controller-owned body rows without owning editing state. */
|
|
15
17
|
export class PromptInput {
|
|
@@ -26,7 +28,7 @@ export class PromptInput {
|
|
|
26
28
|
const contentWidth = Math.max(1, innerWidth - paddingX * 2);
|
|
27
29
|
return { prefixWidth, innerWidth, paddingX, contentWidth, layoutWidth: Math.max(1, contentWidth - (paddingX ? 0 : 1)) };
|
|
28
30
|
}
|
|
29
|
-
render(width, renderBody, ruled = true, padding = 0, promptGlyph = PROMPT_GLYPH) {
|
|
31
|
+
render(width, renderBody, ruled = true, padding = 0, promptGlyph = PROMPT_GLYPH, promptRole = "muted") {
|
|
30
32
|
if (width <= 0)
|
|
31
33
|
return [];
|
|
32
34
|
const { prefixWidth, innerWidth } = this.geometry(width, padding, promptGlyph);
|
|
@@ -40,7 +42,7 @@ export class PromptInput {
|
|
|
40
42
|
return clipped + " ".repeat(Math.max(0, width - this.metrics.measure(clipped)));
|
|
41
43
|
};
|
|
42
44
|
const rows = body.rows.map((row, index) => fit(`${index === 0
|
|
43
|
-
? promptArrow(promptGlyph, this.theme)
|
|
45
|
+
? promptArrow(promptGlyph, this.theme, promptRole)
|
|
44
46
|
: " ".repeat(prefixWidth)}${row}`));
|
|
45
47
|
const rule = (fragment) => fragment === undefined
|
|
46
48
|
? promptRule(width, this.theme)
|
|
@@ -29,10 +29,12 @@ export function withScrollbarRail(lines, geometry, contentWidth, theme, options
|
|
|
29
29
|
*/
|
|
30
30
|
export function renderEmptyState(message, mark, height, width, theme) {
|
|
31
31
|
const middle = Math.floor(height / 2);
|
|
32
|
+
const messageRow = Math.min(Math.max(0, height - 1), middle + 1);
|
|
33
|
+
const markRow = messageRow - 1;
|
|
32
34
|
return Array.from({ length: Math.max(0, height) }, (_line, index) => {
|
|
33
|
-
if (index ===
|
|
35
|
+
if (index === markRow)
|
|
34
36
|
return centre(theme.fg("muted", mark), mark, width);
|
|
35
|
-
return index ===
|
|
37
|
+
return index === messageRow ? centre(theme.fg("muted", message), message, width) : "";
|
|
36
38
|
});
|
|
37
39
|
}
|
|
38
40
|
function centre(painted, raw, width) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const OWNED_UI_SETTINGS_VERSION =
|
|
1
|
+
export declare const OWNED_UI_SETTINGS_VERSION = 19;
|
|
2
2
|
export type OwnedUiSettingValue = string | number | boolean;
|
|
3
3
|
export type OwnedUiSettingApplication = "live" | "restart";
|
|
4
4
|
export interface OwnedUiSettingDeclaration {
|
|
@@ -12,19 +12,28 @@ export interface OwnedUiSettingDeclaration {
|
|
|
12
12
|
readonly application: OwnedUiSettingApplication;
|
|
13
13
|
readonly defaultValue: OwnedUiSettingValue;
|
|
14
14
|
readonly allowedValues: readonly OwnedUiSettingValue[];
|
|
15
|
+
/**
|
|
16
|
+
* Parts of a structured setting, edited through their own dialog: the value is the comma-separated
|
|
17
|
+
* keys of the enabled parts in this order.
|
|
18
|
+
*/
|
|
19
|
+
readonly flags?: readonly {
|
|
20
|
+
readonly key: string;
|
|
21
|
+
readonly label: string;
|
|
22
|
+
readonly description: string;
|
|
23
|
+
}[];
|
|
15
24
|
}
|
|
16
25
|
export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
|
|
17
26
|
readonly updateCheck: Readonly<{
|
|
18
27
|
id: "updateCheck";
|
|
19
|
-
label: "Update
|
|
28
|
+
label: "Update";
|
|
20
29
|
section: Readonly<{
|
|
21
30
|
id: "generic";
|
|
22
31
|
title: "Generic";
|
|
23
32
|
}>;
|
|
24
|
-
description: "
|
|
33
|
+
description: "Auto installs verified channel updates silently, Notify shows the current update notice, and No leaves updates manual. Checks use the public npm registry; applies on next start.";
|
|
25
34
|
application: "restart";
|
|
26
|
-
defaultValue:
|
|
27
|
-
allowedValues: readonly [
|
|
35
|
+
defaultValue: "auto";
|
|
36
|
+
allowedValues: readonly ["auto", "notify", "no"];
|
|
28
37
|
}>;
|
|
29
38
|
readonly timeFormat: Readonly<{
|
|
30
39
|
id: "timeFormat";
|
|
@@ -117,11 +126,23 @@ export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
|
|
|
117
126
|
id: "history";
|
|
118
127
|
title: "History";
|
|
119
128
|
}>;
|
|
120
|
-
description: "Retain reusable prompts
|
|
129
|
+
description: "Retain reusable prompts after restart. Applies on next start; disabling does not erase saved history or stop existing instances.";
|
|
121
130
|
application: "restart";
|
|
122
131
|
defaultValue: true;
|
|
123
132
|
allowedValues: readonly [true, false];
|
|
124
133
|
}>;
|
|
134
|
+
readonly promptHistoryScope: Readonly<{
|
|
135
|
+
id: "promptHistoryScope";
|
|
136
|
+
label: "History scope";
|
|
137
|
+
section: Readonly<{
|
|
138
|
+
id: "history";
|
|
139
|
+
title: "History";
|
|
140
|
+
}>;
|
|
141
|
+
description: "Unique shows each agent session's history; Shared shows the profile-wide history. Switches running agents without moving or erasing saved prompts.";
|
|
142
|
+
application: "live";
|
|
143
|
+
defaultValue: "unique";
|
|
144
|
+
allowedValues: readonly ["unique", "shared"];
|
|
145
|
+
}>;
|
|
125
146
|
readonly promptHistoryMaxItems: Readonly<{
|
|
126
147
|
id: "promptHistoryMaxItems";
|
|
127
148
|
label: "History limit";
|
|
@@ -175,19 +196,44 @@ export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
|
|
|
175
196
|
label: "Position";
|
|
176
197
|
section: Readonly<{
|
|
177
198
|
id: "tabs";
|
|
178
|
-
title: "
|
|
199
|
+
title: "Tab Bar";
|
|
179
200
|
}>;
|
|
180
201
|
description: "Place the resident tab bar at the top or bottom of the terminal.";
|
|
181
202
|
application: "live";
|
|
182
203
|
defaultValue: "top";
|
|
183
204
|
allowedValues: readonly ["top", "bottom"];
|
|
184
205
|
}>;
|
|
206
|
+
readonly tabBarPlusMenu: Readonly<{
|
|
207
|
+
id: "tabBarPlusMenu";
|
|
208
|
+
label: "Plus menu";
|
|
209
|
+
section: Readonly<{
|
|
210
|
+
id: "tabs";
|
|
211
|
+
title: "Tab Bar";
|
|
212
|
+
}>;
|
|
213
|
+
description: "The tabs + offers. With only Agent, + adds an Agent at once; with more, it opens a menu; with none, + is hidden.";
|
|
214
|
+
application: "live";
|
|
215
|
+
defaultValue: "agent";
|
|
216
|
+
allowedValues: readonly ["", "agent", "settings", "changelog", "agent,settings", "agent,changelog", "settings,changelog", "agent,settings,changelog"];
|
|
217
|
+
flags: readonly (Readonly<{
|
|
218
|
+
key: "agent";
|
|
219
|
+
label: "Agent";
|
|
220
|
+
description: "Add a new Agent tab every time.";
|
|
221
|
+
}> | Readonly<{
|
|
222
|
+
key: "settings";
|
|
223
|
+
label: "Settings";
|
|
224
|
+
description: "Show the one Settings tab.";
|
|
225
|
+
}> | Readonly<{
|
|
226
|
+
key: "changelog";
|
|
227
|
+
label: "Changelog";
|
|
228
|
+
description: "Show the one Changelog tab.";
|
|
229
|
+
}>)[];
|
|
230
|
+
}>;
|
|
185
231
|
readonly tabsAutoName: Readonly<{
|
|
186
232
|
id: "tabsAutoName";
|
|
187
233
|
label: "Auto name";
|
|
188
234
|
section: Readonly<{
|
|
189
235
|
id: "tabs";
|
|
190
|
-
title: "
|
|
236
|
+
title: "Tab Bar";
|
|
191
237
|
}>;
|
|
192
238
|
description: "Automatically name a new tab from its first completed turn with the tab's current model.";
|
|
193
239
|
application: "live";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const OWNED_UI_SETTINGS_VERSION =
|
|
1
|
+
export const OWNED_UI_SETTINGS_VERSION = 19;
|
|
2
2
|
const UI_ACCENT_COLOR_CHOICES = Object.freeze([
|
|
3
3
|
"purple", "blue", "cyan", "green", "orange", "pink",
|
|
4
4
|
]);
|
|
@@ -8,16 +8,26 @@ const GENERIC_SECTION = Object.freeze({ id: "generic", title: "Generic" });
|
|
|
8
8
|
const APPEARANCE_SECTION = Object.freeze({ id: "appearance", title: "Appearance" });
|
|
9
9
|
const SCROLL_SECTION = Object.freeze({ id: "scroll", title: "Scroll" });
|
|
10
10
|
const AGENT_SECTION = Object.freeze({ id: "agent", title: "Agent" });
|
|
11
|
-
const TABS_SECTION = Object.freeze({ id: "tabs", title: "
|
|
11
|
+
const TABS_SECTION = Object.freeze({ id: "tabs", title: "Tab Bar" });
|
|
12
|
+
/** The tab kinds the strip's `+` can offer, in the order it shows them. */
|
|
13
|
+
const PLUS_MENU_KINDS = Object.freeze([
|
|
14
|
+
Object.freeze({ key: "agent", label: "Agent", description: "Add a new Agent tab every time." }),
|
|
15
|
+
Object.freeze({ key: "settings", label: "Settings", description: "Show the one Settings tab." }),
|
|
16
|
+
Object.freeze({ key: "changelog", label: "Changelog", description: "Show the one Changelog tab." }),
|
|
17
|
+
]);
|
|
18
|
+
/** Every enabled subset of the plus-menu kinds, each in kind order. */
|
|
19
|
+
const PLUS_MENU_VALUES = Object.freeze([
|
|
20
|
+
"", "agent", "settings", "changelog", "agent,settings", "agent,changelog", "settings,changelog", "agent,settings,changelog",
|
|
21
|
+
]);
|
|
12
22
|
export const OWNED_SETTING_DECLARATIONS = Object.freeze({
|
|
13
23
|
updateCheck: Object.freeze({
|
|
14
24
|
id: "updateCheck",
|
|
15
|
-
label: "Update
|
|
25
|
+
label: "Update",
|
|
16
26
|
section: GENERIC_SECTION,
|
|
17
|
-
description: "
|
|
27
|
+
description: "Auto installs verified channel updates silently, Notify shows the current update notice, and No leaves updates manual. Checks use the public npm registry; applies on next start.",
|
|
18
28
|
application: "restart",
|
|
19
|
-
defaultValue:
|
|
20
|
-
allowedValues: Object.freeze([
|
|
29
|
+
defaultValue: "auto",
|
|
30
|
+
allowedValues: Object.freeze(["auto", "notify", "no"]),
|
|
21
31
|
}),
|
|
22
32
|
timeFormat: Object.freeze({
|
|
23
33
|
id: "timeFormat",
|
|
@@ -90,11 +100,20 @@ export const OWNED_SETTING_DECLARATIONS = Object.freeze({
|
|
|
90
100
|
id: "promptHistoryEnabled",
|
|
91
101
|
label: "Persistent history",
|
|
92
102
|
section: Object.freeze({ id: "history", title: "History" }),
|
|
93
|
-
description: "Retain reusable prompts
|
|
103
|
+
description: "Retain reusable prompts after restart. Applies on next start; disabling does not erase saved history or stop existing instances.",
|
|
94
104
|
application: "restart",
|
|
95
105
|
defaultValue: true,
|
|
96
106
|
allowedValues: Object.freeze([true, false]),
|
|
97
107
|
}),
|
|
108
|
+
promptHistoryScope: Object.freeze({
|
|
109
|
+
id: "promptHistoryScope",
|
|
110
|
+
label: "History scope",
|
|
111
|
+
section: Object.freeze({ id: "history", title: "History" }),
|
|
112
|
+
description: "Unique shows each agent session's history; Shared shows the profile-wide history. Switches running agents without moving or erasing saved prompts.",
|
|
113
|
+
application: "live",
|
|
114
|
+
defaultValue: "unique",
|
|
115
|
+
allowedValues: Object.freeze(["unique", "shared"]),
|
|
116
|
+
}),
|
|
98
117
|
promptHistoryMaxItems: Object.freeze({
|
|
99
118
|
id: "promptHistoryMaxItems",
|
|
100
119
|
label: "History limit",
|
|
@@ -140,6 +159,16 @@ export const OWNED_SETTING_DECLARATIONS = Object.freeze({
|
|
|
140
159
|
defaultValue: "top",
|
|
141
160
|
allowedValues: Object.freeze(["top", "bottom"]),
|
|
142
161
|
}),
|
|
162
|
+
tabBarPlusMenu: Object.freeze({
|
|
163
|
+
id: "tabBarPlusMenu",
|
|
164
|
+
label: "Plus menu",
|
|
165
|
+
section: TABS_SECTION,
|
|
166
|
+
description: "The tabs + offers. With only Agent, + adds an Agent at once; with more, it opens a menu; with none, + is hidden.",
|
|
167
|
+
application: "live",
|
|
168
|
+
defaultValue: "agent",
|
|
169
|
+
allowedValues: PLUS_MENU_VALUES,
|
|
170
|
+
flags: PLUS_MENU_KINDS,
|
|
171
|
+
}),
|
|
143
172
|
tabsAutoName: Object.freeze({
|
|
144
173
|
id: "tabsAutoName",
|
|
145
174
|
label: "Auto name",
|
|
@@ -188,9 +188,13 @@ export class OwnedSettingsManager {
|
|
|
188
188
|
return () => this.#listeners.delete(listener);
|
|
189
189
|
}
|
|
190
190
|
async changeStructured(backend, id, value) {
|
|
191
|
-
if (backend
|
|
192
|
-
return
|
|
193
|
-
|
|
191
|
+
if (backend === "agent")
|
|
192
|
+
return await this.#changeAgentValue(id, value);
|
|
193
|
+
// Invariant: a flagged A1 setting stores its enabled parts as one value, in declaration order.
|
|
194
|
+
const flags = findOwnedUiSettingsEntry(this.sections(), id, "a1")?.flags ?? [];
|
|
195
|
+
if (flags.length === 0)
|
|
196
|
+
return failed(`${id} holds no structured value`);
|
|
197
|
+
return await this.change("a1", id, flags.filter(flag => value[flag.key] === true).map(flag => flag.key).join(","));
|
|
194
198
|
}
|
|
195
199
|
async change(backend, id, value) {
|
|
196
200
|
const entry = findOwnedUiSettingsEntry(this.sections(), id, backend);
|
|
@@ -144,6 +144,17 @@ export const OWNED_UI_SETTINGS_MIGRATIONS = Object.freeze([
|
|
|
144
144
|
return { ...values };
|
|
145
145
|
},
|
|
146
146
|
}),
|
|
147
|
+
Object.freeze({
|
|
148
|
+
to: 19,
|
|
149
|
+
description: "Expand the update check into auto, notify, and no modes.",
|
|
150
|
+
migrate(values) {
|
|
151
|
+
if (values.updateCheck === true)
|
|
152
|
+
return { ...values, updateCheck: "notify" };
|
|
153
|
+
if (values.updateCheck === false)
|
|
154
|
+
return { ...values, updateCheck: "no" };
|
|
155
|
+
return { ...values };
|
|
156
|
+
},
|
|
157
|
+
}),
|
|
147
158
|
]);
|
|
148
159
|
/** Shape-selected compatibility for the metadata-free product object. */
|
|
149
160
|
export function normalizeOwnedUiSettingsValues(source) {
|
|
@@ -153,6 +164,10 @@ export function normalizeOwnedUiSettingsValues(source) {
|
|
|
153
164
|
values.scrollbarAppearance = "auto";
|
|
154
165
|
if (values.accentColor === "default")
|
|
155
166
|
values.accentColor = "purple";
|
|
167
|
+
if (values.updateCheck === true)
|
|
168
|
+
values.updateCheck = "notify";
|
|
169
|
+
else if (values.updateCheck === false)
|
|
170
|
+
values.updateCheck = "no";
|
|
156
171
|
if (values.quitEffect === "off") {
|
|
157
172
|
if (Object.hasOwn(values, "quitAnimation") && values.quitAnimation !== false) {
|
|
158
173
|
return { values: null, failure: "legacy quitEffect conflicts with quitAnimation" };
|
|
@@ -49,4 +49,8 @@ export interface BuildOwnedUiSettingsSectionsInput {
|
|
|
49
49
|
}
|
|
50
50
|
export declare const AGENT_SECTION_ID = "agent";
|
|
51
51
|
export declare function buildOwnedUiSettingsSections(input: BuildOwnedUiSettingsSectionsInput): readonly OwnedUiSettingsSection[];
|
|
52
|
+
/** The enabled parts a flagged A1 setting's comma-separated value names, as the record its dialog edits. */
|
|
53
|
+
export declare function flagRecord(flags: readonly {
|
|
54
|
+
readonly key: string;
|
|
55
|
+
}[], value: unknown): Record<string, boolean>;
|
|
52
56
|
export declare function findOwnedUiSettingsEntry(sections: readonly OwnedUiSettingsSection[], id: string, backend: OwnedUiSettingsBackend): OwnedUiSettingsEntry | null;
|
|
@@ -5,20 +5,21 @@ export function buildOwnedUiSettingsSections(input) {
|
|
|
5
5
|
for (const setting of input.resolution.settings) {
|
|
6
6
|
const section = setting.declaration.section ?? { id: "a1", title: "A1" };
|
|
7
7
|
const group = grouped.get(section.id) ?? { title: section.title, entries: [] };
|
|
8
|
+
const flagged = setting.declaration.flags;
|
|
8
9
|
group.entries.push({
|
|
9
10
|
id: setting.declaration.id,
|
|
10
11
|
label: setting.declaration.label ?? null,
|
|
11
12
|
backend: "a1",
|
|
12
13
|
description: setting.declaration.description,
|
|
13
14
|
value: setting.value,
|
|
14
|
-
rawValue: setting.value,
|
|
15
|
+
rawValue: flagged === undefined ? setting.value : flagRecord(flagged, setting.value),
|
|
15
16
|
storedValue: setting.value,
|
|
16
17
|
effectiveValue: setting.value,
|
|
17
18
|
editable: true,
|
|
18
|
-
structured:
|
|
19
|
+
structured: flagged !== undefined,
|
|
19
20
|
minimum: null,
|
|
20
21
|
maximum: null,
|
|
21
|
-
flags: [],
|
|
22
|
+
flags: flagged?.map(flag => ({ ...flag, fallback: false })) ?? [],
|
|
22
23
|
choices: setting.declaration.allowedValues,
|
|
23
24
|
origin: setting.source,
|
|
24
25
|
application: setting.declaration.application === "restart" ? "next-start" : "live",
|
|
@@ -44,6 +45,11 @@ export function buildOwnedUiSettingsSections(input) {
|
|
|
44
45
|
};
|
|
45
46
|
return Object.freeze([...ownedSections, combinedAgent]);
|
|
46
47
|
}
|
|
48
|
+
/** The enabled parts a flagged A1 setting's comma-separated value names, as the record its dialog edits. */
|
|
49
|
+
export function flagRecord(flags, value) {
|
|
50
|
+
const enabled = new Set(typeof value === "string" ? value.split(",") : []);
|
|
51
|
+
return Object.fromEntries(flags.map(flag => [flag.key, enabled.has(flag.key)]));
|
|
52
|
+
}
|
|
47
53
|
export function findOwnedUiSettingsEntry(sections, id, backend) {
|
|
48
54
|
for (const section of sections) {
|
|
49
55
|
const entry = section.entries.find(candidate => candidate.id === id && candidate.backend === backend);
|