@timurproko/a1 0.1.8-dev.182 → 0.1.8-dev.214
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/bin/cli.js +2 -2
- package/bin/sync-pi-tui-proxy.js +1 -1
- package/bin/ui.js +1 -1
- package/dist/cli/dispatch.js +3 -3
- package/dist/cli/packages.js +1 -1
- package/dist/cli/version-stats.js +3 -3
- package/dist/composition/owned-ui.js +1 -1
- package/dist/composition/settings-route-host.js +6 -4
- package/dist/features/launch/development-launch.js +1 -1
- package/dist/features/owned-ui/customization.d.ts +2 -0
- package/dist/features/owned-ui/customization.js +2 -0
- package/dist/features/owned-ui/diagnostics.d.ts +1 -0
- package/dist/features/owned-ui/diagnostics.js +1 -0
- package/dist/features/owned-ui/project-trust-prompt.d.ts +11 -6
- package/dist/features/owned-ui/project-trust-prompt.js +134 -17
- package/dist/features/owned-ui/settings-app.js +47 -50
- package/dist/features/workspace/reducer.d.ts +1 -0
- package/dist/features/workspace/reducer.js +1 -0
- package/dist/features/workspace/router.d.ts +1 -0
- package/dist/features/workspace/router.js +1 -0
- package/dist/features/workspace/store.d.ts +1 -0
- package/dist/features/workspace/store.js +1 -0
- package/dist/foundation/launch-guardian/main.js +1 -1
- package/dist/foundation/native-host-protocol/codec.d.ts +2 -0
- package/dist/foundation/native-host-protocol/codec.js +2 -0
- package/dist/foundation/process-containment/linux-process-inspector.d.ts +1 -0
- package/dist/foundation/process-containment/linux-process-inspector.js +1 -0
- package/dist/foundation/process-containment/native-guardian-containment.d.ts +1 -0
- package/dist/foundation/process-containment/native-guardian-containment.js +1 -0
- package/dist/foundation/process-containment/windows-process-inspector.d.ts +1 -0
- package/dist/foundation/process-containment/windows-process-inspector.js +1 -0
- package/dist/foundation/protocol/client.d.ts +1 -0
- package/dist/foundation/protocol/client.js +1 -0
- package/dist/foundation/protocol/messages.d.ts +1 -0
- package/dist/foundation/protocol/messages.js +1 -0
- package/dist/foundation/release/bootstrap.js +6 -6
- package/dist/foundation/release/cohort-state.d.ts +1 -0
- package/dist/foundation/release/cohort-state.js +1 -0
- package/dist/foundation/release/release-gc.js +1 -1
- package/dist/foundation/release/release.js +1 -1
- package/dist/foundation/release/update-transaction.d.ts +1 -0
- package/dist/foundation/release/update-transaction.js +1 -0
- package/dist/foundation/release/update.js +12 -12
- package/dist/foundation/storage/control-store.d.ts +1 -0
- package/dist/foundation/storage/control-store.js +1 -0
- package/dist/foundation/structured-agent-runtime/backpressure.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/backpressure.js +1 -0
- package/dist/foundation/structured-agent-runtime/commands.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/commands.js +1 -0
- package/dist/foundation/structured-agent-runtime/reconnection.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/reconnection.js +1 -0
- package/dist/foundation/structured-agent-runtime/state.d.ts +1 -0
- package/dist/foundation/structured-agent-runtime/state.js +1 -0
- package/dist/foundation/supervision/main.js +1 -1
- package/dist/foundation/supervision/server.d.ts +1 -0
- package/dist/foundation/supervision/server.js +4 -6
- package/dist/integrations/pi/components/conformance.d.ts +1 -0
- package/dist/integrations/pi/components/conformance.js +1 -0
- package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
- package/dist/integrations/pi/components/shell-footer-status.js +8 -7
- package/dist/integrations/pi/components/shell-shared-facade.js +1 -1
- package/dist/integrations/pi/engine/adapter.d.ts +7 -0
- package/dist/integrations/pi/engine/adapter.js +37 -35
- package/dist/integrations/pi/engine/conformance.d.ts +2 -0
- package/dist/integrations/pi/engine/conformance.js +2 -0
- package/dist/integrations/pi/engine/http-dispatcher.js +1 -1
- package/dist/integrations/pi/engine/model-auth-integration.d.ts +1 -0
- package/dist/integrations/pi/engine/model-auth-integration.js +1 -0
- package/dist/integrations/pi/engine/package-integration.js +1 -1
- package/dist/integrations/pi/engine/project-trust-preflight.js +1 -1
- package/dist/integrations/pi/engine/resource-extension-integration.d.ts +1 -0
- package/dist/integrations/pi/engine/resource-extension-integration.js +1 -0
- package/dist/integrations/pi/engine/session-integration.d.ts +1 -0
- package/dist/integrations/pi/engine/session-integration.js +2 -1
- package/dist/integrations/pi/engine/settings-effects.d.ts +13 -2
- package/dist/integrations/pi/engine/settings-effects.js +62 -42
- package/dist/integrations/pi/engine/settings-integration.js +4 -4
- package/dist/integrations/pi/engine/workflow-controllers.d.ts +1 -0
- package/dist/integrations/pi/engine/workflow-controllers.js +1 -0
- package/dist/integrations/pi/session-ui/index.d.ts +1 -0
- package/dist/integrations/pi/session-ui/index.js +1 -0
- package/dist/integrations/pi/session-ui/prompt-chips.js +1 -1
- package/dist/integrations/pi/session-ui/session-shell-root.d.ts +30 -2
- package/dist/integrations/pi/session-ui/session-shell-root.js +133 -72
- package/dist/integrations/pi/session-ui/session-shell.d.ts +9 -2
- package/dist/integrations/pi/session-ui/session-shell.js +112 -37
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +5 -0
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +44 -11
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
- package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
- package/dist/integrations/pi/session-ui/system-clipboard.js +6 -6
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -0
- package/dist/integrations/pi/tui-runtime/adapter.js +138 -8
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +25 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +63 -0
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +240 -0
- package/dist/integrations/pi/tui-runtime/index.d.ts +2 -0
- package/dist/integrations/pi/tui-runtime/index.js +2 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/ui/apps/host.js +5 -9
- package/dist/ui/apps/registry.d.ts +1 -0
- package/dist/ui/apps/registry.js +1 -0
- package/dist/ui/components/dialog-panel.js +5 -3
- package/dist/ui/components/frame.d.ts +1 -0
- package/dist/ui/components/frame.js +1 -0
- package/dist/ui/components/index.d.ts +1 -0
- package/dist/ui/components/index.js +1 -0
- package/dist/ui/components/line-input.d.ts +1 -6
- package/dist/ui/components/line-input.js +4 -9
- package/dist/ui/components/list-view.d.ts +0 -6
- package/dist/ui/components/list-view.js +14 -7
- package/dist/ui/components/progress-status.d.ts +2 -0
- package/dist/ui/components/progress-status.js +4 -0
- package/dist/ui/components/scrollbar.js +1 -1
- package/dist/ui/components/shortcuts.d.ts +1 -0
- package/dist/ui/components/shortcuts.js +1 -0
- package/dist/ui/components/spans.d.ts +0 -5
- package/dist/ui/components/spans.js +3 -8
- package/dist/ui/components/surface.d.ts +0 -5
- package/dist/ui/components/surface.js +1 -5
- package/dist/ui/components/text-selection.d.ts +10 -1
- package/dist/ui/components/text-selection.js +96 -29
- package/dist/ui/components/text.js +3 -3
- package/dist/ui/components/transcript-viewport.d.ts +42 -0
- package/dist/ui/components/transcript-viewport.js +287 -39
- package/dist/ui/settings/sections.d.ts +0 -2
- package/dist/ui/settings/sections.js +10 -16
- package/dist/ui/settings/session.js +5 -4
- package/dist/ui/settings/store.d.ts +1 -0
- package/dist/ui/settings/store.js +2 -1
- package/docs/architecture/code-documentation.md +77 -0
- package/docs/architecture/project-structure.md +1 -1
- package/docs/architecture/ui-reference-provenance.md +23 -3
- package/docs/ci-release-runbook.md +30 -4
- package/docs/manual-owned-ui-checkpoint.md +28 -1
- package/docs/manual-terminal-colour-check.md +4 -3
- package/package.json +7 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { backgroundSgrSpan, composeSubmittedPromptRows, displayWidth, formatSubmittedPromptTime, heldNativeHyperlinkStyle, hyperlinkSgrSpan, nativeHyperlinkStyle, overlaySpan, submittedPromptLayout, stripAnsi, } from "../../../ui/components/index.js";
|
|
1
|
+
import { backgroundSgrSpan, composeSubmittedPromptRows, displayWidth, formatSubmittedPromptTime, heldNativeHyperlinkStyle, hyperlinkSgrSpan, nativeHyperlinkStyle, overlaySpan, progressStatusText, submittedPromptLayout, stripAnsi, } from "../../../ui/components/index.js";
|
|
2
2
|
import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES, } from "../engine/index.js";
|
|
3
3
|
import { createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellStatus, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, onPiThemeChange, piShellVisibleWidth, piTheme, renderPiShellPackageUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, } from "../components/index.js";
|
|
4
|
-
import { PiTuiRuntimeAdapter, } from "../tui-runtime/index.js";
|
|
4
|
+
import { PiTuiRuntimeAdapter, classifyPiTuiInput, } from "../tui-runtime/index.js";
|
|
5
5
|
import { PromptChipStore } from "./prompt-chips.js";
|
|
6
6
|
import { SessionViewportController } from "./session-viewport-controller.js";
|
|
7
|
+
/** Composes backend session state into the owned transcript, viewport, editor, and dock presentation. */
|
|
7
8
|
export class OwnedUiSessionShellRoot {
|
|
8
9
|
editor;
|
|
9
10
|
header;
|
|
@@ -12,7 +13,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
12
13
|
#transcript = new Map();
|
|
13
14
|
#blocksById = new Map();
|
|
14
15
|
#renderedRows = new Map();
|
|
15
|
-
|
|
16
|
+
// Performance: document layouts are shared by wheel, rail, jump, and selection frames.
|
|
16
17
|
#documentLayouts = new Map();
|
|
17
18
|
#themeUnsubscribe;
|
|
18
19
|
#transcriptOrder = [];
|
|
@@ -26,6 +27,8 @@ export class OwnedUiSessionShellRoot {
|
|
|
26
27
|
#customViewport;
|
|
27
28
|
#submittedPromptComposer;
|
|
28
29
|
#viewportController;
|
|
30
|
+
#viewportTheme;
|
|
31
|
+
#onViewportFrame;
|
|
29
32
|
#componentRuntime;
|
|
30
33
|
#toolsExpanded = false;
|
|
31
34
|
#thinkingVisible = true;
|
|
@@ -38,6 +41,13 @@ export class OwnedUiSessionShellRoot {
|
|
|
38
41
|
#workflowStatusMessages = new Map();
|
|
39
42
|
#lastWorkflowStatusId;
|
|
40
43
|
#inputSurface;
|
|
44
|
+
#inputSurfaceCoordination = "editor";
|
|
45
|
+
#dockInputReuseEnabled;
|
|
46
|
+
#dockInputCandidate = false;
|
|
47
|
+
#visibleViewportSnapshot;
|
|
48
|
+
#fullViewportCompositions = 0;
|
|
49
|
+
#dockOnlyViewportCompositions = 0;
|
|
50
|
+
#transcriptBlockRenders = 0;
|
|
41
51
|
#extensionHeader = null;
|
|
42
52
|
#extensionFooter = null;
|
|
43
53
|
#extensionWidgets = new Map();
|
|
@@ -61,9 +71,11 @@ export class OwnedUiSessionShellRoot {
|
|
|
61
71
|
this.#extensionRenderers = extensionRenderers;
|
|
62
72
|
this.#imageAssets = imageAssets;
|
|
63
73
|
this.#componentRuntime = handlers;
|
|
74
|
+
this.#onViewportFrame = handlers.onViewportFrame;
|
|
75
|
+
this.#dockInputReuseEnabled = handlers.enableDockInputReuse ?? true;
|
|
64
76
|
this.header = createPiShellHeader(startup);
|
|
65
77
|
this.resources = createPiShellLoadedResources(startup.resources ?? [], startup.expanded ?? false);
|
|
66
|
-
this.#status = createPiShellStatus(view, handlers);
|
|
78
|
+
this.#status = createPiShellStatus(view, progressStatusText, handlers);
|
|
67
79
|
this.#footer = createPiShellFooter(this.#viewWithExtensionStatuses(view), cwd);
|
|
68
80
|
this.#queued = createPiQueuedInputStatus(view.editor.queuedSubmissions, this.#customViewport ? "custom-viewport" : "pinned");
|
|
69
81
|
this.editor = createPiShellEditor({
|
|
@@ -78,7 +90,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
78
90
|
if (ranges.length === 0)
|
|
79
91
|
return row;
|
|
80
92
|
const linkResetAndTail = `\u001b]8;;\u001b\\\u001b[24m${" ".repeat(Math.max(0, width - piShellVisibleWidth(row)))}`;
|
|
81
|
-
// VS15 is zero-column and default-ignorable. It breaks Windows Terminal's
|
|
93
|
+
// Platform: VS15 is zero-column and default-ignorable. It breaks Windows Terminal's
|
|
82
94
|
// plain-text URL detector only in the held-button paint; semantic text stays exact.
|
|
83
95
|
const paintRow = this.#viewportController.editorPointerSelecting
|
|
84
96
|
? row.replaceAll("https://", "https:\uFE0E//").replaceAll("http://", "http:\uFE0E//")
|
|
@@ -86,7 +98,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
86
98
|
const decorated = this.#viewportController.editorPointerSelecting
|
|
87
99
|
? ranges.reduce((result, range) => backgroundSgrSpan(result, piShellVisibleWidth(plain.slice(0, range.start)), piShellVisibleWidth(plain.slice(0, range.end)), "\u001b[4:4m", "\u001b[24m", piShellVisibleWidth), paintRow)
|
|
88
100
|
: ranges.reduce((result, range) => hyperlinkSgrSpan(result, piShellVisibleWidth(plain.slice(0, range.start)), piShellVisibleWidth(plain.slice(0, range.end)), range.target, piShellVisibleWidth), row);
|
|
89
|
-
// Windows Terminal can retain stale native dotted-link cells when a mutable
|
|
101
|
+
// Platform: Windows Terminal can retain stale native dotted-link cells when a mutable
|
|
90
102
|
// prompt replaces a longer URL. Explicit non-link spaces overwrite that tail.
|
|
91
103
|
return `${decorated}${linkResetAndTail}`;
|
|
92
104
|
},
|
|
@@ -101,6 +113,16 @@ export class OwnedUiSessionShellRoot {
|
|
|
101
113
|
requestRender: force => this.#componentRuntime.requestRender(force),
|
|
102
114
|
hasEditorLinks: () => this.#promptChips.hyperlinkRanges(this.editor.getText()).length > 0,
|
|
103
115
|
});
|
|
116
|
+
// Performance: stable painter identities let the neutral viewport retain row-level
|
|
117
|
+
// selection variants while each callback still resolves the live Pi theme.
|
|
118
|
+
this.#viewportTheme = {
|
|
119
|
+
track: text => `${SCROLLBAR_CELL_RESET}${piTheme().fg("dim", text)}`,
|
|
120
|
+
thumb: text => `${SCROLLBAR_CELL_RESET}${piTheme().fg("accent", text)}`,
|
|
121
|
+
sticky: (text, hovered) => piTheme().bg(hovered ? "selectedBg" : "toolPendingBg", piTheme().fg("text", withoutTerminalBackground(text))),
|
|
122
|
+
quietSticky: text => `\u001b[2m${text.replace(/\u001b\[(?:0|22)m/g, "$&\u001b[2m")}\u001b[22m`,
|
|
123
|
+
bottomControl: (text, hovered) => piTheme().bg(hovered ? "selectedBg" : "toolPendingBg", piTheme().fg("text", text)),
|
|
124
|
+
selection: (line, from, to) => backgroundSgrSpan(line, from, to, "\u001b[48;2;38;79;120m", "\u001b[49m"),
|
|
125
|
+
};
|
|
104
126
|
this.editor.setThinkingLevel(view.thinkingLevel);
|
|
105
127
|
this.#inputSurface = this.editor;
|
|
106
128
|
for (const block of view.transcript) {
|
|
@@ -108,7 +130,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
108
130
|
this.editor.addToHistory(block.text);
|
|
109
131
|
}
|
|
110
132
|
this.#syncTranscript(view.transcript);
|
|
111
|
-
//
|
|
133
|
+
// Invariant: colours come from the active theme, so rendered rows outlive their revision only
|
|
112
134
|
// until the theme under them changes.
|
|
113
135
|
this.#themeUnsubscribe = onPiThemeChange(() => {
|
|
114
136
|
this.#renderedRows.clear();
|
|
@@ -190,7 +212,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
190
212
|
else if (component.revision !== block.revision) {
|
|
191
213
|
component.update(block);
|
|
192
214
|
}
|
|
193
|
-
//
|
|
215
|
+
// Performance: one chunk touches one block, and the updated component tracks its own dirtiness.
|
|
194
216
|
// Invalidating the whole shell here would re-wrap the entire transcript per chunk.
|
|
195
217
|
this.#renderedRows.delete(block.id);
|
|
196
218
|
this.#documentLayouts.clear();
|
|
@@ -202,62 +224,79 @@ export class OwnedUiSessionShellRoot {
|
|
|
202
224
|
}
|
|
203
225
|
const height = Math.max(0, this.#componentRuntime.getRows());
|
|
204
226
|
const dock = this.#renderDockLayout(width);
|
|
205
|
-
|
|
206
|
-
// Ordinary transcript content uses the full terminal width. The rail is an
|
|
227
|
+
// Invariant: ordinary transcript content uses the full terminal width. The rail is an
|
|
207
228
|
// overlay, not a lost wrapping cell. Submitted prompts alone retain the
|
|
208
229
|
// intentional final gutter after their right-aligned timestamp.
|
|
209
230
|
const documentWidth = width;
|
|
210
|
-
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
// stable editor/footer dock.
|
|
216
|
-
const pinTransient = document.rows.length + dock.transientRows.length <= availableWithoutTransient;
|
|
217
|
-
const dockRows = pinTransient ? dock.rows : dock.rowsWithoutTransient;
|
|
231
|
+
const document = this.#renderDocumentLayout(documentWidth);
|
|
232
|
+
// Invariant: prompt-adjacent transient surfaces always belong to the dock.
|
|
233
|
+
// Changing from fitting to overflowing content reallocates transcript rows
|
|
234
|
+
// only; it never moves queued or Working rows into selectable history.
|
|
235
|
+
const dockRows = dock.rows;
|
|
218
236
|
const selectableDocumentRowCount = document.rows.length;
|
|
219
|
-
if (!pinTransient)
|
|
220
|
-
document = { ...document, rows: [...document.rows, ...dock.transientRows] };
|
|
221
237
|
const dockStartRow = height - dockRows.length + 1;
|
|
222
|
-
const editorOffset =
|
|
238
|
+
const editorOffset = dock.editorOffset;
|
|
223
239
|
this.#viewportController.setEditorPointerFrame(this.usesDefaultInputSurface()
|
|
224
240
|
? {
|
|
225
241
|
rowStart: dockStartRow + editorOffset,
|
|
226
242
|
rowEnd: dockStartRow + editorOffset + dock.inputRows - 1,
|
|
227
243
|
}
|
|
228
244
|
: undefined);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
245
|
+
const snapshot = this.#visibleViewportSnapshot;
|
|
246
|
+
const dockInputCandidate = this.#dockInputCandidate;
|
|
247
|
+
this.#dockInputCandidate = false;
|
|
248
|
+
let frame = dockInputCandidate
|
|
249
|
+
&& snapshot !== undefined
|
|
250
|
+
&& snapshot.width === width
|
|
251
|
+
&& snapshot.height === height
|
|
252
|
+
&& snapshot.documentRows === document.rows
|
|
253
|
+
&& snapshot.promptAnchors === document.promptAnchors
|
|
254
|
+
&& snapshot.dockLength === dockRows.length
|
|
255
|
+
&& snapshot.inputSurface === this.#inputSurface
|
|
256
|
+
&& snapshot.viewportRevision === this.#viewportController.presentationRevision
|
|
257
|
+
&& snapshot.selectionRevision === this.#viewportController.selectionRevision
|
|
258
|
+
? this.#viewportController.composeDockOnly(dockRows, width, height)
|
|
259
|
+
: null;
|
|
260
|
+
if (frame === null) {
|
|
261
|
+
frame = this.#viewportController.compose({
|
|
262
|
+
documentRows: document.rows,
|
|
263
|
+
...(this.#viewportController.transcriptPointerSelecting
|
|
264
|
+
? { paintDocumentRow: heldNativeHyperlinkStyle }
|
|
265
|
+
: {}),
|
|
266
|
+
// Invariant: selection and copying stop at the real document tail; queued
|
|
267
|
+
// and Working rows remain dock-owned status chrome at every fit boundary.
|
|
268
|
+
selectableDocumentRowCount,
|
|
269
|
+
dockRows,
|
|
270
|
+
promptAnchors: document.promptAnchors,
|
|
271
|
+
width,
|
|
272
|
+
height,
|
|
273
|
+
// Invariant: the control belongs immediately above the complete dock,
|
|
274
|
+
// never on top of a queued or Working row.
|
|
275
|
+
bottomControlRow: Math.max(0, height - Math.min(height, dockRows.length) - 1),
|
|
276
|
+
theme: this.#viewportTheme,
|
|
277
|
+
});
|
|
278
|
+
this.#fullViewportCompositions += 1;
|
|
279
|
+
}
|
|
280
|
+
else
|
|
281
|
+
this.#dockOnlyViewportCompositions += 1;
|
|
282
|
+
this.#visibleViewportSnapshot = {
|
|
239
283
|
width,
|
|
240
284
|
height,
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
// foreground roles (including links, warnings, muted text, and bold
|
|
257
|
-
// intensity) remain exactly as rendered instead of being inverted.
|
|
258
|
-
selection: (line, from, to) => backgroundSgrSpan(line, from, to, "\u001b[48;2;38;79;120m", "\u001b[49m"),
|
|
259
|
-
},
|
|
260
|
-
}).rows;
|
|
285
|
+
documentRows: document.rows,
|
|
286
|
+
promptAnchors: document.promptAnchors,
|
|
287
|
+
dockLength: dockRows.length,
|
|
288
|
+
inputSurface: this.#inputSurface,
|
|
289
|
+
viewportRevision: this.#viewportController.presentationRevision,
|
|
290
|
+
selectionRevision: this.#viewportController.selectionRevision,
|
|
291
|
+
};
|
|
292
|
+
this.#onViewportFrame?.(frame);
|
|
293
|
+
return frame.rows;
|
|
294
|
+
}
|
|
295
|
+
viewportFrameDescriptor() {
|
|
296
|
+
return this.#viewportController.frame?.descriptor ?? null;
|
|
297
|
+
}
|
|
298
|
+
hasActiveSelection() {
|
|
299
|
+
return this.#viewportController.hasSelection || this.editor.hasSelection();
|
|
261
300
|
}
|
|
262
301
|
setViewportConfig(config) {
|
|
263
302
|
if (this.#viewportController.setConfig(config))
|
|
@@ -292,11 +331,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
292
331
|
const rowsWithoutTransient = [...aboveWidgets, ...input, ...belowWidgets, ...footer];
|
|
293
332
|
return {
|
|
294
333
|
rows: [...transientRows, ...rowsWithoutTransient],
|
|
295
|
-
|
|
296
|
-
transientRows,
|
|
297
|
-
stableBottomRows: rowsWithoutTransient.length,
|
|
298
|
-
editorOffsetWithTransient: transientRows.length + aboveWidgets.length,
|
|
299
|
-
editorOffsetWithoutTransient: aboveWidgets.length,
|
|
334
|
+
editorOffset: transientRows.length + aboveWidgets.length,
|
|
300
335
|
inputRows: input.length,
|
|
301
336
|
};
|
|
302
337
|
}
|
|
@@ -353,7 +388,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
353
388
|
return this.#renderDocumentLayout(width).rows;
|
|
354
389
|
}
|
|
355
390
|
#renderDocumentLayout(width) {
|
|
356
|
-
//
|
|
391
|
+
// Performance: extension headers may animate independently of transcript revisions, so
|
|
357
392
|
// only the stable built-in document participates in this frame cache.
|
|
358
393
|
const cached = this.#extensionHeader === null ? this.#documentLayouts.get(width) : undefined;
|
|
359
394
|
if (cached !== undefined)
|
|
@@ -387,7 +422,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
387
422
|
: width;
|
|
388
423
|
const blockRows = this.#blockRows(id, block, blockWidth);
|
|
389
424
|
if (block?.kind === "user") {
|
|
390
|
-
//
|
|
425
|
+
// Compatibility: the first natural prompt gets one breathing row at the document top.
|
|
391
426
|
// Once scrolling advances, the prompt itself reaches row zero and then
|
|
392
427
|
// becomes sticky there, so the spacer is never pinned with it.
|
|
393
428
|
if (this.#customViewport && index === 0)
|
|
@@ -430,23 +465,19 @@ export class OwnedUiSessionShellRoot {
|
|
|
430
465
|
const layout = { rows: Object.freeze(rows), promptAnchors: Object.freeze(promptAnchors) };
|
|
431
466
|
if (this.#extensionHeader === null) {
|
|
432
467
|
this.#documentLayouts.set(width, layout);
|
|
433
|
-
//
|
|
468
|
+
// Performance: the custom viewport commonly probes full width and reserved-rail width.
|
|
434
469
|
while (this.#documentLayouts.size > 2)
|
|
435
470
|
this.#documentLayouts.delete(this.#documentLayouts.keys().next().value);
|
|
436
471
|
}
|
|
437
472
|
return layout;
|
|
438
473
|
}
|
|
439
|
-
|
|
440
|
-
* Rows for one transcript block. A finalized block renders once for a given revision
|
|
441
|
-
* and width and is reused after that, so a frame costs what changed rather than what
|
|
442
|
-
* the session has accumulated. A live block, and anything the shell drives itself, is
|
|
443
|
-
* rendered every time because its content is still moving.
|
|
444
|
-
*/
|
|
474
|
+
// Performance: finalized blocks cache by revision and width; live blocks always render.
|
|
445
475
|
#blockRows(id, block, width) {
|
|
446
476
|
const component = this.#transcript.get(id);
|
|
447
477
|
if (component === undefined)
|
|
448
478
|
return [];
|
|
449
479
|
const render = () => {
|
|
480
|
+
this.#transcriptBlockRenders += 1;
|
|
450
481
|
const rows = component.render(width);
|
|
451
482
|
if (!this.#customViewport || block?.kind === "user")
|
|
452
483
|
return rows;
|
|
@@ -464,7 +495,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
464
495
|
this.#renderedRows.set(id, byWidth);
|
|
465
496
|
}
|
|
466
497
|
byWidth.set(width, { revision: block.revision, rows });
|
|
467
|
-
//
|
|
498
|
+
// Invariant: bare A1 probes full width before reserving the overflowing rail column;
|
|
468
499
|
// retain both widths without turning resize history into an unbounded cache.
|
|
469
500
|
while (byWidth.size > 2)
|
|
470
501
|
byWidth.delete(byWidth.keys().next().value);
|
|
@@ -481,7 +512,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
481
512
|
continue;
|
|
482
513
|
if (rows.length > 0 && block.kind === "user")
|
|
483
514
|
rows.push("");
|
|
484
|
-
rows.push(...this.#blockRows(id, block, width).map(
|
|
515
|
+
rows.push(...this.#blockRows(id, block, width).map(sanitizeExitTranscriptRow));
|
|
485
516
|
}
|
|
486
517
|
while (rows.at(-1) === "")
|
|
487
518
|
rows.pop();
|
|
@@ -653,7 +684,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
653
684
|
this.#extensionWorkingMessage = undefined;
|
|
654
685
|
this.#status.setWorkingOverride(undefined);
|
|
655
686
|
this.#footer.update(this.#viewWithExtensionStatuses(this.#view));
|
|
656
|
-
//
|
|
687
|
+
// Invariant: an extension renderer may have drawn transcript blocks that are now unrendered by it.
|
|
657
688
|
this.#renderedRows.clear();
|
|
658
689
|
this.#documentLayouts.clear();
|
|
659
690
|
this.invalidate();
|
|
@@ -678,19 +709,41 @@ export class OwnedUiSessionShellRoot {
|
|
|
678
709
|
usesDefaultInputSurface() {
|
|
679
710
|
return this.#inputSurface === this.editor;
|
|
680
711
|
}
|
|
681
|
-
|
|
712
|
+
inputCoordinationSurface() {
|
|
713
|
+
return this.#inputSurfaceCoordination;
|
|
714
|
+
}
|
|
715
|
+
viewportCompositionEvidence() {
|
|
716
|
+
return { full: this.#fullViewportCompositions, dockOnly: this.#dockOnlyViewportCompositions };
|
|
717
|
+
}
|
|
718
|
+
transcriptRenderCount() {
|
|
719
|
+
return this.#transcriptBlockRenders;
|
|
720
|
+
}
|
|
721
|
+
setInputSurface(component, disposePrevious = true, coordination = "owned") {
|
|
682
722
|
const next = component ?? this.editor;
|
|
683
|
-
|
|
723
|
+
const nextCoordination = next === this.editor ? "editor" : coordination;
|
|
724
|
+
if (next === this.#inputSurface) {
|
|
725
|
+
this.#inputSurfaceCoordination = nextCoordination;
|
|
684
726
|
return;
|
|
727
|
+
}
|
|
728
|
+
this.#dockInputCandidate = false;
|
|
685
729
|
this.#inputSurface.setFocused?.(false);
|
|
686
730
|
if (disposePrevious && this.#inputSurface !== this.editor)
|
|
687
731
|
this.#inputSurface.dispose?.();
|
|
688
732
|
this.#inputSurface = next;
|
|
733
|
+
this.#inputSurfaceCoordination = nextCoordination;
|
|
689
734
|
this.#inputSurface.setFocused?.(true);
|
|
690
735
|
this.invalidate();
|
|
691
736
|
}
|
|
692
737
|
handleInput(data) {
|
|
693
|
-
this.#
|
|
738
|
+
this.#dockInputCandidate = this.#customViewport && this.#dockInputReuseEnabled
|
|
739
|
+
&& classifyPiTuiInput(data, this.#inputSurfaceCoordination) === "safe";
|
|
740
|
+
try {
|
|
741
|
+
this.#inputSurface.handleInput?.(data);
|
|
742
|
+
}
|
|
743
|
+
catch (error) {
|
|
744
|
+
this.#dockInputCandidate = false;
|
|
745
|
+
throw error;
|
|
746
|
+
}
|
|
694
747
|
}
|
|
695
748
|
invalidate() {
|
|
696
749
|
this.header.invalidate();
|
|
@@ -718,6 +771,8 @@ export class OwnedUiSessionShellRoot {
|
|
|
718
771
|
this.#transcript.clear();
|
|
719
772
|
this.#renderedRows.clear();
|
|
720
773
|
this.#documentLayouts.clear();
|
|
774
|
+
this.#visibleViewportSnapshot = undefined;
|
|
775
|
+
this.#dockInputCandidate = false;
|
|
721
776
|
if (this.#inputSurface !== this.editor)
|
|
722
777
|
this.#inputSurface.dispose?.();
|
|
723
778
|
this.#extensionHeader?.dispose?.();
|
|
@@ -849,13 +904,19 @@ export class OwnedUiSessionShellRoot {
|
|
|
849
904
|
this.resources.setExpanded(expanded);
|
|
850
905
|
for (const component of this.#transcript.values())
|
|
851
906
|
component.setExpanded(expanded);
|
|
852
|
-
//
|
|
907
|
+
// Invariant: expansion changes what a block draws without changing its revision.
|
|
853
908
|
this.#renderedRows.clear();
|
|
854
909
|
this.#documentLayouts.clear();
|
|
855
910
|
this.invalidate();
|
|
856
911
|
}
|
|
857
912
|
}
|
|
858
913
|
const SCROLLBAR_CELL_RESET = "\u001b[22;23;24;25;27;28;29;39;54;55m";
|
|
914
|
+
const KITTY_IMAGE_CONTROL = /\u001b_G[\s\S]*?\u001b\\/g;
|
|
915
|
+
const ITERM_IMAGE_CONTROL = /\u001b]1337;File=[^\u0007]*(?:\u0007|\u001b\\)/g;
|
|
916
|
+
/** Keep semantic SGR/OSC styling while excluding non-replayable image payloads. */
|
|
917
|
+
function sanitizeExitTranscriptRow(row) {
|
|
918
|
+
return row.replace(KITTY_IMAGE_CONTROL, "").replace(ITERM_IMAGE_CONTROL, "");
|
|
919
|
+
}
|
|
859
920
|
const TERMINAL_BACKGROUND = /\u001b\[(?:4[0-9]|10[0-7]|48(?:[;:][0-9;:]*)?)m/g;
|
|
860
921
|
/** Web URLs use link blue; file targets retain A1's cyan interactive accent. */
|
|
861
922
|
function nativeTranscriptLinkColor(text, target) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { OwnedUiSessionViewModel, OwnedUiThinkingLevel } from "../../../contracts/owned-ui/index.js";
|
|
2
2
|
import { type AdapterCommandResult, type PiWorkflowRequest } from "../engine/index.js";
|
|
3
3
|
import { type PiShellSelectorOption } from "../components/index.js";
|
|
4
|
-
import { PiTuiRuntimeAdapter, type PiTuiOverlayHandle } from "../tui-runtime/index.js";
|
|
4
|
+
import { PiTuiRuntimeAdapter, type PiTuiDamageDecision, type PiTuiOverlayHandle } from "../tui-runtime/index.js";
|
|
5
5
|
import { OwnedUiSessionShellRoot, type OwnedUiBackendPort, type OwnedUiSessionShellOptions } from "./session-shell-root.js";
|
|
6
6
|
export { OwnedUiSessionShellRoot, type OwnedUiSessionShellOptions } from "./session-shell-root.js";
|
|
7
|
+
/** Coordinates backend, owned presentation, and Pi TUI lifecycles for one interactive session. */
|
|
7
8
|
export declare class OwnedUiSessionShell {
|
|
8
9
|
#private;
|
|
9
10
|
readonly backend: OwnedUiBackendPort;
|
|
@@ -11,6 +12,7 @@ export declare class OwnedUiSessionShell {
|
|
|
11
12
|
readonly runtime: PiTuiRuntimeAdapter;
|
|
12
13
|
constructor(options: OwnedUiSessionShellOptions);
|
|
13
14
|
view(): OwnedUiSessionViewModel;
|
|
15
|
+
damagePresentationDecision(): PiTuiDamageDecision | null;
|
|
14
16
|
start(): void;
|
|
15
17
|
onView(listener: (view: OwnedUiSessionViewModel) => void): () => void;
|
|
16
18
|
waitUntilStopped(): Promise<void>;
|
|
@@ -44,5 +46,10 @@ export declare class OwnedUiSessionShell {
|
|
|
44
46
|
showScopedModelsSelector(): void;
|
|
45
47
|
dispose(): Promise<void>;
|
|
46
48
|
}
|
|
47
|
-
export
|
|
49
|
+
export interface SessionResumeCommandMetadata {
|
|
50
|
+
readonly sessionId: string;
|
|
51
|
+
readonly sessionDir: string;
|
|
52
|
+
readonly usesDefaultSessionDir: boolean;
|
|
53
|
+
}
|
|
54
|
+
export declare function formatSessionResumeCommand(metadata: SessionResumeCommandMetadata): string;
|
|
48
55
|
export declare function quoteCommandArgument(value: string): string;
|