@timurproko/a1 0.2.7-dev.788 → 0.2.7-dev.794
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/session-shell/session-shell-root.d.ts +2 -1
- package/dist/app/session-shell/session-shell-root.js +41 -15
- package/dist/app/session-shell/session-shell.d.ts +1 -0
- package/dist/app/session-shell/session-shell.js +15 -4
- package/dist/app/session-shell/session-viewport-controller.d.ts +2 -2
- package/dist/app/session-shell/session-viewport-controller.js +24 -12
- package/dist/cli/tabs.js +1 -1
- package/dist/composition/owned-ui.d.ts +2 -0
- package/dist/composition/owned-ui.js +42 -4
- package/dist/contracts/owned-ui/index.d.ts +1 -1
- package/dist/contracts/owned-ui/model.d.ts +3 -0
- package/dist/features/owned-ui/settings-app.js +9 -6
- package/dist/features/resident-tab/index.d.ts +3 -1
- package/dist/features/resident-tab/index.js +5 -1
- package/dist/features/resident-tab/shortcut-bindings-file.d.ts +8 -0
- package/dist/features/resident-tab/shortcut-bindings-file.js +40 -0
- package/dist/features/resident-tab/shortcut-declarations.d.ts +13 -0
- package/dist/features/resident-tab/{shortcuts.js → shortcut-declarations.js} +6 -17
- package/dist/features/resident-tab/shortcut-projection.d.ts +29 -0
- package/dist/features/resident-tab/shortcut-projection.js +64 -0
- package/dist/foundation/launch-guardian/exit-watcher.d.ts +14 -0
- package/dist/foundation/launch-guardian/exit-watcher.js +94 -0
- package/dist/foundation/launch-guardian/main.d.ts +2 -1
- package/dist/foundation/launch-guardian/main.js +58 -6
- package/dist/foundation/process-containment/{native-guardian-containment.d.ts → addon-containment.d.ts} +7 -5
- package/dist/foundation/process-containment/addon-containment.js +139 -0
- package/dist/foundation/process-containment/addon-process-inspector.d.ts +11 -0
- package/dist/foundation/process-containment/addon-process-inspector.js +36 -0
- package/dist/foundation/process-containment/addon.d.ts +42 -0
- package/dist/foundation/process-containment/addon.js +57 -0
- package/dist/foundation/process-containment/artifact.d.ts +1 -1
- package/dist/foundation/process-containment/artifact.js +6 -5
- package/dist/foundation/process-containment/contracts.d.ts +2 -0
- package/dist/foundation/process-containment/index.d.ts +4 -4
- package/dist/foundation/process-containment/index.js +3 -3
- package/dist/foundation/process-containment/native-process-inspector.d.ts +2 -1
- package/dist/foundation/process-containment/native-process-inspector.js +10 -10
- package/dist/foundation/release/bootstrap.js +54 -16
- package/dist/foundation/release/index.d.ts +1 -1
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/release-store.d.ts +12 -0
- package/dist/foundation/release/release-store.js +124 -2
- package/dist/foundation/resident-tabs/bounded-host-command.d.ts +3 -1
- package/dist/foundation/resident-tabs/bounded-host-command.js +6 -2
- package/dist/foundation/resident-tabs/bridge-client.d.ts +7 -0
- package/dist/foundation/resident-tabs/bridge-client.js +30 -1
- package/dist/foundation/resident-tabs/doctor.d.ts +0 -1
- package/dist/foundation/resident-tabs/doctor.js +4 -4
- package/dist/foundation/resident-tabs/ensure-terminal-host.d.ts +7 -2
- package/dist/foundation/resident-tabs/ensure-terminal-host.js +15 -11
- package/dist/foundation/resident-tabs/host-entry.d.ts +1 -0
- package/dist/foundation/resident-tabs/host-entry.js +17 -0
- package/dist/foundation/resident-tabs/index.d.ts +2 -2
- package/dist/foundation/resident-tabs/index.js +1 -1
- package/dist/foundation/resident-tabs/maintenance.d.ts +5 -4
- package/dist/foundation/resident-tabs/maintenance.js +32 -17
- package/dist/foundation/resident-tabs/prompt-journal.d.ts +0 -2
- package/dist/foundation/resident-tabs/prompt-journal.js +0 -1
- package/dist/foundation/resident-tabs/release-holds.d.ts +3 -2
- package/dist/foundation/resident-tabs/release-holds.js +16 -7
- package/dist/foundation/resident-tabs/settings.d.ts +0 -1
- package/dist/foundation/resident-tabs/settings.js +1 -7
- package/dist/foundation/resident-tabs/terminal-host-artifact.d.ts +11 -15
- package/dist/foundation/resident-tabs/terminal-host-artifact.js +57 -32
- package/dist/foundation/session-writer-lock/index.d.ts +1 -3
- package/dist/foundation/session-writer-lock/index.js +8 -6
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +2 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +13 -0
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +3 -1
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +1 -0
- package/dist/integrations/pi/components/shell-presenters-info.js +10 -30
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +4 -0
- package/dist/native/darwin-arm64/manifest.json +10 -7
- package/dist/native/darwin-arm64/process-guardian.node +0 -0
- package/dist/native/darwin-arm64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/native/darwin-arm64/terminal-host.manifest.json +16 -14
- package/dist/native/darwin-arm64/terminal-host.node +0 -0
- package/dist/native/darwin-x64/manifest.json +10 -7
- package/dist/native/darwin-x64/process-guardian.node +0 -0
- package/dist/native/darwin-x64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/native/darwin-x64/terminal-host.manifest.json +16 -14
- package/dist/native/darwin-x64/terminal-host.node +0 -0
- package/dist/native/linux-x64/manifest.json +10 -7
- package/dist/native/linux-x64/process-guardian.node +0 -0
- package/dist/native/linux-x64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/native/linux-x64/terminal-host.manifest.json +16 -14
- package/dist/native/linux-x64/terminal-host.node +0 -0
- package/dist/native/win32-x64/manifest.json +10 -7
- package/dist/native/win32-x64/process-guardian.node +0 -0
- package/dist/native/win32-x64/terminal-host-THIRD-PARTY-NOTICES.txt +1 -1
- package/dist/native/win32-x64/terminal-host.manifest.json +16 -14
- 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 +3 -2
- package/dist/runtime-payload-inventory.json +1 -0
- package/dist/ui/components/index.d.ts +2 -2
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/selection-copy.d.ts +2 -0
- package/dist/ui/components/selection-copy.js +13 -0
- package/dist/ui/components/submitted-prompt.d.ts +7 -4
- package/dist/ui/components/submitted-prompt.js +18 -10
- package/dist/ui/components/transcript-viewport.d.ts +10 -6
- package/dist/ui/components/transcript-viewport.js +28 -13
- package/dist/ui/settings/declarations.d.ts +13 -13
- package/dist/ui/settings/declarations.js +12 -11
- package/dist/ui/settings/migrations.js +7 -0
- package/docs/architecture/boundaries.md +10 -9
- package/docs/architecture/evidence/resident-tabs/macos-x64.md +1 -1
- package/docs/architecture/process-guardian-provenance.md +17 -11
- package/docs/architecture/project-structure.md +8 -0
- package/docs/architecture/resident-tabs.md +54 -36
- package/docs/architecture/terminal-host-provenance.md +6 -4
- package/docs/architecture/toolchain.md +6 -6
- package/docs/openspec-archive-automation.md +3 -3
- package/docs/validation.md +7 -3
- package/package.json +1 -1
- package/dist/features/resident-tab/shortcuts.d.ts +0 -10
- package/dist/foundation/process-containment/darwin-process-inspector.d.ts +0 -5
- package/dist/foundation/process-containment/darwin-process-inspector.js +0 -7
- package/dist/foundation/process-containment/native-guardian-containment.js +0 -152
- package/dist/foundation/process-containment/windows-process-inspector.d.ts +0 -19
- package/dist/foundation/process-containment/windows-process-inspector.js +0 -56
- package/dist/native/darwin-arm64/a1_session_lock.node +0 -0
- package/dist/native/darwin-arm64/process-guardian +0 -0
- package/dist/native/darwin-arm64/terminal-host +0 -0
- package/dist/native/darwin-x64/a1_session_lock.node +0 -0
- package/dist/native/darwin-x64/process-guardian +0 -0
- package/dist/native/darwin-x64/terminal-host +0 -0
- package/dist/native/linux-x64/a1_session_lock.node +0 -0
- package/dist/native/linux-x64/process-guardian +0 -0
- package/dist/native/linux-x64/terminal-host +0 -0
- package/dist/native/win32-x64/a1_session_lock.node +0 -0
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/native/win32-x64/terminal-host.exe +0 -0
|
@@ -46,6 +46,7 @@ export interface OwnedUiShellEngineOptions {
|
|
|
46
46
|
/** Resident tab quit routes detach the outer client without stopping this engine session. */
|
|
47
47
|
readonly residentTab?: {
|
|
48
48
|
requestDetach(): Promise<boolean>;
|
|
49
|
+
closeOwnedRoute?(route: string): void;
|
|
49
50
|
reportStatus?(status: "working" | "idle" | "stalled"): void;
|
|
50
51
|
readonly stallNoticeSeconds?: number;
|
|
51
52
|
admit?(input: {
|
|
@@ -53,7 +54,6 @@ export interface OwnedUiShellEngineOptions {
|
|
|
53
54
|
readonly sessionFile: string | null;
|
|
54
55
|
readonly kind: "prompt" | "steer" | "follow-up";
|
|
55
56
|
readonly text: string;
|
|
56
|
-
readonly images?: readonly unknown[];
|
|
57
57
|
}): Promise<{
|
|
58
58
|
readonly id: string;
|
|
59
59
|
}>;
|
|
@@ -192,6 +192,7 @@ export declare class OwnedUiSessionShellRoot implements PiTuiComponentPort {
|
|
|
192
192
|
readonly requestHyperlinkCleanup?: (rows?: readonly number[]) => void;
|
|
193
193
|
readonly enableDockInputReuse?: boolean;
|
|
194
194
|
readonly persistentHistory?: boolean;
|
|
195
|
+
readonly hideSettingsCommand?: boolean;
|
|
195
196
|
readonly historyEditor?: import("../../integrations/pi/components/index.js").HistoryEditorConstructor;
|
|
196
197
|
readonly onSubmit: (text: string) => void;
|
|
197
198
|
readonly onPasteRejected?: (error: unknown) => void;
|
|
@@ -96,9 +96,8 @@ export class OwnedUiSessionShellRoot {
|
|
|
96
96
|
...(handlers.promptImageLimit === undefined ? {} : { imageLimit: handlers.promptImageLimit }) });
|
|
97
97
|
this.#submittedPromptComposer = this.#customViewport
|
|
98
98
|
? {
|
|
99
|
-
layout: submittedPromptLayout,
|
|
100
|
-
compose: (rows, width, source, style) => composeSubmittedPromptRows(rows, width, source, { ...style, prefix: text => promptArrow(text, piTheme()) })
|
|
101
|
-
.map(row => nativeHyperlinkStyle(row, nativeTranscriptLinkColor)),
|
|
99
|
+
layout: (width, source) => submittedPromptLayout(width, source, this.#viewportController.config.timeFormat ?? "8:00 PM"),
|
|
100
|
+
compose: (rows, width, source, style) => composeSubmittedPromptRows(rows, width, source, { ...style, prefix: text => promptArrow(text, piTheme()) }, this.#viewportController.config.timeFormat ?? "8:00 PM").map(row => nativeHyperlinkStyle(row, nativeTranscriptLinkColor)),
|
|
102
101
|
}
|
|
103
102
|
: undefined;
|
|
104
103
|
this.#cwd = cwd;
|
|
@@ -430,6 +429,23 @@ export class OwnedUiSessionShellRoot {
|
|
|
430
429
|
const selectableDocumentRowCount = document.rows.length;
|
|
431
430
|
const dockStartRow = height - dockRows.length + 1;
|
|
432
431
|
const editorOffset = dock.editorOffset;
|
|
432
|
+
// Rationale: rendered chip tags are lossy presentation (truncated labels), so a frame drag over
|
|
433
|
+
// a draft holding chips stays visual-only; editor-owned word/line selection still copies the
|
|
434
|
+
// expanded chip text through its semantic route.
|
|
435
|
+
const draft = this.usesDefaultInputSurface() ? this.editor.getText() : "";
|
|
436
|
+
const promptCopyRows = draft.length > 0
|
|
437
|
+
&& !draft.split("\n").some(line => this.#promptChips.atomicRanges(line).length > 0)
|
|
438
|
+
? Math.max(0, dock.inputRows - 2)
|
|
439
|
+
: 0;
|
|
440
|
+
const copyableDockRows = [
|
|
441
|
+
...Array.from({ length: promptCopyRows }, (_value, index) => ({
|
|
442
|
+
row: editorOffset + index + 1,
|
|
443
|
+
prompt: index === 0 ? "first" : "continuation",
|
|
444
|
+
})),
|
|
445
|
+
...Array.from({ length: dock.footerRows }, (_value, index) => ({
|
|
446
|
+
row: dockRows.length - dock.footerRows + index,
|
|
447
|
+
})),
|
|
448
|
+
];
|
|
433
449
|
this.#viewportController.setInputSurfaceFrame(this.usesDefaultInputSurface() ? undefined : {
|
|
434
450
|
component: this.#inputSurface,
|
|
435
451
|
columnStart: 1,
|
|
@@ -458,7 +474,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
458
474
|
&& snapshot.inputSurface === inputSurface
|
|
459
475
|
&& snapshot.viewportRevision === viewportRevision
|
|
460
476
|
&& snapshot.selectionRevision === selectionRevision
|
|
461
|
-
? this.#viewportController.composeDockOnly(dockRows, width, height,
|
|
477
|
+
? this.#viewportController.composeDockOnly(dockRows, width, height, copyableDockRows)
|
|
462
478
|
: null;
|
|
463
479
|
if (frame === null) {
|
|
464
480
|
frame = this.#viewportController.compose({
|
|
@@ -474,7 +490,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
474
490
|
...(document.liveTailStartRow === undefined ? {} : { liveTailStartRow: document.liveTailStartRow }),
|
|
475
491
|
bottomAlignedTailRowCount: steeringRows.length + statusRows.length,
|
|
476
492
|
dockRows,
|
|
477
|
-
|
|
493
|
+
copyableDockRows,
|
|
478
494
|
promptAnchors: document.promptAnchors,
|
|
479
495
|
width,
|
|
480
496
|
height,
|
|
@@ -541,8 +557,11 @@ export class OwnedUiSessionShellRoot {
|
|
|
541
557
|
return this.#viewportController.hasSelection || this.editor.hasSelection();
|
|
542
558
|
}
|
|
543
559
|
setViewportConfig(config) {
|
|
544
|
-
if (this.#viewportController.setConfig(config))
|
|
560
|
+
if (this.#viewportController.setConfig(config)) {
|
|
561
|
+
this.#renderedRows.clear();
|
|
545
562
|
this.#documentLayouts.clear();
|
|
563
|
+
this.#visibleViewportSnapshot = undefined;
|
|
564
|
+
}
|
|
546
565
|
}
|
|
547
566
|
setFullscreenCopyOnSelect(enabled) {
|
|
548
567
|
this.#viewportController.setCopyOnSelect(enabled);
|
|
@@ -751,11 +770,13 @@ export class OwnedUiSessionShellRoot {
|
|
|
751
770
|
}
|
|
752
771
|
rows.push(...blockRows);
|
|
753
772
|
if (promptLike && blockRows[0] !== undefined) {
|
|
773
|
+
const source = pinnedPromptSource(block, blockRows[0], blockWidth, this.#viewportController.config.timeFormat);
|
|
754
774
|
promptAnchors.push({
|
|
755
775
|
id: block.id,
|
|
756
776
|
firstRow,
|
|
757
777
|
lastRow: Math.max(firstRow, rows.length - 1),
|
|
758
|
-
sourceRow:
|
|
778
|
+
sourceRow: source.row,
|
|
779
|
+
copySuffixWidth: source.copySuffixWidth,
|
|
759
780
|
prominentSourceRow: blockRows[0],
|
|
760
781
|
});
|
|
761
782
|
}
|
|
@@ -1322,20 +1343,25 @@ function withoutTerminalBackground(text) {
|
|
|
1322
1343
|
return text.replace(TERMINAL_BACKGROUND, "");
|
|
1323
1344
|
}
|
|
1324
1345
|
/** Preserve the stable metadata-grey foreground for every pinned timestamp state. */
|
|
1325
|
-
function
|
|
1346
|
+
function pinnedPromptSource(block, sourceRow, width, timeFormat) {
|
|
1347
|
+
const unchanged = { row: sourceRow, copySuffixWidth: 0 };
|
|
1326
1348
|
if (typeof block.payload !== "object" || block.payload === null)
|
|
1327
|
-
return
|
|
1349
|
+
return unchanged;
|
|
1328
1350
|
const value = block.payload.timestamp;
|
|
1329
1351
|
if (typeof value !== "number" || !Number.isFinite(value))
|
|
1330
|
-
return
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1352
|
+
return unchanged;
|
|
1353
|
+
const format = timeFormat ?? "8:00 PM";
|
|
1354
|
+
const timestamp = formatSubmittedPromptTime(value, format);
|
|
1355
|
+
if (timestamp === null || submittedPromptLayout(width, value, format).timestamp === null)
|
|
1356
|
+
return unchanged;
|
|
1334
1357
|
const rowWidth = displayWidth(sourceRow);
|
|
1335
1358
|
const timestampWidth = displayWidth(timestamp);
|
|
1336
1359
|
if (rowWidth < timestampWidth)
|
|
1337
|
-
return
|
|
1338
|
-
return
|
|
1360
|
+
return unchanged;
|
|
1361
|
+
return {
|
|
1362
|
+
row: overlaySpan(sourceRow, rowWidth - timestampWidth, rowWidth, paintPiSubmittedPromptTimestamp(timestamp)),
|
|
1363
|
+
copySuffixWidth: timestampWidth,
|
|
1364
|
+
};
|
|
1339
1365
|
}
|
|
1340
1366
|
/**
|
|
1341
1367
|
* The pinned-profile screen: a followed transcript scroll above the dock. The runtime mounts one such layout,
|
|
@@ -72,6 +72,7 @@ export declare class OwnedUiSessionPresenter implements OwnedUiHostedPresenter {
|
|
|
72
72
|
readonly mode: "regular" | "fullscreen";
|
|
73
73
|
readonly columns: number;
|
|
74
74
|
}): OwnedUiPresenterRelease;
|
|
75
|
+
openOwnedRoute(route: string): void;
|
|
75
76
|
hotkeysPresentation(): PiShellHotkeysPresentation;
|
|
76
77
|
}
|
|
77
78
|
/**
|
|
@@ -189,6 +189,7 @@ export class OwnedUiSessionPresenter {
|
|
|
189
189
|
}),
|
|
190
190
|
enableDockInputReuse: inputPresentation?.viewportReuse !== false,
|
|
191
191
|
footerSessionName: this.#residentTabOptions === undefined,
|
|
192
|
+
hideSettingsCommand: this.#residentTabOptions !== undefined,
|
|
192
193
|
persistentHistory: this.#customViewport && promptHistory !== undefined,
|
|
193
194
|
...(promptHistory === undefined ? {} : { historyEditor: promptHistory.editor }),
|
|
194
195
|
onSubmit: text => { void this.submit(text).catch(() => this.#reportSubmissionError()); },
|
|
@@ -270,7 +271,7 @@ export class OwnedUiSessionPresenter {
|
|
|
270
271
|
// Invariant: the presenter owns its root (theme subscription and helper clients) and disposes it once the
|
|
271
272
|
// terminal no longer renders it.
|
|
272
273
|
constructed.push(() => this.root.dispose());
|
|
273
|
-
this.#restoreResidentInput();
|
|
274
|
+
this.#restoreResidentInput(options.history?.imageSidecar);
|
|
274
275
|
const initialPiSettings = this.backend.settings.snapshot();
|
|
275
276
|
this.#programStatus = new ProgramStatusReporter(status => this.#terminal.setProgramStatus(status), () => this.view().status.footer?.sessionName ?? undefined);
|
|
276
277
|
this.#reloadPresentation = reloadPresentation;
|
|
@@ -802,7 +803,6 @@ export class OwnedUiSessionPresenter {
|
|
|
802
803
|
sessionFile: this.#currentSessionFile(),
|
|
803
804
|
kind: type,
|
|
804
805
|
text: input,
|
|
805
|
-
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
806
806
|
});
|
|
807
807
|
}
|
|
808
808
|
catch {
|
|
@@ -1213,11 +1213,13 @@ export class OwnedUiSessionPresenter {
|
|
|
1213
1213
|
this.#resolveStoppedLifecycle();
|
|
1214
1214
|
}
|
|
1215
1215
|
}
|
|
1216
|
-
#restoreResidentInput() {
|
|
1216
|
+
#restoreResidentInput(imageSidecar) {
|
|
1217
1217
|
const recovered = this.#residentTabOptions?.recovered;
|
|
1218
1218
|
if (recovered === undefined)
|
|
1219
1219
|
return;
|
|
1220
|
-
const prompts = recovered.prompts
|
|
1220
|
+
const prompts = recovered.prompts
|
|
1221
|
+
.map(prompt => this.root.rehydrateHistoryText(prompt.text, id => imageSidecar?.readAttachment(id) ?? null))
|
|
1222
|
+
.filter(Boolean);
|
|
1221
1223
|
if (prompts.length > 0) {
|
|
1222
1224
|
this.root.editor.setText(prompts[0]);
|
|
1223
1225
|
if (recovered.draft)
|
|
@@ -1342,6 +1344,8 @@ export class OwnedUiSessionPresenter {
|
|
|
1342
1344
|
return { outcome: "completed", diagnostic: null };
|
|
1343
1345
|
}
|
|
1344
1346
|
if (request.command === "settings" && request.selection === undefined && request.confirmed === undefined) {
|
|
1347
|
+
if (this.#residentTabOptions !== undefined)
|
|
1348
|
+
return rejected("Settings is available from the global Settings tab.");
|
|
1345
1349
|
this.showSettingsSelector();
|
|
1346
1350
|
return { outcome: "completed", diagnostic: null };
|
|
1347
1351
|
}
|
|
@@ -1716,6 +1720,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1716
1720
|
void onClosed?.()?.catch(() => undefined);
|
|
1717
1721
|
}
|
|
1718
1722
|
catch { /* Rationale: a failed acknowledgement stays pending. */ }
|
|
1723
|
+
this.#residentTabOptions?.closeOwnedRoute?.(route);
|
|
1719
1724
|
}
|
|
1720
1725
|
},
|
|
1721
1726
|
});
|
|
@@ -1763,6 +1768,9 @@ export class OwnedUiSessionPresenter {
|
|
|
1763
1768
|
});
|
|
1764
1769
|
this.#dialogId = dialog.id;
|
|
1765
1770
|
}
|
|
1771
|
+
openOwnedRoute(route) {
|
|
1772
|
+
this.#openOwnedRoute(route);
|
|
1773
|
+
}
|
|
1766
1774
|
hotkeysPresentation() {
|
|
1767
1775
|
const presentation = this.root.hotkeysPresentation();
|
|
1768
1776
|
return this.#residentTabOptions === undefined ? presentation : { ...presentation, residentTabs: true };
|
|
@@ -1772,6 +1780,9 @@ export class OwnedUiSessionPresenter {
|
|
|
1772
1780
|
const separator = body.search(/\s/);
|
|
1773
1781
|
const name = separator < 0 ? body : body.slice(0, separator);
|
|
1774
1782
|
const argument = separator < 0 ? "" : body.slice(separator + 1).trimStart();
|
|
1783
|
+
if (name === "settings" && this.#residentTabOptions !== undefined) {
|
|
1784
|
+
return rejected("Settings is available from the global Settings tab.");
|
|
1785
|
+
}
|
|
1775
1786
|
if (this.#routeHost?.claims(name))
|
|
1776
1787
|
return this.#openOwnedRoute(name);
|
|
1777
1788
|
if (this.#isWorkflowRoute(name))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PiTuiPointerSurface } from "../../integrations/pi/tui-runtime/contracts.js";
|
|
2
2
|
import type { OwnedUiViewportSettings } from "../../contracts/owned-ui/index.js";
|
|
3
3
|
import { type TranscriptViewportFrame, type TranscriptViewportFrameInput } from "../../ui/components/transcript-viewport.js";
|
|
4
|
-
import type
|
|
4
|
+
import { type SelectionCopySnapshot } from "../../ui/components/selection-copy.js";
|
|
5
5
|
import type { PiShellEditorPort } from "../../integrations/pi/components/shell-shared-facade.js";
|
|
6
6
|
import type { PasteEvent } from "./paste-protocol.js";
|
|
7
7
|
export interface SessionViewportControllerOptions {
|
|
@@ -64,7 +64,7 @@ export declare class SessionViewportController {
|
|
|
64
64
|
setOverlaySurfaces(surfaces: readonly PiTuiPointerSurface[] | null): void;
|
|
65
65
|
get inputGeometryReady(): boolean;
|
|
66
66
|
compose(input: Omit<TranscriptViewportFrameInput, "pointerPosition">): TranscriptViewportFrame;
|
|
67
|
-
composeDockOnly(dockRows: readonly string[], width: number, height: number,
|
|
67
|
+
composeDockOnly(dockRows: readonly string[], width: number, height: number, copyableDockRows?: TranscriptViewportFrameInput["copyableDockRows"]): TranscriptViewportFrame | null;
|
|
68
68
|
/** Returns true when document wrapping may have changed. */
|
|
69
69
|
setConfig(config: OwnedUiViewportSettings): boolean;
|
|
70
70
|
resumeFollowing(): void;
|
|
@@ -3,6 +3,7 @@ import { TranscriptViewport } from "../../ui/components/transcript-viewport.js";
|
|
|
3
3
|
import { readVisibleHyperlinks } from "../../ui/components/visible-hyperlinks.js";
|
|
4
4
|
import { routeMouseInput } from "../../ui/components/mouse.js";
|
|
5
5
|
import { scrollForTrackPage, scrollForThumbRow, scrollbarSelectionRows, scrollbarWheelRows } from "../../ui/components/scrollbar.js";
|
|
6
|
+
import { literalSelectionCopySnapshot } from "../../ui/components/selection-copy.js";
|
|
6
7
|
function withinTailControl(region, column, row) {
|
|
7
8
|
return row >= region.rowStart && row <= region.rowEnd && column >= region.columnStart && column <= region.columnEnd;
|
|
8
9
|
}
|
|
@@ -22,6 +23,7 @@ export class SessionViewportController {
|
|
|
22
23
|
#pasteDiagnosticRequest = 0;
|
|
23
24
|
#viewport = new TranscriptViewport();
|
|
24
25
|
#config = {
|
|
26
|
+
timeFormat: "8:00 PM",
|
|
25
27
|
scrollbarAppearance: "auto",
|
|
26
28
|
scrollbarStyle: "thin",
|
|
27
29
|
scrollbarSpeed: "normal",
|
|
@@ -165,16 +167,18 @@ export class SessionViewportController {
|
|
|
165
167
|
}
|
|
166
168
|
return frame;
|
|
167
169
|
}
|
|
168
|
-
composeDockOnly(dockRows, width, height,
|
|
169
|
-
return this.#viewport.composeDockOnly(dockRows, width, height,
|
|
170
|
+
composeDockOnly(dockRows, width, height, copyableDockRows = []) {
|
|
171
|
+
return this.#viewport.composeDockOnly(dockRows, width, height, copyableDockRows);
|
|
170
172
|
}
|
|
171
173
|
/** Returns true when document wrapping may have changed. */
|
|
172
174
|
setConfig(config) {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
const normalized = { ...config, timeFormat: config.timeFormat ?? "8:00 PM" };
|
|
176
|
+
const layoutChanged = normalized.scrollbarAppearance !== this.#config.scrollbarAppearance
|
|
177
|
+
|| normalized.timeFormat !== this.#config.timeFormat;
|
|
178
|
+
this.#config = normalized;
|
|
179
|
+
this.#viewport.setConfig(normalized);
|
|
176
180
|
this.#requestRender();
|
|
177
|
-
return
|
|
181
|
+
return layoutChanged;
|
|
178
182
|
}
|
|
179
183
|
resumeFollowing() {
|
|
180
184
|
if (!this.#enabled)
|
|
@@ -302,12 +306,10 @@ export class SessionViewportController {
|
|
|
302
306
|
});
|
|
303
307
|
}
|
|
304
308
|
if (data === "\u0003") {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
else if (this.#viewport.hasSelection) {
|
|
310
|
-
const copySelection = this.#viewport.captureSelectedText("explicit");
|
|
309
|
+
// Invariant: the newest complete-frame gesture owns explicit copy even if an
|
|
310
|
+
// older editor word/line selection remains painted beneath it.
|
|
311
|
+
if (this.#viewport.hasSelection) {
|
|
312
|
+
const copySelection = this.#viewport.captureSelectedText();
|
|
311
313
|
this.#viewport.clearSelection();
|
|
312
314
|
this.#stopSelectionAutoScroll();
|
|
313
315
|
this.#requestRender();
|
|
@@ -315,6 +317,10 @@ export class SessionViewportController {
|
|
|
315
317
|
? { data: "", consumed: true }
|
|
316
318
|
: { data: "", consumed: true, copySelection };
|
|
317
319
|
}
|
|
320
|
+
if (editorActive && this.#editor.hasSelection()) {
|
|
321
|
+
if (this.#viewport.clearSelection())
|
|
322
|
+
this.#requestRender();
|
|
323
|
+
}
|
|
318
324
|
}
|
|
319
325
|
const previousPrompt = SHIFT_UP_INPUTS.has(data) || this.#editor.matchesTerminalKey(data, "alt+home");
|
|
320
326
|
if (editorActive && allowWheel && (previousPrompt || SHIFT_DOWN_INPUTS.has(data))) {
|
|
@@ -541,6 +547,12 @@ export class SessionViewportController {
|
|
|
541
547
|
const editorRow = pendingEditorClick.row - this.#editorPointerFrame.rowStart + 1;
|
|
542
548
|
this.#editor.handlePointer({ kind: "press", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
543
549
|
this.#editor.handlePointer({ kind: "release", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
550
|
+
if (this.#copyOnSelect) {
|
|
551
|
+
const selected = this.#editor.selectedText?.();
|
|
552
|
+
if (selected !== undefined) {
|
|
553
|
+
completedCopy = literalSelectionCopySnapshot(selected, this.#viewport.selectionRevision) ?? undefined;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
544
556
|
}
|
|
545
557
|
forceRepaint = true;
|
|
546
558
|
repaint = true;
|
package/dist/cli/tabs.js
CHANGED
|
@@ -30,7 +30,7 @@ export async function runTabsCommand(request, options = {}) {
|
|
|
30
30
|
stateDir: report.stateDir,
|
|
31
31
|
hostStatus: report,
|
|
32
32
|
releaseRoots,
|
|
33
|
-
settings: {
|
|
33
|
+
settings: { tabsAutoName: settings.tabsAutoName },
|
|
34
34
|
});
|
|
35
35
|
if (request.json)
|
|
36
36
|
stdout(`${JSON.stringify({ schema: "a1-tabs-doctor-v1", path: bundle.path, bytes: bundle.bytes, dropped: bundle.dropped })}\n`);
|
|
@@ -87,4 +87,6 @@ export declare function composeOwnedUiApplication(options?: OwnedUiCompositionOp
|
|
|
87
87
|
export declare function composeOwnedUi(options?: OwnedUiCompositionOptions): Promise<OwnedUiComposition>;
|
|
88
88
|
export declare function bindResidentTabBridge(tabBridge: TabBridgeClient, backend: Pick<ComposedSessionBackend, "identity" | "session" | "workflows" | "generateResidentTabName">, recovery?: Pick<ResidentTabRecovery, "settled"> | null, options?: {
|
|
89
89
|
readonly autoName?: boolean;
|
|
90
|
+
readonly openRoute?: (route: "settings") => void;
|
|
90
91
|
}): Promise<() => void>;
|
|
92
|
+
export declare function correlateResidentTabSubmission(recovery: Pick<ResidentTabRecovery, "correlated" | "settled">, backend: Pick<ComposedSessionBackend, "identity" | "session">, submissionId: string, entryId: string): Promise<void>;
|
|
@@ -12,6 +12,8 @@ import { createPiSessionPresenters } from "../integrations/pi/session-presenters
|
|
|
12
12
|
import { ClipboardDiagnosticCapture } from "../app/session-shell/clipboard-diagnostics.js";
|
|
13
13
|
import { createOwnedUiClipboardServices } from "../app/session-shell/clipboard-services.js";
|
|
14
14
|
import { createPiKeybindingsHost } from "../integrations/pi/components/shell-shared-facade.js";
|
|
15
|
+
import { projectResidentTabShortcuts } from "../features/resident-tab/shortcut-projection.js";
|
|
16
|
+
import { readShortcutBindingsFile } from "../features/resident-tab/shortcut-bindings-file.js";
|
|
15
17
|
import { OwnedUiSessionPresenter, OwnedUiTerminalHost, sessionTerminalHostOptions, } from "../app/session-shell/session-shell.js";
|
|
16
18
|
import { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
17
19
|
import { createPiTerminalBridge } from "../integrations/pi/tui-runtime/presentation-adapter.js";
|
|
@@ -100,7 +102,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
100
102
|
namespace: PRODUCT_IDENTITY.commandName,
|
|
101
103
|
legacyConfigDir: productPaths.configDir,
|
|
102
104
|
agentProvider: () => backend.settingsPort(),
|
|
103
|
-
...(options.hideTabSettings ? { hiddenOwnedSettingIds: ["
|
|
105
|
+
...(options.hideTabSettings ? { hiddenOwnedSettingIds: ["tabsAutoName"] } : {}),
|
|
104
106
|
hiddenAgentSettingIds: ["fullscreenWheelScrollLines"],
|
|
105
107
|
agentSettingLabelOverrides: { fullscreenCopyOnSelect: "Copy on select" },
|
|
106
108
|
});
|
|
@@ -165,7 +167,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
165
167
|
if (tabBridge !== null && settings !== null && ownedSurfaces)
|
|
166
168
|
tabBridge.accent(settings.value("accentColor"));
|
|
167
169
|
let removeControllerBoundaryInput = () => { };
|
|
168
|
-
|
|
170
|
+
let unsubscribeTabBridge = () => { };
|
|
169
171
|
let releaseNotes = null;
|
|
170
172
|
let releaseNotesFailure;
|
|
171
173
|
if (ownedSurfaces) {
|
|
@@ -254,7 +256,18 @@ export async function composeOwnedUi(options = {}) {
|
|
|
254
256
|
? new ClipboardDiagnosticCapture(clipboardDestination) : null;
|
|
255
257
|
// Invariant: process-wide services are created once here and borrowed by every session shell. The
|
|
256
258
|
// keybinding registry is applied before any presenter is built, so none of them reads Pi's defaults.
|
|
257
|
-
const
|
|
259
|
+
const keybindingsHost = createPiKeybindingsHost({ profile: ownedSurfaces ? "a1" : "pi", agentDir: backend.identity.agentDir });
|
|
260
|
+
// Invariant: the resident host dispatches and labels the tab shortcuts this child projects
|
|
261
|
+
// from its effective declarations, so a customization reload republishes the projection.
|
|
262
|
+
const publishTabShortcuts = () => tabBridge?.shortcuts(projectResidentTabShortcuts({
|
|
263
|
+
configured: readShortcutBindingsFile(backend.identity.agentDir),
|
|
264
|
+
reserved: keybindingsHost.manager.getEffectiveConfig(),
|
|
265
|
+
}).assignments);
|
|
266
|
+
const keybindings = tabBridge === null ? keybindingsHost : {
|
|
267
|
+
...keybindingsHost,
|
|
268
|
+
reload: () => { keybindingsHost.reload(); publishTabShortcuts(); },
|
|
269
|
+
};
|
|
270
|
+
publishTabShortcuts();
|
|
258
271
|
const clipboardServices = ownedSurfaces ? createOwnedUiClipboardServices() : null;
|
|
259
272
|
let createdTerminalHost;
|
|
260
273
|
let terminalHost;
|
|
@@ -280,11 +293,15 @@ export async function composeOwnedUi(options = {}) {
|
|
|
280
293
|
...(ownedSurfaces ? { sessionLayout: "custom-viewport" } : {}),
|
|
281
294
|
...(tabBridge === null || tabRecovery === null ? {} : { residentTab: {
|
|
282
295
|
requestDetach: () => tabBridge.requestDetach(),
|
|
296
|
+
closeOwnedRoute: route => {
|
|
297
|
+
if (tabBridge.tabId.startsWith("settings-") && route === "settings")
|
|
298
|
+
void tabBridge.requestClose();
|
|
299
|
+
},
|
|
283
300
|
reportStatus: status => tabBridge.status(status),
|
|
284
301
|
stallNoticeSeconds: 300,
|
|
285
302
|
admit: input => tabRecovery.admit({ ...input, incarnation: options.tab.incarnation }),
|
|
286
303
|
dispatched: () => tabRecovery.dispatched(),
|
|
287
|
-
correlated: (submissionId, entryId) => tabRecovery
|
|
304
|
+
correlated: (submissionId, entryId) => correlateResidentTabSubmission(tabRecovery, backend, submissionId, entryId),
|
|
288
305
|
checkpoint: text => tabRecovery.checkpoint(text),
|
|
289
306
|
gracefulStop: sessionFile => tabRecovery.gracefulStop(sessionFile),
|
|
290
307
|
...(recoveredTabInput === undefined ? {} : { recovered: recoveredTabInput }),
|
|
@@ -331,6 +348,12 @@ export async function composeOwnedUi(options = {}) {
|
|
|
331
348
|
if (recoveryDegraded)
|
|
332
349
|
presentRecoveryDegraded(true);
|
|
333
350
|
terminalHost.attach(presenter);
|
|
351
|
+
if (tabBridge !== null) {
|
|
352
|
+
unsubscribeTabBridge = await bindResidentTabBridge(tabBridge, backend, tabRecovery, {
|
|
353
|
+
autoName: settings?.value("tabsAutoName") ?? true,
|
|
354
|
+
openRoute: route => presenter.openOwnedRoute(route),
|
|
355
|
+
});
|
|
356
|
+
}
|
|
334
357
|
}
|
|
335
358
|
catch (error) {
|
|
336
359
|
await createdTerminalHost?.dispose().catch(() => undefined);
|
|
@@ -463,6 +486,12 @@ export async function bindResidentTabBridge(tabBridge, backend, recovery = null,
|
|
|
463
486
|
if (command.type === "rename") {
|
|
464
487
|
void backend.workflows.executeWorkflow({ command: "name", argument: command.name }).catch(() => { });
|
|
465
488
|
}
|
|
489
|
+
else if (command.type === "route") {
|
|
490
|
+
if (options.openRoute !== undefined)
|
|
491
|
+
options.openRoute(command.route);
|
|
492
|
+
else
|
|
493
|
+
void backend.workflows.executeWorkflow({ command: command.route, argument: "" }).catch(() => { });
|
|
494
|
+
}
|
|
466
495
|
else if (command.type === "stop") {
|
|
467
496
|
void backend.session.dispose().catch(() => { });
|
|
468
497
|
}
|
|
@@ -502,6 +531,14 @@ export async function bindResidentTabBridge(tabBridge, backend, recovery = null,
|
|
|
502
531
|
unsubscribeEvents();
|
|
503
532
|
};
|
|
504
533
|
}
|
|
534
|
+
export async function correlateResidentTabSubmission(recovery, backend, submissionId, entryId) {
|
|
535
|
+
await recovery.correlated(submissionId, entryId);
|
|
536
|
+
// Concurrency: a normal prompt command can resolve after the ready transition already fired.
|
|
537
|
+
// Re-read lifecycle only after correlation is active; a concurrent ready observer and this path
|
|
538
|
+
// safely race because recovery consumes the active entry once and retirement is idempotent.
|
|
539
|
+
if (backend.session.view().lifecycle !== "busy")
|
|
540
|
+
await recovery.settled(currentBackendSessionFile(backend));
|
|
541
|
+
}
|
|
505
542
|
function currentBackendSessionFile(backend) {
|
|
506
543
|
const direct = backend.identity.currentSessionFile?.();
|
|
507
544
|
if (direct !== undefined && direct !== null)
|
|
@@ -523,6 +560,7 @@ function quitOutroSettingsSnapshot(settings) {
|
|
|
523
560
|
}
|
|
524
561
|
function viewportSettingsSnapshot(settings) {
|
|
525
562
|
return {
|
|
563
|
+
timeFormat: settings.value("timeFormat"),
|
|
526
564
|
scrollbarAppearance: settings.value("scrollbarAppearance"),
|
|
527
565
|
scrollbarStyle: settings.value("scrollbarStyle"),
|
|
528
566
|
scrollbarSpeed: settings.value("scrollbarSpeed"),
|
|
@@ -3,7 +3,7 @@ export type UiAccentColor = "purple" | "blue" | "cyan" | "green" | "orange" | "p
|
|
|
3
3
|
export { OWNED_UI_EXTENSION_CONTRACT_VERSION, OWNED_UI_EXTENSION_RENDER_CALLBACKS, OWNED_UI_EXTENSION_UI_CALLBACKS, OWNED_UI_EXTENSION_UI_PROPERTIES, assertOwnedUiExtensionUiPort, } from "./extension-ui.js";
|
|
4
4
|
export type { OwnedUiExtensionAutocompleteItem, OwnedUiExtensionAutocompleteProvider, OwnedUiExtensionAutocompleteProviderFactory, OwnedUiExtensionAutocompleteSuggestions, OwnedUiExtensionComponent, OwnedUiExtensionComponentFactory, OwnedUiExtensionComponentFactoryContext, OwnedUiExtensionCustomFactory, OwnedUiExtensionCustomOptions, OwnedUiExtensionDialogOptions, OwnedUiExtensionEditorComponent, OwnedUiExtensionEditorFactory, OwnedUiExtensionEditorThemePort, OwnedUiExtensionEntryRenderInput, OwnedUiExtensionFooterDataPort, OwnedUiExtensionFooterFactory, OwnedUiExtensionInputListener, OwnedUiExtensionKeybindingsPort, OwnedUiExtensionMessageRenderInput, OwnedUiExtensionNotificationSeverity, OwnedUiExtensionOverlayAnchor, OwnedUiExtensionOverlayHandle, OwnedUiExtensionOverlayMargin, OwnedUiExtensionOverlayOptions, OwnedUiExtensionRenderCallback, OwnedUiExtensionRendererPort, OwnedUiExtensionRuntimePort, OwnedUiExtensionSelectListThemePort, OwnedUiExtensionSizeValue, OwnedUiExtensionTerminalPort, OwnedUiExtensionThemeBackground, OwnedUiExtensionThemeColor, OwnedUiExtensionThemeInfo, OwnedUiExtensionThemePort, OwnedUiExtensionToolRenderContext, OwnedUiExtensionUiCallback, OwnedUiExtensionUiPort, OwnedUiExtensionUiProperty, OwnedUiExtensionWidgetOptions, OwnedUiExtensionWidgetPlacement, OwnedUiExtensionWorkingIndicatorOptions, } from "./extension-ui.js";
|
|
5
5
|
export { OWNED_UI_CONTRACT_VERSION } from "./model.js";
|
|
6
|
-
export type { OwnedUiBackgroundSettingsPort, OwnedUiBackgroundStyle, OwnedUiBlockStatus, OwnedUiCommand, OwnedUiCommandOutcome, OwnedUiCorrelationId, OwnedUiCustomization, OwnedUiDiagnostics, OwnedUiDialog, OwnedUiEditorState, OwnedUiEntityId, OwnedUiEvent, OwnedUiFooterView, OwnedUiImageAttachment, OwnedUiLifecycle, OwnedUiModelInfo, OwnedUiOverlay, OwnedUiPromptSuggestionGeneratorPort, OwnedUiPromptSuggestionIdentity, OwnedUiPromptSuggestionReasoning, OwnedUiPromptSuggestionRequest, OwnedUiPromptSuggestionResult, OwnedUiPromptSuggestionState, OwnedUiQuitOutroSettings, OwnedUiQuitOutroSettingsPort, OwnedUiSessionId, OwnedUiSessionViewModel, OwnedUiSeverity, OwnedUiSlotId, OwnedUiSnapshot, OwnedUiStatusView, OwnedUiTerminalSurface, OwnedUiThinkingLevel, OwnedUiToolRendering, OwnedUiToolResultPart, OwnedUiToolState, OwnedUiTranscriptBlock, OwnedUiTranscriptBlockKind, OwnedUiTranscriptImageReference, OwnedUiUsageView, OwnedUiViewportSettings, OwnedUiViewportSettingsPort, } from "./model.js";
|
|
6
|
+
export type { OwnedUiBackgroundSettingsPort, OwnedUiBackgroundStyle, OwnedUiBlockStatus, OwnedUiCommand, OwnedUiCommandOutcome, OwnedUiCorrelationId, OwnedUiCustomization, OwnedUiDiagnostics, OwnedUiDialog, OwnedUiEditorState, OwnedUiEntityId, OwnedUiEvent, OwnedUiFooterView, OwnedUiImageAttachment, OwnedUiLifecycle, OwnedUiModelInfo, OwnedUiOverlay, OwnedUiPromptSuggestionGeneratorPort, OwnedUiPromptSuggestionIdentity, OwnedUiPromptSuggestionReasoning, OwnedUiPromptSuggestionRequest, OwnedUiPromptSuggestionResult, OwnedUiPromptSuggestionState, OwnedUiQuitOutroSettings, OwnedUiQuitOutroSettingsPort, OwnedUiSessionId, OwnedUiSessionViewModel, OwnedUiSeverity, OwnedUiSlotId, OwnedUiSnapshot, OwnedUiStatusView, OwnedUiTerminalSurface, OwnedUiThinkingLevel, OwnedUiTimeFormat, OwnedUiToolRendering, OwnedUiToolResultPart, OwnedUiToolState, OwnedUiTranscriptBlock, OwnedUiTranscriptBlockKind, OwnedUiTranscriptImageReference, OwnedUiUsageView, OwnedUiViewportSettings, OwnedUiViewportSettingsPort, } from "./model.js";
|
|
7
7
|
export type { OwnedUiExtensionPort, OwnedUiSessionBackend, OwnedUiSessionCatalogPort, OwnedUiSessionFactory, OwnedUiSessionIdentityPort, OwnedUiSessionPort, OwnedUiSessionRequest, OwnedUiSessionSettingsPort, OwnedUiWorkflowPort, } from "./session-backend.js";
|
|
8
8
|
export type { OwnedUiDialogHost, OwnedUiInputSurface, OwnedUiPresenterHost, OwnedUiSessionPresenter, OwnedUiSessionPresenters, OwnedUiShortcutDescription, OwnedUiTerminalHost, OwnedUiTranscriptRendererPort, } from "./session-presenters.js";
|
|
9
9
|
export { OWNED_UI_HIDDEN_COMMAND_NAMES, OWNED_UI_MODELS_COMMAND_NAME, OWNED_UI_WORKFLOW_COMMAND_NAMES, } from "./session-workflows.js";
|
|
@@ -53,7 +53,10 @@ export interface OwnedUiPromptSuggestionGeneratorPort {
|
|
|
53
53
|
generate(request: OwnedUiPromptSuggestionRequest): Promise<OwnedUiPromptSuggestionResult>;
|
|
54
54
|
}
|
|
55
55
|
export type OwnedUiThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
56
|
+
export type OwnedUiTimeFormat = "20:00" | "8:00 PM";
|
|
56
57
|
export interface OwnedUiViewportSettings {
|
|
58
|
+
/** Omitted by older SDK callers; bare A1 composition always supplies the owned default. */
|
|
59
|
+
readonly timeFormat?: OwnedUiTimeFormat;
|
|
57
60
|
readonly scrollbarAppearance: "auto" | "always" | "hidden";
|
|
58
61
|
readonly scrollbarStyle: "thin" | "thick";
|
|
59
62
|
/** normal is baseline; fast is 2x normal; high is normal plus fast. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DIALOG_BACK_SHORTCUT_HINT, DIALOG_CLOSE_SHORTCUT_HINT } from "../../contracts/presentation/index.js";
|
|
2
|
-
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, assertNoShortcutConflicts, blockJumpTarget, numericValues, RAIL_COLUMNS, renderDialogPanel, renderSteppedDialogPanel, renderEmptyState, renderGroupHeader, renderInputRow, renderListRow, renderNote, renderShortcutHintsWithClose, menuRowAt, regionAt, renderValueMenu, withScrollbarRail, stepperEnds, steppedValue, truncateToWidth, valueColumnFor, valueMenuFrame, blockRowSpan, displayWidth, handleLineInputKey, humanizeLabel, humanizeTitle, indexOfKey, layoutList, moveSelection, rowKey, scrollForSelection, scrollForTrackPage, scrollbarGeometry, scrollbarPresentation, ScrollbarRails, scrollbarWheelRows, selectableIndexes, } from "../../ui/components/index.js";
|
|
2
|
+
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, assertNoShortcutConflicts, blockJumpTarget, numericValues, RAIL_COLUMNS, renderDialogPanel, renderSteppedDialogPanel, renderEmptyState, renderGroupHeader, renderInputRow, renderListRow, renderNote, renderShortcutHintsWithClose, menuRowAt, regionAt, renderValueMenu, withScrollbarRail, stepperEnds, steppedValue, truncateToWidth, valueColumnFor, valueMenuFrame, blockRowSpan, displayWidth, formatLocalTime, handleLineInputKey, humanizeLabel, humanizeTitle, indexOfKey, layoutList, moveSelection, rowKey, scrollForSelection, scrollForTrackPage, scrollbarGeometry, scrollbarPresentation, ScrollbarRails, scrollbarWheelRows, selectableIndexes, } from "../../ui/components/index.js";
|
|
3
3
|
import { SETTINGS_APP_ID } from "./settings-route.js";
|
|
4
4
|
export { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
5
5
|
const SCOPE = SETTINGS_APP_ID;
|
|
@@ -921,7 +921,7 @@ export class SettingsApp {
|
|
|
921
921
|
? CONFIGURE
|
|
922
922
|
: shown === null
|
|
923
923
|
? describeRaw(entry.rawValue)
|
|
924
|
-
:
|
|
924
|
+
: displaySettingValue(entry, shown);
|
|
925
925
|
const range = rangeOf(entry);
|
|
926
926
|
return {
|
|
927
927
|
key,
|
|
@@ -938,11 +938,11 @@ export class SettingsApp {
|
|
|
938
938
|
return lines;
|
|
939
939
|
}
|
|
940
940
|
const state = {
|
|
941
|
-
choices: menu.choices.map(choice =>
|
|
941
|
+
choices: menu.choices.map(choice => displaySettingValue(menu.entry, choice)),
|
|
942
942
|
...(menu.entry.id === "accentColor" ? {
|
|
943
943
|
previews: menu.choices.map(choice => theme.accentPreview?.(String(choice), "■") ?? ""),
|
|
944
944
|
} : {}),
|
|
945
|
-
current: this.#shownValue(menu.entry) === null ? null :
|
|
945
|
+
current: this.#shownValue(menu.entry) === null ? null : displaySettingValue(menu.entry, this.#shownValue(menu.entry)),
|
|
946
946
|
index: menu.index,
|
|
947
947
|
};
|
|
948
948
|
const frame = valueMenuFrame(state, {
|
|
@@ -1084,8 +1084,11 @@ function labelOf(entry) {
|
|
|
1084
1084
|
function rangeOf(entry) {
|
|
1085
1085
|
return { minimum: entry.minimum, maximum: entry.maximum, values: numericValues(entry.choices) };
|
|
1086
1086
|
}
|
|
1087
|
-
/** Booleans read as yes and no;
|
|
1088
|
-
function
|
|
1087
|
+
/** Booleans read as yes and no; time-format choices preview the current local time. */
|
|
1088
|
+
function displaySettingValue(entry, value) {
|
|
1089
|
+
if (entry.backend === "a1" && entry.id === "timeFormat" && (value === "20:00" || value === "8:00 PM")) {
|
|
1090
|
+
return formatLocalTime(new Date(), value) ?? value;
|
|
1091
|
+
}
|
|
1089
1092
|
if (typeof value === "boolean")
|
|
1090
1093
|
return value ? "yes" : "no";
|
|
1091
1094
|
return String(value);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { AUTO_NAME_MAX_LENGTH, AUTO_NAME_TIMEOUT_MS, AUTO_NAME_TOKEN_BUDGETS, fallbackAutoName, generateAutoName, normalizeAutoName, type AutoNameCompletion, } from "./auto-name.js";
|
|
2
|
-
export { RESIDENT_TAB_SHORTCUTS,
|
|
2
|
+
export { RESIDENT_TAB_SHORTCUTS, type ResidentTabAction, type ResidentTabShortcut, } from "./shortcut-declarations.js";
|
|
3
|
+
export { projectResidentTabShortcuts, RESIDENT_TAB_GLOBAL_SHORTCUTS, type ResidentTabGlobalAction, type ResidentTabShortcutConflict, type ResidentTabShortcutProjection, type ShortcutBindings, } from "./shortcut-projection.js";
|
|
4
|
+
export { readShortcutBindingsFile } from "./shortcut-bindings-file.js";
|
|
3
5
|
export { deriveResidentTabStatus, type ResidentTabDerivedStatus, type ResidentTabFacts, } from "./status-deriver.js";
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export { AUTO_NAME_MAX_LENGTH, AUTO_NAME_TIMEOUT_MS, AUTO_NAME_TOKEN_BUDGETS, fallbackAutoName, generateAutoName, normalizeAutoName, } from "./auto-name.js";
|
|
2
|
-
|
|
2
|
+
// Performance: the registry builder lives in `shortcuts.ts`, outside this barrel, so startup
|
|
3
|
+
// presentation can read the declarations without loading the component registry.
|
|
4
|
+
export { RESIDENT_TAB_SHORTCUTS, } from "./shortcut-declarations.js";
|
|
5
|
+
export { projectResidentTabShortcuts, RESIDENT_TAB_GLOBAL_SHORTCUTS, } from "./shortcut-projection.js";
|
|
6
|
+
export { readShortcutBindingsFile } from "./shortcut-bindings-file.js";
|
|
3
7
|
export { deriveResidentTabStatus, } from "./status-deriver.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ShortcutBindings } from "./shortcut-projection.js";
|
|
2
|
+
/** Largest `keybindings.json` the projection reads; a larger file counts as absent. */
|
|
3
|
+
export declare const MAX_SHORTCUT_BINDINGS_BYTES: number;
|
|
4
|
+
/**
|
|
5
|
+
* Reads the user's `keybindings.json` as shortcut bindings, keeping `null` entries so an
|
|
6
|
+
* explicit unbind survives, and treating any unreadable or malformed file as empty.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readShortcutBindingsFile(agentDir: string): ShortcutBindings;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Largest `keybindings.json` the projection reads; a larger file counts as absent. */
|
|
4
|
+
export const MAX_SHORTCUT_BINDINGS_BYTES = 256 * 1024;
|
|
5
|
+
/**
|
|
6
|
+
* Reads the user's `keybindings.json` as shortcut bindings, keeping `null` entries so an
|
|
7
|
+
* explicit unbind survives, and treating any unreadable or malformed file as empty.
|
|
8
|
+
*/
|
|
9
|
+
export function readShortcutBindingsFile(agentDir) {
|
|
10
|
+
let text;
|
|
11
|
+
try {
|
|
12
|
+
text = readFileSync(join(agentDir, "keybindings.json"), "utf8");
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
if (text.length > MAX_SHORTCUT_BINDINGS_BYTES)
|
|
18
|
+
return {};
|
|
19
|
+
let parsed;
|
|
20
|
+
try {
|
|
21
|
+
parsed = JSON.parse(text.replace(/^/u, ""));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
27
|
+
return {};
|
|
28
|
+
const bindings = {};
|
|
29
|
+
for (const [action, value] of Object.entries(parsed)) {
|
|
30
|
+
if (action === "$schema")
|
|
31
|
+
continue;
|
|
32
|
+
if (value === null || typeof value === "string") {
|
|
33
|
+
bindings[action] = value;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(value))
|
|
37
|
+
bindings[action] = value.filter((key) => typeof key === "string");
|
|
38
|
+
}
|
|
39
|
+
return bindings;
|
|
40
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type ResidentTabAction = "tabs.new" | "tabs.close" | "tabs.rename" | "tabs.settings" | "tabs.retry" | "tabs.fresh" | "tabs.next" | "tabs.previous" | "tabs.moveRight" | "tabs.moveLeft" | `tabs.jump${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10}`;
|
|
2
|
+
export interface ResidentTabShortcut {
|
|
3
|
+
readonly id: ResidentTabAction;
|
|
4
|
+
readonly defaultKey: string | null;
|
|
5
|
+
readonly scope: "global" | "failed-banner";
|
|
6
|
+
readonly description: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The tab shortcut declarations, in the order that decides which action keeps a duplicated key.
|
|
10
|
+
* This module stays dependency-free so startup presentation and the resident projection can
|
|
11
|
+
* read it without loading the component registry.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RESIDENT_TAB_SHORTCUTS: readonly ResidentTabShortcut[];
|