@timurproko/a1 0.2.7-dev.810 → 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/resident-tab-coordinator.d.ts +6 -9
- package/dist/app/session-shell/resident-tab-coordinator.js +9 -52
- package/dist/app/session-shell/session-shell-root.d.ts +9 -3
- package/dist/app/session-shell/session-shell.js +70 -20
- package/dist/app/session-shell/session-viewport-controller.js +6 -4
- 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 -43
- 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 +9 -3
- package/dist/foundation/resident-tabs/bridge-client.js +14 -7
- package/dist/foundation/resident-tabs/routes.d.ts +5 -0
- package/dist/foundation/resident-tabs/routes.js +5 -0
- package/dist/foundation/resident-tabs/settings.d.ts +0 -1
- package/dist/foundation/resident-tabs/settings.js +0 -2
- 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 +5 -4
- package/dist/ui/components/prompt-input.js +8 -6
- package/dist/ui/components/submitted-prompt.d.ts +2 -2
- package/dist/ui/components/submitted-prompt.js +3 -3
- package/dist/ui/components/surface.js +4 -2
- package/dist/ui/components/transcript-viewport.d.ts +1 -1
- package/dist/ui/components/transcript-viewport.js +141 -24
- package/dist/ui/settings/declarations.d.ts +65 -15
- package/dist/ui/settings/declarations.js +45 -13
- package/dist/ui/settings/manager.js +7 -3
- package/dist/ui/settings/migrations.js +22 -0
- package/dist/ui/settings/sections.d.ts +4 -0
- package/dist/ui/settings/sections.js +9 -3
- package/docs/architecture/resident-tabs.md +39 -11
- package/docs/architecture/tool-image-presentation.md +2 -1
- package/docs/features/prompt-history.md +41 -20
- package/package.json +1 -1
|
@@ -6,11 +6,13 @@ import { PromptImageSidecar } from "../features/prompt-history/image-sidecar.js"
|
|
|
6
6
|
import { resolvePromptHistoryPath } from "../features/prompt-history/paths.js";
|
|
7
7
|
import { resolveLaunchProfilePaths, resolvePromptHistoryDataDir } from "../features/launch/profile-paths.js";
|
|
8
8
|
import { resolveProductPaths } from "../foundation/lifecycle/paths.js";
|
|
9
|
+
import { MAX_CLIPBOARD_TEXT_BYTES } from "../contracts/owned-ui/index.js";
|
|
9
10
|
import { applyConfiguredPiTheme, getAvailablePiThemes, setPiAccentColor, setPiPackageBorderProjectionEnabled } from "../integrations/pi/components/upstream/theme/theme.js";
|
|
10
11
|
import { createPiEngineHost } from "../integrations/pi/engine/host.js";
|
|
11
12
|
import { createPiSessionPresenters } from "../integrations/pi/session-presenters/index.js";
|
|
12
13
|
import { ClipboardDiagnosticCapture } from "../app/session-shell/clipboard-diagnostics.js";
|
|
13
14
|
import { createOwnedUiClipboardServices } from "../app/session-shell/clipboard-services.js";
|
|
15
|
+
import { writeSystemClipboardText } from "../app/session-shell/system-clipboard.js";
|
|
14
16
|
import { createPiKeybindingsHost } from "../integrations/pi/components/shell-shared-facade.js";
|
|
15
17
|
import { OwnedUiSessionPresenter, OwnedUiTerminalHost, sessionTerminalHostOptions, } from "../app/session-shell/session-shell.js";
|
|
16
18
|
import { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
@@ -19,7 +21,7 @@ import { createOwnedRouteHost } from "./settings-route-host.js";
|
|
|
19
21
|
import { renderPiShellChangelogLines } from "../integrations/pi/components/shell-presenters-info.js";
|
|
20
22
|
import { nativeHyperlinkStyle } from "../ui/components/spans.js";
|
|
21
23
|
import { ResidentTabRecovery } from "../foundation/resident-tabs/recovery.js";
|
|
22
|
-
import { bindResidentTabBridge, correlateResidentTabSubmission, currentBackendSessionFile, residentTabKeybindings } from "./resident-tab-bridge.js";
|
|
24
|
+
import { bindResidentTabBridge, closeResidentUtilityRoute, correlateResidentTabSubmission, currentBackendSessionFile, residentRouteHostOptions, residentTabKeybindings } from "./resident-tab-bridge.js";
|
|
23
25
|
import { SessionRuntimeRegistry } from "./session-runtime-registry.js";
|
|
24
26
|
import { readPackageVersion, StartupReleaseNote } from "./startup-route.js";
|
|
25
27
|
export { bindResidentTabBridge, correlateResidentTabSubmission } from "./resident-tab-bridge.js";
|
|
@@ -50,7 +52,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
50
52
|
namespace: PRODUCT_IDENTITY.commandName,
|
|
51
53
|
legacyConfigDir: productPaths.configDir,
|
|
52
54
|
agentProvider: () => backend.settingsPort(),
|
|
53
|
-
...(options.hideTabSettings ? { hiddenOwnedSettingIds: ["tabsAutoName"] } : {}),
|
|
55
|
+
...(options.hideTabSettings ? { hiddenOwnedSettingIds: ["tabsAutoName", "tabsPosition", "tabBarPlusMenu"] } : {}),
|
|
54
56
|
hiddenAgentSettingIds: ["fullscreenWheelScrollLines"],
|
|
55
57
|
agentSettingLabelOverrides: { fullscreenCopyOnSelect: "Copy on select" },
|
|
56
58
|
});
|
|
@@ -130,12 +132,15 @@ export async function composeOwnedUi(options = {}) {
|
|
|
130
132
|
host.setAccentColor(accent);
|
|
131
133
|
tabBridge?.accent(accent);
|
|
132
134
|
});
|
|
133
|
-
// Rationale:
|
|
134
|
-
// change saved in
|
|
135
|
-
const unwatchSharedSettings = settings === null || !ownedSurfaces
|
|
135
|
+
// Rationale: resident tabs and separate solo agents share a settings document; a live scope
|
|
136
|
+
// change saved in either reaches the others only by rereading that document.
|
|
137
|
+
const unwatchSharedSettings = settings === null || !ownedSurfaces
|
|
136
138
|
? () => { }
|
|
137
139
|
: watchSharedSettings(settings);
|
|
138
140
|
const unsubscribeAccent = () => { unwatchSharedSettings(); unsubscribeAccentChange(); };
|
|
141
|
+
// Invariant: the Settings search and agent prompt borrow the same resolved Pi keybindings.
|
|
142
|
+
const keybindingsHost = createPiKeybindingsHost({ profile: ownedSurfaces ? "a1" : "pi", agentDir: backend.identity.agentDir });
|
|
143
|
+
const keybindings = residentTabKeybindings(tabBridge, backend.identity.agentDir, keybindingsHost);
|
|
139
144
|
// Rationale: Routes open only after shell construction.
|
|
140
145
|
const references = {
|
|
141
146
|
changelog: async (input) => {
|
|
@@ -151,9 +156,8 @@ export async function composeOwnedUi(options = {}) {
|
|
|
151
156
|
},
|
|
152
157
|
session: () => import("./session-info-reference.js").then(m => m.loadSessionInfoReference(backend)),
|
|
153
158
|
};
|
|
154
|
-
const routeHost = settings === null || !ownedSurfaces ? null
|
|
155
|
-
|
|
156
|
-
});
|
|
159
|
+
const routeHost = settings === null || !ownedSurfaces ? null
|
|
160
|
+
: createOwnedRouteHost(settings, references, settingsRouteOptions(tabBridge, keybindings, backend.identity.agentDir, cwd));
|
|
157
161
|
const viewportSettings = settings === null || !ownedSurfaces ? null : {
|
|
158
162
|
snapshot: () => viewportSettingsSnapshot(settings),
|
|
159
163
|
onChange: listener => settings.onChange(() => listener(viewportSettingsSnapshot(settings))),
|
|
@@ -181,26 +185,11 @@ export async function composeOwnedUi(options = {}) {
|
|
|
181
185
|
// Rationale: one listener covers both the A1 presentation choice and the engine skill-command toggle.
|
|
182
186
|
onChange: (listener) => settings.onChange(() => listener()),
|
|
183
187
|
};
|
|
184
|
-
const
|
|
185
|
-
const historyProfileLocation = settings === null || !ownedSurfaces || !settings.value("promptHistoryEnabled")
|
|
186
|
-
? null
|
|
187
|
-
: resolvePromptHistoryPath(resolvePromptHistoryDataDir(), backend.identity.agentDir);
|
|
188
|
-
const promptHistory = historyProfileLocation === null ? null : {
|
|
189
|
-
limit: typeof historyLimit === "number" ? historyLimit : 100,
|
|
190
|
-
store: new PromptHistoryService({
|
|
191
|
-
dataDir: resolvePromptHistoryDataDir(),
|
|
192
|
-
profileRoot: backend.identity.agentDir,
|
|
193
|
-
limit: typeof historyLimit === "number" ? historyLimit : 100,
|
|
194
|
-
}),
|
|
195
|
-
imageSidecar: new PromptImageSidecar(historyProfileLocation.imagesDir),
|
|
196
|
-
};
|
|
188
|
+
const promptHistory = createPromptHistoryConfiguration(settings, backend, ownedSurfaces);
|
|
197
189
|
const clipboardDestination = options.clipboardDiagnosticsPath ?? process.env[PRODUCT_IDENTITY.environment.clipboardDiagnostics];
|
|
198
190
|
const clipboardDiagnostics = settings !== null && ownedSurfaces && clipboardDestination?.trim()
|
|
199
191
|
? new ClipboardDiagnosticCapture(clipboardDestination) : null;
|
|
200
|
-
// Invariant: process-wide services are created once here and borrowed by every session shell.
|
|
201
|
-
// keybinding registry is applied before any presenter is built, so none of them reads Pi's defaults.
|
|
202
|
-
const keybindingsHost = createPiKeybindingsHost({ profile: ownedSurfaces ? "a1" : "pi", agentDir: backend.identity.agentDir });
|
|
203
|
-
const keybindings = residentTabKeybindings(tabBridge, backend.identity.agentDir, keybindingsHost);
|
|
192
|
+
// Invariant: process-wide services are created once here and borrowed by every session shell.
|
|
204
193
|
const clipboardServices = ownedSurfaces ? createOwnedUiClipboardServices() : null;
|
|
205
194
|
let createdTerminalHost;
|
|
206
195
|
let terminalHost;
|
|
@@ -216,12 +205,8 @@ export async function composeOwnedUi(options = {}) {
|
|
|
216
205
|
...(ownedSurfaces ? { sessionLayout: "custom-viewport" } : {}),
|
|
217
206
|
...(tabBridge === null || tabRecovery === null ? {} : { residentTab: {
|
|
218
207
|
requestDetach: () => tabBridge.requestDetach(),
|
|
219
|
-
closeOwnedRoute: route =>
|
|
220
|
-
if (tabBridge.tabId.startsWith("settings-") && route === "settings")
|
|
221
|
-
void tabBridge.requestClose();
|
|
222
|
-
},
|
|
208
|
+
closeOwnedRoute: route => closeResidentUtilityRoute(tabBridge, route),
|
|
223
209
|
reportStatus: status => tabBridge.status(status),
|
|
224
|
-
stallNoticeSeconds: 300,
|
|
225
210
|
admit: input => tabRecovery.admit({ ...input, incarnation: options.tab.incarnation }),
|
|
226
211
|
dispatched: () => tabRecovery.dispatched(),
|
|
227
212
|
correlated: (submissionId, entryId) => correlateResidentTabSubmission(tabRecovery, backend, submissionId, entryId),
|
|
@@ -291,18 +276,13 @@ export async function composeOwnedUi(options = {}) {
|
|
|
291
276
|
// Rationale: pinned Pi's version check is unreachable because the owned shell never runs its
|
|
292
277
|
// InteractiveMode, so A1 checks its own channel. The result is never awaited on the startup path;
|
|
293
278
|
// settings are read here because the runner resolves them only just before start.
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
...(settings === null || !ownedSurfaces ? {} : { settingEnabled: settings.value("updateCheck") }),
|
|
302
|
-
});
|
|
303
|
-
if (release !== null)
|
|
304
|
-
backend.extensions.announceReleaseUpdate(release);
|
|
305
|
-
};
|
|
279
|
+
const releaseUpdates = createStartupReleaseUpdateObservation({
|
|
280
|
+
backend,
|
|
281
|
+
configDir: productPaths.configDir,
|
|
282
|
+
mode: settings === null || !ownedSurfaces ? "auto" : settings.value("updateCheck"),
|
|
283
|
+
packageVersion: releaseNote.packageVersion, notificationVersion: options.notificationVersion,
|
|
284
|
+
checkForNewerRelease: options.checkForNewerRelease,
|
|
285
|
+
});
|
|
306
286
|
const exitNoticePath = process.env[PRODUCT_IDENTITY.environment.exitNoticePath];
|
|
307
287
|
// Security: tools the agent runs must never see, or rewrite, this instance's notice.
|
|
308
288
|
delete process.env[PRODUCT_IDENTITY.environment.exitNoticePath];
|
|
@@ -315,11 +295,12 @@ export async function composeOwnedUi(options = {}) {
|
|
|
315
295
|
exitNotice = import("../app/session-shell/exit-notice.js")
|
|
316
296
|
.then(module => module.armExitNotice(backend, exitNoticePath), () => null);
|
|
317
297
|
presenter.start();
|
|
318
|
-
|
|
298
|
+
releaseUpdates.start();
|
|
319
299
|
},
|
|
320
300
|
flush: () => backend.session.flushEvents(),
|
|
321
301
|
waitUntilStopped: () => presenter.waitUntilStopped(),
|
|
322
302
|
dispose: async () => {
|
|
303
|
+
releaseUpdates.stop();
|
|
323
304
|
try {
|
|
324
305
|
await terminalHost.dispose();
|
|
325
306
|
// Invariant: cleared only once the terminal is restored; a failed dispose leaves it armed.
|
|
@@ -344,6 +325,63 @@ export async function composeOwnedUi(options = {}) {
|
|
|
344
325
|
};
|
|
345
326
|
return { application, settings };
|
|
346
327
|
}
|
|
328
|
+
function createPromptHistoryConfiguration(settings, backend, ownedSurfaces) {
|
|
329
|
+
const limit = settings?.value("promptHistoryMaxItems") ?? 100;
|
|
330
|
+
const scope = settings?.value("promptHistoryScope") ?? "unique";
|
|
331
|
+
const enabled = settings !== null && ownedSurfaces && settings.value("promptHistoryEnabled");
|
|
332
|
+
const sessionId = enabled ? backend.identity.currentHistorySessionId() : null;
|
|
333
|
+
if (settings === null || !enabled || (scope === "unique" && sessionId === null))
|
|
334
|
+
return null;
|
|
335
|
+
const dataDir = resolvePromptHistoryDataDir();
|
|
336
|
+
const forScope = (selected, id) => {
|
|
337
|
+
if (selected === "unique" && id === null)
|
|
338
|
+
return null;
|
|
339
|
+
const location = resolvePromptHistoryPath(dataDir, backend.identity.agentDir, process.platform, selected, id ?? "");
|
|
340
|
+
return {
|
|
341
|
+
store: new PromptHistoryService({ dataDir, profileRoot: backend.identity.agentDir, limit, scope: selected, sessionId: id ?? "" }),
|
|
342
|
+
imageSidecar: new PromptImageSidecar(location.imagesDir),
|
|
343
|
+
};
|
|
344
|
+
};
|
|
345
|
+
return {
|
|
346
|
+
limit, scope,
|
|
347
|
+
...(sessionId === null ? {} : { sessionId }),
|
|
348
|
+
forScope,
|
|
349
|
+
onScopeChange: (listener) => settings.onChange(() => listener(settings.value("promptHistoryScope"))),
|
|
350
|
+
...forScope(scope, sessionId),
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function createStartupReleaseUpdateObservation(input) {
|
|
354
|
+
const controller = new AbortController();
|
|
355
|
+
const observe = async () => {
|
|
356
|
+
const check = input.checkForNewerRelease
|
|
357
|
+
?? (await import("../foundation/release/latest-release.js")).checkForNewerRelease;
|
|
358
|
+
const runningVersion = input.packageVersion ?? await readPackageVersion();
|
|
359
|
+
const discoveryVersion = input.mode === "notify" ? input.notificationVersion ?? runningVersion : runningVersion;
|
|
360
|
+
const release = await check({
|
|
361
|
+
runningVersion: discoveryVersion,
|
|
362
|
+
configDir: input.configDir,
|
|
363
|
+
interactive: process.stdout.isTTY === true,
|
|
364
|
+
settingMode: input.mode,
|
|
365
|
+
});
|
|
366
|
+
if (release === null || controller.signal.aborted)
|
|
367
|
+
return;
|
|
368
|
+
if (input.mode === "notify") {
|
|
369
|
+
input.backend.extensions.announceReleaseUpdate(release);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (input.mode === "auto") {
|
|
373
|
+
const installed = await import("../foundation/release/automatic-update.js")
|
|
374
|
+
.then(module => module.requestAutomaticUpdate({ release, runningVersion, signal: controller.signal }));
|
|
375
|
+
if (installed !== null && !controller.signal.aborted) {
|
|
376
|
+
input.backend.extensions.announceReleaseUpdate({ status: "installed", version: installed });
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
return {
|
|
381
|
+
start() { void observe().catch(() => undefined); },
|
|
382
|
+
stop() { controller.abort(); },
|
|
383
|
+
};
|
|
384
|
+
}
|
|
347
385
|
const SHARED_SETTINGS_POLL_MS = 250;
|
|
348
386
|
/** Rereads the shared settings document whenever its stat changes; returns the stop. */
|
|
349
387
|
export function watchSharedSettings(settings) {
|
|
@@ -359,6 +397,18 @@ export function watchSharedSettings(settings) {
|
|
|
359
397
|
watchFile(file, { interval: SHARED_SETTINGS_POLL_MS, persistent: false }, listener);
|
|
360
398
|
return () => unwatchFile(file, listener);
|
|
361
399
|
}
|
|
400
|
+
function settingsRouteOptions(tabBridge, keybindings, agentDir, cwd) {
|
|
401
|
+
return {
|
|
402
|
+
...residentRouteHostOptions(tabBridge),
|
|
403
|
+
keybindings,
|
|
404
|
+
agentDir,
|
|
405
|
+
cwd,
|
|
406
|
+
copyText: text => {
|
|
407
|
+
if (Buffer.byteLength(text) <= MAX_CLIPBOARD_TEXT_BYTES)
|
|
408
|
+
void writeSystemClipboardText(text).catch(() => { });
|
|
409
|
+
},
|
|
410
|
+
};
|
|
411
|
+
}
|
|
362
412
|
function quitOutroSettingsSnapshot(settings) {
|
|
363
413
|
return {
|
|
364
414
|
enabled: settings.value("quitAnimation"),
|
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import type { TabBridgeClient } from "../foundation/resident-tabs/bridge-client.js";
|
|
2
|
+
import { type ResidentTabRoute } from "../foundation/resident-tabs/routes.js";
|
|
2
3
|
import type { ResidentTabRecovery } from "../foundation/resident-tabs/recovery.js";
|
|
3
4
|
import type { PiKeybindingsHost } from "../integrations/pi/components/shell-shared-facade.js";
|
|
4
5
|
import type { ComposedSessionBackend } from "./session-backend.js";
|
|
6
|
+
import type { OwnedRouteHostOptions } from "./settings-route-host.js";
|
|
5
7
|
/**
|
|
6
8
|
* The keybindings the shells borrow. Inside a resident tab the host dispatches and labels the tab
|
|
7
9
|
* shortcuts this child projects from its effective declarations, so the projection is published now
|
|
8
10
|
* and again after every customization reload.
|
|
9
11
|
*/
|
|
10
12
|
export declare function residentTabKeybindings(tabBridge: TabBridgeClient | null, agentDir: string, keybindingsHost: PiKeybindingsHost): PiKeybindingsHost;
|
|
13
|
+
/**
|
|
14
|
+
* How owned screens are presented in a resident tab: a Settings or Changelog tab's screen is the tab, and the Plus menu entry opens
|
|
15
|
+
* the tab bar's own Plus Menu dialog while this tab's controlling client can show it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function residentRouteHostOptions(tabBridge: TabBridgeClient | null): OwnedRouteHostOptions;
|
|
18
|
+
/** Closes a utility tab when its own screen closes. Invariant: a utility tab's screen is the tab. */
|
|
19
|
+
export declare function closeResidentUtilityRoute(tabBridge: Pick<TabBridgeClient, "tabId" | "requestClose">, route: string): void;
|
|
11
20
|
export declare function bindResidentTabBridge(tabBridge: TabBridgeClient, backend: Pick<ComposedSessionBackend, "identity" | "session" | "workflows" | "generateResidentTabName">, recovery?: Pick<ResidentTabRecovery, "settled"> | null, options?: {
|
|
12
21
|
readonly autoName?: boolean;
|
|
13
|
-
readonly openRoute?: (route:
|
|
22
|
+
readonly openRoute?: (route: ResidentTabRoute) => void;
|
|
14
23
|
}): Promise<() => void>;
|
|
15
24
|
export declare function correlateResidentTabSubmission(recovery: Pick<ResidentTabRecovery, "correlated" | "settled">, backend: Pick<ComposedSessionBackend, "identity" | "session">, submissionId: string, entryId: string): Promise<void>;
|
|
16
25
|
export declare function currentBackendSessionFile(backend: Pick<ComposedSessionBackend, "identity">): string | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { residentUtilityRoute } from "../foundation/resident-tabs/routes.js";
|
|
1
2
|
import { deriveResidentTabStatus } from "../features/resident-tab/status-deriver.js";
|
|
2
3
|
import { projectResidentTabShortcuts } from "../features/resident-tab/shortcut-projection.js";
|
|
3
4
|
import { readShortcutBindingsFile } from "../features/resident-tab/shortcut-bindings-file.js";
|
|
@@ -16,6 +17,26 @@ export function residentTabKeybindings(tabBridge, agentDir, keybindingsHost) {
|
|
|
16
17
|
publish();
|
|
17
18
|
return { ...keybindingsHost, reload: () => { keybindingsHost.reload(); publish(); } };
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* How owned screens are presented in a resident tab: a Settings or Changelog tab's screen is the tab, and the Plus menu entry opens
|
|
22
|
+
* the tab bar's own Plus Menu dialog while this tab's controlling client can show it.
|
|
23
|
+
*/
|
|
24
|
+
export function residentRouteHostOptions(tabBridge) {
|
|
25
|
+
return {
|
|
26
|
+
...(tabBridge === null ? {} : { tabRoute: residentUtilityRoute(tabBridge.tabId) }),
|
|
27
|
+
configurePlusMenu: () => {
|
|
28
|
+
if (tabBridge === null || !tabBridge.available || tabBridge.captureAttachment() === null)
|
|
29
|
+
return false;
|
|
30
|
+
void tabBridge.requestAction("configure-plus");
|
|
31
|
+
return true;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Closes a utility tab when its own screen closes. Invariant: a utility tab's screen is the tab. */
|
|
36
|
+
export function closeResidentUtilityRoute(tabBridge, route) {
|
|
37
|
+
if (residentUtilityRoute(tabBridge.tabId) === route)
|
|
38
|
+
void tabBridge.requestClose();
|
|
39
|
+
}
|
|
19
40
|
export async function bindResidentTabBridge(tabBridge, backend, recovery = null, options = {}) {
|
|
20
41
|
await tabBridge.start().catch(() => false);
|
|
21
42
|
tabBridge.status("starting");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReferenceDocumentProvider } from "../features/owned-ui/reference-screen-app.js";
|
|
2
2
|
import type { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
3
3
|
import type { UiRouteHost, UiRouteInput } from "../ui/apps/contracts.js";
|
|
4
|
+
import type { PiKeybindingsHost } from "../integrations/pi/components/shell-shared-facade.js";
|
|
4
5
|
/** Styled document rows for one content width. */
|
|
5
6
|
export type OwnedReferenceRows = NonNullable<ReferenceDocumentProvider["rows"]>;
|
|
6
7
|
/** Documents supplied by composition so the route host never reads shell data itself. */
|
|
@@ -11,8 +12,17 @@ export interface OwnedReferenceProviders {
|
|
|
11
12
|
}
|
|
12
13
|
/** How the settings route is presented. */
|
|
13
14
|
export interface OwnedRouteHostOptions {
|
|
14
|
-
/**
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The route whose screen is this resident utility tab. That screen is the tab, so it offers no
|
|
17
|
+
* screen-level close: neither Esc nor one Ctrl+C dismisses it, and it shows no close hint.
|
|
18
|
+
*/
|
|
19
|
+
readonly tabRoute?: string | null;
|
|
20
|
+
/** Opens the tab bar's own Plus Menu dialog; false when no tab bar can show it. */
|
|
21
|
+
readonly configurePlusMenu?: () => boolean;
|
|
22
|
+
readonly keybindings?: PiKeybindingsHost;
|
|
23
|
+
readonly agentDir?: string;
|
|
24
|
+
readonly cwd?: string;
|
|
25
|
+
readonly copyText?: (text: string) => void;
|
|
16
26
|
}
|
|
17
27
|
/** Declares settings and lazy document routes. */
|
|
18
28
|
export declare function createOwnedRouteHost(settings: OwnedSettingsManager, references?: OwnedReferenceProviders, options?: OwnedRouteHostOptions): UiRouteHost;
|
|
@@ -11,13 +11,14 @@ export function createOwnedRouteHost(settings, references, options = {}) {
|
|
|
11
11
|
if (!routes.has(route))
|
|
12
12
|
return null;
|
|
13
13
|
if (route === SETTINGS_ROUTE) {
|
|
14
|
-
return deferredSurface(SETTINGS_APP_ID, "settings", () => loadSettingsSurface(settings, options
|
|
14
|
+
return deferredSurface(SETTINGS_APP_ID, "settings", () => loadSettingsSurface(settings, options));
|
|
15
15
|
}
|
|
16
16
|
const changelog = route === CHANGELOG_ROUTE;
|
|
17
17
|
const session = route === "session";
|
|
18
18
|
const title = session ? "Session Info" : changelog ? input ? "What's New" : "Changelog" : HOTKEYS_TITLE;
|
|
19
19
|
const document = session ? references.session() : changelog ? references.changelog(input) : references.hotkeys();
|
|
20
|
-
|
|
20
|
+
const pinned = options.tabRoute === route;
|
|
21
|
+
return deferredSurface(route, title, () => loadReferenceSurface(settings, route, title, document, pinned));
|
|
21
22
|
},
|
|
22
23
|
};
|
|
23
24
|
}
|
|
@@ -61,12 +62,27 @@ function deferredSurface(id, label, load) {
|
|
|
61
62
|
onExitRequested: listener => { onExit = listener; },
|
|
62
63
|
};
|
|
63
64
|
}
|
|
64
|
-
async function loadSettingsSurface(settings,
|
|
65
|
-
const { SettingsApp } = await
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
async function loadSettingsSurface(settings, options) {
|
|
66
|
+
const [{ SettingsApp }, { createSettingsSearchInputFactory }] = await Promise.all([
|
|
67
|
+
import("../features/owned-ui/settings-app.js"),
|
|
68
|
+
import("./settings-search-input.js"),
|
|
69
|
+
]);
|
|
70
|
+
const pinned = options.tabRoute === SETTINGS_ROUTE;
|
|
71
|
+
const searchInputFactory = createSettingsSearchInputFactory({
|
|
72
|
+
...(options.keybindings === undefined ? {} : { keybindings: options.keybindings }),
|
|
73
|
+
...(options.agentDir === undefined ? {} : { agentDir: options.agentDir }),
|
|
74
|
+
...(options.cwd === undefined ? {} : { cwd: options.cwd }),
|
|
75
|
+
});
|
|
76
|
+
// Invariant: a pinned Settings tab closes as a tab; neither Esc nor one unclaimed Ctrl+C dismisses its screen.
|
|
77
|
+
return hostApp(SETTINGS_APP_ID, SETTINGS_ROUTE, () => new SettingsApp(settings, {
|
|
78
|
+
pinned,
|
|
79
|
+
searchInputFactory,
|
|
80
|
+
configurePlusMenu: options.configurePlusMenu ?? null,
|
|
81
|
+
...(options.copyText === undefined ? {} : { copyText: options.copyText }),
|
|
82
|
+
}), !pinned, true);
|
|
68
83
|
}
|
|
69
|
-
async function loadReferenceSurface(settings,
|
|
84
|
+
async function loadReferenceSurface(settings, route, title, document, pinned) {
|
|
85
|
+
const id = route;
|
|
70
86
|
// Rationale: the app module and the document load together, so a document that fails
|
|
71
87
|
// to render is reported by the placeholder rather than by a screen that never fills.
|
|
72
88
|
const [{ ReferenceScreenApp }, content] = await Promise.all([import("../features/owned-ui/reference-screen-app.js"), document]);
|
|
@@ -79,9 +95,10 @@ async function loadReferenceSurface(settings, id, route, title, document) {
|
|
|
79
95
|
scrollbarStyle: settings.value("scrollbarStyle"),
|
|
80
96
|
scrollbarSpeed: settings.value("scrollbarSpeed"),
|
|
81
97
|
}),
|
|
82
|
-
|
|
98
|
+
pinned,
|
|
99
|
+
}), !pinned);
|
|
83
100
|
}
|
|
84
|
-
async function hostApp(id, route, create, closeOnInterrupt = true) {
|
|
101
|
+
async function hostApp(id, route, create, closeOnInterrupt = true, appInputBeforeInterrupt = false) {
|
|
85
102
|
const [{ UiAppHost }, { UiAppRegistry }] = await Promise.all([
|
|
86
103
|
import("../ui/apps/host.js"),
|
|
87
104
|
import("../ui/apps/registry.js"),
|
|
@@ -96,6 +113,7 @@ async function hostApp(id, route, create, closeOnInterrupt = true) {
|
|
|
96
113
|
const host = new UiAppHost({
|
|
97
114
|
registry,
|
|
98
115
|
closeOnInterrupt,
|
|
116
|
+
appInputBeforeInterrupt,
|
|
99
117
|
theme: pinnedTheme(),
|
|
100
118
|
surface: {
|
|
101
119
|
size: () => size,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SettingsSearchInputFactory } from "../features/owned-ui/settings-search-input.js";
|
|
2
|
+
import { type PiKeybindingsHost } from "../integrations/pi/components/shell-shared-facade.js";
|
|
3
|
+
export interface SettingsSearchInputFactoryOptions {
|
|
4
|
+
readonly keybindings?: PiKeybindingsHost;
|
|
5
|
+
readonly agentDir?: string;
|
|
6
|
+
readonly cwd?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Builds Settings search from the same configurable owned editor used by the agent prompt. */
|
|
9
|
+
export declare function createSettingsSearchInputFactory(options?: SettingsSearchInputFactoryOptions): SettingsSearchInputFactory;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { editorInsertedText } from "../integrations/pi/components/owned-editor-ux.js";
|
|
2
|
+
import { createPiShellEditor } from "../integrations/pi/components/shell-editor-autocomplete.js";
|
|
3
|
+
import { piShellTruncateToWidth, piShellVisibleWidth, } from "../integrations/pi/components/shell-shared-facade.js";
|
|
4
|
+
import { backgroundSgrSpan } from "../ui/components/spans.js";
|
|
5
|
+
import { caretCell } from "../ui/components/line-input.js";
|
|
6
|
+
import { PromptInput } from "../ui/components/prompt-input.js";
|
|
7
|
+
/** Builds Settings search from the same configurable owned editor used by the agent prompt. */
|
|
8
|
+
export function createSettingsSearchInputFactory(options = {}) {
|
|
9
|
+
return {
|
|
10
|
+
isTextInput: data => {
|
|
11
|
+
const text = editorInsertedText(data);
|
|
12
|
+
return text !== undefined && /[^\p{Cc}]/u.test(text);
|
|
13
|
+
},
|
|
14
|
+
create: surface => createSettingsSearchInput(surface, options),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function createSettingsSearchInput(surface, options) {
|
|
18
|
+
let columns = 80;
|
|
19
|
+
const editor = createPiShellEditor({
|
|
20
|
+
keybindingProfile: "a1",
|
|
21
|
+
inputCapabilities: {
|
|
22
|
+
singleLine: true,
|
|
23
|
+
paste: false,
|
|
24
|
+
autocomplete: false,
|
|
25
|
+
placeholder: "Search settings",
|
|
26
|
+
},
|
|
27
|
+
...(options.keybindings === undefined ? {} : { keybindings: options.keybindings }),
|
|
28
|
+
...(options.agentDir === undefined ? {} : { agentDir: options.agentDir }),
|
|
29
|
+
cwd: options.cwd ?? process.cwd(),
|
|
30
|
+
getColumns: () => columns,
|
|
31
|
+
getRows: surface.getRows,
|
|
32
|
+
requestRender: surface.requestRender,
|
|
33
|
+
onSubmit: () => { },
|
|
34
|
+
onCopyText: text => surface.copyText(text),
|
|
35
|
+
paintEditorSelection: (line, from, to, atomic) => backgroundSgrSpan(line, from, to, atomic ? "\u001b[7m" : "\u001b[27m\u001b[48;2;38;79;120m", atomic ? "\u001b[27m" : "\u001b[49m", piShellVisibleWidth),
|
|
36
|
+
promptPresentation: {
|
|
37
|
+
input: new PromptInput({ fg: (token, text) => surface.theme.fg(token, text) }, {
|
|
38
|
+
measure: piShellVisibleWidth,
|
|
39
|
+
truncate: piShellTruncateToWidth,
|
|
40
|
+
}),
|
|
41
|
+
styleSuggestion: text => surface.theme.fg("dim", text),
|
|
42
|
+
styleSuggestionCaret: caretCell,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
editor.setFocused?.(true);
|
|
46
|
+
return {
|
|
47
|
+
render(width) {
|
|
48
|
+
columns = width;
|
|
49
|
+
return editor.render(width);
|
|
50
|
+
},
|
|
51
|
+
handleInput: (data) => editor.handleInput?.(data),
|
|
52
|
+
handlePointer: (event) => editor.handlePointer(event),
|
|
53
|
+
getText: () => editor.getText(),
|
|
54
|
+
hasSelection: () => editor.hasSelection(),
|
|
55
|
+
ownsPointer: () => editor.ownsPointer(),
|
|
56
|
+
setFocused: (focused) => editor.setFocused?.(focused),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -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
|
+
}
|