@24klynx/tui 0.1.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,1309 @@
1
+ import React, { ReactNode } from "react";
2
+ import { Key } from "ink";
3
+ import { Message, Session } from "@lynx/core";
4
+
5
+ //#region src/components/PermissionRequest.d.ts
6
+ /** Safety level determines badge color and severity. */
7
+ type SafetyLevel = "Safe" | "WorkspaceSafe" | "RequiresApproval" | "Dangerous";
8
+ /** Information about a pending permission request. */
9
+ interface PermissionRequestData {
10
+ /** Unique request identifier. */
11
+ requestId: string;
12
+ /** Name of the tool being invoked. */
13
+ toolName: string;
14
+ /** Safety level of the tool. */
15
+ safety: SafetyLevel;
16
+ /** Human‑readable description of what the tool will do. */
17
+ description: string;
18
+ /** Optional parameter summary for display. */
19
+ parameters?: Record<string, unknown>;
20
+ }
21
+ /** Callback when the user makes a decision. */
22
+ type PermissionChoice = "allow" | "deny" | "always_allow";
23
+ type PermissionCallback = (requestId: string, choice: PermissionChoice) => void;
24
+ /** Props for the PermissionRequest modal. */
25
+ interface PermissionRequestProps {
26
+ request: PermissionRequestData;
27
+ onDecide: PermissionCallback;
28
+ onCancel: () => void;
29
+ }
30
+ /**
31
+ * Permission request dialog.
32
+ *
33
+ * Users navigate with A/D/L keys and can press Escape to cancel.
34
+ * After AUTO_DENY_MS, the dialog auto‑denies.
35
+ */
36
+ declare function PermissionRequest({
37
+ request,
38
+ onDecide,
39
+ onCancel
40
+ }: PermissionRequestProps): React.ReactElement;
41
+ //#endregion
42
+ //#region src/types.d.ts
43
+ /** Model descriptor for the model picker. Mirrors @lynx/llm's ModelInfo. */
44
+ interface TuiModelInfo {
45
+ /** Provider‑unique model identifier. */
46
+ id: string;
47
+ /** Human‑readable label. */
48
+ label: string;
49
+ /** Maximum context window in tokens. */
50
+ contextWindow: number;
51
+ /** Maximum output tokens. */
52
+ maxOutput: number;
53
+ /** Approximate USD per 1M input tokens. */
54
+ inputPrice?: number;
55
+ /** Approximate USD per 1M output tokens. */
56
+ outputPrice?: number;
57
+ }
58
+ interface TuiCallbacks {
59
+ /** User submitted a message. Returns the assistant response stream. */
60
+ onInput(message: string): AsyncGenerator<TuiStreamEvent, void, void>;
61
+ /** User requested session switch. */
62
+ onSessionPick(sessionId: string): void;
63
+ /** User requested a permission action. */
64
+ onPermissionReply(requestId: string, approved: boolean): void;
65
+ /** User triggered abort (first Ctrl+C). */
66
+ onAbort(): void;
67
+ /** User selected a model. */
68
+ onModelPick?(modelId: string): void;
69
+ /** User toggled a config setting. */
70
+ onConfigChange?(key: string, value: unknown): void;
71
+ /** User selected a theme. */
72
+ onThemeChange?(themeName: string): void;
73
+ /** Budget update after each turn — token count and estimated cost. */
74
+ onBudgetUpdate?: (tokensUsed: number, costUsd: number, maxUsd: number) => void;
75
+ /** Connect to an MCP server by name. */
76
+ onMcpConnect?(serverName: string): void;
77
+ /** Disconnect from an MCP server by name. */
78
+ onMcpDisconnect?(serverName: string): void;
79
+ /** Reconnect a failed MCP server by name. */
80
+ onMcpReconnect?(serverName: string): void;
81
+ /** Called when user wants to add an MCP server via the panel. */
82
+ onMcpAddServer?: (serverConfig: {
83
+ name: string;
84
+ transport: string;
85
+ url?: string;
86
+ command?: string;
87
+ args?: string[];
88
+ }) => void;
89
+ /** Called when user wants to remove an MCP server. */
90
+ onMcpRemoveServer?: (serverName: string) => void;
91
+ /** Load a plugin by name. */
92
+ onPluginLoad?(pluginName: string): void;
93
+ /** Unload a plugin by name. */
94
+ onPluginUnload?(pluginName: string): void;
95
+ /** Create a new session with the given label. */
96
+ onSessionCreate?(label: string): void;
97
+ /** Fork the current session with the given label. */
98
+ onSessionFork?(newLabel: string): void;
99
+ /** Rename the current session. */
100
+ onSessionRename?(newLabel: string): void;
101
+ /** Delete a session by ID. */
102
+ onSessionDelete?(sessionId: string): void;
103
+ /** Resume a session by ID (switch active session). */
104
+ onSessionResume?(sessionId: string): void;
105
+ /** Compact the current session's conversation context. */
106
+ onSessionCompact?(): void;
107
+ /** Request diff output for git changes. */
108
+ onRequestDiff?(): Promise<Array<{
109
+ path: string;
110
+ status: string;
111
+ diff: string;
112
+ }>>;
113
+ /** Request snapshot list. */
114
+ onRequestSnapshots?(): Promise<Array<{
115
+ id: string;
116
+ timestamp: number;
117
+ label: string;
118
+ }>>;
119
+ /** Request background task list. */
120
+ onRequestTasks?(): Promise<Array<{
121
+ id: string;
122
+ name: string;
123
+ status: "running" | "queued" | "done" | "failed";
124
+ error?: string;
125
+ }>>;
126
+ /** Open external editor for the current input, returns edited text or null if cancelled. */
127
+ onOpenExternalEditor?(currentText: string): Promise<string | null>;
128
+ }
129
+ /** Stream event from the agent engine, simplified for TUI rendering. */
130
+ type TuiStreamEvent = {
131
+ type: "text_delta";
132
+ text: string;
133
+ } | {
134
+ type: "tool_use";
135
+ name: string;
136
+ callId: string;
137
+ } | {
138
+ type: "tool_result";
139
+ callId: string;
140
+ content: string;
141
+ } | {
142
+ type: "reasoning_status";
143
+ status: "started" | "ended";
144
+ durationMs?: number;
145
+ text?: string;
146
+ } | {
147
+ type: "tool_recap";
148
+ summary: string;
149
+ toolCount: number;
150
+ durationMs: number;
151
+ } | {
152
+ type: "error";
153
+ message: string;
154
+ } | {
155
+ type: "done";
156
+ totalTokens?: number;
157
+ costUsd?: number;
158
+ };
159
+ type ViewId = "chat" | "sessions" | "help" | "permission" | "settings" | "commands" | "model" | "theme" | "confirm" | "input_prompt" | "doctor" | "file_picker" | "stash" | "mcp" | "plugin" | "skills" | "context" | "usage" | "diff" | "snapshots" | "tasks" | "skill_pick";
160
+ interface ViewEntry {
161
+ id: ViewId;
162
+ props?: Record<string, unknown>;
163
+ }
164
+ interface ViewStack {
165
+ push(view: ViewEntry): void;
166
+ pop(): ViewEntry | undefined;
167
+ replace(view: ViewEntry): void;
168
+ top(): ViewEntry | undefined;
169
+ toArray(): ViewEntry[];
170
+ }
171
+ type ThemeName = "dark" | "light" | "catppuccin" | "monokai" | "solarized" | "dracula";
172
+ interface TuiTheme {
173
+ name: ThemeName;
174
+ /** Semantic color tokens — 60+ available, grouped by purpose. */
175
+ colors: Record<string, string>;
176
+ }
177
+ /** Status of an MCP server connection. */
178
+ type McpConnectionStatus = "disconnected" | "connecting" | "connected" | "error";
179
+ /** MCP server connection info displayed in the /mcp panel. */
180
+ interface McpConnectionInfo {
181
+ /** Server name (unique key). */
182
+ name: string;
183
+ /** Connection status. */
184
+ status: McpConnectionStatus;
185
+ /** Number of tools exported by this server. */
186
+ toolCount: number;
187
+ /** Human-readable status or error detail. */
188
+ detail: string;
189
+ /** Transport type: "stdio" | "sse" | "ws" | "inproc". */
190
+ transport?: string;
191
+ /** Authentication status for OAuth/XAA-enabled servers. */
192
+ authStatus?: "none" | "authenticated" | "expired";
193
+ /** Number of resources exported by this server. */
194
+ resourceCount?: number;
195
+ /** Tools exported by this server (for detail view). */
196
+ tools?: Array<{
197
+ name: string;
198
+ description: string;
199
+ }>;
200
+ /** Resources exported by this server (for detail view). */
201
+ resources?: Array<{
202
+ name: string;
203
+ uri: string;
204
+ }>;
205
+ }
206
+ /** Plugin descriptor displayed in the /plugin panel. */
207
+ interface PluginInfo {
208
+ /** Plugin name (unique key). */
209
+ name: string;
210
+ /** Installed version. */
211
+ version: string;
212
+ /** Short description of what the plugin does. */
213
+ description: string;
214
+ /** Whether the plugin is currently loaded. */
215
+ loaded: boolean;
216
+ }
217
+ /** Skill descriptor displayed in the /skills panel. */
218
+ interface SkillInfo {
219
+ /** Skill name (unique key). */
220
+ name: string;
221
+ /** Short description of what the skill does. */
222
+ description: string;
223
+ /** Source origin: builtin / user / project. */
224
+ source: "builtin" | "user" | "project";
225
+ }
226
+ /** Context information displayed in the /context panel. */
227
+ interface ContextInfo {
228
+ /** Number of facts loaded from memory. */
229
+ memoryFacts: number;
230
+ /** Number of rules loaded from ~/.lynx/rules/ and workspace .claude/rules/. */
231
+ rules: number;
232
+ /** Number of skills discovered from all sources. */
233
+ skills: number;
234
+ /** Currently active model ID. */
235
+ model: string;
236
+ /** Workspace directory path. */
237
+ workspace: string;
238
+ /** Active session label. */
239
+ sessionLabel: string;
240
+ }
241
+ /** Usage information displayed in the /usage panel. */
242
+ interface UsageInfo {
243
+ /** Total tokens used in the current session. */
244
+ tokensUsed: number;
245
+ /** Estimated cost in USD. */
246
+ costUsd: number;
247
+ /** Soft budget limit in tokens, or 0 if unlimited. */
248
+ budgetMaxTokens: number;
249
+ /** Hard budget limit in USD, or 0 if unlimited. */
250
+ budgetMaxUsd: number;
251
+ /** Number of turns executed so far. */
252
+ turns: number;
253
+ /** Per-model pricing info in the format "model: $N/M input · $N/M output". */
254
+ modelPricing: string;
255
+ }
256
+ interface AppProps {
257
+ /** Callbacks wired by the CLI bootstrap layer. */
258
+ callbacks: TuiCallbacks;
259
+ /** Current session (null when no session is active). */
260
+ session: Session | null;
261
+ /** All sessions for the session picker. */
262
+ sessions: Session[];
263
+ /** Available models for the model picker. */
264
+ models?: TuiModelInfo[];
265
+ /** Currently active model ID. */
266
+ currentModel?: string;
267
+ /** Whether to show the safety confirmation screen before the REPL. Default: true. */
268
+ showWelcome?: boolean;
269
+ /** Terminal dimensions at startup. */
270
+ columns: number;
271
+ rows: number;
272
+ /**
273
+ * Called by the TUI on mount to register the permission dialog trigger.
274
+ * The handler receives permission request data and should show the
275
+ * PermissionRequest modal. Pass `null` to unregister on unmount.
276
+ */
277
+ onPermissionReady?: (handler: ((req: {
278
+ requestId: string;
279
+ toolName: string;
280
+ description: string;
281
+ safety: SafetyLevel;
282
+ }) => void) | null) => void;
283
+ /** MCP server connections for the /mcp panel. */
284
+ mcpConnections?: McpConnectionInfo[];
285
+ /** Installed plugins for the /plugin panel. */
286
+ plugins?: PluginInfo[];
287
+ /** Discovered skills for the /skills panel. */
288
+ skills?: SkillInfo[];
289
+ /** Context summary for the /context panel. */
290
+ contextInfo?: ContextInfo;
291
+ /** Usage statistics for the /usage panel. */
292
+ usageInfo?: UsageInfo;
293
+ }
294
+ //#endregion
295
+ //#region src/app.d.ts
296
+ /** Main application component rendered by Ink. */
297
+ declare function App(props: AppProps): React.ReactElement;
298
+ //#endregion
299
+ //#region src/components/ChatView.d.ts
300
+ interface ChatViewProps {
301
+ messages: Message[];
302
+ streaming: boolean;
303
+ }
304
+ declare function ChatView({
305
+ messages,
306
+ streaming
307
+ }: ChatViewProps): React.ReactElement;
308
+ //#endregion
309
+ //#region src/components/ChatLog.d.ts
310
+ /** A single entry in the chat transcript. */
311
+ interface ChatLogEntry {
312
+ readonly id: string;
313
+ readonly kind: "system" | "user" | "assistant" | "tool_use" | "tool_result" | "btw" | "thinking";
314
+ readonly text: string;
315
+ readonly streaming?: boolean;
316
+ readonly pending?: boolean;
317
+ readonly toolName?: string;
318
+ readonly toolCallId?: string;
319
+ readonly toolStartedAt?: number;
320
+ readonly level?: "info" | "warn" | "error";
321
+ /** Duration in ms for thinking entries (shown as "已思考 X.Xs"). */
322
+ readonly durationMs?: number;
323
+ readonly timestamp: number;
324
+ }
325
+ /** Imperative handle exposed to the parent (agent loop / App). */
326
+ interface ChatLogHandle {
327
+ /** Append a system message (info, warning, or error). */
328
+ addSystem(text: string, level?: "info" | "warn" | "error"): void;
329
+ /** Append a user message, optionally marked as pending (optimistic). */
330
+ addUser(text: string, pending?: boolean): void;
331
+ /** Remove the pending marker from the most recent user message. */
332
+ commitPendingUser(): void;
333
+ /** Remove the pending user message entirely. */
334
+ dropPendingUser(): void;
335
+ /** Create (or update) a streaming assistant message. */
336
+ startAssistant(text?: string): void;
337
+ /** Incrementally update the streaming assistant's text. */
338
+ updateAssistant(text: string): void;
339
+ /** Finalize the streaming assistant message — sets streaming=false. */
340
+ finalizeAssistant(text?: string): void;
341
+ /** Remove the streaming assistant message (on error / abort). */
342
+ dropAssistant(): void;
343
+ /** Append a tool‑use entry. */
344
+ addTool(name: string, callId: string): void;
345
+ /** Update the result of a previously added tool‑use entry. */
346
+ updateToolResult(callId: string, result: string): void;
347
+ /** Show a by‑the‑way hint (non‑conversational guidance). */
348
+ showBtw(text: string): void;
349
+ /** Remove the btw message. */
350
+ dismissBtw(): void;
351
+ /** Show a collapsible thinking entry with duration. Default collapsed, Enter toggles. */
352
+ showThinking(text: string, durationMs: number): void;
353
+ /** Remove the thinking message. */
354
+ dismissThinking(): void;
355
+ /** Clear the entire transcript. */
356
+ clearAll(): void;
357
+ /** Return the total number of entries (for scroll calculation). */
358
+ getEntryCount(): number;
359
+ }
360
+ /** Props passed to the ChatLog component. */
361
+ interface ChatLogProps {
362
+ readonly visibleRange?: {
363
+ readonly start: number;
364
+ readonly end: number;
365
+ };
366
+ /** Called when search mode is toggled (so parent can disable InputBox). */
367
+ readonly onSearchActiveChange?: (active: boolean) => void;
368
+ /** Transcript display mode: compact hides timestamps, full shows them + expanded content. */
369
+ readonly transcriptMode?: "compact" | "full";
370
+ }
371
+ /** ChatLog component — renders the message transcript driven by a handle. */
372
+ declare const ChatLog: React.ForwardRefExoticComponent<ChatLogProps & React.RefAttributes<ChatLogHandle>>;
373
+ //#endregion
374
+ //#region src/components/InputBox.d.ts
375
+ /** Vim editing mode. */
376
+ type VimMode = "insert" | "normal" | "visual";
377
+ interface InputBoxProps {
378
+ /** Called when the user submits text. */
379
+ onSubmit: (text: string) => void;
380
+ /** Called on each Ctrl+C press (parent tracks abort count). */
381
+ onAbort: () => void;
382
+ /** Whether input is disabled (e.g. during streaming). */
383
+ disabled: boolean;
384
+ /** Placeholder text shown when input is empty. */
385
+ placeholder?: string;
386
+ /** Called when the user presses Ctrl+S to stash the current input. */
387
+ onStash?: (text: string) => void;
388
+ /** Text to append at cursor position (from FilePicker, @-mention, etc.). */
389
+ appendText?: string;
390
+ /** Called after appendText has been consumed. */
391
+ onAppendTextConsumed?: () => void;
392
+ /** Workspace directory for @‑mention file autocomplete. */
393
+ workspace?: string;
394
+ /** Enable vim‑style editing modes (INSERT/NORMAL/VISUAL). */
395
+ vimMode?: boolean;
396
+ /** Called when vim mode changes (for status display). */
397
+ onVimModeChange?: (mode: VimMode) => void;
398
+ }
399
+ declare function InputBox({
400
+ onSubmit,
401
+ onAbort,
402
+ disabled,
403
+ placeholder,
404
+ onStash,
405
+ appendText,
406
+ onAppendTextConsumed,
407
+ workspace,
408
+ vimMode: vimEnabled,
409
+ onVimModeChange
410
+ }: InputBoxProps): React.ReactElement;
411
+ //#endregion
412
+ //#region src/components/StatusBar.d.ts
413
+ interface StatusBarProps {
414
+ mode: string;
415
+ model: string;
416
+ streaming: boolean;
417
+ viewName: string;
418
+ /** Total tokens consumed in the current session. */
419
+ tokensUsed?: number;
420
+ /** Estimated cost in USD for the current session. */
421
+ costUsd?: number;
422
+ /** Budget maximum USD for color coding. */
423
+ budgetMaxUsd?: number;
424
+ }
425
+ declare function StatusBar({
426
+ mode,
427
+ model,
428
+ streaming,
429
+ viewName,
430
+ tokensUsed,
431
+ costUsd,
432
+ budgetMaxUsd
433
+ }: StatusBarProps): React.ReactElement;
434
+ //#endregion
435
+ //#region src/components/Dialog.d.ts
436
+ /** Props for the Dialog shell component. */
437
+ interface DialogProps {
438
+ /** Modal title shown in the top border. */
439
+ title: string;
440
+ /** Optional accent color for title and border (theme color key). */
441
+ accentColor?: string;
442
+ /** Optional subtitle shown below the title. */
443
+ subtitle?: string;
444
+ /** Bottom hint text (e.g. "Enter to confirm · Esc to cancel"). */
445
+ inputGuide?: string;
446
+ /** Width of the dialog in characters. Default: 60. */
447
+ width?: number;
448
+ /** Children rendered as the dialog body. */
449
+ children?: React.ReactNode;
450
+ }
451
+ /**
452
+ * Unified dialog wrapper for modals, pickers, and confirmations.
453
+ *
454
+ * All modals in the TUI use this component to ensure visual consistency.
455
+ * The dialog renders as an absolutely positioned overlay with a
456
+ * double‑border style.
457
+ */
458
+ declare function Dialog({
459
+ title,
460
+ accentColor,
461
+ subtitle,
462
+ inputGuide,
463
+ width,
464
+ children
465
+ }: DialogProps): React.ReactElement;
466
+ //#endregion
467
+ //#region src/components/SessionPicker.d.ts
468
+ /** Props for the SessionPicker modal. */
469
+ interface SessionPickerProps {
470
+ /** All available sessions. */
471
+ sessions: Session[];
472
+ /** Called when the user selects a session (Enter key). */
473
+ onSelect(sessionId: string): void;
474
+ /** Called when the user dismisses the picker (Escape key). */
475
+ onCancel(): void;
476
+ }
477
+ /**
478
+ * Session picker modal.
479
+ *
480
+ * Filters sessions by label substring, displays them in a scrollable
481
+ * list, and handles selection via Enter key.
482
+ */
483
+ declare function SessionPicker({
484
+ sessions: allSessions,
485
+ onSelect,
486
+ onCancel
487
+ }: SessionPickerProps): React.ReactElement;
488
+ //#endregion
489
+ //#region src/components/HelpModal.d.ts
490
+ /** Props for the HelpModal. */
491
+ interface HelpModalProps {
492
+ onCancel(): void;
493
+ }
494
+ /**
495
+ * Help modal displaying keyboard shortcuts.
496
+ *
497
+ * Categorized display with search filtering.
498
+ */
499
+ declare function HelpModal({
500
+ onCancel
501
+ }: HelpModalProps): React.ReactElement;
502
+ //#endregion
503
+ //#region src/components/CommandPalette.d.ts
504
+ /** A single command entry in the palette. */
505
+ interface CommandEntry {
506
+ name: string;
507
+ description: string;
508
+ }
509
+ /** Props for the CommandPalette. */
510
+ interface CommandPaletteProps {
511
+ /** Called when the user selects a command (Enter key). */
512
+ onSelect(command: string): void;
513
+ /** Called when the user dismisses (Escape key). */
514
+ onCancel(): void;
515
+ /** Additional commands from plugins/extensions. */
516
+ extraCommands?: CommandEntry[];
517
+ }
518
+ /**
519
+ * Command palette modal.
520
+ *
521
+ * Fuzzy‑filters the command list as the user types and supports
522
+ * arrow‑key navigation with Enter to execute.
523
+ */
524
+ declare function CommandPalette({
525
+ onSelect,
526
+ onCancel,
527
+ extraCommands
528
+ }: CommandPaletteProps): React.ReactElement;
529
+ //#endregion
530
+ //#region src/components/ToolRenderer.d.ts
531
+ /** Props passed to the ToolRenderer. */
532
+ interface ToolRendererProps {
533
+ /** Name of the tool being rendered. */
534
+ toolName: string;
535
+ /** Whether this is the tool call (header) or the result. */
536
+ phase: "call" | "result";
537
+ /** Content to display (command, file path, result text). */
538
+ content: string;
539
+ }
540
+ /**
541
+ * ToolRenderer component.
542
+ *
543
+ * Renders tool invocations and results with appropriate icons and colors.
544
+ * Different tool categories get different visual treatments.
545
+ */
546
+ declare function ToolRenderer({
547
+ toolName,
548
+ phase,
549
+ content
550
+ }: ToolRendererProps): React.ReactElement;
551
+ //#endregion
552
+ //#region src/components/Mascot.d.ts
553
+ /** The five mascot states. */
554
+ type MascotState = "idle" | "listen" | "think" | "speak" | "error";
555
+ /** Props for the Mascot component. */
556
+ interface MascotProps {
557
+ /** Current mascot state. */
558
+ state: MascotState;
559
+ /** Whether animation is enabled (respects reduce‑motion preference). */
560
+ animate?: boolean;
561
+ }
562
+ /**
563
+ * Animated mascot character.
564
+ *
565
+ * Renders a single emoji that changes based on the current state.
566
+ * Animation is frame‑based with configurable intervals per state.
567
+ */
568
+ declare function Mascot({
569
+ state,
570
+ animate
571
+ }: MascotProps): React.ReactElement;
572
+ //#endregion
573
+ //#region src/hooks/useTerminalSize.d.ts
574
+ /**
575
+ * useTerminalSize — track stdout dimensions via Ink's useStdout hook.
576
+ *
577
+ * Returns { columns, rows } and updates on terminal resize events.
578
+ */
579
+ interface TerminalSize {
580
+ columns: number;
581
+ rows: number;
582
+ }
583
+ /**
584
+ * Hook that returns the current terminal dimensions.
585
+ * Updates when the terminal is resized.
586
+ */
587
+ declare function useTerminalSize(): TerminalSize;
588
+ //#endregion
589
+ //#region src/hooks/useInput.d.ts
590
+ interface InputState {
591
+ /** Current text in the input box. */
592
+ value: string;
593
+ /** Cursor position within the value. */
594
+ cursor: number;
595
+ /** Whether the input is currently focused. */
596
+ focused: boolean;
597
+ }
598
+ interface InputActions {
599
+ /** Set the full value. */
600
+ setValue: (value: string) => void;
601
+ /** Clear the input. */
602
+ clear: () => void;
603
+ /** Focus the input. */
604
+ focus: () => void;
605
+ /** Blur the input. */
606
+ blur: () => void;
607
+ /** Submit the current value. Returns the submitted text. */
608
+ submit: () => string;
609
+ /** Insert text at cursor position. */
610
+ insert: (text: string) => void;
611
+ }
612
+ /**
613
+ * Controlled input hook for the main REPL input area.
614
+ *
615
+ * @param onSubmit Called when the user presses Enter with non‑empty input.
616
+ * @param onKey Optional handler for non‑Enter key presses (slash menu, shortcuts, etc.).
617
+ */
618
+ declare function useInput(onSubmit: (text: string) => void, onKey?: (input: string, key: Key) => void): [InputState, InputActions];
619
+ //#endregion
620
+ //#region src/hooks/useScroll.d.ts
621
+ /** Scroll state returned by useScroll. */
622
+ interface ScrollState {
623
+ /** Start index of the visible message range. */
624
+ visibleStart: number;
625
+ /** End index (exclusive) of the visible message range. */
626
+ visibleEnd: number;
627
+ /** Whether the view is auto‑following new messages. */
628
+ stickyScroll: boolean;
629
+ /** How many new messages are below the current viewport (for pill display). */
630
+ unseenCount: number;
631
+ /** Call to jump back to the bottom (resumes auto‑scroll). */
632
+ jumpToBottom(): void;
633
+ /** Handle keyboard input for scroll navigation. */
634
+ handleKey(input: string, key: Key): boolean;
635
+ /** Scroll up by one line (for mouse wheel). */
636
+ scrollUp(): void;
637
+ /** Scroll down by one line (for mouse wheel). */
638
+ scrollDown(): void;
639
+ /** Update the total entry count (call from a ref or interval). */
640
+ setTotalEntries(count: number): void;
641
+ }
642
+ /** Options for useScroll. */
643
+ interface UseScrollOptions {
644
+ /** Number of visible rows in the chat area (from terminal size). */
645
+ visibleRows: number;
646
+ }
647
+ /**
648
+ * React hook that manages scrolling behaviour for the ChatLog.
649
+ *
650
+ * Call `setTotalEntries(getEntryCount())` periodically to keep
651
+ * the hook in sync with the ChatLog's entry list.
652
+ */
653
+ declare function useScroll({
654
+ visibleRows
655
+ }: UseScrollOptions): ScrollState;
656
+ //#endregion
657
+ //#region src/theme/theme.d.ts
658
+ /** Initialize the theme system. Call once at startup. */
659
+ declare function initTheme(): void;
660
+ /** Get the current theme. */
661
+ declare function getTheme(): TuiTheme;
662
+ /** Switch to a different theme. */
663
+ declare function setTheme(name: ThemeName): void;
664
+ /** Get a specific color from the current theme. */
665
+ declare function color(name: string): string;
666
+ /** List all available theme names. */
667
+ declare function listThemes(): ThemeName[];
668
+ //#endregion
669
+ //#region src/renderer/markdown.d.ts
670
+ interface MarkdownBlock {
671
+ type: "paragraph" | "heading" | "code" | "list_item" | "blockquote" | "hr" | "diff" | "table";
672
+ /** Heading level (1–6), only for heading blocks. */
673
+ level?: number;
674
+ /** Source text for this block. */
675
+ text: string;
676
+ /** Language tag for fenced code blocks. */
677
+ language?: string;
678
+ /** For ordered list items, the number. */
679
+ listNumber?: number;
680
+ /** For diff blocks, the diff line type. */
681
+ diffLineType?: "header" | "hunk" | "add" | "remove" | "context";
682
+ /** For task list items, whether the checkbox is checked. */
683
+ checked?: boolean;
684
+ /** Indentation depth for nested list items (0 = top level). */
685
+ indentLevel?: number;
686
+ /** For table blocks, the column headers. */
687
+ tableHeaders?: string[];
688
+ /** For table blocks, the data rows (each row is an array of cell text). */
689
+ tableRows?: string[][];
690
+ /** For table blocks, column alignments. */
691
+ tableAligns?: ("left" | "center" | "right")[];
692
+ }
693
+ interface RenderOptions {
694
+ /** Max number of blocks to render (limits re‑render cost). */
695
+ maxBlocks?: number;
696
+ /** If true, only parse complete blocks (for streaming). */
697
+ stableOnly?: boolean;
698
+ }
699
+ /** Simple line‑by‑line markdown parser. Returns blocks in order. */
700
+ declare function parseMarkdown(md: string, opts?: RenderOptions): MarkdownBlock[];
701
+ /**
702
+ * For streaming text, find the last "stable" offset — the position
703
+ * after the last complete block. Everything before this offset can
704
+ * be memoized; only the suffix needs re‑parsing.
705
+ */
706
+ declare function findStableOffset(text: string): number;
707
+ /**
708
+ * Render parsed markdown blocks as Ink elements.
709
+ *
710
+ * Uses a Box with flexDirection="column" as the container so that
711
+ * code blocks (which are Box elements with borders) can coexist with
712
+ * text blocks (which are Text elements).
713
+ */
714
+ declare function renderBlocks(blocks: MarkdownBlock[]): ReactNode;
715
+ //#endregion
716
+ //#region src/renderer/sanitize.d.ts
717
+ /**
718
+ * Text sanitization — strip control characters, ANSI escapes, and
719
+ * handle Unicode RTL isolation for safe terminal rendering.
720
+ *
721
+ * All functions are sync and pure — they take a string and return a
722
+ * cleaned version suitable for display.
723
+ */
724
+ /**
725
+ * Strip ANSI escape sequences (CSI, OSC, etc.) from text.
726
+ *
727
+ * Matches: CSI (\\x1b[), OSC (\\x1b]), and single‑character escapes.
728
+ * Does NOT strip SGR‑only sequences within Ink elements —
729
+ * this is for raw text from tool output or LLM responses.
730
+ */
731
+ declare function stripAnsi(text: string): string;
732
+ /**
733
+ * Strip control characters from text, preserving tab and newline.
734
+ *
735
+ * Removes: NUL, BEL, BS, FF, CR, SO, SI, DLE–US, DEL.
736
+ * Preserves: \\t (tab), \\n (newline), \\r (carriage return).
737
+ */
738
+ declare function stripControlChars(text: string): string;
739
+ /**
740
+ * Wrap RTL (right‑to‑left) text with Unicode bidirectional isolation
741
+ * characters to prevent it from corrupting surrounding LTR layout.
742
+ *
743
+ * RTL scripts detected: Arabic, Hebrew, Syriac, Thaana, N'Ko.
744
+ */
745
+ declare function isolateRtl(text: string): string;
746
+ /**
747
+ * Insert soft line‑break opportunities into long "words" (tokens) to
748
+ * prevent terminal line overflow. URLs and code blocks are preserved.
749
+ *
750
+ * Tokens longer than {@link LONG_TOKEN_LENGTH} characters are split
751
+ * with zero‑width spaces every 33 characters.
752
+ */
753
+ declare function chunkLongTokens(text: string, maxLen?: number): string;
754
+ /**
755
+ * Detect binary content by measuring the ratio of non‑printable
756
+ * characters (excluding common whitespace).
757
+ *
758
+ * If the binary ratio exceeds 50%, returns `"[binary content]"`;
759
+ * otherwise returns the original text.
760
+ */
761
+ declare function redactBinaryContent(text: string): string;
762
+ /**
763
+ * Full sanitization pipeline — applies all sanitizers in order.
764
+ *
765
+ * This is the recommended entry point for cleaning tool output
766
+ * before rendering in the TUI.
767
+ */
768
+ declare function sanitize(text: string): string;
769
+ //#endregion
770
+ //#region src/renderer/frame-limiter.d.ts
771
+ /**
772
+ * FrameRateLimiter — throttle Ink re‑renders to ~30 FPS via microtask batching.
773
+ *
774
+ * Ink renders on every state change. For high‑frequency updates (streaming
775
+ * text deltas, tool output), this can cause excessive re‑renders.
776
+ * FrameRateLimiter coalesces state updates within a 16 ms window.
777
+ *
778
+ * Design (§5.9i):
779
+ * - 30 fps throttle (~33 ms frame budget, 16 ms coalesce window)
780
+ * - In‑memory transcript cache for static entries
781
+ * - React.memo on static message blocks
782
+ */
783
+ /**
784
+ * Simple frame‑rate limiter.
785
+ *
786
+ * Uses a pending flag and microtask scheduling to ensure
787
+ * callbacks fire at most once per `frameMs` window.
788
+ */
789
+ declare class FrameRateLimiter {
790
+ private lastFrame;
791
+ private pending;
792
+ private readonly frameMs;
793
+ constructor(frameMs?: number);
794
+ /**
795
+ * Schedule a callback to run on the next available frame.
796
+ *
797
+ * If a callback was already scheduled within the current frame window,
798
+ * the new callback replaces it (last‑writer‑wins semantics).
799
+ */
800
+ schedule(fn: () => void): void;
801
+ /** Reset the limiter state. */
802
+ reset(): void;
803
+ }
804
+ /**
805
+ * Create a transcript cache key for stable React.memo comparison.
806
+ *
807
+ * Static messages (non‑streaming, non‑pending) can be memoized
808
+ * since their rendered output never changes.
809
+ */
810
+ declare function transcriptCacheKey(entryId: string, isStreaming: boolean, isPending: boolean): string;
811
+ /**
812
+ * Default frame rate limiter instance for transcript rendering.
813
+ *
814
+ * Created once per ChatLog mount to throttle streaming updates.
815
+ */
816
+ declare function createFrameRateLimiter(frameMs?: number): FrameRateLimiter;
817
+ //#endregion
818
+ //#region src/keybindings/keybindings.d.ts
819
+ interface KeyBinding {
820
+ /** Human‑readable description shown in the help modal. */
821
+ description: string;
822
+ /** Which views this binding applies to (empty = all views). */
823
+ scopes: string[];
824
+ /** Key matcher function. */
825
+ match: (input: string, key: Key) => boolean;
826
+ /** Action to execute. */
827
+ action: () => void;
828
+ }
829
+ type KeyBindingCatalog = KeyBinding[];
830
+ /**
831
+ * Create the default keybinding catalog.
832
+ *
833
+ * Callers provide concrete actions for each binding.
834
+ * The catalog is stateless — each binding is a closure
835
+ * over the action it should perform.
836
+ */
837
+ declare function createDefaultBindings(actions: {
838
+ abort: () => void;
839
+ help: () => void;
840
+ sessionPicker: () => void;
841
+ clearScreen: () => void;
842
+ scrollUp: () => void;
843
+ scrollDown: () => void;
844
+ }): KeyBindingCatalog;
845
+ /**
846
+ * Find and execute the first matching keybinding for the current scope.
847
+ *
848
+ * @returns true if a binding matched and was executed.
849
+ */
850
+ declare function dispatchBinding(catalog: KeyBindingCatalog, scope: string, input: string, key: Key): boolean;
851
+ //#endregion
852
+ //#region src/components/ModelPicker.d.ts
853
+ /** Props for the ModelPicker component. */
854
+ interface ModelPickerProps {
855
+ /** Available models to display. */
856
+ models: TuiModelInfo[];
857
+ /** Currently selected model ID. */
858
+ currentModel?: string;
859
+ /** Called when the user selects a model. */
860
+ onSelect: (modelId: string) => void;
861
+ /** Called when the user sets a model as default. */
862
+ onSetDefault?: (modelId: string) => void;
863
+ /** Called when the user cancels. */
864
+ onCancel: () => void;
865
+ }
866
+ /**
867
+ * Interactive model picker modal with search filtering.
868
+ *
869
+ * Navigation:
870
+ * Type text → filter models by id/label
871
+ * ↑/↓ — move cursor
872
+ * Enter — select and close
873
+ * s — set as default (does not close)
874
+ * Esc — cancel
875
+ */
876
+ declare function ModelPicker({
877
+ models,
878
+ currentModel,
879
+ onSelect,
880
+ onSetDefault,
881
+ onCancel
882
+ }: ModelPickerProps): React.ReactElement;
883
+ //#endregion
884
+ //#region src/components/ConfigMenu.d.ts
885
+ /** A single configurable setting. */
886
+ interface ConfigSetting {
887
+ /** Setting key, e.g. "autoCompact". */
888
+ key: string;
889
+ /** Human‑readable label. */
890
+ label: string;
891
+ /** Current value. Type determines rendering: boolean → checkbox, string/number → inline display. */
892
+ value: boolean | string | number;
893
+ /** Category tab this setting belongs to. */
894
+ category: string;
895
+ }
896
+ /** Props for the ConfigMenu component. */
897
+ interface ConfigMenuProps {
898
+ /** Active settings (optional; falls back to defaults). */
899
+ settings?: ConfigSetting[];
900
+ /** Called when a boolean setting is toggled. */
901
+ onToggle: (key: string, value: boolean) => void;
902
+ /** Called when a text/number setting needs editing. valueType helps the handler decide whether to parse as number. */
903
+ onEdit?: (key: string, label: string, currentValue: string, valueType: "text" | "number") => void;
904
+ /** Called when the user cancels. */
905
+ onCancel: () => void;
906
+ }
907
+ /**
908
+ * Interactive settings panel with tabbed categories.
909
+ *
910
+ * Navigation:
911
+ * ←/→ — switch tabs
912
+ * ↑/↓ — move cursor
913
+ * Enter — toggle boolean / edit text / edit number
914
+ * Esc — close
915
+ */
916
+ declare function ConfigMenu({
917
+ settings,
918
+ onToggle,
919
+ onEdit,
920
+ onCancel
921
+ }: ConfigMenuProps): React.ReactElement;
922
+ //#endregion
923
+ //#region src/components/ThemePicker.d.ts
924
+ /** Props for the ThemePicker component. */
925
+ interface ThemePickerProps {
926
+ /** Currently active theme name. */
927
+ currentTheme?: ThemeName;
928
+ /** Called when the user selects a theme. */
929
+ onSelect: (themeName: ThemeName) => void;
930
+ /** Called when the user cancels. */
931
+ onCancel: () => void;
932
+ }
933
+ /**
934
+ * Interactive theme picker modal.
935
+ *
936
+ * Navigation:
937
+ * ↑/↓ — move cursor
938
+ * Enter — apply theme and close
939
+ * Esc — cancel
940
+ */
941
+ declare function ThemePicker({
942
+ currentTheme,
943
+ onSelect,
944
+ onCancel
945
+ }: ThemePickerProps): React.ReactElement;
946
+ //#endregion
947
+ //#region src/components/ConfirmDialog.d.ts
948
+ /** Props for the ConfirmDialog component. */
949
+ interface ConfirmDialogProps {
950
+ /** Title shown in the border. */
951
+ title: string;
952
+ /** Body message explaining the action. */
953
+ message: string;
954
+ /** Label for the confirm option. Default: "Yes" */
955
+ confirmLabel?: string;
956
+ /** Label for the cancel option. Default: "No" */
957
+ cancelLabel?: string;
958
+ /** Called when the user confirms. */
959
+ onConfirm: () => void;
960
+ /** Called when the user cancels. */
961
+ onCancel: () => void;
962
+ }
963
+ /**
964
+ * Generic confirmation dialog with Yes/No options.
965
+ *
966
+ * Navigation:
967
+ * ↑/↓ — switch between options
968
+ * Enter — confirm current selection
969
+ * Esc — cancel
970
+ */
971
+ declare function ConfirmDialog({
972
+ title,
973
+ message,
974
+ confirmLabel,
975
+ cancelLabel,
976
+ onConfirm,
977
+ onCancel
978
+ }: ConfirmDialogProps): React.ReactElement;
979
+ //#endregion
980
+ //#region src/components/InputPrompt.d.ts
981
+ /** Props for the InputPrompt component. */
982
+ interface InputPromptProps {
983
+ /** Title shown in the border. */
984
+ title: string;
985
+ /** Initial value to pre‑fill the input. */
986
+ initialValue?: string;
987
+ /** Placeholder shown when input is empty. */
988
+ placeholder?: string;
989
+ /** Called when the user confirms with Enter. */
990
+ onConfirm: (value: string) => void;
991
+ /** Called when the user cancels with Esc. */
992
+ onCancel: () => void;
993
+ /** Maximum allowed input length. Default: 100. */
994
+ maxLength?: number;
995
+ }
996
+ /**
997
+ * Single‑line text input modal.
998
+ *
999
+ * Key bindings:
1000
+ * Enter — confirm and return value
1001
+ * Esc — cancel
1002
+ * Backspace — delete character before cursor
1003
+ * Delete — delete character at cursor
1004
+ * ←/→ — move cursor
1005
+ * Home/End — jump to start/end
1006
+ * Ctrl+A/E — jump to start/end
1007
+ * Ctrl+K — delete to end of line
1008
+ * Ctrl+W — delete previous word
1009
+ */
1010
+ declare function InputPrompt({
1011
+ title,
1012
+ initialValue,
1013
+ placeholder,
1014
+ onConfirm,
1015
+ onCancel,
1016
+ maxLength
1017
+ }: InputPromptProps): React.ReactElement;
1018
+ //#endregion
1019
+ //#region src/components/DoctorPanel.d.ts
1020
+ /** Result of a single diagnostic check. */
1021
+ interface DoctorCheck {
1022
+ /** Human‑readable name of the check. */
1023
+ label: string;
1024
+ /** Status: "ok" = pass, "warn" = warning, "error" = failed. */
1025
+ status: "ok" | "warn" | "error";
1026
+ /** Optional detail shown on the same line. */
1027
+ detail?: string;
1028
+ /** Optional fix hint shown in dimmed text below the check. */
1029
+ fixHint?: string;
1030
+ }
1031
+ /** Props for the DoctorPanel component. */
1032
+ interface DoctorPanelProps {
1033
+ /** List of check results to display. */
1034
+ checks: DoctorCheck[];
1035
+ /** Called when the user cancels (Escape). */
1036
+ onCancel: () => void;
1037
+ }
1038
+ /**
1039
+ * System diagnostics panel.
1040
+ *
1041
+ * Displays each check result with a status icon and optional detail.
1042
+ * The Escape key closes the panel (handled by the global handler).
1043
+ */
1044
+ declare function DoctorPanel({
1045
+ checks: initialChecks,
1046
+ onCancel
1047
+ }: DoctorPanelProps): React.ReactElement;
1048
+ /**
1049
+ * Run built‑in checks synchronously and return results.
1050
+ *
1051
+ * These checks run within the TUI process and don't require
1052
+ * spawning a separate `lynx doctor` subprocess.
1053
+ */
1054
+ declare function runBuiltinChecks(): DoctorCheck[];
1055
+ //#endregion
1056
+ //#region src/components/FilePicker.d.ts
1057
+ /** Props for the FilePicker modal. */
1058
+ interface FilePickerProps {
1059
+ /** Workspace root directory to walk. */
1060
+ workspace: string;
1061
+ /** Called when the user selects a file (Enter). */
1062
+ onSelect: (filePath: string) => void;
1063
+ /** Called when the user dismisses (Escape). */
1064
+ onCancel: () => void;
1065
+ /** Initial filter text (e.g. from @-mention). */
1066
+ initialFilter?: string;
1067
+ }
1068
+ /**
1069
+ * Interactive file picker modal with flat list and tree view modes.
1070
+ *
1071
+ * Flat mode: files sorted by relevance. Tree mode: files grouped by
1072
+ * directory with expand/collapse. Git status colors indicate modifications.
1073
+ */
1074
+ declare function FilePicker({
1075
+ workspace,
1076
+ onSelect,
1077
+ onCancel,
1078
+ initialFilter
1079
+ }: FilePickerProps): React.ReactElement;
1080
+ //#endregion
1081
+ //#region src/components/StashPicker.d.ts
1082
+ /** A single stashed item. */
1083
+ interface StashEntry {
1084
+ /** Unique identifier. */
1085
+ id: string;
1086
+ /** Truncated content preview. */
1087
+ preview: string;
1088
+ /** Unix timestamp when stashed. */
1089
+ timestamp: number;
1090
+ }
1091
+ /** Props for the StashPicker modal. */
1092
+ interface StashPickerProps {
1093
+ /** Stashed items (newest first). */
1094
+ items: StashEntry[];
1095
+ /** Called when the user restores an item (Enter). */
1096
+ onRestore: (id: string) => void;
1097
+ /** Called when the user deletes an item (Ctrl+D). */
1098
+ onDelete: (id: string) => void;
1099
+ /** Called when the user dismisses (Escape). */
1100
+ onCancel: () => void;
1101
+ }
1102
+ /**
1103
+ * Stash picker modal.
1104
+ *
1105
+ * Lists stashed inputs with restore and delete actions.
1106
+ */
1107
+ declare function StashPicker({
1108
+ items,
1109
+ onRestore,
1110
+ onDelete,
1111
+ onCancel
1112
+ }: StashPickerProps): React.ReactElement;
1113
+ //#endregion
1114
+ //#region src/components/ErrorBoundary.d.ts
1115
+ /** Props for the ErrorBoundary. */
1116
+ interface ErrorBoundaryProps {
1117
+ children: React.ReactNode;
1118
+ }
1119
+ /** State tracked by the ErrorBoundary. */
1120
+ interface ErrorBoundaryState {
1121
+ hasError: boolean;
1122
+ error: Error | null;
1123
+ }
1124
+ /**
1125
+ * React error boundary for Ink components.
1126
+ *
1127
+ * Catches rendering errors and displays a fallback UI instead of
1128
+ * crashing the entire terminal application.
1129
+ */
1130
+ declare class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
1131
+ constructor(props: ErrorBoundaryProps);
1132
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
1133
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
1134
+ render(): React.ReactNode;
1135
+ }
1136
+ //#endregion
1137
+ //#region src/components/AlternateScreen.d.ts
1138
+ /** Props for the AlternateScreen wrapper. */
1139
+ interface AlternateScreenProps {
1140
+ /** Children rendered inside the alt buffer. */
1141
+ children: ReactNode;
1142
+ /** Called when entering fullscreen mode. */
1143
+ onEnter(): void;
1144
+ /** Called when exiting fullscreen mode. */
1145
+ onExit(): void;
1146
+ }
1147
+ /**
1148
+ * Wraps children in alternate‑buffer lifecycle management.
1149
+ *
1150
+ * Calls `onEnter` on mount and `onExit` on unmount,
1151
+ * ensuring terminal recovery even on unexpected crashes.
1152
+ */
1153
+ declare function AlternateScreen({
1154
+ children,
1155
+ onEnter,
1156
+ onExit
1157
+ }: AlternateScreenProps): React.ReactElement;
1158
+ //#endregion
1159
+ //#region src/components/DiffViewer.d.ts
1160
+ /** A single changed file with diff content. */
1161
+ interface DiffFile {
1162
+ /** Relative file path. */
1163
+ path: string;
1164
+ /** Git status: M(odified), A(dded), D(eleted), R(enamed). */
1165
+ status: string;
1166
+ /** Unified diff text. */
1167
+ diff: string;
1168
+ }
1169
+ /** Props for the DiffViewer component. */
1170
+ interface DiffViewerProps {
1171
+ /** Async callback that fetches the diff data from git. */
1172
+ onRequestDiff?: () => Promise<DiffFile[]>;
1173
+ /** Called when the user dismisses the viewer. */
1174
+ onCancel: () => void;
1175
+ }
1176
+ /**
1177
+ * Git diff visualisation panel.
1178
+ *
1179
+ * Two modes:
1180
+ * - File list (default): shows changed files with status, preview snippet.
1181
+ * - Detail view: full unified diff for the selected file.
1182
+ * Arrow keys navigate the file list; Enter opens detail; Escape goes back.
1183
+ */
1184
+ declare function DiffViewer({
1185
+ onRequestDiff,
1186
+ onCancel
1187
+ }: DiffViewerProps): React.ReactElement;
1188
+ //#endregion
1189
+ //#region src/components/SnapshotBrowser.d.ts
1190
+ /** A single snapshot record. */
1191
+ interface SnapshotEntry {
1192
+ /** Unique snapshot identifier. */
1193
+ id: string;
1194
+ /** Unix-ms timestamp when the snapshot was captured. */
1195
+ timestamp: number;
1196
+ /** Human-readable snapshot label. */
1197
+ label: string;
1198
+ }
1199
+ /** Props for the SnapshotBrowser component. */
1200
+ interface SnapshotBrowserProps {
1201
+ /** Async callback that fetches snapshot records. */
1202
+ onRequestSnapshots?: () => Promise<SnapshotEntry[]>;
1203
+ /** Called when the user dismisses the browser. */
1204
+ onCancel: () => void;
1205
+ }
1206
+ /**
1207
+ * File snapshot browser.
1208
+ *
1209
+ * Lists all captured snapshots sorted by timestamp (newest first).
1210
+ * Arrow keys navigate; currently read‑only (restore support in a future phase).
1211
+ */
1212
+ declare function SnapshotBrowser({
1213
+ onRequestSnapshots,
1214
+ onCancel
1215
+ }: SnapshotBrowserProps): React.ReactElement;
1216
+ //#endregion
1217
+ //#region src/components/TasksPanel.d.ts
1218
+ /** Task status enum. */
1219
+ type TaskStatus = "running" | "queued" | "done" | "failed";
1220
+ /** A single background task record. */
1221
+ interface TaskEntry {
1222
+ /** Unique task identifier. */
1223
+ id: string;
1224
+ /** Human-readable task name. */
1225
+ name: string;
1226
+ /** Current task status. */
1227
+ status: TaskStatus;
1228
+ /** Error message if status is "failed". */
1229
+ error?: string;
1230
+ }
1231
+ /** Props for the TasksPanel component. */
1232
+ interface TasksPanelProps {
1233
+ /** Async callback that fetches the current task list. */
1234
+ onRequestTasks?: () => Promise<TaskEntry[]>;
1235
+ /** Called when the user dismisses the panel. */
1236
+ onCancel: () => void;
1237
+ }
1238
+ /**
1239
+ * Background task monitor panel.
1240
+ *
1241
+ * Auto‑polls the task list every 2 seconds. Shows status icon,
1242
+ * task name, and error detail for failed tasks.
1243
+ * Press 'r' to manually refresh.
1244
+ */
1245
+ declare function TasksPanel({
1246
+ onRequestTasks,
1247
+ onCancel
1248
+ }: TasksPanelProps): React.ReactElement;
1249
+ //#endregion
1250
+ //#region src/components/SkillPicker.d.ts
1251
+ /** Props for the SkillPicker component. */
1252
+ interface SkillPickerProps {
1253
+ /** All available skills (from builtin, user, project). */
1254
+ skills: SkillInfo[];
1255
+ /** Called when the user selects a skill (Enter). */
1256
+ onSelect(skillName: string): void;
1257
+ /** Called when the user dismisses (Escape). */
1258
+ onCancel(): void;
1259
+ }
1260
+ /**
1261
+ * Fuzzy skill search modal.
1262
+ *
1263
+ * The user types a query to filter skills. Results are ranked by
1264
+ * fuzzy match score. Arrow keys select; Enter invokes; Escape closes.
1265
+ */
1266
+ declare function SkillPicker({
1267
+ skills,
1268
+ onSelect,
1269
+ onCancel
1270
+ }: SkillPickerProps): React.ReactElement;
1271
+ //#endregion
1272
+ //#region src/screens/WelcomeScreen.d.ts
1273
+ /** Props for the WelcomeScreen component. */
1274
+ interface WelcomeScreenProps {
1275
+ /** Workspace directory path. */
1276
+ workspace: string;
1277
+ /** Lynx version string. */
1278
+ version: string;
1279
+ /** Last session info — null on first visit. */
1280
+ lastSession?: {
1281
+ label: string;
1282
+ relativeTime: string;
1283
+ sessionCount: number;
1284
+ };
1285
+ /** Called when the user confirms (trusts the workspace). */
1286
+ onConfirm: () => void;
1287
+ /** Called when the user exits (does not trust / cancels). */
1288
+ onExit: () => void;
1289
+ }
1290
+ /**
1291
+ * Safety confirmation screen.
1292
+ *
1293
+ * The user is shown workspace info and must confirm before
1294
+ * Lynx starts Phase 2 (loading sessions, MCP, memory, etc.).
1295
+ */
1296
+ declare function WelcomeScreen({
1297
+ workspace,
1298
+ version,
1299
+ lastSession,
1300
+ onConfirm,
1301
+ onExit
1302
+ }: WelcomeScreenProps): React.ReactElement;
1303
+ //#endregion
1304
+ //#region src/views/stack.d.ts
1305
+ /** Create a new view stack with an initial view. */
1306
+ declare function createViewStack(initial?: ViewId): ViewStack;
1307
+ //#endregion
1308
+ export { AlternateScreen, type AlternateScreenProps, App, type AppProps, ChatLog, type ChatLogEntry, type ChatLogHandle, type ChatLogProps, ChatView, type ChatViewProps, type CommandEntry, CommandPalette, type CommandPaletteProps, ConfigMenu, type ConfigMenuProps, ConfirmDialog, type ConfirmDialogProps, type ContextInfo, Dialog, type DialogProps, type DiffFile, DiffViewer, type DiffViewerProps, type DoctorCheck, DoctorPanel, type DoctorPanelProps, ErrorBoundary, FilePicker, type FilePickerProps, FrameRateLimiter, HelpModal, type HelpModalProps, type InputActions, InputBox, type InputBoxProps, InputPrompt, type InputPromptProps, type InputState, type KeyBinding, type KeyBindingCatalog, type MarkdownBlock, Mascot, type MascotProps, type MascotState, type McpConnectionInfo, ModelPicker, type ModelPickerProps, type PermissionChoice, PermissionRequest, type PermissionRequestData, type PermissionRequestProps, type PluginInfo, type RenderOptions, type SafetyLevel, type ScrollState, SessionPicker, type SessionPickerProps, type SkillInfo, SkillPicker, type SkillPickerProps, SnapshotBrowser, type SnapshotBrowserProps, type SnapshotEntry, type StashEntry, StashPicker, type StashPickerProps, StatusBar, type StatusBarProps, type TaskEntry, type TaskStatus, TasksPanel, type TasksPanelProps, type TerminalSize, type ThemeName, ThemePicker, type ThemePickerProps, ToolRenderer, type ToolRendererProps, type TuiCallbacks, type TuiModelInfo, type TuiStreamEvent, type TuiTheme, type UsageInfo, type UseScrollOptions, type ViewEntry, type ViewId, type ViewStack, type VimMode, WelcomeScreen, type WelcomeScreenProps, chunkLongTokens, color, createDefaultBindings, createFrameRateLimiter, createViewStack, dispatchBinding, findStableOffset, getTheme, initTheme, isolateRtl, listThemes, parseMarkdown, redactBinaryContent, renderBlocks, runBuiltinChecks, sanitize, setTheme, stripAnsi, stripControlChars, transcriptCacheKey, useInput, useScroll, useTerminalSize };
1309
+ //# sourceMappingURL=index.d.mts.map