@timurproko/a1 0.2.7-dev.808 → 0.2.7-dev.810

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.
Files changed (141) hide show
  1. package/README.md +4 -2
  2. package/dist/app/session-shell/dialog-coordinator.d.ts +42 -0
  3. package/dist/app/session-shell/dialog-coordinator.js +133 -0
  4. package/dist/app/session-shell/dock-chrome.d.ts +34 -0
  5. package/dist/app/session-shell/dock-chrome.js +109 -0
  6. package/dist/app/session-shell/exit-notice.d.ts +1 -1
  7. package/dist/app/session-shell/exit-notice.js +1 -1
  8. package/dist/app/session-shell/extension-surface.d.ts +30 -0
  9. package/dist/app/session-shell/extension-surface.js +105 -0
  10. package/dist/app/session-shell/input-surface-switch.d.ts +36 -0
  11. package/dist/app/session-shell/input-surface-switch.js +85 -0
  12. package/dist/app/session-shell/login-interaction.d.ts +27 -0
  13. package/dist/app/session-shell/login-interaction.js +91 -0
  14. package/dist/app/session-shell/prompt-submission.d.ts +48 -0
  15. package/dist/app/session-shell/prompt-submission.js +276 -0
  16. package/dist/app/session-shell/resident-tab-coordinator.d.ts +41 -0
  17. package/dist/app/session-shell/resident-tab-coordinator.js +120 -0
  18. package/dist/app/session-shell/response-copy-transport.d.ts +13 -0
  19. package/dist/app/session-shell/response-copy-transport.js +16 -7
  20. package/dist/app/session-shell/session-concern.d.ts +22 -0
  21. package/dist/app/session-shell/session-concern.js +29 -0
  22. package/dist/app/session-shell/session-lifecycle.d.ts +29 -0
  23. package/dist/app/session-shell/session-lifecycle.js +49 -0
  24. package/dist/app/session-shell/session-shell-root.d.ts +1 -1
  25. package/dist/app/session-shell/session-shell-root.js +182 -931
  26. package/dist/app/session-shell/session-shell.d.ts +2 -8
  27. package/dist/app/session-shell/session-shell.js +202 -901
  28. package/dist/app/session-shell/settings-bindings.d.ts +17 -0
  29. package/dist/app/session-shell/settings-bindings.js +91 -0
  30. package/dist/app/session-shell/shell-editor-factory.d.ts +27 -0
  31. package/dist/app/session-shell/shell-editor-factory.js +102 -0
  32. package/dist/app/session-shell/shell-host.d.ts +6 -0
  33. package/dist/app/session-shell/shell-host.js +8 -0
  34. package/dist/app/session-shell/shell-layout.d.ts +64 -0
  35. package/dist/app/session-shell/shell-layout.js +18 -0
  36. package/dist/app/session-shell/suggestion-surface.d.ts +25 -0
  37. package/dist/app/session-shell/suggestion-surface.js +63 -0
  38. package/dist/app/session-shell/transcript-document.d.ts +78 -0
  39. package/dist/app/session-shell/transcript-document.js +365 -0
  40. package/dist/app/session-shell/viewport-layout.d.ts +31 -0
  41. package/dist/app/session-shell/viewport-layout.js +160 -0
  42. package/dist/app/session-shell/workflow-output.d.ts +33 -0
  43. package/dist/app/session-shell/workflow-output.js +174 -0
  44. package/dist/app/session-shell/workflow-router.d.ts +25 -0
  45. package/dist/app/session-shell/workflow-router.js +39 -0
  46. package/dist/composition/owned-ui.d.ts +4 -25
  47. package/dist/composition/owned-ui.js +26 -270
  48. package/dist/composition/resident-tab-bridge.d.ts +16 -0
  49. package/dist/composition/resident-tab-bridge.js +159 -0
  50. package/dist/composition/session-backend.d.ts +19 -0
  51. package/dist/composition/session-backend.js +1 -0
  52. package/dist/composition/session-runtime-registry.d.ts +20 -0
  53. package/dist/composition/session-runtime-registry.js +85 -0
  54. package/dist/composition/startup-route.d.ts +32 -0
  55. package/dist/composition/startup-route.js +72 -0
  56. package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
  57. package/dist/foundation/release/progress-palette.generated.js +2 -2
  58. package/dist/foundation/startup/startup-descriptor.js +2 -2
  59. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
  60. package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
  61. package/dist/integrations/pi/components/shell-extension-ui.js +79 -60
  62. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
  63. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
  64. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  65. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  66. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  67. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  68. package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
  69. package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
  70. package/dist/integrations/pi/components/upstream/components/extension-selector.js +1 -1
  71. package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
  72. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
  73. package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
  74. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  75. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
  76. package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
  77. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  78. package/dist/integrations/pi/components/upstream/components/session-selector.js +1 -1
  79. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
  80. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
  81. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
  82. package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
  83. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  84. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  85. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
  86. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
  87. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +2 -4
  88. package/dist/integrations/pi/components/upstream/components/tool-execution.js +77 -98
  89. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
  90. package/dist/integrations/pi/components/upstream/components/tree-selector.js +1 -1
  91. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  92. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  93. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
  94. package/dist/integrations/pi/components/upstream/history/editor-core.js +1 -1
  95. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  96. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  97. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  98. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  99. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  100. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  101. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  102. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  103. package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
  104. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
  105. package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
  106. package/dist/integrations/pi/engine/adapter.d.ts +4 -77
  107. package/dist/integrations/pi/engine/adapter.js +85 -393
  108. package/dist/integrations/pi/engine/command-dispatch.d.ts +13 -0
  109. package/dist/integrations/pi/engine/command-dispatch.js +57 -0
  110. package/dist/integrations/pi/engine/host.js +2 -2
  111. package/dist/integrations/pi/engine/ports.d.ts +56 -0
  112. package/dist/integrations/pi/engine/ports.js +89 -0
  113. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  114. package/dist/integrations/pi/engine/view-state.d.ts +42 -0
  115. package/dist/integrations/pi/engine/view-state.js +126 -0
  116. package/dist/integrations/pi/startup-public.js +164 -150
  117. package/dist/integrations/pi/startup-public.manifest.json +351 -310
  118. package/dist/integrations/pi/tui-runtime/adapter.js +4 -0
  119. package/dist/integrations/pi/tui-runtime/contracts.d.ts +5 -0
  120. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
  121. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
  122. package/dist/native/darwin-arm64/manifest.json +1 -1
  123. package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
  124. package/dist/native/darwin-arm64/terminal-host.node +0 -0
  125. package/dist/native/darwin-x64/manifest.json +1 -1
  126. package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
  127. package/dist/native/darwin-x64/terminal-host.node +0 -0
  128. package/dist/native/linux-x64/manifest.json +1 -1
  129. package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
  130. package/dist/native/linux-x64/terminal-host.node +0 -0
  131. package/dist/native/win32-x64/manifest.json +2 -2
  132. package/dist/native/win32-x64/process-guardian.node +0 -0
  133. package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
  134. package/dist/native/win32-x64/terminal-host.node +0 -0
  135. package/dist/runtime-payload-inventory.json +5181 -5369
  136. package/dist/ui/components/transcript-viewport.js +10 -19
  137. package/docs/architecture/boundaries.md +14 -0
  138. package/docs/architecture/resident-tabs.md +8 -8
  139. package/docs/architecture/response-copy-delivery.md +1 -1
  140. package/docs/architecture/toolchain.md +2 -2
  141. package/package.json +5 -5
@@ -4,6 +4,10 @@ import { backgroundSgrSpan, overlaySpan } from "./spans.js";
4
4
  import { faint, truncateToWidth, displayWidth, stripAnsi } from "./text.js";
5
5
  import { extendTextSelection, orderedTextSelection, pressTextSelection, releaseTextSelection, textSelectionLineExtendColumn, textSelectionPointAt, textSelectionText, usefulTextLineContent, } from "./text-selection.js";
6
6
  const CONTROL_STYLE_RESET = "\u001b]8;;\u001b\\\u001b[0m";
7
+ // Protocol: upstream OSC 133 zones are layout annotations, not fullscreen cursor commands.
8
+ // Styling/padding can move them away from the row prefix Pi strips; 133;A then advances a real
9
+ // terminal parser to a fresh line. The custom viewport owns prompt anchors separately.
10
+ const VIEWPORT_PROMPT_ZONES = /\u001b\]133;[ABC](?:\u0007|\u001b\\)/gu;
7
11
  // Invariant: scrollbar chrome closes source links and decoration without clearing
8
12
  // the row surface painted beneath its dedicated, non-semantic gutter.
9
13
  const GUTTER_DECORATION_RESET = "\u001b]8;;\u001b\\\u001b[22;23;24;25;27;28;29;39;54;55m";
@@ -362,7 +366,7 @@ export class TranscriptViewport {
362
366
  contentLength: documentRows.length,
363
367
  viewportHeight,
364
368
  scroll: this.#scrollTop,
365
- // Compatibility: the session rail deliberately starts one line below the viewport top.
369
+ // Invariant: the rail keeps its top gap; the shell owns the spacing above the dock.
366
370
  trackHeight: Math.max(0, viewportHeight - 1),
367
371
  });
368
372
  const presentation = scrollbarPresentation({
@@ -504,7 +508,7 @@ export class TranscriptViewport {
504
508
  // Invariant: paint the rail after selection over the gutter's continued row
505
509
  // background. Source content and selection still end at the preceding cell.
506
510
  let railCell = "";
507
- if (row < viewportHeight && presentation.visible && geometry !== null && row > 0) {
511
+ if (row > 0 && row < viewportHeight && presentation.visible && geometry !== null) {
508
512
  const trackRow = row - 1;
509
513
  const thumb = isThumbRow(geometry, trackRow);
510
514
  const glyph = thumb ? presentation.thumbGlyph : presentation.trackGlyph;
@@ -526,7 +530,7 @@ export class TranscriptViewport {
526
530
  return overlayWidth === 0 ? withControl : overlaySpan(padRowPreservingBackground(withControl, width), overlayLimit - overlayWidth, overlayLimit, `${GUTTER_DECORATION_RESET}${overlayText}`, { inheritStartStyle: true });
527
531
  });
528
532
  rowRecomputed ||= !final.reused;
529
- frameRows[row] = final.value;
533
+ frameRows[row] = final.value.replace(VIEWPORT_PROMPT_ZONES, "");
530
534
  (rowRecomputed ? recomputedRows : reusedRows).push(row + 1);
531
535
  const state = `${width}\u0000${row}\u0000${painted}\u0000${rangeKey}\u0000${range === null ? "" : selectionPainterId}\u0000${railCell}\u0000${overlayText}\u0000${rowControl?.text ?? ""}`;
532
536
  visibleStates.push(state);
@@ -627,19 +631,10 @@ export class TranscriptViewport {
627
631
  || !sameRectangle(previous.descriptor.transcript, expectedTranscript))
628
632
  return null;
629
633
  const descriptor = {
634
+ ...previous.descriptor,
630
635
  frameId: ++this.#frameId,
631
- width: boundedWidth,
632
- height: boundedHeight,
633
- transcript: expectedTranscript,
634
- dock: expectedDock,
635
636
  previousDocumentRange: previous.descriptor.nextDocumentRange,
636
- nextDocumentRange: previous.descriptor.nextDocumentRange,
637
637
  previousFollowingEnd: previous.followingEnd,
638
- followingEnd: previous.followingEnd,
639
- transientRowCount: previous.descriptor.transientRowCount,
640
- transientAlignmentGapRows: previous.descriptor.transientAlignmentGapRows,
641
- bottomAlignedTailRowCount: previous.descriptor.bottomAlignedTailRowCount,
642
- liveTailRows: previous.descriptor.liveTailRows,
643
638
  verticalShiftRows: 0,
644
639
  safeVerticalShift: false,
645
640
  selectionRevision: this.#selectionRevision,
@@ -650,12 +645,8 @@ export class TranscriptViewport {
650
645
  this.#selectionRows = [...this.#selectionRows.slice(0, viewportHeight), ...dock].slice(0, boundedHeight);
651
646
  this.#copyableDockRows = copyableDockRowsBySuffix(dockRows, copyableDockRows);
652
647
  const frame = {
653
- rows: [...previous.rows.slice(0, viewportHeight), ...dock].slice(0, boundedHeight),
654
- contentWidth: previous.contentWidth,
655
- scrollTop: previous.scrollTop,
656
- maxScroll: previous.maxScroll,
657
- followingEnd: previous.followingEnd,
658
- hits: previous.hits,
648
+ ...previous,
649
+ rows: [...previous.rows.slice(0, viewportHeight), ...dock.map(row => row.replace(VIEWPORT_PROMPT_ZONES, ""))].slice(0, boundedHeight),
659
650
  descriptor,
660
651
  selectionDamage: {
661
652
  revision: this.#selectionRevision,
@@ -44,6 +44,20 @@ The JavaScript product path has no PTY or terminal-emulator dependency. Reintrod
44
44
 
45
45
  `scripts/governance/check-architecture.mjs` enforces the structural parts of these boundaries. Cross-cutting rationale belongs here; implementation history belongs in Git and archived OpenSpec changes.
46
46
 
47
+ ## Session shell composition
48
+
49
+ The session presenter (`src/app/session-shell/session-shell.ts`) coordinates; it does not own per-concern state. Each concern implements `SessionConcern` (`session-concern.ts`): it resets its own state in `onSessionReplaced` and releases it in `dispose`, and the presenter lists its concerns once, in reset order, in `#createConcerns`. New submission, routing, dialog, login, or resident-tab behavior goes into the concern that owns it, or a new concern added to that list. The render root (`session-shell-root.ts`) likewise picks one `ShellLayout` at construction and delegates transcript caching to `TranscriptDocument`, dock chrome to `DockChrome`, workflow output to `WorkflowOutput`, extension surfaces to `ExtensionSurface`, and the dock's input surface to `InputSurfaceSwitch`. The engine adapter serves the shell through the ports built in `src/integrations/pi/engine/ports.ts`, and the composition root delegates runtime claims, the startup release note, and the resident-tab bridge to their own modules under `src/composition/`.
50
+
51
+ ## Unit size ratchet
52
+
53
+ Module boundaries do not stop one class or function inside a module from absorbing every feature. The architecture gate therefore measures every production TypeScript class under `src/` (methods and fields) and every TypeScript or Rust function under `src/` and `native/<crate>/src/` (inclusive lines), excluding vendored sources and Rust `#[cfg(test)]` code. A unit with more than 20 methods, 15 fields, or 100 function lines must be recorded in `config/baselines/size-ratchet.json`, and its recorded counts can only shrink:
54
+
55
+ - A recorded count that grows fails the gate. Split the unit instead. If growth is truly unavoidable, raise the entry by hand in the same pull request and say why in its description, so the growth is reviewed rather than silent.
56
+ - An unrecorded unit over a threshold fails the gate; split it before it lands.
57
+ - A count that shrinks, or a unit that falls below every threshold, fails until `node scripts/governance/update-size-ratchet.mjs` lowers or removes the entry. That script never adds or raises an entry; `--check` reports without writing.
58
+
59
+ The measurement in `scripts/governance/size-ratchet-policy.mjs` masks strings, comments, and regular expressions and counts braces, so it needs no build; a file whose braces do not balance is reported rather than mismeasured. Keys are `<path>::<Class>`, `<path>::<Class>.<method>`, or `<path>::<Type>::<fn>`, so moving or renaming a unit means moving its entry.
60
+
47
61
  ## Multi-session limits of the pinned engine
48
62
 
49
63
  The engine host removes A1's own obstacles to several Pi sessions in one process, but three remain in the pinned Pi SDK and must be planned around, not discovered:
@@ -64,7 +64,7 @@ The read-only review used A1 `develop` at `b42b3c9e`, PR #586 at `8fdb7361`, `E:
64
64
 
65
65
  ### Milestone 3 failure-isolation contract (2026-10-14)
66
66
 
67
- - The native `core/server.rs` and `core/holder.rs` state machines are deterministic and I/O-free; the production holder uses the holder core for bounded input admission and ordered writer effects, and the production server uses the server core for heartbeat supervision. Blocking identity/termination work runs through the bounded worker shell with deadlines and stale-incarnation filtering.
67
+ - The native `core/server.rs`, `core/holder.rs`, and `core/attach/` state machines are deterministic and I/O-free; the production holder uses the holder core for bounded input admission and ordered writer effects, the production server uses the server core for heartbeat supervision, and the attach client steps the attach core for every interaction mode (popup, rename, drag), shortcut, deferred input, and server answer while `roles/attach.rs` keeps the connection, outer terminal, encoders, and presentation. Blocking identity/termination work runs through the bounded worker shell with deadlines and stale-incarnation filtering.
68
68
  - Every attach, server, and holder role has an independent 15-second watchdog. Watchdog records are bounded, timestamped, owner-only metadata under the profile runtime directory; fault-only role freezes are refused by non-test release builds.
69
69
  - Holders read PTY output continuously, use one bounded input authority, reserve complete pastes before delivery, and emit a typed uncertain-delivery result after an admitted write failure. Each holder independently refreshes the server's latest complete retained surface even while hidden. Server-to-client control lanes are frame/byte bounded, render lanes retain one replaceable full current surface, and only the viewed tab is delivered to each attach client.
70
70
  - Server replacement is serialized by `server-start.lock` in the profile runtime directory. Recovery verifies the recorded native owner before termination, waits boundedly for the registry-writer lease, increments the durable epoch, derives holder credentials, and re-admits only exact holder/child identities and incarnations. A durable three-start/sixty-second budget stops automatic replacement; explicit `--restart` clears it.
@@ -229,7 +229,7 @@ The channels carry bounded generation-1 frames: a u32 little-endian length follo
229
229
 
230
230
  ### 6. Rendering, input, and outer-terminal fidelity
231
231
 
232
- - **Composition.** The attach client composes row 0 (the strip) and rows `1..N` (the viewed tab's surface). The tab PTY is sized `cols × (rows − 1)`. Ghostty remains the sole child-terminal parser. Its stream parser reports synchronized-output begin/end/reset boundaries to the holder, which keeps mutable parser state separate from an immutable committed surface and never publishes an open transaction. A non-renewable 250 ms deadline publishes one typed recovery commit for a malformed transaction. The outer composer owns the only synchronized envelope and falls back to a full repaint only when identity, geometry generation, dimensions, or the structured base changes.
232
+ - **Composition.** The attach client composes row 0 (the strip) and rows `1..N` (the viewed tab's surface). The tab PTY is sized `cols × (rows − 1)`. Ghostty remains the sole child-terminal parser. Its stream parser reports synchronized-output begin/end/reset boundaries to the holder, which keeps mutable parser state separate from an immutable committed surface and never publishes an open transaction. A non-renewable 250 ms deadline publishes one typed recovery commit for a malformed transaction. On Windows, ConPTY re-renders the child's cells on its own schedule and relays the DEC 2026 markers when it parses them, so a render pass can land between a frame's markers and the rest of its cells can arrive after the end marker; the holder therefore treats a relayed end marker as "frame parsed", keeps the state private until the following render pass has arrived and settled for 2 ms, and publishes anyway after a 40 ms bound. A begin marker that arrives while that pass is still pending does not publish the torn state. Unix PTYs relay bytes verbatim, so their markers still delimit frames exactly. The outer composer owns the only synchronized envelope and falls back to a full repaint only when identity, geometry generation, dimensions, or the structured base changes.
233
233
  - **Outer modes.** The client negotiates the outer terminal's modes: raw mode, alternate screen, bracketed paste, focus events, SGR mouse, kitty keyboard protocol where available, and synchronized output.
234
234
  - Child-requested modes are tracked in the holder's model. Input is re-encoded per child mode by libghostty-vt, which the proof already does.
235
235
  - Mouse rows are offset by the strip. Row 0 belongs to the client.
@@ -395,12 +395,12 @@ Every queue, buffer, file, and collection the resident roles keep has a declared
395
395
  | Structured complete surface | 512 × 256 geometry, 65,536 cells, 4,096 styles, 4,096 links, and 8 MiB decoded state | `protocol.rs` `StructuredSurface::validate` | `structured_surfaces_fail_closed_on_dimensions_indexes_and_control_injection` |
396
396
  | Input per message and holder input queue | 1 MiB | `protocol.rs`, `core/holder.rs`, `roles/holder.rs` | `over_capacity_paste_delivers_no_prefix` |
397
397
  | Holder PTY ingress and work round | 64 × 16 KiB lossless chunks; at most 256 KiB or 2 ms before yielding | `roles/holder.rs` | `verify-resident-parallel-progress.mjs` concurrent and stopped-stage cases |
398
- | Per-client control lane | 1,024 frames and 4 MiB | `roles/server.rs` | `control_lane_is_bounded_by_frames_and_bytes` |
399
- | Per-client render slot | one pending full surface; a newer one replaces it | `roles/server.rs` `Peer::offer_surface` | `stalled_client_gets_one_full_current_surface` |
400
- | Concurrent endpoint connections | 128 | `roles/server.rs` `admit_connection` | `connections_beyond_the_cap_are_refused_and_released_slots_are_reused` |
401
- | Attached viewing clients | 16 | `roles/server.rs` `client_slot_available` | `attached_clients_are_capped` |
398
+ | Per-client control lane | 1,024 frames and 4 MiB | `roles/server/mod.rs` | `control_lane_is_bounded_by_frames_and_bytes` |
399
+ | Per-client render slot | one pending full surface; a newer one replaces it | `roles/server/mod.rs` `Peer::offer_surface` | `stalled_client_gets_one_full_current_surface` |
400
+ | Concurrent endpoint connections | 128 | `roles/server/mod.rs` `admit_connection` | `connections_beyond_the_cap_are_refused_and_released_slots_are_reused` |
401
+ | Attached viewing clients | 16 | `roles/server/mod.rs` `client_slot_available` | `attached_clients_are_capped` |
402
402
  | Concurrent holder starts | default 2, hard 8 | `core/server.rs` | `limits_starts_and_drops_stale_completion` |
403
- | Stopped tab records | 16, oldest dropped first | `roles/server.rs` `prune_stopped_records` | `stopped_records_are_bounded_oldest_first_and_live_tabs_are_kept` |
403
+ | Stopped tab records | 16, oldest dropped first | `roles/server/mod.rs` `prune_stopped_records` | `stopped_records_are_bounded_oldest_first_and_live_tabs_are_kept` |
404
404
  | Prior tab-set archives | bounded history | `roles/registry.rs` | `prior_tab_sets_are_bounded` |
405
405
  | Abandoned blocking workers | 8 | `shell/workers.rs` | `fails_fast_after_eight_abandoned_workers` |
406
406
  | Diagnostic logs | 5 MiB × 3 generations per role | `roles/diagnostics.rs` | `logs_rotate_at_their_cap_and_keep_a_bounded_number_of_generations` |
@@ -458,7 +458,7 @@ The v2 daemon was unreliable for structural reasons, and a forensic pass over it
458
458
  | Synchronous `taskkill` loops blocked the daemon for 30–60 s | Blocking kills on the event loop | Kills run asynchronously and concurrently, with deadlines. The loop keeps answering heartbeats. |
459
459
  | Blocked ConPTY writes stalled the loop, and keystrokes or pastes were silently dropped ("newest wins") | No flow control | A dedicated writer per holder with a bounded queue. Reserve capacity for a complete paste before delivery; reject an over-capacity paste visibly without delivering a prefix. After admission, preserve byte order and report delivery uncertainty if a child or process fails; never silently truncate or retry accepted bytes. |
460
460
  | Terminal queries (DA/DSR/CPR) were answered by the busy shared emulator, so children stalled | One emulator loop for all agents | Each holder answers its own tab's queries from its own model. |
461
- | Repaints arrived in fragments ("ghost frames"), patched with timing heuristics and two screen sources | Emulation reconciled with bridge surfaces by timers | One source of truth, the holder model. Frames are published at synchronized-output boundaries, with a bounded coalescing window. |
461
+ | Repaints arrived in fragments ("ghost frames"), patched with timing heuristics and two screen sources | Emulation reconciled with bridge surfaces by timers | One source of truth, the holder model. Frames are published at synchronized-output boundaries, with a bounded coalescing window; where ConPTY relays those boundaries ahead of the cells it re-renders, publication waits for the render pass instead of the marker. |
462
462
  | A late exit event poisoned the replacement child | Events were not tied to an incarnation | Incarnation IDs on every event. Stale events are discarded. |
463
463
  | Resizes were lost in transit | Edge-triggered resize | Size is desired state, reconciled until observed. |
464
464
  | Restore spawned duplicate agents | No restore gate | A single start gate for crash restarts, at most one start in flight per tab, and conditional revisions. The duplicate-start invariant is checked in simulation. |
@@ -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. 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.
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. Native POSIX copy writers (`wl-copy`, `xclip`, `pbcopy`) start detached in their own process group, as in pinned Pi 1.4, so a writer that daemonizes to keep serving the clipboard is not stopped when Ctrl+Z suspends A1. 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.
@@ -34,9 +34,9 @@ It contains no executable built from A1 sources, separate session-lock addon, br
34
34
 
35
35
  ## Native addon layer
36
36
 
37
- `npm run doctor` reports this contract against the current machine—Node range, npm major, git, the GitHub CLI, Rust/Cargo, and whether `node_modules` matches the lockfile—and names the install command for anything missing. `npm run build` runs the same check as its first step, so an unmet prerequisite fails by name rather than inside a module resolver or Cargo. Unmet tool prerequisites block; a Node or npm version outside the declared contract is reported as an advisory without failing the build.
37
+ `npm run doctor` reports this contract against the current machine—Node range, npm major, git, the GitHub CLI, Rust/Cargo, Windows Microsoft C++ readiness where applicable, and whether `node_modules` matches the lockfile—and names the explicit setup action for anything missing. `npm run build` resolves the same native environment and runs the check before cleaning or compiling, so an unmet prerequisite fails by name rather than inside a module resolver, Cargo, or the linker. Unmet tool prerequisites block; a Node or npm version outside the declared contract is reported as an advisory without failing the build.
38
38
 
39
- Source builds require Rust/Cargo 1.85 or newer; `rust-toolchain.toml` pins the exact version CI and publication install through `scripts/development/prepare-ci-rust.sh`, and rustup selects that version for Cargo commands inside the repository, installing it on first use. The Zig cache (`mlugg/setup-zig`, one entry per workflow and platform per run, bounded to 512 MiB) stays enabled: measured on 2026-10-16, a cold Zig build of `libghostty-vt` added about 40 to 60 seconds to a terminal-host test build (Linux 2m21s cold against 1m20s warm, Windows 2m05s against 1m26s), which the cache saves on every warm run.
39
+ Source builds require Rust/Cargo 1.85 or newer; `rust-toolchain.toml` pins the exact version CI and publication install through `scripts/development/prepare-ci-rust.sh`, and rustup selects that version for Cargo commands inside the repository, installing it on first use. On Windows, the resolver honors explicit `CARGO` and `RUSTC` executables, then the launching `PATH`, then `%USERPROFILE%\.cargo\bin`; the fallback changes only build-child state. Windows native linking also requires Visual Studio or Visual Studio Build Tools with the Desktop development with C++ workload, MSVC x64/x86 tools, and a Windows SDK. Visual Studio Code is not a compiler prerequisite. An already valid developer environment is retained; otherwise the resolver uses the installed stable Visual Studio locator and `vcvars64.bat`, verifies that `cl.exe` and Microsoft's `link.exe` come from the selected VC tools, and passes the captured environment only to child processes. This prevents Git Bash's GNU `link.exe` from shadowing MSVC without changing persistent `PATH`. A1 never installs these tools, elevates privileges, or accepts licenses automatically. The Zig cache (`mlugg/setup-zig`, one entry per workflow and platform per run, bounded to 512 MiB) stays enabled: measured on 2026-10-16, a cold Zig build of `libghostty-vt` added about 40 to 60 seconds to a terminal-host test build (Linux 2m21s cold against 1m20s warm, Windows 2m05s against 1m26s), which the cache saves on every warm run.
40
40
 
41
41
  `npm run build` compiles `native/process-guardian` as the host platform's Node-API 9 addon, places `process-guardian.node` under `dist/native/<platform>-<architecture>/`, loads it to observe its version identity, and writes the v2 integrity manifest. It also builds the current platform's release-profile `terminal-host.node`, whose v2 manifest binds the addon, `dist/foundation/resident-tabs/host-entry.js`, and notices, so the ordinary `npm run build && ./scripts/dev` handoff exercises resident tabs without deployment. On Windows the normal build reuses a compatible ignored terminal-library cache or downloads the newest compatible library from the current branch or a successful CI run belonging to a pull request already merged into `develop`, then links it under the crate's manifest verification; it never silently invokes the quarantined Zig package fetch. An unavailable or mismatched prerequisite fails the build instead of leaving a nominally successful single-agent-only tree. The npm `prepare` lifecycle and validation preflight use the explicit core build because selected native lanes assemble and certify terminal hosts separately.
42
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timurproko/a1",
3
- "version": "0.2.7-dev.808",
3
+ "version": "0.2.7-dev.810",
4
4
  "description": "Standalone terminal workspace for supervised native and managed agents",
5
5
  "type": "module",
6
6
  "privateLaunchContract": "neutral-launch-v1",
@@ -23,8 +23,8 @@
23
23
  },
24
24
  "scripts": {
25
25
  "clean": "node scripts/clean.mjs",
26
- "build": "node scripts/development/check-environment.mjs && npm run build:managed && node scripts/development/prepare-local-terminal-host.mjs && node scripts/release/generate-runtime-payload-inventory.mjs",
27
- "build:core": "node scripts/development/check-environment.mjs && npm run build:managed && node scripts/release/generate-runtime-payload-inventory.mjs",
26
+ "build": "node scripts/development/run-build.mjs",
27
+ "build:core": "node scripts/development/run-build.mjs --core",
28
28
  "build:managed": "npm run clean && tsc -p tsconfig.build.json && node scripts/release/generate-release-notes-resource.mjs && node scripts/pi/build-pi-settings-metadata.mjs && node scripts/pi/build-startup-public.mjs && node scripts/development/build-process-guardian.mjs",
29
29
  "build:process-guardian": "node scripts/development/build-process-guardian.mjs",
30
30
  "build:terminal-host": "node scripts/development/build-terminal-host.mjs",
@@ -72,8 +72,8 @@
72
72
  "typecheck:bin": "tsgo -p tsconfig.bin.json"
73
73
  },
74
74
  "dependencies": {
75
- "@earendil-works/pi-coding-agent": "1.3.0",
76
- "@earendil-works/pi-tui": "1.3.0",
75
+ "@earendil-works/pi-coding-agent": "1.4.0",
76
+ "@earendil-works/pi-tui": "1.4.0",
77
77
  "@silvia-odwyer/photon-node": "0.3.4",
78
78
  "chalk": "5.6.2",
79
79
  "cross-spawn": "7.0.6",