@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.
@@ -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 cancel = () => {
96
+ const stop = (discard) => {
97
97
  if (stopping)
98
98
  return;
99
99
  stopping = true;
100
- prepared = [];
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. Bound a malformed helper that sends a result but never exits.
164
- cleanup = setTimeout(cancel, COPY_CLEANUP_MS);
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-18T05:51:31.871Z",
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-18T05:51:15.837Z",
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-18T05:51:47.497Z",
8
+ "builtAt": "2026-09-18T07:00:04.002Z",
9
9
  "artifact": {
10
10
  "filename": "process-guardian.exe",
11
- "sha256": "80d650d76e86b74f88dd08eda58f6be203642bc46fcaf1f67e11176fa8392da1",
11
+ "sha256": "fe38413d952c311619532245f5fad4fef8461e7f23f4c0d3b3d72326f2516e56",
12
12
  "size": 177664
13
13
  },
14
14
  "provenance": {
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timurproko/a1",
3
- "version": "0.1.8-dev.469",
3
+ "version": "0.1.8-dev.472",
4
4
  "description": "Standalone terminal workspace for supervised native and managed agents",
5
5
  "type": "module",
6
6
  "privateLaunchContract": "neutral-launch-v1",