@aitty/browser 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # @aitty/browser
2
+
3
+ Browser-side DOM terminal renderer for aitty sessions.
4
+
5
+ Use this package inside your web UI to mount a PTY-backed agent session created
6
+ by `@aitty/server`.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm i @aitty/browser
12
+ ```
13
+
14
+ Import the stylesheet once:
15
+
16
+ ```ts
17
+ import "@aitty/browser/style.css";
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```ts
23
+ import { mountAitty } from "@aitty/browser";
24
+ import "@aitty/browser/style.css";
25
+
26
+ const terminal = await mountAitty("#terminal", {
27
+ src: sessionUrl,
28
+ config: {
29
+ appearance: {
30
+ fontSize: 16,
31
+ lineHeight: 1.5,
32
+ theme: "light",
33
+ themeTarget: "container"
34
+ }
35
+ },
36
+ onStatusChange(status) {
37
+ console.log(status.connection, status.sessionState, status.message);
38
+ }
39
+ });
40
+
41
+ terminal.updateConfig({
42
+ appearance: {
43
+ theme: "dark"
44
+ }
45
+ });
46
+ ```
47
+
48
+ ```html
49
+ <div id="terminal" style="height: 100dvh"></div>
50
+ ```
51
+
52
+ If the page is served directly from an aitty session URL, `src` can be omitted.
53
+ When embedding aitty inside an existing app route, pass `src`.
54
+
55
+ By default, `@aitty/browser` scopes theme writes to the mounted container and
56
+ does not install the reference shell controls. That keeps host apps in control
57
+ of their own header, fullscreen UI, theme switcher, status indicator, and page
58
+ theme. The reference CLI shell opts into document-level theme and shell controls
59
+ explicitly through its own `data-aitty-*` attributes.
60
+
61
+ `themeTarget` is a mount-time ownership setting. Keep it at `"container"` for
62
+ embedded apps; use `"document"` only for full-page shells.
63
+
64
+ ## Main Exports
65
+
66
+ - `mountAitty()` mounts the terminal into a selector or element and connects to a session.
67
+ - `defineAittyTerminalElement()` registers the web component wrapper.
68
+ - `mountTerminalApp()` mounts with explicit elements and dependencies for advanced integrations.
69
+ - `createBufferedTerminalWriter()` buffers terminal writes until the renderer is ready.
70
+ - `BrowserTerminalRenderer` exposes the DOM renderer used by aitty.
71
+ - `normalizeTerminalConfig()`, `mergeTerminalConfig()`, and `cloneTerminalConfig()` help host apps manage settings state.
72
+ - `installShellControls()` wires the optional reference shell buttons used by the CLI page.
73
+ - `installTerminalInputPolicies()` wires keyboard, IME, paste, and shortcut handling.
74
+
75
+ ## Integration Hooks
76
+
77
+ - Use `onStatusChange` to render your own header, badge, or connection state UI.
78
+ - Use `config.appearance` and `terminal.updateConfig()` to keep host UI and terminal state aligned.
79
+ - Use `scrollAdapter` when integrating custom scrollbar libraries such as OverlayScrollbars.
80
+ - Use `config.behavior.input.resolveKey` for agent-specific shortcuts while leaving browser-reserved shortcuts to the browser.
81
+
82
+ ## License
83
+
84
+ Apache-2.0
package/dist/browser.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- import { BrowserTerminalBridge, BrowserTerminalRenderer, BrowserTerminalStyleOverride, BrowserTerminalStyleTracker } from "./frontend/browser-terminal-renderer.js";
2
- import { TerminalInputCallbacks, TerminalKeyResolver, installTerminalInputPolicies, isBrowserSafeShortcut, isCompositionKeyDown, isContainedTerminalNavigationKey } from "./frontend/terminal-input-policies.js";
3
- import { BinaryWriteTarget, BufferedTerminalWriter, FrameScheduler, MountAittyContainerOptions, MountAittyOptions, MountTerminalDependencies, MountTerminalElements, MountedTerminalApp, TerminalConnectionState, TerminalLoadingPresentation, TerminalOutputState, TerminalScrollAdapter, TerminalScrollAdapterContext, TerminalScrollAdapterFactory, TerminalScrollMetrics, TerminalScrollOptions, TerminalSessionPresentationState, TerminalStatusListener, TerminalStatusSnapshot, TerminalTheme, TerminalTransport, TransportCloseEvent, TransportHandlers, createBufferedTerminalWriter, defineAittyTerminalElement, mountAitty, mountTerminalApp } from "./frontend/terminal-app.js";
1
+ import { BrowserTerminalBridge, BrowserTerminalRenderer } from "./frontend/browser-terminal-renderer.js";
2
+ import { TerminalInputCallbacks, TerminalKeyResolver, TerminalPasteShortcut, TerminalPasteShortcutResult, installTerminalInputPolicies, isBrowserSafeShortcut, isCompositionKeyDown, isContainedTerminalNavigationKey } from "./frontend/terminal-input-policies.js";
3
+ import { TerminalAppearanceConfig, TerminalBehaviorConfig, TerminalConfig, TerminalConfigListener, TerminalConfigPatch, TerminalFontSizeRange, TerminalResolvedAppearanceConfig, TerminalResolvedBehaviorConfig, TerminalResolvedConfig, TerminalTheme, TerminalThemeTarget, cloneTerminalConfig, mergeTerminalConfig, normalizeTerminalConfig } from "./frontend/terminal-config.js";
4
+ import { BinaryWriteTarget, BufferedTerminalWriter, FrameScheduler, MountAittyContainerOptions, MountAittyOptions, MountTerminalDependencies, MountTerminalElements, MountedTerminalApp, TerminalConnectionState, TerminalLoadingPresentation, TerminalOutputState, TerminalScrollAdapter, TerminalScrollAdapterContext, TerminalScrollAdapterFactory, TerminalScrollMetrics, TerminalScrollOptions, TerminalSessionPresentationState, TerminalStatusListener, TerminalStatusSnapshot, TerminalTransport, TransportCloseEvent, TransportHandlers, createBufferedTerminalWriter, defineAittyTerminalElement, mountAitty, mountTerminalApp } from "./frontend/terminal-app.js";
4
5
  import { AittyTheme, AittyThemeSource, AittyThemeSubscription } from "./theme-source.js";
5
6
  import { AnsiStyleTracker, createAnsiStyleTracker } from "./frontend/ansi-style-tracker.js";
6
- export { type AittyTheme, type AittyThemeSource, type AittyThemeSubscription, type AnsiStyleTracker, type BinaryWriteTarget, type BrowserTerminalBridge, BrowserTerminalRenderer, type BrowserTerminalStyleOverride, type BrowserTerminalStyleTracker, type BufferedTerminalWriter, type FrameScheduler, type MountAittyContainerOptions, type MountAittyOptions, type MountTerminalDependencies, type MountTerminalElements, type MountedTerminalApp, type TerminalConnectionState, type TerminalInputCallbacks, type TerminalKeyResolver, type TerminalLoadingPresentation, type TerminalOutputState, type TerminalScrollAdapter, type TerminalScrollAdapterContext, type TerminalScrollAdapterFactory, type TerminalScrollMetrics, type TerminalScrollOptions, type TerminalSessionPresentationState, type TerminalStatusListener, type TerminalStatusSnapshot, type TerminalTheme, type TerminalTransport, type TransportCloseEvent, type TransportHandlers, createAnsiStyleTracker, createBufferedTerminalWriter, defineAittyTerminalElement, installTerminalInputPolicies, isBrowserSafeShortcut, isCompositionKeyDown, isContainedTerminalNavigationKey, mountAitty, mountTerminalApp };
7
+ import { ShellControlOptions, ShellControlScrollAnchor, installShellControls } from "./frontend/shell-controls.js";
8
+ export { type AittyTheme, type AittyThemeSource, type AittyThemeSubscription, type AnsiStyleTracker, type BinaryWriteTarget, type BrowserTerminalBridge, BrowserTerminalRenderer, type BufferedTerminalWriter, type FrameScheduler, type MountAittyContainerOptions, type MountAittyOptions, type MountTerminalDependencies, type MountTerminalElements, type MountedTerminalApp, type ShellControlOptions, type ShellControlScrollAnchor, type TerminalAppearanceConfig, type TerminalBehaviorConfig, type TerminalConfig, type TerminalConfigListener, type TerminalConfigPatch, type TerminalConnectionState, type TerminalFontSizeRange, type TerminalInputCallbacks, type TerminalKeyResolver, type TerminalLoadingPresentation, type TerminalOutputState, type TerminalPasteShortcut, type TerminalPasteShortcutResult, type TerminalResolvedAppearanceConfig, type TerminalResolvedBehaviorConfig, type TerminalResolvedConfig, type TerminalScrollAdapter, type TerminalScrollAdapterContext, type TerminalScrollAdapterFactory, type TerminalScrollMetrics, type TerminalScrollOptions, type TerminalSessionPresentationState, type TerminalStatusListener, type TerminalStatusSnapshot, type TerminalTheme, type TerminalThemeTarget, type TerminalTransport, type TransportCloseEvent, type TransportHandlers, cloneTerminalConfig, createAnsiStyleTracker, createBufferedTerminalWriter, defineAittyTerminalElement, installShellControls, installTerminalInputPolicies, isBrowserSafeShortcut, isCompositionKeyDown, isContainedTerminalNavigationKey, mergeTerminalConfig, mountAitty, mountTerminalApp, normalizeTerminalConfig };
package/dist/browser.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { createAnsiStyleTracker } from "./frontend/ansi-style-tracker.js";
2
2
  import { BrowserTerminalRenderer } from "./frontend/browser-terminal-renderer.js";
3
+ import { cloneTerminalConfig, mergeTerminalConfig, normalizeTerminalConfig } from "./frontend/terminal-config.js";
4
+ import { installShellControls } from "./frontend/shell-controls.js";
3
5
  import { installTerminalInputPolicies, isBrowserSafeShortcut, isCompositionKeyDown, isContainedTerminalNavigationKey } from "./frontend/terminal-input-policies.js";
4
6
  import { createBufferedTerminalWriter, defineAittyTerminalElement, mountAitty, mountTerminalApp } from "./frontend/terminal-app.js";
5
- export { BrowserTerminalRenderer, createAnsiStyleTracker, createBufferedTerminalWriter, defineAittyTerminalElement, installTerminalInputPolicies, isBrowserSafeShortcut, isCompositionKeyDown, isContainedTerminalNavigationKey, mountAitty, mountTerminalApp };
7
+ export { BrowserTerminalRenderer, cloneTerminalConfig, createAnsiStyleTracker, createBufferedTerminalWriter, defineAittyTerminalElement, installShellControls, installTerminalInputPolicies, isBrowserSafeShortcut, isCompositionKeyDown, isContainedTerminalNavigationKey, mergeTerminalConfig, mountAitty, mountTerminalApp, normalizeTerminalConfig };
@@ -0,0 +1,43 @@
1
+ self.addEventListener("push", (event) => {
2
+ let payload = {};
3
+
4
+ try {
5
+ payload = event.data ? event.data.json() : {};
6
+ } catch {
7
+ payload = {};
8
+ }
9
+
10
+ const title = typeof payload.title === "string" && payload.title ? payload.title : "aitty";
11
+ const options = {
12
+ body: typeof payload.body === "string" ? payload.body : "Terminal session needs your attention.",
13
+ data: {
14
+ requestId: typeof payload.requestId === "string" ? payload.requestId : "",
15
+ url: typeof payload.url === "string" && payload.url ? payload.url : "/"
16
+ },
17
+ tag: typeof payload.tag === "string" && payload.tag ? payload.tag : "aitty-notification"
18
+ };
19
+
20
+ event.waitUntil(self.registration.showNotification(title, options));
21
+ });
22
+
23
+ self.addEventListener("notificationclick", (event) => {
24
+ event.notification.close();
25
+
26
+ const targetUrl = new URL(event.notification.data?.url || "/", self.location.origin).toString();
27
+
28
+ event.waitUntil((async () => {
29
+ const windows = await self.clients.matchAll({
30
+ includeUncontrolled: true,
31
+ type: "window"
32
+ });
33
+
34
+ for (const client of windows) {
35
+ if (client.url === targetUrl || new URL(client.url).pathname === new URL(targetUrl).pathname) {
36
+ await client.focus();
37
+ return;
38
+ }
39
+ }
40
+
41
+ await self.clients.openWindow(targetUrl);
42
+ })());
43
+ });
@@ -1,5 +1,10 @@
1
- //#region src/frontend/ansi-sequences.d.ts
1
+ //#region packages/browser/src/frontend/ansi-sequences.d.ts
2
2
  declare function parseCsiParams(paramBuffer: string): number[];
3
3
  declare function nextAltScreenState(currentState: boolean, privateMarker: string, paramBuffer: string, finalByte: string): boolean;
4
+ type FocusReportingParser = {
5
+ append(chunk: string | Uint8Array): boolean | null;
6
+ reset(): void;
7
+ };
8
+ declare function createFocusReportingParser(): FocusReportingParser;
4
9
  //#endregion
5
- export { nextAltScreenState, parseCsiParams };
10
+ export { FocusReportingParser, createFocusReportingParser, nextAltScreenState, parseCsiParams };
@@ -1,9 +1,10 @@
1
- //#region src/frontend/ansi-sequences.ts
1
+ //#region packages/browser/src/frontend/ansi-sequences.ts
2
2
  const ALT_SCREEN_PARAMS = new Set([
3
3
  47,
4
4
  1047,
5
5
  1049
6
6
  ]);
7
+ const FOCUS_REPORTING_PARAM = 1004;
7
8
  function parseCsiParams(paramBuffer) {
8
9
  if (!paramBuffer) return [];
9
10
  return paramBuffer.split(/[;:]/).map((value) => Number(value)).filter((value) => !Number.isNaN(value));
@@ -13,5 +14,67 @@ function nextAltScreenState(currentState, privateMarker, paramBuffer, finalByte)
13
14
  if (!parseCsiParams(paramBuffer).some((value) => ALT_SCREEN_PARAMS.has(value))) return currentState;
14
15
  return finalByte === "h";
15
16
  }
17
+ function createFocusReportingParser() {
18
+ const decoder = new TextDecoder();
19
+ let parserState = "text";
20
+ let csiPrivate = "";
21
+ let csiParams = "";
22
+ const resetCsi = () => {
23
+ csiPrivate = "";
24
+ csiParams = "";
25
+ };
26
+ const reset = () => {
27
+ parserState = "text";
28
+ resetCsi();
29
+ };
30
+ const finishCsi = (finalByte) => {
31
+ const nextState = nextFocusReportingState(null, csiPrivate, csiParams, finalByte);
32
+ reset();
33
+ return nextState;
34
+ };
35
+ return {
36
+ append(chunk) {
37
+ const text = typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
38
+ let latestState = null;
39
+ for (const character of text) {
40
+ if (parserState === "escape") {
41
+ if (character === "[") {
42
+ parserState = "csi";
43
+ resetCsi();
44
+ continue;
45
+ }
46
+ if (character === "c") latestState = false;
47
+ parserState = "text";
48
+ continue;
49
+ }
50
+ if (parserState === "csi") {
51
+ if (character === "?") {
52
+ csiPrivate = "?";
53
+ continue;
54
+ }
55
+ if (character >= "0" && character <= "9" || character === ";" || character === ":") {
56
+ csiParams += character;
57
+ continue;
58
+ }
59
+ if (character >= "@" && character <= "~") {
60
+ const nextState = finishCsi(character);
61
+ if (nextState !== null) latestState = nextState;
62
+ continue;
63
+ }
64
+ reset();
65
+ continue;
66
+ }
67
+ if (character === "\x1B") parserState = "escape";
68
+ }
69
+ return latestState;
70
+ },
71
+ reset
72
+ };
73
+ }
74
+ function nextFocusReportingState(currentState, privateMarker, paramBuffer, finalByte) {
75
+ if (privateMarker !== "?" || finalByte !== "h" && finalByte !== "l") return currentState;
76
+ if (!parseCsiParams(paramBuffer).includes(FOCUS_REPORTING_PARAM)) return currentState;
77
+ return finalByte === "h";
78
+ }
16
79
  //#endregion
17
- export { nextAltScreenState, parseCsiParams };
80
+ export { createFocusReportingParser, nextAltScreenState, parseCsiParams };
@@ -1,13 +1,9 @@
1
- //#region src/frontend/ansi-style-tracker.d.ts
1
+ //#region packages/browser/src/frontend/ansi-style-tracker.d.ts
2
2
  type NullableStyle = {
3
3
  bg: string | null;
4
4
  fg: string | null;
5
5
  };
6
- type StyleCell = (NullableStyle & {
7
- displayStart?: number;
8
- hidden?: boolean;
9
- width?: number;
10
- }) | null;
6
+ type StyleCell = (NullableStyle & {}) | null;
11
7
  type CursorPosition = {
12
8
  col: number;
13
9
  row: number;
@@ -1,6 +1,6 @@
1
1
  import { nextAltScreenState, parseCsiParams } from "./ansi-sequences.js";
2
2
  import { cellWidthForCodePoint } from "./cell-width.js";
3
- //#region src/frontend/ansi-style-tracker.ts
3
+ //#region packages/browser/src/frontend/ansi-style-tracker.ts
4
4
  const ESC = "\x1B";
5
5
  function createBlankRow(cols) {
6
6
  return Array.from({ length: cols }, () => null);
@@ -10,10 +10,7 @@ function cloneRow(row) {
10
10
  if (!cell) return null;
11
11
  return {
12
12
  bg: cell.bg ?? null,
13
- displayStart: cell.displayStart,
14
- fg: cell.fg ?? null,
15
- hidden: cell.hidden,
16
- width: cell.width
13
+ fg: cell.fg ?? null
17
14
  };
18
15
  });
19
16
  }
@@ -24,13 +21,11 @@ function createBuffer(cols, rows) {
24
21
  return {
25
22
  cursor: {
26
23
  col: 0,
27
- displayCol: 0,
28
24
  row: 0
29
25
  },
30
26
  rows: Array.from({ length: rows }, () => createBlankRow(cols)),
31
27
  savedCursor: {
32
28
  col: 0,
33
- displayCol: 0,
34
29
  row: 0
35
30
  },
36
31
  scrollback: []
@@ -64,46 +59,20 @@ function createAnsiStyleTracker(options = {}) {
64
59
  const clampCursor = (cursor) => {
65
60
  cursor.row = clamp(cursor.row, 0, rows - 1);
66
61
  cursor.col = clamp(cursor.col, 0, cols - 1);
67
- cursor.displayCol = clamp(cursor.displayCol, 0, cols - 1);
68
62
  };
69
- const cellDisplayStart = (row, col) => row[col]?.displayStart ?? col;
70
- const cellWidth = (row, col) => row[col]?.width ?? 1;
71
- const makeCellState = (style, sourceCol, displayStart, width, hidden = false) => {
72
- if (!hidden && style.fg === null && style.bg === null && displayStart === sourceCol && width === 1) return null;
63
+ const makeCellState = (style) => {
64
+ if (style.fg === null && style.bg === null) return null;
73
65
  return {
74
66
  bg: style.bg,
75
- displayStart,
76
- fg: style.fg,
77
- hidden,
78
- width
67
+ fg: style.fg
79
68
  };
80
69
  };
81
- const markCellHidden = (row, col) => {
82
- const cell = row[col];
83
- row[col] = {
84
- bg: cell?.bg ?? null,
85
- displayStart: cellDisplayStart(row, col),
86
- fg: cell?.fg ?? null,
87
- hidden: true,
88
- width: cellWidth(row, col)
89
- };
90
- };
91
- const hideCellsCoveredByDisplayRange = (row, displayStart, width, sourceCol) => {
92
- const displayEnd = displayStart + width;
93
- for (let col = 0; col < cols; col += 1) {
94
- if (col === sourceCol) continue;
95
- const cellStart = cellDisplayStart(row, col);
96
- const cellEnd = cellStart + cellWidth(row, col);
97
- if (cellStart < displayEnd && cellEnd > displayStart) markCellHidden(row, col);
98
- }
99
- };
100
70
  const storeCellAtCursor = (width) => {
101
71
  const buffer = activeBuffer();
102
72
  const row = buffer.rows[buffer.cursor.row];
103
73
  if (!row) return;
104
- const displayStart = buffer.cursor.displayCol;
105
- hideCellsCoveredByDisplayRange(row, displayStart, width, buffer.cursor.col);
106
- row[buffer.cursor.col] = makeCellState(currentStyle, buffer.cursor.col, displayStart, width);
74
+ row[buffer.cursor.col] = makeCellState(currentStyle);
75
+ if (width > 1 && buffer.cursor.col + 1 < cols) row[buffer.cursor.col + 1] = makeCellState(currentStyle);
107
76
  };
108
77
  const scrollActiveBuffer = () => {
109
78
  const buffer = activeBuffer();
@@ -114,17 +83,15 @@ function createAnsiStyleTracker(options = {}) {
114
83
  const moveCursorTo = (buffer, row, col) => {
115
84
  buffer.cursor.row = clamp(row, 0, rows - 1);
116
85
  buffer.cursor.col = clamp(col, 0, cols - 1);
117
- buffer.cursor.displayCol = cellDisplayStart(buffer.rows[buffer.cursor.row] ?? [], buffer.cursor.col);
118
86
  };
119
87
  const advanceCursor = (width) => {
120
88
  const buffer = activeBuffer();
121
- if (buffer.cursor.col < cols - 1) {
122
- buffer.cursor.col += 1;
123
- buffer.cursor.displayCol = clamp(buffer.cursor.displayCol + width, 0, cols - 1);
89
+ const nextCol = buffer.cursor.col + width;
90
+ if (nextCol < cols) {
91
+ buffer.cursor.col = nextCol;
124
92
  return;
125
93
  }
126
94
  buffer.cursor.col = 0;
127
- buffer.cursor.displayCol = 0;
128
95
  if (buffer.cursor.row < rows - 1) {
129
96
  buffer.cursor.row += 1;
130
97
  return;
@@ -170,9 +137,7 @@ function createAnsiStyleTracker(options = {}) {
170
137
  return row.slice(0, nextCols);
171
138
  });
172
139
  buffer.cursor.col = clamp(buffer.cursor.col, 0, nextCols - 1);
173
- buffer.cursor.displayCol = clamp(buffer.cursor.displayCol, 0, nextCols - 1);
174
140
  buffer.savedCursor.col = clamp(buffer.savedCursor.col, 0, nextCols - 1);
175
- buffer.savedCursor.displayCol = clamp(buffer.savedCursor.displayCol, 0, nextCols - 1);
176
141
  };
177
142
  const setAltBuffer = (nextState) => {
178
143
  if (nextState === useAltBuffer) return;
@@ -312,11 +277,10 @@ function createAnsiStyleTracker(options = {}) {
312
277
  }
313
278
  if (character === "\r") {
314
279
  buffer.cursor.col = 0;
315
- buffer.cursor.displayCol = 0;
316
280
  return;
317
281
  }
318
282
  if (character === " ") {
319
- const nextTabStop = (Math.floor(buffer.cursor.displayCol / 8) + 1) * 8;
283
+ const nextTabStop = (Math.floor(buffer.cursor.col / 8) + 1) * 8;
320
284
  moveCursorTo(buffer, buffer.cursor.row, nextTabStop);
321
285
  return;
322
286
  }
@@ -1,9 +1,12 @@
1
- //#region src/frontend/browser-terminal-renderer.d.ts
1
+ //#region packages/browser/src/frontend/browser-terminal-renderer.d.ts
2
2
  type TerminalCell = {
3
3
  bg: number;
4
+ bgRgb?: number;
4
5
  char: number;
5
6
  fg: number;
7
+ fgRgb?: number;
6
8
  flags: number;
9
+ width?: number;
7
10
  };
8
11
  type TerminalCursor = {
9
12
  col: number;
@@ -25,33 +28,35 @@ type BrowserTerminalBridge = {
25
28
  isDirtyRow(row: number): boolean;
26
29
  usingAltScreen(): boolean;
27
30
  };
28
- type BrowserTerminalStyleOverride = {
29
- bg?: string | null;
30
- fg?: string | null;
31
- hidden?: boolean;
32
- } | null;
33
- type BrowserTerminalStyleTracker = {
34
- getGridOverride(row: number, col: number): BrowserTerminalStyleOverride;
35
- getScrollbackOverride(offset: number, col: number): BrowserTerminalStyleOverride;
36
- };
37
31
  type BrowserTerminalRenderOptions = {
38
32
  force?: boolean;
39
33
  };
34
+ type BrowserTerminalRendererOptions = {
35
+ onScrollbackRowsDropped?: (rows: string[]) => void;
36
+ renderedScrollbackLimit?: number;
37
+ };
40
38
  type SnapshotRow = {
41
39
  element: HTMLElement;
42
40
  text: string;
43
41
  };
44
42
  type GetCell = (col: number) => TerminalCell;
45
- type GetOverride = (col: number) => BrowserTerminalStyleOverride;
43
+ declare function resolveTerminalCellColumnSpan(getCell: GetCell, col: number, _lineLength: number): 1 | 2;
44
+ declare function serializeRowText(getCell: GetCell, lineLength: number): string;
46
45
  declare class BrowserTerminalRenderer {
47
46
  private _altScreenMeaningfulScrollbackCount;
48
47
  private _altScreenVisibleRowSnapshot;
49
48
  private _lastAltScreenState;
49
+ private _lastTotalScrollbackCount;
50
50
  private _renderedScrollbackCount;
51
+ private _renderedScrollbackTexts;
51
52
  private _restoreSnapshotCount;
53
+ private _rowSegmentKeys;
54
+ private _rowSegmentTexts;
52
55
  private _scrollbackRowEls;
53
56
  cols: number;
54
57
  container: HTMLElement;
58
+ renderedScrollbackLimit: number;
59
+ onScrollbackRowsDropped: (rows: string[]) => void;
55
60
  prevContainerBg: string;
56
61
  prevCursorCol: number;
57
62
  prevCursorRow: number;
@@ -59,13 +64,13 @@ declare class BrowserTerminalRenderer {
59
64
  prevRowBg: string[];
60
65
  rowEls: HTMLElement[];
61
66
  rows: number;
62
- styleTracker: BrowserTerminalStyleTracker;
63
- constructor(container: HTMLElement, styleTracker: BrowserTerminalStyleTracker);
67
+ constructor(container: HTMLElement, options?: BrowserTerminalRendererOptions);
64
68
  _resolveFirstLiveGridRow(): HTMLElement | null;
65
69
  _insertScrollbackFragment(fragment: DocumentFragment): void;
66
70
  setup(cols: number, rows: number): void;
67
- _buildRowContent(rowEl: HTMLElement, getCell: GetCell, getOverride: GetOverride, lineLen: number, cursorCol: number, rowIndex: number): void;
71
+ _buildRowContent(rowEl: HTMLElement, getCell: GetCell, lineLen: number, cursorCol: number, rowIndex: number): void;
68
72
  _buildScrollbackRowEl(bridge: BrowserTerminalBridge, offset: number): HTMLElement;
73
+ _readScrollbackRowTexts(bridge: BrowserTerminalBridge, scrollbackCount?: number): string[];
69
74
  _captureVisibleRowSnapshot(): void;
70
75
  _clearAltScreenRestoreSnapshot(): void;
71
76
  _readGridRowText(bridge: BrowserTerminalBridge, row: number): string;
@@ -75,6 +80,9 @@ declare class BrowserTerminalRenderer {
75
80
  trimPadding?: boolean;
76
81
  }): string[];
77
82
  _readScrollbackRowText(bridge: BrowserTerminalBridge, offset: number): string;
83
+ _isShiftedScrollbackMatch(bridge: BrowserTerminalBridge, shiftCount: number, scrollbackCount: number): boolean;
84
+ _resolveShiftedScrollbackCount(bridge: BrowserTerminalBridge, scrollbackCount: number): number | null;
85
+ getRenderedScrollbackCount(): number;
78
86
  _readLiveTranscriptRows(bridge: BrowserTerminalBridge, currentVisibleRows: string[]): string[];
79
87
  _liveTranscriptContainsSnapshots(bridge: BrowserTerminalBridge, snapshots: SnapshotRow[], currentVisibleRows: string[]): boolean;
80
88
  _getRestoredScrollbackSnapshots(bridge: BrowserTerminalBridge): SnapshotRow[];
@@ -83,4 +91,4 @@ declare class BrowserTerminalRenderer {
83
91
  render(bridge: BrowserTerminalBridge, options?: BrowserTerminalRenderOptions): void;
84
92
  }
85
93
  //#endregion
86
- export { BrowserTerminalBridge, BrowserTerminalRenderOptions, BrowserTerminalRenderer, BrowserTerminalStyleOverride, BrowserTerminalStyleTracker };
94
+ export { BrowserTerminalBridge, BrowserTerminalRenderOptions, BrowserTerminalRenderer, BrowserTerminalRendererOptions, resolveTerminalCellColumnSpan, serializeRowText };