@timurproko/a1 0.1.8-dev.468 → 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/ci-release-runbook.md +1 -0
- 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.
|
|
@@ -250,6 +250,7 @@ Rules that do not bend:
|
|
|
250
250
|
path, and use the confirmed apply mode only for an accepted mutable policy change.
|
|
251
251
|
- **Nightly documentation review fails:** inspect the reported paths and rules, identify the introducing merge from the nightly interval, and repair the invariant before unrelated work proceeds.
|
|
252
252
|
- **Development publication fails:** fix the cause and rerun `npm run develop`; an npm version that already exists is never overwritten.
|
|
253
|
+
- **Registry verification times out:** a `has not propagated` failure after a successful `npm publish` means npm is still ingesting the upload; it warns that a provenance-signed package "may take a few minutes" and the publisher polls for ten minutes. Confirm the version and its shasum on `https://registry.npmjs.org/<name>/<version>`, then rerun the failed jobs: the final registry check finds the exact bytes, skips `npm publish`, and verification passes. A digest or tag mismatch is not a timeout and is never repaired by rerunning.
|
|
253
254
|
- **Stable preparation stops before dispatch:** inspect the reported version PR/worktree. After preserving work, an exact matching pending PR can be observed again. If develop already declares the prepared stable version, use its exact target (for example `npm run release -- 0.1.8`) only after verifying that source's merged PR and confirming the registry/tag guards still permit it. Do not use `patch` from stable develop to retry the same version: that deliberately selects the next patch.
|
|
254
255
|
- **Stable publication fails or is uncertain:** inspect the workflow, registry version/digest, tag, and release before choosing recovery. No reopening PR is prepared. Never republish immutable bytes or move a release tag.
|
|
255
256
|
- **Stable publication succeeded but reopening stops:** the stable version is already published. Inspect and finish the reported next-development PR manually; do not repeat stable publication. If no reopening PR was created, prepare the next-development version through a separately validated manual PR after inspecting remote state.
|
|
@@ -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