@timurproko/a1 0.2.7-dev.810 → 0.2.7-dev.828
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/bin/automatic-update.js +7 -0
- package/bin/tab-launch-context.d.ts +1 -0
- package/bin/tab-launch-context.js +3 -3
- package/bin/ui.js +96 -66
- package/dist/app/session-shell/resident-tab-coordinator.d.ts +6 -9
- package/dist/app/session-shell/resident-tab-coordinator.js +9 -52
- package/dist/app/session-shell/session-shell-root.d.ts +14 -8
- package/dist/app/session-shell/session-shell-root.js +9 -5
- package/dist/app/session-shell/session-shell.js +70 -20
- package/dist/app/session-shell/session-viewport-controller.js +6 -4
- package/dist/app/session-shell/shell-host.js +6 -3
- package/dist/app/session-shell/transcript-document.js +1 -1
- package/dist/cli/tabs.d.ts +1 -1
- package/dist/cli/tabs.js +10 -14
- package/dist/composition/owned-settings.d.ts +12 -0
- package/dist/composition/owned-settings.js +36 -0
- package/dist/composition/owned-ui.d.ts +5 -14
- package/dist/composition/owned-ui.js +93 -64
- package/dist/composition/resident-tab-bridge.d.ts +10 -1
- package/dist/composition/resident-tab-bridge.js +21 -0
- package/dist/composition/settings-route-host.d.ts +12 -2
- package/dist/composition/settings-route-host.js +27 -9
- package/dist/composition/settings-search-input.d.ts +9 -0
- package/dist/composition/settings-search-input.js +58 -0
- package/dist/composition/utility-tab.d.ts +28 -0
- package/dist/composition/utility-tab.js +242 -0
- package/dist/contracts/owned-ui/session-backend.d.ts +2 -0
- package/dist/contracts/owned-ui/session-workflows.d.ts +7 -3
- package/dist/contracts/presentation/index.d.ts +11 -0
- package/dist/contracts/presentation/index.js +12 -0
- package/dist/features/launch/development-launch.js +6 -0
- package/dist/features/launch/profile-paths.js +4 -0
- package/dist/features/owned-ui/plus-menu-dialog.d.ts +22 -0
- package/dist/features/owned-ui/plus-menu-dialog.js +76 -0
- package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
- package/dist/features/owned-ui/project-trust-dialog.js +6 -8
- package/dist/features/owned-ui/project-trust-prompt.d.ts +1 -0
- package/dist/features/owned-ui/project-trust-prompt.js +7 -3
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
- package/dist/features/owned-ui/reference-screen-app.js +12 -2
- package/dist/features/owned-ui/settings-app.d.ts +10 -3
- package/dist/features/owned-ui/settings-app.js +98 -45
- package/dist/features/owned-ui/settings-search-input.d.ts +29 -0
- package/dist/features/owned-ui/settings-search-input.js +1 -0
- package/dist/features/prompt-history/index.d.ts +1 -1
- package/dist/features/prompt-history/paths.d.ts +2 -1
- package/dist/features/prompt-history/paths.js +10 -2
- package/dist/features/prompt-history/service.d.ts +5 -0
- package/dist/features/prompt-history/service.js +1 -1
- package/dist/features/resident-tab/shortcut-declarations.d.ts +1 -1
- package/dist/features/resident-tab/shortcut-declarations.js +2 -0
- package/dist/foundation/launch-context/index.d.ts +2 -0
- package/dist/foundation/launch-context/index.js +1 -0
- package/dist/foundation/lifecycle/session-repository-context.js +16 -2
- package/dist/foundation/release/automatic-update.d.ts +37 -0
- package/dist/foundation/release/automatic-update.js +265 -0
- package/dist/foundation/release/bootstrap.d.ts +1 -9
- package/dist/foundation/release/bootstrap.js +7 -3
- package/dist/foundation/release/early-accent.d.ts +12 -0
- package/dist/foundation/release/early-accent.js +59 -0
- package/dist/foundation/release/index.d.ts +1 -1
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/latest-release.d.ts +3 -2
- package/dist/foundation/release/latest-release.js +1 -1
- package/dist/foundation/release/progress-palette.generated.d.ts +137 -3
- package/dist/foundation/release/progress-palette.generated.js +137 -3
- package/dist/foundation/release/release-gc.js +19 -4
- package/dist/foundation/release/update-execution-lease.d.ts +36 -0
- package/dist/foundation/release/update-execution-lease.js +145 -0
- package/dist/foundation/release/update.d.ts +9 -7
- package/dist/foundation/release/update.js +244 -175
- package/dist/foundation/resident-tabs/bridge-client.d.ts +10 -3
- package/dist/foundation/resident-tabs/bridge-client.js +20 -8
- package/dist/foundation/resident-tabs/maintenance.d.ts +2 -6
- package/dist/foundation/resident-tabs/maintenance.js +5 -23
- package/dist/foundation/resident-tabs/progress-observation-schema.d.ts +34 -0
- package/dist/foundation/resident-tabs/progress-observation-schema.js +1 -0
- package/dist/foundation/resident-tabs/progress-observation.d.ts +3 -6
- package/dist/foundation/resident-tabs/progress-observation.js +43 -12
- package/dist/foundation/resident-tabs/release-holds.js +3 -14
- package/dist/foundation/resident-tabs/routes.d.ts +5 -0
- package/dist/foundation/resident-tabs/routes.js +5 -0
- package/dist/foundation/resident-tabs/settings.d.ts +0 -1
- package/dist/foundation/resident-tabs/settings.js +0 -2
- package/dist/integrations/pi/components/editor-interaction.d.ts +2 -0
- package/dist/integrations/pi/components/modal-frame.d.ts +17 -1
- package/dist/integrations/pi/components/modal-frame.js +48 -9
- package/dist/integrations/pi/components/models-dialog.js +4 -52
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +3 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +75 -4
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +57 -37
- package/dist/integrations/pi/components/shell-footer-status.js +19 -3
- package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +4 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +9 -2
- package/dist/integrations/pi/components/skills-dialog.js +2 -2
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +7 -5
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +15 -8
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +3 -3
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +2 -2
- package/dist/integrations/pi/components/upstream/components/session-footer.js +26 -23
- package/dist/integrations/pi/components/upstream/components/session-selector.js +7 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +7 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +9 -8
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +6 -4
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +8 -8
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +10 -10
- package/dist/integrations/pi/components/upstream/history/editor-core.js +2 -0
- package/dist/integrations/pi/components/upstream/theme/theme.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/theme/theme.js +5 -1
- package/dist/integrations/pi/engine/adapter.js +7 -2
- package/dist/integrations/pi/engine/offline-settings-port.d.ts +23 -0
- package/dist/integrations/pi/engine/offline-settings-port.js +53 -0
- package/dist/integrations/pi/engine/ports.d.ts +1 -1
- package/dist/integrations/pi/engine/ports.js +4 -0
- package/dist/integrations/pi/engine/settings-bridge.d.ts +5 -0
- package/dist/integrations/pi/engine/settings-bridge.js +13 -0
- package/dist/integrations/pi/engine/settings-port.js +1 -14
- package/dist/integrations/pi/engine/workflow-runner.js +9 -2
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-arm64/terminal-host.node +0 -0
- package/dist/native/darwin-x64/manifest.json +1 -1
- package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-x64/terminal-host.node +0 -0
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
- package/dist/native/linux-x64/terminal-host.node +0 -0
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.node +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
- package/dist/native/win32-x64/terminal-host.node +0 -0
- package/dist/product-identity.d.ts +1 -1
- package/dist/product-identity.js +2 -2
- package/dist/product-identity.json +2 -0
- package/dist/ui/apps/host.d.ts +2 -0
- package/dist/ui/apps/host.js +7 -1
- package/dist/ui/components/dialog-panel.js +35 -30
- package/dist/ui/components/line-input.d.ts +3 -0
- package/dist/ui/components/line-input.js +3 -1
- package/dist/ui/components/prompt-input.d.ts +5 -4
- package/dist/ui/components/prompt-input.js +8 -6
- package/dist/ui/components/spans.js +2 -2
- package/dist/ui/components/submitted-prompt.d.ts +2 -2
- package/dist/ui/components/submitted-prompt.js +3 -3
- package/dist/ui/components/surface.js +4 -2
- package/dist/ui/components/text.d.ts +3 -6
- package/dist/ui/components/text.js +6 -8
- package/dist/ui/components/transcript-viewport.d.ts +1 -1
- package/dist/ui/components/transcript-viewport.js +141 -24
- package/dist/ui/settings/declarations.d.ts +67 -17
- package/dist/ui/settings/declarations.js +47 -15
- package/dist/ui/settings/early-accent.d.ts +81 -0
- package/dist/ui/settings/early-accent.js +50 -0
- package/dist/ui/settings/manager.js +7 -3
- package/dist/ui/settings/migrations.js +22 -0
- package/dist/ui/settings/progress-palette.generated.d.ts +139 -0
- package/dist/ui/settings/progress-palette.generated.js +139 -0
- package/dist/ui/settings/sections.d.ts +4 -0
- package/dist/ui/settings/sections.js +9 -3
- package/docs/architecture/resident-tabs.md +52 -21
- package/docs/architecture/tool-image-presentation.md +2 -1
- package/docs/features/prompt-history.md +41 -20
- package/docs/validation.md +25 -5
- package/package.json +1 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { connect } from "node:net";
|
|
2
2
|
import { encodeResidentFrame, ResidentFrameDecoder } from "./protocol.js";
|
|
3
|
+
import { RESIDENT_TAB_ROUTES } from "./routes.js";
|
|
4
|
+
export { residentUtilityRoute } from "./routes.js";
|
|
5
|
+
const RESIDENT_TAB_ROUTE_SET = new Set(RESIDENT_TAB_ROUTES);
|
|
3
6
|
/** Metadata-only advisory bridge. Terminal input and transcript bytes have no API here. */
|
|
4
7
|
export class TabBridgeClient {
|
|
5
8
|
#options;
|
|
@@ -67,7 +70,7 @@ export class TabBridgeClient {
|
|
|
67
70
|
this.#startWaiter = finish;
|
|
68
71
|
transport.once("connect", () => {
|
|
69
72
|
this.#send("hello", {
|
|
70
|
-
role: "bridge", generation: 1, build: this.#options.build ?? "a1",
|
|
73
|
+
role: "bridge", generation: 1, build: this.#options.build ?? "a1", releaseId: this.#options.credentials.releaseId,
|
|
71
74
|
features: ["bridge-status", "bridge-detach", "bridge-heartbeat", "bridge-restart", "bridge-visibility", "bridge-rename", "bridge-route", "bridge-stop", "bridge-shortcuts", "controller-boundary", "recovery-journal"],
|
|
72
75
|
token: [...Buffer.from(this.#options.credentials.token, "base64")], tabId: this.#options.credentials.tabId,
|
|
73
76
|
pid: this.#options.pid ?? process.pid, startIdentity: this.#options.startIdentity ?? `${process.pid}:node`,
|
|
@@ -80,7 +83,7 @@ export class TabBridgeClient {
|
|
|
80
83
|
}
|
|
81
84
|
status(state, degraded = false, pendingRequests = 0, queuedInput = 0) {
|
|
82
85
|
this.#latestStatus = { state, degraded, accent: this.#accent, pendingRequests, queuedInput };
|
|
83
|
-
const recoveryState = state === "unresponsive" || state === "
|
|
86
|
+
const recoveryState = state === "unresponsive" || state === "crashed" || state === "restarting" || state === "failed";
|
|
84
87
|
if (recoveryState && !this.#supports("recovery-status"))
|
|
85
88
|
return;
|
|
86
89
|
this.#send("bridge.status", {
|
|
@@ -118,13 +121,13 @@ export class TabBridgeClient {
|
|
|
118
121
|
this.#send("bridge.shortcuts", { assignments: this.#latestShortcuts.map(([action, key]) => [action, key]) });
|
|
119
122
|
}
|
|
120
123
|
requestDetach(origin = this.captureAttachment(), timeoutMs = 1_000) {
|
|
121
|
-
return this
|
|
124
|
+
return this.requestAction("detach", origin, timeoutMs);
|
|
122
125
|
}
|
|
123
126
|
requestRestart(origin = this.captureAttachment(), timeoutMs = 1_000) {
|
|
124
|
-
return this
|
|
127
|
+
return this.requestAction("restart", origin, timeoutMs);
|
|
125
128
|
}
|
|
126
129
|
requestClose(origin = this.captureAttachment(), timeoutMs = 1_000) {
|
|
127
|
-
return this
|
|
130
|
+
return this.requestAction("close", origin, timeoutMs);
|
|
128
131
|
}
|
|
129
132
|
consumeControllerBoundaryInput(data) {
|
|
130
133
|
const prefix = "\x1bP+a1;controller=";
|
|
@@ -205,6 +208,11 @@ export class TabBridgeClient {
|
|
|
205
208
|
}
|
|
206
209
|
#receive(message) {
|
|
207
210
|
if (message.type === "welcome" && message.body["generation"] === 1) {
|
|
211
|
+
const id = this.#options.credentials.releaseId;
|
|
212
|
+
if (id !== undefined && message.body["releaseId"] !== id) {
|
|
213
|
+
this.#fail(false);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
208
216
|
const advertised = message.body["features"];
|
|
209
217
|
this.#features = new Set(Array.isArray(advertised) ? advertised.filter((feature) => typeof feature === "string") : []);
|
|
210
218
|
this.#connected = true;
|
|
@@ -232,8 +240,8 @@ export class TabBridgeClient {
|
|
|
232
240
|
this.#emitCommand({ type: "rename", name: message.body["name"], nameSource: source === "auto" || source === "default" ? source : "user" });
|
|
233
241
|
return;
|
|
234
242
|
}
|
|
235
|
-
if (message.type === "bridge.route" && message.body["route"]
|
|
236
|
-
this.#emitCommand({ type: "route", route: "
|
|
243
|
+
if (message.type === "bridge.route" && RESIDENT_TAB_ROUTE_SET.has(message.body["route"])) {
|
|
244
|
+
this.#emitCommand({ type: "route", route: message.body["route"] });
|
|
237
245
|
return;
|
|
238
246
|
}
|
|
239
247
|
if (message.type === "bridge.stop" && typeof message.body["deadlineMs"] === "number") {
|
|
@@ -255,7 +263,11 @@ export class TabBridgeClient {
|
|
|
255
263
|
}
|
|
256
264
|
}
|
|
257
265
|
}
|
|
258
|
-
|
|
266
|
+
/**
|
|
267
|
+
* Asks the server to act for the client that controls this tab, as `origin`: leave it, restart or close the tab,
|
|
268
|
+
* or open the tab bar's Plus Menu dialog (`configure-plus`).
|
|
269
|
+
*/
|
|
270
|
+
async requestAction(action, origin = this.captureAttachment(), timeoutMs = 1_000) {
|
|
259
271
|
if (!this.available || origin === null || (action === "restart" && !this.#supports("bridge-restart")))
|
|
260
272
|
return false;
|
|
261
273
|
const requestId = ++this.#request;
|
|
@@ -21,7 +21,7 @@ export interface MaintenanceOptions {
|
|
|
21
21
|
readonly profileRoot: string;
|
|
22
22
|
readonly dataDir: string;
|
|
23
23
|
readonly runtimeDir: string;
|
|
24
|
-
/**
|
|
24
|
+
/** The first root is the invoking release; other roots never substitute for it. */
|
|
25
25
|
readonly releaseRoots: readonly string[];
|
|
26
26
|
readonly environment: NodeJS.ProcessEnv;
|
|
27
27
|
readonly platform?: NodeJS.Platform;
|
|
@@ -33,11 +33,7 @@ export interface MaintenanceOptions {
|
|
|
33
33
|
readonly stdout: string;
|
|
34
34
|
}>;
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Runs one maintenance form through a verified terminal host. When the running host speaks
|
|
38
|
-
* another protocol generation, it retries once with the addon from the release that host
|
|
39
|
-
* recorded, after verifying that release's manifest; it never loads an unverified addon.
|
|
40
|
-
*/
|
|
36
|
+
/** Runs maintenance only through the invoking release; another cohort is never a retry target. */
|
|
41
37
|
export declare function runTerminalHostMaintenance(options: MaintenanceOptions): Promise<MaintenanceReport>;
|
|
42
38
|
/** The largest maintenance report accepted from the terminal host. */
|
|
43
39
|
export declare const MAX_MAINTENANCE_REPORT_BYTES: number;
|
|
@@ -4,26 +4,14 @@ import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
|
4
4
|
import { runBoundedHostCommand } from "./bounded-host-command.js";
|
|
5
5
|
import { resolveTerminalHostEntryPath, resolveTerminalHostPath } from "./ensure-terminal-host.js";
|
|
6
6
|
import { verifyTerminalHostArtifact } from "./terminal-host-artifact.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Runs one maintenance form through a verified terminal host. When the running host speaks
|
|
10
|
-
* another protocol generation, it retries once with the addon from the release that host
|
|
11
|
-
* recorded, after verifying that release's manifest; it never loads an unverified addon.
|
|
12
|
-
*/
|
|
7
|
+
/** Runs maintenance only through the invoking release; another cohort is never a retry target. */
|
|
13
8
|
export async function runTerminalHostMaintenance(options) {
|
|
14
9
|
const platform = options.platform ?? process.platform;
|
|
15
10
|
const architecture = options.architecture ?? process.arch;
|
|
16
|
-
const command = await firstVerifiedHost(options, options.releaseRoots, platform, architecture);
|
|
11
|
+
const command = await firstVerifiedHost(options, options.releaseRoots.slice(0, 1), platform, architecture);
|
|
17
12
|
if (command === undefined)
|
|
18
|
-
return unavailable(options.action, "no verified terminal host
|
|
19
|
-
|
|
20
|
-
if (report.exitCode !== INCOMPATIBLE_EXIT || typeof report.releaseRoot !== "string")
|
|
21
|
-
return report;
|
|
22
|
-
const cohort = await firstVerifiedHost({ ...options, environment: {} }, [report.releaseRoot], platform, architecture);
|
|
23
|
-
if (cohort === undefined || cohort.entry === command.entry) {
|
|
24
|
-
return { ...report, message: "the running tabs use another version whose terminal host cannot be verified" };
|
|
25
|
-
}
|
|
26
|
-
return await invoke({ ...options, environment: installedEnvironment(options.environment) }, cohort);
|
|
13
|
+
return unavailable(options.action, "the invoking release has no verified terminal host");
|
|
14
|
+
return await invoke(options, command);
|
|
27
15
|
}
|
|
28
16
|
function arguments_(options) {
|
|
29
17
|
const command = options.action === "stop" ? ["stop", options.tabId ?? ""] : [options.action];
|
|
@@ -67,17 +55,11 @@ async function firstVerifiedHost(options, roots, platform, architecture) {
|
|
|
67
55
|
return { executable: process.execPath, entry: resolveTerminalHostEntryPath(root) };
|
|
68
56
|
}
|
|
69
57
|
catch {
|
|
70
|
-
//
|
|
58
|
+
// Invariant: a missing or altered invoking artifact fails closed.
|
|
71
59
|
}
|
|
72
60
|
}
|
|
73
61
|
return undefined;
|
|
74
62
|
}
|
|
75
|
-
function installedEnvironment(environment) {
|
|
76
|
-
const sanitized = { ...environment };
|
|
77
|
-
delete sanitized[PRODUCT_IDENTITY.environment.developmentInstanceId];
|
|
78
|
-
delete sanitized[PRODUCT_IDENTITY.environment.terminalHostPath];
|
|
79
|
-
return sanitized;
|
|
80
|
-
}
|
|
81
63
|
function unavailable(action, message) {
|
|
82
64
|
return { schema: "a1-tabs-maintenance-v1", command: action, host: "unavailable", message, exitCode: 3 };
|
|
83
65
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Payload-free fixture schema; type-only imports keep it outside the evaluated startup graph. */
|
|
2
|
+
export type ResidentInputPhase = "receipt" | "semantic-start" | "semantic-end" | "composition-start" | "composition-end" | "write-start" | "write-end";
|
|
3
|
+
export interface ProgressFields {
|
|
4
|
+
readonly eventSequence?: number;
|
|
5
|
+
readonly revision?: number;
|
|
6
|
+
readonly geometryGeneration?: number;
|
|
7
|
+
readonly bytes?: number;
|
|
8
|
+
readonly count?: number;
|
|
9
|
+
readonly eventKind?: string;
|
|
10
|
+
readonly frameId?: number;
|
|
11
|
+
readonly renderCause?: string;
|
|
12
|
+
readonly fragmentCount?: number;
|
|
13
|
+
readonly transactionKind?: "synchronized-output" | "ordinary";
|
|
14
|
+
}
|
|
15
|
+
export interface ProgressRecord extends ProgressFields {
|
|
16
|
+
readonly schema: "a1-resident-progress-observation-v1";
|
|
17
|
+
readonly runId: string;
|
|
18
|
+
readonly role: "child";
|
|
19
|
+
readonly stage: "engine-delivery" | "child-render-write" | "child-input-phase";
|
|
20
|
+
readonly pid: number;
|
|
21
|
+
readonly processInstance: string;
|
|
22
|
+
readonly timestampUnixUs: number;
|
|
23
|
+
readonly clockErrorUs: number;
|
|
24
|
+
readonly sequence: number;
|
|
25
|
+
readonly tabId: string;
|
|
26
|
+
readonly incarnation: number;
|
|
27
|
+
readonly lostBefore: number;
|
|
28
|
+
}
|
|
29
|
+
export interface ResidentProgressObserverPort {
|
|
30
|
+
readonly tabId: string;
|
|
31
|
+
engineDelivery(event: unknown): void;
|
|
32
|
+
inputPhase?(phase: ResidentInputPhase, revision: number): void;
|
|
33
|
+
childRenderWrite(bytes: number, fragments: number, transaction: "synchronized-output" | "ordinary", frameId?: number, renderCause?: string): void;
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
childRenderWrite(bytes: number, fragments: number, transaction: "synchronized-output" | "ordinary", frameId?: number, renderCause?: string): void;
|
|
5
|
-
}
|
|
6
|
-
/** Returns the opt-in payload-free observer for a resident child, or null on ordinary launches. */
|
|
1
|
+
import type { ResidentProgressObserverPort } from "./progress-observation-schema.js";
|
|
2
|
+
export type { ResidentProgressObserverPort } from "./progress-observation-schema.js";
|
|
3
|
+
/** Opt-in payload-free child observer; ordinary launches return null. */
|
|
7
4
|
export declare function residentProgressObserver(environment?: NodeJS.ProcessEnv): ResidentProgressObserverPort | null;
|
|
@@ -17,7 +17,10 @@ class ResidentProgressObserver {
|
|
|
17
17
|
#engineSequence = 0;
|
|
18
18
|
#pendingBytes = 0;
|
|
19
19
|
#lost = 0;
|
|
20
|
-
#writing =
|
|
20
|
+
#writing = false;
|
|
21
|
+
#pending = [];
|
|
22
|
+
#scheduled = false;
|
|
23
|
+
#directoryReady = false;
|
|
21
24
|
#failed = false;
|
|
22
25
|
get tabId() { return this.#tabId; }
|
|
23
26
|
constructor(directory, runId, tabId, incarnation) {
|
|
@@ -36,6 +39,9 @@ class ResidentProgressObserver {
|
|
|
36
39
|
count: 1,
|
|
37
40
|
});
|
|
38
41
|
}
|
|
42
|
+
inputPhase(phase, revision) {
|
|
43
|
+
this.#observe("child-input-phase", { eventKind: phase, revision, count: 1 });
|
|
44
|
+
}
|
|
39
45
|
childRenderWrite(bytes, fragments, transaction, frameId, renderCause) {
|
|
40
46
|
this.#observe("child-render-write", {
|
|
41
47
|
eventSequence: this.#engineSequence,
|
|
@@ -59,7 +65,7 @@ class ResidentProgressObserver {
|
|
|
59
65
|
pid: process.pid,
|
|
60
66
|
processInstance: this.#processInstance,
|
|
61
67
|
timestampUnixUs: Math.round((performance.timeOrigin + performance.now()) * 1_000),
|
|
62
|
-
// Rationale:
|
|
68
|
+
// Rationale: epoch-calibrated timeOrigin retains conservative cross-process clock error.
|
|
63
69
|
clockErrorUs: 1_000,
|
|
64
70
|
sequence: ++this.#sequence,
|
|
65
71
|
tabId: this.#tabId,
|
|
@@ -75,18 +81,44 @@ class ResidentProgressObserver {
|
|
|
75
81
|
}
|
|
76
82
|
this.#lost = 0;
|
|
77
83
|
this.#pendingBytes += length;
|
|
78
|
-
this.#
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
this.#pending.push(line);
|
|
85
|
+
this.#schedule();
|
|
86
|
+
}
|
|
87
|
+
#schedule() {
|
|
88
|
+
if (this.#scheduled || this.#writing || this.#failed)
|
|
89
|
+
return;
|
|
90
|
+
this.#scheduled = true;
|
|
91
|
+
// Performance: check-phase batches yield to input and amortize file opens and promises.
|
|
92
|
+
setImmediate(() => { this.#scheduled = false; void this.#flush(); });
|
|
93
|
+
}
|
|
94
|
+
async #flush() {
|
|
95
|
+
if (this.#failed || this.#pending.length === 0)
|
|
96
|
+
return;
|
|
97
|
+
this.#writing = true;
|
|
98
|
+
const batch = this.#pending.join("");
|
|
99
|
+
this.#pending = [];
|
|
100
|
+
// Rationale: cap pending only.
|
|
101
|
+
this.#pendingBytes = 0;
|
|
102
|
+
try {
|
|
103
|
+
if (!this.#directoryReady) {
|
|
104
|
+
await mkdir(this.#directory, { recursive: true });
|
|
105
|
+
this.#directoryReady = true;
|
|
106
|
+
}
|
|
107
|
+
await appendFile(this.#path, batch, "utf8");
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
82
110
|
this.#failed = true;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
111
|
+
this.#pending = [];
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
this.#writing = false;
|
|
115
|
+
if (this.#pending.length > 0)
|
|
116
|
+
this.#schedule();
|
|
117
|
+
}
|
|
86
118
|
}
|
|
87
119
|
}
|
|
88
120
|
let observer;
|
|
89
|
-
/**
|
|
121
|
+
/** Opt-in payload-free child observer; ordinary launches return null. */
|
|
90
122
|
export function residentProgressObserver(environment = process.env) {
|
|
91
123
|
if (environment === process.env && observer !== undefined)
|
|
92
124
|
return observer;
|
|
@@ -99,8 +131,7 @@ export function residentProgressObserver(environment = process.env) {
|
|
|
99
131
|
: null;
|
|
100
132
|
if (environment === process.env) {
|
|
101
133
|
observer = value;
|
|
102
|
-
// Security:
|
|
103
|
-
// this observer instance so extensions and spawned tools cannot append to the fixture trace.
|
|
134
|
+
// Security: keep evidence paths and identity private; erase them before extensions/tools inherit env.
|
|
104
135
|
for (const name of [
|
|
105
136
|
OBSERVATION_DIRECTORY_ENV,
|
|
106
137
|
OBSERVATION_RUN_ENV,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdir
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
4
4
|
import { runBoundedHostCommand } from "./bounded-host-command.js";
|
|
@@ -51,19 +51,8 @@ async function hasResidentRecords(dataDir) {
|
|
|
51
51
|
catch (error) {
|
|
52
52
|
return !(error instanceof Error && "code" in error && error.code === "ENOENT");
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
await stat(resolve(dataDir, "tabs", profile, record));
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
if (!(error instanceof Error && "code" in error && error.code === "ENOENT"))
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
54
|
+
// Invariant: native inspection, not a following stat, judges unknown or linked namespace entries.
|
|
55
|
+
return profiles.length > 0;
|
|
67
56
|
}
|
|
68
57
|
function incomplete(reason) {
|
|
69
58
|
return { complete: false, releaseRoots: [], uncertain: [reason] };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The owned screens the server opens in a utility tab; each names its tab id stem, `<route>-…`. */
|
|
2
|
+
export type ResidentTabRoute = "settings" | "changelog";
|
|
3
|
+
export declare const RESIDENT_TAB_ROUTES: readonly ResidentTabRoute[];
|
|
4
|
+
/** The utility route whose screen is the resident tab `tabId`, or `null` for an Agent tab. */
|
|
5
|
+
export declare function residentUtilityRoute(tabId: string): ResidentTabRoute | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const RESIDENT_TAB_ROUTES = ["settings", "changelog"];
|
|
2
|
+
/** The utility route whose screen is the resident tab `tabId`, or `null` for an Agent tab. */
|
|
3
|
+
export function residentUtilityRoute(tabId) {
|
|
4
|
+
return RESIDENT_TAB_ROUTES.find(route => tabId.startsWith(`${route}-`)) ?? null;
|
|
5
|
+
}
|
|
@@ -7,7 +7,6 @@ export interface ResidentTabLaunchSettings {
|
|
|
7
7
|
readonly maxConcurrentStarts: number;
|
|
8
8
|
readonly prewarmCount: number;
|
|
9
9
|
readonly unresponsiveRestartSeconds: number;
|
|
10
|
-
readonly stallNoticeSeconds: number;
|
|
11
10
|
}
|
|
12
11
|
/** Read only resident-launch values before any UI or extension module is loaded. */
|
|
13
12
|
export declare function readResidentTabLaunchSettings(profileDir: string, namespace?: string, legacyConfigDir?: string, profileId?: string): Promise<ResidentTabLaunchSettings>;
|
|
@@ -11,7 +11,6 @@ const DEFAULTS = Object.freeze({
|
|
|
11
11
|
maxConcurrentStarts: RESIDENT_TABS_MAX_CONCURRENT_STARTS,
|
|
12
12
|
prewarmCount: RESIDENT_TABS_PREWARM_COUNT,
|
|
13
13
|
unresponsiveRestartSeconds: 120,
|
|
14
|
-
stallNoticeSeconds: 300,
|
|
15
14
|
});
|
|
16
15
|
/** Read only resident-launch values before any UI or extension module is loaded. */
|
|
17
16
|
export async function readResidentTabLaunchSettings(profileDir, namespace = "a1", legacyConfigDir, profileId = namespace) {
|
|
@@ -55,6 +54,5 @@ function resolveLaunchValues(document, migrations) {
|
|
|
55
54
|
maxConcurrentStarts: RESIDENT_TABS_MAX_CONCURRENT_STARTS,
|
|
56
55
|
prewarmCount: RESIDENT_TABS_PREWARM_COUNT,
|
|
57
56
|
unresponsiveRestartSeconds: DEFAULTS.unresponsiveRestartSeconds,
|
|
58
|
-
stallNoticeSeconds: DEFAULTS.stallNoticeSeconds,
|
|
59
57
|
};
|
|
60
58
|
}
|
|
@@ -25,6 +25,8 @@ export interface EditorRecallPort {
|
|
|
25
25
|
};
|
|
26
26
|
observe(listener: () => void): () => void;
|
|
27
27
|
reset(): void;
|
|
28
|
+
/** Exit a recall browse cycle by restoring the unsent draft rather than keeping the recalled entry. */
|
|
29
|
+
restoreDraft?(): void;
|
|
28
30
|
}
|
|
29
31
|
export interface EditorSurface extends Pick<Editor, Exclude<keyof Editor, "setText" | "render" | "handleInput">> {
|
|
30
32
|
setText(text: string): void;
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
import { Container, type Component, type TUI } from "@earendil-works/pi-tui";
|
|
1
|
+
import { Container, Input, type Component, type Focusable, type TUI, type TuiMouseEvent, type TuiMouseEventResult } from "@earendil-works/pi-tui";
|
|
2
2
|
export declare const PI_MODAL_CONTENT_PADDING_X = 1;
|
|
3
|
+
/** Paints the standard Pi Input prompt as a live-themed dialog-search marker. */
|
|
4
|
+
export declare function renderPiModalSearchInput(input: Input, width: number): string[];
|
|
5
|
+
/** Keeps Pi Input behavior and geometry while owning only its standard dialog-search presentation. */
|
|
6
|
+
export declare class PiModalSearchInput implements Component, Focusable {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(input: Input);
|
|
9
|
+
get focused(): boolean;
|
|
10
|
+
set focused(value: boolean);
|
|
11
|
+
invalidate(): void;
|
|
12
|
+
render(width: number): string[];
|
|
13
|
+
handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Replaces one explicitly identified direct Input child with the standard search presentation. */
|
|
16
|
+
export declare function adoptPiModalSearchInput(container: Container, input: Component): PiModalSearchInput;
|
|
17
|
+
/** Adds one standard dialog-search presentation while callers retain the Input controller. */
|
|
18
|
+
export declare function addPiModalSearchInput(container: Container, input: Input): PiModalSearchInput;
|
|
3
19
|
/** Adds the standard navigation/select/close footer before a dependency component's bottom rule. */
|
|
4
20
|
export declare function addPiModalSelectFooter(container: Container): void;
|
|
5
21
|
/** Owned cancellable operation frame with the canonical dialog close guidance. */
|
|
@@ -1,7 +1,47 @@
|
|
|
1
|
-
import { CancellableLoader, Container, Spacer, Text } from "@earendil-works/pi-tui";
|
|
1
|
+
import { CancellableLoader, Container, Input, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
2
|
+
import { DIALOG_CONTENT_PADDING_X, dialogFrameGeometry, insetDialogContent } from "../../../contracts/presentation/index.js";
|
|
2
3
|
import { DynamicBorder } from "../startup-public.js";
|
|
3
4
|
import { DIALOG_CLOSE_SHORTCUT_HINT, paintPiBorder, piTheme, renderPiModalShortcutHints } from "./theme.js";
|
|
4
|
-
export const PI_MODAL_CONTENT_PADDING_X =
|
|
5
|
+
export const PI_MODAL_CONTENT_PADDING_X = DIALOG_CONTENT_PADDING_X;
|
|
6
|
+
/** Paints the standard Pi Input prompt as a live-themed dialog-search marker. */
|
|
7
|
+
export function renderPiModalSearchInput(input, width) {
|
|
8
|
+
return input.render(width).map(row => {
|
|
9
|
+
if (row.length === 0)
|
|
10
|
+
return row;
|
|
11
|
+
if (!row.startsWith(">"))
|
|
12
|
+
throw new TypeError("modal search input does not use the standard prompt");
|
|
13
|
+
return `${piTheme().fg("accent", ">")}${row.slice(1)}`;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/** Keeps Pi Input behavior and geometry while owning only its standard dialog-search presentation. */
|
|
17
|
+
export class PiModalSearchInput {
|
|
18
|
+
#input;
|
|
19
|
+
constructor(input) {
|
|
20
|
+
this.#input = input;
|
|
21
|
+
}
|
|
22
|
+
get focused() { return this.#input.focused; }
|
|
23
|
+
set focused(value) { this.#input.focused = value; }
|
|
24
|
+
invalidate() { this.#input.invalidate(); }
|
|
25
|
+
render(width) { return renderPiModalSearchInput(this.#input, width); }
|
|
26
|
+
handleMouse(event) { return this.#input.handleMouse(event); }
|
|
27
|
+
}
|
|
28
|
+
/** Replaces one explicitly identified direct Input child with the standard search presentation. */
|
|
29
|
+
export function adoptPiModalSearchInput(container, input) {
|
|
30
|
+
if (!(input instanceof Input))
|
|
31
|
+
throw new TypeError("modal search component is not an Input");
|
|
32
|
+
const index = container.children.indexOf(input);
|
|
33
|
+
if (index === -1)
|
|
34
|
+
throw new TypeError("modal search Input is not a direct child");
|
|
35
|
+
const presentation = new PiModalSearchInput(input);
|
|
36
|
+
container.children.splice(index, 1, presentation);
|
|
37
|
+
return presentation;
|
|
38
|
+
}
|
|
39
|
+
/** Adds one standard dialog-search presentation while callers retain the Input controller. */
|
|
40
|
+
export function addPiModalSearchInput(container, input) {
|
|
41
|
+
const presentation = new PiModalSearchInput(input);
|
|
42
|
+
container.addChild(presentation);
|
|
43
|
+
return presentation;
|
|
44
|
+
}
|
|
5
45
|
/** Adds the standard navigation/select/close footer before a dependency component's bottom rule. */
|
|
6
46
|
export function addPiModalSelectFooter(container) {
|
|
7
47
|
container.children.splice(container.children.length - 1, 0, new Text(renderPiModalShortcutHints([
|
|
@@ -67,21 +107,20 @@ export class PiModalFrame {
|
|
|
67
107
|
this.#bottomRule.invalidate();
|
|
68
108
|
}
|
|
69
109
|
render(width) {
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const rows = [...this.#topRule.render(width)];
|
|
110
|
+
const geometry = dialogFrameGeometry(width);
|
|
111
|
+
const rows = [...this.#topRule.render(geometry.frameWidth)];
|
|
73
112
|
for (const component of this.#content) {
|
|
74
113
|
if (this.#fullWidthContent.has(component) || this.#preInsetContent.has(component)) {
|
|
75
|
-
rows.push(...component.render(
|
|
114
|
+
rows.push(...component.render(geometry.frameWidth));
|
|
76
115
|
}
|
|
77
116
|
else if (component instanceof Spacer) {
|
|
78
|
-
rows.push(...component.render(contentWidth));
|
|
117
|
+
rows.push(...component.render(geometry.contentWidth));
|
|
79
118
|
}
|
|
80
119
|
else {
|
|
81
|
-
rows.push(...component.render(contentWidth).map(row =>
|
|
120
|
+
rows.push(...component.render(geometry.contentWidth).map(row => insetDialogContent(row, geometry)));
|
|
82
121
|
}
|
|
83
122
|
}
|
|
84
|
-
rows.push(...this.#bottomRule.render(
|
|
123
|
+
rows.push(...this.#bottomRule.render(geometry.frameWidth));
|
|
85
124
|
return rows;
|
|
86
125
|
}
|
|
87
126
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Input, getKeybindings, matchesKey, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { DynamicBorder } from "../startup-public.js";
|
|
3
|
-
import { PiModalFrame } from "./modal-frame.js";
|
|
3
|
+
import { PiModalFrame, renderPiModalSearchInput } from "./modal-frame.js";
|
|
4
4
|
import { DIALOG_CLOSE_SHORTCUT_HINT, paintPiBorder, piTheme, renderPiModalListRow, renderPiModalShortcutHints, } from "./theme.js";
|
|
5
5
|
function renderHintsWithClose(entries, width) {
|
|
6
6
|
const body = renderPiModalShortcutHints(entries.slice(0, -1));
|
|
@@ -13,7 +13,6 @@ function renderHintsWithClose(entries, width) {
|
|
|
13
13
|
}
|
|
14
14
|
const MAX_VISIBLE_ROWS = 10;
|
|
15
15
|
const MODELS_TITLE = "Models";
|
|
16
|
-
const REFRESHING_TITLE_MIN_DURATION_MS = 1_000;
|
|
17
16
|
class ModalTitleLine {
|
|
18
17
|
#text = "";
|
|
19
18
|
setText(text) { this.#text = text; }
|
|
@@ -60,9 +59,6 @@ export class ModelsDialogComponent {
|
|
|
60
59
|
#selectedIndex = 0;
|
|
61
60
|
#preferredId;
|
|
62
61
|
#refreshStatus;
|
|
63
|
-
#refreshing = false;
|
|
64
|
-
#refreshStartedAt;
|
|
65
|
-
#refreshOutcomeTimer;
|
|
66
62
|
#disposed = false;
|
|
67
63
|
#focused = false;
|
|
68
64
|
constructor(config, callbacks) {
|
|
@@ -71,10 +67,6 @@ export class ModelsDialogComponent {
|
|
|
71
67
|
this.#scopeIds = [...config.scopeIds];
|
|
72
68
|
this.#savedScopeIds = [...config.savedScopeIds];
|
|
73
69
|
this.#filter = config.initialFilter ?? "all";
|
|
74
|
-
if (config.refreshStatus !== undefined) {
|
|
75
|
-
this.#refreshing = true;
|
|
76
|
-
this.#refreshStartedAt = Date.now();
|
|
77
|
-
}
|
|
78
70
|
if (config.initialQuery)
|
|
79
71
|
this.#input.setValue(config.initialQuery);
|
|
80
72
|
this.#replaceModels(config.models);
|
|
@@ -114,38 +106,10 @@ export class ModelsDialogComponent {
|
|
|
114
106
|
setRefreshStatus(message, kind) {
|
|
115
107
|
if (this.#disposed)
|
|
116
108
|
return;
|
|
117
|
-
|
|
118
|
-
this.#clearRefreshOutcome();
|
|
119
|
-
this.#refreshStatus = undefined;
|
|
120
|
-
this.#refreshing = true;
|
|
121
|
-
this.#refreshStartedAt = Date.now();
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
const visibleMs = this.#refreshStartedAt === undefined ? REFRESHING_TITLE_MIN_DURATION_MS : Date.now() - this.#refreshStartedAt;
|
|
125
|
-
const remainingMs = Math.max(0, REFRESHING_TITLE_MIN_DURATION_MS - visibleMs);
|
|
126
|
-
if (this.#refreshing && remainingMs > 0) {
|
|
127
|
-
this.#clearRefreshOutcome();
|
|
128
|
-
const timer = setTimeout(() => {
|
|
129
|
-
if (this.#refreshOutcomeTimer !== timer)
|
|
130
|
-
return;
|
|
131
|
-
this.#refreshOutcomeTimer = undefined;
|
|
132
|
-
if (this.#disposed)
|
|
133
|
-
return;
|
|
134
|
-
this.#applyRefreshOutcome(message, kind);
|
|
135
|
-
this.#callbacks.requestRender();
|
|
136
|
-
}, remainingMs);
|
|
137
|
-
timer.unref?.();
|
|
138
|
-
this.#refreshOutcomeTimer = timer;
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
this.#clearRefreshOutcome();
|
|
142
|
-
this.#applyRefreshOutcome(message, kind);
|
|
109
|
+
this.#refreshStatus = kind === "warning" ? { message, kind } : undefined;
|
|
143
110
|
}
|
|
144
111
|
dispose() {
|
|
145
112
|
this.#disposed = true;
|
|
146
|
-
this.#clearRefreshOutcome();
|
|
147
|
-
this.#refreshing = false;
|
|
148
|
-
this.#refreshStartedAt = undefined;
|
|
149
113
|
}
|
|
150
114
|
invalidate() {
|
|
151
115
|
this.#input.invalidate();
|
|
@@ -235,21 +199,9 @@ export class ModelsDialogComponent {
|
|
|
235
199
|
render(width) {
|
|
236
200
|
const theme = piTheme();
|
|
237
201
|
this.#title.setText(theme.fg("accent", theme.bold(MODELS_TITLE))
|
|
238
|
-
+ (this.dirty ? theme.fg("warning", " (unsaved)") : "")
|
|
239
|
-
+ (this.#refreshing ? theme.fg("muted", " (refreshing)") : ""));
|
|
202
|
+
+ (this.dirty ? theme.fg("warning", " (unsaved)") : ""));
|
|
240
203
|
return this.#frame.render(width);
|
|
241
204
|
}
|
|
242
|
-
#applyRefreshOutcome(message, kind) {
|
|
243
|
-
this.#refreshing = false;
|
|
244
|
-
this.#refreshStartedAt = undefined;
|
|
245
|
-
this.#refreshStatus = kind === "warning" ? { message, kind } : undefined;
|
|
246
|
-
}
|
|
247
|
-
#clearRefreshOutcome() {
|
|
248
|
-
if (this.#refreshOutcomeTimer === undefined)
|
|
249
|
-
return;
|
|
250
|
-
clearTimeout(this.#refreshOutcomeTimer);
|
|
251
|
-
this.#refreshOutcomeTimer = undefined;
|
|
252
|
-
}
|
|
253
205
|
#renderBody(width) {
|
|
254
206
|
const theme = piTheme();
|
|
255
207
|
const lines = [];
|
|
@@ -261,7 +213,7 @@ export class ModelsDialogComponent {
|
|
|
261
213
|
+ theme.fg("dim", " | ")
|
|
262
214
|
+ theme.fg(this.#filter === "scoped" ? "mdHeading" : "dim", "scoped"));
|
|
263
215
|
push();
|
|
264
|
-
for (const line of this.#input
|
|
216
|
+
for (const line of renderPiModalSearchInput(this.#input, width))
|
|
265
217
|
push(line);
|
|
266
218
|
push();
|
|
267
219
|
if (rows.length === 0) {
|
|
@@ -51,6 +51,8 @@ export interface PromptSelectionUxOptions {
|
|
|
51
51
|
readonly beginClipboardPaste?: () => PiShellPasteReservation;
|
|
52
52
|
readonly beginTextPaste?: (text: string) => PiShellPasteReservation;
|
|
53
53
|
readonly deferTextPaste?: (text: string) => boolean;
|
|
54
|
+
/** False consumes every paste transport without changing editor text. */
|
|
55
|
+
readonly pasteEnabled?: boolean;
|
|
54
56
|
readonly onPasteRejected?: (error: unknown) => void;
|
|
55
57
|
readonly onPasteInput?: (bytes: number, phase: "framing" | "inserting" | "settled") => void;
|
|
56
58
|
readonly transformPastedContent: (content: PiShellClipboardContent) => string;
|
|
@@ -72,5 +74,6 @@ export interface PromptSelectionUxOptions {
|
|
|
72
74
|
};
|
|
73
75
|
}
|
|
74
76
|
export declare function createPromptSelectionInterceptor(editor: Editor, keybindings: KeybindingsManager, options: PromptSelectionUxOptions): OwnedEditorUxInterceptor;
|
|
77
|
+
export declare function editorInsertedText(data: string): string | undefined;
|
|
75
78
|
/** Shares the existing atomic-aware body layout with prompt/menu composition. */
|
|
76
79
|
export declare function editorVisualLineCount(editor: Editor, width: number): number | undefined;
|