@fishwithcat/dsh-tui-app 0.0.0-stage → 0.2.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,572 @@
1
+ /**
2
+ * pi-tui components for the terminal surface: the transcript document, the
3
+ * pinned status bar, and the formatting helpers they share. Every rendered line
4
+ * is truncated to the viewport width because the renderer treats an over-wide
5
+ * line as a component defect.
6
+ * @module @deepseek-ai/dsh-tui-app/views
7
+ */
8
+ import type { Component, Editor, Focusable, SelectItem, SelectListLayoutOptions, SelectListTheme, TuiMouseEvent, TuiMouseEventResult } from '@earendil-works/pi-tui';
9
+ import type { TuiTheme } from './ansi.ts';
10
+ import { TerminalTranscript } from './transcript.ts';
11
+ /**
12
+ * One-line account of a Tool call's arguments.
13
+ * @param args - the raw arguments JSON string.
14
+ * @returns a short, human-readable summary on one line.
15
+ */
16
+ export declare function summarizeToolArguments(args: string): string;
17
+ /**
18
+ * The transcript document. It renders every row it holds and reuses the rows an
19
+ * earlier revision already rendered; the surrounding viewport (an
20
+ * alternate-screen scroll view, or the terminal's own scrollback) owns
21
+ * scrolling.
22
+ */
23
+ export declare class TranscriptView implements Component {
24
+ private readonly transcript;
25
+ private readonly theme;
26
+ private document;
27
+ private rendered;
28
+ private readonly markdown;
29
+ private readonly markdownTheme;
30
+ /**
31
+ * @param transcript - the model this view renders.
32
+ * @param theme - the surface theme.
33
+ */
34
+ constructor(transcript: TerminalTranscript, theme: TuiTheme);
35
+ /** Release cached lines and Markdown components, including those of a replaced session. */
36
+ invalidate(): void;
37
+ /**
38
+ * Render the transcript body.
39
+ *
40
+ * Only the rows a revision touched are rendered again: a durable entry is
41
+ * never mutated after the fold appends it, and a live entry is a fresh object
42
+ * for every frame, so the per-entry cache is keyed by entry identity and
43
+ * width.
44
+ * @param width - the viewport width in columns.
45
+ * @returns one string per row, each within `width`.
46
+ */
47
+ render(width: number): string[];
48
+ /**
49
+ * One entry's rows at one width, reused until the entry or the width changes.
50
+ * @param entry - the row to render.
51
+ * @param width - the viewport width in columns.
52
+ * @returns the entry's rows, each within `width`.
53
+ */
54
+ private entryLines;
55
+ private renderEntry;
56
+ private assistantMarkdown;
57
+ /**
58
+ * One local shell row: the command with its local/sandbox label, the streamed
59
+ * output, then the state line. A command may span lines when it was pasted,
60
+ * so every line after the first starts under the bare indent.
61
+ */
62
+ private shellLines;
63
+ private toolLines;
64
+ /** One Tool row's heading and body for the card its views resolved to. */
65
+ private cardLines;
66
+ /** The ordinary heading: the Tool name and a one-line argument summary. */
67
+ private nameHeading;
68
+ /**
69
+ * A generic card's rows: the Tool's declared title (falling back to the
70
+ * ordinary name heading) and raw-input summary, then its UI-facing content or
71
+ * the raw result text.
72
+ */
73
+ private genericLines;
74
+ /**
75
+ * The parenthesized suffix a generic card shows for its salient raw input.
76
+ * A title that already spells the input out suppresses the repetition.
77
+ * @param title - the card's declared title.
78
+ * @param rawInput - the presenter's salient input.
79
+ * @returns the suffix, or an empty string when it adds nothing.
80
+ */
81
+ private rawInputSuffix;
82
+ /** A terminal card's rows: description, command heading with cwd and exit state, then output. */
83
+ private terminalLines;
84
+ /** The exit-status pill a settled terminal card declares, when it declares one. */
85
+ private exitPill;
86
+ /** A mutation's rows: the declared title with +/- totals, then the unified diff. */
87
+ private diffLines;
88
+ /** A read card's rows: the title and window extent, then numbered file lines. */
89
+ private readLines;
90
+ /** A search card's rows: grouped matched lines or a path list, with the cap signal. */
91
+ private searchLines;
92
+ /** The cap signal a truncated search card declares. */
93
+ private searchCap;
94
+ /** A web card's rows: the cited sources with the provider answer, or the fetch summary. */
95
+ private webLines;
96
+ /**
97
+ * Indent and bound pre-styled body rows to the viewport width.
98
+ * @param rows - the already-styled rows.
99
+ * @param width - the viewport width.
100
+ * @returns the indented rows, folded when they exceed the body budget.
101
+ */
102
+ private boundedRows;
103
+ /** A mutation's heading: the Tool's own card title and the change's +/- totals. */
104
+ private diffHeading;
105
+ /**
106
+ * A diff card's indented body, folded to a bounded number of rows.
107
+ * @param card - the built diff card.
108
+ * @param width - the viewport width.
109
+ * @returns the indented body lines.
110
+ */
111
+ private diffBody;
112
+ /** One diff row with its role's prefix and style, truncated to the body width. */
113
+ private diffRow;
114
+ }
115
+ /** Most rows a prompt heading occupies; a longer question keeps its first rows and ends with an ellipsis. */
116
+ export declare const PROMPT_TITLE_MAX_ROWS = 3;
117
+ /** Rows a prompt spends outside its body at most: the wrapped heading and the blank row under it. */
118
+ export declare const PROMPT_PANEL_CHROME_ROWS: number;
119
+ /** Rows a multi-select picker spends on its key hint below the list. */
120
+ export declare const MULTI_SELECT_HINT_ROWS = 1;
121
+ /**
122
+ * Row budget for one prompt panel on a terminal with `rows` rows left to it.
123
+ * @param rows - rows available to the panel, excluding any pinned footer.
124
+ * @param detailed - whether the body carries scrollable detail under a control.
125
+ * Such a panel may take every available row, because the detail is what the user
126
+ * must read; a detail-less picker stays capped so a long list does not fill a
127
+ * tall terminal.
128
+ * @returns the largest panel height, keeping at least one body row.
129
+ */
130
+ export declare function promptPanelRows(rows: number, detailed?: boolean): number;
131
+ /**
132
+ * A modal body that shows a prompt's supporting detail above its control.
133
+ *
134
+ * `detail` is markdown the caller supplied — a plan under review, or facts a
135
+ * question rests on — and can be taller than the panel. The detail renders in a
136
+ * viewport that yields every row its control does not use; the control's
137
+ * rendered height, not a fixed split, sizes the viewport, so a two-option
138
+ * review gives the plan nearly the whole panel and a long picker leaves the
139
+ * plan less.
140
+ *
141
+ * Scrolling keys depend on whether the detail overflows. While it does, Up and
142
+ * Down scroll it by one row, PageUp and PageDown by one viewport, and the wheel
143
+ * by its reported lines; a control that supplies `step` is then moved with Left
144
+ * and Right (or Tab and Shift+Tab), which keeps those keys off the scroller.
145
+ * While the detail fits, every key reaches the control unchanged, so a plain
146
+ * picker keeps its own Up, Down, Enter, and Escape bindings.
147
+ */
148
+ export declare class DetailBody implements Component {
149
+ private readonly control;
150
+ private readonly theme;
151
+ private readonly rows;
152
+ private readonly step?;
153
+ private readonly markdown;
154
+ private scrollTop;
155
+ /** Rows the last render gave the detail; also the PageUp/PageDown step. */
156
+ private viewport;
157
+ /** Detail rows the last render measured, for clamping a scroll. */
158
+ private content;
159
+ /**
160
+ * @param detail - the markdown shown above the control.
161
+ * @param control - the focused control that answers the prompt.
162
+ * @param theme - the surface theme.
163
+ * @param rows - the panel body's row budget, chrome excluded.
164
+ * @param step - moves the control's selection by one item while the detail
165
+ * overflows; absent when the control has no selection to move.
166
+ */
167
+ constructor(detail: string, control: Component, theme: TuiTheme, rows: number, step?: ((delta: -1 | 1) => void) | undefined);
168
+ /**
169
+ * Scroll the overflowing detail, move the control's selection, or hand the
170
+ * key to the control.
171
+ * @param data - raw key bytes.
172
+ */
173
+ handleInput(data: string): void;
174
+ /**
175
+ * Scroll the overflowing detail with the wheel, or hand the mouse event to
176
+ * the control. While the detail fits it leaves the wheel to the caller, so a
177
+ * prompt that has nothing to scroll passes it to the transcript instead.
178
+ * @param event - the normalized mouse event.
179
+ * @returns the control's result, or `handled` for a consumed wheel event.
180
+ */
181
+ handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
182
+ /** Drop both the detail's and the control's cached render state. */
183
+ invalidate(): void;
184
+ /**
185
+ * Render the detail viewport followed by the control.
186
+ * @param width - the viewport width in columns.
187
+ * @returns the body lines.
188
+ */
189
+ render(width: number): string[];
190
+ private scrollTo;
191
+ }
192
+ /**
193
+ * A prompt heading. Its header and trailing text stay on the first row — a
194
+ * header labeling the question, a trailing countdown at the right edge — while
195
+ * the question itself wraps across the heading rows.
196
+ */
197
+ export interface PromptHeading {
198
+ /** Dim label above the question, such as the question's header or its batch position. */
199
+ readonly header?: string | undefined;
200
+ /** The question presented to the user, wrapped across the heading rows. */
201
+ readonly question: string;
202
+ /** Text pinned to the right of the first heading row, such as a timed window's countdown. */
203
+ readonly trailing?: string | undefined;
204
+ }
205
+ /** A prompt heading: a plain line, a structured heading, or a provider of either re-evaluated each repaint. */
206
+ export type PromptTitle = string | PromptHeading | (() => string | PromptHeading);
207
+ /**
208
+ * Rows a prompt heading occupies at one width.
209
+ *
210
+ * A prompt reserves its body budget from this before the first paint, so the
211
+ * body never overflows the rows the heading's wrapping left it.
212
+ * @param value - the headed value to measure.
213
+ * @param width - the available columns.
214
+ * @returns the number of rows the panel draws for the heading.
215
+ */
216
+ export declare function promptHeadingRows(value: string | PromptHeading, width: number): number;
217
+ /**
218
+ * A modal panel: an optional heading, a blank row when a heading is present,
219
+ * and the control that handles keys. The renderer focuses the component passed
220
+ * to `showOverlay`, and a bare container does not forward keys, so the panel is
221
+ * the focused component.
222
+ *
223
+ * Escape is intercepted here instead of by the control: the control binds it
224
+ * together with Ctrl+C to one cancel action, so a prompt that offers a skip
225
+ * could not otherwise tell the two apart. Ctrl+C keeps its own meaning and
226
+ * reaches the control's cancel binding.
227
+ *
228
+ * The panel reads as ordinary output rather than a dialog: no border, left
229
+ * aligned like a transcript row. Every row is padded to the width the caller
230
+ * passes, though, because the renderer composites an overlay over the row it
231
+ * covers and leaves the rest of that row as the transcript printed it; padding
232
+ * the full row is what keeps the transcript from showing through beside the
233
+ * body, which would read as one garbled line.
234
+ */
235
+ export declare class PromptPanel implements Component, Focusable {
236
+ private readonly title;
237
+ private readonly theme;
238
+ private readonly body;
239
+ /** Set by the renderer when this panel owns the keyboard. */
240
+ focused: boolean;
241
+ /** Called when the user presses Escape to move past the prompt without answering. */
242
+ onSkip?: () => void;
243
+ /** Heading and separator rows the last render drew, so a mouse event keeps the control's own coordinates. */
244
+ private chromeRows;
245
+ /**
246
+ * @param title - the heading, a provider evaluated on every render for a
247
+ * heading that changes while the panel is open, such as a countdown, or
248
+ * undefined for a body that supplies its own first line.
249
+ * @param theme - the surface theme.
250
+ * @param body - the control that handles keys.
251
+ */
252
+ constructor(title: PromptTitle | undefined, theme: TuiTheme, body: Component);
253
+ /**
254
+ * Answer Escape as a skip and hand every other key to the wrapped control.
255
+ * @param data - raw key bytes.
256
+ */
257
+ handleInput(data: string): void;
258
+ /**
259
+ * Forward a mouse event past the panel's chrome to the wrapped control, so a
260
+ * scrolling body reaches its own viewport at the rows it rendered. Events on
261
+ * the heading or blank row belong to no control.
262
+ * @param event - the normalized mouse event, in panel coordinates.
263
+ * @returns the body's result, when it handled the event.
264
+ */
265
+ handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
266
+ /** Drop the wrapped control's cached render state. */
267
+ invalidate(): void;
268
+ /**
269
+ * Render the optional heading and the body, filling every row the overlay
270
+ * covers.
271
+ * @param width - the viewport width in columns.
272
+ * @returns the panel lines, each exactly `width` columns wide.
273
+ */
274
+ render(width: number): string[];
275
+ /**
276
+ * Wrap the heading into at most {@link PROMPT_TITLE_MAX_ROWS} rows.
277
+ * @param width - the available columns.
278
+ * @returns the styled heading rows, or none when the panel has no heading.
279
+ */
280
+ private heading;
281
+ /**
282
+ * Pin one line of text to the right of a heading row.
283
+ * @param line - the heading row.
284
+ * @param trailing - the text to pin.
285
+ * @param width - the available columns.
286
+ * @returns the row with the trailing text at its right edge.
287
+ */
288
+ private withTrailing;
289
+ private row;
290
+ }
291
+ /**
292
+ * A single-select picker that answers only keyboard input.
293
+ *
294
+ * `SelectList` confirms a left click on a row and moves the highlight on the
295
+ * wheel; a stray click in the terminal would settle a prompt the user only meant
296
+ * to focus. This wrapper exposes no mouse handler, so the arrow keys move the
297
+ * highlight and Enter or Escape are the only ways to settle the list. It
298
+ * forwards the wrapped picker's own key handling, selection callbacks, and
299
+ * render state.
300
+ */
301
+ export declare class KeyboardSelectList implements Component {
302
+ /** Called with the highlighted option when the user confirms. */
303
+ onSelect?: (item: SelectItem) => void;
304
+ /** Called when the user cancels. */
305
+ onCancel?: () => void;
306
+ /** Called whenever the highlighted option changes. */
307
+ onSelectionChange?: (item: SelectItem) => void;
308
+ private readonly list;
309
+ /**
310
+ * @param items - the options to show.
311
+ * @param maxVisible - most rows the picker shows before scrolling.
312
+ * @param theme - the picker theme.
313
+ * @param layout - the picker's column layout.
314
+ */
315
+ constructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme, layout?: SelectListLayoutOptions);
316
+ /**
317
+ * Forward keyboard input to the wrapped picker.
318
+ * @param data - raw key bytes.
319
+ */
320
+ handleInput(data: string): void;
321
+ /**
322
+ * Move the highlight onto one option.
323
+ * @param index - the option index; clamped to the list.
324
+ */
325
+ setSelectedIndex(index: number): void;
326
+ /**
327
+ * The highlighted option.
328
+ * @returns the highlighted option, or null when the list shows none.
329
+ */
330
+ getSelectedItem(): SelectItem | null;
331
+ /** Drop the wrapped picker's cached render state. */
332
+ invalidate(): void;
333
+ /**
334
+ * Render the wrapped picker's options.
335
+ * @param width - the viewport width in columns.
336
+ * @returns the picker lines.
337
+ */
338
+ render(width: number): string[];
339
+ }
340
+ /**
341
+ * A modal picker whose options are checked with Space and submitted with Enter.
342
+ *
343
+ * The single-select picker confirms on the same key that moves, so a checkable
344
+ * list cannot reuse it unchanged: this owns the check state and wraps the picker
345
+ * for navigation, scrolling, and rendering. Every option it passes down is its
346
+ * own copy whose label carries the marker, so a toggle rewrites that label in
347
+ * place — the picker renders the objects it was given, so the marker follows the
348
+ * check state without a second rendering path. Enter submits the checked options
349
+ * in list order and is ignored while none is checked, so a stray confirm cannot
350
+ * answer with an empty selection; Escape still cancels.
351
+ */
352
+ export declare class MultiSelectList implements Component {
353
+ /** Called with the checked options in list order when the user confirms. */
354
+ onConfirm?: (items: SelectItem[]) => void;
355
+ /** Called when the user cancels the picker. */
356
+ onCancel?: () => void;
357
+ /** Called whenever the highlighted option changes. */
358
+ onSelectionChange?: (item: SelectItem) => void;
359
+ private readonly list;
360
+ private readonly items;
361
+ private readonly theme;
362
+ /**
363
+ * @param items - the options to check.
364
+ * @param maxVisible - most rows the picker shows before scrolling.
365
+ * @param theme - the picker theme shared with the single-select list.
366
+ * @param layout - the picker's column layout.
367
+ */
368
+ constructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme, layout?: SelectListLayoutOptions);
369
+ /**
370
+ * Toggle the highlighted option on Space, confirm the checked ones on Enter,
371
+ * and hand every other key to the wrapped picker.
372
+ * @param data - raw key bytes.
373
+ */
374
+ handleInput(data: string): void;
375
+ /**
376
+ * Move the highlight onto one option.
377
+ * @param index - the option index; clamped to the list.
378
+ */
379
+ setSelectedIndex(index: number): void;
380
+ /** Drop the wrapped picker's cached render state. */
381
+ invalidate(): void;
382
+ /**
383
+ * Render the options with their check markers and the key hint.
384
+ * @param width - the viewport width in columns.
385
+ * @returns the picker lines, the hint last.
386
+ */
387
+ render(width: number): string[];
388
+ /**
389
+ * The checked options.
390
+ * @returns the checked options in list order.
391
+ */
392
+ selectedItems(): SelectItem[];
393
+ private toggle;
394
+ }
395
+ /** Context occupancy the footer reports against the routed model's capacity. */
396
+ export interface TuiContextStatus {
397
+ /** Estimated tokens of the next request's prompt. */
398
+ tokens: number;
399
+ /** The routed model's context window in tokens. */
400
+ window: number;
401
+ /** Whether the mounted engine compacts automatically at this pressure. */
402
+ automatic: boolean;
403
+ }
404
+ /** Delegated subagents the footer summarizes. */
405
+ export interface TuiSubagentStatus {
406
+ /** Children this session's catalogs record, at any depth. */
407
+ total: number;
408
+ /** Children whose activation is still running. */
409
+ running: number;
410
+ }
411
+ /** Whole-log token figures the footer's bottom-right group reports. */
412
+ export interface TuiSessionStats {
413
+ /** Decode throughput averaged over decode-timed steps; absent until one is timed. */
414
+ tokensPerSecond?: number | undefined;
415
+ /** Billed prompt tokens over the whole log: uncached input plus cache reads and writes. */
416
+ promptTokens: number;
417
+ /** Provider-reported output tokens over the whole log. */
418
+ outputTokens: number;
419
+ /** Prompt tokens the provider served from cache. */
420
+ cacheReadTokens: number;
421
+ }
422
+ /** One frame of the status bar. */
423
+ export interface TuiStatus {
424
+ /** Workspace directory, abbreviated against the home directory. */
425
+ workspace: string;
426
+ /**
427
+ * Agent lifecycle state, `compacting` while a compaction transaction runs
428
+ * outside the turn lifecycle and the Agent itself stays idle, or `shell`
429
+ * while a local `!` command occupies the surface.
430
+ */
431
+ state: 'idle' | 'running' | 'compacting' | 'shell';
432
+ /** Display label for the routed model, provider-qualified when the deployment registers several. */
433
+ model: string;
434
+ /** Reasoning effort in force, when the route declares one. */
435
+ effort?: string | undefined;
436
+ /**
437
+ * Whether plan mode is in force, or selected to apply from the next step;
438
+ * absent when the deployment mounts no plan mode.
439
+ */
440
+ plan?: boolean | undefined;
441
+ /** Whether a clipboard image read is in flight; the identity line reports the wait. */
442
+ pasting?: boolean | undefined;
443
+ /** Context occupancy, absent until the meter reports both a pressure and a capacity. */
444
+ context?: TuiContextStatus | undefined;
445
+ /** Delegated children the session's catalogs record, absent while it has none. */
446
+ subagents?: TuiSubagentStatus | undefined;
447
+ /** Whole-log throughput and token totals; absent when the frame carries no measurement. */
448
+ stats?: TuiSessionStats | undefined;
449
+ }
450
+ /**
451
+ * Display label for the routed model: the provider qualifies it only when the
452
+ * deployment registers several, so the common single-provider footer stays short.
453
+ * @param provider - the routed provider.
454
+ * @param model - the routed model id.
455
+ * @param providerCount - providers the deployment registered.
456
+ * @returns the label the footer's right side shows.
457
+ */
458
+ export declare function modelLabel(provider: string, model: string, providerCount: number): string;
459
+ /**
460
+ * Display parts of the footer's bottom-right group, in display order: whole-log
461
+ * decode throughput, the billed token total, and the cache-hit share. A figure
462
+ * whose input has no data is omitted rather than shown as zero.
463
+ * @param stats - the whole-log token figures for one frame.
464
+ * @returns one text per available figure.
465
+ */
466
+ export declare function sessionStatsParts(stats: TuiSessionStats): string[];
467
+ /**
468
+ * The pinned footer under the composer: the workspace and Agent state against
469
+ * the routed model, then the context occupancy with the whole-log token figures
470
+ * at the bottom-right edge.
471
+ */
472
+ export declare class StatusBar implements Component {
473
+ private readonly theme;
474
+ private status;
475
+ /**
476
+ * @param theme - the surface theme.
477
+ */
478
+ constructor(theme: TuiTheme);
479
+ /**
480
+ * Replace the rendered status.
481
+ * @param status - the current facts.
482
+ */
483
+ set(status: TuiStatus): void;
484
+ /** Drop cached render state. */
485
+ invalidate(): void;
486
+ /**
487
+ * Render the footer.
488
+ * @param width - the viewport width in columns.
489
+ * @returns the footer lines, each within `width`.
490
+ */
491
+ render(width: number): string[];
492
+ /**
493
+ * Render context occupancy and whole-log token figures for either terminal surface.
494
+ * @param width - the viewport width in columns.
495
+ * @returns the usage line within `width`.
496
+ */
497
+ renderUsage(width: number): string;
498
+ /** The usage line's left side: occupancy, then the delegated-work marker while any child is recorded. */
499
+ private usageLeft;
500
+ /**
501
+ * The delegated-work marker: `●` while at least one child runs, `○` once every
502
+ * recorded child has settled, with the count as running of total.
503
+ */
504
+ private subagentsPart;
505
+ /**
506
+ * Place a right side against a left side at the footer's edges.
507
+ *
508
+ * The right side yields first — truncated, then dropped — so the identity and
509
+ * state a user reads stay intact on a narrow terminal; only a left side wider
510
+ * than the terminal is truncated itself.
511
+ * @param left - the already styled left side.
512
+ * @param right - the already styled right side.
513
+ * @param width - the viewport width in columns.
514
+ * @returns one line within `width`.
515
+ */
516
+ private pairLine;
517
+ private headText;
518
+ /**
519
+ * The lifecycle slot: `compacting` while a compaction transaction occupies an
520
+ * otherwise idle Agent, because no turn status changes until it settles.
521
+ * @returns the styled lifecycle label.
522
+ */
523
+ private stateText;
524
+ private modelText;
525
+ /** The bottom-right group: whole-log throughput, token total, and cache-hit share. */
526
+ private statsRight;
527
+ private contextPart;
528
+ }
529
+ /**
530
+ * The composer with a placeholder.
531
+ *
532
+ * While the composer is empty, its content row shows the key hints, so the
533
+ * surface does not spend a footer line on keys the user already knows; the
534
+ * first typed character replaces them.
535
+ */
536
+ export declare class PlaceholderEditor implements Component, Focusable {
537
+ private readonly editor;
538
+ private readonly theme;
539
+ private hint;
540
+ /**
541
+ * @param editor - the composer the user types into.
542
+ * @param theme - the surface theme.
543
+ */
544
+ constructor(editor: Editor, theme: TuiTheme);
545
+ /** Forward focus to the composer so it emits its cursor marker. */
546
+ get focused(): boolean;
547
+ set focused(value: boolean);
548
+ /**
549
+ * Replace the placeholder text.
550
+ * @param hint - the key hints line.
551
+ */
552
+ setHint(hint: string): void;
553
+ /** Forward input to the composer. */
554
+ handleInput(data: string): void;
555
+ /** Drop the composer's cached render state. */
556
+ invalidate(): void;
557
+ /**
558
+ * Render the composer, showing the hints in place of an empty content line.
559
+ * @param width - the viewport width in columns.
560
+ * @returns the composer lines, each within `width`.
561
+ */
562
+ render(width: number): string[];
563
+ /**
564
+ * The empty composer's content line: the hints with the cursor on their first
565
+ * character, so an untouched composer still shows where typing lands. A focused
566
+ * composer emits the hardware-cursor marker exactly as the editor does.
567
+ * @param width - the viewport width in columns.
568
+ * @returns the padded content line.
569
+ */
570
+ private placeholderLine;
571
+ }
572
+ //# sourceMappingURL=views.d.ts.map
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The viewing side of the local subagent stream: open one authenticated
3
+ * loopback request, parse its NDJSON frames, and report a decoded snapshot and
4
+ * ordered updates. This module never creates an Agent and never retries.
5
+ * @module @deepseek-ai/dsh-tui-app/watch/client
6
+ */
7
+ import type { WatchAssistantFrame, WatchConnectionRecord, WatchExecutionState, WatchServerFrame, WatchSnapshotFrame } from './protocol.ts';
8
+ import type { SessionEvent } from '@deepseek-ai/dsh-session';
9
+ /** Failure classes the viewer distinguishes. */
10
+ export type WatchStreamFailureKind =
11
+ /** The service exists but refused this viewer: bad token, wrong version, or not viewable. */
12
+ 'refused'
13
+ /** The service answered with malformed protocol data. */
14
+ | 'protocol'
15
+ /** The TCP/HTTP connection or body failed. */
16
+ | 'network'
17
+ /** The service reported an internal read failure. */
18
+ | 'service';
19
+ /** Typed failure with a user-facing message. */
20
+ export declare class WatchStreamError extends Error {
21
+ readonly kind: WatchStreamFailureKind;
22
+ readonly status?: number | undefined;
23
+ /**
24
+ * @param kind - the failure class.
25
+ * @param message - user-facing diagnostic.
26
+ * @param status - HTTP status when the failure came from a response.
27
+ */
28
+ constructor(kind: WatchStreamFailureKind, message: string, status?: number | undefined);
29
+ }
30
+ /** Opening snapshot and ordered updates delivered to one viewer. */
31
+ export interface WatchStreamHandlers {
32
+ /** Apply the opening snapshot synchronously before any later frames are delivered. */
33
+ onSnapshot(snapshot: WatchSnapshotFrame): void;
34
+ /** One later committed event. */
35
+ onEvent(event: SessionEvent): void;
36
+ /** One later assistant frame. */
37
+ onAssistant(frame: WatchAssistantFrame): void;
38
+ /** Execution state changed. */
39
+ onStatus(status: WatchExecutionState): void;
40
+ /** The child finished one execution; the stream stays open for later runs. */
41
+ onExecutionEnd(stopReason: string): void;
42
+ /** The service is shutting down. */
43
+ onServiceClosed(): void;
44
+ /** The stream failed after the snapshot. */
45
+ onFailure(error: WatchStreamError): void;
46
+ }
47
+ /** One open watch stream. */
48
+ export interface WatchStream {
49
+ /** The opening snapshot, already validated and decoded. */
50
+ readonly snapshot: WatchSnapshotFrame;
51
+ /** Close the local side without reporting a failure. */
52
+ close(): void;
53
+ }
54
+ /**
55
+ * Open one watch stream and wait for its snapshot.
56
+ * @param record - the published connection record.
57
+ * @param sessionId - the child session requested.
58
+ * @param handlers - callbacks for frames after the snapshot.
59
+ * @returns the snapshot and a close handle.
60
+ * @throws {WatchStreamError} when the request, response, or opening frame fails.
61
+ */
62
+ export declare function openWatchStream(record: WatchConnectionRecord, sessionId: string, handlers: WatchStreamHandlers): Promise<WatchStream>;
63
+ /**
64
+ * Parse and validate one NDJSON line.
65
+ * @param line - one complete JSON line without its terminator.
66
+ * @returns the validated frame.
67
+ * @throws {WatchStreamError} when the line is malformed or unknown.
68
+ */
69
+ export declare function parseServerFrame(line: string): WatchServerFrame;
70
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Read-only history access for the watch viewer.
3
+ *
4
+ * History mode opens the persistence read handle only: it takes no write lock,
5
+ * restores no Agent, and issues no model request.
6
+ * @module @deepseek-ai/dsh-tui-app/watch/history
7
+ */
8
+ import type { Context } from '@deepseek-ai/cordis';
9
+ import type { SessionEvent, SessionHeader } from '@deepseek-ai/dsh-session';
10
+ /** One stored session cut the viewer folds. */
11
+ export interface WatchHistory {
12
+ /** Stored session header. */
13
+ readonly header: SessionHeader;
14
+ /** Committed events in sequence order. */
15
+ readonly events: readonly SessionEvent[];
16
+ }
17
+ /**
18
+ * Read a stored child session without activating it.
19
+ * @param ctx - context carrying the optional persistence service.
20
+ * @param sessionId - the stored session to read.
21
+ * @returns the header and every committed event.
22
+ * @throws when persistence is unmounted, the session is absent, or the read fails.
23
+ */
24
+ export declare function readWatchHistory(ctx: Context, sessionId: string): Promise<WatchHistory>;
25
+ //# sourceMappingURL=history.d.ts.map