@x-otto/tui 0.0.1-alpha.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,1917 @@
1
+ import { Command, CommandContext, CommandRegistry, CommandResult, RenderOptions, createBuiltinCommands, showCommandPalette } from "./compat.js";
2
+ import { $ as ExtensionListEntry, $n as ToolCompletionMessage, $t as observationRow, A as RemoteSessionSnapshot, An as ThemePresetSource, At as SigilKind, B as SelectState, Bn as STATUS, Bt as getCommandSuggestions, C as TuiHandle, Cn as LangMode, Ct as ProviderUsageBadgeItem, Dn as ThemePreset, Dt as PromptInput, E as TuiStreamEvent, En as ThemeAppearance, Et as QueuedCommands, F as createLocalSessionDataSource, Fn as DIALOG_BORDER, Ft as SlashNavigateAction, G as makeNotifyScheduler, Gn as ChatMessage, Gt as PasteStore, H as A2uiButtonInfo, Hn as ThemeColors, Ht as CreatePasteStoreOptions, I as MessageStore, In as PANEL_BORDER, It as TypeaheadState, J as MemoryEntry, Jn as StopReason, Jt as Completer, K as MemoryDialog, Kn as MessageContent, Kt as PasteStoreResidencySource, Ln as FIGURES, Lt as applySlashCompletion, M as SessionDataTarget, Mn as createBuiltinThemeRegistry, Mt as SigilSearchRegistry, N as SessionTransport, Nn as LAYOUT, Nt as CommandEntry, O as AttachDataSourceDeps, On as ThemePresetInput, Ot as SubmitMode, P as createAttachSessionDataSource, Pn as SPACING, Pt as CommandRegistry$1, Qn as ToolCall, Qt as observationLiveFields, R as SelectOption, Rn as FiguresMap, Rt as createCommandRegistry, S as SubagentContext, Sn as Lang, St as SessionListItem, T as TuiPanelRegistration, Tn as MarkdownThemeOverrides, Tt as isUsingOverage, U as NotifyScheduler, Un as A2uiContent, Ut as PasteSnapshot, V as createSelectState, Vn as THEME, Vt as navigateSuggestions, W as NotifyStats, Wn as AssistantMessage, Wt as PasteSnapshotEntry, Xn as TextContent, Xt as formatAgentDiagnosticsText, Y as MemoryEntrySource, Yn as StreamEvent, Yt as ObservationLike, Zn as ThinkingContent, Zt as formatTurnTimeline, _ as ModalRequestInput, _n as useAppState, _t as BudgetView, an as ErrorRetryItem, at as ButtonColor, b as PluginRegistration, bn as initI18n, bt as Home, c as TabableRegistry, cn as OnboardingResult, ct as PluginMessageRenderer, dn as DataListEntry, dt as registerPluginRenderers, en as subagentEntryStatus, er as ToolMessage, et as ExtensionMenuContribution, f as ConfirmDialog, fn as DataListProps, ft as NotificationStore, g as DraftItemView, gn as Store, gt as BudgetStore, h as ConfirmRequest, hn as PerfStore, ht as BudgetState, i as Tabable, in as ErrorRetryActionKind, it as Button, j as SessionDataSource, jn as ThemeRegistry, jt as SigilPrefix, k as RemoteSessionEvent, kn as ThemePresetSelection, kt as SigilEntry, l as UseTabableOptions, ln as KeyBindingPredicate, lt as RegisteredRenderer, m as AlertRequest, mn as DataListTone, mt as CacheStore, nn as EditedFileEntry, nt as ExtensionDetailAction, on as RateLimitType, ot as ButtonProps, p as ConfirmDialogProps, pn as DataListRow, pt as ProxyStore, q as MemoryDialogProps, qn as PulseSurveyItem, qt as createPasteStore, rn as ErrorRetryAction, rt as ExtensionDetailRequest, s as TabableProps, sn as ContextStore, st as ButtonVariant, t as FocusStyle, tn as subagentRestoreFields, tr as UserMessage, tt as ExtensionsListRequest, u as useTabable, un as DataList, ut as clearPluginRenderers, v as ModalRequestVoid, vn as detectLanguage, vt as createBudgetStore, w as TuiOptions, wn as Risk, wt as formatProviderUsageLimitTypeFull, x as PromptRequest, xn as t, xt as HomeProps, y as PermissionDecision, yn as i18next, yt as TaskStore, z as SelectOptions, zn as PALETTE, zt as extractSlashPrefix } from "./Tabable-B7PtwING.js";
3
+ import React from "react";
4
+ import { DOMElement, Key } from "ink";
5
+ import { FuzzySearchOptions, HighlightRange, RankedMatch, SearchableItem, SubsequenceResult, matchSubsequence, positionsToHighlightRanges, rankCandidates, rankLabeledItems, rankNamedItems, scoreSubsequence } from "@x-otto/shared";
6
+ import { SigilTrigger, applySigilCompletion, extractSigilPrefix } from "@x-otto/interchange";
7
+ import { SessionEvent, TaskItem } from "@x-otto/session-contract";
8
+
9
+ //#region src/overlays/TrustPromptDialog.d.ts
10
+ type TrustPromptChoice = 'trust' | 'readonly' | 'exit';
11
+ //#endregion
12
+ //#region src/WorkspaceTrustPrompt.d.ts
13
+ interface WorkspaceTrustPromptOptions {
14
+ /** 解析到的工作区根(展示给用户 + 信任记录单元)。 */
15
+ root: string;
16
+ /** 用户配置语言(zh/en/auto),使弹窗与会话一致。 */
17
+ language?: string;
18
+ }
19
+ /**
20
+ * 弹出工作区信任弹窗,resolve 用户选择('trust' | 'readonly' | 'exit')。
21
+ * 仅在 cli 判定 `evaluateWorkspaceTrustPrompt().shouldPrompt` 后调用。
22
+ */
23
+ declare function promptWorkspaceTrust(opts: WorkspaceTrustPromptOptions): Promise<TrustPromptChoice>;
24
+ //#endregion
25
+ //#region src/overlays/ParentWorkspaceDialog.d.ts
26
+ type ParentWorkspaceChoice = 'use_parent' | 'create_new' | 'exit';
27
+ //#endregion
28
+ //#region src/ParentWorkspacePrompt.d.ts
29
+ interface ParentWorkspacePromptOptions {
30
+ parentRoot: string;
31
+ currentRoot: string;
32
+ language?: string;
33
+ }
34
+ declare function promptParentWorkspaceChoice(opts: ParentWorkspacePromptOptions): Promise<ParentWorkspaceChoice>;
35
+ //#endregion
36
+ //#region src/ui-state/types.d.ts
37
+ /** 此刻持有键盘焦点的拥有者。优先级见 focus.ts FOCUS_PRIORITY。 */
38
+ type FocusOwner = 'home' | 'forcedUpgrade' | 'prompt'
39
+ /** `/help` 命令面板独立查看器(复用 FileContentViewer 固定高度+滚动逻辑,同 fileViewer 一类)。 */
40
+ /** RFC-212 D3:Enter-on-chip 打开的只读内容查看器(paste chip 原文查看)。 */
41
+ /** shell 面板 `v` 键打开的全量输出查看器(复用 FileContentViewer 固定高度+滚动逻辑)。 */
42
+ | 'shellFullOutput' | 'notifications' | 'background' | 'pasteConfirm' | 'editedFiles' | 'schedule' | 'subagents' | 'clipboard' | 'taskFocus' | 'taskDetail' | 'subagentContext' | 'editedFileFull' | 'sigilPane' | 'shell' | 'draft' | 'queue' | 'info' | 'queueEdit' | 'perf' | 'cacheStats' | 'compactionLog' | 'gallery'
43
+ /** RFC-255 终局:/pane/proxy 面板焦点归属。此前 App.tsx routeDerivedOwner 已返回 'proxy'
44
+ * 但缺类型成员(靠 as FocusOwner 强转),useRouteDerivedOwner hook 则降级为 'prompt'
45
+ * 丢失语义——补成员后两处统一为 'proxy'(proxy 面板打开时 onFocusOwnerChange 得到非
46
+ * 'prompt' 值 → buffer 正确缓冲不 flush,同 perf/cacheStats 等同类只读面板)。 */
47
+ | 'proxy' | 'prompts' | 'retry' | 'errorRetry'
48
+ /** RFC-208:满意度脉冲调查弹层(Band B 标准形态,同 toast/errorRetry)。
49
+ * RFC-251 Phase 4f 后键盘由 PulseSurveyOverlay 通过 FocusBus 自管。 */
50
+ | 'pulseSurvey' | 'toast';
51
+ //#endregion
52
+ //#region src/term/paste.d.ts
53
+ /**
54
+ * paste.ts — bracketed paste 状态机(D7 终端协议旁路)。
55
+ *
56
+ * 在 Ink useInput 之外操作 stdin,检测 \x1b[200~ / \x1b[201~ 区间。
57
+ *
58
+ * 优化点:后期可加 100ms 超时回退 + image 剪贴板检测钩子(见 V1 paste.ts)。
59
+ * 当前实现:最小可用——完整记录粘贴开始/结束 + 全文缓冲。
60
+ */
61
+ type PasteEvent = {
62
+ type: 'paste_start';
63
+ } | {
64
+ type: 'paste_end';
65
+ text: string;
66
+ isEmpty: boolean;
67
+ } | {
68
+ type: 'paste_timeout';
69
+ partialText: string;
70
+ };
71
+ interface BracketedPasteOptions {
72
+ timeoutMs?: number;
73
+ onEmptyPaste?: () => void;
74
+ }
75
+ declare class BracketedPasteHandler {
76
+ private buffer;
77
+ private active;
78
+ private timer;
79
+ private readonly timeoutMs;
80
+ private readonly onEmptyPaste?;
81
+ constructor(opts?: BracketedPasteOptions);
82
+ get isPasting(): boolean;
83
+ get currentBuffer(): string;
84
+ feed(chunk: string): PasteEvent[];
85
+ forceEnd(): PasteEvent | null;
86
+ reset(): void;
87
+ destroy(): void;
88
+ private resetTimer;
89
+ private clearTimer;
90
+ private flushPasteEnd;
91
+ }
92
+ //#endregion
93
+ //#region src/term/keys.d.ts
94
+ /**
95
+ * keys.ts — 扩展键解析器(D7 终端协议旁路)。
96
+ *
97
+ * kitty CSI u + modifyOtherKeys + CSI 方向键/功能键 + SS3。
98
+ * 在 Ink useInput 之外操作,解析后的结果可注入输入栈。
99
+ *
100
+ * 优化点:后期可加入不完整序列缓冲 + 50ms flush 定时器。
101
+ */
102
+ interface ParsedExtendedKey {
103
+ name: string;
104
+ ctrl: boolean;
105
+ shift: boolean;
106
+ alt: boolean;
107
+ meta: boolean;
108
+ sequence: string;
109
+ }
110
+ declare function parseExtendedKey(seq: string): ParsedExtendedKey | null;
111
+ //#endregion
112
+ //#region src/term/osc.d.ts
113
+ declare function osc8Hyperlink(text: string, url: string | null, id?: string): string;
114
+ declare function osc8FilePath(text: string, filePath: string, line?: number, col?: number): string;
115
+ declare function osc52Write(text: string, clipboard?: 'c' | 'p'): void;
116
+ declare function osc52QuerySequence(clipboard?: 'c' | 'p'): string;
117
+ declare function beginSyncFrame(): void;
118
+ declare function endSyncFrame(): void;
119
+ declare function withSyncFrame<T>(fn: () => T): T;
120
+ //#endregion
121
+ //#region src/term/sync-output.d.ts
122
+ /**
123
+ * sync-output.ts — P3 anti-flicker:tmux 下剥离同步输出(BSU/ESU)。
124
+ *
125
+ * Ink v7 自带同步输出(DEC private mode 2026:ESC[?2026h 开 / ESC[?2026l 关),把整帧包成
126
+ * 原子写避免撕裂——这本是好事。但它仅按 `stdout.isTTY && interactive` 开关,不跳过 tmux;
127
+ * 部分 tmux 不可靠透传 ?2026(残留可见序列 / 嵌套语义错位)。故在 tmux 下禁用同步输出:
128
+ * tmux 环境下从写出流里剥掉整段(含 ESC)。
129
+ *
130
+ * Ink 无关闭同步输出的选项(`shouldSync()` 只读 isTTY+interactive),故用 stdout 代理在
131
+ * 写出层剥离——非 fork、零侵入,且仅 tmux 下启用,其余路径完全不受影响。
132
+ */
133
+ /** 剥离 DEC 2026 同步输出 begin/end 序列(BSU ESC[?2026h / ESU ESC[?2026l)。 */
134
+ declare function stripSyncSequences(s: string): string;
135
+ /** 包一层 stdout 代理:写出时剥离 ?2026,其余成员原样转发到真实流。 */
136
+ declare function stripSyncStdout(stdout: NodeJS.WriteStream): NodeJS.WriteStream;
137
+ /** 是否应在当前环境剥离同步输出:tmux 下默认开;`OTTO_TUI_SYNC=1` 可强制保留。 */
138
+ declare function shouldStripSyncOutput(env?: NodeJS.ProcessEnv): boolean;
139
+ //#endregion
140
+ //#region src/term/insert-history.d.ts
141
+ type InsertHistoryMode = 'standard' | 'raw';
142
+ type WrapPolicy = 'pre' | 'terminal';
143
+ interface InsertHistoryOptions {
144
+ /** 终端总行数。 */
145
+ rows: number;
146
+ /** 终端总列数(= 预换行宽度)。 */
147
+ columns: number;
148
+ /** Ink live 区顶部所在屏幕行(0-based)。历史插在它之上。
149
+ * live 区紧贴底部时 = rows - liveHeight。 */
150
+ liveTop: number;
151
+ /** 插入后光标还原位置(缺省 = live 区左上角 {0, liveTop})。 */
152
+ cursor?: {
153
+ x: number;
154
+ y: number;
155
+ };
156
+ /** 标准(DECSTBM 滚动区)/ raw(Zellij/老终端兜底,直写+预留空行)。 */
157
+ mode?: InsertHistoryMode;
158
+ /** pre = 我们按宽度预换行;terminal = 交给终端软换行。缺省 pre。 */
159
+ wrap?: WrapPolicy;
160
+ }
161
+ /** 可视宽度(剥 ANSI + CJK 宽字符占 2 + ambiguous-width 按终端 locale 校准)。 */
162
+ declare const displayWidth: (s: string) => number;
163
+ /**
164
+ * 把一条逻辑行预换行成若干物理行。
165
+ * - `terminal` 策略 / 宽度 ≤ 0:原样返回(交给终端软换行)。
166
+ * - 含 URL 的行:软换行(`hard:false`)——长 URL token 不被切断,可保持可点。
167
+ * - 普通散文行:硬换行(`hard:true`)——任何超宽行都被切到 ≤ 宽度,渲染可预测。
168
+ * 保留行首缩进(`trim:false`);空行→单个空物理行(保留段落间距)。
169
+ */
170
+ declare function preWrapLine(line: string, width: number, policy?: WrapPolicy): string[];
171
+ /** 把多条逻辑行展开为物理行序列。 */
172
+ declare function preWrapLines(lines: readonly string[], width: number, policy?: WrapPolicy): string[];
173
+ /**
174
+ * 生成把 `lines` 插进 scrollback(live 区之上)的转义序列。纯函数,不触 I/O。
175
+ * 返回空串表示无可写内容。
176
+ */
177
+ declare function insertHistorySequence(lines: readonly string[], opts: InsertHistoryOptions): string;
178
+ /** 写出历史插入序列到流(薄封装)。 */
179
+ declare function insertHistory(out: NodeJS.WriteStream, lines: readonly string[], opts: InsertHistoryOptions): void;
180
+ /** 按环境选模式:Zellij 走 raw,其余走标准 DECSTBM。 */
181
+ declare function pickInsertMode(env?: NodeJS.ProcessEnv): InsertHistoryMode;
182
+ //#endregion
183
+ //#region src/term/clear-guard.d.ts
184
+ /** 从一段输出里剥掉 scrollback 清除序列(`\x1b[3J`),保留其余清屏序列。 */
185
+ declare function stripScrollbackClear(s: string): string;
186
+ /** 包一层 stdout 代理:写出时剥掉 `\x1b[3J`,其余成员原样转发。 */
187
+ declare function guardScrollbackStdout(stdout: NodeJS.WriteStream): NodeJS.WriteStream;
188
+ //#endregion
189
+ //#region src/input/cursor.d.ts
190
+ /**
191
+ * cursor.ts — Immutable Cursor model (CC utils/Cursor.ts port).
192
+ * Intl.Segmenter grapheme boundaries, CJK width 2, ZWJ-aware via string-width v8.x.
193
+ * Two deltas: tab→width 1 special case; per-grapheme width cache (4096 entries).
194
+ */
195
+ declare function stringWidth(str: string): number;
196
+ declare class MeasuredText {
197
+ readonly text: string;
198
+ readonly columns: number;
199
+ readonly lines: string[];
200
+ private _graphemes?;
201
+ private _wordBreaks?;
202
+ constructor(text: string, columns: number);
203
+ get graphemeList(): Array<{
204
+ segment: string;
205
+ index: number;
206
+ }>;
207
+ get wordBreaks(): number[];
208
+ get lineCount(): number;
209
+ offsetToLineCol(offset: number): {
210
+ line: number;
211
+ col: number;
212
+ };
213
+ lineColToOffset(line: number, col: number): number;
214
+ }
215
+ declare class Cursor {
216
+ readonly measuredText: MeasuredText;
217
+ readonly offset: number;
218
+ readonly selection: number;
219
+ private constructor();
220
+ static fromText(text: string, columns: number, offset?: number): Cursor;
221
+ static fromCursor(cursor: Cursor, columns?: number): Cursor;
222
+ get text(): string;
223
+ get columns(): number;
224
+ get position(): {
225
+ line: number;
226
+ col: number;
227
+ };
228
+ get hasSelection(): boolean;
229
+ equals(other: Cursor): boolean;
230
+ right(): Cursor;
231
+ left(): Cursor;
232
+ up(): Cursor;
233
+ down(): Cursor;
234
+ prevWord(): Cursor;
235
+ nextWord(): Cursor;
236
+ insert(value: string): Cursor;
237
+ backspace(): Cursor;
238
+ delete(): Cursor;
239
+ killToLineEnd(): {
240
+ cursor: Cursor;
241
+ killed: string;
242
+ };
243
+ killToLineStart(): {
244
+ cursor: Cursor;
245
+ killed: string;
246
+ };
247
+ killWordBefore(): {
248
+ cursor: Cursor;
249
+ killed: string;
250
+ };
251
+ modifyText(end: number, ins?: string): Cursor;
252
+ deleteTokenBefore(): Cursor | null;
253
+ getViewportStartLine(maxVisible: number): number;
254
+ toEnd(): Cursor;
255
+ toStart(): Cursor;
256
+ toLineStart(): Cursor;
257
+ toLineEnd(): Cursor;
258
+ }
259
+ //#endregion
260
+ //#region src/input/text-input-logic.d.ts
261
+ interface EditKeyEvent {
262
+ name: string;
263
+ ctrl: boolean;
264
+ shift: boolean;
265
+ alt: boolean;
266
+ meta: boolean;
267
+ }
268
+ type EditAction = 'insert' | 'delete_backward' | 'delete_forward' | 'kill_to_end' | 'kill_to_start' | 'kill_word_before' | 'move_to_start' | 'move_to_end' | 'move_left' | 'move_right' | 'move_word_left' | 'move_word_right' | 'submit' | 'submit_force' | 'none' | 'clear_text';
269
+ interface EditResult {
270
+ cursor: Cursor;
271
+ action: EditAction;
272
+ killed?: string;
273
+ }
274
+ declare function handleEditingKey(cursor: Cursor, key: EditKeyEvent): EditResult | null;
275
+ declare function getKillRingEntries(): readonly string[];
276
+ declare function resetKillRing(): void;
277
+ declare function handleEditingKeyExtended(cursor: Cursor, key: EditKeyEvent): EditResult | null;
278
+ declare function shouldUseViewport(cursor: Cursor): boolean;
279
+ declare function getInputViewport(cursor: Cursor, maxVisible: number): {
280
+ startLine: number;
281
+ endLine: number;
282
+ visibleLines: string[];
283
+ cursorLine: number;
284
+ } | null;
285
+ //#endregion
286
+ //#region src/input/input-buffer.d.ts
287
+ /**
288
+ * input-buffer.ts — Undo snapshot stack (CC useInputBuffer port, M48-04).
289
+ * (renamed from useInputBuffer.ts — factory function, no React hooks; `use*` prefix was misleading)
290
+ *
291
+ * Module-level undo buffer: snapshot BEFORE each edit, ctrl+_ triggers undo.
292
+ *
293
+ * Constraints:
294
+ * - Time debounce 1000ms (not per-key)
295
+ * - Skip duplicates (same text+offset as top)
296
+ * - MAX=50 (slice(-50) on overflow)
297
+ * - No redo
298
+ * - Snapshot timing: "snapshot old value before change"
299
+ *
300
+ * Usage:
301
+ * const buf = createInputBuffer()
302
+ * buf.snapshot({ text: cursor.text, offset: cursor.offset }) // before edit
303
+ * const prev = buf.undo() // ctrl+_
304
+ */
305
+ interface BufferEntry {
306
+ text: string;
307
+ offset: number;
308
+ timestamp: number;
309
+ }
310
+ interface InputBuffer {
311
+ snapshot(state: {
312
+ text: string;
313
+ offset: number;
314
+ }): void;
315
+ undo(): BufferEntry | null;
316
+ readonly depth: number;
317
+ reset(): void;
318
+ }
319
+ declare function createInputBuffer(maxSize?: number): InputBuffer;
320
+ //#endregion
321
+ //#region src/input/history-provider.d.ts
322
+ interface SearchMatch {
323
+ entry: string;
324
+ matchStart: number;
325
+ matchEnd: number;
326
+ /** 非连续模糊命中区间(RFC-125 M125-4 高亮) */
327
+ highlightRanges?: HighlightRange[];
328
+ }
329
+ interface InputHistory {
330
+ push(entry: string): void;
331
+ navigateUp(currentDraft: string): string | null;
332
+ navigateDown(): string | null;
333
+ beginSearch(draft: string): void;
334
+ search(query: string): SearchMatch[];
335
+ acceptSearch(index: number): string | null;
336
+ cancelSearch(): string | null;
337
+ resetNavigation(): void;
338
+ readonly size: number;
339
+ /**
340
+ * 当前历史导航态。未导航(游标在底部草稿)时返回 null;
341
+ * 导航中返回 { position, total }——position 为「距最新的位置」(1=最近一条),
342
+ * total 为历史总条数。供会话头 HUD 展示「N/total + 当前条目」。
343
+ */
344
+ readonly navState: {
345
+ position: number;
346
+ total: number;
347
+ } | null;
348
+ /** 获取全部历史条目(最近在末尾)。/history 面板用。 */
349
+ getAll(): readonly string[];
350
+ clear(): void;
351
+ }
352
+ interface CreateInputHistoryOptions {
353
+ maxSize?: number;
354
+ initialEntries?: readonly string[];
355
+ }
356
+ declare function createInputHistory(options?: CreateInputHistoryOptions): InputHistory;
357
+ //#endregion
358
+ //#region src/input/TextInput.d.ts
359
+ type InputMode = 'send' | 'bash' | 'bash_async' | 'memory' | 'steer' | 'dialog';
360
+ interface TextInputProps {
361
+ value: string;
362
+ offset: number;
363
+ columns: number;
364
+ mode?: InputMode;
365
+ placeholder?: string;
366
+ maxVisibleLines?: number;
367
+ /** @deprecated 使用 tabIndex 替代。向后兼容:传入时覆盖 useTabable 结果。 */
368
+ focused?: boolean;
369
+ /** tabIndex for focus traversal(默认 -1 = 不参与 Tab 切换;0+ = 参与)。 */
370
+ tabIndex?: number;
371
+ /** 遮罩渲染(如 API Key)——显示为 '•' 占位,不回显明文;跳过 chip 高亮解析。 */
372
+ mask?: boolean;
373
+ /**
374
+ * 抑制模式前缀(RFC-273 D3)——调用方**自带前缀**时传 true,避免双前缀。
375
+ * 例:SelectDialog 的 filter 框外部已渲染 `/ ` 搜索前缀,此时 TextInput 不应再加 `> `。
376
+ */
377
+ noPrefix?: boolean;
378
+ /** 行内 dim ghost 补全后缀(RFC-128 Fish-like autosuggestion)。 */
379
+ ghostSuffix?: string;
380
+ /** RFC-198 §5.3:当前失效的粘贴引用 id 集合(`PasteStore.findMissingIds` 结果)——
381
+ * 命中的 `[@paste:#N]` chip 渲染为失效样式(错误色 + 删除线),不覆盖 `[@paste:image #N]`
382
+ * (image refs 不参与本机制,见 cursor.ts `parsePasteChipId` 头注释)。 */
383
+ invalidPasteIds?: ReadonlySet<number>;
384
+ /** RFC-311:根 Box 节点 ref——useMeasuredCursorOrigin 实测光标绝对原点用。
385
+ * 挂根(稳定节点)而非光标行(行节点 key 含内容、每帧重建);光标行相对根的
386
+ * 偏移由 computeCursorInline 同帧算出(与渲染结构逐行同源)。 */
387
+ containerRef?: React.Ref<DOMElement>;
388
+ /**
389
+ * RFC-317:是否声明**物理光标**(IME 候选框锚定的前提)。
390
+ *
391
+ * 默认 false(既有消费方行为不变)。为 true 时 TextInput 用**自身渲染期的几何
392
+ * 真值**(softWrap 结果 + 窗口化偏移)声明光标位置——不再由上层重算同一份几何,
393
+ * 消除双源漂移;且任何消费方挂上即得正确的候选框位置(RFC-317 下沉主旨)。
394
+ *
395
+ * 需要配合 containerRef(原点实测锚点)。
396
+ */
397
+ physicalCursor?: boolean;
398
+ /** 最近一次退格/删除键时刻——解除 IME 冻结闸武装(退格与 preedit 同样使 text
399
+ * 变短,必须用按键事件区分,否则删除时光标冻结在原位)。 */
400
+ deleteKeyAt?: number;
401
+ }
402
+ declare const TextInput: React.MemoExoticComponent<({
403
+ value,
404
+ offset,
405
+ columns,
406
+ mode,
407
+ placeholder,
408
+ maxVisibleLines,
409
+ focused: focusedProp,
410
+ tabIndex,
411
+ mask,
412
+ noPrefix,
413
+ ghostSuffix,
414
+ invalidPasteIds,
415
+ containerRef,
416
+ physicalCursor,
417
+ deleteKeyAt
418
+ }: TextInputProps) => React.ReactElement>;
419
+ //#endregion
420
+ //#region src/input/horizontal-step.d.ts
421
+ /**
422
+ * 横排按钮组的方向解算(单一真源)。
423
+ *
424
+ * 语义(对齐 Segmented.tsx / GalleryPane.tsx 既有正确实现):
425
+ * ← / Shift+Tab → -1(反向)
426
+ * → / Tab → +1(正向)
427
+ * 其余 → 0(不消费)
428
+ *
429
+ * 历史缺陷(RFC-289 §2.3):方向量曾写成 `key.shift && key.tab ? -1 : 1`,
430
+ * 只区分 Shift+Tab,导致 leftArrow 与 rightArrow 同走 +1——左箭头行为等同右箭头。
431
+ * 该写法被复制到 7 个 dialog,因测试只覆盖右箭头而长期未被发现。
432
+ */
433
+ declare function resolveHorizontalStep(key: Key): -1 | 0 | 1;
434
+ /** 环形步进:在 [0, count) 内按 step 回绕。 */
435
+ declare function cycleIndex(current: number, step: number, count: number): number;
436
+ //#endregion
437
+ //#region src/input/submit-routing.d.ts
438
+ type SubmitRoute = 'command' | 'steer' | 'queue' | 'send';
439
+ interface SubmitRouteCtx {
440
+ /** agent 是否正在跑(TUI 镜像态)。 */
441
+ processing: boolean;
442
+ /** 命令名(小写,无前导 /)是否为「本地立即处理、不起 agent 回合」的注册命令。 */
443
+ isImmediateCommand: (name: string) => boolean;
444
+ /**
445
+ * 命令名是否为「中止当前回合」命令(/abort 等)。这类命令的语义恰恰是**打断正在跑的回合**,
446
+ * 必须在运行中立即放行(否则被当普通斜杠命令入队→等回合自然跑完才回放,中止彻底失效)。
447
+ * cli 侧 onSubmit 据此直接走中断入口(等价 Ctrl+C),不起新回合、不污染处理态。
448
+ */
449
+ isInterruptCommand?: (name: string) => boolean;
450
+ }
451
+ /** 提取斜杠命令名(小写,无 /);非 send 模式或非 / 开头 → 空串。 */
452
+ declare function slashCommandName(text: string, mode: SubmitMode): string;
453
+ /**
454
+ * cli 端"有效忙"= 引擎 prompt in-flight(engineBusy=session.isBusy) **或** cli 处理周期内
455
+ * (cliProcessing=agentProcessing,含续轮循环)。取**或**是要害:续轮循环两轮 handleInput 之间
456
+ * engineBusy 会瞬时落 false,单看引擎会让续轮间隙的提交起 reentrant 新回合;cliProcessing 整个
457
+ * onSubmit 周期恒为 true(finally 复位,不 stuck),补上这段缝。**别简化成只看 engineBusy**(本函数即为
458
+ * 防该回退而存在,见 submit-routing.test.ts 的 (false,true)→true 断言)。
459
+ */
460
+ declare function effectiveBusy(engineBusy: boolean, cliProcessing: boolean): boolean;
461
+ declare function routeSubmit(text: string, mode: SubmitMode, force: boolean, ctx: SubmitRouteCtx): SubmitRoute;
462
+ //#endregion
463
+ //#region src/history/types.d.ts
464
+ interface HistoryEntry {
465
+ command: string;
466
+ /** unix 毫秒;部分源(如 bash plain)无时间戳 */
467
+ timestamp?: number;
468
+ source: string;
469
+ }
470
+ interface HistorySource {
471
+ readonly id: string;
472
+ load(): Promise<readonly HistoryEntry[]>;
473
+ }
474
+ interface MergedHistoryProvider {
475
+ /** 供 pickAutosuggestion / createInputHistory;旧→新,最新在末尾 */
476
+ getCommands(): readonly string[];
477
+ getEntries(): readonly HistoryEntry[];
478
+ }
479
+ //#endregion
480
+ //#region src/history/sensitive-patterns.d.ts
481
+ /** RFC-129 §3 D3:可选敏感行过滤(默认模式,可被配置覆盖) */
482
+ declare const DEFAULT_SENSITIVE_PATTERNS: readonly RegExp[];
483
+ declare function isSensitiveCommand(command: string, patterns?: readonly RegExp[]): boolean;
484
+ //#endregion
485
+ //#region src/history/zsh-history-parser.d.ts
486
+ declare const ZSH_HISTFILE_SOURCE = "zsh-histfile";
487
+ interface ParseZshHistoryOptions {
488
+ source?: string;
489
+ sensitivePatterns?: readonly RegExp[];
490
+ /** 为 true 时丢弃匹配 sensitivePatterns 的行 */
491
+ filterSensitive?: boolean;
492
+ }
493
+ /** 解析 zsh history 文件内容(extended + plain),纯函数、不读盘。 */
494
+ declare function parseZshHistory(content: string, options?: ParseZshHistoryOptions): HistoryEntry[];
495
+ declare function normalizeCommand(command: string): string;
496
+ //#endregion
497
+ //#region src/history/bash-history-parser.d.ts
498
+ declare const BASH_HISTFILE_SOURCE = "bash-histfile";
499
+ interface ParseBashHistoryOptions {
500
+ source?: string;
501
+ sensitivePatterns?: readonly RegExp[];
502
+ filterSensitive?: boolean;
503
+ }
504
+ /**
505
+ * 解析 bash history 文件(一行一条;可选 `#<unix_ts>` 时间戳行 + 命令行对)。
506
+ */
507
+ declare function parseBashHistory(content: string, options?: ParseBashHistoryOptions): HistoryEntry[];
508
+ //#endregion
509
+ //#region src/history/fish-history-parser.d.ts
510
+ declare const FISH_HISTFILE_SOURCE = "fish-histfile";
511
+ interface ParseFishHistoryOptions {
512
+ source?: string;
513
+ sensitivePatterns?: readonly RegExp[];
514
+ filterSensitive?: boolean;
515
+ }
516
+ /** 解析 fish history YAML 块(`- cmd:` / `when:`),纯函数。 */
517
+ declare function parseFishHistory(content: string, options?: ParseFishHistoryOptions): HistoryEntry[];
518
+ //#endregion
519
+ //#region src/history/merged-history-provider.d.ts
520
+ declare const OTTO_SESSION_SOURCE = "otto-session";
521
+ interface MergeHistoryOptions {
522
+ /** 合成时间戳起点,保证 otto 会话内顺序(旧→新) */
523
+ ottoTimestampBase?: number;
524
+ }
525
+ /** 合并 otto 会话历史与外部源;otto 同源优先,再比时间戳。 */
526
+ declare function mergeHistoryEntries(ottoSessionCommands: readonly string[], externalEntries: readonly HistoryEntry[], options?: MergeHistoryOptions): HistoryEntry[];
527
+ declare function entriesToCommands(entries: readonly HistoryEntry[]): string[];
528
+ declare function createMergedHistoryProvider(ottoSessionCommands: readonly string[], externalEntries: readonly HistoryEntry[], options?: MergeHistoryOptions): MergedHistoryProvider;
529
+ //#endregion
530
+ //#region src/panes/SigilPane.d.ts
531
+ interface SigilPaneProps {
532
+ /** 触发的 sigil(决定面板过滤哪一类)。 */
533
+ sigil: SigilPrefix;
534
+ /** 触发时的初始查询串(sigil 后已输入的字符)。 */
535
+ initialQuery: string;
536
+ /** 数据源(只读 search / searchAsync)。 */
537
+ registry: SigilSearchRegistry;
538
+ /** 键盘接管开关(focusOwner==='sigilPane' 时为 true)。 */
539
+ active: boolean;
540
+ /** 终端总行数(FileContentViewer 需要)。 */
541
+ rows: number;
542
+ /** 过滤输入框可用列宽(Cursor 折行计算需要,缺省 60,对齐 InputDialog/SelectDialog 默认值)。 */
543
+ columns?: number;
544
+ /**
545
+ * 终端总列宽(RFC-187:@file 全文查看候选视图预折行需要,与 `columns`——过滤框可用
546
+ * 列宽——语义不同,不能复用;缺省 80,同 EditedFileFullPane/ExtensionDetailDialog)。
547
+ */
548
+ viewerColumns?: number;
549
+ /** 选中条目。 */
550
+ onSelect: (entry: SigilEntry) => void;
551
+ /** 关闭面板(Esc,或空过滤再退格删 sigil)。deletedSigil 表示是否应连带删除 sigil 字符。 */
552
+ onClose: (opts: {
553
+ deleteSigil: boolean;
554
+ }) => void;
555
+ /**
556
+ * 覆盖默认标题。缺省按 sigil 前缀:@ → 提及,# → 标签。
557
+ * Ctrl+R / /history 历史搜索模式用「历史」(history.label)覆盖。
558
+ */
559
+ title?: string;
560
+ /** 过滤串变化(用于 App 同步「面板内输入」到 prompt 文本,可选)。 */
561
+ onQueryChange?: (query: string) => void;
562
+ /**
563
+ * 读取文件全文(用于 @file 条目的 FileContentViewer 预览)。
564
+ * 未提供时 file 条目回退到 preview 截断文本(旧行为)。
565
+ *
566
+ * `truncated=true`(RFC-189 追加修复:`readFileCapped` 读取层熔断场景)时
567
+ * `resolveFileContentViews` 须强制走大文件降级候选,见下方 `preTruncated` 用法。
568
+ */
569
+ readFileContent?: (path: string) => Promise<{
570
+ content: string;
571
+ truncated: boolean;
572
+ }>;
573
+ /**
574
+ * 最近选中的条目(MRU,跨 kind 混合,最多 RECENT_MAX 条,最近在前)。
575
+ * 仅在过滤框为空(`query === ''`)时置顶展示为独立「最近使用」分组——一旦用户开始
576
+ * 输入过滤字符,该分组让位给正常按 kind 分组的搜索结果(对齐 /model 面板的
577
+ * MRU 心智,但只在空查询时出现,避免与真实搜索结果的分组次序混淆)。
578
+ * 与 registry 搜索结果不去重(同一条目可能同时出现在「最近使用」与其原生分组里,
579
+ * 对齐 /model recentOptions 同款设计)。
580
+ */
581
+ recentEntries?: SigilEntry[];
582
+ }
583
+ declare function SigilPane({
584
+ sigil,
585
+ initialQuery,
586
+ registry,
587
+ active,
588
+ rows,
589
+ columns,
590
+ viewerColumns,
591
+ onSelect,
592
+ onClose,
593
+ onQueryChange,
594
+ readFileContent,
595
+ recentEntries,
596
+ title
597
+ }: SigilPaneProps): React.ReactElement;
598
+ //#endregion
599
+ //#region src/messages/stream-commit.d.ts
600
+ /**
601
+ * stream-commit.ts — P0 anti-flicker:流式正文「已稳定块」增量提交模型。
602
+ *
603
+ * 背景:把整轮不断增高、且每帧回流的流式正文留在动态区,是 Ink TUI 闪烁的主因。
604
+ * 采用 scrollback-aware 增量提交(滚动区把完成行推进 scrollback,配合稳定/尾段切分)——
605
+ * 核心是「已完成内容尽快离开动态区,永不再画」。
606
+ *
607
+ * 本模块是纯函数状态机:喂入累计全文,吐出「应提交进 <Static> 的新块」+「仍需动态
608
+ * 渲染的未稳定尾段」。startTui 据此把块推进 messages(走 Static 一次性渲染),动态区
609
+ * 只剩尾段→高度恒定→消闪烁。纯函数便于单测,且是唯一真源(startTui 仅做适配)。
610
+ */
611
+ /** 可安全提交的边界:最后一个不在未闭合代码围栏内的空行(\n\n)之后的位置。 */
612
+ declare function safeCommitBoundary(text: string): number;
613
+ interface StreamCommitState {
614
+ /** 本回复累计全文(最近一次 step 入参) */
615
+ prev: string;
616
+ /** 已提交进 Static 的字节数 */
617
+ committedLen: number;
618
+ /** 本回复是否已提交首块(决定续块 lead 标志) */
619
+ led: boolean;
620
+ }
621
+ interface StreamChunk {
622
+ text: string;
623
+ /** 该回复首块 → 渲 ⏺ 圆点;续块对齐缩进无圆点 */
624
+ lead: boolean;
625
+ }
626
+ interface StreamCommitResult {
627
+ /** 本次新产生、应追加进 Static 的块(按序) */
628
+ chunks: StreamChunk[];
629
+ /** 仍需动态渲染的未稳定尾段 */
630
+ tail: string;
631
+ /** 新状态(喂给下一次 step) */
632
+ state: StreamCommitState;
633
+ }
634
+ declare function initStreamCommit(): StreamCommitState;
635
+ /**
636
+ * 喂入累计全文 t(空串 = 块/回合结束,收尾残余尾段)。
637
+ * 返回新提交块 + 动态尾段 + 新状态。纯函数,无副作用。
638
+ */
639
+ declare function streamCommitStep(s: StreamCommitState, t: string): StreamCommitResult;
640
+ //#endregion
641
+ //#region src/messages/stream-coalesce.d.ts
642
+ declare const STREAM_COALESCE_MS: number;
643
+ interface Coalescer {
644
+ /** immediate=true 时立即 flush 挂起值并同步 apply(v)(用于 finalize)。 */
645
+ push(v: string, immediate: boolean): void;
646
+ /** 取消挂起的定时器(unmount/stop 时调用)。 */
647
+ cancel(): void;
648
+ }
649
+ declare function makeCoalescer(apply: (v: string) => void, intervalMs?: number): Coalescer;
650
+ //#endregion
651
+ //#region src/messages/query-guard.d.ts
652
+ /**
653
+ * query-guard.ts — Generation-counting state machine (M49-02).
654
+ * Prevents stale async finally blocks from corrupting state.
655
+ */
656
+ type GuardState = 'idle' | 'dispatching' | 'running';
657
+ interface QueryGuard {
658
+ reserve(): boolean;
659
+ /** Cancel reservation (dispatching→idle, no gen bump). Used when await fails before tryStart. */
660
+ cancelReservation(): void;
661
+ tryStart(): number;
662
+ end(generation: number, callback?: () => void): void;
663
+ forceEnd(): void;
664
+ readonly state: GuardState;
665
+ readonly generation: number;
666
+ readonly isRunning: boolean;
667
+ subscribe(listener: () => void): () => void;
668
+ reset(): void;
669
+ }
670
+ declare function createQueryGuard(): QueryGuard;
671
+ //#endregion
672
+ //#region src/messages/collapse.d.ts
673
+ interface CollapsedBlock {
674
+ type: 'collapsed';
675
+ messages: AssistantMessage[];
676
+ summary: string;
677
+ collapsed: boolean;
678
+ }
679
+ type CollapsibleMessage = AssistantMessage | CollapsedBlock;
680
+ declare function collapseMessages(msgs: AssistantMessage[], threshold?: number): CollapsibleMessage[];
681
+ declare function toggleCollapse(block: CollapsedBlock): CollapsedBlock;
682
+ declare function expandCollapsed(msgs: CollapsibleMessage[]): AssistantMessage[];
683
+ //#endregion
684
+ //#region src/messages/Message.d.ts
685
+ interface MessageProps {
686
+ message: ChatMessage;
687
+ columns?: number;
688
+ }
689
+ declare function MessageView({
690
+ message,
691
+ columns
692
+ }: MessageProps): React.ReactElement;
693
+ declare const Message: React.MemoExoticComponent<typeof MessageView>;
694
+ //#endregion
695
+ //#region src/stores/scroll-store.d.ts
696
+ interface ScrollState {
697
+ /** 距底部行数(0 = 贴底 follow;> 0 = 回看态)。 */
698
+ offset: number;
699
+ /** 内容总行数(消费方上报——上界 clamp 防 overscroll 死区)。 */
700
+ totalLines: number;
701
+ }
702
+ interface ScrollStore {
703
+ store: Store<ScrollState>;
704
+ /** 相对滚动(正 = 向更早/上方,负 = 向最新/下方)。clamp 由渲染端 computeScrollWindow 保证。 */
705
+ scrollBy(delta: number): void;
706
+ /** 翻一页(一屏行数)。dir=1 向更早,-1 向最新。 */
707
+ page(dir: 1 | -1, rows: number): void;
708
+ /** 跳到最早(顶部)。 */
709
+ toTop(): void;
710
+ /** 回 live(offset=0,follow 恢复)。 */
711
+ toBottom(): void;
712
+ /** RFC-300 M3a:绝对定位(find 导航跳转用——目标 offset 由渲染端换算传入)。 */
713
+ setOffset(n: number): void;
714
+ /** RFC-300 终局(A⑤ overscroll 死区):上报内容总行数——scrollBy/page 上界 clamp。 */
715
+ setTotalLines(n: number): void;
716
+ /**
717
+ * RFC-300 M3c:滚轮事件总线——其他滚动视图(FileContentViewer 等)mount 时
718
+ * 注册滚轮回调(delta=±1/格),main.ts 的 wheelCoalescer 把滚轮事件分发给
719
+ * 当前持焦视图。返回注销函数。
720
+ */
721
+ registerWheel(handler: (delta: number) => void): () => void;
722
+ /** RFC-300 M3c:把滚轮事件分发给最近注册的订阅者(视图栈顶——当前焦点视图)。 */
723
+ dispatchWheel(delta: number): boolean;
724
+ }
725
+ //#endregion
726
+ //#region src/stores/stream-store.d.ts
727
+ interface StreamState {
728
+ streamingText: string;
729
+ streamingThinking: string;
730
+ streamCommit: StreamCommitState;
731
+ /** 上一次流式尾段(scrollback 模式 streamControllerStep 用于判断是否需要重渲)。 */
732
+ lastTail: string | undefined;
733
+ spinnerMode: 'requesting' | 'responding' | null;
734
+ outputTokensThisTurn: number;
735
+ maxOutputTokens: number | undefined;
736
+ toolTurnCount: number;
737
+ maxToolTurns: number;
738
+ promptOutputTokens: number;
739
+ promptOutputTokenBudget: number;
740
+ processing: boolean;
741
+ activeTool: string | null;
742
+ }
743
+ interface StreamStore {
744
+ store: Store<StreamState>;
745
+ /** `/clear`(clearSession)用:重置全部 13 字段到初始值(覆盖迁移前只重置 3 个的缺口)。 */
746
+ reset(): void;
747
+ }
748
+ //#endregion
749
+ //#region src/messages/REPLRegion.d.ts
750
+ interface REPLRegionProps {
751
+ streamStore: StreamStore;
752
+ completedMessages: ChatMessage[];
753
+ columns?: number;
754
+ rows?: number;
755
+ maxPreviewRows?: number;
756
+ suppressLive?: boolean;
757
+ /** RFC-283 D1:pending echo 在 live 区渲染(灰色),转正时由 clearPendingEcho commit 到 scrollback。 */
758
+ pendingEcho?: {
759
+ text: string;
760
+ mode: string;
761
+ } | null;
762
+ /** scrollback 模式(OTTO_TUI_SCROLLBACK=1):pending echo 不进 store,仅靠 live 区渲染。
763
+ * 非 scrollback(窗口模式/legacy Static)下 echoUserInput 已把 streaming:true 消息 append
764
+ * 进 store(转录区渲染),此处不得再画 live 行——否则同一条 prompt 双回显(真实用户反馈)。 */
765
+ scrollbackMode?: boolean;
766
+ /** RFC-337 D3:待定 steer(运行中追加)在 live 区渲染(灰色),转正/撤回时移除。 */
767
+ pendingSteers?: readonly {
768
+ text: string;
769
+ id: string;
770
+ }[];
771
+ /** RFC-300 D1:窗口模式(默认)——已完成消息走 ScrollableTranscript 窗口渲染(可滚动/可回看);
772
+ * legacy Static 模式(OTTO_TUI_SCROLLBACK=0)保持 <Static> 全量渲染。 */
773
+ windowMode?: boolean;
774
+ /** RFC-300 M1b:对话流滚动状态(回看态 offset;0=贴底 follow)。 */
775
+ scrollStore: ScrollStore;
776
+ /** RFC-300 M2:补页状态与回调(App 层编排)。 */
777
+ earlierLoading?: boolean;
778
+ earlierEnded?: boolean;
779
+ onNeedEarlier?: () => void;
780
+ onPrepend?: (deltaLines: number) => void;
781
+ /** RFC-300 M3a:find 搜索(query/活跃匹配/导航)。 */
782
+ findQuery?: string;
783
+ findActiveMatch?: number;
784
+ onFindNavigateTo?: (offset: number) => void;
785
+ onFindCountChange?: (count: number) => void;
786
+ onReviewHintChange?: (hint: string | null) => void;
787
+ renderReviewHint?: boolean;
788
+ }
789
+ declare function REPLRegion({
790
+ streamStore,
791
+ completedMessages,
792
+ columns,
793
+ rows,
794
+ maxPreviewRows,
795
+ suppressLive,
796
+ pendingEcho,
797
+ scrollbackMode,
798
+ pendingSteers,
799
+ windowMode,
800
+ scrollStore,
801
+ earlierLoading,
802
+ earlierEnded,
803
+ onNeedEarlier,
804
+ onPrepend,
805
+ findQuery,
806
+ findActiveMatch,
807
+ onFindNavigateTo,
808
+ onFindCountChange,
809
+ onReviewHintChange,
810
+ renderReviewHint
811
+ }: REPLRegionProps): React.ReactElement;
812
+ //#endregion
813
+ //#region src/messages/diff-logic.d.ts
814
+ /**
815
+ * diff-logic.ts — Pure diff logic (no React). Extracted from StructuredDiff for testability.
816
+ */
817
+ interface DiffHunkLine {
818
+ type: 'add' | 'remove' | 'context';
819
+ content: string;
820
+ oldLine?: number;
821
+ newLine?: number;
822
+ wordSegments?: Array<{
823
+ text: string;
824
+ changed: boolean;
825
+ }>;
826
+ }
827
+ interface DiffHunk {
828
+ header: string;
829
+ lines: DiffHunkLine[];
830
+ }
831
+ //#endregion
832
+ //#region src/messages/message-lines.d.ts
833
+ /**
834
+ * 一条消息 → ANSI 文本行(去首尾空行)。Mode A 提交路径与 B 模式 <Message> 薄包共用此单一真源。
835
+ */
836
+ declare function renderMessageLines(message: unknown, columns?: number): string[];
837
+ //#endregion
838
+ //#region src/messages/markdown-typography.d.ts
839
+ interface MarkdownTypographyTheme {
840
+ /** H1 标题色(默认 accent)。 */
841
+ heading1: string;
842
+ /** H2 标题色(默认 secondary)。 */
843
+ heading2: string;
844
+ /** H5/H6 弱标题色(默认 inactive)。H3/H4 不着色,只 bold,不在此收口。 */
845
+ headingWeak: string;
846
+ /** 一级列表 marker 色(默认 secondary)。 */
847
+ listMarkerPrimary: string;
848
+ /** 二级及以下列表 marker 色(默认 inactive)。 */
849
+ listMarkerMuted: string;
850
+ /** 引用竖条色(默认 accentDim)。 */
851
+ quoteBar: string;
852
+ /** 引用正文色(默认 secondary)。 */
853
+ quoteText: string;
854
+ /** 链接色(默认 accentBright)。 */
855
+ link: string;
856
+ /** 行内 code 色(默认 codeText)。 */
857
+ inlineCode: string;
858
+ /** code fence divider 色(默认 inactive)。 */
859
+ codeFenceDivider: string;
860
+ /** 表格 header/竖屏 fallback key 色(默认 secondary)。 */
861
+ tableHeader: string;
862
+ /** 表格 divider 色(默认 inactive)。 */
863
+ tableDivider: string;
864
+ /** 列表每层缩进(RFC-276 D3:默认 2,M3 暂不接入 override 生效路径,仅保留字段)。 */
865
+ listIndent: 2 | 3;
866
+ /** 无序列表按深度轮换的 marker 字形,必须全部单宽。 */
867
+ listMarkers: readonly [string, string, string, string];
868
+ /** code fence divider 开关(默认 'hr';'none' 时只隐藏 divider,不影响 line-number gutter)。 */
869
+ codeBlockDivider: 'hr' | 'none';
870
+ /** H1 divider 色——不可覆盖的固定装饰色,仍统一走本函数解析。 */
871
+ h1Divider: string;
872
+ /** 纯 `---` 水平线色——不可覆盖。 */
873
+ hr: string;
874
+ /** code block 行号 gutter 色——不可覆盖(RFC-021 基石特性,不受 preset 影响)。 */
875
+ codeGutter: string;
876
+ /** code block language label 色——不可覆盖。 */
877
+ codeLabel: string;
878
+ /** 表格正文/value 色——不可覆盖。 */
879
+ tableBody: string | undefined;
880
+ /** task list 已勾选 checkbox 色——不可覆盖(状态语义色 success,非排版角色,不在 D3 覆盖面内)。 */
881
+ taskChecked: string;
882
+ }
883
+ declare function setMarkdownThemeUserOverrides(overrides: MarkdownThemeOverrides | undefined): void;
884
+ declare function getMarkdownThemeUserOverrides(): MarkdownThemeOverrides | undefined;
885
+ //#endregion
886
+ //#region src/messages/markdown-to-lines.d.ts
887
+ /**
888
+ * 行内:走 marked 行内 token → 带 ANSI(plain=true 仅取文本,剥样式)。
889
+ * 真解析器正确处理:嵌套强调(`**粗 *斜***`)、转义(`\*`)、代码 span 内标记不被吃(`` `a*b*` ``)。
890
+ */
891
+ declare function renderInline(line: string, plain?: boolean, typography?: MarkdownTypographyTheme): string;
892
+ declare function renderMarkdownToLines(text: string, columns?: number, typography?: MarkdownTypographyTheme): string[];
893
+ //#endregion
894
+ //#region src/messages/transcript-text.d.ts
895
+ /**
896
+ * 渲染纯文本转录。`streamingText` 为当前 turn 尚未落入 messages 的 in-flight 流式尾巴(可选)。
897
+ * 块间空行分隔;user=`▸ you`、assistant=`⏺ assistant`(thinking 前缀 `∴`)、tool=`⎿ name → result`。
898
+ *
899
+ * 下方 switch 无 `default` 分支——本函数专供子代理观测面板(DelegateOutputPane)的纯文本
900
+ * 转录导出,边界类消息(`compact_boundary`/`prune_boundary`/`history_capped`/`model_switch`/
901
+ * `model_fallback`/`tool_completion`/`pane`/`write_lease_denied`/`write_lease_restored`)
902
+ * 有意静默丢弃,不进纯文本导出(这些是主转录流的 UI 提示层,子代理观测面板只关心
903
+ * user/assistant/tool 三类实质对话内容)。9 类消息统一按此约定处理,非遗漏——独立 review
904
+ * 已核实一致性(2026-07-12;write_lease_* 于 2026-07-14 修复新增时复核仍适用同一约定)。
905
+ */
906
+ declare function formatTranscriptText(messages: ChatMessage[], streamingText?: string): string;
907
+ //#endregion
908
+ //#region src/messages/key-value-lines.d.ts
909
+ /** 一行键值对:`label: value`。 */
910
+ interface KeyValueRow {
911
+ label: string;
912
+ value: string;
913
+ }
914
+ type KeyValueEntry = KeyValueRow | null;
915
+ /**
916
+ * Format entries into aligned text lines for openModal({ kind: 'info', lines }).
917
+ * label column aligned by max displayWidth; null → empty line.
918
+ */
919
+ declare function formatKeyValueLines(entries: readonly KeyValueEntry[]): string[];
920
+ //#endregion
921
+ //#region src/dialogs/SelectPrimitive.d.ts
922
+ interface SelectItemProps {
923
+ value: string;
924
+ disabled?: boolean;
925
+ /** 附加说明(渲染为选中项下方一行弱化色文本,对齐 `SelectOption.detail`)。 */
926
+ detail?: string;
927
+ /** 条目行前导空白(默认一个空格)。 */
928
+ indent?: string;
929
+ /**
930
+ * 序号标记:`'number'` 渲染该项在整个列表中的序数(1-based,跨分组连续计数);
931
+ * `'-'` / `'·'` 渲染固定项目符。不传 = 不渲染标记(默认现状)。
932
+ */
933
+ marker?: 'number' | '-' | '·';
934
+ /** 行内尾随文案(同一行右侧,非另起一行的 `detail`)。 */
935
+ trailingLabel?: string;
936
+ /** `trailingLabel` 的颜色(默认 colors.inactive)。 */
937
+ trailingColor?: string;
938
+ /** label 颜色覆盖(独立于 `disabled`,不追加任何文案后缀)。 */
939
+ labelColor?: string;
940
+ children: React.ReactNode;
941
+ }
942
+ /** 单个可选条目。本身不渲染——`Select.Root` 遍历 children 树时提取其 props 编译为 `SelectOption`。 */
943
+ declare function SelectItem(_props: SelectItemProps): null;
944
+ declare namespace SelectItem {
945
+ var displayName: string;
946
+ }
947
+ interface SelectLabelProps {
948
+ children: React.ReactNode;
949
+ }
950
+ /** 分组标题。本身不渲染——`Select.Group` 读取其 children 文本作为分组标签。 */
951
+ declare function SelectLabel(_props: SelectLabelProps): null;
952
+ declare namespace SelectLabel {
953
+ var displayName: string;
954
+ }
955
+ interface SelectGroupProps {
956
+ children: React.ReactNode;
957
+ }
958
+ /** 分组容器:内部第一个 `Select.Label` 作为组标签,其余 `Select.Item` 归入该组。 */
959
+ declare function SelectGroup(_props: SelectGroupProps): null;
960
+ declare namespace SelectGroup {
961
+ var displayName: string;
962
+ }
963
+ /** 视觉分隔(渲染为一行空白,供顶层 `Select.Group` 之间留白)。本身不渲染——仅作 children 树标记。 */
964
+ declare function SelectSeparator(): null;
965
+ declare namespace SelectSeparator {
966
+ var displayName: string;
967
+ }
968
+ /** 结构占位符:无内联展开/popover 定位场景,仅透传 children 供 `Select.Root` 直接消费。 */
969
+ declare function SelectContent({
970
+ children
971
+ }: {
972
+ children: React.ReactNode;
973
+ }): React.ReactElement;
974
+ declare namespace SelectContent {
975
+ var displayName: string;
976
+ }
977
+ /** 结构占位符:本仓无"点击展开"交互,Trigger 不渲染任何内容(openModal 已在外层触发展开)。 */
978
+ declare function SelectTrigger(_props: {
979
+ children?: React.ReactNode;
980
+ }): null;
981
+ declare namespace SelectTrigger {
982
+ var displayName: string;
983
+ }
984
+ interface SelectRootProps {
985
+ /** 标题行(DialogFrame header,可选)。 */
986
+ title?: string;
987
+ /** 副标题(弱化色,标题下一行,可选)。 */
988
+ subtitle?: string;
989
+ /**
990
+ * 标题下的可聚焦入口(对齐 `/model` 的「N 个 provider 插件待授权 [ 去授权 ]」提示范式,
991
+ * 即 `SelectDialog` 的 `subtitle && hasActions` 分支)——渲染为 accent 边框盒:
992
+ * `hint` 提示文案 + 行内 `[ label ]` ghost 按钮,位于 subtitle 之下、列表之上。
993
+ * 焦点机:列表首项 ↑ → 入口;入口 ↓ → 列表首项;入口 Enter → 触发 `onPress`
994
+ * (不经 onValueChange,语义是"列表外的动作")。缺省无入口,行为不变。
995
+ */
996
+ headerAction?: {
997
+ hint: string;
998
+ label: string;
999
+ onPress: () => void;
1000
+ };
1001
+ /** 受控选中值;不传则内部自持状态(对齐 Radix `defaultValue`/`value` 双模式,本组件仅支持 defaultValue 语义)。 */
1002
+ defaultValue?: string;
1003
+ /** 选中值变化回调(Enter 确认时触发,而非每次移动都触发——对齐 SelectDialog 现有语义)。 */
1004
+ onValueChange?: (value: string) => void;
1005
+ /** 取消回调(Esc)。 */
1006
+ onCancel?: () => void;
1007
+ /** 单屏可见条目数(默认 10,对齐 SelectDialog)。 */
1008
+ maxVisible?: number;
1009
+ /** 底部快捷键提示(不传则用默认 ↑↓/Enter/Esc 三件套)。 */
1010
+ footer?: React.ReactNode;
1011
+ /** 是否持有键盘焦点(对齐仓库"焦点门禁"惯例,默认 true)。 */
1012
+ active?: boolean;
1013
+ /**
1014
+ * 扩展键盘处理器(对齐 `FileContentViewer.onKey` 先例):在标准 ↑↓/Enter/Esc/数字直达
1015
+ * 之前调用,收到当前选中项(可能为 `null`,如空列表);返回 `true` 表示已消费,
1016
+ * 本次按键不再进入标准 select 键位处理(用于扩展如"d 删除选中项"这类消费方自定义动作)。
1017
+ */
1018
+ onKey?: (input: string, key: Key, selected: SelectOption | null) => boolean;
1019
+ /**
1020
+ * 是否套 `DialogFrame` 独立边框(默认 `true`)。传 `false` 时不渲染边框/背景/内边距,
1021
+ * 仅输出 header + rows + footer 三段裸内容——供已有自己外层容器的消费方(如 Welcome
1022
+ * 启动横幅)嵌入复用同一套分组/条目视觉规范,避免双层边框。
1023
+ */
1024
+ frame?: boolean;
1025
+ /**
1026
+ * 是否渲染选中态高亮(默认 `true`)。传 `false` 时所有条目按各自 disabled 态着色,
1027
+ * 不应用 `colors.selection`——供纯展示(无键盘导航意义)场景使用,如 `active=false`
1028
+ * 的静态列表,避免出现"看起来被选中"但实际不可交互的视觉误导。
1029
+ */
1030
+ highlightSelection?: boolean;
1031
+ /** 终端总行数(RFC-301 窗口上限)。缺省 24。 */
1032
+ rows?: number;
1033
+ /**
1034
+ * extension 家族专用高度模式(优化 2026-08-09 用户定稿):总帧高上限 rows/3
1035
+ * (更紧于全局 RFC-301 的 2/5),透传给 DialogFrame.maxHeight。true 时窗口预算
1036
+ * 同步按 1/3 预算重算(不再叠加 15 min),避免窗口本身已经顶到 min 15 超出上限
1037
+ * 再被 maxHeight 硬切。其他消费方保持全局 2/5 不受影响。
1038
+ */
1039
+ extensionHeightBudget?: boolean;
1040
+ /**
1041
+ * detail 排布位置——对齐 SelectDialog 同名 prop:
1042
+ * `'below'`(缺省)detail 独占条目下方一行;
1043
+ * `'inline'` label → trailingLabel → detail 三列同行左对齐(各自按全表最大宽度 pad)。
1044
+ * 缺省 below 保持现有行为不变;inline 适用于 KeybindingsDialog 等需要键位+说明同行的场景。
1045
+ */
1046
+ detailPlacement?: 'below' | 'inline';
1047
+ children: React.ReactNode;
1048
+ }
1049
+ declare function SelectRoot({
1050
+ title,
1051
+ subtitle,
1052
+ headerAction,
1053
+ defaultValue,
1054
+ onValueChange,
1055
+ onCancel,
1056
+ maxVisible,
1057
+ footer,
1058
+ active,
1059
+ onKey,
1060
+ frame,
1061
+ highlightSelection,
1062
+ rows,
1063
+ extensionHeightBudget,
1064
+ detailPlacement,
1065
+ children
1066
+ }: SelectRootProps): React.ReactElement;
1067
+ /** `Select.*` 命名空间导出(对齐 `<Select.Root><Select.Group>…` 组合语法)。 */
1068
+ declare const Select: {
1069
+ Root: typeof SelectRoot;
1070
+ Trigger: typeof SelectTrigger;
1071
+ Content: typeof SelectContent;
1072
+ Group: typeof SelectGroup;
1073
+ Label: typeof SelectLabel;
1074
+ Item: typeof SelectItem;
1075
+ Separator: typeof SelectSeparator;
1076
+ };
1077
+ //#endregion
1078
+ //#region src/dialogs/PermissionDialog.d.ts
1079
+ interface PermissionDialogProps {
1080
+ tool: string;
1081
+ input: string;
1082
+ risk: 'low' | 'medium' | 'high';
1083
+ onApprove: (mode?: 'once' | 'always') => void;
1084
+ onDeny: () => void;
1085
+ }
1086
+ declare function PermissionDialog({
1087
+ tool,
1088
+ input,
1089
+ risk,
1090
+ onApprove,
1091
+ onDeny
1092
+ }: PermissionDialogProps): React.ReactElement;
1093
+ //#endregion
1094
+ //#region src/dialogs/BashPermissionDialog.d.ts
1095
+ interface BashPermissionDialogProps {
1096
+ command: string;
1097
+ risk: 'low' | 'medium' | 'high';
1098
+ /** 模型生成的命令解释文本 */
1099
+ description?: string;
1100
+ /** 「始终允许」拟记住的命令前缀(如 `git status`);显式呈现避免盲授权。 */
1101
+ alwaysAllowLabel?: string;
1102
+ onApprove: (mode?: 'once' | 'always') => void;
1103
+ onDeny: () => void;
1104
+ }
1105
+ declare function BashPermissionDialog({
1106
+ command,
1107
+ risk,
1108
+ description,
1109
+ alwaysAllowLabel,
1110
+ onApprove,
1111
+ onDeny
1112
+ }: BashPermissionDialogProps): React.ReactElement;
1113
+ //#endregion
1114
+ //#region src/dialogs/AlertDialog.d.ts
1115
+ interface AlertDialogProps {
1116
+ title: string;
1117
+ /** 正文(单行或多行)。 */
1118
+ message: string | string[];
1119
+ /** OK 按钮文案(默认 i18next.t('common.okButton'))。 */
1120
+ okLabel?: string;
1121
+ onOk: () => void;
1122
+ }
1123
+ declare function AlertDialog({
1124
+ title,
1125
+ message,
1126
+ okLabel,
1127
+ onOk
1128
+ }: AlertDialogProps): React.ReactElement;
1129
+ //#endregion
1130
+ //#region src/dialogs/PromptDialog.d.ts
1131
+ interface PromptDialogProps {
1132
+ title?: string;
1133
+ /** 提示正文(单行或多行)。 */
1134
+ message?: string | string[];
1135
+ /** 输入框占位符。 */
1136
+ placeholder?: string;
1137
+ /** 初始值。 */
1138
+ initialValue?: string;
1139
+ /** 提交按钮文案(默认 i18next.t('prompt.submitButton'))。 */
1140
+ submitLabel?: string;
1141
+ /** 取消按钮文案(默认 i18next.t('common.genericCancelButton'))。 */
1142
+ cancelLabel?: string;
1143
+ /** 输入框可用列宽(Cursor 折行计算需要,缺省 60,对齐 InputDialog 默认值)。 */
1144
+ columns?: number;
1145
+ onSubmit: (value: string) => void;
1146
+ onCancel: () => void;
1147
+ }
1148
+ declare function PromptDialog({
1149
+ title,
1150
+ message,
1151
+ placeholder,
1152
+ initialValue,
1153
+ submitLabel,
1154
+ cancelLabel,
1155
+ columns,
1156
+ onSubmit,
1157
+ onCancel
1158
+ }: PromptDialogProps): React.ReactElement;
1159
+ //#endregion
1160
+ //#region src/stores/compaction-log-store.d.ts
1161
+ interface CompactionLogEntry {
1162
+ /** 单调递增 id(store 内生成,供列表 key 与详情选中定位)。 */
1163
+ id: number;
1164
+ timestamp: number;
1165
+ kind: 'compact' | 'prune' | 'history_capped';
1166
+ /** compact:压缩前消息数;prune/history_capped 不适用。 */
1167
+ before?: number;
1168
+ /** compact:压缩后消息数。 */
1169
+ after?: number;
1170
+ /** compact:完整摘要文本(详情视图展示;列表视图只显示计数)。 */
1171
+ summary?: string;
1172
+ /** prune:节省的 token 数。 */
1173
+ tokensSaved?: number;
1174
+ /** prune:本次裁剪的工具输出条数。 */
1175
+ prunedCount?: number;
1176
+ /** history_capped:物理删除的消息条目数。 */
1177
+ removedCount?: number;
1178
+ }
1179
+ interface CompactionLogState {
1180
+ entries: CompactionLogEntry[];
1181
+ }
1182
+ interface CompactionLogStore {
1183
+ store: Store<CompactionLogState>;
1184
+ /** RFC-256 收尾:面板可见性由 Router 栈单一真源派生(isInStack('/pane/compaction-log')),
1185
+ * store 不再持 `open` 布尔——原 toggle() 已删除。 */
1186
+ /** 记一条压缩事件(CLI 订阅 compaction.end 时调用)。 */
1187
+ recordCompaction(before: number, after: number, summary?: string): void;
1188
+ /** 记一条裁剪事件(CLI 订阅 memory.pruned 时调用)。 */
1189
+ recordPrune(tokensSaved: number, prunedCount?: number): void;
1190
+ /** 记一条历史封顶事件(CLI 订阅 session.history-capped 时调用)。 */
1191
+ recordHistoryCapped(removedCount: number): void;
1192
+ }
1193
+ //#endregion
1194
+ //#region src/stores/gallery-store.d.ts
1195
+ interface GalleryState {
1196
+ categoryIndex: number;
1197
+ itemIndex: number;
1198
+ variantIndex: number;
1199
+ }
1200
+ interface GalleryStore {
1201
+ store: Store<GalleryState>;
1202
+ /** RFC-256 收尾:面板可见性由 Router 栈单一真源派生(isInStack('/pane/gallery')),
1203
+ * store 不再持 `open` 布尔——原 toggle() 已删除。 */
1204
+ reset(): void;
1205
+ setCategoryIndex(i: number): void;
1206
+ setItemIndex(i: number): void;
1207
+ setVariantIndex(i: number): void;
1208
+ }
1209
+ //#endregion
1210
+ //#region src/panes/ShellPane.d.ts
1211
+ interface ShellExecution {
1212
+ command: string;
1213
+ output: string;
1214
+ status: 'running' | 'done' | 'error';
1215
+ exitCode: number | null;
1216
+ /** 非空表示被信号终止(如 SIGTERM)。 */
1217
+ terminated?: boolean;
1218
+ }
1219
+ //#endregion
1220
+ //#region src/app-props.d.ts
1221
+ interface AppProps {
1222
+ columns?: number;
1223
+ /** 终端总行数(自适应预览高度用)。 */
1224
+ rows?: number;
1225
+ /** 注入 Ink 的 writeToStdout(useStdout().write)给 startTui,
1226
+ * 让已完成历史经 Ink 协调的方式滚进 scrollback(log.clear→写→restoreLastOutput)。 */
1227
+ registerWrite?: (write: (data: string) => void) => void;
1228
+ /** 强制流式预览行数上限(scrollback 模式置 1,动态区恒小避免泄漏)。 */
1229
+ maxPreviewRows?: number;
1230
+ /** 是否已有历史进 scrollback(A 模式 messages 恒空,靠此隐藏 Welcome)。 */
1231
+ hasHistory?: boolean;
1232
+ /** RFC-300 D1:窗口模式(默认)——消息进 store + ScrollableTranscript 窗口渲染。 */
1233
+ windowMode?: boolean;
1234
+ /** RFC-283 D1:scrollback 逃生口模式(OTTO_TUI_SCROLLBACK=1)——pending echo 只走 live 区,
1235
+ * 不进 store。窗口/legacy 模式恒 false(消息已 append 进 store)。 */
1236
+ scrollbackMode?: boolean;
1237
+ /** RFC-345 D5:影子模式——不写盘会话可见性双通道(状态栏徽标 + 输入区 chip)。 */
1238
+ shadow?: boolean;
1239
+ /** RFC-300 M1b:对话流滚动状态(回看态 offset)。 */
1240
+ scrollStore?: ScrollStore;
1241
+ /** RFC-300 M2:加载更早历史(DB 补页)——CLI 注入,返回带 id/seq 的 ChatMessage[] 或 null。 */
1242
+ loadHistory?: (req: {
1243
+ limit: number;
1244
+ }) => Promise<ChatMessage[] | null>;
1245
+ /** RFC-300 M2:messageStore handle(补页头部插入需要)。 */
1246
+ messageStore?: MessageStore;
1247
+ messages?: ChatMessage[];
1248
+ /** 当前界面语言(状态栏徽标显示;en/zh)。 */
1249
+ language?: Lang;
1250
+ /** RFC-263 M5:TUI 主题初值(缺省 dark);'system' 时配合 systemTheme 解析明暗。 */
1251
+ /** RFC-263 M5:system 模式的终端背景探测结果(启动时 OSC 11 求得);undefined = 未测到走 dark。 */
1252
+ systemTheme?: 'dark' | 'light';
1253
+ /**
1254
+ * RFC-277 M6:主题预设注册表(含内置 dark/light + extension 贡献的 preset,见
1255
+ * `ThemeRegistry`/M5 `theme-preset-wiring.ts`)。未传时 `ThemeProvider` 落回
1256
+ * `createBuiltinThemeRegistry()`(M1-M5 既有行为,纯内置 dark/light,向后兼容)。
1257
+ */
1258
+ themeRegistry?: ThemeRegistry;
1259
+ /**
1260
+ * RFC-277 M6:按 appearance 分槽的 preset 选择(settings `theme_preset` 字段初值)。
1261
+ * 未传时每个 appearance 都用其 builtin preset(`dark`/`light`),行为等价于 M1-M5。
1262
+ */
1263
+ presetSelection?: ThemePresetSelection;
1264
+ /**
1265
+ * 用户快捷键覆盖表(settings `keybinding_overrides`)——喂给 useAppKeyboard 的
1266
+ * `matchKeyBinding`,使面板/settings.json 里的重绑真正作用于按键分发。
1267
+ * 详见 bootstrap/types.ts 同名字段注释(RFC-174 运行时消费缺口修复)。
1268
+ */
1269
+ keybindingOverrides?: Record<string, KeyBindingPredicate>;
1270
+ /** Shift+Tab 循环切换权限 mode 回调(cli 切并落盘)。 */
1271
+ onCyclePermissionMode?: () => void;
1272
+ cost?: string;
1273
+ /** #/@ sigil 条目数据源(coding 层 PluginInputRegistry,结构同构)。
1274
+ * 仅消费 search;App 持有面板状态、渲染 SigilPane(FocusOwner='sigilPane')。 */
1275
+ pluginInput?: SigilSearchRegistry;
1276
+ /**
1277
+ * 读取文件全文(用于 @file 条目 Enter 后 FileContentViewer 预览)。
1278
+ * 未提供时 file 条目回退到 preview 截断文本(旧行为)。
1279
+ *
1280
+ * 返回 `{content, truncated}`(RFC-189 追加修复:`readFileCapped` 读取层熔断场景,
1281
+ * `truncated=true` 时下游 `SigilPane` 须强制 `resolveFileContentViews` 的
1282
+ * `preTruncated` 参数走大文件降级候选,不依赖不可靠的长度比较)。
1283
+ */
1284
+ readFileContent?: (path: string) => Promise<{
1285
+ content: string;
1286
+ truncated: boolean;
1287
+ }>;
1288
+ /**
1289
+ * RFC-217 D1:EditedFileFullPane「整个文件 diff」(vs git HEAD)异步取数 provider——
1290
+ * 透传自 TuiOptions.resolveWholeFileDiff,cli 层绑定 projectRoot 注入。缺省
1291
+ * `undefined` 时该模式不可用,`f` 键三态循环退化为现状二态。
1292
+ */
1293
+ resolveWholeFileDiff?: (path: string, operation: EditedFileEntry['operation']) => Promise<{
1294
+ oldContent?: string;
1295
+ newContent?: string;
1296
+ error?: string;
1297
+ }>;
1298
+ /** 按回合编号获取消息切片(1-based turn → 对应回合的 assistant/tool 消息)。 */
1299
+ getTurnMessages?: (turn: number) => ChatMessage[];
1300
+ /** 编辑文件面板是否打开(Ctrl+V 翻转) */
1301
+ editedFilesOpen?: boolean;
1302
+ /** Ctrl+V 翻转编辑文件面板 */
1303
+ onToggleEditedFiles?: () => void;
1304
+ /** 子代理面板是否聚焦(Ctrl+T 翻转) */
1305
+ subagentsOpen?: boolean;
1306
+ /** Ctrl+T 翻转子代理面板聚焦 */
1307
+ onToggleSubagents?: () => void;
1308
+ /** SchedulePane 是否打开。 */
1309
+ scheduleOpen?: boolean;
1310
+ /** 回调打开/关闭 SchedulePane。 */
1311
+ onToggleSchedule?: () => void;
1312
+ /** DraftPane 是否打开(Ctrl+O 或 /draft 命令)。 */
1313
+ draftOpen?: boolean;
1314
+ /** 回调打开/关闭 DraftPane。 */
1315
+ onToggleDraftPane?: () => void;
1316
+ /** ctrl+s 保存当前输入为一条自动命名的草稿(cli 侧写入 session.session.setDrafts() 并落盘)。 */
1317
+ onDraftSave?: (text: string) => void;
1318
+ /** `@` 面板选中一条条目后回调(cli 侧据此维护 settings.recent_mentions MRU 并落盘,
1319
+ * 见 startTui-types.ts TuiOptions.onSigilSelect 同名字段注释)。 */
1320
+ onSigilSelect?: (entry: SigilEntry) => void;
1321
+ /** DraftPane 内 d 删除选中草稿(按当前渲染列表下标,cli 侧据此定位 id 后从 session.setDrafts 移除)。 */
1322
+ onDraftDelete?: (index: number) => void;
1323
+ /** DraftPane 内 d 批量删除全部勾选(Space 多选)的草稿,入参为草稿 id 集合。 */
1324
+ onDraftDeleteMany?: (ids: string[]) => void;
1325
+ /** QueuePane 是否打开(Ctrl+Q 或 /queue 命令)。 */
1326
+ queueOpen?: boolean;
1327
+ /** 回调打开/关闭 QueuePane。 */
1328
+ onToggleQueuePane?: () => void;
1329
+ /** 回调打开/关闭 PromptLogPane(/prompts 命令)。 */
1330
+ onTogglePrompts?: () => void;
1331
+ /** QueuePane 内 d 删除选中排队项。 */
1332
+ onQueueDelete?: (index: number) => void;
1333
+ /** QueuePane 内 J/K 把选中项在队列中下移/上移一位(调整执行顺序)。 */
1334
+ onQueueMove?: (index: number, delta: number) => void;
1335
+ /** QueueEditDialog「确定」:仅更新队列内该 index 项的文本,位置/模式不变。 */
1336
+ onQueueEditText?: (index: number, text: string) => void;
1337
+ /** QueueEditDialog「直接发送」:出队 + 按该项原始 mode 分流执行(send→steer/send,
1338
+ * bash/memory→原始通道,见 QueueEditDialog 头注释)。 */
1339
+ onQueueSendNow?: (index: number, text: string) => void;
1340
+ /** 持久化输入历史初始条目(从磁盘恢复,传给 PromptInput)。 */
1341
+ initialHistory?: string[];
1342
+ /** RFC-129:外部 shell 历史命令(只读,ghost/Ctrl+R)。 */
1343
+ externalHistoryCommands?: readonly string[];
1344
+ /** 每次 push 新历史条目时回调——携带完整 entries 供上层落盘。 */
1345
+ onHistoryPush?: (entries: readonly string[]) => void;
1346
+ /** RFC-198 §4.4:PasteStore 内存压力分级来源只读视图(cli 层传入,透传给 PromptInput
1347
+ * 构造 createPasteStore)。省略时 PasteStore 固定 healthy 上限。 */
1348
+ residencyGovernor?: PasteStoreResidencySource;
1349
+ /**
1350
+ * errorRetry 卡片焦点索引变更回调(←/→/Tab 触发)。修复:键盘层此前直接原地
1351
+ * mutate `errorRetry.focusIndex`,同一对象引用穿透 `React.memo(App)` 浅比较判定
1352
+ * "props 未变",导致方向键切焦点在 UI 上不可见(mode='manual' 场景无倒计时兜底,
1353
+ * 表现为永久卡死)。改为经此回调 → 上层 store 生成新对象 → notify() 的响应式路径,
1354
+ * 对齐 setEditedSelIndex/onQueueMove 等既有可导航列表的既定模式。
1355
+ */
1356
+ onErrorRetryFocusChange?: (index: number) => void;
1357
+ /**
1358
+ * RFC-208:脉冲调查瞬态 UI 状态合并更新(phase/selectedIndex/commentText/commentOffset)
1359
+ * ——同 onErrorRetryFocusChange 模式,由 PulseSurveyOverlay 的 FocusBus handler
1360
+ * 调用,经上层 store 生成新对象引用触发响应式重渲。
1361
+ */
1362
+ onPulseSurveyChange?: (updates: Partial<PulseSurveyItem>) => void;
1363
+ /** /tasks 面板是否打开(聚焦时接管 ↑↓/k/o/esc) */
1364
+ backgroundTasksOpen?: boolean;
1365
+ /** Ctrl+P 翻转委派面板聚焦(对齐 Ctrl+T 子代理 / Ctrl+V 编辑文件) */
1366
+ onToggleDelegates?: () => void;
1367
+ /** 关闭 /tasks 面板(esc) */
1368
+ onBackgroundClose?: () => void;
1369
+ /** 杀选中后台进程(k) */
1370
+ onBackgroundKill?: (id: string) => void;
1371
+ /** 看选中后台进程输出(o)→ 进入实时跟随 */
1372
+ onBackgroundViewOutput?: (id: string) => void;
1373
+ /** 退出实时跟随回到列表(esc) */
1374
+ onBackgroundOutputClose?: () => void;
1375
+ /** 应用 ready 的 agent-session 作业(a 键) */
1376
+ onBackgroundApply?: (id: string) => void;
1377
+ /** enter 键切换对话流到 sub-agent。 */
1378
+ onBackgroundSwitch?: (id: string) => void;
1379
+ /** 删除选中的已终结委派项(d 键,运行中/待处理项不可用)。 */
1380
+ onBackgroundDelete?: (id: string) => void;
1381
+ /** esc 退出 sub-agent 对话流(恢复主对话)。 */
1382
+ onExitSubagentContext?: () => void;
1383
+ /** App-local 全屏面板(editedFileFull/taskDetail)开/关时下推 detour 态给 startTui,
1384
+ * 使主代理在面板底下的产出也被缓冲(消残影第二源)。active=false 须在关闭 setState **之前**同步调用(D4)。 */
1385
+ onPaneOwnsViewportChange?: (active: boolean) => void;
1386
+ /**
1387
+ * `focusOwner` 每次变化时下推给 startTui(含变回 'prompt')——用于对话选中态保护
1388
+ * (用户报告"流式期间弹窗打开时终端全选闪烁"的修复):任意模态/浮层/导航栈
1389
+ * 面板在场时(`focusOwner !== 'prompt'`)暂停主代理 scrollback 写入,与 `paneOwnsViewport`
1390
+ * 现有的全屏面板缓冲逻辑 OR 合并,见 startTui.tsx。零新增按键、零新增用户心智负担——
1391
+ * 复用 resolveFocus 已有的单一焦点归属判定,弹窗本身就是"用户想要画面稳定"的信号。
1392
+ *
1393
+ * **范围边界(独立审核确认)**:仅覆盖"弹窗/面板在场"这一路径;不覆盖"从未打开任何
1394
+ * 弹窗、纯流式输出期间直接选中文字"——那是终端字符网格持续被 Ink log-update 改写导致
1395
+ * 的更广问题(根因见 packages/tui 相关调研记录),需要独立的"暂停"原语才能覆盖,
1396
+ * 本次不在范围内。
1397
+ */
1398
+ onFocusOwnerChange?: (owner: FocusOwner) => void;
1399
+ /**
1400
+ * RFC-253 M-T5:对话流滚动是否活跃(当前是对话路由 '/' 且无阻断式确认框)。下推给
1401
+ * 树外滚轮消费端(main.ts wheelCoalescer),使**滚轮门与键盘门同源**——非路由确认框
1402
+ * (forcedUpgrade/queueClose/interrupt/popQueued,currentPath 仍为 '/')在场时同步禁滚。
1403
+ */
1404
+ onScrollActiveChange?: (active: boolean) => void;
1405
+ /** 向运行中的 delegate 补充信息(输出视图内打字 + Enter)。 */
1406
+ onDelegateSupply?: (id: string, text: string) => void;
1407
+ /**
1408
+ * RFC-253 M-T5:初始路由。resume 到有历史会话时传 '/'(直接进对话,消除首帧闪 Home);
1409
+ * 全新会话缺省 '/home'。Home 与对话是互斥路由,prompt 作为共享 chrome 在两者都活跃。
1410
+ */
1411
+ initialPath?: string;
1412
+ /** 启动横幅参数(version/cwd);未提供则不显示横幅 */
1413
+ welcome?: {
1414
+ version?: string;
1415
+ buildId?: number;
1416
+ cwd?: string; /** 用户昵称(settings.nickname):Welcome 具名问候;缺省无名版。 */
1417
+ nickname?: string;
1418
+ updateAvailable?: {
1419
+ latest: string;
1420
+ current: string;
1421
+ newer: boolean;
1422
+ forced: boolean;
1423
+ };
1424
+ weather?: {
1425
+ condition: string;
1426
+ temp: number;
1427
+ location: string;
1428
+ };
1429
+ };
1430
+ /** RFC-234 P2-b:选择会话回调。 */
1431
+ onSessionSelect?: (id: string) => void;
1432
+ /** RFC-335 M6:上下文预算 store(状态栏占用条 + ContextPane 消费)。 */
1433
+ budgetStore?: BudgetStore;
1434
+ contextStore?: ContextStore;
1435
+ /** RFC-333 M3-a:通知/暂停态 store(notifications/paused/pausePending/toast 等真源)。
1436
+ * M3 让 Region 经 AppStoresContext 自订阅这些字段,替代 cli 计算后 props 下传。 */
1437
+ notificationStore?: NotificationStore;
1438
+ /** RFC-116 M1:性能监控面板 store(startTui 注入);缺省时内部建空 store(永不开启)。 */
1439
+ perfStore?: PerfStore;
1440
+ /** RFC-019 M2:缓存命中率面板 store(startTui 注入);缺省时内部建空 store(永不开启)。 */
1441
+ cacheStore?: CacheStore;
1442
+ /** /proxy 面板 store(startTui 注入);缺省时内部建空 store(永不开启)。 */
1443
+ proxyStore?: ProxyStore;
1444
+ /** /proxy 面板是否打开。 */
1445
+ proxyOpen?: boolean;
1446
+ /** /proxy 面板关闭回调。 */
1447
+ onProxyDismiss?: () => void;
1448
+ /**
1449
+ * /proxy 面板呼出模态对话框(编辑地址走 InputDialog,清除配置走 ConfirmDialog)——
1450
+ * 同 `TuiHandle.openModal`,仅取 ProxyPane 需要的两个重载。
1451
+ */
1452
+ onProxyOpenModal?: {
1453
+ (req: ModalRequestInput): Promise<string | null>;
1454
+ (req: ModalRequestVoid): void;
1455
+ };
1456
+ /** /proxy 面板提交代理地址(编辑/设置)。 */
1457
+ onProxySubmitUrl?: (url: string) => void;
1458
+ /** /proxy 面板切换启用/停用。 */
1459
+ onProxyToggleEnabled?: () => void;
1460
+ /** /proxy 面板清除配置(ConfirmDialog 确认后调用)。 */
1461
+ onProxyClear?: () => void;
1462
+ /** /proxy 面板「测试连接」动作(RFC-288 D4)。 */
1463
+ onProxyTest?: () => void;
1464
+ /** 压缩/裁剪事件日志 store(startTui 注入);缺省时内部建空 store(永不开启)。 */
1465
+ compactionLogStore?: CompactionLogStore;
1466
+ /** RFC-147 M2:组件画廊面板 store(startTui 注入);缺省时内部建空 store(永不开启)。 */
1467
+ galleryStore?: GalleryStore;
1468
+ /**
1469
+ * RFC-106 M2:流式高频状态 store(streamingText/streamingThinking/spinnerMode 等 13
1470
+ * 字段,startTui 注入)。消费方(StreamingSpinner/REPLRegion)经 `useAppState(streamStore,
1471
+ * selector)` 细粒度订阅——替代此前的 StreamingContext(D5,已移除)。缺省时内部建空
1472
+ * store(与 inspector 同款兜底模式)。
1473
+ */
1474
+ streamStore?: StreamStore;
1475
+ taskStore?: TaskStore;
1476
+ /** RFC-116 M5:`/perf` 面板内手动刷新键(r)触发。 */
1477
+ onPerfRefresh?: () => void;
1478
+ /** force=true 表示修饰键+Enter(Alt/Ctrl/Cmd);透传给 startTui 的 submitOrQueue 决定 steer/followUp。 */
1479
+ onSubmit?: (text: string, mode: SubmitMode, force?: boolean) => void;
1480
+ onInterrupt?: () => void;
1481
+ /** Esc:队列非空时逐条删(每按一次删最近一条 followUp 排队);队列空时才中断。 */
1482
+ onPopQueued?: () => void;
1483
+ onPermissionDecision?: (id: string, approved: boolean, mode?: 'once' | 'always') => void;
1484
+ /** 选定(value)/取消(null) 回调。 */
1485
+ onSelectResolve?: (value: string | null) => void;
1486
+ /** 提交(value)/取消(null) 回调。 */
1487
+ onInputResolve?: (value: string | null) => void;
1488
+ /** 输入对话框的 action 按钮回调(如 OAuth「打开浏览器」)。 */
1489
+ onInputAction?: () => void;
1490
+ /** 首次引导弹层完成回调(携带昵称/语言/主题;未设置的字段=用户跳过)。 */
1491
+ onOnboardingResolve?: (result: OnboardingResult) => void;
1492
+ /** 提交(answers + freeformText)/取消(null) 回调。 */
1493
+ onQuestionsResolve?: (answers: Record<string, string[]> | null, freeformText?: string) => void;
1494
+ /** 确认(confirmed)/取消 回调。 */
1495
+ onConfirmResolve?: (confirmed: boolean, extra?: boolean) => void;
1496
+ /** OK 回调。 */
1497
+ onAlertResolve?: () => void;
1498
+ /** 提交(value)/取消(null) 回调。 */
1499
+ onPromptResolve?: (value: string | null) => void;
1500
+ /** 关闭信息模态窗。 */
1501
+ onInfoDismiss?: () => void;
1502
+ /** RFC-256 收尾:/context 详情子态由 Router 栈派生(/pane/context/detail),非 store 布尔。
1503
+ * contextDetail 为 App 内部 route 派生值(PanelRegion 消费以抑制 InspectorPane 同屏)。 */
1504
+ contextDetail?: boolean;
1505
+ /** ContextPane「View details」→ push /pane/context/detail(进入逐 turn 明细)。 */
1506
+ onViewDetails?: () => void;
1507
+ /** ContextDetailPane「Esc back」→ goBack 退回 ContextPane。 */
1508
+ onBackToContextPane?: () => void;
1509
+ /** /context 面板整体关闭(ContextPane Esc)——逐层退回主输入。 */
1510
+ onContextDismiss?: () => void;
1511
+ /** RFC-116 M1:关闭性能监控面板(PerfPane 内部 Esc 触发)。 */
1512
+ onPerfDismiss?: () => void;
1513
+ /** RFC-019 M2:关闭缓存命中率面板(CachePane 内部 Esc 触发)。 */
1514
+ onCacheDismiss?: () => void;
1515
+ /** 关闭压缩/裁剪日志面板(CompactionLogPane 内部 Esc 触发)。 */
1516
+ onCompactionLogDismiss?: () => void;
1517
+ /** RFC-147 M2:关闭组件画廊面板(GalleryPane 内部 Esc 触发)。 */
1518
+ onGalleryDismiss?: () => void;
1519
+ /** 关闭记忆模态窗。 */
1520
+ onMemoryDismiss?: () => void;
1521
+ /** 关闭快捷键面板(keybindingPanelProps.onDismiss 回填源,RFC-106 M4 补完)。 */
1522
+ onKeybindingPanelDismiss?: () => void;
1523
+ /** 关闭快捷方式管理面板(shortcutsPanelProps.onDismiss 回填源,RFC-233)。 */
1524
+ onShortcutsDialogDismiss?: () => void;
1525
+ /** 通知中心是否打开(ctrl+n 翻转)。 */
1526
+ notificationsOpen?: boolean;
1527
+ /** ctrl+n 翻转通知中心。 */
1528
+ onToggleNotifications?: () => void;
1529
+ /** 消除单条通知。 */
1530
+ onDismissNotification?: (id: number) => void;
1531
+ /** 关闭通知中心(esc,全部标已读)。 */
1532
+ onCloseNotifications?: () => void;
1533
+ /** 强制升级:点击 [Upgrade] 触发(执行 /upgrade)。 */
1534
+ onUpgrade?: () => void;
1535
+ /** 强制升级:点击 [Cancel] 触发(退出 TUI)。 */
1536
+ onCancelUpgrade?: () => void;
1537
+ /** toast 通知回调(透传给 PromptInput,ctrl+s/o 草稿操作时调用) */
1538
+ onToast?: (title: string, content: string) => void;
1539
+ /** ESC 关闭当前 toast 回调(清除计时器并立即消失)。 */
1540
+ onDismissToast?: () => void;
1541
+ /** 命令 registry ref(向 PromptInput 传递,用于外层注册参数补全函数) */
1542
+ registryRef?: {
1543
+ current: CommandRegistry$1 | null;
1544
+ };
1545
+ /** Shell 补全编排器 ref(向 PromptInput 传递,由 startTui 创建并管理生命周期) */
1546
+ shellBackendRef?: {
1547
+ current: Completer | null;
1548
+ };
1549
+ /** 异步 shell 执行状态(`!! <cmd>` 面板)。 */
1550
+ shellExecution?: ShellExecution | null;
1551
+ /** shell 执行中 Ctrl+C 回调(终止进程)。 */
1552
+ onShellAbort?: () => void;
1553
+ /** shell 执行完成后 Esc 回调(关闭面板)。 */
1554
+ onShellDismiss?: () => void;
1555
+ /** 复制完整 shell 输出到剪贴板(c 键,RFC-225 M1)。 */
1556
+ onShellCopyOutput?: () => void;
1557
+ /** 问 AI(a 键,仅错误态,RFC-225 M2)。 */
1558
+ onShellAskAi?: () => void;
1559
+ /** M-N3:当前消息流中注册的 A2UI 按钮(数字键 1-9 快捷触发)。 */
1560
+ a2uiButtons?: A2uiButtonInfo[];
1561
+ /** M-N3:A2UI 按钮触发回调(componentId, action, payload)。 */
1562
+ onA2uiAction?: (componentId: string, action: string, payload?: Record<string, unknown>) => void;
1563
+ /** ESC 撤回时把文本回填到 PromptInput 的桥接 ref。 */
1564
+ restoreInputRef?: {
1565
+ current: {
1566
+ fill: (text: string) => void;
1567
+ } | null;
1568
+ };
1569
+ /** RFC-338 D7a:粘贴缓存树外桥接 ref(cli hydrate/落盘),同 restoreInputRef 模式。 */
1570
+ pasteBridgeRef?: {
1571
+ current: {
1572
+ hydrate: (snapshot: PasteSnapshot | null | undefined) => void;
1573
+ export: () => PasteSnapshot;
1574
+ } | null;
1575
+ };
1576
+ /** 刚 echo、模型尚未返回首字节的 user 消息(ESC 撤回窗口态快照)。 */
1577
+ pendingEcho?: {
1578
+ text: string;
1579
+ mode: string;
1580
+ } | null;
1581
+ /** ESC 撤回 pending 消息时通知上层(text=原文、mode=提交模式)。 */
1582
+ onWithdrawPending?: (text: string, mode: string) => void;
1583
+ /** RFC-337 D3:ESC 撤回一条运行中追加(steer)时通知上层(id=steer 稳定 id)。
1584
+ * cli 侧 removeSteer 命中(未消费)→ 撤回 live 回显;未命中(已 drain)→ 退化中止整回合。 */
1585
+ onWithdrawSteer?: (id: string) => void;
1586
+ }
1587
+ //#endregion
1588
+ //#region src/App.d.ts
1589
+ declare const App: React.MemoExoticComponent<(props: AppProps) => React.ReactElement>;
1590
+ //#endregion
1591
+ //#region src/components/Spinner.d.ts
1592
+ interface SpinnerProps {
1593
+ verb?: string;
1594
+ elapsed?: boolean;
1595
+ paused?: boolean;
1596
+ /** Monotonically increasing response length — used for stall detection */
1597
+ responseLength?: number;
1598
+ /** Whether any tools are currently active */
1599
+ hasActiveTools?: boolean;
1600
+ /** 累计 token 数(显示 ↓ Nk tokens;0 则不显示) */
1601
+ tokens?: number;
1602
+ /** RFC-097:LLM 调用阶段——requesting(已发起/等待首字节)|responding(已收到首字节/流式中)。
1603
+ * 缺省不显示阶段箭头(向后兼容既有调用方,如压缩场景不区分阶段)。 */
1604
+ mode?: 'requesting' | 'responding';
1605
+ /** RFC-097:输出占比(0-100,= min(outputTokens/maxOutput,1)*100)。仅 responding 阶段显示;
1606
+ * `maxOutput` 缺失/非法时调用方应传 undefined——组件不做除法,只做纯展示,避免 NaN 由此扩散。 */
1607
+ progressPercent?: number;
1608
+ /** 工具调用预算:本窗口已用轮次(与 maxToolTurns 一起决定是否显示 x/y tools)。 */
1609
+ toolTurnCount?: number;
1610
+ /** 工具调用预算:本窗口上限(0/undefined = 未知,不显示 x/y 提示)。 */
1611
+ maxToolTurns?: number;
1612
+ /** RFC-097 M5:压缩场景的虚假进度条——无真实完成度信号(黑盒单次 LLM 调用),按耗时
1613
+ * 渐近估算(`~{pct}%`,硬顶 92%,见下方 estimatedProgressPercent)。与 `progressPercent`
1614
+ * 互斥使用(后者是真实 token/maxOutput 占比),两者共用同一展示位但语义不同——诚实标记
1615
+ * 是 `~` 前缀(STR.spinner.estimatedPercent),不额外用配色区分(配色已被 stall/budget 占用)。 */
1616
+ estimatedProgress?: boolean;
1617
+ }
1618
+ declare function Spinner({
1619
+ verb,
1620
+ elapsed,
1621
+ paused,
1622
+ responseLength,
1623
+ hasActiveTools,
1624
+ tokens,
1625
+ mode,
1626
+ progressPercent,
1627
+ toolTurnCount,
1628
+ maxToolTurns,
1629
+ estimatedProgress
1630
+ }: SpinnerProps): React.ReactElement;
1631
+ //#endregion
1632
+ //#region src/layouts/GroupDivider.d.ts
1633
+ interface GroupDividerProps {
1634
+ label: string;
1635
+ /** 前导空白字符串(默认 1 个空格,对齐多数消费方)。 */
1636
+ indent?: string;
1637
+ }
1638
+ declare function GroupDivider({
1639
+ label,
1640
+ indent
1641
+ }: GroupDividerProps): React.ReactElement;
1642
+ //#endregion
1643
+ //#region src/utils/tool-label.d.ts
1644
+ /**
1645
+ * tool-label.ts — 工具名 → 人类友好展示名(统一所有工具的展示).
1646
+ *
1647
+ * 规则:显式 label 优先;否则美化名字:
1648
+ * - MCP 工具 `mcp__<server>__<tool>` → "<server> / <tool>"(剥前缀,否则丑成 "Mcp X Y")
1649
+ * - snake_case / kebab-case → Title Case(task_delegate → "Task Delegate"、grill_me → "Grill Me")
1650
+ * "没 label 用名字"——但名字先过美化。
1651
+ */
1652
+ /** RFC-097 M2:压缩期间复用 `activeTool` 状态机的哨兵值(非真实工具名,`__` 双下划线前后缀
1653
+ * 避免与任何真实工具名/MCP 命名空间碰撞)。消费方(`StreamingSpinner.tsx`)据此走
1654
+ * `STR.compact.ingVerb` 分支而非 `STR.bg.runningVerb(activeTool)`。 */
1655
+ declare const COMPACTING_SENTINEL = "__compacting__";
1656
+ //#endregion
1657
+ //#region src/components/Segmented.d.ts
1658
+ interface SegmentItemSpec {
1659
+ key: string;
1660
+ label: string;
1661
+ disabled?: boolean;
1662
+ }
1663
+ interface SegmentedProps {
1664
+ items: SegmentItemSpec[];
1665
+ /** 当前激活 tab 的 key。 */
1666
+ activeKey: string;
1667
+ /** 激活态背景色(对齐 Button color,默认 accent 蓝)。 */
1668
+ color?: ButtonColor;
1669
+ /** tabIndex for focus traversal(默认 -1 = 不参与)。 */
1670
+ tabIndex?: number;
1671
+ /** ←→ 切换时回调。 */
1672
+ onSelect?: (key: string) => void;
1673
+ /**
1674
+ * 可用总宽(RFC-272 D2)。传入后启用**宽度自适应窗口**:以激活项为中心裁出可见窗口,
1675
+ * 溢出侧渲染 `← N` / `→ N`,超长标签按显示宽度截断(CJK 安全)。
1676
+ *
1677
+ * **未传时退化为全展开**(原行为,向后兼容)——但那样在窄终端会溢出,
1678
+ * 而 stock Ink 不裁溢出即残影(RFC-271 §1.2),故新消费方应始终传入。
1679
+ */
1680
+ availableWidth?: number;
1681
+ /**
1682
+ * 数字键 1-9 直达(RFC-272 D3)——**缺省关闭,必须显式开启**。
1683
+ *
1684
+ * 不可默认开启的原因(评审 P1-1,实证核实):`SelectDialog` 的 searchable 模式规定
1685
+ * 「所有可打印字符进入过滤输入框」(`SelectDialog.tsx` 头注释),数字键若被本组件
1686
+ * 无条件吞掉会劫持用户的过滤输入。故仅 tab 数 ≤9 且无文本输入的场景(如 InspectorPane)
1687
+ * 显式开启。
1688
+ */
1689
+ enableDigitAccess?: boolean;
1690
+ }
1691
+ declare function Segmented({
1692
+ items,
1693
+ activeKey,
1694
+ color,
1695
+ tabIndex,
1696
+ onSelect,
1697
+ availableWidth,
1698
+ enableDigitAccess
1699
+ }: SegmentedProps): React.ReactElement;
1700
+ //#endregion
1701
+ //#region src/components/ScrollIndicators.d.ts
1702
+ interface ScrollIndicatorAboveProps {
1703
+ /** 上方是否还有更多内容。 */
1704
+ hasMore: boolean;
1705
+ /** 上方隐藏的条目/行数(提供时渲染精确计数 `↑ 上方 N 行`;不提供则渲染无计数的 `▲ 更多`)。 */
1706
+ count?: number;
1707
+ /** 前导空白(默认一个空格,对齐多数消费方;部分消费方如 SigilPane 用两格)。 */
1708
+ indent?: string;
1709
+ }
1710
+ /** 上方"还有更多"指示行。`hasMore=false` 时不渲染任何内容(含外层容器)。 */
1711
+ declare function ScrollIndicatorAbove({
1712
+ hasMore,
1713
+ count,
1714
+ indent
1715
+ }: ScrollIndicatorAboveProps): React.ReactElement | null;
1716
+ interface ScrollIndicatorBelowProps {
1717
+ /** 下方是否还有更多内容。 */
1718
+ hasMore: boolean;
1719
+ /** 下方隐藏的条目/行数(提供时渲染精确计数 `↓ 下方 N 行`;不提供则渲染无计数的 `▼ 更多`)。 */
1720
+ count?: number;
1721
+ /** 前导空白(默认一个空格,对齐多数消费方;部分消费方如 SigilPane 用两格)。 */
1722
+ indent?: string;
1723
+ }
1724
+ /** 下方"还有更多"指示行。`hasMore=false` 时不渲染任何内容(含外层容器)。 */
1725
+ declare function ScrollIndicatorBelow({
1726
+ hasMore,
1727
+ count,
1728
+ indent
1729
+ }: ScrollIndicatorBelowProps): React.ReactElement | null;
1730
+ //#endregion
1731
+ //#region src/router/TabScope.d.ts
1732
+ interface TabScopeProps {
1733
+ /** 私有虚拟路径,隔离本 scope 与外部(不参与任何导航匹配,仅作 registry 路由键)。 */
1734
+ scopeId: string;
1735
+ children: React.ReactNode;
1736
+ }
1737
+ /**
1738
+ * TabScope 上下文——子组件可读取本 scope 的焦点状态(替代裸 useRouter 的降级读法)。
1739
+ */
1740
+ interface TabScopeContextValue {
1741
+ activeId: string | null;
1742
+ registry: TabableRegistry;
1743
+ }
1744
+ declare function useTabScope(): TabScopeContextValue;
1745
+ declare function TabScope({
1746
+ scopeId,
1747
+ children
1748
+ }: TabScopeProps): React.ReactElement;
1749
+ //#endregion
1750
+ //#region src/main.d.ts
1751
+ declare function startTui(opts: TuiOptions): Promise<TuiHandle>;
1752
+ //#endregion
1753
+ //#region src/session-contract/reduce.d.ts
1754
+ /** reduce 目标:TuiHandle 的渲染子集(结构镜像;真 tui 满足;测试用录制 fake)。tui 特定,不进共享包。 */
1755
+ interface TuiSink {
1756
+ pushMessage(msg: ChatMessage): void;
1757
+ echoUserInput(text: string): void;
1758
+ pushEngineEvent(event: TuiStreamEvent): void;
1759
+ setTasks(tasks: TaskItem[], title?: string): void;
1760
+ addTurnBoundary?(messageIndex: number): void;
1761
+ getNotifyStats?(): NotifyStats;
1762
+ }
1763
+ interface ReducerState {
1764
+ streamBuf: string;
1765
+ thinkBuf: string;
1766
+ turnStart: number;
1767
+ turnToolCount: number;
1768
+ lastTasks: TaskItem[];
1769
+ messageIndex: number;
1770
+ }
1771
+ declare function createReducerState(): ReducerState;
1772
+ /**
1773
+ * resume 时从 ChatMessage 流**派生** turnBoundaries(不存索引,避免 rebase)。
1774
+ *
1775
+ * 回合起点 = role:'user' 的 ChatMessage(agentMessagesToChatMessages 已滤掉 internal 注入消息)。
1776
+ * 幸存的 K 个 user 消息 = 最近 K 个回合 [turnCount-K+1 .. turnCount](被 pruneOldMessages 裁掉的
1777
+ * 早期回合不在其中)。产物满足 getTurnMessages(turn)=slice(b[turn-2]??0, b[turn-1]??len) 契约:
1778
+ * - b 长度 = turnCount-1(turnCount 个回合的 turnCount-1 个分隔点;末回合 end 越界→undefined→len)。
1779
+ * - b[k] = 绝对回合 k+2 的起始消息位置。
1780
+ * - 末尾对齐:userPositions[i] 属绝对回合 (turnCount-K+1+i),置 b[turnCount-K-1+i]=userPositions[i]。
1781
+ * - 早期 pruned 回合的分隔点压平到首个幸存位 → slice 为空(其消息确已不存在,合理降级)。
1782
+ *
1783
+ * turnCount 缺失(旧快照)时传 K(= user 消息数)→ 退化为无 prune 的自然对齐。
1784
+ */
1785
+ declare function deriveTurnBoundaries(messages: ReadonlyArray<{
1786
+ role?: string;
1787
+ }>, turnCount: number): number[];
1788
+ /** 持久化回合摘要条目的最小字段面(与 @x-otto/session TurnSummaryEntry 结构一致,不直接依赖该包)。 */
1789
+ interface PersistedTurnSummary {
1790
+ turn: number;
1791
+ status: 'done' | 'error' | 'interrupted' | 'incomplete';
1792
+ toolCount: number;
1793
+ elapsedMs: number;
1794
+ tokensUsed?: number;
1795
+ cacheHitRatio?: number;
1796
+ model?: string;
1797
+ tasksDone?: number;
1798
+ tasksTotal?: number;
1799
+ completedAt: number;
1800
+ }
1801
+ /**
1802
+ * resume 时把持久化的回合摘要插回 ChatMessage 流对应位置——复用 `deriveTurnBoundaries`
1803
+ * 同款的"user 消息位置 = 绝对回合起点"对齐算法(幸存 K 个 user 消息 = 最近 K 个回合
1804
+ * [turnCount-K+1 .. turnCount]),保证摘要行落在它所属回合的转录内容之后、下一回合
1805
+ * 开始之前——与实时产出时(`prompt.end` 时机)的相对位置一致。
1806
+ *
1807
+ * 早于幸存范围的摘要(turn < turnCount-K+1,对应转录已被 pruneOldMessages 裁掉)静默
1808
+ * 丢弃——它们指向的转录内容本就不存在,插入一条"孤儿摘要"(前面没有对应回合内容)
1809
+ * 比完全不显示更容易误导用户,故按不可恢复处理(同 deriveTurnBoundaries 头注释
1810
+ * "早期 pruned 回合的分隔点压平...其消息确已不存在,合理降级"的既有降级原则)。
1811
+ *
1812
+ * 纯函数:入参不被修改,返回插入后的新数组。
1813
+ */
1814
+ declare function insertTurnSummaries(messages: readonly ChatMessage[], turnSummaries: readonly PersistedTurnSummary[], turnCount: number): ChatMessage[];
1815
+ /** `prompt.end` 事件的最小字段面——`buildTurnSummary` 只读这几个字段,不依赖完整 SessionEvent 判别式。 */
1816
+ interface PromptEndFields {
1817
+ tokens?: number;
1818
+ model?: string;
1819
+ cacheHitRatio?: number;
1820
+ /** RFC-235:本回合实际 effort 档(供回合摘要行显示 ·Effort)。 */
1821
+ effort?: string;
1822
+ /** 回合结束原因(缺省 = 'completed',向后兼容旧事件/resume 历史)。 */
1823
+ stopReason?: 'completed' | 'interrupted' | 'error';
1824
+ }
1825
+ /**
1826
+ * 回合完成摘要对象——渲染(`reduceToTui` 内部 `sink.pushMessage`)与持久化
1827
+ * (`interactive-events.ts` 的 `se.kind === 'prompt.end'` 分支,对齐 `tasks.update` →
1828
+ * `setTodoList` 既有写法)共用同一份构造逻辑,避免两处独立实现产生字段漂移。
1829
+ *
1830
+ * status 优先级(从高到低):
1831
+ * 1. stopReason = 'error' → status = 'error'(错误终止)
1832
+ * 2. stopReason = 'interrupted' → status = 'interrupted'(用户中断)
1833
+ * 3. 有未完成 task → status = 'incomplete'(LLM 主动结束但 task 没做完)
1834
+ * 4. 其余 → status = 'done'(正常完成)
1835
+ */
1836
+ declare function buildTurnSummary(ev: PromptEndFields, state: ReducerState): {
1837
+ status: "incomplete";
1838
+ tasksDone: number;
1839
+ tasksTotal: number;
1840
+ toolCount: number;
1841
+ elapsedMs: number;
1842
+ tokensUsed: number | undefined;
1843
+ model: string | undefined;
1844
+ effort: string | undefined;
1845
+ cacheHitRatio: number | undefined;
1846
+ } | {
1847
+ status: "interrupted" | "error" | "done";
1848
+ toolCount: number;
1849
+ elapsedMs: number;
1850
+ tokensUsed: number | undefined;
1851
+ model: string | undefined;
1852
+ effort: string | undefined;
1853
+ cacheHitRatio: number | undefined;
1854
+ };
1855
+ declare function reduceToTui(ev: SessionEvent, sink: TuiSink, state: ReducerState): void;
1856
+ //#endregion
1857
+ //#region src/utils/print-messages.d.ts
1858
+ /**
1859
+ * print-messages.ts — Backward-compatible ANSI message printer for non-interactive mode.
1860
+ *
1861
+ * Used by packages/coding/src/modes/run-modes.ts in print mode.
1862
+ * Prints AgentMessages to stdout with minimal ANSI formatting.
1863
+ */
1864
+ interface PrintOptions {
1865
+ /** Terminal columns */
1866
+ columns?: number;
1867
+ /** Whether to show thinking content */
1868
+ showThinking?: boolean;
1869
+ /** Context window size (unused, kept for API compat) */
1870
+ contextWindow?: number;
1871
+ /** Start time for elapsed calculation */
1872
+ startTime?: number;
1873
+ }
1874
+ /** 结构化最小消息形状——运行时按 role 分发,接受任意消息联合(AgentMessage 等)。 */
1875
+ interface PrintableMessage {
1876
+ role?: string;
1877
+ content?: unknown;
1878
+ tool_calls?: unknown;
1879
+ }
1880
+ declare function printMessages(messages: readonly PrintableMessage[], _opts?: PrintOptions): void;
1881
+ //#endregion
1882
+ //#region src/search/incremental-search.d.ts
1883
+ interface IncrementalSearcher<T> {
1884
+ search(query: string): RankedMatch<T>[];
1885
+ }
1886
+ /** 绑定固定候选集,返回同步增量搜索函数。 */
1887
+ declare function createIncrementalSearcher<T>(items: readonly SearchableItem<T>[], options?: FuzzySearchOptions): IncrementalSearcher<T>;
1888
+ //#endregion
1889
+ //#region src/bootstrap/store-tui-sink.d.ts
1890
+ interface StoreTuiSink {
1891
+ pushMessage(msg: ChatMessage): void;
1892
+ echoUserInput(text: string): void;
1893
+ pushEngineEvent(event: TuiStreamEvent): void;
1894
+ getNotifyStats?(): NotifyStats;
1895
+ setTasks?(tasks: TaskItem[], title?: string): void;
1896
+ addTurnBoundary?(messageIndex: number): void;
1897
+ }
1898
+ interface StoreTuiSinkDeps {
1899
+ pushMessage(msg: ChatMessage): void;
1900
+ echoUserInput(text: string): void;
1901
+ pushEngineEvent(event: TuiStreamEvent): void;
1902
+ getNotifyStats(): NotifyStats;
1903
+ setTasks(tasks: TaskItem[], title?: string): void;
1904
+ addTurnBoundary(messageIndex: number): void;
1905
+ }
1906
+ declare function createStoreTuiSink(deps: StoreTuiSinkDeps): StoreTuiSink;
1907
+ //#endregion
1908
+ //#region src/bootstrap/session-event-reduce-bridge.d.ts
1909
+ interface AttachEventBridge {
1910
+ handle(event: RemoteSessionEvent): void;
1911
+ /** Reset reducer state after authoritative snapshot hydration. */
1912
+ reset(messageCount?: number): void;
1913
+ }
1914
+ declare function createSessionEventReduceBridge(sink: StoreTuiSink): AttachEventBridge;
1915
+ //#endregion
1916
+ export { type A2uiContent, AlertDialog, type AlertDialogProps, type AlertRequest, App, type AppProps, type AssistantMessage, type AttachDataSourceDeps, BASH_HISTFILE_SOURCE, BashPermissionDialog, BracketedPasteHandler, type BracketedPasteOptions, type BudgetState, type BudgetStore, type BudgetView, type BufferEntry, Button, type ButtonColor, type ButtonProps, type ButtonVariant, COMPACTING_SENTINEL, type ChatMessage, type Coalescer, type CollapsedBlock, type CollapsibleMessage, type Command, type CommandContext, type CommandEntry, type CommandRegistry, type CommandResult, ConfirmDialog, type ConfirmDialogProps, type ConfirmRequest, type CreatePasteStoreOptions, Cursor, DEFAULT_SENSITIVE_PATTERNS, DIALOG_BORDER, DataList, type DataListEntry, type DataListProps, type DataListRow, type DataListTone, type DiffHunk, type DiffHunkLine, type DraftItemView, type EditAction, type EditKeyEvent, type EditResult, type ErrorRetryAction, type ErrorRetryActionKind, type ErrorRetryItem, type ExtensionDetailAction, type ExtensionDetailRequest, type ExtensionListEntry, type ExtensionMenuContribution, type ExtensionsListRequest, FIGURES, FISH_HISTFILE_SOURCE, type FiguresMap, type FocusOwner, type FocusStyle, type FuzzySearchOptions, GroupDivider, type GroupDividerProps, type GuardState, type HighlightRange, type HistoryEntry, type HistorySource, Home, type HomeProps, type IncrementalSearcher, type InputBuffer, type InputHistory, type InputMode, type InsertHistoryMode, type InsertHistoryOptions, type KeyBindingPredicate, type KeyValueEntry, type KeyValueRow, LAYOUT, type Lang, type LangMode, type MarkdownThemeOverrides, MeasuredText, MemoryDialog, type MemoryDialogProps, type MemoryEntry, type MemoryEntrySource, type MergeHistoryOptions, type MergedHistoryProvider, Message, type MessageContent, type MessageProps, type NotifyScheduler, type NotifyStats, OTTO_SESSION_SOURCE, type ObservationLike, PALETTE, PANEL_BORDER, type ParentWorkspaceChoice, type ParentWorkspacePromptOptions, type ParseBashHistoryOptions, type ParseFishHistoryOptions, type ParseZshHistoryOptions, type ParsedExtendedKey, type PasteEvent, type PasteSnapshot, type PasteSnapshotEntry, type PasteStore, type PasteStoreResidencySource, type PermissionDecision, PermissionDialog as PermissionDialogDialog, type PersistedTurnSummary, type PluginMessageRenderer, type PluginRegistration, type PrintOptions, type PrintableMessage, PromptDialog, type PromptDialogProps, type PromptEndFields, PromptInput, type PromptRequest, type ProviderUsageBadgeItem, type QueryGuard, QueuedCommands, REPLRegion, type REPLRegionProps, type RankedMatch, type RateLimitType, type ReducerState, type RegisteredRenderer, type RemoteSessionEvent, type RemoteSessionSnapshot, type RenderOptions, type Risk, SPACING, STATUS, STREAM_COALESCE_MS, ScrollIndicatorAbove, ScrollIndicatorBelow, type SearchMatch, type SearchableItem, Segmented, Segmented as Tabs, type SegmentedProps, Select, type SelectGroupProps, type SelectItemProps, type SelectLabelProps, type SelectOption, type SelectOptions, type SelectRootProps, type SelectState, type SessionDataSource, type SessionDataTarget, type SessionListItem, type SessionTransport, type SigilEntry, type SigilKind, SigilPane, type SigilPaneProps, type SigilPrefix, type SigilSearchRegistry, type SigilTrigger, type SlashNavigateAction, Spinner, type SpinnerProps, type StopReason, type Store, type StreamChunk, type StreamCommitResult, type StreamCommitState, type StreamEvent, type SubagentContext, type SubmitMode, type SubmitRoute, type SubmitRouteCtx, type SubsequenceResult, THEME, TabScope, type TabScopeProps, Tabable, type TabableProps, type TextContent, TextInput, type TextInputProps, type ThemeAppearance, type ThemeColors, type ThemePreset, type ThemePresetInput, type ThemePresetSelection, type ThemePresetSource, ThemeRegistry, type ThinkingContent, type ToolCall, type ToolCompletionMessage, type ToolMessage, type TrustPromptChoice, type TuiHandle, type TuiPanelRegistration, type TuiSink, type TuiStreamEvent, type TypeaheadState, type UseTabableOptions, type UserMessage, type WorkspaceTrustPromptOptions, type WrapPolicy, ZSH_HISTFILE_SOURCE, applySigilCompletion, applySlashCompletion, beginSyncFrame, buildTurnSummary, clearPluginRenderers, collapseMessages, createAttachSessionDataSource, createBudgetStore, createBuiltinCommands, createBuiltinThemeRegistry, createCommandRegistry, createIncrementalSearcher, createInputBuffer, createInputHistory, createLocalSessionDataSource, createMergedHistoryProvider, createPasteStore, createQueryGuard, createReducerState, createSelectState, createSessionEventReduceBridge, createStoreTuiSink, cycleIndex, deriveTurnBoundaries, detectLanguage, displayWidth, effectiveBusy, endSyncFrame, entriesToCommands, expandCollapsed, extractSigilPrefix, extractSlashPrefix, formatAgentDiagnosticsText, formatKeyValueLines, formatProviderUsageLimitTypeFull, formatTranscriptText, formatTurnTimeline, getCommandSuggestions, getInputViewport, getKillRingEntries, getMarkdownThemeUserOverrides, guardScrollbackStdout, handleEditingKey, handleEditingKeyExtended, i18next, initI18n, initStreamCommit, insertHistory, insertHistorySequence, insertTurnSummaries, isSensitiveCommand, isUsingOverage, makeCoalescer, makeNotifyScheduler, matchSubsequence, mergeHistoryEntries, navigateSuggestions, normalizeCommand, observationLiveFields, observationRow, osc52QuerySequence, osc52Write, osc8FilePath, osc8Hyperlink, parseBashHistory, parseExtendedKey, parseFishHistory, parseZshHistory, pickInsertMode, positionsToHighlightRanges, preWrapLine, preWrapLines, printMessages, promptParentWorkspaceChoice, promptWorkspaceTrust, rankCandidates, rankLabeledItems, rankNamedItems, reduceToTui, registerPluginRenderers, renderInline, renderMarkdownToLines, renderMessageLines, resetKillRing, resolveHorizontalStep, routeSubmit, safeCommitBoundary, scoreSubsequence, setMarkdownThemeUserOverrides, shouldStripSyncOutput, shouldUseViewport, showCommandPalette, slashCommandName, startTui, streamCommitStep, stringWidth, stripScrollbackClear, stripSyncSequences, stripSyncStdout, subagentEntryStatus, subagentRestoreFields, t, toggleCollapse, useAppState, useTabScope, useTabable, withSyncFrame };
1917
+ //# sourceMappingURL=index.d.ts.map