@timurproko/a1 0.2.7-dev.820 → 0.2.7-dev.828
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/tab-launch-context.d.ts +1 -0
- package/bin/tab-launch-context.js +3 -3
- package/bin/ui.js +96 -66
- package/dist/app/session-shell/session-shell-root.d.ts +13 -6
- package/dist/app/session-shell/session-shell-root.js +9 -5
- package/dist/app/session-shell/session-shell.js +68 -18
- package/dist/app/session-shell/shell-host.js +6 -3
- package/dist/app/session-shell/transcript-document.js +1 -1
- package/dist/cli/tabs.d.ts +1 -1
- package/dist/cli/tabs.js +10 -14
- package/dist/composition/owned-settings.d.ts +12 -0
- package/dist/composition/owned-settings.js +36 -0
- package/dist/composition/owned-ui.d.ts +5 -14
- package/dist/composition/owned-ui.js +93 -63
- 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/composition/utility-tab.d.ts +28 -0
- package/dist/composition/utility-tab.js +242 -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/project-trust-dialog.d.ts +1 -1
- package/dist/features/owned-ui/project-trust-dialog.js +6 -8
- package/dist/features/owned-ui/project-trust-prompt.d.ts +1 -0
- package/dist/features/owned-ui/project-trust-prompt.js +7 -3
- 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/lifecycle/session-repository-context.js +16 -2
- 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/early-accent.d.ts +12 -0
- package/dist/foundation/release/early-accent.js +59 -0
- 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/progress-palette.generated.d.ts +137 -3
- package/dist/foundation/release/progress-palette.generated.js +137 -3
- package/dist/foundation/release/release-gc.js +19 -4
- 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 +9 -7
- package/dist/foundation/release/update.js +244 -175
- package/dist/foundation/resident-tabs/bridge-client.d.ts +9 -2
- package/dist/foundation/resident-tabs/bridge-client.js +19 -7
- package/dist/foundation/resident-tabs/maintenance.d.ts +2 -6
- package/dist/foundation/resident-tabs/maintenance.js +5 -23
- package/dist/foundation/resident-tabs/progress-observation-schema.d.ts +34 -0
- package/dist/foundation/resident-tabs/progress-observation-schema.js +1 -0
- package/dist/foundation/resident-tabs/progress-observation.d.ts +3 -6
- package/dist/foundation/resident-tabs/progress-observation.js +43 -12
- package/dist/foundation/resident-tabs/release-holds.js +3 -14
- 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/components/upstream/theme/theme.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/theme/theme.js +5 -1
- package/dist/integrations/pi/engine/adapter.js +7 -2
- package/dist/integrations/pi/engine/offline-settings-port.d.ts +23 -0
- package/dist/integrations/pi/engine/offline-settings-port.js +53 -0
- package/dist/integrations/pi/engine/ports.d.ts +1 -1
- package/dist/integrations/pi/engine/ports.js +4 -0
- package/dist/integrations/pi/engine/settings-bridge.d.ts +5 -0
- package/dist/integrations/pi/engine/settings-bridge.js +13 -0
- package/dist/integrations/pi/engine/settings-port.js +1 -14
- 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 +2 -2
- package/dist/product-identity.json +2 -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/spans.js +2 -2
- package/dist/ui/components/surface.js +4 -2
- package/dist/ui/components/text.d.ts +3 -6
- package/dist/ui/components/text.js +6 -8
- package/dist/ui/settings/declarations.d.ts +56 -10
- package/dist/ui/settings/declarations.js +38 -9
- package/dist/ui/settings/early-accent.d.ts +81 -0
- package/dist/ui/settings/early-accent.js +50 -0
- package/dist/ui/settings/manager.js +7 -3
- package/dist/ui/settings/migrations.js +15 -0
- package/dist/ui/settings/progress-palette.generated.d.ts +139 -0
- package/dist/ui/settings/progress-palette.generated.js +139 -0
- package/dist/ui/settings/sections.d.ts +4 -0
- package/dist/ui/settings/sections.js +9 -3
- package/docs/architecture/resident-tabs.md +48 -17
- package/docs/architecture/tool-image-presentation.md +2 -1
- package/docs/features/prompt-history.md +41 -20
- package/docs/validation.md +25 -5
- package/package.json +1 -1
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { MAX_CLIPBOARD_TEXT_BYTES } from "../contracts/owned-ui/index.js";
|
|
4
|
+
import { writeSystemClipboardText } from "../app/session-shell/system-clipboard.js";
|
|
5
|
+
import { OwnedUiTerminalHost, } from "../app/session-shell/shell-host.js";
|
|
6
|
+
import { nativeHyperlinkStyle } from "../ui/components/spans.js";
|
|
7
|
+
import { createPiKeybindingsHost } from "../integrations/pi/components/shell-shared-facade.js";
|
|
8
|
+
import { applyConfiguredPiTheme, setPiAccentColor, setPiPackageBorderProjectionEnabled } from "../integrations/pi/components/upstream/theme/theme.js";
|
|
9
|
+
import { createPiTerminalBridge } from "../integrations/pi/tui-runtime/presentation-adapter.js";
|
|
10
|
+
import { resolveLaunchProfilePaths } from "../features/launch/profile-paths.js";
|
|
11
|
+
import { createOwnedSettingsManager, watchSharedSettings } from "./owned-settings.js";
|
|
12
|
+
import { residentRouteHostOptions, residentTabKeybindings } from "./resident-tab-bridge.js";
|
|
13
|
+
import { createOwnedRouteHost } from "./settings-route-host.js";
|
|
14
|
+
import { runOwnedUi, terminateOwnedUiProcess } from "../features/owned-ui/run.js";
|
|
15
|
+
export { terminateOwnedUiProcess };
|
|
16
|
+
/** Runs one pinned Settings or Changelog screen without constructing an Agent engine or session. */
|
|
17
|
+
export async function runUtilityTab(options) {
|
|
18
|
+
const composition = await composeUtilityTab(options);
|
|
19
|
+
options.onApplication?.(composition.application);
|
|
20
|
+
return await runOwnedUi(composition);
|
|
21
|
+
}
|
|
22
|
+
export async function composeUtilityTab(options) {
|
|
23
|
+
const cwd = options.cwd ?? process.cwd();
|
|
24
|
+
const agentDir = options.agentDir ?? utilityAgentDir();
|
|
25
|
+
const { settings, offline } = await prepareUtilitySettings(options, cwd, agentDir);
|
|
26
|
+
await options.bridge.start().catch(() => false);
|
|
27
|
+
options.bridge.status("starting");
|
|
28
|
+
applyUtilityTheme(settings, options.bridge);
|
|
29
|
+
const keybindings = residentTabKeybindings(options.bridge, agentDir, createPiKeybindingsHost({ profile: "a1", agentDir }));
|
|
30
|
+
const routeHost = options.routeHost ?? createUtilityRouteHost(options, settings, keybindings, cwd, agentDir);
|
|
31
|
+
return {
|
|
32
|
+
settings,
|
|
33
|
+
application: createUtilityApplication(options, settings, offline, routeHost),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function prepareUtilitySettings(options, cwd, agentDir) {
|
|
37
|
+
const offline = options.settings === undefined && options.route === "settings"
|
|
38
|
+
? await import("../integrations/pi/engine/offline-settings-port.js")
|
|
39
|
+
.then(module => module.createOfflinePiSettingsPort({ cwd, agentDir }))
|
|
40
|
+
: null;
|
|
41
|
+
return {
|
|
42
|
+
offline,
|
|
43
|
+
settings: options.settings ?? createOwnedSettingsManager({
|
|
44
|
+
profileId: options.profileId ?? "a1",
|
|
45
|
+
agent: offline?.port ?? null,
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function applyUtilityTheme(settings, bridge) {
|
|
50
|
+
setPiPackageBorderProjectionEnabled(true);
|
|
51
|
+
setPiAccentColor(settings.value("accentColor"));
|
|
52
|
+
applyConfiguredPiTheme("dark");
|
|
53
|
+
bridge.accent(settings.value("accentColor"));
|
|
54
|
+
}
|
|
55
|
+
function createUtilityRouteHost(options, settings, keybindings, cwd, agentDir) {
|
|
56
|
+
let catalog;
|
|
57
|
+
const releaseNoteCatalog = () => catalog ??= options.releaseNotes === undefined
|
|
58
|
+
? import("../features/owned-ui/release-notes.js").then(module => module.readPackagedReleaseNotes())
|
|
59
|
+
: Promise.resolve(options.releaseNotes);
|
|
60
|
+
return pinnedRouteHost(options.route, createOwnedRouteHost(settings, {
|
|
61
|
+
changelog: async () => {
|
|
62
|
+
const [notes, { renderPiShellChangelogLines }] = await Promise.all([
|
|
63
|
+
releaseNoteCatalog(),
|
|
64
|
+
import("../integrations/pi/components/shell-presenters-info.js"),
|
|
65
|
+
]);
|
|
66
|
+
return { rows: width => renderPiShellChangelogLines(notes.completeMarkdown, width).map(row => nativeHyperlinkStyle(row)) };
|
|
67
|
+
},
|
|
68
|
+
hotkeys: async () => { throw new Error("hotkeys are unavailable in a utility tab"); },
|
|
69
|
+
session: async () => { throw new Error("session information is unavailable in a utility tab"); },
|
|
70
|
+
}, {
|
|
71
|
+
...residentRouteHostOptions(options.bridge),
|
|
72
|
+
keybindings,
|
|
73
|
+
agentDir,
|
|
74
|
+
cwd,
|
|
75
|
+
copyText: text => {
|
|
76
|
+
if (Buffer.byteLength(text) <= MAX_CLIPBOARD_TEXT_BYTES)
|
|
77
|
+
void writeSystemClipboardText(text).catch(() => { });
|
|
78
|
+
},
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
function createUtilityApplication(options, settings, offline, routeHost) {
|
|
82
|
+
const backgroundSettings = {
|
|
83
|
+
snapshot: () => settings.value("backgroundStyle"),
|
|
84
|
+
onChange: listener => settings.onChange(current => listener(current.value("backgroundStyle"))),
|
|
85
|
+
};
|
|
86
|
+
const terminalHost = new OwnedUiTerminalHost({
|
|
87
|
+
layout: "custom-viewport", mode: "fullscreen", hardwareCursor: false,
|
|
88
|
+
...(options.terminal === undefined ? {} : { terminal: createPiTerminalBridge(options.terminal) }),
|
|
89
|
+
backgroundSettings,
|
|
90
|
+
});
|
|
91
|
+
const presenter = new UtilityTabPresenter(terminalHost, routeHost, options.route, options.bridge);
|
|
92
|
+
const removeBoundaryInput = terminalHost.runtime.addPreInputListener(data => ({ data: options.bridge.consumeControllerBoundaryInput(data) }));
|
|
93
|
+
const unwatchSettings = watchSharedSettings(settings);
|
|
94
|
+
const unsubscribeAccent = settings.onChange(current => {
|
|
95
|
+
const accent = current.value("accentColor");
|
|
96
|
+
setPiAccentColor(accent);
|
|
97
|
+
options.bridge.accent(accent);
|
|
98
|
+
});
|
|
99
|
+
let disposed = false;
|
|
100
|
+
let started = false;
|
|
101
|
+
let stopResolve;
|
|
102
|
+
let unsubscribeBridge = () => { };
|
|
103
|
+
const stopped = new Promise(resolvePromise => { stopResolve = resolvePromise; });
|
|
104
|
+
return {
|
|
105
|
+
get disposed() { return disposed; },
|
|
106
|
+
start: () => {
|
|
107
|
+
if (started || disposed)
|
|
108
|
+
return;
|
|
109
|
+
started = true;
|
|
110
|
+
presenter.start();
|
|
111
|
+
terminalHost.attach(presenter);
|
|
112
|
+
unsubscribeBridge = options.bridge.onCommand(command => handleBridgeCommand(command, presenter, options.route, () => {
|
|
113
|
+
stopResolve();
|
|
114
|
+
void terminalHost.dispose().catch(() => undefined);
|
|
115
|
+
}));
|
|
116
|
+
options.bridge.status("idle");
|
|
117
|
+
void offline?.modelsReady.then(() => settings.load()).catch(() => undefined);
|
|
118
|
+
},
|
|
119
|
+
flush: async () => { },
|
|
120
|
+
waitUntilStopped: () => stopped,
|
|
121
|
+
dispose: async () => {
|
|
122
|
+
if (disposed)
|
|
123
|
+
return;
|
|
124
|
+
disposed = true;
|
|
125
|
+
stopResolve();
|
|
126
|
+
unsubscribeBridge();
|
|
127
|
+
unsubscribeAccent();
|
|
128
|
+
unwatchSettings();
|
|
129
|
+
removeBoundaryInput();
|
|
130
|
+
try {
|
|
131
|
+
await terminalHost.dispose();
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
options.bridge.close();
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function pinnedRouteHost(route, host) {
|
|
140
|
+
return {
|
|
141
|
+
claims: candidate => candidate === route && host.claims(candidate),
|
|
142
|
+
open: (candidate, input) => candidate === route ? host.open(candidate, input) : null,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function handleBridgeCommand(command, presenter, route, stop) {
|
|
146
|
+
if (command.type === "stop")
|
|
147
|
+
stop();
|
|
148
|
+
else if (command.type === "route" && command.route === route)
|
|
149
|
+
presenter.presentRoute();
|
|
150
|
+
}
|
|
151
|
+
export function utilityAgentDir(environment = process.env) {
|
|
152
|
+
const configured = environment.PI_CODING_AGENT_DIR;
|
|
153
|
+
if (configured !== undefined && configured.trim().length > 0) {
|
|
154
|
+
return resolve(configured.startsWith("~/") || configured.startsWith("~\\")
|
|
155
|
+
? `${homedir()}${configured.slice(1)}`
|
|
156
|
+
: configured);
|
|
157
|
+
}
|
|
158
|
+
return resolveLaunchProfilePaths().agentProfile;
|
|
159
|
+
}
|
|
160
|
+
class UtilityTabPresenter {
|
|
161
|
+
#host;
|
|
162
|
+
#terminal;
|
|
163
|
+
#routeHost;
|
|
164
|
+
#route;
|
|
165
|
+
#bridge;
|
|
166
|
+
#surface = null;
|
|
167
|
+
#routeHandle = null;
|
|
168
|
+
#released = false;
|
|
169
|
+
constructor(host, routeHost, route, bridge) {
|
|
170
|
+
this.#host = host;
|
|
171
|
+
this.#routeHost = routeHost;
|
|
172
|
+
this.#route = route;
|
|
173
|
+
this.#bridge = bridge;
|
|
174
|
+
this.#terminal = host.connect(this);
|
|
175
|
+
}
|
|
176
|
+
render(_width) { return []; }
|
|
177
|
+
handleInput(_data) { }
|
|
178
|
+
invalidate() { this.#terminal.requestRender(); }
|
|
179
|
+
setFocused(_focused) { }
|
|
180
|
+
inputCoordinationSurface() { return "owned"; }
|
|
181
|
+
setOverlaySurfaces(_surfaces) { }
|
|
182
|
+
noteImmediatePresentation() { }
|
|
183
|
+
handleViewportInput(_data) { return undefined; }
|
|
184
|
+
layoutPart(_part) { return EMPTY_COMPONENT; }
|
|
185
|
+
activated() { this.presentRoute(); }
|
|
186
|
+
start() { this.#terminal.start(); }
|
|
187
|
+
waitUntilStopped() { return new Promise(() => { }); }
|
|
188
|
+
dispose() { return this.#host.close(this); }
|
|
189
|
+
presentRoute() {
|
|
190
|
+
if (this.#released || this.#routeHandle !== null)
|
|
191
|
+
return;
|
|
192
|
+
if (!this.#terminal.running || !this.#terminal.attached)
|
|
193
|
+
return;
|
|
194
|
+
const surface = this.#routeHost.open(this.#route);
|
|
195
|
+
if (surface === null)
|
|
196
|
+
throw new Error(`utility route is unavailable: ${this.#route}`);
|
|
197
|
+
this.#surface = surface;
|
|
198
|
+
let exitRequested = false;
|
|
199
|
+
const handle = this.#terminal.openRoute(surface, {
|
|
200
|
+
closed: rendered => {
|
|
201
|
+
if (this.#routeHandle === handle)
|
|
202
|
+
this.#routeHandle = null;
|
|
203
|
+
this.#surface = null;
|
|
204
|
+
queueMicrotask(() => {
|
|
205
|
+
if (rendered && !exitRequested)
|
|
206
|
+
void this.#bridge.requestClose();
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
exit: () => {
|
|
210
|
+
exitRequested = true;
|
|
211
|
+
void this.#bridge.requestDetach().then(() => this.presentRoute(), () => this.presentRoute());
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
this.#routeHandle = handle;
|
|
215
|
+
}
|
|
216
|
+
release() {
|
|
217
|
+
if (this.#released)
|
|
218
|
+
return { exitText: "", failures: [], settle: async () => [] };
|
|
219
|
+
this.#released = true;
|
|
220
|
+
const failures = [];
|
|
221
|
+
try {
|
|
222
|
+
this.#routeHandle?.hide();
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
failures.push(error);
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
this.#surface?.close();
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
failures.push(error);
|
|
232
|
+
}
|
|
233
|
+
this.#routeHandle = null;
|
|
234
|
+
this.#surface = null;
|
|
235
|
+
return { exitText: "", failures, settle: async () => [] };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const EMPTY_COMPONENT = {
|
|
239
|
+
render: () => [],
|
|
240
|
+
handleInput: () => { },
|
|
241
|
+
invalidate: () => { },
|
|
242
|
+
};
|
|
@@ -37,6 +37,8 @@ export interface OwnedUiSessionIdentityPort {
|
|
|
37
37
|
readonly sessionBindingGeneration: number;
|
|
38
38
|
readonly disposed: boolean;
|
|
39
39
|
currentSessionFile(): string | null;
|
|
40
|
+
/** The durable conversation identity; unlike sessionId it survives agent process restart. */
|
|
41
|
+
currentHistorySessionId(): string | null;
|
|
40
42
|
currentSessionResumeMetadata(): OwnedUiSessionResumeMetadata | null;
|
|
41
43
|
}
|
|
42
44
|
/** The session lifecycle, its view, its event stream, and command admission. */
|
|
@@ -337,9 +337,13 @@ export interface OwnedUiVisualExtensionSupport {
|
|
|
337
337
|
readonly renderCallbacks: typeof OWNED_UI_EXTENSION_RENDER_CALLBACKS;
|
|
338
338
|
readonly diagnostic: string;
|
|
339
339
|
}
|
|
340
|
-
/** A newer release found by the startup check. */
|
|
341
|
-
export
|
|
340
|
+
/** A newer release found by the startup check, or one installed for the next restart. */
|
|
341
|
+
export type OwnedUiReleaseUpdate = {
|
|
342
|
+
readonly status?: "available";
|
|
342
343
|
readonly version: string;
|
|
343
344
|
readonly command: string;
|
|
344
345
|
readonly changelogUrl: string | null;
|
|
345
|
-
}
|
|
346
|
+
} | {
|
|
347
|
+
readonly status: "installed";
|
|
348
|
+
readonly version: string;
|
|
349
|
+
};
|
|
@@ -14,6 +14,17 @@ export declare const DIALOG_BACK_SHORTCUT_HINT: Readonly<{
|
|
|
14
14
|
key: string;
|
|
15
15
|
action: string;
|
|
16
16
|
}>;
|
|
17
|
+
/** Global inset inherited by every semantic row inside an A1-owned dialog frame. */
|
|
18
|
+
export declare const DIALOG_CONTENT_PADDING_X = 1;
|
|
19
|
+
export interface DialogFrameGeometry {
|
|
20
|
+
readonly frameWidth: number;
|
|
21
|
+
readonly contentPaddingX: number;
|
|
22
|
+
readonly contentWidth: number;
|
|
23
|
+
}
|
|
24
|
+
/** Shared full-width-rule/content-width geometry for string and component dialog renderers. */
|
|
25
|
+
export declare function dialogFrameGeometry(width: number): DialogFrameGeometry;
|
|
26
|
+
/** Injects a semantic row into the frame's global content inset. */
|
|
27
|
+
export declare function insetDialogContent(row: string, geometry: DialogFrameGeometry): string;
|
|
17
28
|
export interface ShortcutHintRoles {
|
|
18
29
|
key(label: string): string;
|
|
19
30
|
action(name: string): string;
|
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
export const DIALOG_CLOSE_SHORTCUT_HINT = Object.freeze({ key: "esc", action: "close" });
|
|
3
3
|
/** Canonical return guidance for a nested step within a dialog surface. */
|
|
4
4
|
export const DIALOG_BACK_SHORTCUT_HINT = Object.freeze({ key: "esc", action: "back" });
|
|
5
|
+
/** Global inset inherited by every semantic row inside an A1-owned dialog frame. */
|
|
6
|
+
export const DIALOG_CONTENT_PADDING_X = 1;
|
|
7
|
+
/** Shared full-width-rule/content-width geometry for string and component dialog renderers. */
|
|
8
|
+
export function dialogFrameGeometry(width) {
|
|
9
|
+
const frameWidth = Math.max(0, width);
|
|
10
|
+
const contentPaddingX = Math.min(DIALOG_CONTENT_PADDING_X, frameWidth);
|
|
11
|
+
return { frameWidth, contentPaddingX, contentWidth: frameWidth - contentPaddingX };
|
|
12
|
+
}
|
|
13
|
+
/** Injects a semantic row into the frame's global content inset. */
|
|
14
|
+
export function insetDialogContent(row, geometry) {
|
|
15
|
+
return `${" ".repeat(geometry.contentPaddingX)}${row}`;
|
|
16
|
+
}
|
|
5
17
|
const SHORTCUT_KEY_NAMES = Object.freeze({
|
|
6
18
|
alt: "Alt", backspace: "Backspace", cmd: "Cmd", ctrl: "Ctrl", delete: "Delete", down: "Down", end: "End",
|
|
7
19
|
enter: "Enter", esc: "Esc", escape: "Escape", home: "Home", insert: "Insert", left: "Left", meta: "Meta",
|
|
@@ -19,6 +19,11 @@ export function resolveDevelopmentLaunchEnvironment(canonicalPackageRoot, releas
|
|
|
19
19
|
? join(developmentRoot, "config")
|
|
20
20
|
: join(checkoutRoot, "config");
|
|
21
21
|
const dataDir = resolve(source[PRODUCT_IDENTITY.environment.dataDir] ?? join(developmentRoot, "data"));
|
|
22
|
+
// Rationale: solo processes keep isolated control state but must see the same history
|
|
23
|
+
// after selecting Shared; use a checkout-wide root across rebuilds unless overridden.
|
|
24
|
+
const historyDataDir = resolve(source[PRODUCT_IDENTITY.environment.developmentHistoryDataDir]
|
|
25
|
+
?? source[PRODUCT_IDENTITY.environment.dataDir]
|
|
26
|
+
?? (selectedDevelopmentRoot ? dataDir : join(checkoutRoot, "data")));
|
|
22
27
|
return {
|
|
23
28
|
checkoutId,
|
|
24
29
|
releaseId,
|
|
@@ -27,6 +32,7 @@ export function resolveDevelopmentLaunchEnvironment(canonicalPackageRoot, releas
|
|
|
27
32
|
environment: {
|
|
28
33
|
...source,
|
|
29
34
|
[PRODUCT_IDENTITY.environment.developmentInstanceId]: instanceId,
|
|
35
|
+
[PRODUCT_IDENTITY.environment.developmentHistoryDataDir]: historyDataDir,
|
|
30
36
|
[PRODUCT_IDENTITY.environment.configDir]: resolve(source[PRODUCT_IDENTITY.environment.configDir] ?? persistentConfigDir),
|
|
31
37
|
[PRODUCT_IDENTITY.environment.dataDir]: dataDir,
|
|
32
38
|
[PRODUCT_IDENTITY.environment.runtimeDir]: resolve(source[PRODUCT_IDENTITY.environment.runtimeDir] ?? join(developmentRoot, "runtime")),
|
|
@@ -18,6 +18,10 @@ export function resolveLaunchProfilePaths(options = {}) {
|
|
|
18
18
|
export function resolvePromptHistoryDataDir(options = {}) {
|
|
19
19
|
const environment = options.environment ?? process.env;
|
|
20
20
|
const platform = options.platform ?? process.platform;
|
|
21
|
+
const developmentHistoryDataDir = environment[PRODUCT_IDENTITY.environment.developmentHistoryDataDir];
|
|
22
|
+
if (developmentHistoryDataDir !== undefined) {
|
|
23
|
+
return resolveProductPaths({ ...environment, [PRODUCT_IDENTITY.environment.dataDir]: developmentHistoryDataDir }, platform).dataDir;
|
|
24
|
+
}
|
|
21
25
|
if (environment[PRODUCT_IDENTITY.environment.dataDir] !== undefined) {
|
|
22
26
|
return resolveProductPaths(environment, platform).dataDir;
|
|
23
27
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { UiTheme } from "../../ui/components/index.js";
|
|
2
|
+
/** The A1 setting holding the tab kinds the strip's `+` offers. */
|
|
3
|
+
export declare const PLUS_MENU_SETTING_ID = "tabBarPlusMenu";
|
|
4
|
+
/** One tab kind the plus menu can offer. */
|
|
5
|
+
export interface PlusMenuKind {
|
|
6
|
+
readonly key: string;
|
|
7
|
+
readonly label: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The plus-menu dialog: every tab kind with `●` when `+` offers it and `○` when not, filtered by typed
|
|
11
|
+
* text. It owns only its filter and the row in hand; the enabled record and its saving stay with the
|
|
12
|
+
* Settings screen that opened it.
|
|
13
|
+
*/
|
|
14
|
+
export declare class PlusMenuDialog {
|
|
15
|
+
#private;
|
|
16
|
+
constructor(kinds: readonly PlusMenuKind[]);
|
|
17
|
+
/** The kinds the filter keeps, in kind order. */
|
|
18
|
+
shown(): readonly PlusMenuKind[];
|
|
19
|
+
/** Handles one key by its resolved name; `toggle` flips a kind. Returns whether the dialog closed. */
|
|
20
|
+
handle(name: string, data: string, toggle: (key: string) => void): "close" | "handled";
|
|
21
|
+
lines(enabled: Readonly<Record<string, boolean | string>>, width: number, theme: UiTheme): readonly string[];
|
|
22
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { LineInput, displayWidth, handleLineInputKey, renderInputRow, truncateToWidth, } from "../../ui/components/index.js";
|
|
2
|
+
/** The A1 setting holding the tab kinds the strip's `+` offers. */
|
|
3
|
+
export const PLUS_MENU_SETTING_ID = "tabBarPlusMenu";
|
|
4
|
+
const TITLE = "Plus Menu";
|
|
5
|
+
const DESCRIPTION = "Choose what the + button in the tab bar can add.";
|
|
6
|
+
const HINT = "Type search · ↑↓ navigate · Space toggle · Esc close";
|
|
7
|
+
/**
|
|
8
|
+
* The plus-menu dialog: every tab kind with `●` when `+` offers it and `○` when not, filtered by typed
|
|
9
|
+
* text. It owns only its filter and the row in hand; the enabled record and its saving stay with the
|
|
10
|
+
* Settings screen that opened it.
|
|
11
|
+
*/
|
|
12
|
+
export class PlusMenuDialog {
|
|
13
|
+
#kinds;
|
|
14
|
+
#filter = new LineInput("");
|
|
15
|
+
#index = 0;
|
|
16
|
+
constructor(kinds) {
|
|
17
|
+
this.#kinds = kinds;
|
|
18
|
+
}
|
|
19
|
+
/** The kinds the filter keeps, in kind order. */
|
|
20
|
+
shown() {
|
|
21
|
+
const needle = this.#filter.value.trim().toLowerCase();
|
|
22
|
+
return this.#kinds.filter(kind => needle.length === 0 || kind.label.toLowerCase().includes(needle));
|
|
23
|
+
}
|
|
24
|
+
/** Handles one key by its resolved name; `toggle` flips a kind. Returns whether the dialog closed. */
|
|
25
|
+
handle(name, data, toggle) {
|
|
26
|
+
const shown = this.shown();
|
|
27
|
+
if (name === "escape")
|
|
28
|
+
return "close";
|
|
29
|
+
if (name === "up" || name === "down") {
|
|
30
|
+
this.#index = Math.min(Math.max(0, shown.length - 1), Math.max(0, this.#index + (name === "down" ? 1 : -1)));
|
|
31
|
+
return "handled";
|
|
32
|
+
}
|
|
33
|
+
if (name === "space") {
|
|
34
|
+
const kind = shown[this.#index];
|
|
35
|
+
if (kind !== undefined)
|
|
36
|
+
toggle(kind.key);
|
|
37
|
+
return "handled";
|
|
38
|
+
}
|
|
39
|
+
handleLineInputKey(this.#filter, data);
|
|
40
|
+
this.#index = 0;
|
|
41
|
+
return "handled";
|
|
42
|
+
}
|
|
43
|
+
lines(enabled, width, theme) {
|
|
44
|
+
const rule = theme.fg("border", "─".repeat(Math.max(0, width)));
|
|
45
|
+
const inset = width > 0 ? " " : "";
|
|
46
|
+
const contentWidth = Math.max(0, width - inset.length);
|
|
47
|
+
const row = (painted, raw) => {
|
|
48
|
+
const clipped = truncateToWidth(painted, contentWidth);
|
|
49
|
+
return `${inset}${clipped}${" ".repeat(Math.max(0, contentWidth - displayWidth(raw)))}`;
|
|
50
|
+
};
|
|
51
|
+
const shown = this.shown();
|
|
52
|
+
const index = Math.min(this.#index, Math.max(0, shown.length - 1));
|
|
53
|
+
const rows = shown.length === 0
|
|
54
|
+
? [row(theme.fg("dim", "No tabs match"), "No tabs match")]
|
|
55
|
+
: shown.map((kind, position) => {
|
|
56
|
+
const selected = position === index;
|
|
57
|
+
const cursor = selected ? "→ " : " ";
|
|
58
|
+
const marker = enabled[kind.key] === true ? "●" : "○";
|
|
59
|
+
const raw = `${cursor}${marker} ${kind.label}`;
|
|
60
|
+
const content = `${selected ? theme.fg("accent", cursor) : cursor}${theme.fg("text", marker)} ${theme.fg("text", kind.label)}`;
|
|
61
|
+
return row(selected ? theme.highlight(content) : content, raw);
|
|
62
|
+
});
|
|
63
|
+
return [
|
|
64
|
+
rule,
|
|
65
|
+
row(theme.bold(theme.fg("accent", TITLE)), TITLE),
|
|
66
|
+
row(theme.fg("dim", DESCRIPTION), DESCRIPTION),
|
|
67
|
+
"",
|
|
68
|
+
...renderInputRow(this.#filter, width, { ruled: false, promptGlyph: "> ", theme }).lines,
|
|
69
|
+
"",
|
|
70
|
+
...rows,
|
|
71
|
+
"",
|
|
72
|
+
row(theme.fg("dim", HINT), HINT),
|
|
73
|
+
rule,
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Fixed startup-safe rendering only; project-derived presentation is forbidden before trust resolves. */
|
|
2
|
-
export declare function renderProjectTrustDialog(cwd: string, options: readonly string[], selected: number, terminalWidth: number, terminalRows: number): readonly string[];
|
|
2
|
+
export declare function renderProjectTrustDialog(cwd: string, options: readonly string[], selected: number, terminalWidth: number, terminalRows: number, accent: string, border: string): readonly string[];
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { DIALOG_CLOSE_SHORTCUT_HINT, displayShortcutKeyLabel } from "../../contracts/presentation/index.js";
|
|
2
|
-
const ACCENT = "\u001b[38;2;167;152;215m";
|
|
3
|
-
const BORDER = "\u001b[38;2;97;133;204m";
|
|
4
2
|
const MUTED = "\u001b[38;2;157;165;169m";
|
|
5
3
|
const DIM = "\u001b[38;2;126;136;142m";
|
|
6
4
|
const RESET_FG = "\u001b[39m";
|
|
@@ -8,12 +6,12 @@ const BOLD = "\u001b[1m";
|
|
|
8
6
|
const RESET_BOLD = "\u001b[22m";
|
|
9
7
|
const EXPLANATION = "This allows to load project settings and resources, install missing project packages, and execute project extensions.";
|
|
10
8
|
/** Fixed startup-safe rendering only; project-derived presentation is forbidden before trust resolves. */
|
|
11
|
-
export function renderProjectTrustDialog(cwd, options, selected, terminalWidth, terminalRows) {
|
|
9
|
+
export function renderProjectTrustDialog(cwd, options, selected, terminalWidth, terminalRows, accent, border) {
|
|
12
10
|
const width = Math.max(1, terminalWidth);
|
|
13
|
-
const rule = `${
|
|
14
|
-
const title = ` ${BOLD}${
|
|
11
|
+
const rule = `${border}${"─".repeat(width)}${RESET_FG}`;
|
|
12
|
+
const title = ` ${BOLD}${accent}Trust project folder?${RESET_FG}${RESET_BOLD}`;
|
|
15
13
|
const path = ` ${MUTED}${sanitize(cwd)}${RESET_FG}`;
|
|
16
|
-
const choices = options.map((label, index) => choice(label, selected === index));
|
|
14
|
+
const choices = options.map((label, index) => choice(label, selected === index, accent));
|
|
17
15
|
const closeKey = displayShortcutKeyLabel(DIALOG_CLOSE_SHORTCUT_HINT.key);
|
|
18
16
|
const hint = ` ${DIM}↑↓${MUTED} navigate ${DIM}Enter${MUTED} select ${DIM}${closeKey}${MUTED} ${DIALOG_CLOSE_SHORTCUT_HINT.action}${RESET_FG}`;
|
|
19
17
|
const explanation = wrap(EXPLANATION, Math.max(1, width - 2)).map(line => ` ${line}`);
|
|
@@ -35,8 +33,8 @@ export function renderProjectTrustDialog(cwd, options, selected, terminalWidth,
|
|
|
35
33
|
return choiceWindow(choices, selected, 2);
|
|
36
34
|
return [choices[selected] ?? choices[0] ?? ""];
|
|
37
35
|
}
|
|
38
|
-
function choice(label, selected) {
|
|
39
|
-
return selected ? ` ${
|
|
36
|
+
function choice(label, selected, accent) {
|
|
37
|
+
return selected ? ` ${accent}→ ${label}${RESET_FG}` : ` ${label}`;
|
|
40
38
|
}
|
|
41
39
|
function choiceWindow(choices, selected, capacity) {
|
|
42
40
|
const start = Math.min(Math.max(0, selected - Math.floor(capacity / 2)), Math.max(0, choices.length - capacity));
|
|
@@ -22,6 +22,7 @@ export interface ConsoleProjectTrustPromptOptions {
|
|
|
22
22
|
readonly rows?: number;
|
|
23
23
|
};
|
|
24
24
|
readonly presentation?: "bare" | "comparison";
|
|
25
|
+
readonly environment?: NodeJS.ProcessEnv;
|
|
25
26
|
}
|
|
26
27
|
/** Fixed pre-resource selector; no project resource is available. */
|
|
27
28
|
export declare function createConsoleProjectTrustPrompt(options?: ConsoleProjectTrustPromptOptions): OwnedProjectTrustPrompt;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EMERGENCY_TERMINAL_RESET } from "../../foundation/terminal-cleanup/terminal-reset.js";
|
|
2
|
+
import { preTrustPalette, preTrustTerminalAppearance, preTrustTerminalColorMode, readPreTrustAccent } from "../../ui/settings/early-accent.js";
|
|
2
3
|
const ENTER_ALTERNATE_SCREEN = "\u001b[?1049h";
|
|
3
4
|
const HIDE_CURSOR = "\u001b[?25l";
|
|
4
5
|
const CLEAR_HOME = "\u001b[2J\u001b[H";
|
|
@@ -34,8 +35,8 @@ export function createConsoleProjectTrustPrompt(options = {}) {
|
|
|
34
35
|
if (choices.length === 0)
|
|
35
36
|
throw new Error("project trust choices are unavailable");
|
|
36
37
|
const comparison = options.presentation === "comparison";
|
|
37
|
-
const renderBareDialog = comparison
|
|
38
|
-
|
|
38
|
+
const renderBareDialog = comparison ? undefined : (await import("./project-trust-dialog.js")).renderProjectTrustDialog;
|
|
39
|
+
const palette = comparison ? null : trustPaletteOptions(options.environment ?? process.env);
|
|
39
40
|
const wasRaw = input.isRaw === true;
|
|
40
41
|
let selected = 0;
|
|
41
42
|
let restored = false;
|
|
@@ -66,7 +67,7 @@ export function createConsoleProjectTrustPrompt(options = {}) {
|
|
|
66
67
|
const render = () => {
|
|
67
68
|
const width = Math.max(renderBareDialog ? 1 : 20, output.columns ?? 80);
|
|
68
69
|
const rows = Math.max(1, output.rows ?? 24);
|
|
69
|
-
const lines = (renderBareDialog?.(cwd, choices.map(choice => choice.label), selected, width, rows) ?? [
|
|
70
|
+
const lines = (renderBareDialog?.(cwd, choices.map(choice => choice.label), selected, width, rows, palette.accent, palette.border) ?? [
|
|
70
71
|
`${BOLD}${ACCENT}Trust project folder?${RESET_FG}${RESET_BOLD}`,
|
|
71
72
|
cwd,
|
|
72
73
|
"",
|
|
@@ -179,6 +180,9 @@ export function createConsoleProjectTrustPrompt(options = {}) {
|
|
|
179
180
|
}
|
|
180
181
|
};
|
|
181
182
|
}
|
|
183
|
+
function trustPaletteOptions(environment) {
|
|
184
|
+
return preTrustPalette(readPreTrustAccent(environment), preTrustTerminalAppearance(environment), preTrustTerminalColorMode(environment));
|
|
185
|
+
}
|
|
182
186
|
function optionRow(label, selected) {
|
|
183
187
|
return selected
|
|
184
188
|
? `${ACCENT}→ ${label}${RESET_FG}`
|
|
@@ -24,6 +24,8 @@ export interface ReferenceScreenOptions {
|
|
|
24
24
|
readonly document: ReferenceDocumentProvider;
|
|
25
25
|
/** The reader's scroll settings, read on every frame so a live change is honored. */
|
|
26
26
|
readonly scrollSettings: () => OwnedUiViewportSettings;
|
|
27
|
+
/** The screen is a resident tab, such as the Changelog tab: it offers no screen-level close. */
|
|
28
|
+
readonly pinned?: boolean;
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
31
|
* Presents one read-only document full screen between two accent rules: the bold
|
|
@@ -48,6 +48,7 @@ export class ReferenceScreenApp {
|
|
|
48
48
|
#title;
|
|
49
49
|
#document;
|
|
50
50
|
#scrollSettings;
|
|
51
|
+
#pinned;
|
|
51
52
|
#scroll = 0;
|
|
52
53
|
#interruptArmed = false;
|
|
53
54
|
#failure = null;
|
|
@@ -67,6 +68,7 @@ export class ReferenceScreenApp {
|
|
|
67
68
|
this.#title = options.title;
|
|
68
69
|
this.#document = options.document;
|
|
69
70
|
this.#scrollSettings = options.scrollSettings;
|
|
71
|
+
this.#pinned = options.pinned === true;
|
|
70
72
|
}
|
|
71
73
|
onActivate(host) {
|
|
72
74
|
const ready = this.#document.ready;
|
|
@@ -139,7 +141,7 @@ export class ReferenceScreenApp {
|
|
|
139
141
|
const withRail = withScrollbarRail(body.slice(0, bodyHeight), geometry, contentWidth, theme, { presentation });
|
|
140
142
|
const hint = this.#interruptArmed
|
|
141
143
|
? theme.fg("dim", " press ctrl+c again to exit a1")
|
|
142
|
-
: renderShortcutHintsWithClose(
|
|
144
|
+
: renderShortcutHintsWithClose(this.#hintEntries(), theme, rect.width, 1);
|
|
143
145
|
// Compatibility: the v2 reference screen frames its document between two border-coloured rules.
|
|
144
146
|
const rule = theme.fg("border", "─".repeat(rect.width));
|
|
145
147
|
// Invariant: dialog chrome shares the title's one-cell inset; document content keeps its own layout.
|
|
@@ -153,7 +155,8 @@ export class ReferenceScreenApp {
|
|
|
153
155
|
return { consumed: false };
|
|
154
156
|
switch (action) {
|
|
155
157
|
case "close":
|
|
156
|
-
|
|
158
|
+
if (!this.#pinned)
|
|
159
|
+
host.close();
|
|
157
160
|
return { consumed: true };
|
|
158
161
|
case "up":
|
|
159
162
|
this.#scrollBy(-1);
|
|
@@ -216,6 +219,13 @@ export class ReferenceScreenApp {
|
|
|
216
219
|
}
|
|
217
220
|
return { owned: true, changed: true };
|
|
218
221
|
}
|
|
222
|
+
// Invariant: a pinned screen is its tab and `Esc` does not close it, so it shows no close hint.
|
|
223
|
+
#hintEntries() {
|
|
224
|
+
const entries = REFERENCE_SCREEN_SHORTCUTS.hintEntries(SCOPE);
|
|
225
|
+
if (!this.#pinned)
|
|
226
|
+
return entries;
|
|
227
|
+
return entries.filter(entry => entry.key !== DIALOG_CLOSE_SHORTCUT_HINT.key || entry.action !== DIALOG_CLOSE_SHORTCUT_HINT.action);
|
|
228
|
+
}
|
|
219
229
|
// Invariant: the title is the first document row, as in v2, so it scrolls with the document.
|
|
220
230
|
#content(width, theme) {
|
|
221
231
|
// Compatibility: one leading space, so the title lines up with the padded Markdown rows as in v2.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { AppHostServices, UiApp } from "../../ui/apps/index.js";
|
|
2
2
|
import { ShortcutRegistry, type PaneInputResult, type PaneMouseEvent, type PaneRect } from "../../ui/components/index.js";
|
|
3
3
|
import type { OwnedSettingsManager } from "../../ui/settings/index.js";
|
|
4
|
+
import type { SettingsSearchInputFactory } from "./settings-search-input.js";
|
|
4
5
|
export { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
5
|
-
type Action = "move-up" | "move-down" | "block-up" | "block-down" | "first" | "last" | "page-up" | "page-down" | "previous-value" | "next-value" | "activate" | "
|
|
6
|
+
type Action = "move-up" | "move-down" | "block-up" | "block-down" | "first" | "last" | "page-up" | "page-down" | "previous-value" | "next-value" | "activate" | "edit-filter" | "close" | "undo" | "part-previous" | "part-next" | "part-change";
|
|
6
7
|
export declare const SETTINGS_SHORTCUTS: ShortcutRegistry<Action>;
|
|
7
8
|
/**
|
|
8
9
|
* The settings screen. Rows, sticky headers, scrolling, and the keymap come from
|
|
@@ -12,9 +13,15 @@ export declare const SETTINGS_SHORTCUTS: ShortcutRegistry<Action>;
|
|
|
12
13
|
export declare class SettingsApp implements UiApp {
|
|
13
14
|
#private;
|
|
14
15
|
readonly id = "settings";
|
|
15
|
-
/**
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* `pinned` presents the screen as a resident Settings tab, which offers no screen-level close;
|
|
18
|
+
* `configurePlusMenu` opens the tab bar's Plus Menu dialog in place of this screen's own.
|
|
19
|
+
*/
|
|
20
|
+
constructor(session: OwnedSettingsManager, options: {
|
|
17
21
|
readonly pinned?: boolean;
|
|
22
|
+
readonly searchInputFactory: SettingsSearchInputFactory;
|
|
23
|
+
readonly copyText?: (text: string) => void;
|
|
24
|
+
readonly configurePlusMenu?: (() => boolean) | null;
|
|
18
25
|
});
|
|
19
26
|
onActivate(host: AppHostServices): void;
|
|
20
27
|
onClose(_host: AppHostServices): void;
|