silvery 0.17.0 → 0.17.2
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/dist/UPNG-AVSMjiFE.mjs +5076 -0
- package/dist/UPNG-AVSMjiFE.mjs.map +1 -0
- package/dist/__vite-browser-external-2447137e-D3GdsvS_.mjs +6 -0
- package/dist/__vite-browser-external-2447137e-D3GdsvS_.mjs.map +1 -0
- package/dist/animation-C_PTO0uH.mjs +304 -0
- package/dist/animation-C_PTO0uH.mjs.map +1 -0
- package/dist/ansi-CXLE_pt1.mjs +71 -0
- package/dist/ansi-CXLE_pt1.mjs.map +1 -0
- package/dist/ansi-zmNzgkPB.d.mts +49 -0
- package/dist/ansi-zmNzgkPB.d.mts.map +1 -0
- package/dist/apng-DCWY913R.mjs +3 -0
- package/dist/apng-ENBAJk-H.mjs +70 -0
- package/dist/apng-ENBAJk-H.mjs.map +1 -0
- package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
- package/dist/backend-CkIkIHR-.mjs +13396 -0
- package/dist/backend-CkIkIHR-.mjs.map +1 -0
- package/dist/backends-CkvbG3js.mjs +1181 -0
- package/dist/backends-CkvbG3js.mjs.map +1 -0
- package/dist/backends-CyJqNLeK.mjs +3 -0
- package/dist/chunk-BSw8zbkd.mjs +37 -0
- package/dist/cli-B-k7Bm56.mjs +4 -0
- package/dist/context-QreF3UHr.mjs +64 -0
- package/dist/context-QreF3UHr.mjs.map +1 -0
- package/dist/derive-D7bFJdfU.d.mts +28 -0
- package/dist/derive-D7bFJdfU.d.mts.map +1 -0
- package/dist/devtools-CscuKaDK.mjs +89 -0
- package/dist/devtools-CscuKaDK.mjs.map +1 -0
- package/dist/devtools-D4oGc6LY.mjs +2 -0
- package/dist/eta-DLiVPaSD.mjs +110 -0
- package/dist/eta-DLiVPaSD.mjs.map +1 -0
- package/dist/flexily-zero-adapter-DmG4Ge8t.mjs +3376 -0
- package/dist/flexily-zero-adapter-DmG4Ge8t.mjs.map +1 -0
- package/dist/flexily-zero-adapter-GHwEW11s.mjs +2 -0
- package/dist/gif-BaJNREpP.mjs +3 -0
- package/dist/gif-Bp6fIyN3.mjs +73 -0
- package/dist/gif-Bp6fIyN3.mjs.map +1 -0
- package/dist/gifenc-GiVCZ9-3.mjs +730 -0
- package/dist/gifenc-GiVCZ9-3.mjs.map +1 -0
- package/dist/image-Dx7gYjkq.mjs +346 -0
- package/dist/image-Dx7gYjkq.mjs.map +1 -0
- package/dist/index-CBcSpGSM.d.mts +3416 -0
- package/dist/index-CBcSpGSM.d.mts.map +1 -0
- package/dist/index-DCVL3jHo.d.mts +634 -0
- package/dist/index-DCVL3jHo.d.mts.map +1 -0
- package/dist/index-p-wBs_wH.d.mts +175 -0
- package/dist/index-p-wBs_wH.d.mts.map +1 -0
- package/dist/index.d.mts +7296 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +9399 -0
- package/dist/index.mjs.map +1 -0
- package/dist/key-mapping-BsUHe_nk.mjs +3 -0
- package/dist/key-mapping-DsyfLEdC.mjs +132 -0
- package/dist/key-mapping-DsyfLEdC.mjs.map +1 -0
- package/dist/layout-engine-B3dsnVLU.mjs +50 -0
- package/dist/layout-engine-B3dsnVLU.mjs.map +1 -0
- package/dist/layout-engine-D_lSR4i9.mjs +2 -0
- package/dist/multi-progress-C0-rkn86.d.mts +180 -0
- package/dist/multi-progress-C0-rkn86.d.mts.map +1 -0
- package/dist/multi-progress-CQVB9lES.mjs +219 -0
- package/dist/multi-progress-CQVB9lES.mjs.map +1 -0
- package/dist/node-Dedx-6xF.mjs +1085 -0
- package/dist/node-Dedx-6xF.mjs.map +1 -0
- package/dist/pipeline-DDOPrjuY.mjs +4387 -0
- package/dist/pipeline-DDOPrjuY.mjs.map +1 -0
- package/dist/progress-bar-COPSBlT9.mjs +155 -0
- package/dist/progress-bar-COPSBlT9.mjs.map +1 -0
- package/dist/reconciler-2lp5VXK7.mjs +16506 -0
- package/dist/reconciler-2lp5VXK7.mjs.map +1 -0
- package/dist/render-string-BXvxTg5P.mjs +201 -0
- package/dist/render-string-BXvxTg5P.mjs.map +1 -0
- package/dist/render-string-hvfpVtoP.mjs +2 -0
- package/dist/resvg-js-V6oMi8CY.mjs +203 -0
- package/dist/resvg-js-V6oMi8CY.mjs.map +1 -0
- package/dist/runtime-BjDHNTxJ.mjs +8723 -0
- package/dist/runtime-BjDHNTxJ.mjs.map +1 -0
- package/dist/runtime.d.mts +2 -0
- package/dist/runtime.mjs +3 -0
- package/dist/spinner-Cgej6Vnb.d.mts +127 -0
- package/dist/spinner-Cgej6Vnb.d.mts.map +1 -0
- package/dist/spinner-DSByknyx.mjs +298 -0
- package/dist/spinner-DSByknyx.mjs.map +1 -0
- package/dist/src-9B5k0JmY.mjs +1629 -0
- package/dist/src-9B5k0JmY.mjs.map +1 -0
- package/dist/src-C9f3hiVG.mjs +3620 -0
- package/dist/src-C9f3hiVG.mjs.map +1 -0
- package/dist/src-fJVbhdn-.mjs +816 -0
- package/dist/src-fJVbhdn-.mjs.map +1 -0
- package/dist/theme.d.mts +115 -0
- package/dist/theme.d.mts.map +1 -0
- package/dist/theme.mjs +8 -0
- package/dist/theme.mjs.map +1 -0
- package/dist/types-Bhj5QkIQ.mjs +13 -0
- package/dist/types-Bhj5QkIQ.mjs.map +1 -0
- package/dist/types-CDgkE-Rw.d.mts +241 -0
- package/dist/types-CDgkE-Rw.d.mts.map +1 -0
- package/dist/ui/animation.d.mts +2 -0
- package/dist/ui/animation.mjs +2 -0
- package/dist/ui/ansi.d.mts +2 -0
- package/dist/ui/ansi.mjs +2 -0
- package/dist/ui/cli.d.mts +5 -0
- package/dist/ui/cli.mjs +7 -0
- package/dist/ui/display.d.mts +35 -0
- package/dist/ui/display.d.mts.map +1 -0
- package/dist/ui/display.mjs +123 -0
- package/dist/ui/display.mjs.map +1 -0
- package/dist/ui/image.d.mts +2 -0
- package/dist/ui/image.mjs +2 -0
- package/dist/ui/input.d.mts +184 -0
- package/dist/ui/input.d.mts.map +1 -0
- package/dist/ui/input.mjs +285 -0
- package/dist/ui/input.mjs.map +1 -0
- package/dist/ui/progress.d.mts +249 -0
- package/dist/ui/progress.d.mts.map +1 -0
- package/dist/ui/progress.mjs +858 -0
- package/dist/ui/progress.mjs.map +1 -0
- package/dist/ui/react.d.mts +280 -0
- package/dist/ui/react.d.mts.map +1 -0
- package/dist/ui/react.mjs +413 -0
- package/dist/ui/react.mjs.map +1 -0
- package/dist/ui/utils.d.mts +86 -0
- package/dist/ui/utils.d.mts.map +1 -0
- package/dist/ui/utils.mjs +2 -0
- package/dist/ui/wrappers.d.mts +3 -0
- package/dist/ui/wrappers.mjs +2 -0
- package/dist/ui.d.mts +6 -0
- package/dist/ui.mjs +7 -0
- package/dist/useLatest-BMIYXd6e.d.mts +154 -0
- package/dist/useLatest-BMIYXd6e.d.mts.map +1 -0
- package/dist/useLayout-BG2cGl15.mjs +139 -0
- package/dist/useLayout-BG2cGl15.mjs.map +1 -0
- package/dist/with-text-input-CmHf_9d6.d.mts +284 -0
- package/dist/with-text-input-CmHf_9d6.d.mts.map +1 -0
- package/dist/wrapper-Dqh0zi2W.mjs +3527 -0
- package/dist/wrapper-Dqh0zi2W.mjs.map +1 -0
- package/dist/wrappers-hhL8EQ_n.mjs +810 -0
- package/dist/wrappers-hhL8EQ_n.mjs.map +1 -0
- package/dist/yoga-adapter-BJ9SOhTY.mjs +245 -0
- package/dist/yoga-adapter-BJ9SOhTY.mjs.map +1 -0
- package/dist/yoga-adapter-Daq6-dw1.mjs +2 -0
- package/package.json +48 -75
- package/CHANGELOG.md +0 -319
- package/dist/chalk.js +0 -4
- package/dist/index.js +0 -270
- package/dist/ink.js +0 -142
- package/dist/runtime.js +0 -135
- package/dist/theme.js +0 -7
- package/dist/ui/animation.js +0 -3
- package/dist/ui/ansi.js +0 -3
- package/dist/ui/cli.js +0 -9
- package/dist/ui/display.js +0 -4
- package/dist/ui/image.js +0 -4
- package/dist/ui/input.js +0 -3
- package/dist/ui/progress.js +0 -9
- package/dist/ui/react.js +0 -4
- package/dist/ui/utils.js +0 -3
- package/dist/ui/wrappers.js +0 -15
- package/dist/ui.js +0 -18
- package/src/index.ts +0 -73
- package/src/runtime.ts +0 -4
- package/src/theme.ts +0 -4
- package/src/ui/animation.ts +0 -2
- package/src/ui/ansi.ts +0 -2
- package/src/ui/cli.ts +0 -3
- package/src/ui/display.ts +0 -2
- package/src/ui/image.ts +0 -2
- package/src/ui/input.ts +0 -2
- package/src/ui/progress.ts +0 -2
- package/src/ui/react.ts +0 -2
- package/src/ui/utils.ts +0 -2
- package/src/ui/wrappers.ts +0 -2
- package/src/ui.ts +0 -4
|
@@ -0,0 +1,3416 @@
|
|
|
1
|
+
import { Nt as ColorLevel, Pt as TerminalCaps, jt as Theme } from "./index-DCVL3jHo.mjs";
|
|
2
|
+
import * as _$react from "react";
|
|
3
|
+
import React$1, { ReactElement } from "react";
|
|
4
|
+
|
|
5
|
+
//#region packages/ag/src/drag-event-types.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Drag event payload passed to handler props.
|
|
8
|
+
*/
|
|
9
|
+
interface DragEventPayload {
|
|
10
|
+
/** The node being dragged */
|
|
11
|
+
source: AgNode;
|
|
12
|
+
/** Current terminal position of the pointer */
|
|
13
|
+
position: {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
};
|
|
17
|
+
/** The node under the cursor (the drop target receiving this event) */
|
|
18
|
+
dropTarget: AgNode | null;
|
|
19
|
+
}
|
|
20
|
+
interface DragEventProps {
|
|
21
|
+
/** Fired when a dragged node enters this node's bounds */
|
|
22
|
+
onDragEnter?: (event: DragEventPayload) => void;
|
|
23
|
+
/** Fired when a dragged node leaves this node's bounds */
|
|
24
|
+
onDragLeave?: (event: DragEventPayload) => void;
|
|
25
|
+
/** Fired repeatedly as a dragged node moves over this node */
|
|
26
|
+
onDragOver?: (event: DragEventPayload) => void;
|
|
27
|
+
/** Fired when a dragged node is dropped on this node */
|
|
28
|
+
onDrop?: (event: DragEventPayload) => void;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region packages/ag/src/keys.d.ts
|
|
32
|
+
/**
|
|
33
|
+
* Keyboard Constants and Utilities
|
|
34
|
+
*
|
|
35
|
+
* Single source of truth for all key parsing, mapping, and matching in silvery.
|
|
36
|
+
*
|
|
37
|
+
* ## Two-Layer Input Architecture
|
|
38
|
+
*
|
|
39
|
+
* parseKey() returns `[input, key]` where these serve DIFFERENT purposes:
|
|
40
|
+
*
|
|
41
|
+
* - `input` is **normalized for keybinding matching**. Shifted punctuation is
|
|
42
|
+
* decomposed: '#' becomes input='3' with key.shift=true, so keybindings
|
|
43
|
+
* like 'shift-3' can match. Uppercase letters become lowercase + shift.
|
|
44
|
+
*
|
|
45
|
+
* - `key.text` is the **actual typed character** (pre-normalization). For text
|
|
46
|
+
* insertion, always use `key.text ?? input` — this ensures Shift+3 inserts
|
|
47
|
+
* '#', opt+e inserts '´', and IME output inserts the composed string.
|
|
48
|
+
*
|
|
49
|
+
* Rule: keybinding resolution uses `input`. Text insertion uses `key.text`.
|
|
50
|
+
* Never reconstruct characters from key codes — trust what the terminal sent.
|
|
51
|
+
*
|
|
52
|
+
* - KEY_MAP: Playwright key names -> ANSI sequences (for sending input)
|
|
53
|
+
* - CODE_TO_KEY: ANSI escape suffixes -> key names (for parsing input)
|
|
54
|
+
* - Key interface: structured key object with boolean flags
|
|
55
|
+
* - parseKeypress(): raw terminal input -> ParsedKeypress
|
|
56
|
+
* - parseKey(): raw terminal input -> [input, Key]
|
|
57
|
+
* - keyToAnsi(): Playwright key string -> ANSI sequence
|
|
58
|
+
* - keyToName(): Key object -> named key string
|
|
59
|
+
* - keyToModifiers(): Key object -> modifier flags
|
|
60
|
+
* - parseHotkey(): "ctrl+shift+a" -> ParsedHotkey
|
|
61
|
+
* - matchHotkey(): match ParsedHotkey against Key
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* import { keyToAnsi } from '@silvery/test'
|
|
66
|
+
*
|
|
67
|
+
* // Convert key names to ANSI
|
|
68
|
+
* keyToAnsi('Enter') // '\r'
|
|
69
|
+
* keyToAnsi('ArrowUp') // '\x1b[A'
|
|
70
|
+
* keyToAnsi('Control+c') // '\x03'
|
|
71
|
+
* keyToAnsi('a') // 'a'
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* Key object describing which special keys/modifiers were pressed.
|
|
76
|
+
*/
|
|
77
|
+
interface Key {
|
|
78
|
+
/** Up arrow key was pressed */
|
|
79
|
+
upArrow: boolean;
|
|
80
|
+
/** Down arrow key was pressed */
|
|
81
|
+
downArrow: boolean;
|
|
82
|
+
/** Left arrow key was pressed */
|
|
83
|
+
leftArrow: boolean;
|
|
84
|
+
/** Right arrow key was pressed */
|
|
85
|
+
rightArrow: boolean;
|
|
86
|
+
/** Page Down key was pressed */
|
|
87
|
+
pageDown: boolean;
|
|
88
|
+
/** Page Up key was pressed */
|
|
89
|
+
pageUp: boolean;
|
|
90
|
+
/** Home key was pressed */
|
|
91
|
+
home: boolean;
|
|
92
|
+
/** End key was pressed */
|
|
93
|
+
end: boolean;
|
|
94
|
+
/** Return (Enter) key was pressed */
|
|
95
|
+
return: boolean;
|
|
96
|
+
/** Escape key was pressed */
|
|
97
|
+
escape: boolean;
|
|
98
|
+
/** Ctrl key was pressed */
|
|
99
|
+
ctrl: boolean;
|
|
100
|
+
/** Shift key was pressed */
|
|
101
|
+
shift: boolean;
|
|
102
|
+
/** Tab key was pressed */
|
|
103
|
+
tab: boolean;
|
|
104
|
+
/** Backspace key was pressed */
|
|
105
|
+
backspace: boolean;
|
|
106
|
+
/** Delete key was pressed */
|
|
107
|
+
delete: boolean;
|
|
108
|
+
/** Meta key (Alt/Option on macOS, Alt on other platforms) was pressed */
|
|
109
|
+
meta: boolean;
|
|
110
|
+
/** Super key (Cmd on macOS, Win on Windows) was pressed. Requires Kitty protocol. */
|
|
111
|
+
super: boolean;
|
|
112
|
+
/** Hyper key was pressed. Requires Kitty protocol. */
|
|
113
|
+
hyper: boolean;
|
|
114
|
+
/** CapsLock is active. Requires Kitty protocol. */
|
|
115
|
+
capsLock: boolean;
|
|
116
|
+
/** NumLock is active. Requires Kitty protocol. */
|
|
117
|
+
numLock: boolean;
|
|
118
|
+
/** Kitty event type. Only set with Kitty flag 2 (report events). */
|
|
119
|
+
eventType?: "press" | "repeat" | "release";
|
|
120
|
+
/** The actual text character typed (pre-normalization). For text insertion,
|
|
121
|
+
* use this instead of the normalized `input` which maps shifted chars to base keys. */
|
|
122
|
+
text?: string;
|
|
123
|
+
/** True when the key is a modifier pressed alone (Shift, Ctrl, Alt, Super, Hyper, Meta).
|
|
124
|
+
* Set during parsing for Kitty protocol modifier-only events. */
|
|
125
|
+
isModifierOnly?: boolean;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Input handler callback type.
|
|
129
|
+
* Return 'exit' to exit the app.
|
|
130
|
+
*/
|
|
131
|
+
type InputHandler = (input: string, key: Key) => void | "exit";
|
|
132
|
+
/**
|
|
133
|
+
* Parsed hotkey from a string like "ctrl+shift+a" or "Control+ArrowUp".
|
|
134
|
+
*/
|
|
135
|
+
interface ParsedHotkey {
|
|
136
|
+
key: string;
|
|
137
|
+
ctrl: boolean;
|
|
138
|
+
meta: boolean;
|
|
139
|
+
shift: boolean;
|
|
140
|
+
alt: boolean;
|
|
141
|
+
super: boolean;
|
|
142
|
+
hyper: boolean;
|
|
143
|
+
}
|
|
144
|
+
interface ParsedKeypress {
|
|
145
|
+
name: string;
|
|
146
|
+
ctrl: boolean;
|
|
147
|
+
meta: boolean;
|
|
148
|
+
shift: boolean;
|
|
149
|
+
option: boolean;
|
|
150
|
+
super: boolean;
|
|
151
|
+
hyper: boolean;
|
|
152
|
+
/** Kitty event type. Only set with Kitty flag 2 (report events). */
|
|
153
|
+
eventType?: "press" | "repeat" | "release";
|
|
154
|
+
/** The character when Shift is held. From Kitty shifted_codepoint. */
|
|
155
|
+
shiftedKey?: string;
|
|
156
|
+
/** The key on a standard US layout (for non-Latin keyboards). From Kitty base_layout_key. */
|
|
157
|
+
baseLayoutKey?: string;
|
|
158
|
+
/** CapsLock is active. Kitty modifier bit 6. */
|
|
159
|
+
capsLock?: boolean;
|
|
160
|
+
/** NumLock is active. Kitty modifier bit 7. */
|
|
161
|
+
numLock?: boolean;
|
|
162
|
+
/** Decoded text from Kitty REPORT_TEXT mode. */
|
|
163
|
+
associatedText?: string;
|
|
164
|
+
sequence: string;
|
|
165
|
+
/** Raw input string, identical to sequence for most keys. */
|
|
166
|
+
raw?: string;
|
|
167
|
+
code?: string;
|
|
168
|
+
/** Whether this key was parsed from the Kitty keyboard protocol. */
|
|
169
|
+
isKittyProtocol?: boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Whether this key represents printable text input.
|
|
172
|
+
* When false, the key is a control/function/modifier key that should not
|
|
173
|
+
* produce text input (e.g., arrows, function keys, capslock, media keys).
|
|
174
|
+
* Only set by the kitty protocol parser.
|
|
175
|
+
*/
|
|
176
|
+
isPrintable?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Text associated with the key.
|
|
179
|
+
* For printable kitty keys, defaults to the character from the codepoint.
|
|
180
|
+
* When REPORT_TEXT flag is active, contains the decoded text-as-codepoints.
|
|
181
|
+
*/
|
|
182
|
+
text?: string;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Parse a raw input sequence into a structured keypress object.
|
|
186
|
+
* Accepts string or Buffer (Buffer support for stdin compatibility).
|
|
187
|
+
*/
|
|
188
|
+
declare function parseKeypress(s: string | Buffer): ParsedKeypress;
|
|
189
|
+
/**
|
|
190
|
+
* Parse raw terminal input into a Key object and cleaned input string.
|
|
191
|
+
*
|
|
192
|
+
* @param rawInput Raw terminal input (string or Buffer)
|
|
193
|
+
* @returns Tuple of [cleanedInput, Key]
|
|
194
|
+
*/
|
|
195
|
+
declare function parseKey(rawInput: string | Buffer): [string, Key];
|
|
196
|
+
/**
|
|
197
|
+
* Create an empty Key object (all fields false).
|
|
198
|
+
*/
|
|
199
|
+
declare function emptyKey(): Key;
|
|
200
|
+
/**
|
|
201
|
+
* Convert a Key object to a named key string.
|
|
202
|
+
*
|
|
203
|
+
* Returns the Playwright-compatible name for special keys (ArrowUp, Enter, etc.)
|
|
204
|
+
* or "" if no special key is pressed.
|
|
205
|
+
*/
|
|
206
|
+
declare function keyToName(key: Key): string;
|
|
207
|
+
/**
|
|
208
|
+
* Extract modifier flags from a Key object.
|
|
209
|
+
* `alt` is always false (terminals cannot distinguish alt from meta).
|
|
210
|
+
*/
|
|
211
|
+
declare function keyToModifiers(key: Key): {
|
|
212
|
+
ctrl: boolean;
|
|
213
|
+
meta: boolean;
|
|
214
|
+
shift: boolean;
|
|
215
|
+
alt: boolean;
|
|
216
|
+
super: boolean;
|
|
217
|
+
hyper: boolean;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Parse a hotkey string into base key and modifiers.
|
|
221
|
+
*
|
|
222
|
+
* Supports Playwright-style ("Control+c", "Shift+ArrowUp") and
|
|
223
|
+
* lowercase aliases ("ctrl+c", "shift+tab", "cmd+a").
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```tsx
|
|
227
|
+
* parseHotkey('j') // { key: 'j', ctrl: false, meta: false, shift: false, alt: false }
|
|
228
|
+
* parseHotkey('Control+c') // { key: 'c', ctrl: true, ... }
|
|
229
|
+
* parseHotkey('Shift+ArrowUp') // { key: 'ArrowUp', shift: true, ... }
|
|
230
|
+
* parseHotkey('⌘j') // { key: 'j', super: true, ... } (macOS symbol prefix)
|
|
231
|
+
* parseHotkey('⌃⇧a') // { key: 'a', ctrl: true, shift: true, ... }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
declare function parseHotkey(keyStr: string): ParsedHotkey;
|
|
235
|
+
/**
|
|
236
|
+
* Match a parsed hotkey against a Key object and input string.
|
|
237
|
+
*
|
|
238
|
+
* @param hotkey Parsed hotkey to match
|
|
239
|
+
* @param key Key object from input event
|
|
240
|
+
* @param input Optional input string (for matching character keys)
|
|
241
|
+
* @returns true if the hotkey matches the key event
|
|
242
|
+
*/
|
|
243
|
+
declare function matchHotkey(hotkey: ParsedHotkey, key: Key, input?: string): boolean;
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region packages/ag/src/focus-events.d.ts
|
|
246
|
+
/**
|
|
247
|
+
* Synthetic keyboard event, mirroring React.KeyboardEvent / DOM KeyboardEvent.
|
|
248
|
+
*/
|
|
249
|
+
interface SilveryKeyEvent {
|
|
250
|
+
/** The printable character, or "" for non-printable keys */
|
|
251
|
+
key: string;
|
|
252
|
+
/** Raw terminal input string */
|
|
253
|
+
input: string;
|
|
254
|
+
/** Modifier keys */
|
|
255
|
+
ctrl: boolean;
|
|
256
|
+
meta: boolean;
|
|
257
|
+
shift: boolean;
|
|
258
|
+
super: boolean;
|
|
259
|
+
hyper: boolean;
|
|
260
|
+
/** Kitty event type */
|
|
261
|
+
eventType?: "press" | "repeat" | "release";
|
|
262
|
+
/** Deepest focusable node that received this event */
|
|
263
|
+
target: AgNode;
|
|
264
|
+
/** Node whose handler is currently firing (changes during capture/bubble) */
|
|
265
|
+
currentTarget: AgNode;
|
|
266
|
+
/** Stop event from propagating further */
|
|
267
|
+
stopPropagation(): void;
|
|
268
|
+
/** Prevent default behavior */
|
|
269
|
+
preventDefault(): void;
|
|
270
|
+
/** Whether stopPropagation() was called */
|
|
271
|
+
readonly propagationStopped: boolean;
|
|
272
|
+
/** Whether preventDefault() was called */
|
|
273
|
+
readonly defaultPrevented: boolean;
|
|
274
|
+
/** Raw parsed key data */
|
|
275
|
+
nativeEvent: {
|
|
276
|
+
input: string;
|
|
277
|
+
key: Key;
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Synthetic focus event, mirroring React.FocusEvent / DOM FocusEvent.
|
|
282
|
+
*/
|
|
283
|
+
interface SilveryFocusEvent {
|
|
284
|
+
/** The node gaining or losing focus */
|
|
285
|
+
target: AgNode;
|
|
286
|
+
/** The other node involved (losing focus on 'focus', gaining on 'blur') */
|
|
287
|
+
relatedTarget: AgNode | null;
|
|
288
|
+
/** Event type */
|
|
289
|
+
type: "focus" | "blur";
|
|
290
|
+
/** Node whose handler is currently firing (changes during bubble) */
|
|
291
|
+
currentTarget: AgNode;
|
|
292
|
+
/** Stop event from bubbling to parent nodes */
|
|
293
|
+
stopPropagation(): void;
|
|
294
|
+
/** Whether stopPropagation() was called */
|
|
295
|
+
readonly propagationStopped: boolean;
|
|
296
|
+
}
|
|
297
|
+
interface FocusEventProps {
|
|
298
|
+
/** Whether this node can receive focus */
|
|
299
|
+
focusable?: boolean;
|
|
300
|
+
/** Whether this node should receive focus on mount */
|
|
301
|
+
autoFocus?: boolean;
|
|
302
|
+
/** Whether this node creates a focus scope (focus trapping boundary) */
|
|
303
|
+
focusScope?: boolean;
|
|
304
|
+
/** ID of the node to focus when pressing Up from this node */
|
|
305
|
+
nextFocusUp?: string;
|
|
306
|
+
/** ID of the node to focus when pressing Down from this node */
|
|
307
|
+
nextFocusDown?: string;
|
|
308
|
+
/** ID of the node to focus when pressing Left from this node */
|
|
309
|
+
nextFocusLeft?: string;
|
|
310
|
+
/** ID of the node to focus when pressing Right from this node */
|
|
311
|
+
nextFocusRight?: string;
|
|
312
|
+
/** Called when this node gains focus */
|
|
313
|
+
onFocus?: (event: SilveryFocusEvent) => void;
|
|
314
|
+
/** Called when this node loses focus */
|
|
315
|
+
onBlur?: (event: SilveryFocusEvent) => void;
|
|
316
|
+
/** Called on key down (bubble phase) */
|
|
317
|
+
onKeyDown?: (event: SilveryKeyEvent, dispatch?: (msg: unknown) => void) => void;
|
|
318
|
+
/** Called on key up (bubble phase) */
|
|
319
|
+
onKeyUp?: (event: SilveryKeyEvent, dispatch?: (msg: unknown) => void) => void;
|
|
320
|
+
/** Called on key down (capture phase — fires before target) */
|
|
321
|
+
onKeyDownCapture?: (event: SilveryKeyEvent) => void;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Create a synthetic keyboard event.
|
|
325
|
+
*/
|
|
326
|
+
declare function createKeyEvent(input: string, key: Key, target: AgNode): SilveryKeyEvent;
|
|
327
|
+
/**
|
|
328
|
+
* Create a synthetic focus event.
|
|
329
|
+
*/
|
|
330
|
+
declare function createFocusEvent(type: "focus" | "blur", target: AgNode, relatedTarget: AgNode | null): SilveryFocusEvent;
|
|
331
|
+
/**
|
|
332
|
+
* Dispatch a keyboard event through the render tree with DOM-style
|
|
333
|
+
* capture/target/bubble phases.
|
|
334
|
+
*
|
|
335
|
+
* For press/repeat events:
|
|
336
|
+
* 1. Capture phase: root → target (onKeyDownCapture props)
|
|
337
|
+
* 2. Target phase: target's onKeyDown
|
|
338
|
+
* 3. Bubble phase: target parent → root (onKeyDown props)
|
|
339
|
+
*
|
|
340
|
+
* For release events:
|
|
341
|
+
* 1. Target phase: target's onKeyUp
|
|
342
|
+
* 2. Bubble phase: target parent → root (onKeyUp props)
|
|
343
|
+
* (No capture phase for keyUp — deliberate simplification; React DOM has onKeyUpCapture)
|
|
344
|
+
*
|
|
345
|
+
* stopPropagation() halts traversal at any phase.
|
|
346
|
+
*/
|
|
347
|
+
declare function dispatchKeyEvent(event: SilveryKeyEvent, dispatch?: (msg: unknown) => void): void;
|
|
348
|
+
/**
|
|
349
|
+
* Dispatch a focus event through the render tree.
|
|
350
|
+
*
|
|
351
|
+
* Fires onFocus/onBlur on the target, then bubbles to ancestors.
|
|
352
|
+
*/
|
|
353
|
+
declare function dispatchFocusEvent(event: SilveryFocusEvent): void;
|
|
354
|
+
//#endregion
|
|
355
|
+
//#region packages/ag/src/layout-types.d.ts
|
|
356
|
+
/**
|
|
357
|
+
* Layout Type Abstractions
|
|
358
|
+
*
|
|
359
|
+
* Pure type interfaces for layout engines (Yoga, Flexily, etc.)
|
|
360
|
+
* These live in @silvery/ag because they're used by core types (AgNode).
|
|
361
|
+
* The runtime layout engine management lives in @silvery/ag-term/layout-engine.
|
|
362
|
+
*/
|
|
363
|
+
/**
|
|
364
|
+
* Measure mode determines how the width/height constraint should be interpreted.
|
|
365
|
+
*/
|
|
366
|
+
type MeasureMode = "undefined" | "exactly" | "at-most";
|
|
367
|
+
/**
|
|
368
|
+
* Measure function callback for intrinsic sizing.
|
|
369
|
+
* Called when a node needs to determine its size based on content.
|
|
370
|
+
*/
|
|
371
|
+
type MeasureFunc = (width: number, widthMode: MeasureMode, height: number, heightMode: MeasureMode) => {
|
|
372
|
+
width: number;
|
|
373
|
+
height: number;
|
|
374
|
+
};
|
|
375
|
+
/**
|
|
376
|
+
* Abstract layout node interface.
|
|
377
|
+
* Represents a single node in the layout tree.
|
|
378
|
+
*/
|
|
379
|
+
interface LayoutNode {
|
|
380
|
+
insertChild(child: LayoutNode, index: number): void;
|
|
381
|
+
removeChild(child: LayoutNode): void;
|
|
382
|
+
free(): void;
|
|
383
|
+
setMeasureFunc(measureFunc: MeasureFunc): void;
|
|
384
|
+
markDirty(): void;
|
|
385
|
+
setWidth(value: number): void;
|
|
386
|
+
setWidthPercent(value: number): void;
|
|
387
|
+
setWidthAuto(): void;
|
|
388
|
+
setHeight(value: number): void;
|
|
389
|
+
setHeightPercent(value: number): void;
|
|
390
|
+
setHeightAuto(): void;
|
|
391
|
+
setMinWidth(value: number): void;
|
|
392
|
+
setMinWidthPercent(value: number): void;
|
|
393
|
+
setMinHeight(value: number): void;
|
|
394
|
+
setMinHeightPercent(value: number): void;
|
|
395
|
+
setMaxWidth(value: number): void;
|
|
396
|
+
setMaxWidthPercent(value: number): void;
|
|
397
|
+
setMaxHeight(value: number): void;
|
|
398
|
+
setMaxHeightPercent(value: number): void;
|
|
399
|
+
setFlexGrow(value: number): void;
|
|
400
|
+
setFlexShrink(value: number): void;
|
|
401
|
+
setFlexBasis(value: number): void;
|
|
402
|
+
setFlexBasisPercent(value: number): void;
|
|
403
|
+
setFlexBasisAuto(): void;
|
|
404
|
+
setFlexDirection(direction: number): void;
|
|
405
|
+
setFlexWrap(wrap: number): void;
|
|
406
|
+
setAlignItems(align: number): void;
|
|
407
|
+
setAlignSelf(align: number): void;
|
|
408
|
+
setAlignContent(align: number): void;
|
|
409
|
+
setJustifyContent(justify: number): void;
|
|
410
|
+
setPadding(edge: number, value: number): void;
|
|
411
|
+
setMargin(edge: number, value: number): void;
|
|
412
|
+
setBorder(edge: number, value: number): void;
|
|
413
|
+
setGap(gutter: number, value: number): void;
|
|
414
|
+
setDisplay(display: number): void;
|
|
415
|
+
setPositionType(positionType: number): void;
|
|
416
|
+
setPosition(edge: number, value: number): void;
|
|
417
|
+
setPositionPercent(edge: number, value: number): void;
|
|
418
|
+
setOverflow(overflow: number): void;
|
|
419
|
+
setAspectRatio(value: number): void;
|
|
420
|
+
calculateLayout(width: number, height: number, direction?: number): void;
|
|
421
|
+
getComputedLeft(): number;
|
|
422
|
+
getComputedTop(): number;
|
|
423
|
+
getComputedWidth(): number;
|
|
424
|
+
getComputedHeight(): number;
|
|
425
|
+
}
|
|
426
|
+
//#endregion
|
|
427
|
+
//#region packages/ag/src/mouse-event-types.d.ts
|
|
428
|
+
/**
|
|
429
|
+
* Synthetic mouse event, mirroring React.MouseEvent / DOM MouseEvent.
|
|
430
|
+
*/
|
|
431
|
+
interface SilveryMouseEvent {
|
|
432
|
+
/** Terminal column (0-indexed) */
|
|
433
|
+
clientX: number;
|
|
434
|
+
/** Terminal row (0-indexed) */
|
|
435
|
+
clientY: number;
|
|
436
|
+
/** Mouse button: 0=left, 1=middle, 2=right */
|
|
437
|
+
button: number;
|
|
438
|
+
/** Modifier keys */
|
|
439
|
+
altKey: boolean;
|
|
440
|
+
ctrlKey: boolean;
|
|
441
|
+
metaKey: boolean;
|
|
442
|
+
shiftKey: boolean;
|
|
443
|
+
/** Deepest node under cursor */
|
|
444
|
+
target: AgNode;
|
|
445
|
+
/** Node whose handler is currently firing (changes during bubble) */
|
|
446
|
+
currentTarget: AgNode;
|
|
447
|
+
/** Event type */
|
|
448
|
+
type: "click" | "dblclick" | "mousedown" | "mouseup" | "mousemove" | "mouseenter" | "mouseleave" | "wheel";
|
|
449
|
+
/** Stop event from bubbling to parent nodes */
|
|
450
|
+
stopPropagation(): void;
|
|
451
|
+
/** Prevent default behavior */
|
|
452
|
+
preventDefault(): void;
|
|
453
|
+
/** Whether stopPropagation() was called */
|
|
454
|
+
readonly propagationStopped: boolean;
|
|
455
|
+
/** Whether preventDefault() was called */
|
|
456
|
+
readonly defaultPrevented: boolean;
|
|
457
|
+
/** Raw parsed mouse data from terminal protocol */
|
|
458
|
+
nativeEvent: unknown;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Synthetic wheel event, extending SilveryMouseEvent with scroll deltas.
|
|
462
|
+
*/
|
|
463
|
+
interface SilveryWheelEvent extends SilveryMouseEvent {
|
|
464
|
+
/** Vertical scroll: -1 (up) or +1 (down) */
|
|
465
|
+
deltaY: number;
|
|
466
|
+
/** Horizontal scroll: always 0 for terminals */
|
|
467
|
+
deltaX: number;
|
|
468
|
+
}
|
|
469
|
+
interface MouseEventProps {
|
|
470
|
+
onClick?: (event: SilveryMouseEvent) => void;
|
|
471
|
+
onDoubleClick?: (event: SilveryMouseEvent) => void;
|
|
472
|
+
onMouseDown?: (event: SilveryMouseEvent) => void;
|
|
473
|
+
onMouseUp?: (event: SilveryMouseEvent) => void;
|
|
474
|
+
onMouseMove?: (event: SilveryMouseEvent) => void;
|
|
475
|
+
onMouseEnter?: (event: SilveryMouseEvent) => void;
|
|
476
|
+
onMouseLeave?: (event: SilveryMouseEvent) => void;
|
|
477
|
+
onWheel?: (event: SilveryWheelEvent) => void;
|
|
478
|
+
}
|
|
479
|
+
//#endregion
|
|
480
|
+
//#region packages/ag/src/types.d.ts
|
|
481
|
+
/**
|
|
482
|
+
* CSS user-select equivalent for controlling text selectability.
|
|
483
|
+
* - "auto": inherit from parent (root resolves to "text")
|
|
484
|
+
* - "none": not selectable
|
|
485
|
+
* - "text": force selectable (overrides parent "none")
|
|
486
|
+
* - "contain": selectable, but selection cannot escape this node's bounds
|
|
487
|
+
*/
|
|
488
|
+
type UserSelect = "auto" | "none" | "text" | "contain";
|
|
489
|
+
/**
|
|
490
|
+
* A rectangle with position and size.
|
|
491
|
+
* All values are in terminal columns/rows (integers).
|
|
492
|
+
*/
|
|
493
|
+
interface Rect {
|
|
494
|
+
/** X position (0-indexed terminal column) */
|
|
495
|
+
x: number;
|
|
496
|
+
/** Y position (0-indexed terminal row) */
|
|
497
|
+
y: number;
|
|
498
|
+
/** Width in terminal columns */
|
|
499
|
+
width: number;
|
|
500
|
+
/** Height in terminal rows */
|
|
501
|
+
height: number;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Per-node interactive state — written by pointer/selection/focus state machines,
|
|
505
|
+
* read by theme/render for automatic styling.
|
|
506
|
+
*
|
|
507
|
+
* These are plain mutable booleans, NOT reactive signals. State machines set them
|
|
508
|
+
* synchronously during event processing, and the next render reads them.
|
|
509
|
+
* React re-renders are driven by the event processing, not signal subscriptions.
|
|
510
|
+
*
|
|
511
|
+
* The object is lazily created on first write to avoid overhead on non-interactive nodes.
|
|
512
|
+
*/
|
|
513
|
+
interface InteractiveState {
|
|
514
|
+
/** Pointer is over this node (mouseenter/mouseleave) */
|
|
515
|
+
hovered: boolean;
|
|
516
|
+
/** Pointer-down on this node, awaiting pointer-up (will receive click) */
|
|
517
|
+
armed: boolean;
|
|
518
|
+
/** Node is in the current selection set */
|
|
519
|
+
selected: boolean;
|
|
520
|
+
/** Node has keyboard focus */
|
|
521
|
+
focused: boolean;
|
|
522
|
+
/** A drag operation is hovering over this node */
|
|
523
|
+
dropTarget: boolean;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Silvery node types - the primitive elements in the render tree.
|
|
527
|
+
*/
|
|
528
|
+
type AgNodeType = "silvery-root" | "silvery-box" | "silvery-text";
|
|
529
|
+
/**
|
|
530
|
+
* Flexbox properties that can be applied to Box nodes.
|
|
531
|
+
*/
|
|
532
|
+
interface FlexboxProps {
|
|
533
|
+
width?: number | string;
|
|
534
|
+
height?: number | string;
|
|
535
|
+
minWidth?: number | string;
|
|
536
|
+
minHeight?: number | string;
|
|
537
|
+
maxWidth?: number | string;
|
|
538
|
+
maxHeight?: number | string;
|
|
539
|
+
flexGrow?: number;
|
|
540
|
+
flexShrink?: number;
|
|
541
|
+
flexBasis?: number | string;
|
|
542
|
+
flexDirection?: "row" | "column" | "row-reverse" | "column-reverse";
|
|
543
|
+
flexWrap?: "nowrap" | "wrap" | "wrap-reverse";
|
|
544
|
+
alignItems?: "flex-start" | "flex-end" | "center" | "stretch" | "baseline";
|
|
545
|
+
alignSelf?: "auto" | "flex-start" | "flex-end" | "center" | "stretch" | "baseline";
|
|
546
|
+
alignContent?: "flex-start" | "flex-end" | "center" | "stretch" | "space-between" | "space-around" | "space-evenly";
|
|
547
|
+
justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
|
|
548
|
+
padding?: number;
|
|
549
|
+
paddingTop?: number;
|
|
550
|
+
paddingBottom?: number;
|
|
551
|
+
paddingLeft?: number;
|
|
552
|
+
paddingRight?: number;
|
|
553
|
+
paddingX?: number;
|
|
554
|
+
paddingY?: number;
|
|
555
|
+
margin?: number;
|
|
556
|
+
marginTop?: number;
|
|
557
|
+
marginBottom?: number;
|
|
558
|
+
marginLeft?: number;
|
|
559
|
+
marginRight?: number;
|
|
560
|
+
marginX?: number;
|
|
561
|
+
marginY?: number;
|
|
562
|
+
gap?: number;
|
|
563
|
+
columnGap?: number;
|
|
564
|
+
rowGap?: number;
|
|
565
|
+
position?: "relative" | "absolute" | "sticky" | "static";
|
|
566
|
+
top?: number | string;
|
|
567
|
+
left?: number | string;
|
|
568
|
+
bottom?: number | string;
|
|
569
|
+
right?: number | string;
|
|
570
|
+
stickyTop?: number;
|
|
571
|
+
stickyBottom?: number;
|
|
572
|
+
aspectRatio?: number;
|
|
573
|
+
display?: "flex" | "none";
|
|
574
|
+
overflow?: "visible" | "hidden" | "scroll";
|
|
575
|
+
overflowX?: "visible" | "hidden";
|
|
576
|
+
overflowY?: "visible" | "hidden";
|
|
577
|
+
/** Child index to ensure visible (edge-based: only scrolls if off-screen) */
|
|
578
|
+
scrollTo?: number;
|
|
579
|
+
/** Explicit scroll offset in rows (used when scrollTo is undefined for frozen scroll state) */
|
|
580
|
+
scrollOffset?: number;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Props for testing and identification.
|
|
584
|
+
* These props are stored in the node for DOM query access.
|
|
585
|
+
*/
|
|
586
|
+
interface TestProps {
|
|
587
|
+
/** Element ID for DOM queries and visual debugging */
|
|
588
|
+
id?: string;
|
|
589
|
+
/** Test ID for querying nodes (like Playwright's data-testid) */
|
|
590
|
+
testID?: string;
|
|
591
|
+
/** Allow arbitrary data-* attributes for testing */
|
|
592
|
+
[key: `data-${string}`]: unknown;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Underline style variants (SGR 4:x codes).
|
|
596
|
+
* - false: no underline
|
|
597
|
+
* - 'single': standard underline (SGR 4 or 4:1)
|
|
598
|
+
* - 'double': double underline (SGR 4:2)
|
|
599
|
+
* - 'curly': curly/wavy underline (SGR 4:3)
|
|
600
|
+
* - 'dotted': dotted underline (SGR 4:4)
|
|
601
|
+
* - 'dashed': dashed underline (SGR 4:5)
|
|
602
|
+
*/
|
|
603
|
+
type UnderlineStyle$1 = false | "single" | "double" | "curly" | "dotted" | "dashed";
|
|
604
|
+
/**
|
|
605
|
+
* Style properties for text rendering.
|
|
606
|
+
*/
|
|
607
|
+
interface StyleProps {
|
|
608
|
+
color?: string;
|
|
609
|
+
backgroundColor?: string;
|
|
610
|
+
bold?: boolean;
|
|
611
|
+
dim?: boolean;
|
|
612
|
+
/** Alias for dim (Ink compatibility) */
|
|
613
|
+
dimColor?: boolean;
|
|
614
|
+
italic?: boolean;
|
|
615
|
+
/** Enable underline. Use underlineStyle for style variants. */
|
|
616
|
+
underline?: boolean;
|
|
617
|
+
/**
|
|
618
|
+
* Underline style variant: 'single' | 'double' | 'curly' | 'dotted' | 'dashed'.
|
|
619
|
+
* Setting this implies underline=true. Takes precedence over underline prop.
|
|
620
|
+
*/
|
|
621
|
+
underlineStyle?: UnderlineStyle$1;
|
|
622
|
+
/**
|
|
623
|
+
* Underline color (independent of text color).
|
|
624
|
+
* Uses SGR 58 (underline color). Falls back to text color if not specified.
|
|
625
|
+
*/
|
|
626
|
+
underlineColor?: string;
|
|
627
|
+
strikethrough?: boolean;
|
|
628
|
+
inverse?: boolean;
|
|
629
|
+
/**
|
|
630
|
+
* Text size scale factor via OSC 66 (Kitty v0.40+).
|
|
631
|
+
*
|
|
632
|
+
* Float multiplier: 2.0 = double (headings), 1.0 = normal, 0.5 = half (small print).
|
|
633
|
+
* The terminal renders subsequent text at this scale until reset.
|
|
634
|
+
* Requires a terminal that supports the kitty text sizing protocol.
|
|
635
|
+
* Terminals without support silently ignore the escape sequence.
|
|
636
|
+
*/
|
|
637
|
+
textSize?: number;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Props for Box component.
|
|
641
|
+
*/
|
|
642
|
+
interface BoxProps extends FlexboxProps, StyleProps, TestProps, MouseEventProps, DragEventProps, FocusEventProps {
|
|
643
|
+
/** Text truncation mode for child text content (passed through to Text children). */
|
|
644
|
+
wrap?: "wrap" | "hard" | "even" | "truncate" | "truncate-start" | "truncate-middle" | "truncate-end" | "clip" | boolean;
|
|
645
|
+
borderStyle?: "single" | "double" | "round" | "bold" | "singleDouble" | "doubleSingle" | "classic";
|
|
646
|
+
borderColor?: string;
|
|
647
|
+
/** Background color for all border sides (shorthand). Per-side props override this. */
|
|
648
|
+
borderBackgroundColor?: string;
|
|
649
|
+
/** Background color for the top border (overrides borderBackgroundColor). */
|
|
650
|
+
borderTopBackgroundColor?: string;
|
|
651
|
+
/** Background color for the bottom border (overrides borderBackgroundColor). */
|
|
652
|
+
borderBottomBackgroundColor?: string;
|
|
653
|
+
/** Background color for the left border (overrides borderBackgroundColor). */
|
|
654
|
+
borderLeftBackgroundColor?: string;
|
|
655
|
+
/** Background color for the right border (overrides borderBackgroundColor). */
|
|
656
|
+
borderRightBackgroundColor?: string;
|
|
657
|
+
borderTop?: boolean;
|
|
658
|
+
borderBottom?: boolean;
|
|
659
|
+
borderLeft?: boolean;
|
|
660
|
+
borderRight?: boolean;
|
|
661
|
+
/**
|
|
662
|
+
* Outline style — renders border characters at the box edges without affecting layout.
|
|
663
|
+
*
|
|
664
|
+
* Unlike `borderStyle` which adds border dimensions to the layout (making the content
|
|
665
|
+
* area smaller), `outlineStyle` draws border characters that OVERLAP the content area.
|
|
666
|
+
* The layout engine sees no border at all — outline is purely visual.
|
|
667
|
+
*
|
|
668
|
+
* Use cases: selection indicators, hover highlights, focus rings — anything that
|
|
669
|
+
* should visually frame a box without shifting content.
|
|
670
|
+
*/
|
|
671
|
+
outlineStyle?: "single" | "double" | "round" | "bold" | "singleDouble" | "doubleSingle" | "classic";
|
|
672
|
+
/** Foreground color for the outline */
|
|
673
|
+
outlineColor?: string;
|
|
674
|
+
/** Apply dim styling to the outline */
|
|
675
|
+
outlineDimColor?: boolean;
|
|
676
|
+
/** Show top outline edge (default: true) */
|
|
677
|
+
outlineTop?: boolean;
|
|
678
|
+
/** Show bottom outline edge (default: true) */
|
|
679
|
+
outlineBottom?: boolean;
|
|
680
|
+
/** Show left outline edge (default: true) */
|
|
681
|
+
outlineLeft?: boolean;
|
|
682
|
+
/** Show right outline edge (default: true) */
|
|
683
|
+
outlineRight?: boolean;
|
|
684
|
+
/**
|
|
685
|
+
* Override theme for this subtree — $token colors resolve against this theme.
|
|
686
|
+
* Pushed onto the context theme stack during render phase tree walk.
|
|
687
|
+
*/
|
|
688
|
+
theme?: Theme;
|
|
689
|
+
/** CSS pointer-events equivalent. "none" makes this node and its subtree invisible to hit testing. */
|
|
690
|
+
pointerEvents?: "auto" | "none";
|
|
691
|
+
/**
|
|
692
|
+
* CSS user-select equivalent. Controls whether text in this node is selectable.
|
|
693
|
+
* - "auto" (default): inherit from parent. Root resolves to "text".
|
|
694
|
+
* - "none": not selectable. Mouse-drag on this node does not start text selection.
|
|
695
|
+
* - "text": force selectable, even if parent is "none".
|
|
696
|
+
* - "contain": selectable, but selection range cannot escape this node's bounds.
|
|
697
|
+
*/
|
|
698
|
+
userSelect?: UserSelect;
|
|
699
|
+
/**
|
|
700
|
+
* Whether this node can be dragged via mouse.
|
|
701
|
+
* When true, mousedown + drag past threshold initiates a node drag gesture
|
|
702
|
+
* instead of text selection. Not inherited — only the node with draggable=true
|
|
703
|
+
* is draggable, not its children.
|
|
704
|
+
*/
|
|
705
|
+
draggable?: boolean;
|
|
706
|
+
onLayout?: (layout: Rect) => void;
|
|
707
|
+
/**
|
|
708
|
+
* Show scroll overflow indicators (▲N / ▼N) for scrollable containers.
|
|
709
|
+
*
|
|
710
|
+
* For bordered containers, indicators appear on the border.
|
|
711
|
+
* For borderless containers, indicators overlay the content at top-right/bottom-right.
|
|
712
|
+
*
|
|
713
|
+
* Only applies when overflow='scroll'.
|
|
714
|
+
*/
|
|
715
|
+
overflowIndicator?: boolean;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Props for Text component.
|
|
719
|
+
*/
|
|
720
|
+
interface TextProps extends StyleProps, TestProps, MouseEventProps {
|
|
721
|
+
children?: React.ReactNode;
|
|
722
|
+
wrap?: "wrap" | "hard" | "even" | "truncate" | "truncate-start" | "truncate-middle" | "truncate-end" | "clip" | boolean;
|
|
723
|
+
/** Internal transform function applied to each rendered line. Used by Transform component. */
|
|
724
|
+
internal_transform?: (line: string, index: number) => string;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* The core Silvery node - represents an element in the render tree.
|
|
728
|
+
*
|
|
729
|
+
* Each node has:
|
|
730
|
+
* - A Yoga node for layout calculation
|
|
731
|
+
* - Computed layout after Yoga runs
|
|
732
|
+
* - Subscribers that get notified when layout changes
|
|
733
|
+
* - Dirty flags for incremental updates
|
|
734
|
+
*/
|
|
735
|
+
interface AgNode {
|
|
736
|
+
/** Node type */
|
|
737
|
+
type: AgNodeType;
|
|
738
|
+
/** Props passed to this node */
|
|
739
|
+
props: BoxProps | TextProps | Record<string, unknown>;
|
|
740
|
+
/** Child nodes */
|
|
741
|
+
children: AgNode[];
|
|
742
|
+
/** Parent node (null for root) */
|
|
743
|
+
parent: AgNode | null;
|
|
744
|
+
/** The layout node for layout calculation (null for raw text nodes) */
|
|
745
|
+
layoutNode: LayoutNode | null;
|
|
746
|
+
/** Computed layout from previous render (for change detection) */
|
|
747
|
+
prevLayout: Rect | null;
|
|
748
|
+
/**
|
|
749
|
+
* Content-relative position (like CSS offsetTop/offsetLeft).
|
|
750
|
+
* Position within the scrollable content, ignoring scroll offsets.
|
|
751
|
+
* Set after layout phase.
|
|
752
|
+
*/
|
|
753
|
+
boxRect: Rect | null;
|
|
754
|
+
/**
|
|
755
|
+
* Screen-relative position (like CSS getBoundingClientRect).
|
|
756
|
+
* Actual position on the terminal screen, accounting for scroll offsets.
|
|
757
|
+
* Set after screen rect phase.
|
|
758
|
+
*
|
|
759
|
+
* Note: For sticky children, this reflects the node's layout position
|
|
760
|
+
* adjusted for scroll offsets, NOT the actual render position. Use
|
|
761
|
+
* `screenRect` for the actual pixel position on screen.
|
|
762
|
+
*/
|
|
763
|
+
scrollRect: Rect | null;
|
|
764
|
+
/** Previous screen rect (for change detection in notifyLayoutSubscribers) */
|
|
765
|
+
prevScrollRect: Rect | null;
|
|
766
|
+
/**
|
|
767
|
+
* Actual render position on the terminal screen.
|
|
768
|
+
* For non-sticky nodes, this equals `scrollRect`.
|
|
769
|
+
* For sticky nodes (position="sticky"), this accounts for sticky render
|
|
770
|
+
* offsets — the position where pixels are actually painted.
|
|
771
|
+
*
|
|
772
|
+
* Use this for hit testing, cursor positioning, and any feature that
|
|
773
|
+
* needs to know where a node visually appears on screen.
|
|
774
|
+
* Set after screen rect phase.
|
|
775
|
+
*/
|
|
776
|
+
screenRect: Rect | null;
|
|
777
|
+
/** Previous render rect (for change detection) */
|
|
778
|
+
prevScreenRect: Rect | null;
|
|
779
|
+
/** Epoch when layout changed (position or size).
|
|
780
|
+
* Set by propagateLayout in layout phase. Compared against renderEpoch by render phase.
|
|
781
|
+
* This is the authoritative signal for "did layout change?" — unlike
|
|
782
|
+
* !rectEqual(prevLayout, boxRect) which becomes stale when layout
|
|
783
|
+
* phase skips (no dirty nodes).
|
|
784
|
+
* Value: renderEpoch when dirty, INITIAL_EPOCH (-1) when clean. */
|
|
785
|
+
layoutChangedThisFrame: number;
|
|
786
|
+
/** True if layout-affecting props changed and Yoga needs recalculation.
|
|
787
|
+
* Set by reconciler on prop changes. Cleared after layout phase.
|
|
788
|
+
* NOTE: layoutDirty stays boolean — it's cleared by layout phase (not render phase)
|
|
789
|
+
* and has its own tracking set in dirty-tracking.ts. */
|
|
790
|
+
layoutDirty: boolean;
|
|
791
|
+
/**
|
|
792
|
+
* Bit-packed dirty flags for the current epoch.
|
|
793
|
+
*
|
|
794
|
+
* Seven dirty flags packed into a single number:
|
|
795
|
+
* bit 0 (CONTENT_BIT): content changed (text content or content-affecting props)
|
|
796
|
+
* bit 1 (STYLE_PROPS_BIT): visual props changed (color, bg, border, etc.)
|
|
797
|
+
* bit 2 (BG_BIT): backgroundColor specifically changed
|
|
798
|
+
* bit 3 (CHILDREN_BIT): direct children added/removed/reordered
|
|
799
|
+
* bit 4 (SUBTREE_BIT): this node or any descendant has dirty content/layout
|
|
800
|
+
* bit 5 (ABS_CHILD_BIT): absolute child had structural changes
|
|
801
|
+
* bit 6 (DESC_OVERFLOW_BIT): descendant overflow changed
|
|
802
|
+
*
|
|
803
|
+
* Check: `isDirty(node.dirtyBits, node.dirtyEpoch, BIT)`
|
|
804
|
+
* Set: `node.dirtyBits = setDirtyBit(node.dirtyBits, node.dirtyEpoch, BIT); node.dirtyEpoch = getRenderEpoch()`
|
|
805
|
+
* Clear: `advanceRenderEpoch()` — all nodes instantly become clean
|
|
806
|
+
*
|
|
807
|
+
* NOTE: measure phase may clear CONTENT_BIT — STYLE_PROPS_BIT acts as the
|
|
808
|
+
* surviving witness for style changes. See render-phase.ts contentAreaAffected.
|
|
809
|
+
*/
|
|
810
|
+
dirtyBits: number;
|
|
811
|
+
/**
|
|
812
|
+
* Epoch when dirtyBits was last written.
|
|
813
|
+
* When `dirtyEpoch !== renderEpoch`, all bits are stale (node is clean).
|
|
814
|
+
* Value: renderEpoch when any bit is dirty, INITIAL_EPOCH (-1) when clean.
|
|
815
|
+
*/
|
|
816
|
+
dirtyEpoch: number;
|
|
817
|
+
/** Callbacks subscribed to layout changes (used by useBoxRect) */
|
|
818
|
+
layoutSubscribers: Set<() => void>;
|
|
819
|
+
/** Text content for text nodes */
|
|
820
|
+
textContent?: string;
|
|
821
|
+
/** True if this is a raw text node (created by createTextInstance) */
|
|
822
|
+
isRawText?: boolean;
|
|
823
|
+
/** True if this node is hidden (for Suspense support) */
|
|
824
|
+
hidden?: boolean;
|
|
825
|
+
/** Sticky children with computed render positions (for non-scroll containers).
|
|
826
|
+
* When a parent has sticky children but is NOT a scroll container, this array
|
|
827
|
+
* holds the computed render offsets. Same shape as scrollState.stickyChildren. */
|
|
828
|
+
stickyChildren?: Array<{
|
|
829
|
+
/** Index of the sticky child */index: number; /** Computed Y offset to render at (relative to parent content area) */
|
|
830
|
+
renderOffset: number; /** Original natural Y position (relative to parent content area) */
|
|
831
|
+
naturalTop: number; /** Height of the sticky element */
|
|
832
|
+
height: number;
|
|
833
|
+
}>;
|
|
834
|
+
/** Inline rects for virtual text nodes (no layout node). Computed during text rendering.
|
|
835
|
+
* Array for wrapped text (one rect per line fragment). Enables hit testing on nested Text. */
|
|
836
|
+
inlineRects?: Array<{
|
|
837
|
+
x: number;
|
|
838
|
+
y: number;
|
|
839
|
+
width: number;
|
|
840
|
+
height: number;
|
|
841
|
+
}> | null;
|
|
842
|
+
/**
|
|
843
|
+
* Interactive state signals — written by pointer/selection/focus state machines,
|
|
844
|
+
* read by theme/render for automatic styling (hover highlights, focus rings, etc.).
|
|
845
|
+
*
|
|
846
|
+
* Lazily created on first write. Null means no interactive state has been set.
|
|
847
|
+
* See InteractiveState for field docs.
|
|
848
|
+
*/
|
|
849
|
+
interactiveState?: InteractiveState | null;
|
|
850
|
+
/** Scroll state for overflow='scroll' containers */
|
|
851
|
+
scrollState?: {
|
|
852
|
+
/** Current scroll offset (in terminal rows) */offset: number; /** Previous scroll offset from last render (for incremental rendering) */
|
|
853
|
+
prevOffset: number; /** Total content height (all children) */
|
|
854
|
+
contentHeight: number; /** Visible height (container height minus borders/padding) */
|
|
855
|
+
viewportHeight: number; /** Index of first visible child */
|
|
856
|
+
firstVisibleChild: number; /** Index of last visible child */
|
|
857
|
+
lastVisibleChild: number; /** Previous first visible child from last render (for incremental rendering) */
|
|
858
|
+
prevFirstVisibleChild: number; /** Previous last visible child from last render (for incremental rendering) */
|
|
859
|
+
prevLastVisibleChild: number; /** Count of items hidden above viewport */
|
|
860
|
+
hiddenAbove: number; /** Count of items hidden below viewport */
|
|
861
|
+
hiddenBelow: number; /** Sticky children with their computed render positions */
|
|
862
|
+
stickyChildren?: Array<{
|
|
863
|
+
/** Index of the sticky child */index: number; /** Computed Y offset to render at (relative to viewport, not content) */
|
|
864
|
+
renderOffset: number; /** Original natural Y position (before sticky adjustment) */
|
|
865
|
+
naturalTop: number; /** Height of the sticky element */
|
|
866
|
+
height: number;
|
|
867
|
+
}>;
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Keyboard event with key information and modifiers.
|
|
872
|
+
*/
|
|
873
|
+
interface KeyEvent {
|
|
874
|
+
type: "key";
|
|
875
|
+
/** The key pressed (character or key name like 'ArrowUp') */
|
|
876
|
+
key: string;
|
|
877
|
+
/** Ctrl modifier was held */
|
|
878
|
+
ctrl?: boolean;
|
|
879
|
+
/** Meta/Alt modifier was held */
|
|
880
|
+
meta?: boolean;
|
|
881
|
+
/** Shift modifier was held */
|
|
882
|
+
shift?: boolean;
|
|
883
|
+
/** Alt/Option modifier was held */
|
|
884
|
+
alt?: boolean;
|
|
885
|
+
/** Super/Cmd modifier was held. Requires Kitty protocol. */
|
|
886
|
+
super?: boolean;
|
|
887
|
+
/** Hyper modifier was held. Requires Kitty protocol. */
|
|
888
|
+
hyper?: boolean;
|
|
889
|
+
/** Kitty event type. Requires Kitty flag 2. */
|
|
890
|
+
eventType?: "press" | "repeat" | "release";
|
|
891
|
+
/** CapsLock is active. Kitty modifier bit 6. */
|
|
892
|
+
capsLock?: boolean;
|
|
893
|
+
/** NumLock is active. Kitty modifier bit 7. */
|
|
894
|
+
numLock?: boolean;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Mouse event with position and button information.
|
|
898
|
+
*/
|
|
899
|
+
interface MouseEvent {
|
|
900
|
+
type: "mouse";
|
|
901
|
+
/** X position in terminal columns (0-indexed) */
|
|
902
|
+
x: number;
|
|
903
|
+
/** Y position in terminal rows (0-indexed) */
|
|
904
|
+
y: number;
|
|
905
|
+
/** Mouse button (0=left, 1=middle, 2=right) */
|
|
906
|
+
button: number;
|
|
907
|
+
/** Event action */
|
|
908
|
+
action: "down" | "up" | "move" | "wheel";
|
|
909
|
+
/** Wheel delta for scroll events */
|
|
910
|
+
delta?: number;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Terminal resize event.
|
|
914
|
+
*/
|
|
915
|
+
interface ResizeEvent {
|
|
916
|
+
type: "resize";
|
|
917
|
+
/** New width in columns */
|
|
918
|
+
width: number;
|
|
919
|
+
/** New height in rows */
|
|
920
|
+
height: number;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Terminal focus event.
|
|
924
|
+
*/
|
|
925
|
+
interface FocusEvent {
|
|
926
|
+
type: "focus";
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Terminal blur event.
|
|
930
|
+
*/
|
|
931
|
+
interface BlurEvent {
|
|
932
|
+
type: "blur";
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Signal event (SIGINT, SIGTERM, etc.).
|
|
936
|
+
*/
|
|
937
|
+
interface SignalEvent {
|
|
938
|
+
type: "signal";
|
|
939
|
+
/** Signal name (e.g., 'SIGINT', 'SIGTERM') */
|
|
940
|
+
signal: string;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Custom event for extensibility.
|
|
944
|
+
*/
|
|
945
|
+
interface CustomEvent {
|
|
946
|
+
type: "custom";
|
|
947
|
+
/** Event name */
|
|
948
|
+
name: string;
|
|
949
|
+
/** Event data */
|
|
950
|
+
data: unknown;
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Union of all event types.
|
|
954
|
+
*
|
|
955
|
+
* Events drive the render loop in interactive mode. When events are present,
|
|
956
|
+
* the render loop runs until exit() is called. When events are absent,
|
|
957
|
+
* the render completes when the UI is stable.
|
|
958
|
+
*/
|
|
959
|
+
type Event$1 = KeyEvent | MouseEvent | ResizeEvent | FocusEvent | BlurEvent | SignalEvent | CustomEvent;
|
|
960
|
+
/**
|
|
961
|
+
* Event source that can be subscribed to and unsubscribed from.
|
|
962
|
+
*/
|
|
963
|
+
interface EventSource {
|
|
964
|
+
/** Subscribe to events, returns unsubscribe function */
|
|
965
|
+
subscribe(handler: (event: Event$1) => void): () => void;
|
|
966
|
+
/** Convert to async iterable */
|
|
967
|
+
[Symbol.asyncIterator](): AsyncIterator<Event$1>;
|
|
968
|
+
}
|
|
969
|
+
//#endregion
|
|
970
|
+
//#region packages/ag-term/src/ansi/types.d.ts
|
|
971
|
+
/**
|
|
972
|
+
* Console method names that can be intercepted.
|
|
973
|
+
*/
|
|
974
|
+
type ConsoleMethod = "log" | "info" | "warn" | "error" | "debug";
|
|
975
|
+
/**
|
|
976
|
+
* Entry captured from console.
|
|
977
|
+
*/
|
|
978
|
+
interface ConsoleEntry {
|
|
979
|
+
method: ConsoleMethod;
|
|
980
|
+
args: unknown[];
|
|
981
|
+
stream: "stdout" | "stderr";
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Options for createTerm().
|
|
985
|
+
*/
|
|
986
|
+
interface CreateTermOptions {
|
|
987
|
+
stdout?: NodeJS.WriteStream;
|
|
988
|
+
stdin?: NodeJS.ReadStream;
|
|
989
|
+
color?: ColorLevel | null;
|
|
990
|
+
unicode?: boolean;
|
|
991
|
+
cursor?: boolean;
|
|
992
|
+
caps?: Partial<TerminalCaps>;
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* A screen region — duck-type matching termless RegionView.
|
|
996
|
+
* Provides text content, line access, and cell-level queries for assertions.
|
|
997
|
+
*/
|
|
998
|
+
interface TermScreen {
|
|
999
|
+
getText(): string;
|
|
1000
|
+
getLines(): string[];
|
|
1001
|
+
containsText?(text: string): boolean;
|
|
1002
|
+
/** Cell-level access — row-first order. Returns resolved RGB colors.
|
|
1003
|
+
* Only available on emulator-backed terms (createTermless). */
|
|
1004
|
+
cell?(row: number, col: number): {
|
|
1005
|
+
readonly fg: unknown;
|
|
1006
|
+
readonly bg: unknown;
|
|
1007
|
+
readonly char: string;
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* A terminal emulator — duck-type matching termless Terminal.
|
|
1012
|
+
* Accepts ANSI output, provides screen/scrollback for inspection.
|
|
1013
|
+
*/
|
|
1014
|
+
interface TermEmulator {
|
|
1015
|
+
readonly cols: number;
|
|
1016
|
+
readonly rows: number;
|
|
1017
|
+
readonly screen: TermScreen;
|
|
1018
|
+
readonly scrollback: TermScreen;
|
|
1019
|
+
feed(data: Uint8Array | string): void;
|
|
1020
|
+
resize(cols: number, rows: number): void;
|
|
1021
|
+
close(): Promise<void>;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* A terminal emulator backend — duck-type matching termless TerminalBackend.
|
|
1025
|
+
* Raw backend that needs initialization. Pass to createTerm(backend, { cols, rows }).
|
|
1026
|
+
*
|
|
1027
|
+
* @example
|
|
1028
|
+
* ```ts
|
|
1029
|
+
* import { createXtermBackend } from "@termless/xtermjs"
|
|
1030
|
+
* using term = createTerm(createXtermBackend(), { cols: 80, rows: 24 })
|
|
1031
|
+
* ```
|
|
1032
|
+
*/
|
|
1033
|
+
interface TermEmulatorBackend {
|
|
1034
|
+
readonly name: string;
|
|
1035
|
+
init(opts: {
|
|
1036
|
+
cols: number;
|
|
1037
|
+
rows: number;
|
|
1038
|
+
scrollbackLimit?: number;
|
|
1039
|
+
}): void;
|
|
1040
|
+
destroy(): void;
|
|
1041
|
+
feed(data: Uint8Array): void;
|
|
1042
|
+
resize(cols: number, rows: number): void;
|
|
1043
|
+
}
|
|
1044
|
+
//#endregion
|
|
1045
|
+
//#region packages/ag/src/text-frame.d.ts
|
|
1046
|
+
/**
|
|
1047
|
+
* TextFrame — Unified interface for a rectangular area of styled terminal text.
|
|
1048
|
+
*
|
|
1049
|
+
* Used by App, RunHandle, term.screen, term.scrollback — one shape everywhere.
|
|
1050
|
+
* Provides plain text, ANSI-styled text, per-line access, cell-level queries,
|
|
1051
|
+
* and text search.
|
|
1052
|
+
*
|
|
1053
|
+
* @packageDocumentation
|
|
1054
|
+
*/
|
|
1055
|
+
/**
|
|
1056
|
+
* RGB color value (0-255 per channel).
|
|
1057
|
+
*/
|
|
1058
|
+
interface RGB {
|
|
1059
|
+
r: number;
|
|
1060
|
+
g: number;
|
|
1061
|
+
b: number;
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* A single cell in a TextFrame with resolved styling.
|
|
1065
|
+
*
|
|
1066
|
+
* Colors are resolved to RGB (or null for default/inherit).
|
|
1067
|
+
* Attributes are flattened booleans for easy testing.
|
|
1068
|
+
*/
|
|
1069
|
+
interface FrameCell {
|
|
1070
|
+
/** The character/grapheme in this cell */
|
|
1071
|
+
readonly char: string;
|
|
1072
|
+
/** Resolved foreground color, or null for default */
|
|
1073
|
+
readonly fg: RGB | null;
|
|
1074
|
+
/** Resolved background color, or null for default */
|
|
1075
|
+
readonly bg: RGB | null;
|
|
1076
|
+
/** Bold attribute */
|
|
1077
|
+
readonly bold: boolean;
|
|
1078
|
+
/** Dim/faint attribute */
|
|
1079
|
+
readonly dim: boolean;
|
|
1080
|
+
/** Italic attribute */
|
|
1081
|
+
readonly italic: boolean;
|
|
1082
|
+
/** Underline style — false if none */
|
|
1083
|
+
readonly underline: UnderlineStyle$1;
|
|
1084
|
+
/** Underline color (independent of fg), or null to use fg */
|
|
1085
|
+
readonly underlineColor: RGB | null;
|
|
1086
|
+
/** Strikethrough attribute */
|
|
1087
|
+
readonly strikethrough: boolean;
|
|
1088
|
+
/** Inverse/reverse video attribute */
|
|
1089
|
+
readonly inverse: boolean;
|
|
1090
|
+
/** Blink attribute */
|
|
1091
|
+
readonly blink: boolean;
|
|
1092
|
+
/** Hidden/invisible attribute */
|
|
1093
|
+
readonly hidden: boolean;
|
|
1094
|
+
/** True if this is a wide character (CJK, emoji) */
|
|
1095
|
+
readonly wide: boolean;
|
|
1096
|
+
/** True if this cell is the continuation of a wide character */
|
|
1097
|
+
readonly continuation: boolean;
|
|
1098
|
+
/** OSC 8 hyperlink URL, or null if none */
|
|
1099
|
+
readonly hyperlink: string | null;
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Unified interface for a rectangular area of styled terminal text.
|
|
1103
|
+
*
|
|
1104
|
+
* Implemented by App, RunHandle, and terminal views (screen, scrollback).
|
|
1105
|
+
* Provides consistent access to text content, styling, and cell-level data.
|
|
1106
|
+
*/
|
|
1107
|
+
interface TextFrame {
|
|
1108
|
+
/** Plain text content (no ANSI codes). Lines separated by newlines. */
|
|
1109
|
+
readonly text: string;
|
|
1110
|
+
/** Text with ANSI styling escape codes. */
|
|
1111
|
+
readonly ansi: string;
|
|
1112
|
+
/** Per-line plain text array (no ANSI codes). */
|
|
1113
|
+
readonly lines: string[];
|
|
1114
|
+
/** Frame width in terminal columns. */
|
|
1115
|
+
readonly width: number;
|
|
1116
|
+
/** Frame height in terminal rows. */
|
|
1117
|
+
readonly height: number;
|
|
1118
|
+
/** Get the cell at the given column and row. */
|
|
1119
|
+
cell(col: number, row: number): FrameCell;
|
|
1120
|
+
/** Check whether the plain text contains the given substring. */
|
|
1121
|
+
containsText(text: string): boolean;
|
|
1122
|
+
}
|
|
1123
|
+
//#endregion
|
|
1124
|
+
//#region packages/ag-term/src/buffer.d.ts
|
|
1125
|
+
/**
|
|
1126
|
+
* Terminal buffer implementation for Silvery.
|
|
1127
|
+
*
|
|
1128
|
+
* Uses packed Uint32Array for efficient cell metadata storage,
|
|
1129
|
+
* with separate string array for character storage (needed for
|
|
1130
|
+
* multi-byte Unicode graphemes and combining characters).
|
|
1131
|
+
*/
|
|
1132
|
+
/**
|
|
1133
|
+
* Underline style variants (SGR 4:x codes).
|
|
1134
|
+
* - false: no underline
|
|
1135
|
+
* - 'single': standard underline (SGR 4 or 4:1)
|
|
1136
|
+
* - 'double': double underline (SGR 4:2)
|
|
1137
|
+
* - 'curly': curly/wavy underline (SGR 4:3)
|
|
1138
|
+
* - 'dotted': dotted underline (SGR 4:4)
|
|
1139
|
+
* - 'dashed': dashed underline (SGR 4:5)
|
|
1140
|
+
*/
|
|
1141
|
+
type UnderlineStyle = false | "single" | "double" | "curly" | "dotted" | "dashed";
|
|
1142
|
+
/**
|
|
1143
|
+
* Text attributes that can be applied to a cell.
|
|
1144
|
+
*/
|
|
1145
|
+
interface CellAttrs {
|
|
1146
|
+
bold?: boolean;
|
|
1147
|
+
dim?: boolean;
|
|
1148
|
+
italic?: boolean;
|
|
1149
|
+
/** Simple underline flag (for backwards compatibility) */
|
|
1150
|
+
underline?: boolean;
|
|
1151
|
+
/**
|
|
1152
|
+
* Underline style: 'single' | 'double' | 'curly' | 'dotted' | 'dashed'.
|
|
1153
|
+
* When set, takes precedence over the underline boolean.
|
|
1154
|
+
*/
|
|
1155
|
+
underlineStyle?: UnderlineStyle;
|
|
1156
|
+
blink?: boolean;
|
|
1157
|
+
inverse?: boolean;
|
|
1158
|
+
hidden?: boolean;
|
|
1159
|
+
strikethrough?: boolean;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Color representation.
|
|
1163
|
+
* - number: 256-color index (0-255)
|
|
1164
|
+
* - RGB object: true color
|
|
1165
|
+
* - null: default/inherit
|
|
1166
|
+
* - DEFAULT_BG: terminal's default background (SGR 49), opaque but uses terminal's own bg color
|
|
1167
|
+
*/
|
|
1168
|
+
type Color = number | {
|
|
1169
|
+
r: number;
|
|
1170
|
+
g: number;
|
|
1171
|
+
b: number;
|
|
1172
|
+
} | null;
|
|
1173
|
+
/**
|
|
1174
|
+
* A single cell in the terminal buffer.
|
|
1175
|
+
*/
|
|
1176
|
+
interface Cell {
|
|
1177
|
+
/** The character/grapheme in this cell */
|
|
1178
|
+
char: string;
|
|
1179
|
+
/** Foreground color */
|
|
1180
|
+
fg: Color;
|
|
1181
|
+
/** Background color */
|
|
1182
|
+
bg: Color;
|
|
1183
|
+
/**
|
|
1184
|
+
* Underline color (independent of fg).
|
|
1185
|
+
* Uses SGR 58. If null, underline uses fg color.
|
|
1186
|
+
*/
|
|
1187
|
+
underlineColor: Color;
|
|
1188
|
+
/** Text attributes */
|
|
1189
|
+
attrs: CellAttrs;
|
|
1190
|
+
/** True if this is a wide character (CJK, emoji, etc.) */
|
|
1191
|
+
wide: boolean;
|
|
1192
|
+
/** True if this is the continuation cell after a wide character */
|
|
1193
|
+
continuation: boolean;
|
|
1194
|
+
/**
|
|
1195
|
+
* OSC 8 hyperlink URL.
|
|
1196
|
+
* When set, the cell is part of a clickable hyperlink in supporting terminals.
|
|
1197
|
+
*/
|
|
1198
|
+
hyperlink?: string;
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Style information for a cell (excludes char and position flags).
|
|
1202
|
+
*/
|
|
1203
|
+
interface Style {
|
|
1204
|
+
fg: Color;
|
|
1205
|
+
bg: Color;
|
|
1206
|
+
/**
|
|
1207
|
+
* Underline color (independent of fg).
|
|
1208
|
+
* Uses SGR 58. If null, underline uses fg color.
|
|
1209
|
+
*/
|
|
1210
|
+
underlineColor?: Color;
|
|
1211
|
+
attrs: CellAttrs;
|
|
1212
|
+
/**
|
|
1213
|
+
* OSC 8 hyperlink URL.
|
|
1214
|
+
* When set, the cell is part of a clickable hyperlink in supporting terminals.
|
|
1215
|
+
*/
|
|
1216
|
+
hyperlink?: string;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Per-row metadata for text extraction correctness.
|
|
1220
|
+
* Maintained by the render phase during text rendering.
|
|
1221
|
+
*/
|
|
1222
|
+
interface RowMetadata {
|
|
1223
|
+
/** True if this row continues on the next row (soft wrap, not hard break) */
|
|
1224
|
+
softWrapped: boolean;
|
|
1225
|
+
/** Rightmost column with non-space content (for trailing space trimming) */
|
|
1226
|
+
lastContentCol: number;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Efficient terminal cell buffer.
|
|
1230
|
+
*
|
|
1231
|
+
* Uses packed Uint32Array for cell metadata and separate string array
|
|
1232
|
+
* for characters. This allows efficient diffing while supporting
|
|
1233
|
+
* full Unicode grapheme clusters.
|
|
1234
|
+
*/
|
|
1235
|
+
declare class TerminalBuffer {
|
|
1236
|
+
/** Packed cell metadata */
|
|
1237
|
+
private cells;
|
|
1238
|
+
/** Character storage (one per cell, may be multi-byte grapheme) */
|
|
1239
|
+
private chars;
|
|
1240
|
+
/** True color foreground storage (only for cells with true color fg) */
|
|
1241
|
+
private fgColors;
|
|
1242
|
+
/** True color background storage (only for cells with true color bg) */
|
|
1243
|
+
private bgColors;
|
|
1244
|
+
/** Underline color storage (independent of fg, for SGR 58) */
|
|
1245
|
+
private underlineColors;
|
|
1246
|
+
/** OSC 8 hyperlink URL storage (only for cells that are part of a hyperlink) */
|
|
1247
|
+
private hyperlinks;
|
|
1248
|
+
/**
|
|
1249
|
+
* Per-row dirty tracking for diff optimization.
|
|
1250
|
+
* When set, diffBuffers() can skip clean rows entirely.
|
|
1251
|
+
* 0 = clean (unchanged since last resetDirtyRows), 1 = dirty (modified).
|
|
1252
|
+
*/
|
|
1253
|
+
private _dirtyRows;
|
|
1254
|
+
/** Bounding box: first dirty row (inclusive). -1 when no rows are dirty. */
|
|
1255
|
+
private _minDirtyRow;
|
|
1256
|
+
/** Bounding box: last dirty row (inclusive). -1 when no rows are dirty. */
|
|
1257
|
+
private _maxDirtyRow;
|
|
1258
|
+
/**
|
|
1259
|
+
* Per-row metadata for text extraction (soft wrap, last content column).
|
|
1260
|
+
* Set by the render phase, read by extractText.
|
|
1261
|
+
*/
|
|
1262
|
+
private _rowMetadata;
|
|
1263
|
+
/**
|
|
1264
|
+
* When true, setCell and fill automatically stamp SELECTABLE_FLAG on written cells.
|
|
1265
|
+
* Set/cleared by the render phase as it traverses nodes with different userSelect values.
|
|
1266
|
+
* This avoids modifying every individual setCell call — zero overhead (single OR per cell).
|
|
1267
|
+
*/
|
|
1268
|
+
private _selectableMode;
|
|
1269
|
+
readonly width: number;
|
|
1270
|
+
readonly height: number;
|
|
1271
|
+
constructor(width: number, height: number);
|
|
1272
|
+
/**
|
|
1273
|
+
* Get the index for a cell position.
|
|
1274
|
+
*/
|
|
1275
|
+
private index;
|
|
1276
|
+
/**
|
|
1277
|
+
* Check if coordinates are within bounds.
|
|
1278
|
+
*/
|
|
1279
|
+
inBounds(x: number, y: number): boolean;
|
|
1280
|
+
/**
|
|
1281
|
+
* Get a cell at the given position.
|
|
1282
|
+
*/
|
|
1283
|
+
getCell(x: number, y: number): Cell;
|
|
1284
|
+
/**
|
|
1285
|
+
* Get just the character at a cell position (no object allocation).
|
|
1286
|
+
* Returns " " for out-of-bounds positions.
|
|
1287
|
+
*/
|
|
1288
|
+
getCellChar(x: number, y: number): string;
|
|
1289
|
+
/**
|
|
1290
|
+
* Get just the background color at a cell position (no object allocation).
|
|
1291
|
+
* Returns null for out-of-bounds positions.
|
|
1292
|
+
*/
|
|
1293
|
+
getCellBg(x: number, y: number): Color;
|
|
1294
|
+
/**
|
|
1295
|
+
* Get just the foreground color at a cell position (no object allocation).
|
|
1296
|
+
* Returns null for out-of-bounds positions.
|
|
1297
|
+
*/
|
|
1298
|
+
getCellFg(x: number, y: number): Color;
|
|
1299
|
+
/**
|
|
1300
|
+
* Get the raw packed metadata at a cell position (no unpackAttrs allocation).
|
|
1301
|
+
* Returns 0 for out-of-bounds positions. The packed value contains color
|
|
1302
|
+
* indices, attr bits, underline style, and flags in a single Uint32.
|
|
1303
|
+
*/
|
|
1304
|
+
getCellAttrs(x: number, y: number): number;
|
|
1305
|
+
/**
|
|
1306
|
+
* Check if a cell is a wide character (no object allocation).
|
|
1307
|
+
* Returns false for out-of-bounds positions.
|
|
1308
|
+
*/
|
|
1309
|
+
isCellWide(x: number, y: number): boolean;
|
|
1310
|
+
/**
|
|
1311
|
+
* Check if a cell is a continuation of a wide character (no object allocation).
|
|
1312
|
+
* Returns false for out-of-bounds positions.
|
|
1313
|
+
*/
|
|
1314
|
+
isCellContinuation(x: number, y: number): boolean;
|
|
1315
|
+
/**
|
|
1316
|
+
* Check if a cell is selectable (SELECTABLE_FLAG is set, no object allocation).
|
|
1317
|
+
* Returns false for out-of-bounds positions.
|
|
1318
|
+
*/
|
|
1319
|
+
isCellSelectable(x: number, y: number): boolean;
|
|
1320
|
+
/**
|
|
1321
|
+
* Set metadata for a row (soft wrap, last content column).
|
|
1322
|
+
* Called by the render phase during text rendering.
|
|
1323
|
+
*/
|
|
1324
|
+
setRowMeta(row: number, meta: Partial<RowMetadata>): void;
|
|
1325
|
+
/**
|
|
1326
|
+
* Get metadata for a row. Returns default values for out-of-bounds rows.
|
|
1327
|
+
*/
|
|
1328
|
+
getRowMeta(row: number): RowMetadata;
|
|
1329
|
+
/**
|
|
1330
|
+
* Get the full row metadata array (for bulk access during text extraction).
|
|
1331
|
+
*/
|
|
1332
|
+
getRowMetadataArray(): readonly RowMetadata[];
|
|
1333
|
+
/**
|
|
1334
|
+
* Enable/disable automatic SELECTABLE_FLAG stamping on cell writes.
|
|
1335
|
+
* When true, all setCell/fill calls stamp SELECTABLE_FLAG on the packed metadata.
|
|
1336
|
+
* Zero overhead: a single OR per cell when enabled.
|
|
1337
|
+
*/
|
|
1338
|
+
setSelectableMode(selectable: boolean): void;
|
|
1339
|
+
/**
|
|
1340
|
+
* Get the current selectable mode.
|
|
1341
|
+
*/
|
|
1342
|
+
getSelectableMode(): boolean;
|
|
1343
|
+
/**
|
|
1344
|
+
* Read cell data into a caller-provided Cell object (zero-allocation).
|
|
1345
|
+
* For hot loops that need the full Cell, reuse a single object:
|
|
1346
|
+
*
|
|
1347
|
+
* const cell = createMutableCell()
|
|
1348
|
+
* for (...) { buffer.readCellInto(x, y, cell) }
|
|
1349
|
+
*
|
|
1350
|
+
* Returns the same `out` object for chaining convenience.
|
|
1351
|
+
*/
|
|
1352
|
+
readCellInto(x: number, y: number, out: Cell): Cell;
|
|
1353
|
+
/**
|
|
1354
|
+
* Set a cell at the given position.
|
|
1355
|
+
*
|
|
1356
|
+
* Optimized: resolves defaults and packs metadata inline to avoid
|
|
1357
|
+
* allocating an intermediate Cell object.
|
|
1358
|
+
*/
|
|
1359
|
+
setCell(x: number, y: number, cell: Partial<Cell>): void;
|
|
1360
|
+
/**
|
|
1361
|
+
* Fill a region with a cell.
|
|
1362
|
+
*
|
|
1363
|
+
* Optimized: packs cell metadata once and assigns directly to arrays,
|
|
1364
|
+
* avoiding O(width*height) intermediate object allocations from setCell().
|
|
1365
|
+
*/
|
|
1366
|
+
fill(x: number, y: number, width: number, height: number, cell: Partial<Cell>): void;
|
|
1367
|
+
/**
|
|
1368
|
+
* Restyle a rectangular region — update fg, bg, and attrs on existing cells
|
|
1369
|
+
* without changing character content (char, wide, continuation, hyperlink).
|
|
1370
|
+
*
|
|
1371
|
+
* This is the style-only fast path: when only visual props changed (color,
|
|
1372
|
+
* bold, dim, inverse, etc.) but text content and layout are identical, we
|
|
1373
|
+
* can skip text collection/formatting and just update the style metadata.
|
|
1374
|
+
*
|
|
1375
|
+
* @param x Left column (inclusive)
|
|
1376
|
+
* @param y Top row (inclusive)
|
|
1377
|
+
* @param width Region width
|
|
1378
|
+
* @param height Region height
|
|
1379
|
+
* @param style New style to apply (fg, bg, attrs, underlineColor)
|
|
1380
|
+
*/
|
|
1381
|
+
restyleRegion(x: number, y: number, width: number, height: number, style: Style): void;
|
|
1382
|
+
/**
|
|
1383
|
+
* Fill only the background color of a region — update bg on existing cells
|
|
1384
|
+
* without changing character content, foreground, or attributes.
|
|
1385
|
+
*
|
|
1386
|
+
* Unlike fill() which writes space characters, this preserves existing chars.
|
|
1387
|
+
* Used by the style-only fast path: when a Box's backgroundColor changes but
|
|
1388
|
+
* children are unchanged, fillBg() paints the new bg without destroying child
|
|
1389
|
+
* chars. Clean children can then be skipped (their chars are correct from the
|
|
1390
|
+
* clone, their bg was updated by fillBg).
|
|
1391
|
+
*
|
|
1392
|
+
* @param x Left column (inclusive)
|
|
1393
|
+
* @param y Top row (inclusive)
|
|
1394
|
+
* @param width Region width
|
|
1395
|
+
* @param height Region height
|
|
1396
|
+
* @param bg New background color
|
|
1397
|
+
*/
|
|
1398
|
+
fillBg(x: number, y: number, width: number, height: number, bg: Color): void;
|
|
1399
|
+
/**
|
|
1400
|
+
* Clear the buffer (fill with empty cells).
|
|
1401
|
+
*/
|
|
1402
|
+
clear(): void;
|
|
1403
|
+
/**
|
|
1404
|
+
* Copy a region from another buffer.
|
|
1405
|
+
*/
|
|
1406
|
+
copyFrom(source: TerminalBuffer, srcX: number, srcY: number, destX: number, destY: number, width: number, height: number): void;
|
|
1407
|
+
/**
|
|
1408
|
+
* Shift content within a rectangular region vertically by `delta` rows.
|
|
1409
|
+
* Positive delta = shift content UP (scroll down), negative = shift DOWN (scroll up).
|
|
1410
|
+
* Exposed rows (at the bottom for positive delta, top for negative) are filled
|
|
1411
|
+
* with the given background cell.
|
|
1412
|
+
*
|
|
1413
|
+
* Uses Uint32Array.copyWithin for the packed cells (native memcpy) and
|
|
1414
|
+
* Array splice for the character array.
|
|
1415
|
+
*/
|
|
1416
|
+
scrollRegion(x: number, y: number, regionWidth: number, regionHeight: number, delta: number, clearCell?: Partial<Cell>): void;
|
|
1417
|
+
/**
|
|
1418
|
+
* Clone this buffer.
|
|
1419
|
+
*/
|
|
1420
|
+
clone(): TerminalBuffer;
|
|
1421
|
+
/**
|
|
1422
|
+
* Check if a row has been modified since the last resetDirtyRows() call.
|
|
1423
|
+
* Used by diffBuffers() to skip unchanged rows.
|
|
1424
|
+
*/
|
|
1425
|
+
isRowDirty(y: number): boolean;
|
|
1426
|
+
/** First dirty row (inclusive), or -1 if no rows are dirty. */
|
|
1427
|
+
get minDirtyRow(): number;
|
|
1428
|
+
/** Last dirty row (inclusive), or -1 if no rows are dirty. */
|
|
1429
|
+
get maxDirtyRow(): number;
|
|
1430
|
+
/**
|
|
1431
|
+
* Reset all dirty row flags to clean.
|
|
1432
|
+
* Call after diffing to prepare for the next frame's modifications.
|
|
1433
|
+
*/
|
|
1434
|
+
resetDirtyRows(): void;
|
|
1435
|
+
/**
|
|
1436
|
+
* Mark all rows as dirty.
|
|
1437
|
+
* Used when the buffer's dirty rows may not cover all changes relative
|
|
1438
|
+
* to a different prev buffer (e.g., after multiple doRender calls where
|
|
1439
|
+
* the runtime's prevBuffer skipped intermediate buffers).
|
|
1440
|
+
*/
|
|
1441
|
+
markAllRowsDirty(): void;
|
|
1442
|
+
/**
|
|
1443
|
+
* Check if two cells at given positions are equal.
|
|
1444
|
+
* Used for diffing.
|
|
1445
|
+
*/
|
|
1446
|
+
cellEquals(x: number, y: number, other: TerminalBuffer): boolean;
|
|
1447
|
+
/**
|
|
1448
|
+
* Fast check: are all packed metadata values identical for a row?
|
|
1449
|
+
* This is a bulk pre-check before per-cell comparison. If metadata differs,
|
|
1450
|
+
* we still need per-cell diffing. If metadata matches, we only need to
|
|
1451
|
+
* check chars, true color maps, underline colors, and hyperlinks.
|
|
1452
|
+
* Returns true if all packed 32-bit values in the row are identical.
|
|
1453
|
+
*/
|
|
1454
|
+
rowMetadataEquals(y: number, other: TerminalBuffer): boolean;
|
|
1455
|
+
/**
|
|
1456
|
+
* Fast check: are all characters identical for a row?
|
|
1457
|
+
* Companion to rowMetadataEquals for a two-phase row comparison.
|
|
1458
|
+
*/
|
|
1459
|
+
rowCharsEquals(y: number, other: TerminalBuffer): boolean;
|
|
1460
|
+
/**
|
|
1461
|
+
* Check Map-based extras for a row: true color fg/bg, underline colors, hyperlinks.
|
|
1462
|
+
* Must be called AFTER rowMetadataEquals confirms packed metadata matches.
|
|
1463
|
+
* Only checks cells that have true color flags set (the Maps are only populated
|
|
1464
|
+
* for those cells). Also checks underline colors and hyperlinks for all cells.
|
|
1465
|
+
*/
|
|
1466
|
+
rowExtrasEquals(y: number, other: TerminalBuffer): boolean;
|
|
1467
|
+
}
|
|
1468
|
+
//#endregion
|
|
1469
|
+
//#region packages/ag-term/src/runtime/types.d.ts
|
|
1470
|
+
/**
|
|
1471
|
+
* Dimensions for rendering.
|
|
1472
|
+
*/
|
|
1473
|
+
interface Dims {
|
|
1474
|
+
cols: number;
|
|
1475
|
+
rows: number;
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Immutable render output buffer.
|
|
1479
|
+
*
|
|
1480
|
+
* Contains:
|
|
1481
|
+
* - text: Plain text without ANSI codes (for assertions)
|
|
1482
|
+
* - ansi: Styled output with ANSI escape codes
|
|
1483
|
+
* - nodes: Internal node tree for locator queries
|
|
1484
|
+
*/
|
|
1485
|
+
interface Buffer$1 {
|
|
1486
|
+
/** Plain text without ANSI codes */
|
|
1487
|
+
readonly text: string;
|
|
1488
|
+
/** Styled output with ANSI escape codes */
|
|
1489
|
+
readonly ansi: string;
|
|
1490
|
+
/** Internal node tree for locator queries */
|
|
1491
|
+
readonly nodes: AgNode;
|
|
1492
|
+
/** Raw terminal buffer for diffing */
|
|
1493
|
+
readonly _buffer: TerminalBuffer;
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Event types from the runtime.
|
|
1497
|
+
*/
|
|
1498
|
+
type Event = {
|
|
1499
|
+
type: "key";
|
|
1500
|
+
key: string;
|
|
1501
|
+
ctrl?: boolean;
|
|
1502
|
+
meta?: boolean;
|
|
1503
|
+
shift?: boolean;
|
|
1504
|
+
} | {
|
|
1505
|
+
type: "mouse";
|
|
1506
|
+
button: number;
|
|
1507
|
+
x: number;
|
|
1508
|
+
y: number;
|
|
1509
|
+
action: "down" | "up" | "move" | "wheel";
|
|
1510
|
+
delta?: number;
|
|
1511
|
+
shift: boolean;
|
|
1512
|
+
meta: boolean;
|
|
1513
|
+
ctrl: boolean;
|
|
1514
|
+
} | {
|
|
1515
|
+
type: "paste";
|
|
1516
|
+
content: string;
|
|
1517
|
+
} | {
|
|
1518
|
+
type: "resize";
|
|
1519
|
+
cols: number;
|
|
1520
|
+
rows: number;
|
|
1521
|
+
} | {
|
|
1522
|
+
type: "tick";
|
|
1523
|
+
time: number;
|
|
1524
|
+
} | {
|
|
1525
|
+
type: "effect";
|
|
1526
|
+
id: string;
|
|
1527
|
+
result: unknown;
|
|
1528
|
+
} | {
|
|
1529
|
+
type: "error";
|
|
1530
|
+
error: Error;
|
|
1531
|
+
};
|
|
1532
|
+
/**
|
|
1533
|
+
* Render target interface - abstracts terminal output.
|
|
1534
|
+
*/
|
|
1535
|
+
interface RenderTarget {
|
|
1536
|
+
/** Write rendered frame to output */
|
|
1537
|
+
write(frame: string): void;
|
|
1538
|
+
/** Get current dimensions */
|
|
1539
|
+
getDims(): Dims;
|
|
1540
|
+
/** Subscribe to resize events */
|
|
1541
|
+
onResize?(handler: (dims: Dims) => void): () => void;
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Runtime options for createRuntime().
|
|
1545
|
+
*/
|
|
1546
|
+
interface RuntimeOptions {
|
|
1547
|
+
/** Render target (terminal, test mock, etc.) */
|
|
1548
|
+
target: RenderTarget;
|
|
1549
|
+
/** Abort signal for cleanup */
|
|
1550
|
+
signal?: AbortSignal;
|
|
1551
|
+
/** Render mode: fullscreen (alt screen) or inline (scrollback-compatible) */
|
|
1552
|
+
mode?: "fullscreen" | "inline";
|
|
1553
|
+
/** Scoped output phase function (from createOutputPhase/createPipeline). When provided,
|
|
1554
|
+
* runtime.render() uses this instead of the raw outputPhase — ensures measurer/caps are threaded. */
|
|
1555
|
+
outputPhaseFn?: (prev: TerminalBuffer | null, next: TerminalBuffer, mode?: "fullscreen" | "inline", scrollbackOffset?: number, termRows?: number) => string;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* The runtime kernel interface.
|
|
1559
|
+
*/
|
|
1560
|
+
interface Runtime {
|
|
1561
|
+
/** Event stream - yields until disposed */
|
|
1562
|
+
events(): AsyncIterable<Event>;
|
|
1563
|
+
/** Schedule an effect with optional cancellation */
|
|
1564
|
+
schedule<T>(effect: () => Promise<T>, opts?: {
|
|
1565
|
+
signal?: AbortSignal;
|
|
1566
|
+
}): void;
|
|
1567
|
+
/** Render a buffer to the target */
|
|
1568
|
+
render(buffer: Buffer$1): void;
|
|
1569
|
+
/** Report lines written to stdout between renders (inline mode only) */
|
|
1570
|
+
addScrollbackLines(lines: number): void;
|
|
1571
|
+
/** Reset diff state so next render outputs a full frame */
|
|
1572
|
+
invalidate(): void;
|
|
1573
|
+
/** Update the output phase function (e.g., after text sizing probe changes measurer) */
|
|
1574
|
+
setOutputPhaseFn(fn: RuntimeOptions["outputPhaseFn"]): void;
|
|
1575
|
+
/** Reset inline cursor tracking state (inline mode only).
|
|
1576
|
+
* Called by useScrollback before re-emitting frozen items on resize. */
|
|
1577
|
+
resetInlineCursor(): void;
|
|
1578
|
+
/** Get inline cursor row relative to render region start. -1 if unknown. */
|
|
1579
|
+
getInlineCursorRow(): number;
|
|
1580
|
+
/** Promote frozen content to scrollback via the output phase.
|
|
1581
|
+
* Content is written in a single frame with the live render — no flicker. */
|
|
1582
|
+
promoteScrollback(content: string, lines: number): void;
|
|
1583
|
+
/** Get current dimensions */
|
|
1584
|
+
getDims(): Dims;
|
|
1585
|
+
/** Dispose and cleanup - idempotent */
|
|
1586
|
+
[Symbol.dispose](): void;
|
|
1587
|
+
}
|
|
1588
|
+
/**
|
|
1589
|
+
* Event emitted by a provider, tagged with event type.
|
|
1590
|
+
*/
|
|
1591
|
+
type ProviderEvent<Events extends Record<string, unknown>> = { [K in keyof Events]: {
|
|
1592
|
+
type: K;
|
|
1593
|
+
data: Events[K];
|
|
1594
|
+
} }[keyof Events];
|
|
1595
|
+
/**
|
|
1596
|
+
* Provider interface - unified store + event source.
|
|
1597
|
+
*
|
|
1598
|
+
* Providers are the building blocks of silvery-loop applications.
|
|
1599
|
+
* They encapsulate:
|
|
1600
|
+
* - State (Zustand-compatible: getState/subscribe)
|
|
1601
|
+
* - Events (AsyncIterable of typed events)
|
|
1602
|
+
* - Cleanup (Symbol.dispose)
|
|
1603
|
+
*
|
|
1604
|
+
* @example
|
|
1605
|
+
* ```typescript
|
|
1606
|
+
* type TermProvider = Provider<
|
|
1607
|
+
* { cols: number; rows: number },
|
|
1608
|
+
* { key: { input: string; key: Key }; resize: Dims }
|
|
1609
|
+
* >;
|
|
1610
|
+
* ```
|
|
1611
|
+
*/
|
|
1612
|
+
interface Provider<State = unknown, Events extends Record<string, unknown> = Record<string, never>> {
|
|
1613
|
+
/** Get current state (Zustand-compatible) */
|
|
1614
|
+
getState(): State;
|
|
1615
|
+
/** Subscribe to state changes (Zustand-compatible) */
|
|
1616
|
+
subscribe(listener: (state: State) => void): () => void;
|
|
1617
|
+
/** Event stream - yields typed events until disposed */
|
|
1618
|
+
events(): AsyncIterable<ProviderEvent<Events>>;
|
|
1619
|
+
/** Cleanup resources */
|
|
1620
|
+
[Symbol.dispose](): void;
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Extract the namespaced event type from a providers map.
|
|
1624
|
+
*
|
|
1625
|
+
* Given { term: TermProvider, sync: SyncProvider }, produces:
|
|
1626
|
+
* | { type: 'term:key'; data: { input: string; key: Key } }
|
|
1627
|
+
* | { type: 'term:resize'; data: Dims }
|
|
1628
|
+
* | { type: 'sync:data'; data: Item[] }
|
|
1629
|
+
* | ...
|
|
1630
|
+
*/
|
|
1631
|
+
type NamespacedEvent<Providers extends Record<string, Provider<unknown, Record<string, unknown>>>> = { [P in keyof Providers]: Providers[P] extends Provider<unknown, infer E> ? { [K in keyof E & string]: {
|
|
1632
|
+
type: `${P & string}:${K}`;
|
|
1633
|
+
data: E[K];
|
|
1634
|
+
} }[keyof E & string] : never }[keyof Providers];
|
|
1635
|
+
/**
|
|
1636
|
+
* Extract all event keys from a providers map.
|
|
1637
|
+
*
|
|
1638
|
+
* Given { term: TermProvider, sync: SyncProvider }, produces:
|
|
1639
|
+
* 'term:key' | 'term:resize' | 'sync:data' | ...
|
|
1640
|
+
*/
|
|
1641
|
+
type ProviderEventKey<Providers extends Record<string, Provider<unknown, Record<string, unknown>>>> = NamespacedEvent<Providers>["type"];
|
|
1642
|
+
/**
|
|
1643
|
+
* Get the data type for a specific event key.
|
|
1644
|
+
*/
|
|
1645
|
+
type EventData<Providers extends Record<string, Provider<unknown, Record<string, unknown>>>, K extends ProviderEventKey<Providers>> = Extract<NamespacedEvent<Providers>, {
|
|
1646
|
+
type: K;
|
|
1647
|
+
}>["data"];
|
|
1648
|
+
//#endregion
|
|
1649
|
+
//#region packages/ag-term/src/mouse.d.ts
|
|
1650
|
+
/**
|
|
1651
|
+
* SGR mouse event parsing (mode 1006).
|
|
1652
|
+
*
|
|
1653
|
+
* SGR format: CSI < button;x;y M (press) or CSI < button;x;y m (release)
|
|
1654
|
+
*
|
|
1655
|
+
* Button encoding:
|
|
1656
|
+
* - Bits 0-1: 0=left, 1=middle, 2=right, 3=release (X10 only, not SGR)
|
|
1657
|
+
* - Bit 2 (+4): Shift held
|
|
1658
|
+
* - Bit 3 (+8): Meta/Alt held
|
|
1659
|
+
* - Bit 4 (+16): Ctrl held
|
|
1660
|
+
* - Bit 5 (+32): Motion event (mouse moved while button held)
|
|
1661
|
+
* - Bits 6-7: 64=wheel-up, 65=wheel-down, 66=wheel-left, 67=wheel-right
|
|
1662
|
+
*/
|
|
1663
|
+
/**
|
|
1664
|
+
* Parsed mouse event from SGR mouse protocol (mode 1006).
|
|
1665
|
+
*/
|
|
1666
|
+
interface ParsedMouse {
|
|
1667
|
+
/** Mouse button: 0=left, 1=middle, 2=right */
|
|
1668
|
+
button: number;
|
|
1669
|
+
/** Column (0-indexed) */
|
|
1670
|
+
x: number;
|
|
1671
|
+
/** Row (0-indexed) */
|
|
1672
|
+
y: number;
|
|
1673
|
+
/** Event action */
|
|
1674
|
+
action: "down" | "up" | "move" | "wheel";
|
|
1675
|
+
/** Wheel delta: -1 for up, +1 for down */
|
|
1676
|
+
delta?: number;
|
|
1677
|
+
/** Shift was held */
|
|
1678
|
+
shift: boolean;
|
|
1679
|
+
/** Alt/Meta was held */
|
|
1680
|
+
meta: boolean;
|
|
1681
|
+
/** Ctrl was held */
|
|
1682
|
+
ctrl: boolean;
|
|
1683
|
+
}
|
|
1684
|
+
/**
|
|
1685
|
+
* Parse an SGR mouse sequence.
|
|
1686
|
+
*
|
|
1687
|
+
* @returns ParsedMouse or null if not a valid mouse sequence
|
|
1688
|
+
*/
|
|
1689
|
+
declare function parseMouseSequence(input: string): ParsedMouse | null;
|
|
1690
|
+
/** Check if a raw input string is a mouse sequence */
|
|
1691
|
+
declare function isMouseSequence(input: string): boolean;
|
|
1692
|
+
//#endregion
|
|
1693
|
+
//#region packages/ag-term/src/runtime/term-provider.d.ts
|
|
1694
|
+
/**
|
|
1695
|
+
* Terminal state.
|
|
1696
|
+
*/
|
|
1697
|
+
interface TermState {
|
|
1698
|
+
cols: number;
|
|
1699
|
+
rows: number;
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Terminal events.
|
|
1703
|
+
*/
|
|
1704
|
+
interface TermEvents {
|
|
1705
|
+
key: {
|
|
1706
|
+
input: string;
|
|
1707
|
+
key: Key;
|
|
1708
|
+
};
|
|
1709
|
+
mouse: ParsedMouse;
|
|
1710
|
+
paste: {
|
|
1711
|
+
text: string;
|
|
1712
|
+
};
|
|
1713
|
+
resize: Dims;
|
|
1714
|
+
focus: {
|
|
1715
|
+
focused: boolean;
|
|
1716
|
+
};
|
|
1717
|
+
[key: string]: unknown;
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Terminal provider type.
|
|
1721
|
+
*/
|
|
1722
|
+
type TermProvider = Provider<TermState, TermEvents>;
|
|
1723
|
+
/**
|
|
1724
|
+
* Options for createTermProvider.
|
|
1725
|
+
*/
|
|
1726
|
+
interface TermProviderOptions {
|
|
1727
|
+
/** Initial columns (default: from stdout or 80) */
|
|
1728
|
+
cols?: number;
|
|
1729
|
+
/** Initial rows (default: from stdout or 24) */
|
|
1730
|
+
rows?: number;
|
|
1731
|
+
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Create a terminal provider from stdin/stdout.
|
|
1734
|
+
*
|
|
1735
|
+
* The provider:
|
|
1736
|
+
* - Exposes terminal dimensions as state
|
|
1737
|
+
* - Yields keyboard and resize events
|
|
1738
|
+
* - Cleans up stdin/stdout listeners on dispose
|
|
1739
|
+
*/
|
|
1740
|
+
declare function createTermProvider(stdin: NodeJS.ReadStream, stdout: NodeJS.WriteStream, options?: TermProviderOptions): TermProvider;
|
|
1741
|
+
//#endregion
|
|
1742
|
+
//#region packages/ag-term/src/ansi/term.d.ts
|
|
1743
|
+
/**
|
|
1744
|
+
* All chalk style method names that can be chained.
|
|
1745
|
+
*/
|
|
1746
|
+
type ChalkStyleName = "reset" | "bold" | "dim" | "italic" | "underline" | "overline" | "inverse" | "hidden" | "strikethrough" | "visible" | "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray" | "grey" | "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright" | "bgBlack" | "bgRed" | "bgGreen" | "bgYellow" | "bgBlue" | "bgMagenta" | "bgCyan" | "bgWhite" | "bgGray" | "bgGrey" | "bgBlackBright" | "bgRedBright" | "bgGreenBright" | "bgYellowBright" | "bgBlueBright" | "bgMagentaBright" | "bgCyanBright" | "bgWhiteBright";
|
|
1747
|
+
/**
|
|
1748
|
+
* StyleChain provides chainable styling methods.
|
|
1749
|
+
* Each property returns a new chain, and the chain is callable.
|
|
1750
|
+
*/
|
|
1751
|
+
type StyleChain = {
|
|
1752
|
+
/**
|
|
1753
|
+
* Apply styles to text.
|
|
1754
|
+
*/
|
|
1755
|
+
(text: string): string;
|
|
1756
|
+
(template: TemplateStringsArray, ...values: unknown[]): string;
|
|
1757
|
+
/**
|
|
1758
|
+
* RGB foreground color.
|
|
1759
|
+
*/
|
|
1760
|
+
rgb(r: number, g: number, b: number): StyleChain;
|
|
1761
|
+
/**
|
|
1762
|
+
* Hex foreground color.
|
|
1763
|
+
*/
|
|
1764
|
+
hex(color: string): StyleChain;
|
|
1765
|
+
/**
|
|
1766
|
+
* 256-color foreground.
|
|
1767
|
+
*/
|
|
1768
|
+
ansi256(code: number): StyleChain;
|
|
1769
|
+
/**
|
|
1770
|
+
* RGB background color.
|
|
1771
|
+
*/
|
|
1772
|
+
bgRgb(r: number, g: number, b: number): StyleChain;
|
|
1773
|
+
/**
|
|
1774
|
+
* Hex background color.
|
|
1775
|
+
*/
|
|
1776
|
+
bgHex(color: string): StyleChain;
|
|
1777
|
+
/**
|
|
1778
|
+
* 256-color background.
|
|
1779
|
+
*/
|
|
1780
|
+
bgAnsi256(code: number): StyleChain;
|
|
1781
|
+
} & {
|
|
1782
|
+
/**
|
|
1783
|
+
* Chainable style properties.
|
|
1784
|
+
*/
|
|
1785
|
+
readonly [K in ChalkStyleName]: StyleChain };
|
|
1786
|
+
/**
|
|
1787
|
+
* Term — the central abstraction for terminal interaction.
|
|
1788
|
+
*
|
|
1789
|
+
* Term is both a styling helper (chainable ANSI via Proxy) and a
|
|
1790
|
+
* Provider (state + typed events). Pass it to `run()` or `createApp()`.
|
|
1791
|
+
*
|
|
1792
|
+
* Provides:
|
|
1793
|
+
* - Capability detection (cached on creation)
|
|
1794
|
+
* - Dimensions (live from stream)
|
|
1795
|
+
* - I/O (stdout, stdin, write, writeLine)
|
|
1796
|
+
* - Provider (getState, subscribe, events — key/mouse/resize)
|
|
1797
|
+
* - Styling (chainable via Proxy)
|
|
1798
|
+
* - Disposable lifecycle
|
|
1799
|
+
*
|
|
1800
|
+
* @example
|
|
1801
|
+
* ```ts
|
|
1802
|
+
* using term = createTerm()
|
|
1803
|
+
* await run(<App />, term)
|
|
1804
|
+
* ```
|
|
1805
|
+
*/
|
|
1806
|
+
interface Term extends Disposable, StyleChain {
|
|
1807
|
+
/**
|
|
1808
|
+
* Check if terminal supports cursor control (repositioning).
|
|
1809
|
+
* Returns false for dumb terminals and piped output.
|
|
1810
|
+
*/
|
|
1811
|
+
hasCursor(): boolean;
|
|
1812
|
+
/**
|
|
1813
|
+
* Check if terminal can read raw keystrokes.
|
|
1814
|
+
* Requires stdin to be a TTY with raw mode support.
|
|
1815
|
+
*/
|
|
1816
|
+
hasInput(): boolean;
|
|
1817
|
+
/**
|
|
1818
|
+
* Check color level supported by terminal.
|
|
1819
|
+
* Returns null if no color support.
|
|
1820
|
+
*/
|
|
1821
|
+
hasColor(): ColorLevel | null;
|
|
1822
|
+
/**
|
|
1823
|
+
* Check if terminal can render unicode symbols.
|
|
1824
|
+
*/
|
|
1825
|
+
hasUnicode(): boolean;
|
|
1826
|
+
/**
|
|
1827
|
+
* Terminal capabilities profile.
|
|
1828
|
+
* Detected when stdin is a TTY, undefined otherwise.
|
|
1829
|
+
* Override via createTerm({ caps: { ... } }).
|
|
1830
|
+
*/
|
|
1831
|
+
readonly caps: TerminalCaps | undefined;
|
|
1832
|
+
/**
|
|
1833
|
+
* Terminal width in columns.
|
|
1834
|
+
* Undefined if not a TTY or dimensions unavailable.
|
|
1835
|
+
*/
|
|
1836
|
+
readonly cols: number | undefined;
|
|
1837
|
+
/**
|
|
1838
|
+
* Terminal height in rows.
|
|
1839
|
+
* Undefined if not a TTY or dimensions unavailable.
|
|
1840
|
+
*/
|
|
1841
|
+
readonly rows: number | undefined;
|
|
1842
|
+
/**
|
|
1843
|
+
* Output stream (defaults to process.stdout).
|
|
1844
|
+
*/
|
|
1845
|
+
readonly stdout: NodeJS.WriteStream;
|
|
1846
|
+
/**
|
|
1847
|
+
* Input stream (defaults to process.stdin).
|
|
1848
|
+
*/
|
|
1849
|
+
readonly stdin: NodeJS.ReadStream;
|
|
1850
|
+
/**
|
|
1851
|
+
* Write string to stdout.
|
|
1852
|
+
*/
|
|
1853
|
+
write(str: string): void;
|
|
1854
|
+
/**
|
|
1855
|
+
* Write string followed by newline to stdout.
|
|
1856
|
+
*/
|
|
1857
|
+
writeLine(str: string): void;
|
|
1858
|
+
/**
|
|
1859
|
+
* Get current terminal state (dimensions).
|
|
1860
|
+
* Always returns defined values (falls back to 80x24).
|
|
1861
|
+
*/
|
|
1862
|
+
getState(): TermState;
|
|
1863
|
+
/**
|
|
1864
|
+
* Subscribe to terminal state changes (resize).
|
|
1865
|
+
* Returns unsubscribe function.
|
|
1866
|
+
*/
|
|
1867
|
+
subscribe(listener: (state: TermState) => void): () => void;
|
|
1868
|
+
/**
|
|
1869
|
+
* Event stream — yields typed key, mouse, and resize events.
|
|
1870
|
+
* Enables raw mode on stdin when iterated. Cleans up on return.
|
|
1871
|
+
*/
|
|
1872
|
+
events(): AsyncIterable<ProviderEvent<TermEvents>>;
|
|
1873
|
+
/**
|
|
1874
|
+
* Strip ANSI escape codes from string.
|
|
1875
|
+
*/
|
|
1876
|
+
stripAnsi(str: string): string;
|
|
1877
|
+
/**
|
|
1878
|
+
* Visible screen region. Only available when created with a terminal backend.
|
|
1879
|
+
* Provides getText(), getLines(), containsText() for assertions.
|
|
1880
|
+
*/
|
|
1881
|
+
readonly screen?: TermScreen;
|
|
1882
|
+
/**
|
|
1883
|
+
* Scrollback region. Only available when created with a terminal backend.
|
|
1884
|
+
* Provides getText(), getLines(), containsText() for assertions.
|
|
1885
|
+
*/
|
|
1886
|
+
readonly scrollback?: TermScreen;
|
|
1887
|
+
/**
|
|
1888
|
+
* Cell-level access for the visible screen — row-first order.
|
|
1889
|
+
* Returns resolved RGB colors, attributes, wide-char info.
|
|
1890
|
+
* Only available on emulator-backed terms (createTermless).
|
|
1891
|
+
*/
|
|
1892
|
+
cell?(row: number, col: number): {
|
|
1893
|
+
readonly fg: unknown;
|
|
1894
|
+
readonly bg: unknown;
|
|
1895
|
+
readonly char: string;
|
|
1896
|
+
};
|
|
1897
|
+
/**
|
|
1898
|
+
* Row-level access for the visible screen.
|
|
1899
|
+
* Only available on emulator-backed terms (createTermless).
|
|
1900
|
+
*/
|
|
1901
|
+
row?(n: number): {
|
|
1902
|
+
getText(): string;
|
|
1903
|
+
cell(col: number): {
|
|
1904
|
+
readonly fg: unknown;
|
|
1905
|
+
readonly bg: unknown;
|
|
1906
|
+
readonly char: string;
|
|
1907
|
+
};
|
|
1908
|
+
};
|
|
1909
|
+
/**
|
|
1910
|
+
* Resize the terminal emulator. Only available when created with a terminal backend.
|
|
1911
|
+
* Resizes the underlying emulator and triggers a re-render in the app.
|
|
1912
|
+
*/
|
|
1913
|
+
resize?(cols: number, rows: number): void;
|
|
1914
|
+
/**
|
|
1915
|
+
* Paint a rendered buffer to produce ANSI output.
|
|
1916
|
+
* Diffs buffer against prev (fresh render if prev is null).
|
|
1917
|
+
* Updates term.frame with an immutable TextFrame snapshot.
|
|
1918
|
+
* Returns the ANSI output string.
|
|
1919
|
+
* For emulator backends, also feeds the output to the emulator.
|
|
1920
|
+
* For headless terms, returns empty string.
|
|
1921
|
+
*/
|
|
1922
|
+
paint?(buffer: TerminalBuffer, prev: TerminalBuffer | null): string;
|
|
1923
|
+
/**
|
|
1924
|
+
* Last painted TextFrame. Set after each paint() call.
|
|
1925
|
+
* Immutable snapshot with cell-level access and resolved RGB colors.
|
|
1926
|
+
*/
|
|
1927
|
+
readonly frame?: TextFrame;
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Create a Term instance.
|
|
1931
|
+
*
|
|
1932
|
+
* Factory overloads:
|
|
1933
|
+
* - `createTerm()` — Node.js terminal (auto-detect from process.stdin/stdout)
|
|
1934
|
+
* - `createTerm({ stdout, stdin, ... })` — Node.js with custom streams/overrides
|
|
1935
|
+
* - `createTerm({ cols, rows })` — Headless for testing (no I/O, fixed dims)
|
|
1936
|
+
* - `createTerm(backend, { cols, rows })` — Terminal emulator backend (termless) for testing
|
|
1937
|
+
* - `createTerm(emulator)` — Pre-created termless Terminal
|
|
1938
|
+
*
|
|
1939
|
+
* Detection results are cached at creation time for consistency.
|
|
1940
|
+
*
|
|
1941
|
+
* @example
|
|
1942
|
+
* ```ts
|
|
1943
|
+
* // Full terminal app
|
|
1944
|
+
* using term = createTerm()
|
|
1945
|
+
* await run(<App />, term)
|
|
1946
|
+
*
|
|
1947
|
+
* // Headless for testing
|
|
1948
|
+
* const term = createTerm({ cols: 80, rows: 24 })
|
|
1949
|
+
*
|
|
1950
|
+
* // Terminal emulator (termless) for full ANSI testing
|
|
1951
|
+
* using term = createTerm(createXtermBackend(), { cols: 80, rows: 24 })
|
|
1952
|
+
* await run(<App />, term)
|
|
1953
|
+
* expect(term.screen).toContainText("Hello")
|
|
1954
|
+
*
|
|
1955
|
+
* // Custom streams
|
|
1956
|
+
* const term = createTerm({ stdout: customStream })
|
|
1957
|
+
* ```
|
|
1958
|
+
*/
|
|
1959
|
+
declare function createTerm(options?: CreateTermOptions): Term;
|
|
1960
|
+
declare function createTerm(dims: {
|
|
1961
|
+
cols: number;
|
|
1962
|
+
rows: number;
|
|
1963
|
+
}): Term;
|
|
1964
|
+
declare function createTerm(backend: TermEmulatorBackend, dims: {
|
|
1965
|
+
cols: number;
|
|
1966
|
+
rows: number;
|
|
1967
|
+
}): Term;
|
|
1968
|
+
declare function createTerm(emulator: TermEmulator): Term;
|
|
1969
|
+
//#endregion
|
|
1970
|
+
//#region packages/ag-term/src/ansi/patch-console.d.ts
|
|
1971
|
+
/**
|
|
1972
|
+
* Aggregate counts of console output by severity.
|
|
1973
|
+
*/
|
|
1974
|
+
interface ConsoleStats {
|
|
1975
|
+
total: number;
|
|
1976
|
+
errors: number;
|
|
1977
|
+
warnings: number;
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* A patched console that intercepts methods and accumulates entries.
|
|
1981
|
+
* Compatible with React's useSyncExternalStore.
|
|
1982
|
+
*/
|
|
1983
|
+
interface PatchedConsole extends Disposable {
|
|
1984
|
+
/** Read current entries (for useSyncExternalStore). Empty when capture=false. */
|
|
1985
|
+
getSnapshot(): readonly ConsoleEntry[];
|
|
1986
|
+
/** Get aggregate counts (total, errors, warnings). Works in all modes. */
|
|
1987
|
+
getStats(): ConsoleStats;
|
|
1988
|
+
/** Subscribe to changes - called when new entry arrives. Returns unsubscribe function. */
|
|
1989
|
+
subscribe(onStoreChange: () => void): () => void;
|
|
1990
|
+
dispose(): void;
|
|
1991
|
+
[Symbol.dispose](): void;
|
|
1992
|
+
}
|
|
1993
|
+
interface PatchConsoleOptions {
|
|
1994
|
+
/**
|
|
1995
|
+
* Suppress original console output when true.
|
|
1996
|
+
* Use in TUI mode where you want console output only in a component.
|
|
1997
|
+
*/
|
|
1998
|
+
suppress?: boolean;
|
|
1999
|
+
/**
|
|
2000
|
+
* Store full entries in memory (default: true).
|
|
2001
|
+
* Set to false for count-only mode — getSnapshot() returns empty array,
|
|
2002
|
+
* but getStats() still tracks counts. Avoids unbounded memory growth.
|
|
2003
|
+
*/
|
|
2004
|
+
capture?: boolean;
|
|
2005
|
+
}
|
|
2006
|
+
/**
|
|
2007
|
+
* Patch console methods to intercept and track output.
|
|
2008
|
+
* Returns a disposable that restores original methods.
|
|
2009
|
+
*
|
|
2010
|
+
* @param console - The console object to patch
|
|
2011
|
+
* @param options - Configuration options
|
|
2012
|
+
* @param options.suppress - If true, don't call original methods (for TUI mode)
|
|
2013
|
+
* @param options.capture - If false, only count entries (no memory storage)
|
|
2014
|
+
*/
|
|
2015
|
+
declare function patchConsole(console: Console, options?: PatchConsoleOptions): PatchedConsole;
|
|
2016
|
+
//#endregion
|
|
2017
|
+
//#region packages/ag-term/src/ansi/index.d.ts
|
|
2018
|
+
declare const term: Term;
|
|
2019
|
+
//#endregion
|
|
2020
|
+
//#region packages/ag-react/src/hooks/useInput.d.ts
|
|
2021
|
+
/**
|
|
2022
|
+
* Options for useInput hook.
|
|
2023
|
+
*/
|
|
2024
|
+
interface UseInputOptions {
|
|
2025
|
+
/**
|
|
2026
|
+
* Enable or disable input handling.
|
|
2027
|
+
* Useful when there are multiple useInput hooks and you want to disable some.
|
|
2028
|
+
* @default true
|
|
2029
|
+
*/
|
|
2030
|
+
isActive?: boolean;
|
|
2031
|
+
/**
|
|
2032
|
+
* Callback for bracketed paste events.
|
|
2033
|
+
* When the terminal has bracketed paste mode enabled,
|
|
2034
|
+
* pasted text is delivered as a single string instead of
|
|
2035
|
+
* individual keystrokes.
|
|
2036
|
+
*/
|
|
2037
|
+
onPaste?: (text: string) => void;
|
|
2038
|
+
/**
|
|
2039
|
+
* Callback for key release events.
|
|
2040
|
+
* Requires Kitty protocol with REPORT_EVENTS flag enabled.
|
|
2041
|
+
* When provided, release events are dispatched here instead of being silently dropped.
|
|
2042
|
+
*
|
|
2043
|
+
* @example
|
|
2044
|
+
* ```tsx
|
|
2045
|
+
* useInput((input, key) => {
|
|
2046
|
+
* // Handle press/repeat events
|
|
2047
|
+
* }, {
|
|
2048
|
+
* onRelease: (input, key) => {
|
|
2049
|
+
* // Handle release events (e.g., stop scrolling, end drag)
|
|
2050
|
+
* },
|
|
2051
|
+
* })
|
|
2052
|
+
* ```
|
|
2053
|
+
*/
|
|
2054
|
+
onRelease?: InputHandler;
|
|
2055
|
+
}
|
|
2056
|
+
/**
|
|
2057
|
+
* Hook for handling user input.
|
|
2058
|
+
*
|
|
2059
|
+
* No-ops if RuntimeContext is not provided (i.e., outside a runtime).
|
|
2060
|
+
* Components render normally without input handling in static mode.
|
|
2061
|
+
* Use useRuntime() for components that need to detect interactive vs static mode.
|
|
2062
|
+
*
|
|
2063
|
+
* @example
|
|
2064
|
+
* ```tsx
|
|
2065
|
+
* function MyComponent() {
|
|
2066
|
+
* useInput((input, key) => {
|
|
2067
|
+
* if (input === 'q') {
|
|
2068
|
+
* // Quit
|
|
2069
|
+
* }
|
|
2070
|
+
* if (key.upArrow) {
|
|
2071
|
+
* // Move up
|
|
2072
|
+
* }
|
|
2073
|
+
* }, {
|
|
2074
|
+
* onRelease: (input, key) => {
|
|
2075
|
+
* // Handle key release (requires Kitty REPORT_EVENTS)
|
|
2076
|
+
* },
|
|
2077
|
+
* });
|
|
2078
|
+
*
|
|
2079
|
+
* return <Text>Press q to quit</Text>;
|
|
2080
|
+
* }
|
|
2081
|
+
* ```
|
|
2082
|
+
*/
|
|
2083
|
+
declare function useInput(inputHandler: InputHandler, options?: UseInputOptions): void;
|
|
2084
|
+
//#endregion
|
|
2085
|
+
//#region packages/ag-react/src/hooks/useExit.d.ts
|
|
2086
|
+
/**
|
|
2087
|
+
* useExit — programmatic exit hook.
|
|
2088
|
+
*
|
|
2089
|
+
* Thin wrapper over useApp().exit that throws outside a runtime
|
|
2090
|
+
* (unlike useApp which returns no-ops in static mode).
|
|
2091
|
+
*
|
|
2092
|
+
* Prefer `return "exit"` from useInput handlers when possible.
|
|
2093
|
+
* Use useExit() for imperative exit from event handlers, timers, etc.
|
|
2094
|
+
*/
|
|
2095
|
+
/**
|
|
2096
|
+
* Returns a function that exits the app.
|
|
2097
|
+
* Throws if called outside a runtime (run(), createApp(), test renderer).
|
|
2098
|
+
*/
|
|
2099
|
+
declare function useExit(): () => void;
|
|
2100
|
+
//#endregion
|
|
2101
|
+
//#region packages/ag/src/focus-manager.d.ts
|
|
2102
|
+
type FocusOrigin = "keyboard" | "mouse" | "programmatic";
|
|
2103
|
+
/**
|
|
2104
|
+
* Callback fired when focus changes. Used by the runtime to dispatch
|
|
2105
|
+
* DOM-level focus/blur events without coupling FocusManager to the event system.
|
|
2106
|
+
*
|
|
2107
|
+
* @param oldNode - The node losing focus (null if nothing was focused)
|
|
2108
|
+
* @param newNode - The node gaining focus (null on blur)
|
|
2109
|
+
* @param origin - How focus was acquired
|
|
2110
|
+
*/
|
|
2111
|
+
type FocusChangeCallback = (oldNode: AgNode | null, newNode: AgNode | null, origin: FocusOrigin | null) => void;
|
|
2112
|
+
interface FocusSnapshot {
|
|
2113
|
+
activeId: string | null;
|
|
2114
|
+
previousId: string | null;
|
|
2115
|
+
focusOrigin: FocusOrigin | null;
|
|
2116
|
+
scopeStack: readonly string[];
|
|
2117
|
+
/** The currently active peer scope (WPF FocusScope model) */
|
|
2118
|
+
activeScopeId: string | null;
|
|
2119
|
+
}
|
|
2120
|
+
interface FocusManagerOptions {
|
|
2121
|
+
/** Called when focus changes — wire up event dispatch here */
|
|
2122
|
+
onFocusChange?: FocusChangeCallback;
|
|
2123
|
+
}
|
|
2124
|
+
/**
|
|
2125
|
+
* Options for registering a hook-based (virtual) focusable.
|
|
2126
|
+
*
|
|
2127
|
+
* Hook focusables are registered via React hooks (e.g. `useFocus()` in the
|
|
2128
|
+
* Ink compat layer) rather than by the `focusable` prop on a tree node. They
|
|
2129
|
+
* participate in Tab cycling but don't have a backing `AgNode` — activeId
|
|
2130
|
+
* tracking is by id only, and `activeElement` is null when a hook focusable
|
|
2131
|
+
* is the active target.
|
|
2132
|
+
*/
|
|
2133
|
+
interface HookFocusableOptions {
|
|
2134
|
+
/** Registration is inert when false — skipped in tab order, never reports focused */
|
|
2135
|
+
isActive?: boolean;
|
|
2136
|
+
/** Focus this id when registered (only when isActive !== false) */
|
|
2137
|
+
autoFocus?: boolean;
|
|
2138
|
+
}
|
|
2139
|
+
interface FocusManager {
|
|
2140
|
+
/** Currently focused node */
|
|
2141
|
+
readonly activeElement: AgNode | null;
|
|
2142
|
+
/** testID of the currently focused node */
|
|
2143
|
+
readonly activeId: string | null;
|
|
2144
|
+
/** Previously focused node */
|
|
2145
|
+
readonly previousElement: AgNode | null;
|
|
2146
|
+
/** testID of the previously focused node */
|
|
2147
|
+
readonly previousId: string | null;
|
|
2148
|
+
/** How focus was most recently acquired */
|
|
2149
|
+
readonly focusOrigin: FocusOrigin | null;
|
|
2150
|
+
/** Stack of active focus scope IDs */
|
|
2151
|
+
readonly scopeStack: readonly string[];
|
|
2152
|
+
/** Map of scope ID -> last focused testID within that scope */
|
|
2153
|
+
readonly scopeMemory: Readonly<Record<string, string>>;
|
|
2154
|
+
/** Focus a specific node */
|
|
2155
|
+
focus(node: AgNode, origin?: FocusOrigin): void;
|
|
2156
|
+
/** Focus a node by testID (requires root for tree search) */
|
|
2157
|
+
focusById(id: string, root: AgNode, origin?: FocusOrigin): void;
|
|
2158
|
+
/**
|
|
2159
|
+
* Focus a hook-registered (virtual) id directly without tree traversal.
|
|
2160
|
+
* Unlike `focusById`, this never needs a root — used by `useFocus()` hooks
|
|
2161
|
+
* that track focus by id only.
|
|
2162
|
+
*/
|
|
2163
|
+
focusVirtualId(id: string, origin?: FocusOrigin): void;
|
|
2164
|
+
/** Clear focus */
|
|
2165
|
+
blur(): void;
|
|
2166
|
+
/**
|
|
2167
|
+
* Register a hook-based focusable id (e.g. from `useFocus()` in Ink compat).
|
|
2168
|
+
*
|
|
2169
|
+
* Hook focusables form a flat list alongside the tree-based focusables.
|
|
2170
|
+
* `focusNext`/`focusPrev` interleave: tree focusables come first (document
|
|
2171
|
+
* order), then hook focusables (registration order). A single unified tab
|
|
2172
|
+
* cycle walks both.
|
|
2173
|
+
*
|
|
2174
|
+
* Returns an unregister callback (safe to call on effect cleanup).
|
|
2175
|
+
*/
|
|
2176
|
+
registerHookFocusable(id: string, options?: HookFocusableOptions): () => void;
|
|
2177
|
+
/** Update an existing hook-focusable's active state. */
|
|
2178
|
+
setHookFocusableActive(id: string, isActive: boolean): void;
|
|
2179
|
+
/** Whether any hook focusables are currently registered. */
|
|
2180
|
+
readonly hasHookFocusables: boolean;
|
|
2181
|
+
/**
|
|
2182
|
+
* Global focus enable (Ink compat). When false, `focusNext`/`focusPrev`
|
|
2183
|
+
* become no-ops for hook-registered focusables. Tree-based focusables
|
|
2184
|
+
* ignore this flag — apps using `useFocusable` are not affected.
|
|
2185
|
+
*/
|
|
2186
|
+
readonly hookFocusEnabled: boolean;
|
|
2187
|
+
setHookFocusEnabled(enabled: boolean): void;
|
|
2188
|
+
/**
|
|
2189
|
+
* Handle a subtree being removed from the tree.
|
|
2190
|
+
* If the focused node (or previous node) is within the removed subtree,
|
|
2191
|
+
* clear the reference to prevent dead node retention and broken navigation.
|
|
2192
|
+
*/
|
|
2193
|
+
handleSubtreeRemoved(removedRoot: AgNode): void;
|
|
2194
|
+
/** Push a focus scope onto the stack */
|
|
2195
|
+
enterScope(scopeId: string): void;
|
|
2196
|
+
/** Pop the current focus scope */
|
|
2197
|
+
exitScope(): void;
|
|
2198
|
+
/** The currently active peer scope ID (WPF FocusScope model) */
|
|
2199
|
+
readonly activeScopeId: string | null;
|
|
2200
|
+
/**
|
|
2201
|
+
* Activate a peer focus scope. Saves current focus in the old scope's memory,
|
|
2202
|
+
* switches to the new scope, and restores the remembered focus (or focuses
|
|
2203
|
+
* the first focusable element in the scope subtree).
|
|
2204
|
+
*/
|
|
2205
|
+
activateScope(scopeId: string, root: AgNode): void;
|
|
2206
|
+
/** Get the testID path from focused node to root */
|
|
2207
|
+
getFocusPath(root: AgNode): string[];
|
|
2208
|
+
/** Check if a subtree rooted at testID contains the focused node */
|
|
2209
|
+
hasFocusWithin(root: AgNode, testID: string): boolean;
|
|
2210
|
+
/** Focus the next focusable node in tab order */
|
|
2211
|
+
focusNext(root: AgNode, scope?: AgNode): void;
|
|
2212
|
+
/** Focus the previous focusable node in tab order */
|
|
2213
|
+
focusPrev(root: AgNode, scope?: AgNode): void;
|
|
2214
|
+
/** Focus in a spatial direction (up/down/left/right) */
|
|
2215
|
+
focusDirection(root: AgNode, direction: "up" | "down" | "left" | "right", layoutFn?: (node: AgNode) => Rect | null): void;
|
|
2216
|
+
/** Subscribe for React integration (useSyncExternalStore) */
|
|
2217
|
+
subscribe(listener: () => void): () => void;
|
|
2218
|
+
/** Get immutable snapshot for useSyncExternalStore */
|
|
2219
|
+
getSnapshot(): FocusSnapshot;
|
|
2220
|
+
}
|
|
2221
|
+
declare function createFocusManager(options?: FocusManagerOptions): FocusManager;
|
|
2222
|
+
//#endregion
|
|
2223
|
+
//#region packages/ag/src/focus-queries.d.ts
|
|
2224
|
+
/**
|
|
2225
|
+
* Walk up from node to nearest ancestor (or self) with focusable prop.
|
|
2226
|
+
* Useful for mouse clicks — find the focusable target from a deep text node.
|
|
2227
|
+
*/
|
|
2228
|
+
declare function findFocusableAncestor(node: AgNode): AgNode | null;
|
|
2229
|
+
/**
|
|
2230
|
+
* DFS traversal of focusable nodes in tab order, optionally scoped.
|
|
2231
|
+
*
|
|
2232
|
+
* When scope is provided, only nodes within that scope subtree are included.
|
|
2233
|
+
* If a focusScope node is encountered during traversal, its children are
|
|
2234
|
+
* skipped (they belong to a different scope), unless that scope IS the
|
|
2235
|
+
* provided scope node.
|
|
2236
|
+
*/
|
|
2237
|
+
declare function getTabOrder(root: AgNode, scope?: AgNode): AgNode[];
|
|
2238
|
+
/**
|
|
2239
|
+
* Walk up from a node to find the nearest ancestor (or self) with focusScope prop.
|
|
2240
|
+
* Returns the testID of the enclosing scope, or null if none found.
|
|
2241
|
+
*/
|
|
2242
|
+
declare function findEnclosingScope(node: AgNode): string | null;
|
|
2243
|
+
/**
|
|
2244
|
+
* Find a node by testID in the subtree rooted at root.
|
|
2245
|
+
* DFS, returns the first match.
|
|
2246
|
+
*/
|
|
2247
|
+
declare function findByTestID(root: AgNode, testID: string): AgNode | null;
|
|
2248
|
+
/**
|
|
2249
|
+
* Find the nearest focusable candidate in a given direction using
|
|
2250
|
+
* 45-degree cone heuristic (tvOS-style spatial navigation).
|
|
2251
|
+
*
|
|
2252
|
+
* From the center of the source rect, draw a cone in the target direction.
|
|
2253
|
+
* Filter candidates whose center falls within the cone. Pick the closest
|
|
2254
|
+
* by Euclidean distance.
|
|
2255
|
+
*
|
|
2256
|
+
* @param from - The currently focused node
|
|
2257
|
+
* @param direction - Direction to search
|
|
2258
|
+
* @param candidates - All focusable nodes to consider
|
|
2259
|
+
* @param layoutFn - Function to get screen rect for a node (null if not laid out)
|
|
2260
|
+
*/
|
|
2261
|
+
declare function findSpatialTarget(from: AgNode, direction: "up" | "down" | "left" | "right", candidates: AgNode[], layoutFn: (node: AgNode) => Rect | null): AgNode | null;
|
|
2262
|
+
/**
|
|
2263
|
+
* Check if a node has an explicit nextFocus{Direction} override prop.
|
|
2264
|
+
*
|
|
2265
|
+
* These props allow components to declare explicit focus targets for
|
|
2266
|
+
* spatial navigation, overriding the cone heuristic.
|
|
2267
|
+
*
|
|
2268
|
+
* @param node - The node to check
|
|
2269
|
+
* @param direction - Direction string: "up", "down", "left", "right"
|
|
2270
|
+
* @returns The testID of the explicit target, or null
|
|
2271
|
+
*/
|
|
2272
|
+
declare function getExplicitFocusLink(node: AgNode, direction: string): string | null;
|
|
2273
|
+
//#endregion
|
|
2274
|
+
//#region packages/ag-react/src/context.d.ts
|
|
2275
|
+
/**
|
|
2276
|
+
* Context that provides access to the Term instance.
|
|
2277
|
+
* Used by useTerm() hook to access terminal capabilities and styling.
|
|
2278
|
+
*/
|
|
2279
|
+
declare const TermContext: _$react.Context<Term | null>;
|
|
2280
|
+
interface StderrContextValue {
|
|
2281
|
+
/** Standard error stream */
|
|
2282
|
+
stderr: NodeJS.WriteStream;
|
|
2283
|
+
/** Write to stderr */
|
|
2284
|
+
write: (data: string) => void;
|
|
2285
|
+
}
|
|
2286
|
+
/**
|
|
2287
|
+
* Context for stderr access.
|
|
2288
|
+
* Used by useStderr() hook.
|
|
2289
|
+
*/
|
|
2290
|
+
declare const StderrContext: _$react.Context<StderrContextValue | null>;
|
|
2291
|
+
/**
|
|
2292
|
+
* Base events every runtime provides.
|
|
2293
|
+
* Apps extend this to add custom events (e.g., BoardEvents adds "op").
|
|
2294
|
+
*/
|
|
2295
|
+
interface BaseRuntimeEvents {
|
|
2296
|
+
/** Keyboard input: [parsedInput, keyMetadata] */
|
|
2297
|
+
input: [input: string, key: Key];
|
|
2298
|
+
/** Bracketed paste: [pastedText] */
|
|
2299
|
+
paste: [text: string];
|
|
2300
|
+
/** Terminal window focus change: [isFocused] */
|
|
2301
|
+
focus: [focused: boolean];
|
|
2302
|
+
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Extract handler function type from an event map entry.
|
|
2305
|
+
*/
|
|
2306
|
+
type EventHandler$1<Args extends unknown[]> = (...args: Args) => void;
|
|
2307
|
+
/**
|
|
2308
|
+
* Typed bidirectional event bus + app lifecycle controls.
|
|
2309
|
+
*
|
|
2310
|
+
* Replaces EventsContext, InputContext, StdinContext, and AppContext with
|
|
2311
|
+
* a single typed interface. Components never see stdin or raw mode.
|
|
2312
|
+
*
|
|
2313
|
+
* Generic parameter E extends BaseRuntimeEvents — all runtimes provide
|
|
2314
|
+
* at least "input" and "paste" events. Apps can extend with custom events:
|
|
2315
|
+
*
|
|
2316
|
+
* ```tsx
|
|
2317
|
+
* interface BoardEvents extends BaseRuntimeEvents {
|
|
2318
|
+
* op: [BoardOp]
|
|
2319
|
+
* }
|
|
2320
|
+
* const rt = useRuntime<BoardEvents>()
|
|
2321
|
+
* rt?.on("input", handler) // runtime → view
|
|
2322
|
+
* rt?.emit("op", { type: "cursor_down" }) // view → runtime
|
|
2323
|
+
* ```
|
|
2324
|
+
*
|
|
2325
|
+
* Present in interactive mode (run/render/createApp/test renderer).
|
|
2326
|
+
* Absent (null) in static mode (renderStatic).
|
|
2327
|
+
*/
|
|
2328
|
+
interface RuntimeContextValue<E extends BaseRuntimeEvents = BaseRuntimeEvents> {
|
|
2329
|
+
/** Subscribe to a typed event. Returns cleanup function. */
|
|
2330
|
+
on<K extends string & keyof E>(event: K, handler: EventHandler$1<E[K] extends unknown[] ? E[K] : never>): () => void;
|
|
2331
|
+
/** Emit a typed event (view → runtime). */
|
|
2332
|
+
emit<K extends string & keyof E>(event: K, ...args: E[K] extends unknown[] ? E[K] : never): void;
|
|
2333
|
+
/** Exit the application with optional error. */
|
|
2334
|
+
exit: (error?: Error) => void;
|
|
2335
|
+
/** Pause rendering output (for screen switching). */
|
|
2336
|
+
pause?: () => void;
|
|
2337
|
+
/** Resume rendering after pause. */
|
|
2338
|
+
resume?: () => void;
|
|
2339
|
+
}
|
|
2340
|
+
/**
|
|
2341
|
+
* Context that provides the typed runtime event bus.
|
|
2342
|
+
*
|
|
2343
|
+
* When non-null: interactive mode — useInput works, components can subscribe
|
|
2344
|
+
* to events via rt.on() and emit via rt.emit().
|
|
2345
|
+
*
|
|
2346
|
+
* When null: static mode — useInput throws (by design), use useRuntime()
|
|
2347
|
+
* for components that need to work in both modes.
|
|
2348
|
+
*/
|
|
2349
|
+
declare const RuntimeContext: _$react.Context<RuntimeContextValue<BaseRuntimeEvents> | null>;
|
|
2350
|
+
/**
|
|
2351
|
+
* Cache backend type — determines where ListView stores cached items.
|
|
2352
|
+
* - "terminal": Write to stdout as native scrollback (inline mode)
|
|
2353
|
+
* - "virtual": In-memory HistoryBuffer ring buffer (fullscreen + virtualInline)
|
|
2354
|
+
* - "retain": Cache items but keep them in the render tree (plain fullscreen
|
|
2355
|
+
* without virtual scrollback — the virtualizer handles windowing)
|
|
2356
|
+
*/
|
|
2357
|
+
type CacheBackend = "terminal" | "virtual" | "retain";
|
|
2358
|
+
/**
|
|
2359
|
+
* Context that provides the cache backend to ListView.
|
|
2360
|
+
* Set by the runtime based on rendering mode:
|
|
2361
|
+
* - alternateScreen: false (inline) → "terminal"
|
|
2362
|
+
* - alternateScreen: true + virtualInline → "virtual"
|
|
2363
|
+
* - alternateScreen: true (plain fullscreen) → "retain"
|
|
2364
|
+
*
|
|
2365
|
+
* Default: "virtual" (safe fallback for test renderers — items unmount as expected)
|
|
2366
|
+
*/
|
|
2367
|
+
declare const CacheBackendContext: _$react.Context<CacheBackend>;
|
|
2368
|
+
/**
|
|
2369
|
+
* Context for the tree-based focus manager.
|
|
2370
|
+
* Provides the FocusManager instance to useFocusable(), useFocusWithin(), and useFocusManager() hooks.
|
|
2371
|
+
*/
|
|
2372
|
+
declare const FocusManagerContext: _$react.Context<FocusManager | null>;
|
|
2373
|
+
/**
|
|
2374
|
+
* Minimal capability lookup interface — matches CapabilityRegistry.get().
|
|
2375
|
+
* Defined here to avoid a dependency from ag-react → @silvery/create internals.
|
|
2376
|
+
*/
|
|
2377
|
+
interface CapabilityLookup {
|
|
2378
|
+
get<T>(key: symbol): T | undefined;
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Context for the capability registry (from @silvery/create composition).
|
|
2382
|
+
*
|
|
2383
|
+
* Provided by createApp() when a capabilityRegistry exists on the app object.
|
|
2384
|
+
* Hooks like useSelection() use this to discover interaction features
|
|
2385
|
+
* (e.g., SelectionFeature) without coupling to the composition layer.
|
|
2386
|
+
*
|
|
2387
|
+
* Returns null in simple `run()` or `render()` apps that don't use pipe() composition.
|
|
2388
|
+
*/
|
|
2389
|
+
declare const CapabilityRegistryContext: _$react.Context<CapabilityLookup | null>;
|
|
2390
|
+
//#endregion
|
|
2391
|
+
//#region packages/create/src/signal-store.d.ts
|
|
2392
|
+
/**
|
|
2393
|
+
* Signal Store — Zustand StoreApi-compatible store backed by alien-signals.
|
|
2394
|
+
*
|
|
2395
|
+
* Drop-in replacement for Zustand's createStore(). Provides the same
|
|
2396
|
+
* StoreApi<T> interface so useApp()/StoreContext keep working unchanged.
|
|
2397
|
+
*
|
|
2398
|
+
* Also re-exports StateCreator for backward compatibility with code
|
|
2399
|
+
* that imported it from "zustand".
|
|
2400
|
+
*/
|
|
2401
|
+
type SetStateInternal<T> = {
|
|
2402
|
+
(partial: T | Partial<T> | ((state: T) => T | Partial<T>), replace?: false): void;
|
|
2403
|
+
(state: T | ((state: T) => T), replace: true): void;
|
|
2404
|
+
};
|
|
2405
|
+
interface StoreApi$1<T> {
|
|
2406
|
+
setState: SetStateInternal<T>;
|
|
2407
|
+
getState: () => T;
|
|
2408
|
+
getInitialState: () => T;
|
|
2409
|
+
subscribe: (listener: (state: T, prevState: T) => void) => () => void;
|
|
2410
|
+
}
|
|
2411
|
+
type StateCreator<T, Mis extends [StoreMutatorIdentifier, unknown][] = [], Mos extends [StoreMutatorIdentifier, unknown][] = [], U = T> = ((setState: StoreApi$1<T>["setState"], getState: StoreApi$1<T>["getState"], store: StoreApi$1<T>) => U) & {
|
|
2412
|
+
$$storeMutators?: Mos;
|
|
2413
|
+
};
|
|
2414
|
+
interface StoreMutators<_S, _A> {}
|
|
2415
|
+
type StoreMutatorIdentifier = keyof StoreMutators<unknown, unknown>;
|
|
2416
|
+
//#endregion
|
|
2417
|
+
//#region packages/create/src/core/index.d.ts
|
|
2418
|
+
/**
|
|
2419
|
+
* The model type that silvery manages for focus state.
|
|
2420
|
+
*
|
|
2421
|
+
* Applications extend this with their own model fields.
|
|
2422
|
+
* The store's update function receives the full model and returns
|
|
2423
|
+
* a new model + effects tuple.
|
|
2424
|
+
*/
|
|
2425
|
+
interface SilveryModel {
|
|
2426
|
+
focus: {
|
|
2427
|
+
activeId: string | null;
|
|
2428
|
+
previousId: string | null;
|
|
2429
|
+
origin: FocusOrigin | null;
|
|
2430
|
+
scopeStack: string[];
|
|
2431
|
+
scopeMemory: Record<string, string>;
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
/**
|
|
2435
|
+
* Direction type used in spatial navigation messages.
|
|
2436
|
+
*/
|
|
2437
|
+
type Direction = "up" | "down" | "left" | "right";
|
|
2438
|
+
/**
|
|
2439
|
+
* Message types that silvery understands.
|
|
2440
|
+
*
|
|
2441
|
+
* Applications can extend this union with their own message types.
|
|
2442
|
+
* The store's update function pattern-matches on `type` to decide
|
|
2443
|
+
* how to update the model.
|
|
2444
|
+
*/
|
|
2445
|
+
type SilveryMsg = {
|
|
2446
|
+
type: "focus";
|
|
2447
|
+
nodeId: string;
|
|
2448
|
+
origin?: FocusOrigin;
|
|
2449
|
+
} | {
|
|
2450
|
+
type: "blur";
|
|
2451
|
+
} | {
|
|
2452
|
+
type: "focus-next";
|
|
2453
|
+
} | {
|
|
2454
|
+
type: "focus-prev";
|
|
2455
|
+
} | {
|
|
2456
|
+
type: "focus-direction";
|
|
2457
|
+
direction: Direction;
|
|
2458
|
+
} | {
|
|
2459
|
+
type: "scope-enter";
|
|
2460
|
+
scopeId: string;
|
|
2461
|
+
} | {
|
|
2462
|
+
type: "scope-exit";
|
|
2463
|
+
} | {
|
|
2464
|
+
type: "term:key";
|
|
2465
|
+
key: string;
|
|
2466
|
+
input: string;
|
|
2467
|
+
ctrl: boolean;
|
|
2468
|
+
meta: boolean;
|
|
2469
|
+
shift: boolean;
|
|
2470
|
+
} | {
|
|
2471
|
+
type: "term:mouse";
|
|
2472
|
+
action: "down" | "up" | "move" | "scroll";
|
|
2473
|
+
x: number;
|
|
2474
|
+
y: number;
|
|
2475
|
+
button: number;
|
|
2476
|
+
} | {
|
|
2477
|
+
type: "term:resize";
|
|
2478
|
+
cols: number;
|
|
2479
|
+
rows: number;
|
|
2480
|
+
};
|
|
2481
|
+
/**
|
|
2482
|
+
* Effect commands returned by update functions.
|
|
2483
|
+
*
|
|
2484
|
+
* Effects are declarative descriptions of side effects. The store
|
|
2485
|
+
* executes them after the model update, keeping the update function pure.
|
|
2486
|
+
*
|
|
2487
|
+
* - `none`: No effect (useful as a default)
|
|
2488
|
+
* - `batch`: Multiple effects to execute
|
|
2489
|
+
* - `dispatch`: Queue another message (no re-entrant dispatch)
|
|
2490
|
+
*/
|
|
2491
|
+
type Effect = {
|
|
2492
|
+
type: "none";
|
|
2493
|
+
} | {
|
|
2494
|
+
type: "batch";
|
|
2495
|
+
effects: Effect[];
|
|
2496
|
+
} | {
|
|
2497
|
+
type: "dispatch";
|
|
2498
|
+
msg: SilveryMsg;
|
|
2499
|
+
};
|
|
2500
|
+
/**
|
|
2501
|
+
* A plugin wraps an update function, adding behavior before/after/around it.
|
|
2502
|
+
*
|
|
2503
|
+
* Plugins compose via `compose()` — the outermost plugin runs first on
|
|
2504
|
+
* message receive, but the innermost (original) update runs first for
|
|
2505
|
+
* model updates. This is the standard middleware pattern.
|
|
2506
|
+
*
|
|
2507
|
+
* @example
|
|
2508
|
+
* ```ts
|
|
2509
|
+
* const logging: Plugin<MyModel, MyMsg> = (inner) => (msg, model) => {
|
|
2510
|
+
* console.log('msg:', msg.type)
|
|
2511
|
+
* const result = inner(msg, model)
|
|
2512
|
+
* console.log('new model:', result[0])
|
|
2513
|
+
* return result
|
|
2514
|
+
* }
|
|
2515
|
+
* ```
|
|
2516
|
+
*/
|
|
2517
|
+
type Plugin<Model, Msg> = (innerUpdate: (msg: Msg, model: Model) => [Model, Effect[]]) => (msg: Msg, model: Model) => [Model, Effect[]];
|
|
2518
|
+
//#endregion
|
|
2519
|
+
//#region packages/create/src/store/index.d.ts
|
|
2520
|
+
/**
|
|
2521
|
+
* Configuration for creating a store.
|
|
2522
|
+
*/
|
|
2523
|
+
interface StoreConfig<Model extends SilveryModel, Msg extends SilveryMsg> {
|
|
2524
|
+
/** Initialize model and effects. Called once on store creation. */
|
|
2525
|
+
init: () => [Model, Effect[]];
|
|
2526
|
+
/** Pure update function: (msg, model) -> [newModel, effects] */
|
|
2527
|
+
update: (msg: Msg, model: Model) => [Model, Effect[]];
|
|
2528
|
+
}
|
|
2529
|
+
/**
|
|
2530
|
+
* The store API returned by createStore.
|
|
2531
|
+
*/
|
|
2532
|
+
interface StoreApi<Model extends SilveryModel, Msg extends SilveryMsg> {
|
|
2533
|
+
/** Send a message through the update function. */
|
|
2534
|
+
dispatch(msg: Msg): void;
|
|
2535
|
+
/** Get the current model. */
|
|
2536
|
+
getModel(): Model;
|
|
2537
|
+
/** Subscribe to model changes. Returns unsubscribe function. */
|
|
2538
|
+
subscribe(listener: () => void): () => void;
|
|
2539
|
+
/** Get a derived value from the model via selector. */
|
|
2540
|
+
getSnapshot<T>(selector: (model: Model) => T): T;
|
|
2541
|
+
}
|
|
2542
|
+
/**
|
|
2543
|
+
* Plugin that handles focus-related messages by updating the focus slice.
|
|
2544
|
+
*
|
|
2545
|
+
* Handles: focus, blur, scope-enter, scope-exit.
|
|
2546
|
+
* Passes focus-next, focus-prev, focus-direction through (they need
|
|
2547
|
+
* the node tree, which the store doesn't have — those are handled
|
|
2548
|
+
* at the React integration layer).
|
|
2549
|
+
*/
|
|
2550
|
+
declare function withFocusManagement<Model extends SilveryModel, Msg extends SilveryMsg>(): Plugin<Model, Msg>;
|
|
2551
|
+
/**
|
|
2552
|
+
* The default silvery update function.
|
|
2553
|
+
*
|
|
2554
|
+
* Returns the model unchanged with no effects for any unhandled message.
|
|
2555
|
+
* Compose with plugins to add behavior.
|
|
2556
|
+
*/
|
|
2557
|
+
declare function silveryUpdate<Model extends SilveryModel, Msg extends SilveryMsg>(_msg: Msg, model: Model): [Model, Effect[]];
|
|
2558
|
+
/**
|
|
2559
|
+
* Create a default initial SilveryModel.
|
|
2560
|
+
*/
|
|
2561
|
+
declare function defaultInit(): [SilveryModel, Effect[]];
|
|
2562
|
+
/**
|
|
2563
|
+
* Create a TEA-style store.
|
|
2564
|
+
*
|
|
2565
|
+
* The store manages model state and effect execution. Messages are
|
|
2566
|
+
* dispatched through the update function, which returns a new model
|
|
2567
|
+
* and a list of effects. Effects are executed after each update cycle.
|
|
2568
|
+
*
|
|
2569
|
+
* Dispatch effects are queued to prevent re-entrant dispatch:
|
|
2570
|
+
* if dispatching msg A triggers effect dispatch(B), B is queued and
|
|
2571
|
+
* processed after A's full update cycle completes.
|
|
2572
|
+
*
|
|
2573
|
+
* @example
|
|
2574
|
+
* ```ts
|
|
2575
|
+
* import { createStore, withFocusManagement, silveryUpdate } from '@silvery/create/store'
|
|
2576
|
+
* import { compose } from '@silvery/create/core'
|
|
2577
|
+
*
|
|
2578
|
+
* const store = createStore({
|
|
2579
|
+
* init: () => [{ focus: { activeId: null, ... }, count: 0 }, []],
|
|
2580
|
+
* update: compose(withFocusManagement())(silveryUpdate),
|
|
2581
|
+
* })
|
|
2582
|
+
*
|
|
2583
|
+
* store.dispatch({ type: 'focus', nodeId: 'btn1' })
|
|
2584
|
+
* console.log(store.getModel().focus.activeId) // 'btn1'
|
|
2585
|
+
* ```
|
|
2586
|
+
*/
|
|
2587
|
+
declare function createStore<Model extends SilveryModel, Msg extends SilveryMsg>(config: StoreConfig<Model, Msg>): StoreApi<Model, Msg>;
|
|
2588
|
+
//#endregion
|
|
2589
|
+
//#region packages/create/src/streams/index.d.ts
|
|
2590
|
+
/**
|
|
2591
|
+
* AsyncIterable stream helpers for event-driven TUI architecture.
|
|
2592
|
+
*
|
|
2593
|
+
* These are pure functions over AsyncIterables - no EventEmitters, no callbacks.
|
|
2594
|
+
* All helpers properly handle cleanup via return() on early break.
|
|
2595
|
+
*
|
|
2596
|
+
* @example
|
|
2597
|
+
* ```typescript
|
|
2598
|
+
* const keys = term.keys()
|
|
2599
|
+
* const resizes = term.resizes()
|
|
2600
|
+
*
|
|
2601
|
+
* // Merge multiple sources
|
|
2602
|
+
* const events = merge(
|
|
2603
|
+
* map(keys, k => ({ type: 'key', ...k })),
|
|
2604
|
+
* map(resizes, r => ({ type: 'resize', ...r }))
|
|
2605
|
+
* )
|
|
2606
|
+
*
|
|
2607
|
+
* // Consume until ctrl+c
|
|
2608
|
+
* for await (const event of events) {
|
|
2609
|
+
* if (event.type === 'key' && event.key === 'ctrl+c') break
|
|
2610
|
+
* }
|
|
2611
|
+
* ```
|
|
2612
|
+
*/
|
|
2613
|
+
/**
|
|
2614
|
+
* Merge multiple AsyncIterables into one.
|
|
2615
|
+
*
|
|
2616
|
+
* Values are emitted in arrival order (first-come). When all sources complete,
|
|
2617
|
+
* the merged iterable completes. If any source throws, the error propagates
|
|
2618
|
+
* and remaining sources are cleaned up.
|
|
2619
|
+
*
|
|
2620
|
+
* IMPORTANT: Each call to merge() creates a fresh iterable. Don't share
|
|
2621
|
+
* the same merged iterable between multiple consumers.
|
|
2622
|
+
*
|
|
2623
|
+
* @example
|
|
2624
|
+
* ```typescript
|
|
2625
|
+
* const merged = merge(keys, resizes, ticks)
|
|
2626
|
+
* for await (const event of merged) {
|
|
2627
|
+
* // Process events from any source
|
|
2628
|
+
* }
|
|
2629
|
+
* ```
|
|
2630
|
+
*/
|
|
2631
|
+
declare function merge<T>(...sources: AsyncIterable<T>[]): AsyncGenerator<T, void, undefined>;
|
|
2632
|
+
/**
|
|
2633
|
+
* Transform each value from an AsyncIterable.
|
|
2634
|
+
*
|
|
2635
|
+
* @example
|
|
2636
|
+
* ```typescript
|
|
2637
|
+
* const keyEvents = map(keys, k => ({ type: 'key' as const, key: k }))
|
|
2638
|
+
* ```
|
|
2639
|
+
*/
|
|
2640
|
+
declare function map<T, U>(source: AsyncIterable<T>, fn: (value: T) => U): AsyncGenerator<U, void, undefined>;
|
|
2641
|
+
/**
|
|
2642
|
+
* Filter values from an AsyncIterable.
|
|
2643
|
+
*
|
|
2644
|
+
* @example
|
|
2645
|
+
* ```typescript
|
|
2646
|
+
* const letters = filter(keys, k => k.key.length === 1)
|
|
2647
|
+
* ```
|
|
2648
|
+
*/
|
|
2649
|
+
declare function filter<T>(source: AsyncIterable<T>, predicate: (value: T) => boolean): AsyncGenerator<T, void, undefined>;
|
|
2650
|
+
/**
|
|
2651
|
+
* Filter and transform in one pass (type narrowing).
|
|
2652
|
+
*
|
|
2653
|
+
* @example
|
|
2654
|
+
* ```typescript
|
|
2655
|
+
* const keyEvents = filterMap(events, e =>
|
|
2656
|
+
* e.type === 'key' ? e : undefined
|
|
2657
|
+
* )
|
|
2658
|
+
* ```
|
|
2659
|
+
*/
|
|
2660
|
+
declare function filterMap<T, U>(source: AsyncIterable<T>, fn: (value: T) => U | undefined): AsyncGenerator<U, void, undefined>;
|
|
2661
|
+
/**
|
|
2662
|
+
* Take values until an AbortSignal fires.
|
|
2663
|
+
*
|
|
2664
|
+
* When the signal aborts, the iterator completes gracefully (no error thrown).
|
|
2665
|
+
* The source iterator is properly cleaned up.
|
|
2666
|
+
*
|
|
2667
|
+
* @example
|
|
2668
|
+
* ```typescript
|
|
2669
|
+
* const controller = new AbortController()
|
|
2670
|
+
* const events = takeUntil(allEvents, controller.signal)
|
|
2671
|
+
*
|
|
2672
|
+
* // Later: controller.abort() will end the iteration
|
|
2673
|
+
* ```
|
|
2674
|
+
*/
|
|
2675
|
+
declare function takeUntil<T>(source: AsyncIterable<T>, signal: AbortSignal): AsyncGenerator<T, void, undefined>;
|
|
2676
|
+
/**
|
|
2677
|
+
* Take the first n values from an AsyncIterable.
|
|
2678
|
+
*
|
|
2679
|
+
* @example
|
|
2680
|
+
* ```typescript
|
|
2681
|
+
* const firstThree = take(events, 3)
|
|
2682
|
+
* ```
|
|
2683
|
+
*/
|
|
2684
|
+
declare function take<T>(source: AsyncIterable<T>, count: number): AsyncGenerator<T, void, undefined>;
|
|
2685
|
+
/**
|
|
2686
|
+
* Create an AsyncIterable from an array (useful for testing).
|
|
2687
|
+
*
|
|
2688
|
+
* @example
|
|
2689
|
+
* ```typescript
|
|
2690
|
+
* const events = fromArray([
|
|
2691
|
+
* { type: 'key', key: 'j' },
|
|
2692
|
+
* { type: 'key', key: 'k' },
|
|
2693
|
+
* ])
|
|
2694
|
+
* ```
|
|
2695
|
+
*/
|
|
2696
|
+
declare function fromArray<T>(items: T[]): AsyncGenerator<T, void, undefined>;
|
|
2697
|
+
/**
|
|
2698
|
+
* Create an AsyncIterable that yields after a delay (useful for testing).
|
|
2699
|
+
*
|
|
2700
|
+
* @example
|
|
2701
|
+
* ```typescript
|
|
2702
|
+
* const delayed = fromArrayWithDelay([1, 2, 3], 100) // 100ms between each
|
|
2703
|
+
* ```
|
|
2704
|
+
*/
|
|
2705
|
+
declare function fromArrayWithDelay<T>(items: T[], delayMs: number): AsyncGenerator<T, void, undefined>;
|
|
2706
|
+
/**
|
|
2707
|
+
* Throttle high-frequency sources.
|
|
2708
|
+
*
|
|
2709
|
+
* Emits the first value immediately, then ignores values for the specified
|
|
2710
|
+
* duration. After the duration, the next value is emitted and the cycle repeats.
|
|
2711
|
+
*
|
|
2712
|
+
* @example
|
|
2713
|
+
* ```typescript
|
|
2714
|
+
* const throttled = throttle(mouseMoves, 16) // ~60fps
|
|
2715
|
+
* ```
|
|
2716
|
+
*/
|
|
2717
|
+
declare function throttle<T>(source: AsyncIterable<T>, ms: number): AsyncGenerator<T, void, undefined>;
|
|
2718
|
+
/**
|
|
2719
|
+
* Debounce values - only emit after source is quiet for specified duration.
|
|
2720
|
+
*
|
|
2721
|
+
* NOTE: With pull-based AsyncIterables, true debouncing is complex. This
|
|
2722
|
+
* implementation collects all values and only yields the final value after
|
|
2723
|
+
* the source completes and quiet period passes. For real-time debouncing,
|
|
2724
|
+
* consider using a push-based pattern or EventEmitter.
|
|
2725
|
+
*
|
|
2726
|
+
* @example
|
|
2727
|
+
* ```typescript
|
|
2728
|
+
* const debounced = debounce(searchInput, 300) // Yields last value after source ends + delay
|
|
2729
|
+
* ```
|
|
2730
|
+
*/
|
|
2731
|
+
declare function debounce<T>(source: AsyncIterable<T>, ms: number): AsyncGenerator<T, void, undefined>;
|
|
2732
|
+
/**
|
|
2733
|
+
* Collect values into batches of specified size.
|
|
2734
|
+
*
|
|
2735
|
+
* @throws {Error} If size is not positive
|
|
2736
|
+
*
|
|
2737
|
+
* @example
|
|
2738
|
+
* ```typescript
|
|
2739
|
+
* const batched = batch(events, 10) // Emit arrays of 10 events
|
|
2740
|
+
* ```
|
|
2741
|
+
*/
|
|
2742
|
+
declare function batch<T>(source: AsyncIterable<T>, size: number): AsyncGenerator<T[], void, undefined>;
|
|
2743
|
+
/**
|
|
2744
|
+
* Concatenate multiple AsyncIterables in sequence.
|
|
2745
|
+
*
|
|
2746
|
+
* @example
|
|
2747
|
+
* ```typescript
|
|
2748
|
+
* const all = concat(header, body, footer)
|
|
2749
|
+
* ```
|
|
2750
|
+
*/
|
|
2751
|
+
declare function concat<T>(...sources: AsyncIterable<T>[]): AsyncGenerator<T, void, undefined>;
|
|
2752
|
+
/**
|
|
2753
|
+
* Zip multiple AsyncIterables together.
|
|
2754
|
+
* Completes when the shortest source completes.
|
|
2755
|
+
*
|
|
2756
|
+
* @example
|
|
2757
|
+
* ```typescript
|
|
2758
|
+
* const pairs = zip(keys, timestamps) // [key, timestamp][]
|
|
2759
|
+
* ```
|
|
2760
|
+
*/
|
|
2761
|
+
declare function zip<T extends unknown[]>(...sources: { [K in keyof T]: AsyncIterable<T[K]> }): AsyncGenerator<T, void, undefined>;
|
|
2762
|
+
//#endregion
|
|
2763
|
+
//#region packages/ag-term/src/runtime/layout.d.ts
|
|
2764
|
+
/**
|
|
2765
|
+
* Options for the layout function.
|
|
2766
|
+
*/
|
|
2767
|
+
interface LayoutOptions {
|
|
2768
|
+
/** Skip layout notifications (for static renders). Default: true */
|
|
2769
|
+
skipLayoutNotifications?: boolean;
|
|
2770
|
+
/** Strip ANSI codes for plain text output. Default: false */
|
|
2771
|
+
plain?: boolean;
|
|
2772
|
+
}
|
|
2773
|
+
/**
|
|
2774
|
+
* Ensure layout engine is initialized.
|
|
2775
|
+
* Must be called before layout() in async contexts.
|
|
2776
|
+
*/
|
|
2777
|
+
declare function ensureLayoutEngine(): Promise<void>;
|
|
2778
|
+
/**
|
|
2779
|
+
* Pure layout function - renders a React element to a Buffer.
|
|
2780
|
+
*
|
|
2781
|
+
* IMPORTANT: Call ensureLayoutEngine() first in async contexts.
|
|
2782
|
+
* The layout engine must be initialized before calling this.
|
|
2783
|
+
*
|
|
2784
|
+
* @param element React element to render
|
|
2785
|
+
* @param dims Terminal dimensions
|
|
2786
|
+
* @param options Layout options
|
|
2787
|
+
* @returns Immutable Buffer with text, ansi, and nodes
|
|
2788
|
+
*
|
|
2789
|
+
* @example
|
|
2790
|
+
* ```typescript
|
|
2791
|
+
* import { layout, ensureLayoutEngine } from '@silvery/ag-term/runtime'
|
|
2792
|
+
*
|
|
2793
|
+
* await ensureLayoutEngine()
|
|
2794
|
+
* const buffer = layout(<Text>Hello</Text>, { cols: 80, rows: 24 })
|
|
2795
|
+
* console.log(buffer.text) // "Hello"
|
|
2796
|
+
* ```
|
|
2797
|
+
*/
|
|
2798
|
+
declare function layout(element: ReactElement, dims: Dims, options?: LayoutOptions): Buffer$1;
|
|
2799
|
+
/**
|
|
2800
|
+
* Synchronous layout - assumes engine is already initialized.
|
|
2801
|
+
* Throws if engine not ready.
|
|
2802
|
+
*/
|
|
2803
|
+
declare function layoutSync(element: ReactElement, dims: Dims, options?: LayoutOptions): Buffer$1;
|
|
2804
|
+
//#endregion
|
|
2805
|
+
//#region packages/ag-term/src/runtime/diff.d.ts
|
|
2806
|
+
/**
|
|
2807
|
+
* Diff mode for ANSI output.
|
|
2808
|
+
*/
|
|
2809
|
+
type DiffMode = "fullscreen" | "inline";
|
|
2810
|
+
/**
|
|
2811
|
+
* Compute the minimal ANSI diff between two buffers.
|
|
2812
|
+
*
|
|
2813
|
+
* @param prev Previous buffer (null on first render)
|
|
2814
|
+
* @param next Current buffer
|
|
2815
|
+
* @param mode Render mode (fullscreen or inline)
|
|
2816
|
+
* @returns ANSI escape sequence string to transform prev into next
|
|
2817
|
+
*
|
|
2818
|
+
* @example
|
|
2819
|
+
* ```typescript
|
|
2820
|
+
* import { diff, layout } from '@silvery/ag-term/runtime'
|
|
2821
|
+
*
|
|
2822
|
+
* const prev = layout(<Text>Hello</Text>, dims)
|
|
2823
|
+
* const next = layout(<Text>World</Text>, dims)
|
|
2824
|
+
* const patch = diff(prev, next)
|
|
2825
|
+
* process.stdout.write(patch)
|
|
2826
|
+
* ```
|
|
2827
|
+
*/
|
|
2828
|
+
declare function diff(prev: Buffer$1 | null, next: Buffer$1, mode?: DiffMode, scrollbackOffset?: number, termRows?: number): string;
|
|
2829
|
+
/**
|
|
2830
|
+
* Render a buffer to ANSI string (no diff, full render).
|
|
2831
|
+
*
|
|
2832
|
+
* @param buffer Buffer to render
|
|
2833
|
+
* @param mode Render mode (fullscreen or inline)
|
|
2834
|
+
* @returns Full ANSI output
|
|
2835
|
+
*/
|
|
2836
|
+
declare function render(buffer: Buffer$1, mode?: DiffMode): string;
|
|
2837
|
+
//#endregion
|
|
2838
|
+
//#region packages/ag-term/src/runtime/create-buffer.d.ts
|
|
2839
|
+
declare function createBuffer(termBuffer: TerminalBuffer, nodes: AgNode): Buffer$1;
|
|
2840
|
+
//#endregion
|
|
2841
|
+
//#region packages/ag-term/src/runtime/create-runtime.d.ts
|
|
2842
|
+
/**
|
|
2843
|
+
* Create a runtime kernel.
|
|
2844
|
+
*
|
|
2845
|
+
* @param options Runtime configuration
|
|
2846
|
+
* @returns Runtime instance implementing Symbol.dispose
|
|
2847
|
+
*/
|
|
2848
|
+
declare function createRuntime(options: RuntimeOptions): Runtime;
|
|
2849
|
+
//#endregion
|
|
2850
|
+
//#region packages/ag-react/src/hooks/usePasteCallback.d.ts
|
|
2851
|
+
/**
|
|
2852
|
+
* usePasteCallback — subscribe to bracketed paste events.
|
|
2853
|
+
*
|
|
2854
|
+
* Simple callback-based paste hook for run() apps.
|
|
2855
|
+
* For component composition with PasteProvider, use usePaste() instead.
|
|
2856
|
+
*
|
|
2857
|
+
* @example
|
|
2858
|
+
* ```tsx
|
|
2859
|
+
* usePasteCallback((text) => {
|
|
2860
|
+
* insertText(text)
|
|
2861
|
+
* })
|
|
2862
|
+
* ```
|
|
2863
|
+
*/
|
|
2864
|
+
type PasteCallback = (text: string) => void;
|
|
2865
|
+
declare function usePasteCallback(handler: PasteCallback): void;
|
|
2866
|
+
//#endregion
|
|
2867
|
+
//#region packages/ag-term/src/runtime/run.d.ts
|
|
2868
|
+
/**
|
|
2869
|
+
* Options for run().
|
|
2870
|
+
*
|
|
2871
|
+
* run() auto-detects terminal capabilities and enables features by default.
|
|
2872
|
+
* Pass explicit values to override. For the full list of capabilities detected,
|
|
2873
|
+
* see {@link detectTerminalCaps} in terminal-caps.ts.
|
|
2874
|
+
*
|
|
2875
|
+
* **Mouse tracking note:** When `mouse` is enabled (the default), the terminal
|
|
2876
|
+
* captures mouse events and native text selection (copy/paste) requires holding
|
|
2877
|
+
* Shift (or Option on macOS in some terminals). Set `mouse: false` to restore
|
|
2878
|
+
* native copy/paste behavior.
|
|
2879
|
+
*/
|
|
2880
|
+
interface RunOptions {
|
|
2881
|
+
/** Terminal dimensions (default: from process.stdout) */
|
|
2882
|
+
cols?: number;
|
|
2883
|
+
rows?: number;
|
|
2884
|
+
/** Standard output (default: process.stdout) */
|
|
2885
|
+
stdout?: NodeJS.WriteStream;
|
|
2886
|
+
/** Standard input (default: process.stdin) */
|
|
2887
|
+
stdin?: NodeJS.ReadStream;
|
|
2888
|
+
/**
|
|
2889
|
+
* Plain writable sink for ANSI output. Headless mode with active output.
|
|
2890
|
+
* Requires cols and rows. Input via handle.press().
|
|
2891
|
+
*/
|
|
2892
|
+
writable?: {
|
|
2893
|
+
write(data: string): void;
|
|
2894
|
+
};
|
|
2895
|
+
/** Abort signal for external cleanup */
|
|
2896
|
+
signal?: AbortSignal;
|
|
2897
|
+
/**
|
|
2898
|
+
* Enable Kitty keyboard protocol for unambiguous key identification
|
|
2899
|
+
* (Cmd ⌘, Hyper ✦ modifiers, key release events).
|
|
2900
|
+
* - `true`: enable with DISAMBIGUATE flag (1)
|
|
2901
|
+
* - number: enable with specific KittyFlags bitfield
|
|
2902
|
+
* - `false`: don't enable
|
|
2903
|
+
* - Default: auto-detected from terminal (enabled for Ghostty, Kitty, WezTerm, foot)
|
|
2904
|
+
*/
|
|
2905
|
+
kitty?: boolean | number;
|
|
2906
|
+
/**
|
|
2907
|
+
* Enable SGR mouse tracking (mode 1006) for click, scroll, and drag events.
|
|
2908
|
+
* When enabled, native text selection requires holding Shift (or Option on macOS)
|
|
2909
|
+
* and native terminal scrolling is disabled.
|
|
2910
|
+
* Default: `true` in fullscreen mode, `false` in inline mode (where content
|
|
2911
|
+
* lives in terminal scrollback and natural scrolling is expected).
|
|
2912
|
+
*/
|
|
2913
|
+
mouse?: boolean;
|
|
2914
|
+
/**
|
|
2915
|
+
* Render mode:
|
|
2916
|
+
* - `"fullscreen"` — alt screen buffer (default)
|
|
2917
|
+
* - `"inline"` — scrollback-compatible, no alt screen
|
|
2918
|
+
* - `"virtualInline"` — alt screen with virtual scrollback (scrollable history + search)
|
|
2919
|
+
*/
|
|
2920
|
+
mode?: "fullscreen" | "inline" | "virtualInline";
|
|
2921
|
+
/**
|
|
2922
|
+
* Enable Kitty text sizing protocol (OSC 66) for PUA characters.
|
|
2923
|
+
* Ensures nerdfont/powerline icons are measured and rendered at the correct width.
|
|
2924
|
+
* - `true`: force enable
|
|
2925
|
+
* - `"auto"`: use heuristic, then probe to verify (progressive enhancement)
|
|
2926
|
+
* - `"probe"`: start disabled, probe async, enable on confirmation
|
|
2927
|
+
* - `false`: disabled
|
|
2928
|
+
* - Default: "auto"
|
|
2929
|
+
*/
|
|
2930
|
+
textSizing?: boolean | "auto" | "probe";
|
|
2931
|
+
/**
|
|
2932
|
+
* Enable DEC width mode detection (modes 1020-1023).
|
|
2933
|
+
* Queries the terminal for emoji/CJK/PUA width settings at startup.
|
|
2934
|
+
* - `true`: always run width detection probe
|
|
2935
|
+
* - `"auto"`: run probe when caps are provided (default)
|
|
2936
|
+
* - `false`: disabled
|
|
2937
|
+
* Default: "auto"
|
|
2938
|
+
*/
|
|
2939
|
+
widthDetection?: boolean | "auto";
|
|
2940
|
+
/**
|
|
2941
|
+
* Enable terminal focus reporting (CSI ?1004h).
|
|
2942
|
+
* Dispatches 'term:focus' events with `{ focused: boolean }`.
|
|
2943
|
+
* Default: true
|
|
2944
|
+
*/
|
|
2945
|
+
focusReporting?: boolean;
|
|
2946
|
+
/**
|
|
2947
|
+
* Terminal capabilities for width measurement and output suppression.
|
|
2948
|
+
* Default: auto-detected via detectTerminalCaps()
|
|
2949
|
+
*/
|
|
2950
|
+
caps?: TerminalCaps;
|
|
2951
|
+
/**
|
|
2952
|
+
* Handle Ctrl+Z by suspending the process. Default: true
|
|
2953
|
+
*/
|
|
2954
|
+
suspendOnCtrlZ?: boolean;
|
|
2955
|
+
/**
|
|
2956
|
+
* Handle Ctrl+C by restoring terminal and exiting. Default: true
|
|
2957
|
+
*/
|
|
2958
|
+
exitOnCtrlC?: boolean;
|
|
2959
|
+
/** Called before suspend. Return false to prevent. */
|
|
2960
|
+
onSuspend?: () => boolean | void;
|
|
2961
|
+
/** Called after resume from suspend. */
|
|
2962
|
+
onResume?: () => void;
|
|
2963
|
+
/** Called on Ctrl+C. Return false to prevent exit. */
|
|
2964
|
+
onInterrupt?: () => boolean | void;
|
|
2965
|
+
}
|
|
2966
|
+
/**
|
|
2967
|
+
* Handle returned by run() for controlling the app.
|
|
2968
|
+
*/
|
|
2969
|
+
interface RunHandle {
|
|
2970
|
+
/** Current rendered text (no ANSI) */
|
|
2971
|
+
readonly text: string;
|
|
2972
|
+
/** Live reconciler root node (for locator queries) */
|
|
2973
|
+
readonly root: AgNode;
|
|
2974
|
+
/** Current terminal buffer (cell-level access) */
|
|
2975
|
+
readonly buffer: TerminalBuffer | null;
|
|
2976
|
+
/** Wait until the app exits */
|
|
2977
|
+
waitUntilExit(): Promise<void>;
|
|
2978
|
+
/** Unmount and cleanup */
|
|
2979
|
+
unmount(): void;
|
|
2980
|
+
/** Dispose (alias for unmount) — enables `using` */
|
|
2981
|
+
[Symbol.dispose](): void;
|
|
2982
|
+
/** Send a key press */
|
|
2983
|
+
press(key: string): Promise<void>;
|
|
2984
|
+
}
|
|
2985
|
+
/**
|
|
2986
|
+
* Run a React component with the silvery-loop runtime.
|
|
2987
|
+
*
|
|
2988
|
+
* Accepts either a Term instance or RunOptions:
|
|
2989
|
+
* - `run(<App />, term)` — Term handles streams, createApp handles rendering
|
|
2990
|
+
* - `run(<App />, { cols, rows, ... })` — classic options API
|
|
2991
|
+
*
|
|
2992
|
+
* Internally delegates to createApp() with an empty store.
|
|
2993
|
+
* For stores and providers, use createApp() directly.
|
|
2994
|
+
*/
|
|
2995
|
+
declare function run(element: ReactElement, term: Term, termOptions?: Partial<RunOptions>): Promise<RunHandle>;
|
|
2996
|
+
declare function run(element: ReactElement, options?: RunOptions): Promise<RunHandle>;
|
|
2997
|
+
//#endregion
|
|
2998
|
+
//#region packages/ag-term/src/runtime/terminal-lifecycle.d.ts
|
|
2999
|
+
/**
|
|
3000
|
+
* Terminal Lifecycle Events
|
|
3001
|
+
*
|
|
3002
|
+
* Handles suspend/resume (Ctrl+Z/SIGCONT) and interrupt (Ctrl+C) for TUI apps.
|
|
3003
|
+
* When stdin is in raw mode, the terminal does not generate SIGTSTP/SIGINT for
|
|
3004
|
+
* Ctrl+Z/Ctrl+C. This module intercepts the raw bytes and manages the full
|
|
3005
|
+
* terminal state save/restore cycle.
|
|
3006
|
+
*
|
|
3007
|
+
* Inspired by ncurses (endwin/refresh), bubbletea, and Textual.
|
|
3008
|
+
*
|
|
3009
|
+
* Protocols managed:
|
|
3010
|
+
* - Raw mode (stdin)
|
|
3011
|
+
* - Alternate screen buffer (DEC private mode 1049)
|
|
3012
|
+
* - Cursor visibility (DEC private mode 25)
|
|
3013
|
+
* - Mouse tracking (modes 1000, 1002, 1006)
|
|
3014
|
+
* - Kitty keyboard protocol (CSI > flags u / CSI < u)
|
|
3015
|
+
* - Bracketed paste (DEC private mode 2004)
|
|
3016
|
+
* - SGR attributes (reset via CSI 0 m)
|
|
3017
|
+
*/
|
|
3018
|
+
/**
|
|
3019
|
+
* Options for terminal lifecycle event handling.
|
|
3020
|
+
*/
|
|
3021
|
+
interface TerminalLifecycleOptions {
|
|
3022
|
+
/** Handle Ctrl+Z by suspending the process. Default: true */
|
|
3023
|
+
suspendOnCtrlZ?: boolean;
|
|
3024
|
+
/** Handle Ctrl+C by exiting the process. Default: true */
|
|
3025
|
+
exitOnCtrlC?: boolean;
|
|
3026
|
+
/** Called before suspend. Return false to prevent. */
|
|
3027
|
+
onSuspend?: () => boolean | void;
|
|
3028
|
+
/** Called after resume from suspend. */
|
|
3029
|
+
onResume?: () => void;
|
|
3030
|
+
/** Called on Ctrl+C. Return false to prevent exit. */
|
|
3031
|
+
onInterrupt?: () => boolean | void;
|
|
3032
|
+
}
|
|
3033
|
+
/**
|
|
3034
|
+
* Snapshot of terminal protocol state for save/restore across suspend/resume.
|
|
3035
|
+
*/
|
|
3036
|
+
interface TerminalState {
|
|
3037
|
+
rawMode: boolean;
|
|
3038
|
+
alternateScreen: boolean;
|
|
3039
|
+
cursorHidden: boolean;
|
|
3040
|
+
mouseEnabled: boolean;
|
|
3041
|
+
kittyEnabled: boolean;
|
|
3042
|
+
kittyFlags: number;
|
|
3043
|
+
bracketedPaste: boolean;
|
|
3044
|
+
focusReporting: boolean;
|
|
3045
|
+
}
|
|
3046
|
+
/**
|
|
3047
|
+
* Capture the current terminal protocol state.
|
|
3048
|
+
*
|
|
3049
|
+
* This builds a TerminalState from the options passed to run()/createApp(),
|
|
3050
|
+
* since terminal state is not directly queryable from the OS.
|
|
3051
|
+
*/
|
|
3052
|
+
declare function captureTerminalState(opts: {
|
|
3053
|
+
alternateScreen?: boolean;
|
|
3054
|
+
cursorHidden?: boolean;
|
|
3055
|
+
mouse?: boolean;
|
|
3056
|
+
kitty?: boolean;
|
|
3057
|
+
kittyFlags?: number;
|
|
3058
|
+
bracketedPaste?: boolean;
|
|
3059
|
+
rawMode?: boolean;
|
|
3060
|
+
focusReporting?: boolean;
|
|
3061
|
+
}): TerminalState;
|
|
3062
|
+
/**
|
|
3063
|
+
* Restore terminal to normal state before suspending or exiting.
|
|
3064
|
+
*
|
|
3065
|
+
* Uses writeSync for reliability during signal handling (async write
|
|
3066
|
+
* may not complete before the process suspends).
|
|
3067
|
+
*
|
|
3068
|
+
* Order matters: disable protocols first, then show cursor, then exit
|
|
3069
|
+
* alternate screen, then disable raw mode.
|
|
3070
|
+
*/
|
|
3071
|
+
declare function restoreTerminalState(stdout: NodeJS.WriteStream, stdin: NodeJS.ReadStream): void;
|
|
3072
|
+
/**
|
|
3073
|
+
* Re-enter TUI mode after resuming from suspend (SIGCONT).
|
|
3074
|
+
*
|
|
3075
|
+
* Restores all protocols that were active before suspend, in the correct
|
|
3076
|
+
* order: raw mode first, then alternate screen, then protocols, then
|
|
3077
|
+
* trigger a full redraw via synthetic resize.
|
|
3078
|
+
*/
|
|
3079
|
+
declare function resumeTerminalState(state: TerminalState, stdout: NodeJS.WriteStream, stdin: NodeJS.ReadStream): void;
|
|
3080
|
+
/**
|
|
3081
|
+
* Execute the full suspend flow: save state, restore terminal, SIGTSTP,
|
|
3082
|
+
* and set up SIGCONT handler to resume.
|
|
3083
|
+
*
|
|
3084
|
+
* @param state - Terminal state snapshot to restore on resume
|
|
3085
|
+
* @param stdout - Output stream
|
|
3086
|
+
* @param stdin - Input stream
|
|
3087
|
+
* @param onResume - Optional callback after resume
|
|
3088
|
+
*/
|
|
3089
|
+
declare function performSuspend(state: TerminalState, stdout: NodeJS.WriteStream, stdin: NodeJS.ReadStream, onResume?: () => void): void;
|
|
3090
|
+
/** Ctrl+C raw byte (ETX - End of Text) */
|
|
3091
|
+
declare const CTRL_C = "\u0003";
|
|
3092
|
+
/** Ctrl+Z raw byte (SUB - Substitute) */
|
|
3093
|
+
declare const CTRL_Z = "\u001A";
|
|
3094
|
+
//#endregion
|
|
3095
|
+
//#region packages/ag-term/src/runtime/create-app.d.ts
|
|
3096
|
+
/**
|
|
3097
|
+
* Event handler context passed to handlers.
|
|
3098
|
+
*
|
|
3099
|
+
* When the store uses `tea()` middleware, `dispatch` is available with the
|
|
3100
|
+
* correct Op type inferred from the store. For non-tea stores it's `undefined`.
|
|
3101
|
+
*/
|
|
3102
|
+
interface EventHandlerContext<S> {
|
|
3103
|
+
set: StoreApi$1<S>["setState"];
|
|
3104
|
+
get: StoreApi$1<S>["getState"];
|
|
3105
|
+
/** The tree-based focus manager */
|
|
3106
|
+
focusManager: FocusManager;
|
|
3107
|
+
/** Convenience: focus a node by testID */
|
|
3108
|
+
focus(testID: string): void;
|
|
3109
|
+
/** Activate a peer focus scope (saves/restores focus per scope) */
|
|
3110
|
+
activateScope(scopeId: string): void;
|
|
3111
|
+
/** Get the focus path from focused node to root */
|
|
3112
|
+
getFocusPath(): string[];
|
|
3113
|
+
/**
|
|
3114
|
+
* Dispatch an operation through the tea() reducer.
|
|
3115
|
+
*
|
|
3116
|
+
* Available when the store was created with `tea()` middleware from `silvery/tea`.
|
|
3117
|
+
* Type-safe: the Op type is inferred from the store's TeaSlice.
|
|
3118
|
+
* For non-tea stores, this is `undefined`.
|
|
3119
|
+
*/
|
|
3120
|
+
dispatch?: "dispatch" extends keyof S ? S["dispatch"] : undefined;
|
|
3121
|
+
/** Hit-test the render tree at (x, y). Returns the deepest SilveryNode at that point, or null. */
|
|
3122
|
+
hitTest(x: number, y: number): AgNode | null;
|
|
3123
|
+
}
|
|
3124
|
+
/**
|
|
3125
|
+
* Generic event handler function.
|
|
3126
|
+
* Return 'exit' to exit the app.
|
|
3127
|
+
*/
|
|
3128
|
+
type EventHandler<T, S> = (data: T, ctx: EventHandlerContext<S>) => void | "exit" | "flush";
|
|
3129
|
+
/**
|
|
3130
|
+
* Event handlers map.
|
|
3131
|
+
* Keys are namespaced as 'provider:event' (e.g., 'term:key', 'term:resize').
|
|
3132
|
+
*/
|
|
3133
|
+
type EventHandlers<S> = {
|
|
3134
|
+
[event: `${string}:${string}`]: EventHandler<unknown, S> | undefined;
|
|
3135
|
+
};
|
|
3136
|
+
/**
|
|
3137
|
+
* Options for app.run().
|
|
3138
|
+
*/
|
|
3139
|
+
interface AppRunOptions {
|
|
3140
|
+
/** Terminal dimensions (default: from process.stdout) */
|
|
3141
|
+
cols?: number;
|
|
3142
|
+
rows?: number;
|
|
3143
|
+
/** Standard output (default: process.stdout) */
|
|
3144
|
+
stdout?: NodeJS.WriteStream;
|
|
3145
|
+
/** Standard input (default: process.stdin) */
|
|
3146
|
+
stdin?: NodeJS.ReadStream;
|
|
3147
|
+
/**
|
|
3148
|
+
* Plain writable sink for ANSI output. Headless mode with active output.
|
|
3149
|
+
* Requires cols and rows. Input via handle.press().
|
|
3150
|
+
*/
|
|
3151
|
+
writable?: {
|
|
3152
|
+
write(data: string): void;
|
|
3153
|
+
};
|
|
3154
|
+
/**
|
|
3155
|
+
* Subscribe to resize events in headless mode.
|
|
3156
|
+
* Called with a handler that should be invoked when dimensions change.
|
|
3157
|
+
* Returns an unsubscribe function.
|
|
3158
|
+
*/
|
|
3159
|
+
onResize?: (handler: (dims: {
|
|
3160
|
+
cols: number;
|
|
3161
|
+
rows: number;
|
|
3162
|
+
}) => void) => () => void;
|
|
3163
|
+
/** Abort signal for external cleanup */
|
|
3164
|
+
signal?: AbortSignal;
|
|
3165
|
+
/** Enter alternate screen buffer (clean slate, restore on exit). Default: false */
|
|
3166
|
+
alternateScreen?: boolean;
|
|
3167
|
+
/** Use Kitty keyboard protocol encoding for press(). Default: false */
|
|
3168
|
+
kittyMode?: boolean;
|
|
3169
|
+
/**
|
|
3170
|
+
* Enable Kitty keyboard protocol.
|
|
3171
|
+
* - `true`: auto-detect and enable with DISAMBIGUATE flag (1)
|
|
3172
|
+
* - number: enable with specific KittyFlags bitfield
|
|
3173
|
+
* - `false`/undefined: don't enable (default)
|
|
3174
|
+
*/
|
|
3175
|
+
kitty?: boolean | number;
|
|
3176
|
+
/**
|
|
3177
|
+
* Enable SGR mouse tracking (mode 1006).
|
|
3178
|
+
* When true, enables mouse events and disables on cleanup.
|
|
3179
|
+
* Default: false
|
|
3180
|
+
*/
|
|
3181
|
+
mouse?: boolean;
|
|
3182
|
+
/**
|
|
3183
|
+
* Enable virtual inline mode: alt screen with virtual scrollback buffer.
|
|
3184
|
+
* Provides scrollable history + search (Ctrl+F) while using fullscreen rendering.
|
|
3185
|
+
* Default: false
|
|
3186
|
+
*/
|
|
3187
|
+
virtualInline?: boolean;
|
|
3188
|
+
/**
|
|
3189
|
+
* Handle Ctrl+Z by suspending the process (save terminal state,
|
|
3190
|
+
* send SIGTSTP, restore on SIGCONT). Default: true
|
|
3191
|
+
*/
|
|
3192
|
+
suspendOnCtrlZ?: boolean;
|
|
3193
|
+
/**
|
|
3194
|
+
* Handle Ctrl+C by restoring terminal and exiting.
|
|
3195
|
+
* Default: true
|
|
3196
|
+
*/
|
|
3197
|
+
exitOnCtrlC?: boolean;
|
|
3198
|
+
/** Called before suspend. Return false to prevent. */
|
|
3199
|
+
onSuspend?: () => boolean | void;
|
|
3200
|
+
/** Called after resume from suspend. */
|
|
3201
|
+
onResume?: () => void;
|
|
3202
|
+
/** Called on Ctrl+C. Return false to prevent exit. */
|
|
3203
|
+
onInterrupt?: () => boolean | void;
|
|
3204
|
+
/**
|
|
3205
|
+
* Enable Kitty text sizing protocol (OSC 66) for PUA characters.
|
|
3206
|
+
* When enabled, nerdfont/powerline icons are measured as 2-wide and
|
|
3207
|
+
* wrapped in OSC 66 sequences so the terminal renders them at the
|
|
3208
|
+
* correct width.
|
|
3209
|
+
* - `true`: force enable
|
|
3210
|
+
* - `"auto"`: use heuristic, then probe to verify (progressive enhancement)
|
|
3211
|
+
* - `"probe"`: start disabled, probe async, enable on confirmation
|
|
3212
|
+
* - `false`/undefined: disabled (default)
|
|
3213
|
+
*/
|
|
3214
|
+
textSizing?: boolean | "auto" | "probe";
|
|
3215
|
+
/**
|
|
3216
|
+
* Enable DEC width mode detection (modes 1020-1023).
|
|
3217
|
+
* Queries the terminal for its actual character width settings (emoji,
|
|
3218
|
+
* CJK, private-use area) and updates the measurer accordingly.
|
|
3219
|
+
* - `true`: always run width detection probe
|
|
3220
|
+
* - `"auto"`: run probe when caps are provided (default for real terminals)
|
|
3221
|
+
* - `false`/undefined: disabled (default)
|
|
3222
|
+
*/
|
|
3223
|
+
widthDetection?: boolean | "auto";
|
|
3224
|
+
/**
|
|
3225
|
+
* Enable terminal focus reporting (CSI ?1004h).
|
|
3226
|
+
* When enabled, the terminal sends focus-in/focus-out events that are
|
|
3227
|
+
* dispatched as 'term:focus' events with `{ focused: boolean }`.
|
|
3228
|
+
* Default: false
|
|
3229
|
+
*/
|
|
3230
|
+
focusReporting?: boolean;
|
|
3231
|
+
/**
|
|
3232
|
+
* Enable buffer-level text selection via mouse drag.
|
|
3233
|
+
* When enabled, left mouse drag selects text, and mouse up copies
|
|
3234
|
+
* selected text to clipboard via OSC 52.
|
|
3235
|
+
* Default: true when mouse is enabled
|
|
3236
|
+
*/
|
|
3237
|
+
selection?: boolean;
|
|
3238
|
+
/**
|
|
3239
|
+
* Terminal capabilities for width measurement and output suppression.
|
|
3240
|
+
* When provided, configures the render pipeline to use these caps
|
|
3241
|
+
* (scoped width measurer + output phase). Typically from term.caps.
|
|
3242
|
+
*/
|
|
3243
|
+
caps?: TerminalCaps;
|
|
3244
|
+
/**
|
|
3245
|
+
* Guard stdout/stderr in alt screen mode. When true (the default for
|
|
3246
|
+
* alternateScreen), intercepts process.stdout.write and process.stderr.write
|
|
3247
|
+
* so that only silvery's render pipeline can write to stdout. Non-silvery
|
|
3248
|
+
* stderr writes are redirected to DEBUG_LOG if set, otherwise suppressed.
|
|
3249
|
+
* This prevents display corruption from libraries that write directly to
|
|
3250
|
+
* process.stdout/stderr (e.g., loggily, debug).
|
|
3251
|
+
*
|
|
3252
|
+
* - `true`: enable output guard (default when alternateScreen is true)
|
|
3253
|
+
* - `false`: disable output guard
|
|
3254
|
+
*/
|
|
3255
|
+
guardOutput?: boolean;
|
|
3256
|
+
/**
|
|
3257
|
+
* Root component that wraps the element tree with additional providers.
|
|
3258
|
+
* Set by plugins (e.g., withInk) via the `app.Root` pattern.
|
|
3259
|
+
* The Root component receives children and wraps them with providers.
|
|
3260
|
+
*/
|
|
3261
|
+
Root?: React$1.ComponentType<{
|
|
3262
|
+
children: React$1.ReactNode;
|
|
3263
|
+
}>;
|
|
3264
|
+
/**
|
|
3265
|
+
* Capability registry from the composition layer (e.g., withDomEvents, withTerminal).
|
|
3266
|
+
* When provided, exposed to React components via CapabilityRegistryContext so
|
|
3267
|
+
* hooks like useSelection() can discover interaction features.
|
|
3268
|
+
*/
|
|
3269
|
+
capabilityRegistry?: CapabilityLookup;
|
|
3270
|
+
/** Providers and plain values to inject */
|
|
3271
|
+
[key: string]: unknown;
|
|
3272
|
+
}
|
|
3273
|
+
/**
|
|
3274
|
+
* Handle returned by app.run().
|
|
3275
|
+
*
|
|
3276
|
+
* Also AsyncIterable<Buffer> — iterate to get frames after each event:
|
|
3277
|
+
* ```typescript
|
|
3278
|
+
* for await (const frame of app.run(<App />)) {
|
|
3279
|
+
* expect(frame.text).toContain('expected')
|
|
3280
|
+
* }
|
|
3281
|
+
* ```
|
|
3282
|
+
*/
|
|
3283
|
+
interface AppHandle<S> {
|
|
3284
|
+
/** Current rendered text (no ANSI) */
|
|
3285
|
+
readonly text: string;
|
|
3286
|
+
/** Live reconciler root node (for locator queries) */
|
|
3287
|
+
readonly root: AgNode;
|
|
3288
|
+
/** Current terminal buffer (cell-level access) */
|
|
3289
|
+
readonly buffer: TerminalBuffer | null;
|
|
3290
|
+
/** Access to the Zustand store */
|
|
3291
|
+
readonly store: StoreApi$1<S>;
|
|
3292
|
+
/** Wait until the app exits */
|
|
3293
|
+
waitUntilExit(): Promise<void>;
|
|
3294
|
+
/** Unmount and cleanup */
|
|
3295
|
+
unmount(): void;
|
|
3296
|
+
/** Dispose (alias for unmount) — enables `using` */
|
|
3297
|
+
[Symbol.dispose](): void;
|
|
3298
|
+
/** Send a key press (simulates term:key event) */
|
|
3299
|
+
press(key: string): Promise<void>;
|
|
3300
|
+
/** Iterate frames yielded after each event */
|
|
3301
|
+
[Symbol.asyncIterator](): AsyncIterator<Buffer$1>;
|
|
3302
|
+
}
|
|
3303
|
+
/**
|
|
3304
|
+
* App definition returned by createApp().
|
|
3305
|
+
*/
|
|
3306
|
+
interface AppDefinition<S> {
|
|
3307
|
+
run(element: ReactElement, options?: AppRunOptions): AppRunner<S>;
|
|
3308
|
+
}
|
|
3309
|
+
/**
|
|
3310
|
+
* Result of app.run() — both a Promise<AppHandle> and an AsyncIterable<Buffer>.
|
|
3311
|
+
*
|
|
3312
|
+
* - `await app.run(el)` → AppHandle (backward compat)
|
|
3313
|
+
* - `for await (const frame of app.run(el))` → iterate frames
|
|
3314
|
+
*/
|
|
3315
|
+
interface AppRunner<S> extends AsyncIterable<Buffer$1>, PromiseLike<AppHandle<S>> {}
|
|
3316
|
+
declare const StoreContext: React$1.Context<StoreApi$1<unknown> | null>;
|
|
3317
|
+
/**
|
|
3318
|
+
* Hook for accessing app state with selectors.
|
|
3319
|
+
*
|
|
3320
|
+
* @example
|
|
3321
|
+
* ```tsx
|
|
3322
|
+
* const count = useApp(s => s.count)
|
|
3323
|
+
* const { count, increment } = useApp(s => ({ count: s.count, increment: s.increment }))
|
|
3324
|
+
* ```
|
|
3325
|
+
*/
|
|
3326
|
+
declare function useApp<S, T>(selector: (state: S) => T): T;
|
|
3327
|
+
/**
|
|
3328
|
+
* Hook for accessing app state with shallow comparison.
|
|
3329
|
+
*
|
|
3330
|
+
* Like useApp, but uses shallow object comparison instead of Object.is().
|
|
3331
|
+
* Use when your selector returns a new object on each call — this prevents
|
|
3332
|
+
* re-renders when all individual fields are unchanged.
|
|
3333
|
+
*
|
|
3334
|
+
* @example
|
|
3335
|
+
* ```tsx
|
|
3336
|
+
* const { cursor, mode } = useAppShallow(s => ({
|
|
3337
|
+
* cursor: s.cursorNodeId,
|
|
3338
|
+
* mode: s.viewMode,
|
|
3339
|
+
* }))
|
|
3340
|
+
* ```
|
|
3341
|
+
*/
|
|
3342
|
+
declare function useAppShallow<S, T>(selector: (state: S) => T): T;
|
|
3343
|
+
/**
|
|
3344
|
+
* Create an app with Zustand store and provider integration.
|
|
3345
|
+
*
|
|
3346
|
+
* This is Layer 3 - it provides:
|
|
3347
|
+
* - Zustand store with fine-grained subscriptions
|
|
3348
|
+
* - Providers as unified stores + event sources
|
|
3349
|
+
* - Event handlers namespaced as 'provider:event'
|
|
3350
|
+
*
|
|
3351
|
+
* @param factory Store factory function that receives providers
|
|
3352
|
+
* @param handlers Optional event handlers (namespaced as 'provider:event')
|
|
3353
|
+
*/
|
|
3354
|
+
declare function createApp<I extends Record<string, unknown>, S extends Record<string, unknown>>(factory: (inject: I) => StateCreator<S>, handlers?: EventHandlers<S & I>): AppDefinition<S & I>;
|
|
3355
|
+
//#endregion
|
|
3356
|
+
//#region packages/ag-term/src/runtime/tick.d.ts
|
|
3357
|
+
/**
|
|
3358
|
+
* Time/tick source for silvery-loop.
|
|
3359
|
+
*
|
|
3360
|
+
* Creates an AsyncIterable that yields at regular intervals.
|
|
3361
|
+
* Used for animations, spinners, progress bars, etc.
|
|
3362
|
+
*/
|
|
3363
|
+
/**
|
|
3364
|
+
* Create a tick source that yields at regular intervals.
|
|
3365
|
+
*
|
|
3366
|
+
* The tick source respects AbortSignal for cleanup and stops
|
|
3367
|
+
* when the signal is aborted.
|
|
3368
|
+
*
|
|
3369
|
+
* @param intervalMs Interval between ticks in milliseconds
|
|
3370
|
+
* @param signal Optional AbortSignal to stop the tick source
|
|
3371
|
+
* @returns AsyncIterable that yields tick numbers (0, 1, 2, ...)
|
|
3372
|
+
*
|
|
3373
|
+
* @example
|
|
3374
|
+
* ```typescript
|
|
3375
|
+
* const controller = new AbortController()
|
|
3376
|
+
* const ticks = createTick(100, controller.signal)
|
|
3377
|
+
*
|
|
3378
|
+
* for await (const tick of ticks) {
|
|
3379
|
+
* console.log(`Tick ${tick}`)
|
|
3380
|
+
* if (tick >= 10) controller.abort()
|
|
3381
|
+
* }
|
|
3382
|
+
* ```
|
|
3383
|
+
*/
|
|
3384
|
+
declare function createTick(intervalMs: number, signal?: AbortSignal): AsyncIterable<number>;
|
|
3385
|
+
/**
|
|
3386
|
+
* Create a tick source that yields at approximately 60fps (~16ms).
|
|
3387
|
+
*
|
|
3388
|
+
* @param signal Optional AbortSignal to stop the tick source
|
|
3389
|
+
* @returns AsyncIterable that yields frame numbers
|
|
3390
|
+
*/
|
|
3391
|
+
declare function createFrameTick(signal?: AbortSignal): AsyncIterable<number>;
|
|
3392
|
+
/**
|
|
3393
|
+
* Create a tick source that yields once per second.
|
|
3394
|
+
*
|
|
3395
|
+
* @param signal Optional AbortSignal to stop the tick source
|
|
3396
|
+
* @returns AsyncIterable that yields second counts
|
|
3397
|
+
*/
|
|
3398
|
+
declare function createSecondTick(signal?: AbortSignal): AsyncIterable<number>;
|
|
3399
|
+
/**
|
|
3400
|
+
* Create a tick source with adaptive timing based on render performance.
|
|
3401
|
+
*
|
|
3402
|
+
* This is useful for maintaining a target frame rate while allowing
|
|
3403
|
+
* for slower frames when needed.
|
|
3404
|
+
*
|
|
3405
|
+
* @param targetFps Target frames per second (default: 60)
|
|
3406
|
+
* @param signal Optional AbortSignal to stop the tick source
|
|
3407
|
+
* @returns AsyncIterable with timing information
|
|
3408
|
+
*/
|
|
3409
|
+
declare function createAdaptiveTick(targetFps?: number, signal?: AbortSignal): AsyncIterable<{
|
|
3410
|
+
tick: number;
|
|
3411
|
+
elapsed: number;
|
|
3412
|
+
delta: number;
|
|
3413
|
+
}>;
|
|
3414
|
+
//#endregion
|
|
3415
|
+
export { defaultInit as $, RuntimeOptions as $t, DiffMode as A, createKeyEvent as An, PatchedConsole as At, filter as B, matchHotkey as Bn, ParsedMouse as Bt, resumeTerminalState as C, LayoutNode as Cn, createFocusManager as Ct, usePasteCallback as D, SilveryFocusEvent as Dn, term as Dt, PasteCallback as E, FocusEventProps as En, useInput as Et, layout as F, ParsedHotkey as Fn, TermEvents as Ft, merge as G, Event as Gt, fromArray as H, parseKey as Hn, parseMouseSequence as Ht, layoutSync as I, ParsedKeypress as In, TermProvider as It, throttle as J, Provider as Jt, take as K, EventData as Kt, batch as L, emptyKey as Ln, TermProviderOptions as Lt, render as M, dispatchKeyEvent as Mn, StyleChain as Mt, LayoutOptions as N, InputHandler as Nn, Term as Nt, createRuntime as O, SilveryKeyEvent as On, ConsoleStats as Ot, ensureLayoutEngine as P, Key as Pn, createTerm as Pt, createStore as Q, Runtime as Qt, concat as R, keyToModifiers as Rn, TermState as Rt, restoreTerminalState as S, SilveryWheelEvent as Sn, FocusSnapshot as St, run as T, MeasureMode as Tn, UseInputOptions as Tt, fromArrayWithDelay as U, parseKeypress as Un, Buffer$1 as Ut, filterMap as V, parseHotkey as Vn, isMouseSequence as Vt, map as W, Dims as Wt, StoreApi as X, ProviderEventKey as Xt, zip as Y, ProviderEvent as Yt, StoreConfig as Z, RenderTarget as Zt, CTRL_Z as _, ResizeEvent as _n, getTabOrder as _t, AppDefinition as a, ConsoleEntry as an, CapabilityLookup as at, captureTerminalState as b, MouseEventProps as bn, FocusManagerOptions as bt, AppRunner as c, BoxProps as cn, RuntimeContext as ct, EventHandlers as d, EventSource as dn, TermContext as dt, Cell as en, silveryUpdate as et, StoreContext as f, FocusEvent as fn, findByTestID as ft, CTRL_C as g, Rect as gn, getExplicitFocusLink as gt, useAppShallow as h, MouseEvent as hn, findSpatialTarget as ht, createTick as i, FrameCell as in, CacheBackendContext as it, diff as j, dispatchFocusEvent as jn, patchConsole as jt, createBuffer as k, createFocusEvent as kn, PatchConsoleOptions as kt, EventHandler as l, CustomEvent as ln, RuntimeContextValue as lt, useApp as m, KeyEvent as mn, findFocusableAncestor as mt, createFrameTick as n, TerminalBuffer as nn, BaseRuntimeEvents as nt, AppHandle as o, AgNode as on, CapabilityRegistryContext as ot, createApp as p, InteractiveState as pn, findEnclosingScope as pt, takeUntil as q, NamespacedEvent as qt, createSecondTick as r, UnderlineStyle as rn, CacheBackend as rt, AppRunOptions as s, BlurEvent as sn, FocusManagerContext as st, createAdaptiveTick as t, Style as tn, withFocusManagement as tt, EventHandlerContext as u, Event$1 as un, StderrContext as ut, TerminalLifecycleOptions as v, SignalEvent as vn, FocusChangeCallback as vt, RunOptions as w, MeasureFunc as wn, useExit as wt, performSuspend as x, SilveryMouseEvent as xn, FocusOrigin as xt, TerminalState as y, TextProps as yn, FocusManager as yt, debounce as z, keyToName as zn, createTermProvider as zt };
|
|
3416
|
+
//# sourceMappingURL=index-CBcSpGSM.d.mts.map
|