@timurproko/a1 0.1.8-dev.137 → 0.1.8-dev.151

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 (105) hide show
  1. package/README.md +2 -4
  2. package/dist/cli/capabilities.d.ts +2 -11
  3. package/dist/cli/capabilities.js +1 -1
  4. package/dist/cli/dispatch.js +3 -6
  5. package/dist/composition/owned-ui.js +26 -5
  6. package/dist/composition/settings-route-host.d.ts +1 -1
  7. package/dist/composition/settings-route-host.js +1 -1
  8. package/dist/contracts/owned-ui/model.d.ts +28 -0
  9. package/dist/contracts/owned-ui/validation.js +14 -0
  10. package/dist/features/launch/development-launch.js +11 -3
  11. package/dist/features/launch/index.d.ts +0 -1
  12. package/dist/features/launch/index.js +0 -1
  13. package/dist/features/launch/intent.d.ts +3 -2
  14. package/dist/features/launch/intent.js +1 -2
  15. package/dist/features/launch/prepare-launch.d.ts +0 -2
  16. package/dist/features/launch/prepare-launch.js +2 -9
  17. package/dist/features/launch/profile-paths.d.ts +1 -2
  18. package/dist/features/launch/profile-paths.js +2 -8
  19. package/dist/features/launch/runtime-selection.d.ts +2 -5
  20. package/dist/features/owned-ui/settings-app.js +38 -14
  21. package/dist/foundation/lifecycle/model.d.ts +1 -1
  22. package/dist/foundation/lifecycle/model.js +1 -1
  23. package/dist/foundation/release/bootstrap.d.ts +1 -3
  24. package/dist/foundation/release/bootstrap.js +1 -1
  25. package/dist/foundation/storage/control-store.js +37 -3
  26. package/dist/integrations/pi/components/owned-editor-ux.d.ts +55 -0
  27. package/dist/integrations/pi/components/owned-editor-ux.js +778 -0
  28. package/dist/integrations/pi/components/shell-editor-autocomplete.js +44 -6
  29. package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
  30. package/dist/integrations/pi/components/shell-footer-status.js +14 -5
  31. package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +3 -2
  32. package/dist/integrations/pi/components/shell-presenters-transcript.js +9 -8
  33. package/dist/integrations/pi/components/shell-shared-facade.d.ts +41 -7
  34. package/dist/integrations/pi/components/shell-shared-facade.js +3 -1
  35. package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +13 -0
  36. package/dist/integrations/pi/components/submitted-prompt-adapter.js +27 -0
  37. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +10 -2
  38. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +36 -3
  39. package/dist/integrations/pi/engine/adapter.js +21 -3
  40. package/dist/integrations/pi/engine/session-integration.d.ts +2 -1
  41. package/dist/integrations/pi/engine/session-integration.js +17 -3
  42. package/dist/integrations/pi/session-ui/prompt-chips.d.ts +23 -0
  43. package/dist/integrations/pi/session-ui/prompt-chips.js +242 -0
  44. package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
  45. package/dist/integrations/pi/{owned-ui → session-ui}/session-shell-root.d.ts +34 -5
  46. package/dist/integrations/pi/{owned-ui → session-ui}/session-shell-root.js +294 -45
  47. package/dist/integrations/pi/{owned-ui → session-ui}/session-shell.d.ts +1 -1
  48. package/dist/integrations/pi/{owned-ui → session-ui}/session-shell.js +167 -24
  49. package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +39 -0
  50. package/dist/integrations/pi/session-ui/session-viewport-controller.js +369 -0
  51. package/dist/integrations/pi/session-ui/system-clipboard.d.ts +11 -0
  52. package/dist/integrations/pi/session-ui/system-clipboard.js +101 -0
  53. package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -1
  54. package/dist/integrations/pi/tui-runtime/adapter.js +51 -2
  55. package/dist/integrations/pi/tui-runtime/contracts.d.ts +4 -6
  56. package/dist/native/darwin-arm64/manifest.json +1 -1
  57. package/dist/native/linux-x64/manifest.json +1 -1
  58. package/dist/native/win32-x64/manifest.json +3 -3
  59. package/dist/native/win32-x64/process-guardian.exe +0 -0
  60. package/dist/product-identity.d.ts +2 -2
  61. package/dist/product-identity.js +3 -4
  62. package/dist/product-identity.json +3 -5
  63. package/dist/ui/apps/contracts.d.ts +23 -1
  64. package/dist/ui/apps/host.js +9 -1
  65. package/dist/ui/components/index.d.ts +3 -0
  66. package/dist/ui/components/index.js +3 -0
  67. package/dist/ui/components/mouse.d.ts +10 -0
  68. package/dist/ui/components/mouse.js +23 -0
  69. package/dist/ui/components/prompt-row.d.ts +14 -0
  70. package/dist/ui/components/prompt-row.js +20 -0
  71. package/dist/ui/components/scrollbar.d.ts +26 -0
  72. package/dist/ui/components/scrollbar.js +35 -0
  73. package/dist/ui/components/spans.d.ts +21 -0
  74. package/dist/ui/components/spans.js +178 -0
  75. package/dist/ui/components/submitted-prompt.d.ts +23 -0
  76. package/dist/ui/components/submitted-prompt.js +50 -0
  77. package/dist/ui/components/text-selection.d.ts +53 -0
  78. package/dist/ui/components/text-selection.js +168 -0
  79. package/dist/ui/components/text.d.ts +14 -0
  80. package/dist/ui/components/text.js +40 -0
  81. package/dist/ui/components/transcript-viewport.d.ts +104 -0
  82. package/dist/ui/components/transcript-viewport.js +381 -0
  83. package/dist/ui/settings/declarations.d.ts +8 -1
  84. package/dist/ui/settings/declarations.js +33 -5
  85. package/dist/ui/settings/migrations.d.ts +1 -1
  86. package/dist/ui/settings/migrations.js +21 -2
  87. package/dist/ui/settings/sections.js +15 -8
  88. package/dist/ui/settings/session.d.ts +2 -0
  89. package/dist/ui/settings/session.js +7 -5
  90. package/docs/architecture/boundaries.md +3 -3
  91. package/docs/architecture/project-structure.md +2 -2
  92. package/docs/architecture/resource-and-data-policy.md +1 -1
  93. package/docs/architecture/toolchain.md +5 -5
  94. package/docs/architecture/ui-reference-provenance.md +11 -2
  95. package/docs/features/launch-profiles.md +7 -14
  96. package/docs/manual-launch-instance-acceptance.md +12 -35
  97. package/docs/manual-owned-ui-checkpoint.md +2 -3
  98. package/docs/manual-pi-boundary-candidate.md +4 -5
  99. package/package.json +4 -2
  100. package/dist/features/launch/profiles.d.ts +0 -12
  101. package/dist/features/launch/profiles.js +0 -26
  102. package/dist/integrations/pi/owned-ui/route-host.d.ts +0 -29
  103. /package/dist/integrations/pi/{owned-ui → session-ui}/index.d.ts +0 -0
  104. /package/dist/integrations/pi/{owned-ui → session-ui}/index.js +0 -0
  105. /package/dist/integrations/pi/{owned-ui → session-ui}/route-host.js +0 -0
@@ -0,0 +1,53 @@
1
+ export interface TextSelectionPoint {
2
+ readonly line: number;
3
+ readonly column: number;
4
+ }
5
+ export interface TextSelection {
6
+ readonly anchor: TextSelectionPoint;
7
+ readonly head: TextSelectionPoint;
8
+ readonly selecting: boolean;
9
+ readonly cell?: boolean;
10
+ readonly fullRow?: boolean;
11
+ /** Paint an edge whitespace run through the viewport's overlaid rail cell. */
12
+ readonly throughFinalColumn?: boolean;
13
+ }
14
+ export interface TextSelectionClick {
15
+ readonly time: number;
16
+ readonly line: number;
17
+ readonly column: number;
18
+ readonly count: number;
19
+ }
20
+ export interface TextSelectionLineContent {
21
+ readonly from?: number;
22
+ readonly to?: number;
23
+ readonly selectable?: boolean;
24
+ }
25
+ export interface OrderedTextSelection {
26
+ readonly start: TextSelectionPoint;
27
+ readonly end: TextSelectionPoint;
28
+ readonly fullRow?: boolean;
29
+ readonly throughFinalColumn?: boolean;
30
+ }
31
+ export interface TextSelectionPressInput {
32
+ readonly line: number;
33
+ readonly column: number;
34
+ readonly contentWidth: number;
35
+ readonly lineText: string;
36
+ readonly lineContent?: TextSelectionLineContent;
37
+ readonly previousClick?: TextSelectionClick;
38
+ readonly now?: number;
39
+ }
40
+ export declare const TEXT_SELECTION_MULTI_CLICK_MS = 500;
41
+ export declare function orderedTextSelection(selection: TextSelection | undefined): OrderedTextSelection | undefined;
42
+ export declare function pressTextSelection(input: TextSelectionPressInput): {
43
+ readonly selection?: TextSelection;
44
+ readonly click: TextSelectionClick;
45
+ readonly kind: "point" | "word" | "line";
46
+ };
47
+ export declare function extendTextSelection(selection: TextSelection | undefined, point: TextSelectionPoint): TextSelection | undefined;
48
+ export declare function releaseTextSelection(selection: TextSelection | undefined): TextSelection | undefined;
49
+ export declare function textSelectionLineExtendColumn(selection: TextSelection, line: number, contentWidth: number): number;
50
+ export declare function textSelectionText(selection: OrderedTextSelection, rows: readonly string[], lineContent?: (line: number) => TextSelectionLineContent | undefined): string;
51
+ /** Returns the plain cells covered by [from,to), using terminal grapheme widths. */
52
+ export declare function plainTextBetweenColumns(line: string, from: number, to: number): string;
53
+ export declare function usefulTextLineContent(line: string, from?: number): TextSelectionLineContent;
@@ -0,0 +1,168 @@
1
+ import { displayWidth, stripAnsi } from "./text.js";
2
+ const GRAPHEMES = new Intl.Segmenter(undefined, { granularity: "grapheme" });
3
+ export const TEXT_SELECTION_MULTI_CLICK_MS = 500;
4
+ export function orderedTextSelection(selection) {
5
+ if (selection === undefined)
6
+ return undefined;
7
+ const { anchor, head } = selection;
8
+ if (anchor.line === head.line && anchor.column === head.column && !selection.cell && !selection.fullRow)
9
+ 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
+ return {
15
+ ...ordered,
16
+ ...(selection.fullRow ? { fullRow: true } : {}),
17
+ ...(selection.throughFinalColumn ? { throughFinalColumn: true } : {}),
18
+ };
19
+ }
20
+ export function pressTextSelection(input) {
21
+ const now = input.now ?? Date.now();
22
+ const previous = input.previousClick;
23
+ const count = previous !== undefined
24
+ && now - previous.time <= TEXT_SELECTION_MULTI_CLICK_MS
25
+ && previous.line === input.line
26
+ && Math.abs(previous.column - input.column) <= 1
27
+ ? previous.count + 1
28
+ : 1;
29
+ const click = { time: now, line: input.line, column: input.column, count };
30
+ const column = clamp(input.column, 1, Math.max(1, input.contentWidth));
31
+ const kind = ((count - 1) % 3) + 1;
32
+ if (kind === 2) {
33
+ const selection = selectWord(input.line, column, input.contentWidth, input.lineText);
34
+ return selection === undefined ? { click, kind: "word" } : { selection, click, kind: "word" };
35
+ }
36
+ if (kind === 3) {
37
+ if (input.lineContent?.selectable === false)
38
+ return { click, kind: "line" };
39
+ const from = clamp(input.lineContent?.from ?? 1, 1, Math.max(1, input.contentWidth));
40
+ const to = clamp(input.lineContent?.to ?? input.contentWidth, from, Math.max(1, input.contentWidth));
41
+ return {
42
+ selection: {
43
+ anchor: { line: input.line, column: from },
44
+ head: { line: input.line, column: to },
45
+ selecting: true,
46
+ cell: true,
47
+ fullRow: true,
48
+ },
49
+ click,
50
+ kind: "line",
51
+ };
52
+ }
53
+ return {
54
+ selection: {
55
+ anchor: { line: input.line, column },
56
+ head: { line: input.line, column },
57
+ selecting: true,
58
+ cell: false,
59
+ },
60
+ click,
61
+ kind: "point",
62
+ };
63
+ }
64
+ export function extendTextSelection(selection, point) {
65
+ if (selection?.selecting !== true)
66
+ 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 };
76
+ }
77
+ export function releaseTextSelection(selection) {
78
+ if (selection === undefined)
79
+ return undefined;
80
+ const released = selection.selecting ? { ...selection, selecting: false } : selection;
81
+ return orderedTextSelection(released) === undefined ? undefined : released;
82
+ }
83
+ export function textSelectionLineExtendColumn(selection, line, contentWidth) {
84
+ return line < selection.anchor.line ? 1 : Math.max(1, contentWidth);
85
+ }
86
+ export function textSelectionText(selection, rows, lineContent) {
87
+ const parts = [];
88
+ for (let line = selection.start.line; line <= selection.end.line && line < rows.length; line += 1) {
89
+ const plain = stripAnsi(rows[line] ?? "");
90
+ const content = lineContent?.(line);
91
+ if (content?.selectable === false) {
92
+ parts.push("");
93
+ continue;
94
+ }
95
+ const baseFrom = line === selection.start.line ? selection.start.column - 1 : 0;
96
+ 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());
100
+ }
101
+ return parts.join("\n");
102
+ }
103
+ /** Returns the plain cells covered by [from,to), using terminal grapheme widths. */
104
+ export function plainTextBetweenColumns(line, from, to) {
105
+ const plain = stripAnsi(line);
106
+ return plain.slice(indexAtDisplayWidth(plain, from), indexAtDisplayWidth(plain, to));
107
+ }
108
+ export function usefulTextLineContent(line, from = 1) {
109
+ const start = Math.max(1, from);
110
+ const end = displayWidth(stripAnsi(line).replace(/\s+$/, "")) + 1;
111
+ return { from: start, to: Math.max(start, end) };
112
+ }
113
+ function selectWord(line, column, contentWidth, lineText) {
114
+ const plain = stripAnsi(lineText);
115
+ const segments = [];
116
+ let width = 0;
117
+ for (const { segment } of GRAPHEMES.segment(plain)) {
118
+ const cellWidth = displayWidth(segment);
119
+ if (cellWidth <= 0)
120
+ continue;
121
+ segments.push({ cls: characterClass(segment), from: width, to: width + cellWidth });
122
+ width += cellWidth;
123
+ }
124
+ const at = clamp(column, 1, Math.max(1, contentWidth)) - 1;
125
+ const index = segments.findIndex(segment => at >= segment.from && at < segment.to);
126
+ if (index < 0)
127
+ return undefined;
128
+ let low = index;
129
+ let high = index;
130
+ while (low > 0 && segments[low - 1]?.cls === segments[index]?.cls)
131
+ low -= 1;
132
+ while (high + 1 < segments.length && segments[high + 1]?.cls === segments[index]?.cls)
133
+ high += 1;
134
+ const end = segments[high]?.to ?? 1;
135
+ return {
136
+ anchor: { line, column: (segments[low]?.from ?? 0) + 1 },
137
+ head: { line, column: end },
138
+ selecting: true,
139
+ cell: true,
140
+ throughFinalColumn: segments[index]?.cls === 0 && end >= contentWidth,
141
+ };
142
+ }
143
+ function characterClass(character) {
144
+ if (/\s/u.test(character))
145
+ return 0;
146
+ if (/[\p{L}\p{N}_]/u.test(character))
147
+ return 1;
148
+ return 2;
149
+ }
150
+ function indexAtDisplayWidth(plain, column) {
151
+ if (column <= 0)
152
+ return 0;
153
+ let width = 0;
154
+ let index = 0;
155
+ for (const { segment } of GRAPHEMES.segment(plain)) {
156
+ const cellWidth = displayWidth(segment);
157
+ if (width + cellWidth > column)
158
+ break;
159
+ width += cellWidth;
160
+ index += segment.length;
161
+ if (width >= column)
162
+ break;
163
+ }
164
+ return index;
165
+ }
166
+ function clamp(value, minimum, maximum) {
167
+ return Math.max(minimum, Math.min(value, maximum));
168
+ }
@@ -6,6 +6,20 @@
6
6
  */
7
7
  /** Removes styling sequences so only visible characters remain. */
8
8
  export declare function stripAnsi(text: string): string;
9
+ export interface DisplayColumnRange {
10
+ readonly from: number;
11
+ readonly to: number;
12
+ }
13
+ /** Visible-column segment (word, whitespace, or punctuation) under a pointer column. */
14
+ export declare function displayWordColumnRange(text: string, pointerColumn: number): DisplayColumnRange | null;
15
+ export interface DisplayColumnSlice {
16
+ /** Grapheme-aligned visible bounds in the source row. */
17
+ readonly from: number;
18
+ readonly to: number;
19
+ readonly text: string;
20
+ }
21
+ /** Plain graphemes intersecting a visible-column range, expanded at wide-character edges. */
22
+ export declare function displayColumnSlice(text: string, requestedFrom: number, requestedTo: number): DisplayColumnSlice;
9
23
  /** Columns this text occupies once styling is removed. */
10
24
  export declare function displayWidth(text: string): number;
11
25
  /**
@@ -6,6 +6,7 @@
6
6
  */
7
7
  const ANSI_PATTERN = /\[[0-9;:?]*[ -/]*[@-~]|\][^]*(?:|\\)|[@-Z\\-_]/g;
8
8
  const SEGMENTER = new Intl.Segmenter(undefined, { granularity: "grapheme" });
9
+ const WORD_SEGMENTER = new Intl.Segmenter(undefined, { granularity: "word" });
9
10
  /** Removes styling sequences so only visible characters remain. */
10
11
  export function stripAnsi(text) {
11
12
  return text.replace(ANSI_PATTERN, "");
@@ -62,6 +63,45 @@ function graphemeWidth(grapheme) {
62
63
  }
63
64
  return width;
64
65
  }
66
+ /** Visible-column segment (word, whitespace, or punctuation) under a pointer column. */
67
+ export function displayWordColumnRange(text, pointerColumn) {
68
+ const plain = stripAnsi(text);
69
+ const pointer = Math.max(0, pointerColumn);
70
+ let column = 0;
71
+ for (const { segment } of WORD_SEGMENTER.segment(plain)) {
72
+ const width = displayWidth(segment);
73
+ const from = column;
74
+ const to = column + width;
75
+ if (pointer >= from && pointer < to)
76
+ return { from, to };
77
+ column = to;
78
+ }
79
+ return null;
80
+ }
81
+ /** Plain graphemes intersecting a visible-column range, expanded at wide-character edges. */
82
+ export function displayColumnSlice(text, requestedFrom, requestedTo) {
83
+ const plain = stripAnsi(text);
84
+ const from = Math.max(0, requestedFrom);
85
+ const to = Math.max(from, requestedTo);
86
+ let column = 0;
87
+ let actualFrom;
88
+ let actualTo = from;
89
+ let selected = "";
90
+ for (const { segment } of SEGMENTER.segment(plain)) {
91
+ const width = graphemeWidth(segment);
92
+ const start = column;
93
+ const end = column + width;
94
+ if (end > from && start < to) {
95
+ actualFrom ??= start;
96
+ actualTo = end;
97
+ selected += segment;
98
+ }
99
+ column = end;
100
+ if (start >= to)
101
+ break;
102
+ }
103
+ return { from: actualFrom ?? from, to: actualFrom === undefined ? from : actualTo, text: selected };
104
+ }
65
105
  /** Columns this text occupies once styling is removed. */
66
106
  export function displayWidth(text) {
67
107
  let width = 0;
@@ -0,0 +1,104 @@
1
+ import { type ScrollbarAppearance, type ScrollbarGeometry, type ScrollbarStyle } from "./scrollbar.js";
2
+ export interface TranscriptPromptAnchor {
3
+ readonly id: string;
4
+ readonly firstRow: number;
5
+ readonly lastRow: number;
6
+ /** The source first row, including its submitted-prompt styling and timestamp. */
7
+ readonly sourceRow: string;
8
+ }
9
+ export interface TranscriptViewportConfig {
10
+ readonly scrollbarAppearance: ScrollbarAppearance;
11
+ readonly scrollbarStyle: ScrollbarStyle;
12
+ }
13
+ export interface TranscriptViewportTheme {
14
+ readonly track: (text: string) => string;
15
+ readonly thumb: (text: string, active: boolean) => string;
16
+ readonly sticky: (text: string, hovered: boolean) => string;
17
+ readonly quietSticky: (text: string) => string;
18
+ readonly bottomControl: (text: string, hovered: boolean) => string;
19
+ readonly selection: (line: string, from: number, to: number) => string;
20
+ }
21
+ export interface TranscriptViewportFrameInput {
22
+ readonly documentRows: readonly string[];
23
+ /** Optional paint-only transform; semantic selection and copying keep documentRows exact. */
24
+ readonly paintDocumentRow?: (row: string) => string;
25
+ /** Leading document rows that participate in pointer selection and copying. */
26
+ readonly selectableDocumentRowCount?: number;
27
+ readonly dockRows: readonly string[];
28
+ readonly promptAnchors: readonly TranscriptPromptAnchor[];
29
+ readonly width: number;
30
+ readonly height: number;
31
+ /**
32
+ * Optional zero-based terminal row for the floating bottom control. The shell
33
+ * supplies a stable anchor above its editor group so transient status and
34
+ * notification rows cannot make the control jump vertically.
35
+ */
36
+ readonly bottomControlRow?: number;
37
+ readonly now?: number;
38
+ readonly theme?: TranscriptViewportTheme;
39
+ }
40
+ export interface TranscriptViewportHitRegions {
41
+ readonly viewportHeight: number;
42
+ readonly rail: {
43
+ readonly column: number;
44
+ /** One-based terminal row. The one-row top inset is intentionally excluded. */
45
+ readonly rowStart: number;
46
+ readonly trackHeight: number;
47
+ readonly geometry: ScrollbarGeometry;
48
+ } | null;
49
+ readonly sticky: {
50
+ readonly row: number;
51
+ readonly target: number;
52
+ readonly width: number;
53
+ } | null;
54
+ readonly bottom: {
55
+ readonly row: number;
56
+ readonly columnStart: number;
57
+ readonly columnEnd: number;
58
+ } | null;
59
+ }
60
+ export interface TranscriptViewportFrame {
61
+ readonly rows: readonly string[];
62
+ readonly contentWidth: number;
63
+ readonly scrollTop: number;
64
+ readonly maxScroll: number;
65
+ readonly followingEnd: boolean;
66
+ readonly hits: TranscriptViewportHitRegions;
67
+ }
68
+ /**
69
+ * A1-owned viewport state. It knows only rows and semantic prompt anchors; Pi
70
+ * components and transcript payloads remain outside this neutral boundary.
71
+ */
72
+ export declare class TranscriptViewport {
73
+ #private;
74
+ get scrollTop(): number;
75
+ get maxScroll(): number;
76
+ get followingEnd(): boolean;
77
+ get newMessages(): number;
78
+ get frame(): TranscriptViewportFrame | null;
79
+ /** Counts one completed assistant reply while detached; tool rows never call this. */
80
+ noteNewMessage(): boolean;
81
+ setConfig(config: TranscriptViewportConfig): void;
82
+ noteScrollActivity(now?: number, lingerMs?: number): void;
83
+ setRailHovered(hovered: boolean): void;
84
+ setRailDragging(dragging: boolean): void;
85
+ setStickyHovered(hovered: boolean): void;
86
+ setBottomHovered(hovered: boolean): void;
87
+ get selectionActive(): boolean;
88
+ get hasSelection(): boolean;
89
+ pressSelection(column: number, viewportRow: number, now?: number): boolean;
90
+ extendSelection(column: number, viewportRow: number, now?: number, autoScroll?: boolean): boolean;
91
+ releaseSelection(): boolean;
92
+ clearSelection(): boolean;
93
+ selectedText(): string | null;
94
+ scrollBy(lines: number, now?: number): boolean;
95
+ scrollTo(position: number, now?: number): boolean;
96
+ scrollToEnd(now?: number): boolean;
97
+ /** Jumps to the pinned prompt governing this position, then earlier prompts. */
98
+ scrollToPreviousPrompt(now?: number): boolean;
99
+ /** Jumps to the next submitted prompt after the prompt at the current stop. */
100
+ scrollToNextPrompt(now?: number): boolean;
101
+ reset(): void;
102
+ clearTransient(): void;
103
+ compose(input: TranscriptViewportFrameInput): TranscriptViewportFrame;
104
+ }