@timurproko/a1 0.1.8-dev.157 → 0.1.8-dev.214

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 (171) hide show
  1. package/README.md +32 -0
  2. package/bin/cli.js +2 -2
  3. package/bin/sync-pi-tui-proxy.js +1 -1
  4. package/bin/ui.js +18 -3
  5. package/dist/cli/dispatch.js +3 -3
  6. package/dist/cli/packages.js +1 -1
  7. package/dist/cli/version-stats.js +3 -3
  8. package/dist/composition/owned-ui.d.ts +4 -1
  9. package/dist/composition/owned-ui.js +9 -6
  10. package/dist/composition/settings-route-host.js +6 -4
  11. package/dist/contracts/agent-engine/capability-ports.d.ts +2 -2
  12. package/dist/contracts/agent-engine/domain-validation.js +22 -4
  13. package/dist/contracts/agent-engine/domain.d.ts +17 -0
  14. package/dist/contracts/owned-ui/model.d.ts +8 -0
  15. package/dist/contracts/owned-ui/validation.js +11 -0
  16. package/dist/features/launch/development-launch.js +1 -1
  17. package/dist/features/owned-ui/customization.d.ts +2 -0
  18. package/dist/features/owned-ui/customization.js +2 -0
  19. package/dist/features/owned-ui/diagnostics.d.ts +1 -0
  20. package/dist/features/owned-ui/diagnostics.js +1 -0
  21. package/dist/features/owned-ui/index.d.ts +1 -0
  22. package/dist/features/owned-ui/index.js +1 -0
  23. package/dist/features/owned-ui/project-trust-prompt.d.ts +25 -0
  24. package/dist/features/owned-ui/project-trust-prompt.js +149 -0
  25. package/dist/features/owned-ui/settings-app.js +69 -44
  26. package/dist/features/workspace/reducer.d.ts +1 -0
  27. package/dist/features/workspace/reducer.js +1 -0
  28. package/dist/features/workspace/router.d.ts +1 -0
  29. package/dist/features/workspace/router.js +1 -0
  30. package/dist/features/workspace/store.d.ts +1 -0
  31. package/dist/features/workspace/store.js +1 -0
  32. package/dist/foundation/launch-guardian/main.js +1 -1
  33. package/dist/foundation/native-host-protocol/codec.d.ts +2 -0
  34. package/dist/foundation/native-host-protocol/codec.js +2 -0
  35. package/dist/foundation/process-containment/linux-process-inspector.d.ts +1 -0
  36. package/dist/foundation/process-containment/linux-process-inspector.js +1 -0
  37. package/dist/foundation/process-containment/native-guardian-containment.d.ts +1 -0
  38. package/dist/foundation/process-containment/native-guardian-containment.js +1 -0
  39. package/dist/foundation/process-containment/windows-process-inspector.d.ts +1 -0
  40. package/dist/foundation/process-containment/windows-process-inspector.js +1 -0
  41. package/dist/foundation/protocol/client.d.ts +1 -0
  42. package/dist/foundation/protocol/client.js +1 -0
  43. package/dist/foundation/protocol/messages.d.ts +1 -0
  44. package/dist/foundation/protocol/messages.js +1 -0
  45. package/dist/foundation/release/bootstrap.js +6 -6
  46. package/dist/foundation/release/cohort-state.d.ts +1 -0
  47. package/dist/foundation/release/cohort-state.js +1 -0
  48. package/dist/foundation/release/release-gc.js +1 -1
  49. package/dist/foundation/release/release.js +1 -1
  50. package/dist/foundation/release/update-transaction.d.ts +1 -0
  51. package/dist/foundation/release/update-transaction.js +1 -0
  52. package/dist/foundation/release/update.js +12 -12
  53. package/dist/foundation/storage/control-store.d.ts +1 -0
  54. package/dist/foundation/storage/control-store.js +1 -0
  55. package/dist/foundation/structured-agent-runtime/backpressure.d.ts +1 -0
  56. package/dist/foundation/structured-agent-runtime/backpressure.js +1 -0
  57. package/dist/foundation/structured-agent-runtime/commands.d.ts +1 -0
  58. package/dist/foundation/structured-agent-runtime/commands.js +1 -0
  59. package/dist/foundation/structured-agent-runtime/reconnection.d.ts +1 -0
  60. package/dist/foundation/structured-agent-runtime/reconnection.js +1 -0
  61. package/dist/foundation/structured-agent-runtime/state.d.ts +1 -0
  62. package/dist/foundation/structured-agent-runtime/state.js +1 -0
  63. package/dist/foundation/supervision/main.js +1 -1
  64. package/dist/foundation/supervision/server.d.ts +1 -0
  65. package/dist/foundation/supervision/server.js +4 -6
  66. package/dist/integrations/pi/components/conformance.d.ts +1 -0
  67. package/dist/integrations/pi/components/conformance.js +1 -0
  68. package/dist/integrations/pi/components/shell-components.d.ts +1 -0
  69. package/dist/integrations/pi/components/shell-components.js +1 -0
  70. package/dist/integrations/pi/components/shell-editor-autocomplete.js +10 -0
  71. package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
  72. package/dist/integrations/pi/components/shell-footer-status.js +19 -13
  73. package/dist/integrations/pi/components/shell-presenters-info.d.ts +36 -0
  74. package/dist/integrations/pi/components/shell-presenters-info.js +78 -0
  75. package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +3 -36
  76. package/dist/integrations/pi/components/shell-presenters-transcript.js +88 -128
  77. package/dist/integrations/pi/components/shell-shared-facade.d.ts +11 -1
  78. package/dist/integrations/pi/components/shell-shared-facade.js +1 -1
  79. package/dist/integrations/pi/engine/adapter.d.ts +22 -4
  80. package/dist/integrations/pi/engine/adapter.js +220 -70
  81. package/dist/integrations/pi/engine/conformance.d.ts +2 -0
  82. package/dist/integrations/pi/engine/conformance.js +2 -0
  83. package/dist/integrations/pi/engine/http-dispatcher.d.ts +4 -0
  84. package/dist/integrations/pi/engine/http-dispatcher.js +25 -0
  85. package/dist/integrations/pi/engine/index.d.ts +3 -0
  86. package/dist/integrations/pi/engine/index.js +3 -0
  87. package/dist/integrations/pi/engine/model-auth-integration.d.ts +1 -0
  88. package/dist/integrations/pi/engine/model-auth-integration.js +1 -0
  89. package/dist/integrations/pi/engine/package-integration.js +1 -1
  90. package/dist/integrations/pi/engine/project-trust-preflight.d.ts +22 -0
  91. package/dist/integrations/pi/engine/project-trust-preflight.js +50 -0
  92. package/dist/integrations/pi/engine/resource-extension-integration.d.ts +1 -0
  93. package/dist/integrations/pi/engine/resource-extension-integration.js +1 -0
  94. package/dist/integrations/pi/engine/runtime-integration.d.ts +16 -1
  95. package/dist/integrations/pi/engine/runtime-integration.js +34 -4
  96. package/dist/integrations/pi/engine/session-integration.d.ts +1 -0
  97. package/dist/integrations/pi/engine/session-integration.js +2 -1
  98. package/dist/integrations/pi/engine/settings-effects.d.ts +66 -0
  99. package/dist/integrations/pi/engine/settings-effects.js +249 -0
  100. package/dist/integrations/pi/engine/settings-integration.d.ts +14 -26
  101. package/dist/integrations/pi/engine/settings-integration.js +102 -108
  102. package/dist/integrations/pi/engine/workflow-controllers.d.ts +2 -1
  103. package/dist/integrations/pi/engine/workflow-controllers.js +1 -0
  104. package/dist/integrations/pi/session-ui/clipboard-image.d.ts +11 -0
  105. package/dist/integrations/pi/session-ui/clipboard-image.js +29 -0
  106. package/dist/integrations/pi/session-ui/index.d.ts +1 -0
  107. package/dist/integrations/pi/session-ui/index.js +1 -0
  108. package/dist/integrations/pi/session-ui/prompt-chips.js +6 -2
  109. package/dist/integrations/pi/session-ui/session-shell-root.d.ts +39 -4
  110. package/dist/integrations/pi/session-ui/session-shell-root.js +215 -80
  111. package/dist/integrations/pi/session-ui/session-shell.d.ts +10 -1
  112. package/dist/integrations/pi/session-ui/session-shell.js +256 -45
  113. package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +5 -0
  114. package/dist/integrations/pi/session-ui/session-viewport-controller.js +76 -11
  115. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.d.ts +29 -0
  116. package/dist/integrations/pi/session-ui/stream-presentation-coalescer.js +79 -0
  117. package/dist/integrations/pi/session-ui/system-clipboard.d.ts +9 -0
  118. package/dist/integrations/pi/session-ui/system-clipboard.js +38 -9
  119. package/dist/integrations/pi/tui-runtime/adapter.d.ts +6 -0
  120. package/dist/integrations/pi/tui-runtime/adapter.js +166 -8
  121. package/dist/integrations/pi/tui-runtime/contracts.d.ts +25 -0
  122. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +63 -0
  123. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +240 -0
  124. package/dist/integrations/pi/tui-runtime/index.d.ts +2 -0
  125. package/dist/integrations/pi/tui-runtime/index.js +2 -0
  126. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +39 -0
  127. package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.js +139 -0
  128. package/dist/native/darwin-arm64/manifest.json +1 -1
  129. package/dist/native/linux-x64/manifest.json +1 -1
  130. package/dist/native/win32-x64/manifest.json +2 -2
  131. package/dist/native/win32-x64/process-guardian.exe +0 -0
  132. package/dist/ui/apps/host.js +5 -9
  133. package/dist/ui/apps/registry.d.ts +1 -0
  134. package/dist/ui/apps/registry.js +1 -0
  135. package/dist/ui/components/dialog-panel.js +5 -3
  136. package/dist/ui/components/frame.d.ts +1 -0
  137. package/dist/ui/components/frame.js +1 -0
  138. package/dist/ui/components/index.d.ts +1 -0
  139. package/dist/ui/components/index.js +1 -0
  140. package/dist/ui/components/line-input.d.ts +1 -6
  141. package/dist/ui/components/line-input.js +4 -9
  142. package/dist/ui/components/list-view.d.ts +0 -6
  143. package/dist/ui/components/list-view.js +14 -7
  144. package/dist/ui/components/progress-status.d.ts +2 -0
  145. package/dist/ui/components/progress-status.js +4 -0
  146. package/dist/ui/components/scrollbar.js +1 -1
  147. package/dist/ui/components/shortcuts.d.ts +1 -0
  148. package/dist/ui/components/shortcuts.js +1 -0
  149. package/dist/ui/components/spans.d.ts +2 -5
  150. package/dist/ui/components/spans.js +28 -8
  151. package/dist/ui/components/surface.d.ts +0 -5
  152. package/dist/ui/components/surface.js +1 -5
  153. package/dist/ui/components/text-selection.d.ts +10 -1
  154. package/dist/ui/components/text-selection.js +96 -29
  155. package/dist/ui/components/text.js +3 -3
  156. package/dist/ui/components/transcript-viewport.d.ts +42 -0
  157. package/dist/ui/components/transcript-viewport.js +287 -39
  158. package/dist/ui/settings/sections.d.ts +6 -19
  159. package/dist/ui/settings/sections.js +17 -15
  160. package/dist/ui/settings/session.d.ts +8 -18
  161. package/dist/ui/settings/session.js +60 -52
  162. package/dist/ui/settings/store.d.ts +1 -0
  163. package/dist/ui/settings/store.js +2 -1
  164. package/docs/architecture/code-documentation.md +77 -0
  165. package/docs/architecture/project-structure.md +15 -1
  166. package/docs/architecture/ui-reference-provenance.md +23 -3
  167. package/docs/ci-release-runbook.md +98 -7
  168. package/docs/manual-owned-ui-checkpoint.md +28 -1
  169. package/docs/manual-terminal-colour-check.md +4 -3
  170. package/docs/repository-governance-live-acceptance.md +77 -0
  171. package/package.json +11 -3
@@ -5,15 +5,50 @@ export function orderedTextSelection(selection) {
5
5
  if (selection === undefined)
6
6
  return undefined;
7
7
  const { anchor, head } = selection;
8
- if (anchor.line === head.line && anchor.column === head.column && !selection.cell && !selection.fullRow)
8
+ if (selection.fullRow) {
9
+ const startLine = Math.min(anchor.line, head.line);
10
+ const endLine = Math.max(anchor.line, head.line);
11
+ return {
12
+ start: { line: startLine, column: 0 },
13
+ end: { line: endLine, column: Number.MAX_SAFE_INTEGER },
14
+ fullRow: true,
15
+ ...(selection.throughFinalColumn ? { throughFinalColumn: true } : {}),
16
+ };
17
+ }
18
+ if (selection.cell) {
19
+ const anchorFirst = comparePoints(anchor, head) <= 0;
20
+ const first = anchorFirst ? anchor : head;
21
+ const last = anchorFirst ? head : anchor;
22
+ return {
23
+ start: { line: first.line, column: pointBefore(first) },
24
+ end: { line: last.line, column: pointAfter(last) },
25
+ ...(selection.throughFinalColumn ? { throughFinalColumn: true } : {}),
26
+ };
27
+ }
28
+ if (selection.dragged !== true)
29
+ return undefined;
30
+ const direction = comparePoints(anchor, head);
31
+ if (direction === 0)
32
+ return undefined;
33
+ if (sameGrapheme(anchor, head)) {
34
+ return {
35
+ start: { line: anchor.line, column: pointBefore(anchor) },
36
+ end: { line: anchor.line, column: pointAfter(anchor) },
37
+ };
38
+ }
39
+ const ordered = direction < 0
40
+ ? {
41
+ start: { line: anchor.line, column: pointBefore(anchor) },
42
+ end: { line: head.line, column: pointBefore(head) },
43
+ }
44
+ : {
45
+ start: { line: head.line, column: pointAfter(head) },
46
+ end: { line: anchor.line, column: pointAfter(anchor) },
47
+ };
48
+ if (ordered.start.line === ordered.end.line && ordered.start.column >= ordered.end.column)
9
49
  return undefined;
10
- const anchorFirst = anchor.line < head.line || (anchor.line === head.line && anchor.column <= head.column);
11
- const ordered = anchorFirst
12
- ? { start: anchor, end: head }
13
- : { start: head, end: anchor };
14
50
  return {
15
51
  ...ordered,
16
- ...(selection.fullRow ? { fullRow: true } : {}),
17
52
  ...(selection.throughFinalColumn ? { throughFinalColumn: true } : {}),
18
53
  };
19
54
  }
@@ -50,12 +85,13 @@ export function pressTextSelection(input) {
50
85
  kind: "line",
51
86
  };
52
87
  }
88
+ const point = textSelectionPointAt(input.line, column, input.lineText);
53
89
  return {
54
90
  selection: {
55
- anchor: { line: input.line, column },
56
- head: { line: input.line, column },
91
+ anchor: point,
92
+ head: point,
57
93
  selecting: true,
58
- cell: false,
94
+ dragged: false,
59
95
  },
60
96
  click,
61
97
  kind: "point",
@@ -64,15 +100,16 @@ export function pressTextSelection(input) {
64
100
  export function extendTextSelection(selection, point) {
65
101
  if (selection?.selecting !== true)
66
102
  return selection;
67
- if (selection.fullRow) {
68
- if (point.line === selection.anchor.line && selection.head.line === selection.anchor.line)
69
- return selection;
70
- const edge = point.line < selection.anchor.line ? Number.MAX_SAFE_INTEGER : 1;
71
- if (selection.anchor.column !== edge) {
72
- return { ...selection, anchor: { line: selection.anchor.line, column: edge }, head: point };
73
- }
74
- }
75
- return { ...selection, head: point };
103
+ const distinctMotion = comparePoints(selection.head, point) !== 0;
104
+ if (!distinctMotion)
105
+ return selection;
106
+ if (selection.fullRow)
107
+ return { ...selection, head: point };
108
+ return {
109
+ ...selection,
110
+ head: point,
111
+ dragged: true,
112
+ };
76
113
  }
77
114
  export function releaseTextSelection(selection) {
78
115
  if (selection === undefined)
@@ -83,6 +120,21 @@ export function releaseTextSelection(selection) {
83
120
  export function textSelectionLineExtendColumn(selection, line, contentWidth) {
84
121
  return line < selection.anchor.line ? 1 : Math.max(1, contentWidth);
85
122
  }
123
+ /** Resolves a reported one-based pointer cell to the complete grapheme it intersects. */
124
+ export function textSelectionPointAt(line, column, lineText) {
125
+ const plain = stripAnsi(lineText);
126
+ const target = Math.max(0, column - 1);
127
+ let width = 0;
128
+ for (const { segment } of GRAPHEMES.segment(plain)) {
129
+ const cellWidth = displayWidth(segment);
130
+ const next = width + cellWidth;
131
+ if (cellWidth > 0 && target >= width && target < next) {
132
+ return { line, column, from: width, to: next };
133
+ }
134
+ width = next;
135
+ }
136
+ return { line, column, from: target, to: target + 1 };
137
+ }
86
138
  export function textSelectionText(selection, rows, lineContent) {
87
139
  const parts = [];
88
140
  for (let line = selection.start.line; line <= selection.end.line && line < rows.length; line += 1) {
@@ -92,18 +144,20 @@ export function textSelectionText(selection, rows, lineContent) {
92
144
  parts.push("");
93
145
  continue;
94
146
  }
95
- const baseFrom = line === selection.start.line ? selection.start.column - 1 : 0;
147
+ const baseFrom = line === selection.start.line ? selection.start.column : 0;
96
148
  const baseTo = line === selection.end.line ? selection.end.column : Number.MAX_SAFE_INTEGER;
97
- const from = Math.max(baseFrom, Math.max(0, (content?.from ?? 1) - 1));
98
- const to = Math.max(from, Math.min(baseTo, content?.to ?? Number.MAX_SAFE_INTEGER));
99
- parts.push(plain.slice(indexAtDisplayWidth(plain, from), indexAtDisplayWidth(plain, to)).trimEnd());
149
+ const contentFrom = Math.max(0, (content?.from ?? 1) - 1);
150
+ const contentTo = Math.max(contentFrom, (content?.to ?? Number.MAX_SAFE_INTEGER) - 1);
151
+ const from = Math.max(baseFrom, contentFrom);
152
+ const to = Math.max(from, Math.min(baseTo, contentTo));
153
+ parts.push(plain.slice(indexAtDisplayBoundary(plain, from, "start"), indexAtDisplayBoundary(plain, to, "end")).trimEnd());
100
154
  }
101
155
  return parts.join("\n");
102
156
  }
103
- /** Returns the plain cells covered by [from,to), using terminal grapheme widths. */
157
+ /** Returns the plain cells covered by [from,to), expanding at grapheme edges. */
104
158
  export function plainTextBetweenColumns(line, from, to) {
105
159
  const plain = stripAnsi(line);
106
- return plain.slice(indexAtDisplayWidth(plain, from), indexAtDisplayWidth(plain, to));
160
+ return plain.slice(indexAtDisplayBoundary(plain, from, "start"), indexAtDisplayBoundary(plain, to, "end"));
107
161
  }
108
162
  export function usefulTextLineContent(line, from = 1) {
109
163
  const start = Math.max(1, from);
@@ -147,22 +201,35 @@ function characterClass(character) {
147
201
  return 1;
148
202
  return 2;
149
203
  }
150
- function indexAtDisplayWidth(plain, column) {
204
+ function indexAtDisplayBoundary(plain, column, edge) {
151
205
  if (column <= 0)
152
206
  return 0;
153
207
  let width = 0;
154
208
  let index = 0;
155
209
  for (const { segment } of GRAPHEMES.segment(plain)) {
156
210
  const cellWidth = displayWidth(segment);
157
- if (width + cellWidth > column)
158
- break;
159
- width += cellWidth;
211
+ const next = width + cellWidth;
212
+ if (column < next)
213
+ return edge === "start" ? index : index + segment.length;
160
214
  index += segment.length;
215
+ width = next;
161
216
  if (width >= column)
162
- break;
217
+ return index;
163
218
  }
164
219
  return index;
165
220
  }
221
+ function pointBefore(point) {
222
+ return point.from ?? Math.max(0, point.column - 1);
223
+ }
224
+ function pointAfter(point) {
225
+ return point.to ?? Math.max(0, point.column);
226
+ }
227
+ function sameGrapheme(left, right) {
228
+ return left.line === right.line && pointBefore(left) === pointBefore(right) && pointAfter(left) === pointAfter(right);
229
+ }
230
+ function comparePoints(left, right) {
231
+ return left.line === right.line ? left.column - right.column : left.line - right.line;
232
+ }
166
233
  function clamp(value, minimum, maximum) {
167
234
  return Math.max(minimum, Math.min(value, maximum));
168
235
  }
@@ -21,7 +21,7 @@ export function stripAnsi(text) {
21
21
  return text.replace(ANSI_PATTERN, "");
22
22
  }
23
23
  function codePointWidth(codePoint) {
24
- // Zero-width: combining marks, joiners, variation selectors, and format characters.
24
+ // Protocol: zero-width includes combining marks, joiners, variation selectors, and format characters.
25
25
  if (codePoint === 0x200d || codePoint === 0xfeff)
26
26
  return 0;
27
27
  if (codePoint >= 0x0300 && codePoint <= 0x036f)
@@ -38,7 +38,7 @@ function codePointWidth(codePoint) {
38
38
  return 0;
39
39
  if (codePoint >= 0xe0100 && codePoint <= 0xe01ef)
40
40
  return 0;
41
- // Wide: CJK, Hangul, fullwidth forms, and the emoji planes terminals render double-width.
41
+ // Protocol: wide cells include CJK, Hangul, fullwidth forms, and the emoji planes terminals render double-width.
42
42
  if (codePoint >= 0x1100 && codePoint <= 0x115f)
43
43
  return 2;
44
44
  if (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f)
@@ -59,7 +59,7 @@ function codePointWidth(codePoint) {
59
59
  return 2;
60
60
  if (codePoint >= 0x20000 && codePoint <= 0x3fffd)
61
61
  return 2;
62
- // A tab advances to the host runtime's stop; other control characters occupy nothing.
62
+ // Protocol: a tab advances to the host runtime's stop; other control characters occupy nothing.
63
63
  if (codePoint === 0x09)
64
64
  return TAB_WIDTH;
65
65
  if (codePoint < 0x20 || (codePoint >= 0x7f && codePoint < 0xa0))
@@ -57,6 +57,36 @@ export interface TranscriptViewportHitRegions {
57
57
  readonly columnEnd: number;
58
58
  } | null;
59
59
  }
60
+ export interface TranscriptViewportFrameDescriptor {
61
+ readonly frameId: number;
62
+ readonly width: number;
63
+ readonly height: number;
64
+ readonly transcript: {
65
+ readonly rowStart: number;
66
+ readonly rowEnd: number;
67
+ } | null;
68
+ readonly dock: {
69
+ readonly rowStart: number;
70
+ readonly rowEnd: number;
71
+ } | null;
72
+ readonly previousDocumentRange: {
73
+ readonly start: number;
74
+ readonly end: number;
75
+ } | null;
76
+ readonly nextDocumentRange: {
77
+ readonly start: number;
78
+ readonly end: number;
79
+ };
80
+ readonly previousFollowingEnd: boolean | null;
81
+ readonly followingEnd: boolean;
82
+ readonly verticalShiftRows: number;
83
+ readonly safeVerticalShift: boolean;
84
+ /** Monotonic interaction revision used to reject stale selection evidence. */
85
+ readonly selectionRevision: number;
86
+ /** One-based terminal rows whose source or normalized selection range changed. */
87
+ readonly selectionDamagedRows: readonly number[];
88
+ readonly cause: "initial" | "steady" | "dock-input" | "follow-shift" | "detached" | "geometry-change";
89
+ }
60
90
  export interface TranscriptViewportFrame {
61
91
  readonly rows: readonly string[];
62
92
  readonly contentWidth: number;
@@ -64,6 +94,14 @@ export interface TranscriptViewportFrame {
64
94
  readonly maxScroll: number;
65
95
  readonly followingEnd: boolean;
66
96
  readonly hits: TranscriptViewportHitRegions;
97
+ readonly descriptor: TranscriptViewportFrameDescriptor;
98
+ /** Deterministic evidence for bounded selection-only row composition. */
99
+ readonly selectionDamage: {
100
+ readonly revision: number;
101
+ readonly recomputedRows: readonly number[];
102
+ readonly reusedRows: readonly number[];
103
+ readonly cacheEntries: number;
104
+ };
67
105
  }
68
106
  /**
69
107
  * A1-owned viewport state. It knows only rows and semantic prompt anchors; Pi
@@ -76,6 +114,7 @@ export declare class TranscriptViewport {
76
114
  get followingEnd(): boolean;
77
115
  get newMessages(): number;
78
116
  get frame(): TranscriptViewportFrame | null;
117
+ get selectionRevision(): number;
79
118
  /** Counts one completed assistant reply while detached; tool rows never call this. */
80
119
  noteNewMessage(): boolean;
81
120
  setConfig(config: TranscriptViewportConfig): void;
@@ -101,4 +140,7 @@ export declare class TranscriptViewport {
101
140
  reset(): void;
102
141
  clearTransient(): void;
103
142
  compose(input: TranscriptViewportFrameInput): TranscriptViewportFrame;
143
+ /** Reuses an established transcript frame when only same-height dock rows changed. */
144
+ composeDockOnly(dockRows: readonly string[], width: number, height: number): TranscriptViewportFrame | null;
104
145
  }
146
+ export declare function assertTranscriptViewportFrameDescriptor(descriptor: TranscriptViewportFrameDescriptor): void;