@timurproko/a1 0.1.8-dev.469 → 0.1.8-dev.472
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/integrations/pi/session-ui/response-copy-transport.js +8 -4
- package/dist/integrations/pi/session-ui/session-shell-root.d.ts +9 -0
- package/dist/integrations/pi/session-ui/session-shell.js +17 -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/docs/architecture/response-copy-delivery.md +1 -1
- package/docs/local-worktree-cleanup.md +1 -1
- package/package.json +1 -1
|
@@ -93,17 +93,21 @@ function startHelper(snapshot, mode, controlLimit, phase, helper) {
|
|
|
93
93
|
let prepared = [], preparedBytes = 0, expectedBytes;
|
|
94
94
|
const observedPhases = new Set();
|
|
95
95
|
let cleanup;
|
|
96
|
-
const
|
|
96
|
+
const stop = (discard) => {
|
|
97
97
|
if (stopping)
|
|
98
98
|
return;
|
|
99
99
|
stopping = true;
|
|
100
|
-
|
|
100
|
+
if (discard)
|
|
101
|
+
prepared = [];
|
|
101
102
|
iterator = undefined;
|
|
102
103
|
child.kill("SIGKILL");
|
|
103
104
|
// Concurrency: a kernel-stuck child is quarantined by the coordinator, not allowed to pin UI shutdown.
|
|
104
105
|
cleanup = setTimeout(() => { child.unref(); child.channel?.unref(); }, COPY_CLEANUP_MS);
|
|
105
106
|
cleanup.unref();
|
|
106
107
|
};
|
|
108
|
+
const cancel = () => stop(true);
|
|
109
|
+
// Invariant: reaping keeps a complete result's prepared text; discarding it would write "" to the clipboard.
|
|
110
|
+
const reap = () => stop(false);
|
|
107
111
|
const result = new Promise(resolve => {
|
|
108
112
|
let settled = false;
|
|
109
113
|
const settle = () => {
|
|
@@ -160,8 +164,8 @@ function startHelper(snapshot, mode, controlLimit, phase, helper) {
|
|
|
160
164
|
else if (message?.kind === "result" && ["delivered", "submitted-unverified", "failed"].includes(message.result?.outcome)) {
|
|
161
165
|
outcome = message;
|
|
162
166
|
iterator = undefined;
|
|
163
|
-
// Concurrency: a result is not an exit fence
|
|
164
|
-
cleanup = setTimeout(
|
|
167
|
+
// Concurrency: a result is not an exit fence; bound a helper that sends a result but never exits.
|
|
168
|
+
cleanup = setTimeout(reap, COPY_CLEANUP_MS);
|
|
165
169
|
cleanup.unref();
|
|
166
170
|
}
|
|
167
171
|
else
|
|
@@ -72,6 +72,15 @@ export interface OwnedUiSessionShellOptions {
|
|
|
72
72
|
readonly intervalMs?: number;
|
|
73
73
|
readonly scheduler?: StreamPresentationScheduler;
|
|
74
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Minimum time the reload box stays visible so a fast reload still reads as one.
|
|
77
|
+
* Production uses the default hold; tests inject `now`/`sleep` for determinism.
|
|
78
|
+
*/
|
|
79
|
+
readonly reloadPresentation?: {
|
|
80
|
+
readonly minVisibleMs?: number;
|
|
81
|
+
readonly now?: () => number;
|
|
82
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
83
|
+
};
|
|
75
84
|
/** Optional deterministic seam for keyboard scheduling and phase evidence. */
|
|
76
85
|
readonly promptSuggestions?: {
|
|
77
86
|
readonly diagnostics?: SuggestionDiagnosticObserver;
|
|
@@ -56,6 +56,7 @@ export class OwnedUiSessionShell {
|
|
|
56
56
|
#unbindClipboardWriter;
|
|
57
57
|
#damageTerminal;
|
|
58
58
|
#quitOutro;
|
|
59
|
+
#reloadPresentation;
|
|
59
60
|
#streamPresentation;
|
|
60
61
|
#removeViewportPreInput;
|
|
61
62
|
#unsubscribeSettings;
|
|
@@ -251,6 +252,7 @@ export class OwnedUiSessionShell {
|
|
|
251
252
|
this.runtime = runtime;
|
|
252
253
|
this.#damageTerminal = damageTerminal ?? null;
|
|
253
254
|
this.#quitOutro = options.quitOutro;
|
|
255
|
+
this.#reloadPresentation = options.reloadPresentation;
|
|
254
256
|
const presentationInterval = options.streamPresentation?.intervalMs ?? STREAM_PRESENTATION_INTERVAL_MS;
|
|
255
257
|
streamPresentation = options.streamPresentation?.scheduler === undefined
|
|
256
258
|
? new StreamPresentationCoalescer(() => this.runtime.requestRender(), presentationInterval)
|
|
@@ -1153,6 +1155,8 @@ export class OwnedUiSessionShell {
|
|
|
1153
1155
|
}, "Creating gist...")
|
|
1154
1156
|
: undefined;
|
|
1155
1157
|
const operationSurface = shareSurface ?? (request.command === "reload" ? createPiShellReloadBox() : undefined);
|
|
1158
|
+
const now = this.#reloadPresentation?.now ?? Date.now;
|
|
1159
|
+
const shownAt = now();
|
|
1156
1160
|
if (operationSurface) {
|
|
1157
1161
|
this.root.setInputSurface(operationSurface);
|
|
1158
1162
|
this.runtime.requestRender();
|
|
@@ -1163,6 +1167,10 @@ export class OwnedUiSessionShell {
|
|
|
1163
1167
|
}
|
|
1164
1168
|
finally {
|
|
1165
1169
|
if (operationSurface) {
|
|
1170
|
+
// Rationale: a near-instant reload would flash the box for a frame or skip it entirely; holding it
|
|
1171
|
+
// briefly keeps the reload legible regardless of how fast the resources actually load.
|
|
1172
|
+
if (request.command === "reload")
|
|
1173
|
+
await this.#holdReloadSurface(now() - shownAt);
|
|
1166
1174
|
this.root.setInputSurface(null);
|
|
1167
1175
|
this.runtime.requestRender();
|
|
1168
1176
|
}
|
|
@@ -1207,6 +1215,14 @@ export class OwnedUiSessionShell {
|
|
|
1207
1215
|
this.runtime.requestRender();
|
|
1208
1216
|
return workflowAdapterResult(result);
|
|
1209
1217
|
}
|
|
1218
|
+
async #holdReloadSurface(visibleMs) {
|
|
1219
|
+
const minVisibleMs = this.#reloadPresentation?.minVisibleMs ?? RELOAD_SURFACE_MIN_VISIBLE_MS;
|
|
1220
|
+
const remaining = minVisibleMs - visibleMs;
|
|
1221
|
+
if (remaining <= 0 || this.#disposed)
|
|
1222
|
+
return;
|
|
1223
|
+
const sleep = this.#reloadPresentation?.sleep ?? ((ms) => new Promise(resolve => setTimeout(resolve, ms)));
|
|
1224
|
+
await sleep(remaining);
|
|
1225
|
+
}
|
|
1210
1226
|
showTrustSelector() {
|
|
1211
1227
|
const context = this.backend.pinnedProjectTrustContext();
|
|
1212
1228
|
const close = () => {
|
|
@@ -1853,6 +1869,7 @@ function workflowAdapterResult(result) {
|
|
|
1853
1869
|
}
|
|
1854
1870
|
const INTERRUPT = "\u0003";
|
|
1855
1871
|
const INTERRUPT_CHORD_MS = 1_500;
|
|
1872
|
+
const RELOAD_SURFACE_MIN_VISIBLE_MS = 400;
|
|
1856
1873
|
function isWorkflowRoute(value) {
|
|
1857
1874
|
return PINNED_PI_WORKFLOW_COMMAND_NAMES.includes(value)
|
|
1858
1875
|
|| PINNED_PI_HIDDEN_COMMAND_NAMES.includes(value);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "darwin",
|
|
6
6
|
"architecture": "arm64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-18T06:59:11.094Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "9db1726bbe3fc2e8292f2ead1e7e9d0fd4d7d0dc9217b372582bf354b0f565dc",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "linux",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-18T06:59:16.149Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "d8cda6b0c7cb36c0cc41e90802aceebf6c02eaebbc08a83d7d963d2e918dbd7a",
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
"platform": "win32",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-09-
|
|
8
|
+
"builtAt": "2026-09-18T07:00:04.002Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian.exe",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "fe38413d952c311619532245f5fad4fef8461e7f23f4c0d3b3d72326f2516e56",
|
|
12
12
|
"size": 177664
|
|
13
13
|
},
|
|
14
14
|
"provenance": {
|
|
Binary file
|
|
@@ -19,7 +19,7 @@ A generated probe on Windows Node 24.16.0 copied the same eight-character range
|
|
|
19
19
|
- Copy: 5-second admission deadline, one executing request and one newest pending request, at most 16 MiB UTF-8 text. Source snapshots retain only selected rows, capped at 65,536 rows and 32 Mi UTF-16 code units; they do not keep an obsolete whole-transcript graph.
|
|
20
20
|
- Paste: eight distinct admitted requests, a 5-second acquisition budget including the captured write wait, and a 15-second deadline through insertion. A canceled executor counts against capacity until its stop fence. Image conversion has one process-wide slot. Copy supersession is deliberately not used for paste edits.
|
|
21
21
|
- Text transfer: 16 MiB UTF-8 cap; IPC fragments are at most 16,384 code units and preserve surrogate pairs. The receiver acknowledges each fragment. Prepared large text is stored behind the existing compact chip rather than inserted as millions of editor characters. Existing source-image, pixel, encoded-output and attachment-count limits remain unchanged.
|
|
22
|
-
- Clipboard executors have a 250 ms stop grace. POSIX command fallbacks share the paste helper's isolated process group; strict command reads use a forceful kill signal. Unconfirmed executor termination retains its capacity instead of allowing unbounded replacements or late A1-controlled writes. No helper inherits the UI terminal or places clipboard payloads in argv, temporary files, or logs.
|
|
22
|
+
- Clipboard executors have a 250 ms stop grace. A helper that has already reported a complete prepared result and lingers past that grace is reaped, not canceled: it is still terminated, but its prepared text is delivered exactly rather than replaced with an empty payload. Only an explicit cancellation, a protocol violation, or an incomplete byte count discards prepared text. POSIX command fallbacks share the paste helper's isolated process group; strict command reads use a forceful kill signal. Unconfirmed executor termination retains its capacity instead of allowing unbounded replacements or late A1-controlled writes. No helper inherits the UI terminal or places clipboard payloads in argv, temporary files, or logs.
|
|
23
23
|
- Local copy prefers native delivery outside the terminal. OSC 52 uses the existing writer only on a non-blocking supported output route and is capped at a complete 64 KiB control, or a lower advertised limit. Submission is not clipboard acknowledgment. Remote/multiplexed sessions never silently read or write a different host's clipboard. Native Ctrl+V acquisition is unavailable when only the remote terminal owns the desired clipboard; normal terminal-provided paste remains supported.
|
|
24
24
|
- URL-chip decoration: at most 65,536 UTF-8 bytes of added OSC 8 metadata per editor render pass across rows and repeated occurrences, including opening/closing pairs and cleanup closes. Targets that do not fit are omitted whole before control construction; a UTF-16 length precheck avoids scanning huge backing values. The budget resets each pass. Full chip data, atomic editing and exact copy/history/submission expansion remain intact; ordinary in-budget links retain their targets. Terminal automatic URL recognition is separate from explicit metadata.
|
|
25
25
|
- Path-list presentation: the isolated classifier budgets 4,096 UTF-16 units per paste for existing individual tags plus 20 suffix-reserve units per occurrence. Over-budget lists use one existing text-paste chip backed by all classified full paths concatenated in order, including repetitions, without extra separators or re-normalization. No individual members are adopted into the UI before compaction. Small lists retain their file/folder/image-file chips; failed/timed-out classification retains the existing original-text fallback. Existing draft/history chips and the synchronous compatibility classifier are unchanged.
|
|
@@ -207,4 +207,4 @@ Dependency-free focused fixtures (temporary repositories only, no live PR mutati
|
|
|
207
207
|
node --test test/repository-governance/local-cleanup.node.mjs test/repository-governance/local-cleanup-evidence.node.mjs test/repository-governance/local-cleanup-watch.node.mjs
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
-
The Vitest bridge includes these fixtures in ordinary fast CI, whose runner is Windows. On Windows the suite exercises an actual exclusive file handle and a junction; a non-Windows run explicitly skips the Windows-only handle case rather than claiming it passed. Required current-head CI and a separately authorized live archive lifecycle remain necessary before acceptance; fixtures and preview do not replace those gates.
|
|
210
|
+
The Vitest bridge includes these fixtures in ordinary fast CI, whose runner is Windows. On Windows the suite exercises an actual exclusive file handle and a junction; a non-Windows run explicitly skips the Windows-only handle case rather than claiming it passed. The handle fixture starts one throwaway `powershell.exe` when the file loads so the hosted runner's interpreter cold start overlaps the earlier tests instead of the fixture's timed hold; its bounds and release protocol are unchanged. Required current-head CI and a separately authorized live archive lifecycle remain necessary before acceptance; fixtures and preview do not replace those gates.
|
package/package.json
CHANGED