@timurproko/a1 0.2.7-dev.779 → 0.2.7-dev.792
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 +0 -1
- package/dist/app/session-shell/session-shell-root.js +45 -18
- package/dist/app/session-shell/session-shell.js +10 -5
- 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/app/session-shell/shell-host.d.ts +0 -2
- package/dist/app/session-shell/shell-host.js +3 -20
- package/dist/cli/tabs.js +15 -0
- package/dist/composition/owned-ui.d.ts +1 -1
- package/dist/composition/owned-ui.js +66 -32
- package/dist/contracts/owned-ui/index.d.ts +1 -1
- package/dist/contracts/owned-ui/model.d.ts +3 -0
- package/dist/contracts/owned-ui/session-workflows.d.ts +4 -1
- package/dist/features/owned-ui/settings-app.js +9 -6
- package/dist/features/resident-tab/auto-name.d.ts +2 -2
- package/dist/features/resident-tab/auto-name.js +7 -5
- package/dist/features/resident-tab/index.d.ts +4 -2
- package/dist/features/resident-tab/index.js +6 -2
- 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/{shortcuts.d.ts → shortcut-declarations.d.ts} +5 -2
- package/dist/features/resident-tab/{shortcuts.js → shortcut-declarations.js} +5 -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/release/bootstrap.js +1 -0
- package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
- package/dist/foundation/release/progress-palette.generated.js +2 -2
- package/dist/foundation/resident-tabs/bridge-client.d.ts +5 -0
- package/dist/foundation/resident-tabs/bridge-client.js +17 -1
- package/dist/foundation/resident-tabs/prompt-journal.d.ts +0 -2
- package/dist/foundation/resident-tabs/prompt-journal.js +0 -1
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- 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/resources/builtin-themes.d.ts +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
- package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -0
- package/dist/integrations/pi/components/share-operation-dialog.js +2 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +1 -0
- 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-selectors-dialogs.js +1 -0
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +3 -11
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.js +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
- package/dist/integrations/pi/engine/pi-settings-metadata.json +12 -0
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/settings-bridge.js +2 -0
- package/dist/integrations/pi/engine/settings-port.js +10 -1
- package/dist/integrations/pi/engine/workflow-runner.js +64 -2
- package/dist/integrations/pi/engine/workflow-support.d.ts +12 -0
- package/dist/integrations/pi/engine/workflow-support.js +36 -0
- package/dist/integrations/pi/engine/workflows.d.ts +3 -1
- package/dist/integrations/pi/engine/workflows.js +1 -0
- package/dist/integrations/pi/startup-public.js +38 -35
- package/dist/integrations/pi/startup-public.manifest.json +110 -116
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
- package/dist/native/darwin-arm64/a1_session_lock.node +0 -0
- package/dist/native/darwin-arm64/manifest.json +3 -2
- package/dist/native/darwin-arm64/terminal-host +0 -0
- package/dist/native/darwin-arm64/terminal-host.manifest.json +7 -6
- package/dist/native/darwin-x64/a1_session_lock.node +0 -0
- package/dist/native/darwin-x64/manifest.json +5 -4
- package/dist/native/darwin-x64/process-guardian +0 -0
- package/dist/native/darwin-x64/terminal-host +0 -0
- package/dist/native/darwin-x64/terminal-host.manifest.json +7 -6
- package/dist/native/linux-x64/a1_session_lock.node +0 -0
- package/dist/native/linux-x64/manifest.json +3 -2
- package/dist/native/linux-x64/terminal-host +0 -0
- package/dist/native/linux-x64/terminal-host.manifest.json +7 -6
- package/dist/native/win32-x64/a1_session_lock.node +0 -0
- package/dist/native/win32-x64/manifest.json +4 -3
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/native/win32-x64/terminal-host.exe +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +6 -5
- package/dist/runtime-payload-inventory.json +4242 -3716
- 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 -1
- package/dist/ui/settings/declarations.js +12 -1
- package/dist/ui/settings/migrations.js +7 -0
- package/docs/architecture/evidence/resident-tabs/macos-x64.md +1 -1
- package/docs/architecture/process-guardian-provenance.md +1 -1
- package/docs/architecture/project-structure.md +8 -0
- package/docs/architecture/resident-tabs.md +18 -2
- package/docs/architecture/terminal-host-provenance.md +1 -1
- package/docs/architecture/toolchain.md +2 -2
- package/docs/ci-release-runbook.md +2 -2
- package/docs/openspec-archive-automation.md +5 -5
- package/docs/validation.md +12 -4
- package/package.json +3 -3
|
@@ -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
|
}
|
|
@@ -960,9 +981,10 @@ export class OwnedUiSessionShellRoot {
|
|
|
960
981
|
return;
|
|
961
982
|
}
|
|
962
983
|
// Rationale: the pinned engine links both share URLs; the workflow result carries the plain URLs.
|
|
963
|
-
const message = result.command
|
|
964
|
-
? `${linkShareUrl(result.message)}\nGist: ${piShellHyperlink(result.detail)}`
|
|
965
|
-
|
|
984
|
+
const message = result.command !== "share" ? result.message
|
|
985
|
+
: result.detail ? `${linkShareUrl(result.message)}\nGist: ${piShellHyperlink(result.detail)}`
|
|
986
|
+
// Protocol: Radius shares carry only the artifact URL.
|
|
987
|
+
: linkShareUrl(result.message);
|
|
966
988
|
this.appendWorkflowStatus(message);
|
|
967
989
|
}
|
|
968
990
|
toggleThinkingVisibility() {
|
|
@@ -1321,20 +1343,25 @@ function withoutTerminalBackground(text) {
|
|
|
1321
1343
|
return text.replace(TERMINAL_BACKGROUND, "");
|
|
1322
1344
|
}
|
|
1323
1345
|
/** Preserve the stable metadata-grey foreground for every pinned timestamp state. */
|
|
1324
|
-
function
|
|
1346
|
+
function pinnedPromptSource(block, sourceRow, width, timeFormat) {
|
|
1347
|
+
const unchanged = { row: sourceRow, copySuffixWidth: 0 };
|
|
1325
1348
|
if (typeof block.payload !== "object" || block.payload === null)
|
|
1326
|
-
return
|
|
1349
|
+
return unchanged;
|
|
1327
1350
|
const value = block.payload.timestamp;
|
|
1328
1351
|
if (typeof value !== "number" || !Number.isFinite(value))
|
|
1329
|
-
return
|
|
1330
|
-
const
|
|
1331
|
-
|
|
1332
|
-
|
|
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;
|
|
1333
1357
|
const rowWidth = displayWidth(sourceRow);
|
|
1334
1358
|
const timestampWidth = displayWidth(timestamp);
|
|
1335
1359
|
if (rowWidth < timestampWidth)
|
|
1336
|
-
return
|
|
1337
|
-
return
|
|
1360
|
+
return unchanged;
|
|
1361
|
+
return {
|
|
1362
|
+
row: overlaySpan(sourceRow, rowWidth - timestampWidth, rowWidth, paintPiSubmittedPromptTimestamp(timestamp)),
|
|
1363
|
+
copySuffixWidth: timestampWidth,
|
|
1364
|
+
};
|
|
1338
1365
|
}
|
|
1339
1366
|
/**
|
|
1340
1367
|
* The pinned-profile screen: a followed transcript scroll above the dock. The runtime mounts one such layout,
|
|
@@ -270,7 +270,7 @@ export class OwnedUiSessionPresenter {
|
|
|
270
270
|
// Invariant: the presenter owns its root (theme subscription and helper clients) and disposes it once the
|
|
271
271
|
// terminal no longer renders it.
|
|
272
272
|
constructed.push(() => this.root.dispose());
|
|
273
|
-
this.#restoreResidentInput();
|
|
273
|
+
this.#restoreResidentInput(options.history?.imageSidecar);
|
|
274
274
|
const initialPiSettings = this.backend.settings.snapshot();
|
|
275
275
|
this.#programStatus = new ProgramStatusReporter(status => this.#terminal.setProgramStatus(status), () => this.view().status.footer?.sessionName ?? undefined);
|
|
276
276
|
this.#reloadPresentation = reloadPresentation;
|
|
@@ -802,7 +802,6 @@ export class OwnedUiSessionPresenter {
|
|
|
802
802
|
sessionFile: this.#currentSessionFile(),
|
|
803
803
|
kind: type,
|
|
804
804
|
text: input,
|
|
805
|
-
...(prepared.images.length === 0 ? {} : { images: prepared.images }),
|
|
806
805
|
});
|
|
807
806
|
}
|
|
808
807
|
catch {
|
|
@@ -1213,11 +1212,13 @@ export class OwnedUiSessionPresenter {
|
|
|
1213
1212
|
this.#resolveStoppedLifecycle();
|
|
1214
1213
|
}
|
|
1215
1214
|
}
|
|
1216
|
-
#restoreResidentInput() {
|
|
1215
|
+
#restoreResidentInput(imageSidecar) {
|
|
1217
1216
|
const recovered = this.#residentTabOptions?.recovered;
|
|
1218
1217
|
if (recovered === undefined)
|
|
1219
1218
|
return;
|
|
1220
|
-
const prompts = recovered.prompts
|
|
1219
|
+
const prompts = recovered.prompts
|
|
1220
|
+
.map(prompt => this.root.rehydrateHistoryText(prompt.text, id => imageSidecar?.readAttachment(id) ?? null))
|
|
1221
|
+
.filter(Boolean);
|
|
1221
1222
|
if (prompts.length > 0) {
|
|
1222
1223
|
this.root.editor.setText(prompts[0]);
|
|
1223
1224
|
if (recovered.draft)
|
|
@@ -1391,7 +1392,11 @@ export class OwnedUiSessionPresenter {
|
|
|
1391
1392
|
}
|
|
1392
1393
|
let result;
|
|
1393
1394
|
try {
|
|
1394
|
-
result = await this.backend.workflows.executeWorkflow(shareSurface === undefined ? request : {
|
|
1395
|
+
result = await this.backend.workflows.executeWorkflow(shareSurface === undefined ? request : {
|
|
1396
|
+
...request,
|
|
1397
|
+
signal: shareSurface.signal,
|
|
1398
|
+
onProgress: message => { shareSurface.setMessage?.(message); this.#terminal.requestRender(); },
|
|
1399
|
+
});
|
|
1395
1400
|
}
|
|
1396
1401
|
finally {
|
|
1397
1402
|
if (operationSurface) {
|
|
@@ -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;
|
|
@@ -98,8 +98,6 @@ export declare class OwnedUiTerminalHost implements OwnedUiTerminalHostContract<
|
|
|
98
98
|
active(): OwnedUiHostedPresenter | null;
|
|
99
99
|
requestRender(from: OwnedUiHostedPresenter, force?: boolean): void;
|
|
100
100
|
start(): void;
|
|
101
|
-
/** Hidden resident tabs retain engine/status work but stop producing terminal animation frames. */
|
|
102
|
-
setPresentationVisible(visible: boolean): void;
|
|
103
101
|
/** Closes one presenter. Closing the last one ends the terminal. */
|
|
104
102
|
close(presenter: OwnedUiHostedPresenter): Promise<void>;
|
|
105
103
|
dispose(): Promise<void>;
|
|
@@ -42,8 +42,6 @@ export class OwnedUiTerminalHost {
|
|
|
42
42
|
#focused = false;
|
|
43
43
|
#pointerReporting = false;
|
|
44
44
|
#started = false;
|
|
45
|
-
#presentationVisible = true;
|
|
46
|
-
#releaseVisibilityHold;
|
|
47
45
|
#ending;
|
|
48
46
|
constructor(options) {
|
|
49
47
|
this.#customViewport = options.layout === "custom-viewport";
|
|
@@ -148,8 +146,10 @@ export class OwnedUiTerminalHost {
|
|
|
148
146
|
active() {
|
|
149
147
|
return this.#active;
|
|
150
148
|
}
|
|
149
|
+
// Invariant: resident tab visibility never gates rendering here; a hidden tab keeps painting into its
|
|
150
|
+
// resident terminal, and the native holder alone withholds inactive surfaces from attach clients.
|
|
151
151
|
requestRender(from, force = false) {
|
|
152
|
-
if (
|
|
152
|
+
if (from === this.#active)
|
|
153
153
|
this.runtime.requestRender(force);
|
|
154
154
|
}
|
|
155
155
|
start() {
|
|
@@ -157,26 +157,9 @@ export class OwnedUiTerminalHost {
|
|
|
157
157
|
return;
|
|
158
158
|
this.#started = true;
|
|
159
159
|
this.runtime.start();
|
|
160
|
-
if (!this.#presentationVisible)
|
|
161
|
-
this.#releaseVisibilityHold = this.runtime.beginPresentationHold();
|
|
162
160
|
if (this.#customViewport)
|
|
163
161
|
this.#setPointerReporting(true);
|
|
164
162
|
}
|
|
165
|
-
/** Hidden resident tabs retain engine/status work but stop producing terminal animation frames. */
|
|
166
|
-
setPresentationVisible(visible) {
|
|
167
|
-
if (this.#presentationVisible === visible)
|
|
168
|
-
return;
|
|
169
|
-
this.#presentationVisible = visible;
|
|
170
|
-
if (!this.#started || this.#ending !== undefined)
|
|
171
|
-
return;
|
|
172
|
-
if (visible) {
|
|
173
|
-
this.#releaseVisibilityHold?.();
|
|
174
|
-
this.#releaseVisibilityHold = undefined;
|
|
175
|
-
}
|
|
176
|
-
else if (this.#releaseVisibilityHold === undefined) {
|
|
177
|
-
this.#releaseVisibilityHold = this.runtime.beginPresentationHold();
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
163
|
/** Closes one presenter. Closing the last one ends the terminal. */
|
|
181
164
|
close(presenter) {
|
|
182
165
|
if (this.#ending !== undefined || !this.#presenters.has(presenter))
|
package/dist/cli/tabs.js
CHANGED
|
@@ -132,9 +132,24 @@ function status(result) {
|
|
|
132
132
|
`detachment: ${String(result.detachmentMode ?? "unknown")}${result.detachmentVerified === false ? " (not verified)" : ""}`,
|
|
133
133
|
`tabs: ${String(result.tabs ?? 0)}${Object.keys(byStatus).length > 0 ? ` (${Object.entries(byStatus).map(([key, value]) => `${key} ${String(value)}`).join(", ")})` : ""}`,
|
|
134
134
|
`clients: ${String(result.clients ?? 0)}`,
|
|
135
|
+
...startsAndLifecycle(result),
|
|
135
136
|
`limits: ${Object.entries(limits).map(([key, value]) => `${key} ${String(value)}`).join(", ")}`,
|
|
136
137
|
`counters: ${Object.entries(counters).map(([key, value]) => `${key} ${String(value)}`).join(", ")}`,
|
|
137
138
|
...(Array.isArray(result.logs) ? result.logs.map(path => `log: ${String(path)}`) : []),
|
|
138
139
|
];
|
|
139
140
|
return `${lines.join("\n")}\n`;
|
|
140
141
|
}
|
|
142
|
+
/** Lifecycle work running this long means a terminal's tab requests are stuck. */
|
|
143
|
+
const LIFECYCLE_STALL_MS = 10_000;
|
|
144
|
+
function startsAndLifecycle(result) {
|
|
145
|
+
const lines = [];
|
|
146
|
+
const starts = result.starts;
|
|
147
|
+
if (starts)
|
|
148
|
+
lines.push(`starts: active ${String(starts.active ?? 0)}, waiting ${String(starts.interactiveWaiting ?? 0)}, recovering ${String(starts.recoverySlots ?? 0)}`);
|
|
149
|
+
const lifecycle = result.lifecycle;
|
|
150
|
+
if (lifecycle) {
|
|
151
|
+
const oldest = typeof lifecycle.oldestMs === "number" ? lifecycle.oldestMs : 0;
|
|
152
|
+
lines.push(`lifecycle: pending ${String(lifecycle.pending ?? 0)}, oldest ${oldest}ms${oldest > LIFECYCLE_STALL_MS ? " (stalled)" : ""}`);
|
|
153
|
+
}
|
|
154
|
+
return lines;
|
|
155
|
+
}
|
|
@@ -87,5 +87,5 @@ 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 onVisibility?: (visible: boolean) => void;
|
|
91
90
|
}): Promise<() => void>;
|
|
91
|
+
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";
|
|
@@ -164,13 +166,8 @@ export async function composeOwnedUi(options = {}) {
|
|
|
164
166
|
const recoveredTabInput = await tabRecovery?.initialize(currentBackendSessionFile(backend), backend.identity.sessionId);
|
|
165
167
|
if (tabBridge !== null && settings !== null && ownedSurfaces)
|
|
166
168
|
tabBridge.accent(settings.value("accentColor"));
|
|
167
|
-
let residentTabVisible = true;
|
|
168
|
-
let applyResidentTabVisibility = () => { };
|
|
169
169
|
let removeControllerBoundaryInput = () => { };
|
|
170
|
-
const unsubscribeTabBridge = tabBridge === null ? () => { } : await bindResidentTabBridge(tabBridge, backend, tabRecovery, {
|
|
171
|
-
autoName: settings?.value("tabsAutoName") ?? true,
|
|
172
|
-
onVisibility: visible => { residentTabVisible = visible; applyResidentTabVisibility(); },
|
|
173
|
-
});
|
|
170
|
+
const unsubscribeTabBridge = tabBridge === null ? () => { } : await bindResidentTabBridge(tabBridge, backend, tabRecovery, { autoName: settings?.value("tabsAutoName") ?? true });
|
|
174
171
|
let releaseNotes = null;
|
|
175
172
|
let releaseNotesFailure;
|
|
176
173
|
if (ownedSurfaces) {
|
|
@@ -259,7 +256,18 @@ export async function composeOwnedUi(options = {}) {
|
|
|
259
256
|
? new ClipboardDiagnosticCapture(clipboardDestination) : null;
|
|
260
257
|
// Invariant: process-wide services are created once here and borrowed by every session shell. The
|
|
261
258
|
// keybinding registry is applied before any presenter is built, so none of them reads Pi's defaults.
|
|
262
|
-
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();
|
|
263
271
|
const clipboardServices = ownedSurfaces ? createOwnedUiClipboardServices() : null;
|
|
264
272
|
let createdTerminalHost;
|
|
265
273
|
let terminalHost;
|
|
@@ -289,7 +297,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
289
297
|
stallNoticeSeconds: 300,
|
|
290
298
|
admit: input => tabRecovery.admit({ ...input, incarnation: options.tab.incarnation }),
|
|
291
299
|
dispatched: () => tabRecovery.dispatched(),
|
|
292
|
-
correlated: (submissionId, entryId) => tabRecovery
|
|
300
|
+
correlated: (submissionId, entryId) => correlateResidentTabSubmission(tabRecovery, backend, submissionId, entryId),
|
|
293
301
|
checkpoint: text => tabRecovery.checkpoint(text),
|
|
294
302
|
gracefulStop: sessionFile => tabRecovery.gracefulStop(sessionFile),
|
|
295
303
|
...(recoveredTabInput === undefined ? {} : { recovered: recoveredTabInput }),
|
|
@@ -322,7 +330,6 @@ export async function composeOwnedUi(options = {}) {
|
|
|
322
330
|
// the host and paints once attached.
|
|
323
331
|
terminalHost = createdTerminalHost = new OwnedUiTerminalHost(sessionTerminalHostOptions(presenterOptions));
|
|
324
332
|
if (tabBridge !== null) {
|
|
325
|
-
applyResidentTabVisibility = () => terminalHost.setPresentationVisible(residentTabVisible);
|
|
326
333
|
removeControllerBoundaryInput = terminalHost.runtime.addPreInputListener(data => ({
|
|
327
334
|
data: tabBridge.consumeControllerBoundaryInput(data),
|
|
328
335
|
}));
|
|
@@ -375,7 +382,6 @@ export async function composeOwnedUi(options = {}) {
|
|
|
375
382
|
exitNotice = import("../app/session-shell/exit-notice.js")
|
|
376
383
|
.then(module => module.armExitNotice(backend, exitNoticePath), () => null);
|
|
377
384
|
presenter.start();
|
|
378
|
-
applyResidentTabVisibility();
|
|
379
385
|
void announceNewerRelease().catch(() => undefined);
|
|
380
386
|
},
|
|
381
387
|
flush: () => backend.session.flushEvents(),
|
|
@@ -420,14 +426,38 @@ export async function bindResidentTabBridge(tabBridge, backend, recovery = null,
|
|
|
420
426
|
tabBridge.status("starting");
|
|
421
427
|
const currentSessionFile = () => currentBackendSessionFile(backend);
|
|
422
428
|
let pendingAutoName = null;
|
|
429
|
+
const isDefaultName = (name) => name == null || /^agent(?: \d+)?$/i.test(name);
|
|
430
|
+
const currentSessionName = () => backend.session.view().status.footer?.sessionName ?? null;
|
|
423
431
|
const announceSession = () => {
|
|
424
|
-
const name =
|
|
425
|
-
const nameSource = name === pendingAutoName ? "auto" :
|
|
432
|
+
const name = currentSessionName();
|
|
433
|
+
const nameSource = name === pendingAutoName ? "auto" : isDefaultName(name) ? "default" : "user";
|
|
426
434
|
tabBridge.session(currentSessionFile(), name, nameSource);
|
|
427
435
|
};
|
|
428
436
|
let working = false;
|
|
429
437
|
let lastTurnFailed = false;
|
|
430
438
|
let autoNameAttempted = false;
|
|
439
|
+
let autoNameArmed = false;
|
|
440
|
+
// Invariant: naming launches once per tab during an agent run, as soon as its prompt is projected,
|
|
441
|
+
// and runs beside the turn instead of waiting for it to settle.
|
|
442
|
+
const launchAutoName = () => {
|
|
443
|
+
if (!autoNameArmed || autoNameAttempted || options.autoName !== true || !isDefaultName(currentSessionName()))
|
|
444
|
+
return;
|
|
445
|
+
const prompt = backend.session.view().transcript.find(block => block.kind === "user")?.text.trim();
|
|
446
|
+
if (!prompt)
|
|
447
|
+
return;
|
|
448
|
+
autoNameAttempted = true;
|
|
449
|
+
void import("../features/resident-tab/index.js").then(({ generateAutoName }) => generateAutoName(prompt, request => backend.generateResidentTabName(request.prompt, request.maxTokens, request.signal))).then(async (name) => {
|
|
450
|
+
// Invariant: a manual rename made while generation was pending owns both the session and the tab.
|
|
451
|
+
if (!isDefaultName(currentSessionName()))
|
|
452
|
+
return;
|
|
453
|
+
pendingAutoName = name;
|
|
454
|
+
const result = await backend.workflows.executeWorkflow({ command: "name", argument: name });
|
|
455
|
+
if (result.outcome === "completed")
|
|
456
|
+
tabBridge.session(currentSessionFile(), name, "auto");
|
|
457
|
+
else if (pendingAutoName === name)
|
|
458
|
+
pendingAutoName = null;
|
|
459
|
+
}).catch(() => { pendingAutoName = null; });
|
|
460
|
+
};
|
|
431
461
|
const reportStatus = (lifecycle) => {
|
|
432
462
|
const view = backend.session.view();
|
|
433
463
|
const pendingRequests = view.dialog == null ? 0 : 1;
|
|
@@ -441,12 +471,14 @@ export async function bindResidentTabBridge(tabBridge, backend, recovery = null,
|
|
|
441
471
|
};
|
|
442
472
|
announceSession();
|
|
443
473
|
const unsubscribeCommands = typeof tabBridge.onCommand === "function" ? tabBridge.onCommand(command => {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
else if (command.type === "rename") {
|
|
474
|
+
// Invariant: visibility stays decoded for generation-1 peers but never pauses rendering; a hidden tab
|
|
475
|
+
// keeps its resident terminal current while the holder withholds only its client surfaces.
|
|
476
|
+
if (command.type === "rename") {
|
|
448
477
|
void backend.workflows.executeWorkflow({ command: "name", argument: command.name }).catch(() => { });
|
|
449
478
|
}
|
|
479
|
+
else if (command.type === "route") {
|
|
480
|
+
void backend.workflows.executeWorkflow({ command: command.route, argument: "" }).catch(() => { });
|
|
481
|
+
}
|
|
450
482
|
else if (command.type === "stop") {
|
|
451
483
|
void backend.session.dispose().catch(() => { });
|
|
452
484
|
}
|
|
@@ -461,24 +493,17 @@ export async function bindResidentTabBridge(tabBridge, backend, recovery = null,
|
|
|
461
493
|
if (wasWorking && !working && recovery !== null) {
|
|
462
494
|
void recovery.settled(currentSessionFile()).catch(() => tabBridge.degraded(true));
|
|
463
495
|
}
|
|
464
|
-
if (wasWorking && !working && options.autoName === true && !autoNameAttempted) {
|
|
465
|
-
autoNameAttempted = true;
|
|
466
|
-
const view = backend.session.view();
|
|
467
|
-
const currentName = view.status.footer?.sessionName;
|
|
468
|
-
const prompt = view.transcript.find(block => block.kind === "user")?.text.trim();
|
|
469
|
-
if (prompt && (currentName == null || /^agent(?: \d+)?$/i.test(currentName))) {
|
|
470
|
-
void import("../features/resident-tab/index.js").then(({ generateAutoName }) => generateAutoName(prompt, request => backend.generateResidentTabName(request.prompt, request.maxTokens, request.signal))).then(async (name) => {
|
|
471
|
-
pendingAutoName = name;
|
|
472
|
-
const result = await backend.workflows.executeWorkflow({ command: "name", argument: name });
|
|
473
|
-
if (result.outcome === "completed")
|
|
474
|
-
tabBridge.session(currentSessionFile(), name, "auto");
|
|
475
|
-
else if (pendingAutoName === name)
|
|
476
|
-
pendingAutoName = null;
|
|
477
|
-
}).catch(() => { pendingAutoName = null; });
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
496
|
}
|
|
497
|
+
if (event.type === "agent-run-started") {
|
|
498
|
+
autoNameArmed = true;
|
|
499
|
+
launchAutoName();
|
|
500
|
+
}
|
|
501
|
+
// Rationale: Pi starts the run before it projects the user message, so the prompt may arrive later.
|
|
502
|
+
if (event.type === "transcript-block" || event.type === "session-view")
|
|
503
|
+
launchAutoName();
|
|
481
504
|
if (event.type === "agent-run-settled") {
|
|
505
|
+
launchAutoName();
|
|
506
|
+
autoNameArmed = false;
|
|
482
507
|
lastTurnFailed = !event.successful && !event.aborted;
|
|
483
508
|
tabBridge.prompt(event.aborted);
|
|
484
509
|
reportStatus();
|
|
@@ -493,6 +518,14 @@ export async function bindResidentTabBridge(tabBridge, backend, recovery = null,
|
|
|
493
518
|
unsubscribeEvents();
|
|
494
519
|
};
|
|
495
520
|
}
|
|
521
|
+
export async function correlateResidentTabSubmission(recovery, backend, submissionId, entryId) {
|
|
522
|
+
await recovery.correlated(submissionId, entryId);
|
|
523
|
+
// Concurrency: a normal prompt command can resolve after the ready transition already fired.
|
|
524
|
+
// Re-read lifecycle only after correlation is active; a concurrent ready observer and this path
|
|
525
|
+
// safely race because recovery consumes the active entry once and retirement is idempotent.
|
|
526
|
+
if (backend.session.view().lifecycle !== "busy")
|
|
527
|
+
await recovery.settled(currentBackendSessionFile(backend));
|
|
528
|
+
}
|
|
496
529
|
function currentBackendSessionFile(backend) {
|
|
497
530
|
const direct = backend.identity.currentSessionFile?.();
|
|
498
531
|
if (direct !== undefined && direct !== null)
|
|
@@ -514,6 +547,7 @@ function quitOutroSettingsSnapshot(settings) {
|
|
|
514
547
|
}
|
|
515
548
|
function viewportSettingsSnapshot(settings) {
|
|
516
549
|
return {
|
|
550
|
+
timeFormat: settings.value("timeFormat"),
|
|
517
551
|
scrollbarAppearance: settings.value("scrollbarAppearance"),
|
|
518
552
|
scrollbarStyle: settings.value("scrollbarStyle"),
|
|
519
553
|
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. */
|
|
@@ -49,6 +49,8 @@ export interface OwnedUiWorkflowRequest {
|
|
|
49
49
|
readonly cwdOverride?: string;
|
|
50
50
|
/** Cancellation for an owned operation surface such as `/share`. */
|
|
51
51
|
readonly signal?: AbortSignal;
|
|
52
|
+
/** Progress label for that operation surface, e.g. when `/share` picks its upload destination. */
|
|
53
|
+
readonly onProgress?: (message: string) => void;
|
|
52
54
|
readonly treeSummary?: {
|
|
53
55
|
readonly summarize: boolean;
|
|
54
56
|
readonly customInstructions?: string;
|
|
@@ -272,6 +274,7 @@ export interface OwnedUiSessionSettingsSnapshot {
|
|
|
272
274
|
readonly autocompleteMaxVisible: number;
|
|
273
275
|
readonly quietStartup: boolean | "header";
|
|
274
276
|
readonly defaultProjectTrust: "ask" | "always" | "never";
|
|
277
|
+
readonly sessionShareDestination: "auto" | "gist" | "radius";
|
|
275
278
|
readonly clearOnShrink: boolean;
|
|
276
279
|
readonly showTerminalProgress: boolean;
|
|
277
280
|
readonly tuiMode: "regular" | "fullscreen";
|
|
@@ -289,7 +292,7 @@ export type OwnedUiJsonValue = null | boolean | number | string | readonly Owned
|
|
|
289
292
|
/** The layer that installs a setting's live effect. */
|
|
290
293
|
export type OwnedUiSettingOwner = "agent" | "shell" | "terminal" | "startup" | "shutdown" | "installation";
|
|
291
294
|
/** Engine settings whose live effect an owner may bind. */
|
|
292
|
-
export type OwnedUiSessionSettingKey = "autoCompact" | "showImages" | "imageWidthCells" | "autoResizeImages" | "blockImages" | "enableSkillCommands" | "steeringMode" | "followUpMode" | "transport" | "httpIdleTimeoutMs" | "cacheWarmingMode" | "modelThinkingLevels" | "theme" | "hideThinkingBlock" | "mermaidRenderingMode" | "showCacheMissNotices" | "collapseChangelog" | "enableInstallTelemetry" | "quietStartup" | "defaultProjectTrust" | "doubleEscapeAction" | "treeFilterMode" | "showHardwareCursor" | "editorPaddingX" | "outputPad" | "autocompleteMaxVisible" | "clearOnShrink" | "showTerminalProgress" | "tuiMode" | "fullscreenExitOutput" | "fullscreenScrollbar" | "fullscreenCopyOnSelect" | "fullscreenWheelScrollLines" | "warnings";
|
|
295
|
+
export type OwnedUiSessionSettingKey = "autoCompact" | "showImages" | "imageWidthCells" | "autoResizeImages" | "blockImages" | "enableSkillCommands" | "steeringMode" | "followUpMode" | "transport" | "httpIdleTimeoutMs" | "cacheWarmingMode" | "modelThinkingLevels" | "theme" | "hideThinkingBlock" | "mermaidRenderingMode" | "showCacheMissNotices" | "collapseChangelog" | "enableInstallTelemetry" | "quietStartup" | "defaultProjectTrust" | "sessionShareDestination" | "doubleEscapeAction" | "treeFilterMode" | "showHardwareCursor" | "editorPaddingX" | "outputPad" | "autocompleteMaxVisible" | "clearOnShrink" | "showTerminalProgress" | "tuiMode" | "fullscreenExitOutput" | "fullscreenScrollbar" | "fullscreenCopyOnSelect" | "fullscreenWheelScrollLines" | "warnings";
|
|
293
296
|
export interface OwnedUiSettingEffectHandler {
|
|
294
297
|
/** Install one value in the active owner. Handlers must be idempotent and reversible. */
|
|
295
298
|
apply(value: OwnedUiJsonValue): void | Promise<void>;
|