@fx-/chat-ink 0.0.0-stage → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,806 @@
1
+ import { BlockLayoutContext, CellBox, FooterHints, FrameInput, ImageLayoutOptions, ImageProvider, ImageState, InkAppearance, InkGlyphs, InkTheme, InkThemeRole, LayoutContext, Line, LineDraft, LineTarget, MarkdownLayout, Measure, MessageFrame, NOTHING_OPEN, OpenState, ROW_PATH, Span, THUMBNAIL, WrappedRow, asciiGlyphs, cachedMeasure, defaultMeasure, emojiGlyphs, footerSpans, graphemes, hardSplit, layoutBody, layoutImage, layoutMessage, lineText, plainGlyphs, plainMarkdownLayout, plainTheme, prefix, resolveAccent, showsSomething, span, suffix, truncate, wrapLines, wrapText } from "./images.d-KUBzdbd9.js";
2
+ import { ClockProviderProps, CoreHooks, ElapsedTimerInput, LiveTokensInput, SharedClock } from "@fx-/chat-core/hooks";
3
+ import { Attachment, CompletionItem, CompletionProvider, CustomBlock, DetailLevel, LivePhase, RenderableMessage, SummaryIconName } from "@fx-/chat-core";
4
+ import * as _0 from "react";
5
+ import * as _3 from "react";
6
+ import { ComponentType, FunctionComponentElement, JSX, ProviderProps, ReactNode, Ref } from "react";
7
+ import * as _1 from "ink";
8
+ import * as _4 from "ink";
9
+ import { DOMElement, Key } from "ink";
10
+
11
+ //#region src/Composer.d.ts
12
+ /** The composer's content: text, caret offset and attachments. */
13
+ interface ComposerValue {
14
+ text: string;
15
+ caret: number;
16
+ attachments: Attachment[];
17
+ }
18
+ declare const emptyComposerValue: ComposerValue;
19
+ /** Drive a composer that takes its keys from the host (`inputSource: 'host'`). */
20
+ interface ComposerHandle {
21
+ key: (input: string, key: Key) => void;
22
+ paste: (text: string) => void;
23
+ }
24
+ interface ComposerProps {
25
+ /** Called with the text, and the attachments when there are any. */
26
+ onSubmit: (text: string, attachments?: Attachment[]) => void;
27
+ /** Esc with no completion open. */
28
+ onEscape?: () => void;
29
+ providers?: CompletionProvider<CompletionItem<never> | CompletionItem>[];
30
+ /** Previous inputs, oldest first. */
31
+ history?: Array<string | {
32
+ text: string;
33
+ attachments?: Attachment[];
34
+ }>;
35
+ placeholder?: string;
36
+ /** Ignore input entirely (e.g. while a dialog owns the keyboard). */
37
+ disabled?: boolean;
38
+ /** Hint line under the input. */
39
+ hint?: string;
40
+ /** Maximum completion items shown. */
41
+ maxItems?: number;
42
+ /** Controlled content; pair with `onChange`. */
43
+ value?: ComposerValue;
44
+ onChange?: (value: ComposerValue) => void;
45
+ /** `boxed` (default) or `plain`: no border, the prompt on the first row only. */
46
+ variant?: 'boxed' | 'plain';
47
+ /** Width in cells: rows soft-wrap to fit (one cell is kept for the caret). */
48
+ width?: number;
49
+ /** Rows shown at most; the input scrolls to keep the caret's row visible. */
50
+ maxRows?: number;
51
+ /** Whether the composer has focus: takes keys and draws the caret (default true). */
52
+ focused?: boolean;
53
+ /** Shown after the attachment descriptions, e.g. `Esc removes`. */
54
+ attachmentHint?: string;
55
+ /** What Ctrl+U clears: to the line start (default) or the whole input. */
56
+ killLine?: 'line' | 'input';
57
+ /** Called first for every key; return true when handled. */
58
+ onKey?: (input: string, key: Key) => boolean;
59
+ /** Called first for every bracketed paste; return true when handled. */
60
+ onPaste?: (text: string) => boolean;
61
+ /** `own` (default) listens for keys; `host` takes them through `ref`. */
62
+ inputSource?: 'own' | 'host';
63
+ ref?: Ref<ComposerHandle>;
64
+ /** Push the kitty keyboard disambiguate flag while focused. */
65
+ kittyKeyboard?: boolean;
66
+ /** Cell measure for soft wrap (default string width). */
67
+ measure?: Measure;
68
+ }
69
+ /**
70
+ * Cells left for text at `width`: the prompt, the border and padding of the
71
+ * boxed variant, and one cell kept for the caret come off.
72
+ */
73
+ declare function composerInnerWidth(width: number, variant?: 'boxed' | 'plain', promptWidth?: number): number;
74
+ /**
75
+ * Rows the composer takes at `width` for `value`: its input rows (up to
76
+ * `maxRows`), the attachments row, and the boxed variant's border — not the
77
+ * hint or completion lines under it. Lets a host size the rest of the screen.
78
+ */
79
+ declare function composerRows(value: Pick<ComposerValue, 'text' | 'attachments'>, width: number, options?: {
80
+ variant?: 'boxed' | 'plain';
81
+ maxRows?: number | undefined;
82
+ promptWidth?: number;
83
+ measure?: Measure;
84
+ }): number;
85
+ declare function Composer({ onSubmit, onEscape, providers, history: initialHistory, placeholder, disabled, hint, maxItems, value: controlled, onChange, variant, width, maxRows, focused, attachmentHint, killLine, onKey, onPaste, inputSource, ref, kittyKeyboard, measure, }: ComposerProps): JSX.Element;
86
+
87
+ //#endregion
88
+ //#region src/MessageView.d.ts
89
+ /** Props passed to a host renderer for a custom block kind. */
90
+ interface InkBlockRendererProps {
91
+ block: CustomBlock;
92
+ message: RenderableMessage;
93
+ isStreaming: boolean;
94
+ }
95
+ interface InkExtensions {
96
+ /** Renderers keyed by custom block `type`. */
97
+ blockRenderers?: Record<string, ComponentType<InkBlockRendererProps>>;
98
+ }
99
+ interface MessageViewProps {
100
+ message: RenderableMessage;
101
+ /** Whether this is the live, streaming message. */
102
+ isActive?: boolean;
103
+ /** Show group and row bodies (reasoning text, tool input/output). */
104
+ expanded?: boolean;
105
+ /** Fold each assistant turn's auxiliary blocks into one group. */
106
+ minimal?: boolean;
107
+ showFooter?: boolean;
108
+ /** Maximum lines of any tool input/output or reasoning body. */
109
+ bodyLines?: number;
110
+ /** Host label for retrying, shown in the footer of a stopped or failed message (e.g. "/retry"). */
111
+ retryHint?: string;
112
+ /** Activity after content instead of in stream order. */
113
+ activityPlacement?: 'inline' | 'after-content';
114
+ /** While live and collapsed, show only the newest N activity blocks after an `N earlier` row. */
115
+ liveTail?: number;
116
+ /** Show the footer (whole-second elapsed and activity facts) while live (opt-in). */
117
+ liveFooter?: boolean;
118
+ extensions?: InkExtensions;
119
+ }
120
+ declare function MessageView({ message: original, isActive, expanded, minimal, showFooter, bodyLines, extensions, retryHint, activityPlacement, liveTail, liveFooter, }: MessageViewProps): JSX.Element;
121
+
122
+ //#endregion
123
+ //#region src/Row.d.ts
124
+ interface RowProps {
125
+ label: ReactNode;
126
+ /** Secondary text after the label (e.g. a tool's input), muted. */
127
+ detail?: string | undefined;
128
+ /** A qualifier after everything else (e.g. `denied`), in the danger tone. */
129
+ qualifier?: string | undefined;
130
+ iconName?: SummaryIconName | undefined;
131
+ /** Rendered before the icon (e.g. the `(+N)` count). */
132
+ prefix?: ReactNode;
133
+ isActive?: boolean | undefined;
134
+ startedAt?: number | undefined;
135
+ durationMs?: number | undefined;
136
+ showTimer?: boolean | undefined;
137
+ tokensPerSecond?: number | undefined;
138
+ error?: boolean | undefined;
139
+ expanded?: boolean | undefined;
140
+ children?: ReactNode;
141
+ }
142
+ declare function Row({ label, detail, qualifier, iconName, prefix, isActive, startedAt, durationMs, showTimer, tokensPerSecond, error, expanded, children, }: RowProps): JSX.Element;
143
+ /** Clip long text to `maxLines`, noting how many lines were hidden. */
144
+ declare function clipLines(text: string, maxLines: number): string;
145
+ /** Pretty JSON, tolerating values JSON cannot encode. */
146
+ declare function toJson(value: unknown): string;
147
+
148
+ //#endregion
149
+ //#region src/Spinner.d.ts
150
+ /** @jsxRuntime classic */
151
+ /** @jsx React.createElement */
152
+ /** @jsxFrag React.Fragment */
153
+ /**
154
+ * An animated spinner in the `marker` role, using the injected frames. It
155
+ * steps once per tick of the shared clock when a ClockProvider is in scope,
156
+ * else every `spinnerIntervalMs`.
157
+ */
158
+ declare function Spinner(): JSX.Element;
159
+
160
+ //#endregion
161
+ //#region src/Transcript.d.ts
162
+ interface TranscriptProps {
163
+ messages: RenderableMessage[];
164
+ isStreaming?: boolean;
165
+ /** The id of the live message, if any. */
166
+ streamingMessageId?: string | undefined;
167
+ /** Expand row bodies of the live turn. */
168
+ expanded?: boolean;
169
+ /** Expand row bodies of finished messages as they are printed. */
170
+ expandFinished?: boolean;
171
+ minimal?: boolean;
172
+ showFooter?: boolean;
173
+ bodyLines?: number;
174
+ extensions?: InkExtensions;
175
+ /** Host label for retrying, shown on stopped or failed messages. */
176
+ retryHint?: string;
177
+ /** Activity after content instead of in stream order. */
178
+ activityPlacement?: 'inline' | 'after-content';
179
+ /** While live and collapsed, show only the newest N activity blocks. */
180
+ liveTail?: number;
181
+ /** Show the footer while live (opt-in). */
182
+ liveFooter?: boolean;
183
+ }
184
+ declare function Transcript({ messages, isStreaming, streamingMessageId, expanded, expandFinished, minimal, showFooter, bodyLines, extensions, retryHint, activityPlacement, liveTail, liveFooter, }: TranscriptProps): JSX.Element;
185
+
186
+ //#endregion
187
+ //#region src/lines/Lines.d.ts
188
+ /** A span's resolved text props. */
189
+ declare function spanProps(s: Span, theme: InkTheme, highlight?: InkAppearance): Record<string, unknown>;
190
+ /** Split text into runs that keep width measurement cheap. */
191
+ declare function splitRuns(text: string): string[];
192
+ interface LinesProps {
193
+ lines: readonly Line[];
194
+ theme: InkTheme;
195
+ /** Replace a line's drawing (e.g. a selection highlight); return undefined to draw normally. */
196
+ override?: (line: Line, index: number) => ReactNode | undefined;
197
+ }
198
+ declare function Lines({ lines, theme, override }: LinesProps): JSX.Element;
199
+
200
+ //#endregion
201
+ //#region src/lines/Status.d.ts
202
+ interface StatusLineProps {
203
+ width: number;
204
+ /** The live message, when one streams: drives the pulse and phase. */
205
+ live?: {
206
+ message: RenderableMessage;
207
+ startedAt: number;
208
+ } | undefined;
209
+ /** Shown when nothing is live. */
210
+ notice?: {
211
+ text: string;
212
+ tone: 'positive' | 'danger';
213
+ } | undefined;
214
+ /** The host's own state when nothing is live and there is no notice (before "↓ N more"). */
215
+ idle?: string | undefined;
216
+ /** Lines below the viewport window ("↓ N more"). */
217
+ below?: number;
218
+ /** Host facts appended while live, e.g. `2 queued`, `^X stop`. */
219
+ extras?: string[];
220
+ /** Host label per phase (return undefined for the default). */
221
+ phaseLabel?: (phase: LivePhase) => string | undefined;
222
+ /** Facts appended once a phase has lasted a while (e.g. a cold-start hint). */
223
+ slowHint?: {
224
+ afterMs: number;
225
+ text: string;
226
+ phases: LivePhase['kind'][];
227
+ };
228
+ /** The pulse's appearance (default: the `accent` role). */
229
+ accent?: InkAppearance;
230
+ measure?: Measure;
231
+ }
232
+ declare function StatusLine({ width, live, notice, idle, below, extras, phaseLabel, slowHint, accent, measure, }: StatusLineProps): JSX.Element;
233
+ interface PendingItem {
234
+ text: string;
235
+ attachments?: number;
236
+ }
237
+ interface PendingRowsProps {
238
+ items: PendingItem[];
239
+ width: number;
240
+ /** At most this many rows, newest last (default 3). */
241
+ maxRows?: number;
242
+ measure?: Measure;
243
+ }
244
+ /** Messages queued while an answer streams (the queue itself is host state). */
245
+ declare function PendingRows({ items, width, maxRows, measure, }: PendingRowsProps): JSX.Element | null;
246
+ interface EmptyStateProps {
247
+ title: string;
248
+ subtitle?: string;
249
+ notes?: string[];
250
+ /** The title's appearance (default: the `accent` role). */
251
+ accent?: InkAppearance;
252
+ }
253
+ /** A centred empty state; pass it as the viewport's `empty`. */
254
+ declare function EmptyState({ title, subtitle, notes, accent }: EmptyStateProps): JSX.Element;
255
+
256
+ //#endregion
257
+ //#region src/lines/Viewport.d.ts
258
+ /** Follow the bottom, or stay pinned to a top line. */
259
+ type Scroll = {
260
+ follow: true;
261
+ } | {
262
+ follow: false;
263
+ top: number;
264
+ };
265
+ /** The viewport's geometry: total lines, the first visible one, rows, and lines below. */
266
+ interface Geometry {
267
+ total: number;
268
+ first: number;
269
+ rows: number;
270
+ below: number;
271
+ }
272
+ declare const scrollHome: Scroll;
273
+ declare const scrollEnd: Scroll;
274
+ /** The window's first line for a scroll state. */
275
+ declare function firstLine(scroll: Scroll, total: number, rows: number): number;
276
+ /** Scroll by `delta` lines, clamped; reaching the bottom returns to follow. */
277
+ declare function scrollBy(scroll: Scroll, delta: number, g: Geometry): Scroll;
278
+ /** Scroll by pages; a page keeps two lines of context. */
279
+ declare function pageBy(scroll: Scroll, pages: number, g: Geometry): Scroll;
280
+ /** Remappable viewport keys; `false` disables a binding (or all of them). */
281
+ interface ViewportKeys {
282
+ page?: boolean;
283
+ lines?: boolean;
284
+ homeEnd?: boolean;
285
+ detail?: boolean;
286
+ }
287
+ interface TranscriptViewportProps {
288
+ messages: RenderableMessage[];
289
+ width: number;
290
+ height: number;
291
+ /** The live message's id, when one streams. */
292
+ streamingMessageId?: string | undefined;
293
+ scroll: Scroll;
294
+ onScroll: (next: Scroll) => void;
295
+ onGeometry?: (geometry: Geometry) => void;
296
+ detail?: DetailLevel;
297
+ onDetailChange?: (detail: DetailLevel) => void;
298
+ /** The message frame (default compact). */
299
+ frame?: MessageFrame;
300
+ activityPlacement?: 'inline' | 'after-content';
301
+ /** Newest tool rows a collapsed live message shows (default 3). */
302
+ liveTail?: number;
303
+ /** Footer on the live message (default true here). */
304
+ liveFooter?: boolean;
305
+ accentFor?: (message: RenderableMessage) => InkThemeRole | InkAppearance;
306
+ /** Drawn centred when there is nothing to show. */
307
+ empty?: ReactNode;
308
+ /** Controlled open state for rows and JSON members (uncontrolled when omitted). */
309
+ opened?: OpenState;
310
+ onToggle?: (blockId: string, path: string) => void;
311
+ hints?: FooterHints;
312
+ /**
313
+ * Injected layouts and measure are compared by identity (part of the layout
314
+ * cache key): pass stable values, or every change lays everything out again.
315
+ */
316
+ markdown?: MarkdownLayout;
317
+ blockLayouts?: Record<string, (block: CustomBlock, ctx: BlockLayoutContext) => LineDraft[]>;
318
+ measure?: Measure;
319
+ /** Whether the viewport takes its keys (default true). */
320
+ focused?: boolean;
321
+ /** Key bindings; `false` disables all. Home/End need `homeEnd: true` (no composer). */
322
+ keys?: ViewportKeys | false;
323
+ /** Lays out a block image line, when the host draws images (compared by identity). */
324
+ image?: LayoutContext['image'];
325
+ /** Draw a line differently (selection highlight); index is within the window. */
326
+ override?: (line: Line, index: number, absolute: number) => ReactNode | undefined;
327
+ /** Bumped by an image provider when an image arrives (part of the cache key). */
328
+ imagesVersion?: number;
329
+ /** Draws block images (used when `image` is not given). */
330
+ images?: ImageProvider;
331
+ /** Rows an expanded image may take (default: the height minus 8). */
332
+ maxImageHeight?: number;
333
+ /** Mouse support (opt-in): wheel, drag-select and copy, clicks. */
334
+ mouse?: ViewportMouse;
335
+ /** Writes terminal escapes: mouse reporting, copies, the image query (default: stdout). */
336
+ write?: (data: string) => void;
337
+ /** Host facts after a message's own footer facts (e.g. `turn 42` in details). */
338
+ footerExtras?: LayoutContext['footerExtras'];
339
+ /** A finished answer's activity when collapsed: its rows (default) or only the footer counts. */
340
+ finishedActivity?: LayoutContext['finishedActivity'];
341
+ /** A blank line between content and adjacent activity (default true). */
342
+ activitySpacing?: boolean;
343
+ }
344
+ /** Mouse options. Shift+drag keeps the terminal's own selection. */
345
+ interface ViewportMouse {
346
+ /** Lines per wheel step (default 3). */
347
+ wheelStep?: number;
348
+ /** Double-click interval in ms (default 400). */
349
+ doubleClickMs?: number;
350
+ /** Writes this feature's escapes (default: the viewport's `write`). */
351
+ write?: (data: string) => void;
352
+ /** Called after a copy with the text and a short description. */
353
+ onCopy?: (text: string, description: string) => void;
354
+ /** Ctrl+click on an image; hosts should accept only http(s). */
355
+ onOpenUrl?: (url: string) => void;
356
+ }
357
+ /** Uncontrolled open state: a version plus the set of open `blockId␟path` keys. */
358
+ declare function useOpenState(): [OpenState, (blockId: string, path: string) => void];
359
+ /** Lay out the transcript and compute the window (for hosts that draw extra chrome). */
360
+ declare function useTranscriptLayout(props: TranscriptViewportProps): {
361
+ lines: Line[];
362
+ geometry: Geometry;
363
+ window: Line[];
364
+ toggle: (blockId: string, path: string) => void;
365
+ now: number;
366
+ imageStates: Map<string, ImageState | undefined>;
367
+ toggleExpanded: (src: string) => void;
368
+ };
369
+ /** What a key does in the viewport (pure, so every binding is testable). */
370
+ declare function viewportKeyAction(input: string, key: Pick<Key, 'pageUp' | 'pageDown' | 'shift' | 'upArrow' | 'downArrow' | 'home' | 'end' | 'ctrl'>, keys: ViewportKeys | false, scroll: Scroll, geometry: Geometry, detail: DetailLevel): {
371
+ scroll: Scroll;
372
+ } | {
373
+ detail: DetailLevel;
374
+ } | undefined;
375
+ declare function TranscriptViewport(props: TranscriptViewportProps): JSX.Element;
376
+
377
+ //#endregion
378
+ //#region src/lines/mouse.d.ts
379
+ /** Button-event tracking with SGR encoding, on and off. */
380
+ declare const MOUSE_ON: string;
381
+ declare const MOUSE_OFF: string;
382
+ interface MouseEvent {
383
+ kind: 'press' | 'release' | 'drag' | 'wheel-up' | 'wheel-down';
384
+ button: 'left' | 'middle' | 'right' | 'none';
385
+ /** Zero-based screen cell. */
386
+ x: number;
387
+ y: number;
388
+ ctrl: boolean;
389
+ shift: boolean;
390
+ meta: boolean;
391
+ }
392
+ /**
393
+ * Every SGR mouse report in a chunk of terminal input. Horizontal wheel
394
+ * reports (buttons 6 and 7) are dropped: the viewport only scrolls vertically.
395
+ */
396
+ declare function parseMouse(data: string): MouseEvent[];
397
+ /**
398
+ * A reader of terminal reports across input chunks: each call returns the
399
+ * complete CSI sequences in what has arrived, keeping an unfinished one at
400
+ * the end for the next chunk (a terminal may split a report anywhere). The
401
+ * kept tail is bounded; past the bound it is dropped as noise.
402
+ */
403
+ declare function createReportReader(): (data: string) => string[];
404
+ /** An OSC 52 clipboard write of `text`. */
405
+ declare function osc52(text: string): string;
406
+ /**
407
+ * The element's position on screen, in cells. This relies on the renderer's
408
+ * layout internals (each node's computed offset from its parent), so it is
409
+ * isolated here.
410
+ */
411
+ declare function screenOrigin(node: DOMElement | null | undefined): {
412
+ x: number;
413
+ y: number;
414
+ };
415
+ /** A point in the transcript: an absolute line index and a cell column. */
416
+ interface Point {
417
+ line: number;
418
+ col: number;
419
+ }
420
+ /** The two ends of a selection, in reading order. */
421
+ declare function ordered(a: Point, b: Point): [Point, Point];
422
+ /**
423
+ * Copy text between two points (inclusive of the end cell): content spans
424
+ * only, decoration lines skipped, lines right-trimmed, soft joins as a space,
425
+ * hard joins as nothing, other lines by newlines.
426
+ */
427
+ declare function copyText(lines: readonly Line[], a: Point, b: Point, measure: Measure): string;
428
+ /**
429
+ * Highlight the content cells of a line from `start` to `end` (inclusive) with
430
+ * the selection appearance; selecting past the line's end highlights one more
431
+ * cell. Decoration lines are returned as they are.
432
+ */
433
+ declare function highlightLine(line: Line, start: number, end: number, selection: InkAppearance, measure: Measure): Line;
434
+ /** Call `handler` with every chunk of raw terminal input while active. */
435
+ declare function useTerminalData(handler: (data: string) => void, active: boolean): void;
436
+ /** Enable mouse reporting while active; disable on deactivation, unmount and process exit. */
437
+ declare function useMouseReporting(active: boolean, write: (data: string) => void): void;
438
+
439
+ //#endregion
440
+ //#region src/registry.d.ts
441
+ /** Props of the markdown slot. */
442
+ interface InkMarkdownProps {
443
+ content: string;
444
+ /** True while the text is still streaming (renderers may relax parsing). */
445
+ streaming?: boolean;
446
+ }
447
+ interface InkComponents {
448
+ theme: InkTheme;
449
+ glyphs: InkGlyphs;
450
+ /** Renders message text. The default prints it verbatim in the `content` role. */
451
+ Markdown: ComponentType<InkMarkdownProps>;
452
+ /** Spinner frame interval in ms (ignored under a shared clock). */
453
+ spinnerIntervalMs: number;
454
+ /** Show the brief completion check when a row finishes (default true). */
455
+ flashComplete: boolean;
456
+ }
457
+ /** A partial registry; nested theme/glyph maps merge per key. */
458
+ interface PartialInkComponents {
459
+ theme?: Partial<InkTheme>;
460
+ glyphs?: Partial<InkGlyphs>;
461
+ Markdown?: ComponentType<InkMarkdownProps>;
462
+ spinnerIntervalMs?: number;
463
+ flashComplete?: boolean;
464
+ }
465
+ /** Prints markdown source as-is. */
466
+ declare function PlainMarkdown({ content }: InkMarkdownProps): JSX.Element;
467
+ declare const plainComponents: InkComponents;
468
+ /** Merge a partial registry over a base. */
469
+ declare function mergeInkComponents(base: InkComponents, partial?: PartialInkComponents): InkComponents;
470
+ declare function InkChatProvider({ components, children, }: {
471
+ components?: PartialInkComponents;
472
+ children?: ReactNode;
473
+ }): JSX.Element;
474
+ declare function useInkComponents(): InkComponents;
475
+ /** Ink `<Text>` props for an appearance. */
476
+ declare function appearanceProps(appearance: InkAppearance): {
477
+ strikethrough?: boolean;
478
+ underline?: boolean;
479
+ inverse?: boolean;
480
+ italic?: boolean;
481
+ bold?: boolean;
482
+ dimColor?: boolean;
483
+ color?: string;
484
+ };
485
+ /** Text drawn in a theme role (`tone`). */
486
+ declare function Styled({ tone, wrap, children, }: {
487
+ tone: InkThemeRole;
488
+ wrap?: 'wrap' | 'truncate-end';
489
+ children?: ReactNode;
490
+ }): JSX.Element;
491
+
492
+ //#endregion
493
+ //#region src/runtime.d.ts
494
+ type ReactApi = typeof _0;
495
+ type InkApi = typeof _1;
496
+ /** What a host hands in. */
497
+ interface ChatInkDeps {
498
+ React: ReactApi;
499
+ ink: InkApi;
500
+ }
501
+ declare let React: ReactApi;
502
+ declare let ink: InkApi;
503
+ /** The core render hooks, bound to the host's React. */
504
+ declare let hooks: CoreHooks;
505
+ /** Whether `createChatInk` has run. */
506
+ declare function isBound(): boolean;
507
+
508
+ //#endregion
509
+ //#region src/create.d.ts
510
+ /**
511
+ * One shared clock for every timer, rate, spinner and pulse this package
512
+ * draws (the core hooks' provider, on the host's React).
513
+ */
514
+ declare function ClockProvider(props: ClockProviderProps): FunctionComponentElement<ClockProviderProps>;
515
+ declare function createChatInk(deps: ChatInkDeps): {
516
+ React: typeof _3;
517
+ ink: typeof _4;
518
+ /** The core render hooks (clock, timers, rates) on the host's React. */
519
+ hooks: {
520
+ ClockProvider: ({ tickMs, children }: ClockProviderProps) => FunctionComponentElement<ProviderProps<SharedClock | null>>;
521
+ useSharedClock: () => SharedClock | null;
522
+ useTicks: (active: boolean, fallbackMs: number) => number;
523
+ useClock: (active: boolean, fallbackMs?: number) => number;
524
+ useElapsedTimer: ({ startedAt, isActive, durationMs, intervalMs, }: ElapsedTimerInput) => number;
525
+ useLiveTokensPerSecond: ({ startedAt, isActive, tokenCount, metrics, intervalMs, }: LiveTokensInput) => number | undefined;
526
+ usePrefersReducedMotion: () => boolean;
527
+ useFlashComplete: (isActive: boolean, duration?: number, enabled?: boolean) => boolean;
528
+ };
529
+ ClockProvider: typeof ClockProvider;
530
+ Composer: typeof Composer;
531
+ EmptyState: typeof EmptyState;
532
+ InkChatProvider: typeof InkChatProvider;
533
+ Lines: typeof Lines;
534
+ MessageView: typeof MessageView;
535
+ PendingRows: typeof PendingRows;
536
+ PlainMarkdown: typeof PlainMarkdown;
537
+ Row: typeof Row;
538
+ Spinner: typeof Spinner;
539
+ StatusLine: typeof StatusLine;
540
+ Styled: typeof Styled;
541
+ Transcript: typeof Transcript;
542
+ TranscriptViewport: typeof TranscriptViewport;
543
+ useInkComponents: typeof useInkComponents;
544
+ useMouseReporting: typeof useMouseReporting;
545
+ useOpenState: typeof useOpenState;
546
+ useTerminalData: typeof useTerminalData;
547
+ useTranscriptLayout: typeof useTranscriptLayout;
548
+ };
549
+ /** The renderer `createChatInk` returns. */
550
+ type ChatInk = ReturnType<typeof createChatInk>;
551
+
552
+ //#endregion
553
+ //#region src/editor.d.ts
554
+ interface EditorState {
555
+ value: string;
556
+ /**
557
+ * Caret offset into `value` (0…length). Every operation leaves it on a
558
+ * grapheme boundary, so an emoji, flag or combining sequence is never split;
559
+ * an offset inside a grapheme is first moved back to that grapheme's start.
560
+ */
561
+ caret: number;
562
+ }
563
+ declare const emptyEditor: EditorState;
564
+ /** `caret` clamped to the value and moved back to the start of the grapheme it is inside. */
565
+ declare function caretBoundary(value: string, caret: number): number;
566
+ /**
567
+ * Split `text` at a caret for drawing: before it, the grapheme under it ('' at
568
+ * the end) and after it. The grapheme is whole, so the caret cell covers all
569
+ * of it (two cells for a wide one) and no character is split around it.
570
+ */
571
+ declare function splitAtCaret(text: string, caret: number): [string, string, string];
572
+ /**
573
+ * Insert at the caret. Text that joins the grapheme after it (a combining
574
+ * mark's base, half a flag) leaves the caret after the joined grapheme.
575
+ */
576
+ declare function insert(state: EditorState, text: string): EditorState;
577
+ declare function backspace(state: EditorState): EditorState;
578
+ declare function deleteForward(state: EditorState): EditorState;
579
+ /** Move the caret `delta` graphemes (negative: left), stopping at the ends. */
580
+ declare function moveBy(state: EditorState, delta: number): EditorState;
581
+ declare function lineStart(state: EditorState): EditorState;
582
+ declare function lineEnd(state: EditorState): EditorState;
583
+ /** Delete from the line start to the caret. */
584
+ declare function killToLineStart(state: EditorState): EditorState;
585
+ /** Delete from the caret to the line end. */
586
+ declare function killToLineEnd(state: EditorState): EditorState;
587
+ /** Delete the word before the caret (and the whitespace after it). */
588
+ declare function deleteWordBack(state: EditorState): EditorState;
589
+ /**
590
+ * Move the caret one line up (`-1`) or down (`+1`), keeping its cell column
591
+ * where the target line is long enough. Returns `undefined` at the first/last
592
+ * line, so the caller can fall through to history navigation.
593
+ */
594
+ declare function moveLine(state: EditorState, direction: -1 | 1, measure?: Measure): EditorState | undefined;
595
+ /** Split into lines, each with the caret column (an offset into the line) when the caret is on it. */
596
+ declare function caretLines(state: EditorState): Array<{
597
+ text: string;
598
+ caret?: number;
599
+ }>;
600
+ /** Jump to the start of the previous whitespace-separated word. */
601
+ declare function wordLeft(state: EditorState): EditorState;
602
+ /** Jump past the end of the next whitespace-separated word. */
603
+ declare function wordRight(state: EditorState): EditorState;
604
+ /**
605
+ * One drawn row of the input: offsets `[start, end)` into the value (a
606
+ * newline is never inside a row). `soft` rows continue on the next row.
607
+ */
608
+ interface VisualRow {
609
+ start: number;
610
+ end: number;
611
+ soft: boolean;
612
+ }
613
+ /**
614
+ * Lay the value out in rows: at newlines, and (with a width) wherever the
615
+ * next grapheme would pass `width` cells — never inside a wide character.
616
+ */
617
+ declare function visualRows(value: string, width?: number, measure?: Measure): VisualRow[];
618
+ /** The row holding the caret: a soft row's end belongs to the next row. */
619
+ declare function caretRow(rows: readonly VisualRow[], caret: number): number;
620
+ /**
621
+ * Move the caret one visual row up or down, keeping its cell column (landing
622
+ * at the end of a shorter row). Undefined at the first or last row.
623
+ */
624
+ declare function moveVisual(state: EditorState, rows: readonly VisualRow[], direction: -1 | 1, measure?: Measure): EditorState | undefined;
625
+ /** A history entry: text, and the attachments sent with it. */
626
+ interface HistoryEntry {
627
+ text: string;
628
+ attachments?: Attachment[];
629
+ }
630
+ /**
631
+ * Input history with a draft: browsing up from a fresh draft keeps it, so
632
+ * coming back down restores what was being typed (with its attachments).
633
+ */
634
+ interface History {
635
+ entries: HistoryEntry[];
636
+ /** Index into `entries` while browsing; `entries.length` means the draft. */
637
+ index: number;
638
+ draft: HistoryEntry;
639
+ }
640
+ declare function createHistory(entries?: Array<string | HistoryEntry>): History;
641
+ declare function pushHistory(history: History, entry: string | HistoryEntry): History;
642
+ /**
643
+ * Replace the entries (the host's list changed), keeping the draft and a
644
+ * browse in progress (clamped to the new list).
645
+ */
646
+ declare function withEntries(history: History, entries: Array<string | HistoryEntry>): History;
647
+ /** Step through history; returns the new history and the entry to show, or undefined at an end. */
648
+ declare function stepHistory(history: History, direction: -1 | 1, current: string | HistoryEntry): {
649
+ history: History;
650
+ value: string;
651
+ attachments?: Attachment[];
652
+ } | undefined;
653
+
654
+ //#endregion
655
+ //#region src/sanitize.d.ts
656
+ /**
657
+ * Content must never drive the terminal. Model output, tool output, titles
658
+ * and other host- or model-provided strings may carry escape sequences (an
659
+ * OSC 52 clipboard write, an OSC 8 link, SGR colours, cursor moves) that Ink
660
+ * would pass straight through. Everything this package draws is cleaned
661
+ * here first; its own styling travels as Ink props, never as escapes in text.
662
+ *
663
+ * Removed: whole ESC/C1 sequences — CSI, OSC, DCS, SOS, PM, APC (a string
664
+ * command up to its terminator: BEL, `ESC \` or ST), and any other ESC
665
+ * sequence — then every remaining C0 control but `\n` and `\t` (so `\r` and
666
+ * BEL go), DEL, and the C1 controls U+0080–U+009F. An unterminated string
667
+ * command loses its introducer only: the rest is plain text once no control
668
+ * can read it, and the scan stays linear.
669
+ */
670
+ /** `text` without terminal control sequences or control characters (bar `\n` and `\t`). */
671
+ declare function stripControls(text: string): string;
672
+ /**
673
+ * `value` with `stripControls` applied to every string in it (object keys
674
+ * included), through arrays and plain objects; other objects (Map, Set,
675
+ * Date, class instances) pass through as they are. Anything unchanged keeps
676
+ * its identity, so clean content costs a scan and no copies. Keys that clean
677
+ * to the same name all survive (see `cleanKeys`); a `__proto__` key stays an
678
+ * own property, never a prototype; a cycle is left as it is where it closes.
679
+ */
680
+ declare function stripControlsDeep<T>(value: T): T;
681
+
682
+ //#endregion
683
+ //#region src/terminal.d.ts
684
+ /**
685
+ * Terminal protocol helpers shared by the composer and the viewport.
686
+ */
687
+ /** Mouse reports and terminal replies arrive as input; key handlers ignore them. */
688
+ declare function isTerminalReport(input: string): boolean;
689
+ /** Kitty keyboard protocol: push the disambiguate flag (Shift+Enter is then reported). */
690
+ declare const KITTY_PUSH: string;
691
+ /** Kitty keyboard protocol: pop the flags pushed last. */
692
+ declare const KITTY_POP: string;
693
+
694
+ //#endregion
695
+ //#region src/lines/frames.d.ts
696
+ /**
697
+ * Compact: a role glyph before the first row (`›` user, `•` answer), rows
698
+ * indented under it, a dim footer line, a blank line after each message.
699
+ */
700
+ declare const compactFrame: MessageFrame;
701
+ /**
702
+ * Threaded: the user's message in a round-cornered box with its time set into
703
+ * the top edge; an answer hangs from the box on a gutter in its accent and
704
+ * ends with a footer corner (bare when the answer has no footer facts). A live answer that shows nothing yet draws
705
+ * nothing.
706
+ */
707
+ declare const threadedFrame: MessageFrame;
708
+
709
+ //#endregion
710
+ //#region src/lines/transcript.d.ts
711
+ /** Memoised `layoutMessage`, keyed by message identity plus a signature. */
712
+ interface LayoutCache {
713
+ get(message: RenderableMessage, ctx: LayoutContext, next?: RenderableMessage): Line[];
714
+ /** Layouts computed (not served from the cache) — for tests and diagnostics. */
715
+ readonly misses: number;
716
+ }
717
+ /**
718
+ * Everything a message's layout reads, as a string. Plain values (hint labels,
719
+ * the resolved accent, host footer facts) count by value; injected functions
720
+ * and the glyph set count by identity, so hosts memoise them.
721
+ */
722
+ declare function layoutSignature(message: RenderableMessage, ctx: LayoutContext, next?: RenderableMessage, imagesVersion?: number): string;
723
+ declare function createLayoutCache(imagesVersion?: () => number): LayoutCache;
724
+ /** Lay out a transcript: all lines, and where each message starts. */
725
+ declare function layoutTranscript(messages: readonly RenderableMessage[], ctx: LayoutContext, cache?: LayoutCache): {
726
+ lines: Line[];
727
+ messageStart: number[];
728
+ };
729
+
730
+ //#endregion
731
+ //#region src/lines/markdown/blocks.d.ts
732
+ interface MarkdownEnv {
733
+ measure: Measure;
734
+ glyphs: InkGlyphs;
735
+ streaming?: boolean | undefined;
736
+ image?: ((src: string, alt: string, width: number) => LineDraft[] | undefined) | undefined;
737
+ }
738
+ /** Lay out markdown source lines as blocks; `tight` drops the blank lines between blocks. */
739
+ declare function layoutBlocks(lines: readonly string[], width: number, env: MarkdownEnv, tight?: boolean): LineDraft[];
740
+ /**
741
+ * Split source lines into top-level chunks at blank lines that end a block:
742
+ * never inside a fence, and not where an indented line or a list item
743
+ * continues the block before. Chunks lay out independently.
744
+ */
745
+ declare function chunks(lines: readonly string[]): string[][];
746
+ /**
747
+ * The default terminal markdown: dependency-free, injected roles and glyphs.
748
+ * Finished blocks are cached, so a streamed delta lays out only the tail.
749
+ */
750
+ declare const terminalMarkdown: MarkdownLayout;
751
+
752
+ //#endregion
753
+ //#region src/lines/markdown/inline.d.ts
754
+ /** The attributes inline markup sets on a span. */
755
+ type InlineStyle = Omit<Span, 'text'>;
756
+ /** Show a source the way a reader can use it: a `data:` URL as its type. */
757
+ declare function describeSource(src: string): string;
758
+ /** Merge adjacent spans with identical attributes. */
759
+ declare function mergeSpans(spans: readonly Span[]): Span[];
760
+ /** Parse inline markdown into spans, every span starting from `base`. */
761
+ declare function parseInline(text: string, base: InlineStyle, glyphs: InkGlyphs): Span[];
762
+
763
+ //#endregion
764
+ //#region src/lines/markdown/table.d.ts
765
+ type Align = 'left' | 'center' | 'right';
766
+ /** The narrowest a wrapped column may get before the table falls back. */
767
+ declare const MIN_COLUMN = 6;
768
+ /** Whether `line` is a GFM table separator row. */
769
+ declare function isSeparator(line: string): boolean;
770
+ /** Split a row into cells on pipes that are neither escaped nor inside a code span. */
771
+ declare function splitRow(line: string): string[];
772
+ /** Column alignments from a separator row. */
773
+ declare function alignments(line: string): Align[];
774
+ /**
775
+ * Fit natural widths into `available` cells: columns within a fair share keep
776
+ * theirs, the rest share what remains. Undefined when a column would fall
777
+ * below its minimum (the minimums together exceed the available cells).
778
+ */
779
+ declare function fitColumns(natural: readonly number[], available: number): number[] | undefined;
780
+ interface TableEnv {
781
+ glyphs: InkGlyphs;
782
+ measure: Measure;
783
+ }
784
+ /** Lay out a table from its header, separator and body source rows. */
785
+ declare function layoutTable(header: string, separator: string, body: readonly string[], maxWidth: number, { glyphs, measure }: TableEnv): LineDraft[];
786
+
787
+ //#endregion
788
+ //#region src/lines/markdown/wrap.d.ts
789
+ interface SpanRow {
790
+ spans: Span[];
791
+ wrap?: 'soft' | 'hard';
792
+ }
793
+ declare function wrapSpans(spans: readonly Span[], width: number, measure: Measure): SpanRow[];
794
+
795
+ //#endregion
796
+ //#region src/lines/Markdown.d.ts
797
+ interface TerminalMarkdownProps extends InkMarkdownProps {
798
+ /** Lay out to this many cells instead of the measured box width. */
799
+ width?: number;
800
+ /** Cell measurement (default: the one Ink lays out by). */
801
+ measure?: Measure;
802
+ }
803
+ declare function TerminalMarkdown({ content, streaming, width, measure, }: TerminalMarkdownProps): JSX.Element;
804
+
805
+ //#endregion
806
+ export { Align, BlockLayoutContext, CellBox, ChatInk, ChatInkDeps, ClockProvider, Composer, ComposerHandle, ComposerProps, ComposerValue, EditorState, EmptyState, EmptyStateProps, FooterHints, FrameInput, Geometry, History, HistoryEntry, ImageLayoutOptions, ImageProvider, ImageState, InkApi, InkAppearance, InkBlockRendererProps, InkChatProvider, InkComponents, InkExtensions, InkGlyphs, InkMarkdownProps, InkTheme, InkThemeRole, InlineStyle, KITTY_POP, KITTY_PUSH, LayoutCache, LayoutContext, Line, LineDraft, LineTarget, Lines, LinesProps, MIN_COLUMN, MOUSE_OFF, MOUSE_ON, MarkdownEnv, MarkdownLayout, Measure, MessageFrame, MessageView, MessageViewProps, MouseEvent, NOTHING_OPEN, OpenState, PartialInkComponents, PendingItem, PendingRows, PendingRowsProps, PlainMarkdown, Point, ROW_PATH, React, ReactApi, Row, RowProps, Scroll, Span, SpanRow, Spinner, StatusLine, StatusLineProps, Styled, THUMBNAIL, TableEnv, TerminalMarkdown, TerminalMarkdownProps, Transcript, TranscriptProps, TranscriptViewport, TranscriptViewportProps, ViewportKeys, ViewportMouse, VisualRow, WrappedRow, alignments, appearanceProps, asciiGlyphs, backspace, cachedMeasure, caretBoundary, caretLines, caretRow, chunks, clipLines, compactFrame, composerInnerWidth, composerRows, copyText, createChatInk, createHistory, createLayoutCache, createReportReader, defaultMeasure, deleteForward, deleteWordBack, describeSource, emojiGlyphs, emptyComposerValue, emptyEditor, firstLine, fitColumns, footerSpans, graphemes, hardSplit, highlightLine, hooks, ink, insert, isBound, isSeparator, isTerminalReport, killToLineEnd, killToLineStart, layoutBlocks, layoutBody, layoutImage, layoutMessage, layoutSignature, layoutTable, layoutTranscript, lineEnd, lineStart, lineText, mergeInkComponents, mergeSpans, moveBy, moveLine, moveVisual, ordered, osc52, pageBy, parseInline, parseMouse, plainComponents, plainGlyphs, plainMarkdownLayout, plainTheme, prefix, pushHistory, resolveAccent, screenOrigin, scrollBy, scrollEnd, scrollHome, showsSomething, span, spanProps, splitAtCaret, splitRow, splitRuns, stepHistory, stripControls, stripControlsDeep, suffix, terminalMarkdown, threadedFrame, toJson, truncate, useInkComponents, useMouseReporting, useOpenState, useTerminalData, useTranscriptLayout, viewportKeyAction, visualRows, withEntries, wordLeft, wordRight, wrapLines, wrapSpans, wrapText };