@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.
- package/README.md +150 -0
- package/dist/Tabable-B7PtwING.d.ts +3940 -0
- package/dist/Tabable-B7PtwING.d.ts.map +1 -0
- package/dist/WizardDialog-BGWYjvqR.js +10 -0
- package/dist/WizardDialog-BGWYjvqR.js.map +1 -0
- package/dist/compat.d.ts +114 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +3 -0
- package/dist/compat.js.map +1 -0
- package/dist/i18n-CznO8p1Y.js +76 -0
- package/dist/i18n-CznO8p1Y.js.map +1 -0
- package/dist/index.d.ts +1917 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/standalone.d.ts +304 -0
- package/dist/standalone.d.ts.map +1 -0
- package/dist/standalone.js +2 -0
- package/dist/standalone.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,3940 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import i18next, { i18n } from "i18next";
|
|
3
|
+
import { StoreApi } from "zustand";
|
|
4
|
+
import * as _$_x_otto_interchange0 from "@x-otto/interchange";
|
|
5
|
+
import { A2uiComponent, StopReason, StreamEvent } from "@x-otto/interchange";
|
|
6
|
+
import { TaskItem, TaskItem as TaskItem$1, TurnRecord } from "@x-otto/session-contract";
|
|
7
|
+
|
|
8
|
+
//#region src/types.d.ts
|
|
9
|
+
interface ToolCall {
|
|
10
|
+
id: string;
|
|
11
|
+
type: 'function';
|
|
12
|
+
function: {
|
|
13
|
+
name: string;
|
|
14
|
+
arguments: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface TextContent {
|
|
18
|
+
type: 'text';
|
|
19
|
+
text: string;
|
|
20
|
+
}
|
|
21
|
+
interface ThinkingContent {
|
|
22
|
+
type: 'thinking';
|
|
23
|
+
thinking: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A2UI 声明式 UI 内容块(RFC-105 D6)——渲染投影层直接复用 `@x-otto/interchange` 的
|
|
27
|
+
* `A2uiComponent`(非手抄副本,见 `messages/a2ui-renderer.ts` 已是同一权威类型的消费方)。
|
|
28
|
+
* 前向兼容补全(2026-07-12,非修复已发生回归——全仓核实当前无任何生产者产出 a2ui 内容块,
|
|
29
|
+
* `@x-otto/interchange` 的 `AssistantMessage.content` 类型目前也不含 A2uiContent,详见
|
|
30
|
+
* `cli/src/view-model-adapter.ts` 头注释的完整分析):此前 `MessageContent` 联合缺此分支,
|
|
31
|
+
* 若协议层未来开放该字段,`agentMessagesToChatMessages`(cli 侧 resume 转换)的 switch 会
|
|
32
|
+
* 落入 default 静默丢弃 a2ui 块——而 `message-lines.ts` 的实时渲染通道已是完整的,会形成
|
|
33
|
+
* "实时能显示、resume 后消失"的不对称。本次补齐使两条路径提前对齐。
|
|
34
|
+
*/
|
|
35
|
+
interface A2uiContent {
|
|
36
|
+
type: 'a2ui';
|
|
37
|
+
version: string;
|
|
38
|
+
components: A2uiComponent[];
|
|
39
|
+
}
|
|
40
|
+
type MessageContent = TextContent | ThinkingContent | A2uiContent;
|
|
41
|
+
interface AssistantMessage {
|
|
42
|
+
role: 'assistant';
|
|
43
|
+
content: MessageContent[];
|
|
44
|
+
tool_calls?: ToolCall[];
|
|
45
|
+
id?: string;
|
|
46
|
+
}
|
|
47
|
+
/** user message for TUI display (echo user input). */
|
|
48
|
+
interface UserMessage {
|
|
49
|
+
role: 'user';
|
|
50
|
+
content: string;
|
|
51
|
+
/**
|
|
52
|
+
* pending 标记——prompt 发出后、模型返回首字节前为 true(灰色 dim 渲染 + ESC 可撤回)。
|
|
53
|
+
* streaming.start 事件到达后由 clearPendingEcho 转正(置 false)。撤回时整条消息从
|
|
54
|
+
* 对话流移除(等价于"没发过这条消息")。
|
|
55
|
+
*/
|
|
56
|
+
streaming?: boolean;
|
|
57
|
+
id?: string;
|
|
58
|
+
}
|
|
59
|
+
/** tool call message — ⏺ Name(args) + ⎿ result + ✓/✗,按工具类型分发渲染. */
|
|
60
|
+
interface ToolMessage {
|
|
61
|
+
role: 'tool';
|
|
62
|
+
name: string;
|
|
63
|
+
args?: string;
|
|
64
|
+
/** 原始参数对象(供 edit diff / write_todos 任务栏 / task_delegate 子代理分发) */
|
|
65
|
+
argsObj?: Record<string, unknown>;
|
|
66
|
+
result?: string;
|
|
67
|
+
isError?: boolean;
|
|
68
|
+
id?: string;
|
|
69
|
+
}
|
|
70
|
+
/** 回合完成摘要(底部一行:状态 + 工具数 + 耗时 + token 消耗 + 模型)。 */
|
|
71
|
+
interface SummaryMessage {
|
|
72
|
+
role: 'summary';
|
|
73
|
+
/**
|
|
74
|
+
* `incomplete` = 回合停了但 todo 面板仍有未完成项(不再用 `done` 冒充 task-complete)。
|
|
75
|
+
*/
|
|
76
|
+
status: 'done' | 'error' | 'interrupted' | 'incomplete';
|
|
77
|
+
toolCount: number;
|
|
78
|
+
elapsedMs: number;
|
|
79
|
+
/** 本轮 token 消耗(prompt + completion),显示在主摘要行工具数和耗时之后。 */
|
|
80
|
+
tokensUsed?: number;
|
|
81
|
+
/**
|
|
82
|
+
* RFC-019 M1:本轮缓存命中率(R1 = cacheRead / totalInput,范围 [0,1])。
|
|
83
|
+
* `undefined` = 供应商没有相应缓存 API 或本回合无 usage 数据——渲染层据此隐藏该字段,
|
|
84
|
+
* 不展示可能永远是 0 的误导性数字。
|
|
85
|
+
*/
|
|
86
|
+
cacheHitRatio?: number;
|
|
87
|
+
/** 本轮实际使用的模型 id(summary 行末显示;session.model 真源)。 */
|
|
88
|
+
model?: string;
|
|
89
|
+
/** `incomplete` 时携带 todo 完成度,渲染 "N/M · K left"。 */
|
|
90
|
+
tasksDone?: number;
|
|
91
|
+
tasksTotal?: number;
|
|
92
|
+
/** 回合完成时刻(epoch ms,cli 侧 reducer 生成)。摘要行末尾灰色渲染 "YYYY-MM-DD HH:MM:SS"。 */
|
|
93
|
+
completedAt?: number;
|
|
94
|
+
id?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* P0 (anti-flicker):流式正文的「已稳定块」增量提交进 <Static>,使动态区高度恒定
|
|
98
|
+
* (用终端原生 scrollback 承载已稳定块)。lead=该回复首块(渲 ⏺ 圆点),
|
|
99
|
+
* 续块对齐缩进无圆点,视觉上仍是同一段连续回复。
|
|
100
|
+
*/
|
|
101
|
+
interface StreamChunkMessage {
|
|
102
|
+
role: 'assistant_stream';
|
|
103
|
+
text: string;
|
|
104
|
+
lead?: boolean;
|
|
105
|
+
id?: string;
|
|
106
|
+
}
|
|
107
|
+
/** 面板/模态信息——仅上下边框,如 /permissions 输出。代码块 JSON 渲染。 */
|
|
108
|
+
interface PaneMessage {
|
|
109
|
+
role: 'pane';
|
|
110
|
+
/** 可选标题(上边框下方第一行,bold)。 */
|
|
111
|
+
title?: string;
|
|
112
|
+
/** 代码块正文。 */
|
|
113
|
+
code: string;
|
|
114
|
+
/** 代码语言(如 json)。 */
|
|
115
|
+
language?: string;
|
|
116
|
+
id?: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 压缩边界——对话流内工具调用风格的单行标记(headerLine:`✓ Compact(before → after
|
|
120
|
+
* 比例条)`),与 Edit/Write/Read 等真实工具调用共用同一视觉语言。自动压缩与手动
|
|
121
|
+
* /compact 都经 compaction.end 会话事件推此消息进转录,取代瞬时 toast,使压缩在
|
|
122
|
+
* 对话流中可见(Gap B)。
|
|
123
|
+
*/
|
|
124
|
+
interface CompactBoundaryMessage {
|
|
125
|
+
role: 'compact_boundary';
|
|
126
|
+
/** 压缩前/后的 LLM 视图消息数(buildContext 口径)。 */
|
|
127
|
+
before: number;
|
|
128
|
+
after: number;
|
|
129
|
+
id?: string;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 裁剪边界——本会话首次裁剪(prune)时对话流插一条单行标记「工具输出已裁剪以适应上下文」。
|
|
133
|
+
* prune 每轮可触发,故 CLI 端只在首次推此消息(去重),之后静默。区别于压缩(离散边界、带前后计数)。
|
|
134
|
+
*/
|
|
135
|
+
interface PruneBoundaryMessage {
|
|
136
|
+
role: 'prune_boundary';
|
|
137
|
+
id?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 历史封顶边界(修复:历史裁剪可观测性,2026-07-12;语义澄清:RFC-159 T6,2026-07-13)——
|
|
141
|
+
* 会话内存态消息数超上限(默认 2000 条)时对话流插一条单行标记「最早 N 条历史已从内存
|
|
142
|
+
* 视图移除」。与 prune_boundary 的区别:prune 是 token 维度的工具输出截短(可能每轮触发,
|
|
143
|
+
* 只提示一次即静默);本消息是**驻留维度的内存视图裁剪**(@x-otto/session
|
|
144
|
+
* capStoredHistory / capStoredHistoryByBytes,只操作内存数组)。
|
|
145
|
+
*
|
|
146
|
+
* **RFC-321 语义更新**:①主闸已由条数改为字节预算(条数退为结构兜底),故不再是"纯条数
|
|
147
|
+
* 维度";②"与模型上下文塑造无关"仅在**无损**路径成立——常态下裁剪只碰已被摘要覆盖的
|
|
148
|
+
* 死历史(R12 压缩前置保证),但压缩连续失败后的兜底裁剪(`lossy`)会真实削减模型上下文,
|
|
149
|
+
* 此时该表述不成立,必须按 lossy 分型提示。**RFC-159 起持久层为
|
|
150
|
+
* append-forever**:默认 SQLite 后端从不因此裁剪删除已持久化的 DB 行,被移出内存视图的
|
|
151
|
+
* 消息仍完整保留在存储中(`/session export` 可导出全量);仅已废弃的 `OTTO_SESSION_BLOB=1`
|
|
152
|
+
* 逃生口后端会整份快照覆写、导致真实数据丢失。携带具体条数(`removedCount`)供用户感知
|
|
153
|
+
* 内存视图收窄的范围。
|
|
154
|
+
*/
|
|
155
|
+
interface HistoryCappedMessage {
|
|
156
|
+
role: 'history_capped';
|
|
157
|
+
/** 本次从内存视图移除的消息条目数(不代表持久化层删除,见上方类型注释)。 */
|
|
158
|
+
removedCount: number;
|
|
159
|
+
/** RFC-178 D6:触发来源分型(缺省视为 'count')——条数上限 / 字节预算 / 内存压力收紧。 */
|
|
160
|
+
trigger?: 'count' | 'bytes' | 'memory-pressure';
|
|
161
|
+
/**
|
|
162
|
+
* RFC-321 R12:本次裁剪是否**有损**——即裁掉的是模型仍在使用、且**没有摘要覆盖**的
|
|
163
|
+
* 活跃上下文(纯信息丢失),而非常态的"已被摘要替换的死历史"(无损)。
|
|
164
|
+
*
|
|
165
|
+
* 仅在"裁剪会触及活跃上下文 + 逃生阀压缩已连续失败达阈值"时为 true。渲染上**优先于
|
|
166
|
+
* `trigger` 分型**并走 warn 态——其余三种分型的文案都写着"存储中仍完整保留",对 lossy
|
|
167
|
+
* 场景会误导用户以为上下文没有损失。
|
|
168
|
+
*/
|
|
169
|
+
lossy?: boolean;
|
|
170
|
+
id?: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 写租约被拒边界(2026-07-14 修复)——RFC-159 D3 会话写租约被另一存活进程持有时,
|
|
174
|
+
* 对话流插一条单行标记「本轮改动未保存」。与 history_capped 同一"持续性数据风险,
|
|
175
|
+
* 每次真实发生都留痕"的设计(不做"仅首次"去重)——每条标记代表一次真实的落盘失败,
|
|
176
|
+
* 用户滚动历史时能看清从哪一轮开始丢失,是事后排查数据丢失范围的直接线索。toast
|
|
177
|
+
* 只在首次弹出详细原因+解决路径(易错过、瞬时),本消息是不会消失的持久痕迹。
|
|
178
|
+
*/
|
|
179
|
+
interface WriteLeaseDeniedMessage {
|
|
180
|
+
role: 'write_lease_denied';
|
|
181
|
+
id?: string;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* 写租约恢复边界(2026-07-14 修复)——与 write_lease_denied 对称:此前只读降级的会话
|
|
185
|
+
* 后续 save 成功获取到租约后插入,与 denied 标记在转录里首尾呼应,用户能精确看到
|
|
186
|
+
* 只读区间的边界(从哪轮开始丢、到哪轮恢复)。
|
|
187
|
+
*/
|
|
188
|
+
interface WriteLeaseRestoredMessage {
|
|
189
|
+
role: 'write_lease_restored';
|
|
190
|
+
id?: string;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* RFC-186 D6:turn 边界暂停已生效——Agent 运行已暂停,排队消息不会自动执行。
|
|
194
|
+
* 对话流中的持久边界标记,供历史回看时知晓"何时暂停、何时恢复"。
|
|
195
|
+
*/
|
|
196
|
+
interface RunPausedMessage {
|
|
197
|
+
role: 'run_paused';
|
|
198
|
+
id?: string;
|
|
199
|
+
/** 本回合总共执行的工具数 */
|
|
200
|
+
toolCount?: number;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* RFC-186 D6:暂停已解除,Agent 已恢复运行。
|
|
204
|
+
*/
|
|
205
|
+
interface RunResumedMessage {
|
|
206
|
+
role: 'run_resumed';
|
|
207
|
+
id?: string;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* RFC-186 D6:等待中的暂停请求已被取消——仅在 turn 边界到达前有效。
|
|
211
|
+
*/
|
|
212
|
+
interface RunPauseCancelledMessage {
|
|
213
|
+
role: 'run_pause_cancelled';
|
|
214
|
+
id?: string;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* RFC-144 M2:lifecycleAsync 工具完成通知——渲染投影层,语义与协议层
|
|
218
|
+
* `SystemNotificationMessage`(role:'system_notification')不同(同 lesson_46:手抄
|
|
219
|
+
* ToolCall/AssistantMessage 是刻意维持的独立渲染形状,非协议层镜像)。单行标记,
|
|
220
|
+
* 区别于 ToolMessage(同步/普通异步工具的完整 ⏺/⎿ 渲染)——lifecycleAsync 工具的
|
|
221
|
+
* "启动"事件走 ToolMessage(placeholder tool_result),"完成"事件才走本类型。
|
|
222
|
+
*/
|
|
223
|
+
interface ToolCompletionMessage {
|
|
224
|
+
role: 'tool_completion';
|
|
225
|
+
/** 已格式化的通知正文(对应协议层 SystemNotificationMessage.content)。 */
|
|
226
|
+
content: string;
|
|
227
|
+
isError?: boolean;
|
|
228
|
+
id?: string;
|
|
229
|
+
}
|
|
230
|
+
/** 模型切换边界——切换模型时对话流插一条单行标记,使切换在转录里可见。 */
|
|
231
|
+
interface ModelSwitchMessage {
|
|
232
|
+
role: 'model_switch';
|
|
233
|
+
/** 已格式化的模型显示串(如 "claude-haiku-4-5-20251001 (200K)")。 */
|
|
234
|
+
label: string;
|
|
235
|
+
id?: string;
|
|
236
|
+
}
|
|
237
|
+
/** 推理投入档切换边界——/effort 切换时对话流插一条单行标记(与 model_switch 同族)。 */
|
|
238
|
+
interface EffortSwitchMessage {
|
|
239
|
+
role: 'effort_switch';
|
|
240
|
+
/** 已格式化的档位显示串(如 "High")。 */
|
|
241
|
+
label: string;
|
|
242
|
+
id?: string;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* 模型回退边界——启动时配置的模型不可用(未认证 provider / catalog 未拉),引擎回退到可用模型。
|
|
246
|
+
* 区别于 model_switch(主动切换、单行标记):这是降级事件、信息量大,渲染为对话流 Dialog
|
|
247
|
+
* (标题/隔行/configured→active/提示/隔行)。
|
|
248
|
+
*/
|
|
249
|
+
interface ModelFallbackMessage {
|
|
250
|
+
role: 'model_fallback';
|
|
251
|
+
/** 配置但不可用的模型 id(如 "anthropic/claude-haiku-4-5-20251001")。 */
|
|
252
|
+
configured: string;
|
|
253
|
+
/** 实际回退生效的模型显示串(如 "deepseek-v4-pro (1M)")。 */
|
|
254
|
+
active: string;
|
|
255
|
+
id?: string;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* 本地命令回显(RFC-233)——斜杠命令的调用与结果作为对话流内一个独立视觉单元渲染,
|
|
259
|
+
* UI-only:`pushMessage` 只写入 TUI 渲染层的 `messageStore`(纯内存数组),从不落
|
|
260
|
+
* trace(无 `recorder.record` 调用)、从不进 `AgentMessage[]`/session(无
|
|
261
|
+
* `session.session.append` 调用)、因此永不作为上下文发给 LLM——与 compact_boundary/
|
|
262
|
+
* history_capped 等既有 UI-only 类型同源架构保证。
|
|
263
|
+
*
|
|
264
|
+
* 取代此前把命令结果伪装成 `pushMessage({role:'assistant'})` 的反模式(8+ 处历史调用点,
|
|
265
|
+
* 见 model-auth.ts 的迁移注释:"此前用 pushMessage 把结果塞进对话转录,既污染对话历史又
|
|
266
|
+
* 无法承载可操作按钮")——本类型有独立 role,视觉上明确标记"这是本地命令,非 AI 发言"。
|
|
267
|
+
*
|
|
268
|
+
* 使用边界:仅用于**产出信息性内容**的命令(如 /diagnose、/trace-gc --dry-run、
|
|
269
|
+
* /session unlock 诊断态);纯确认性、无信息增量的操作(/clear、/rename、/pin 等)
|
|
270
|
+
* 继续用 `showToast`(瞬态浮层,无需留痕在转录流)。
|
|
271
|
+
*/
|
|
272
|
+
interface CommandEchoMessage {
|
|
273
|
+
role: 'command_echo';
|
|
274
|
+
/** 完整命令行回显(如 "/diagnose" 或 "/trace-gc --dry-run")。 */
|
|
275
|
+
command: string;
|
|
276
|
+
/** 结果状态——决定 headerLine 符号与配色(✓ success / ⚠ warning / ✗ error)。缺省 'ok'。 */
|
|
277
|
+
status?: 'ok' | 'warn' | 'error';
|
|
278
|
+
/** 单行结果摘要(headerLine argPreview 位置,超宽 truncate-end)。 */
|
|
279
|
+
summary?: string;
|
|
280
|
+
/** 多行详情(可选,缩进渲染)。默认不截断——命令回显多为用户主动查询的诊断性内容,
|
|
281
|
+
* 截断会丢失用户想看的信息;需要限流由调用方自行截断后传入。 */
|
|
282
|
+
detail?: string;
|
|
283
|
+
id?: string;
|
|
284
|
+
}
|
|
285
|
+
/** Any message renderable in the TUI REPL. */
|
|
286
|
+
type ChatMessage = AssistantMessage | UserMessage | ToolMessage | SummaryMessage | StreamChunkMessage | PaneMessage | CompactBoundaryMessage | PruneBoundaryMessage | HistoryCappedMessage | ModelSwitchMessage | EffortSwitchMessage | ModelFallbackMessage | ToolCompletionMessage | WriteLeaseDeniedMessage | WriteLeaseRestoredMessage | RunPausedMessage | RunResumedMessage | RunPauseCancelledMessage | CommandEchoMessage;
|
|
287
|
+
/** 通知项(通知中心弹窗 + 状态栏铃铛)。 */
|
|
288
|
+
interface AppNotification {
|
|
289
|
+
id: number;
|
|
290
|
+
source: 'job' | 'version' | 'extension' | 'system';
|
|
291
|
+
level: 'info' | 'warning' | 'error';
|
|
292
|
+
title: string;
|
|
293
|
+
message: string;
|
|
294
|
+
timestamp: number;
|
|
295
|
+
read: boolean;
|
|
296
|
+
/** 可选操作(如 "/delegates"、"/extension",enter 时触发)。 */
|
|
297
|
+
action?: string;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* RFC-186 D3:暂停浮层数据项。notificationStore.pauseDialog 非 null 时 App.tsx 渲染
|
|
301
|
+
* PauseDialog 组件。两个阶段:requested(等待 turn 边界)+ active(已暂停)。
|
|
302
|
+
*/
|
|
303
|
+
interface PauseDialogItem {
|
|
304
|
+
phase: 'requested' | 'active';
|
|
305
|
+
requestedAt: number;
|
|
306
|
+
toolCount: number;
|
|
307
|
+
totalToolCount?: number;
|
|
308
|
+
onCancel?: () => void;
|
|
309
|
+
onResume?: () => void;
|
|
310
|
+
onDismiss?: () => void;
|
|
311
|
+
}
|
|
312
|
+
/** RFC-208:满意度脉冲调查三档评分。 */
|
|
313
|
+
type PulseSurveyRating = 'good' | 'neutral' | 'bad';
|
|
314
|
+
/**
|
|
315
|
+
* RFC-208 §3.2/§3.4:满意度脉冲调查浮层数据项。notificationStore.pulseSurvey 非 null 时
|
|
316
|
+
* App.tsx 渲染 PulseSurveyOverlay 组件(Band B 标准形态——同 errorRetry/retry)。
|
|
317
|
+
* RFC-251 Phase 4f 后,键盘处理由 PulseSurveyOverlay 通过 FocusBus 自管。
|
|
318
|
+
*
|
|
319
|
+
* 两阶段:'rating'(评分选择)→ 'comment'(可选意见输入)。阶段切换/选中态/输入内容
|
|
320
|
+
* 由组件 FocusBus handler 调用 onPulseSurveyChange 驱动更新。
|
|
321
|
+
*/
|
|
322
|
+
interface PulseSurveyItem {
|
|
323
|
+
phase: 'rating' | 'comment';
|
|
324
|
+
/** phase='comment' 时已确定;phase='rating' 时为 null。 */
|
|
325
|
+
rating: PulseSurveyRating | null;
|
|
326
|
+
/** phase='rating' 时的 Choices 高亮索引(0=good, 1=neutral, 2=bad)。 */
|
|
327
|
+
selectedIndex: number;
|
|
328
|
+
/** phase='comment' 时的当前输入内容。 */
|
|
329
|
+
commentText: string;
|
|
330
|
+
/** phase='comment' 时的光标偏移(字符索引,同 InputDialog 模式)。 */
|
|
331
|
+
commentOffset: number;
|
|
332
|
+
/** 提交(评分 + 可能为空的意见文字)——阶段 2 无论 Enter 还是 Esc 退出都调用。 */
|
|
333
|
+
onSubmit: (rating: PulseSurveyRating, comment: string | undefined) => void;
|
|
334
|
+
/** 关闭(Esc 阶段 1 不留痕迹 / 阶段 2 提交后 / forced-upgrade 抢占清除)。 */
|
|
335
|
+
onClose: () => void;
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/theme/colors.d.ts
|
|
339
|
+
/**
|
|
340
|
+
* colors.ts — 调色板、语义色、色值工具函数。
|
|
341
|
+
*/
|
|
342
|
+
/** 基础调色板。 */
|
|
343
|
+
declare const PALETTE: {
|
|
344
|
+
readonly ink: "#0D0E11";
|
|
345
|
+
readonly carbon: "#16181D";
|
|
346
|
+
readonly white: "#F4F3EF"; /** 品牌三色:远航藏青 Brand Navy / 拾月紫 Accent Purple / 沧溟墨 Ink Gray。 */
|
|
347
|
+
readonly brandNavy: "#14348C";
|
|
348
|
+
readonly brandPurple: "#A28EF9";
|
|
349
|
+
readonly brandInk: "#12152B"; /** 拾月紫亮/暗端。 */
|
|
350
|
+
readonly purpleBright: "#D1BCFF";
|
|
351
|
+
readonly purpleDim: "#4F3E8C"; /** 远航藏青"交互焦点"亮端——focusBorder/selection/suggestion/permission 专用。 */
|
|
352
|
+
readonly navyBright: "#2D59C8";
|
|
353
|
+
readonly navyDim: "#0F2A73"; /** 注释蓝灰(品牌手册官方灰阶 gray-8)。 */
|
|
354
|
+
readonly comment: "#9498B8";
|
|
355
|
+
};
|
|
356
|
+
/** 状态五色(取自语法高亮 One-Dark 系)。 */
|
|
357
|
+
declare const STATUS: {
|
|
358
|
+
readonly success: "#98C379";
|
|
359
|
+
readonly error: "#E06C75";
|
|
360
|
+
readonly warning: "#E5C07B";
|
|
361
|
+
readonly info: "#61AFEF";
|
|
362
|
+
readonly special: "#C678DD";
|
|
363
|
+
};
|
|
364
|
+
/**
|
|
365
|
+
* 语义角色 → 具体色。消费方只引语义名,便于整体换肤。
|
|
366
|
+
* 分组:品牌琥珀 / 文本 / 状态 / 信息蓝 / diff / chrome。
|
|
367
|
+
*/
|
|
368
|
+
interface ThemeColors {
|
|
369
|
+
/** 品牌字标(Welcome "otto")。 */
|
|
370
|
+
brand: string;
|
|
371
|
+
/** 品牌字标渐变亮端。 */
|
|
372
|
+
brandShimmer: string;
|
|
373
|
+
accent: string;
|
|
374
|
+
/** 呼吸/glow 渐变暗端(hex)。 */
|
|
375
|
+
accentDim: string;
|
|
376
|
+
/** 呼吸/glow 渐变亮端。 */
|
|
377
|
+
accentBright: string;
|
|
378
|
+
/** 主文本——undefined=终端默认前景(自适应明暗)。 */
|
|
379
|
+
text: string | undefined;
|
|
380
|
+
inactive: string;
|
|
381
|
+
/** 次级文本——比 inactive 深,用于工具名/面板 label 等需要明确可读但非主角的内容。 */
|
|
382
|
+
secondary: string;
|
|
383
|
+
/** 预留:比 inactive 更弱的次级文本(当前同 inactive 值;保留供分级弱化)。 */
|
|
384
|
+
subtle: string;
|
|
385
|
+
/** 助手回复行首前缀 `>` 的颜色——与用户前缀(inactive 灰)区分。 */
|
|
386
|
+
replyPrefix: string;
|
|
387
|
+
success: string;
|
|
388
|
+
error: string;
|
|
389
|
+
warning: string;
|
|
390
|
+
special: string;
|
|
391
|
+
/** 自动补全/提示/标识符高亮(模型名、/命令、语言标签)。 */
|
|
392
|
+
suggestion: string;
|
|
393
|
+
/** 权限请求高亮(工具名/命令)。 */
|
|
394
|
+
permission: string;
|
|
395
|
+
/** 行内 `code` 强调色——青/蓝系,区别于 *italic*(斜体)与 **bold**(加粗);用青系区分 codespan。 */
|
|
396
|
+
codeText: string;
|
|
397
|
+
diffAdd: string;
|
|
398
|
+
diffRemove: string;
|
|
399
|
+
/** diff 行背景 tint(GitHub 风)。 */
|
|
400
|
+
diffAddBg: string;
|
|
401
|
+
diffRemoveBg: string;
|
|
402
|
+
/** 浮层/面板统一边框色——所有弹层/面板的上下灰线(配合 PANEL_BORDER 形状常量)。 */
|
|
403
|
+
panelBorder: string;
|
|
404
|
+
/** 浮层/面板暗底——所有 dialog/toast 的统一背景色(hex)。 */
|
|
405
|
+
overlayBg: string;
|
|
406
|
+
/** 内联标签(Tag 组件)的浅色底——比 overlayBg 稍亮的微高亮块,衬托 `[label]`。 */
|
|
407
|
+
tagBg: string;
|
|
408
|
+
/** 工具调用 / Thought 块文字色——同 secondary。
|
|
409
|
+
* @deprecated 新代码用 THEME.secondary 替代,toolText 保留兼容旧消费方。 */
|
|
410
|
+
toolText: string;
|
|
411
|
+
/** 聚焦态高亮——亮蓝色:弹窗标题文字、配置引导提示等(边框已统一为 panelBorder 灰,不再用蓝)。 */
|
|
412
|
+
focusBorder: string;
|
|
413
|
+
/** 选中/激活前景——亮蓝色(与 focusBorder 同色系,语义独立):列表/菜单/树选中行、激活 tab/按钮。 */
|
|
414
|
+
selection: string;
|
|
415
|
+
}
|
|
416
|
+
/** 固定配色——所有 AA 正常文字 ≥4.5:1。 */
|
|
417
|
+
declare const THEME: ThemeColors;
|
|
418
|
+
//#endregion
|
|
419
|
+
//#region src/theme/figures.d.ts
|
|
420
|
+
/** 符号常量(统一字形)。渲染层引这里,不写裸字形。 */
|
|
421
|
+
declare const DEFAULT_FIGURES: {
|
|
422
|
+
/** 助手回复行首前缀 ●(实心圆,与用户前缀 `>` 异符异色,强化对话角色区分)。 */readonly bullet: "●"; /** 工具结果折叠角标 ⎿ */
|
|
423
|
+
readonly toolResult: "⎿"; /** thinking 前缀 ∴ */
|
|
424
|
+
readonly thinking: "∴"; /** 引用竖线 ▎ */
|
|
425
|
+
readonly quoteBar: "▎"; /** 用户输入前缀 > */
|
|
426
|
+
readonly userPrompt: ">"; /** 本地命令回显前缀 ❯ */
|
|
427
|
+
readonly commandPrompt: "❯"; /** 水平分隔 ─(细线) */
|
|
428
|
+
readonly hr: "─"; /** 成功/失败标记 */
|
|
429
|
+
readonly check: "✓";
|
|
430
|
+
readonly cross: "✗"; /** 任务列表复选框:未勾 ☐ / 已勾 ☑ */
|
|
431
|
+
readonly checkboxOff: "☐";
|
|
432
|
+
readonly checkboxOn: "☑"; /** 任务状态:未开始 ○ / 进行中 ◐ / 完成 ● */
|
|
433
|
+
readonly todoPending: "○";
|
|
434
|
+
readonly todoActive: "◐";
|
|
435
|
+
readonly todoDone: "●"; /** 呼吸圆圈:暗(空心)○ / 亮(实心)● */
|
|
436
|
+
readonly breatheDim: "○";
|
|
437
|
+
readonly breatheBright: "●"; /** 省略号 */
|
|
438
|
+
readonly ellipsis: "…"; /** 列表/typeahead 选中行指示箭头 ▶ */
|
|
439
|
+
readonly pointer: "▶"; /** 开关态:开 ◉ / 关 ○ */
|
|
440
|
+
readonly toggleOn: "◉";
|
|
441
|
+
readonly toggleOff: "○"; /** 告警符号 ⚠ */
|
|
442
|
+
readonly warn: "⚠"; /** 对话选中态保护——用户手动冻结指示 ❄ */
|
|
443
|
+
readonly frozen: "❄"; /** 等待输入态 ◑ */
|
|
444
|
+
readonly needsInput: "◑"; /** 状态圆点 ● */
|
|
445
|
+
readonly statusDot: "●"; /** 条目激活标记 ▸ */
|
|
446
|
+
readonly itemActive: "▸"; /** 注意/待处理菱形 ◆ */
|
|
447
|
+
readonly attention: "◆"; /** Sparkline 八阶块字符 */
|
|
448
|
+
readonly sparkline: "▁▂▃▄▅▆▇█"; /** LineGauge 已完成段 ━ */
|
|
449
|
+
readonly gaugeFilled: "━"; /** LineGauge 未完成段 ╌ */
|
|
450
|
+
readonly gaugeRest: "╌"; /** Scrollbar thumb 右半块 ▐ */
|
|
451
|
+
readonly scrollThumb: "▐"; /** 委托任务识别到的服务前缀 ↕ */
|
|
452
|
+
readonly service: "↕"; /** 已编辑文件标记 ✎(RFC-309 SummaryStrip) */
|
|
453
|
+
readonly edited: "✎"; /** 定时/计划任务标记 ◷(RFC-309 SummaryStrip) */
|
|
454
|
+
readonly scheduled: "◷"; /** 剪贴板信号 ✓(复制成功提示) */
|
|
455
|
+
readonly clipboard: "✓"; /** LLM 调用阶段箭头:requesting ↑,responding ↓ */
|
|
456
|
+
readonly requesting: "↑";
|
|
457
|
+
readonly responding: "↓";
|
|
458
|
+
};
|
|
459
|
+
type FiguresMap = typeof DEFAULT_FIGURES;
|
|
460
|
+
/** 符号常量表(固定值,不再支持运行时覆盖)。 */
|
|
461
|
+
declare const FIGURES: FiguresMap;
|
|
462
|
+
//#endregion
|
|
463
|
+
//#region src/theme/borders.d.ts
|
|
464
|
+
/**
|
|
465
|
+
* borders.ts — 面板/弹层边框形态常量。
|
|
466
|
+
*/
|
|
467
|
+
/**
|
|
468
|
+
* 内联面板统一边框形状——仅上下两条单线(无左右)。
|
|
469
|
+
*
|
|
470
|
+
* **单一真源**:所有内联 UI 元素写 `<Box {...PANEL_BORDER} borderColor={THEME.panelBorder}>`。
|
|
471
|
+
*/
|
|
472
|
+
declare const PANEL_BORDER: {
|
|
473
|
+
readonly borderStyle: "single";
|
|
474
|
+
readonly borderTop: true;
|
|
475
|
+
readonly borderBottom: true;
|
|
476
|
+
readonly borderLeft: false;
|
|
477
|
+
readonly borderRight: false;
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* DIALOG_BORDER — 所有弹层/对话框的统一边框形态(四边圆角 `╭─╮`)。
|
|
481
|
+
*
|
|
482
|
+
* **单一真源**:所有经 DialogFrame 呈现的弹层写此常量。历史上曾有 `BORDER_VARIANTS`
|
|
483
|
+
* 三档(hard/nav/overlay)按界面层级分不同形态(RFC-183 D1),但 2026-07-22 commit
|
|
484
|
+
* 9466cb7c9「统一所有弹层为四边圆角」有意将三档收敛为同一形态;RFC-266 D1 据此删除
|
|
485
|
+
* 无差异的 variant API,收敛为本单一常量(语义分层由 focus-registry band 承载,边框层
|
|
486
|
+
* 不再重复编码)。将来若需按层级再分化边框,以新 RFC 重新设计,不保留投机性 API。
|
|
487
|
+
*/
|
|
488
|
+
declare const DIALOG_BORDER: {
|
|
489
|
+
readonly borderStyle: "round";
|
|
490
|
+
readonly borderTop: true;
|
|
491
|
+
readonly borderBottom: true;
|
|
492
|
+
readonly borderLeft: true;
|
|
493
|
+
readonly borderRight: true;
|
|
494
|
+
};
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region src/theme/spacing.d.ts
|
|
497
|
+
/**
|
|
498
|
+
* spacing.ts — 间距 scale 与布局裕量常量。
|
|
499
|
+
*/
|
|
500
|
+
/**
|
|
501
|
+
* SPACING — 间距 scale(对标 Radix Themes 9 级 spacing,缩减为终端字符网格 4 级)。
|
|
502
|
+
*
|
|
503
|
+
* **单一真源**:全部 margin/padding/gap 系 Ink Box props 引用本常量,不再写裸数字。
|
|
504
|
+
*/
|
|
505
|
+
declare const SPACING: {
|
|
506
|
+
readonly none: 0;
|
|
507
|
+
readonly tight: 1;
|
|
508
|
+
readonly section: 2;
|
|
509
|
+
readonly loose: 4;
|
|
510
|
+
};
|
|
511
|
+
/**
|
|
512
|
+
* LAYOUT — 宽度裕量常量。
|
|
513
|
+
*/
|
|
514
|
+
declare const LAYOUT: {
|
|
515
|
+
/** 通用内容裕量——最常见的 `columns - 4` 场景。 */readonly contentInset: 4; /** 边框内裕量——已在 DialogFrame/PANEL_BORDER 内部的场景(`columns - 2`)。 */
|
|
516
|
+
readonly borderInset: 2;
|
|
517
|
+
};
|
|
518
|
+
//#endregion
|
|
519
|
+
//#region src/theme/theme-registry.d.ts
|
|
520
|
+
type ThemeAppearance = 'dark' | 'light';
|
|
521
|
+
type ThemeResolveMode = ThemeAppearance | 'system';
|
|
522
|
+
type ThemePresetSource = {
|
|
523
|
+
kind: 'builtin';
|
|
524
|
+
} | {
|
|
525
|
+
kind: 'extension';
|
|
526
|
+
extensionId: string;
|
|
527
|
+
};
|
|
528
|
+
interface MarkdownThemeOverrides {
|
|
529
|
+
heading1?: keyof ThemeColors;
|
|
530
|
+
heading2?: keyof ThemeColors;
|
|
531
|
+
headingWeak?: keyof ThemeColors;
|
|
532
|
+
listMarker?: keyof ThemeColors;
|
|
533
|
+
listMarkerMuted?: keyof ThemeColors;
|
|
534
|
+
quoteBar?: keyof ThemeColors;
|
|
535
|
+
quoteText?: keyof ThemeColors;
|
|
536
|
+
link?: keyof ThemeColors;
|
|
537
|
+
inlineCode?: keyof ThemeColors;
|
|
538
|
+
codeFence?: keyof ThemeColors;
|
|
539
|
+
tableHeader?: keyof ThemeColors;
|
|
540
|
+
tableDivider?: keyof ThemeColors;
|
|
541
|
+
listIndent?: 2 | 3;
|
|
542
|
+
listMarkers?: readonly [string, string, string, string];
|
|
543
|
+
codeBlockDivider?: 'hr' | 'none';
|
|
544
|
+
}
|
|
545
|
+
interface ThemePresetInput {
|
|
546
|
+
/** Builtin may pass id directly; extension ids are generated as `${extensionId}/${localId}`. */
|
|
547
|
+
id?: string;
|
|
548
|
+
localId?: string;
|
|
549
|
+
label: string;
|
|
550
|
+
appearance: ThemeAppearance;
|
|
551
|
+
colors: ThemeColors;
|
|
552
|
+
markdown?: MarkdownThemeOverrides;
|
|
553
|
+
meta?: {
|
|
554
|
+
author?: string;
|
|
555
|
+
description?: string;
|
|
556
|
+
version?: string;
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
interface ThemePreset extends Omit<ThemePresetInput, 'id'> {
|
|
560
|
+
id: string;
|
|
561
|
+
source: ThemePresetSource;
|
|
562
|
+
}
|
|
563
|
+
interface ThemePresetSelection {
|
|
564
|
+
dark?: string;
|
|
565
|
+
light?: string;
|
|
566
|
+
}
|
|
567
|
+
declare class ThemeRegistry {
|
|
568
|
+
private readonly presets;
|
|
569
|
+
private readonly presetSourceKeys;
|
|
570
|
+
register(source: ThemePresetSource, input: ThemePresetInput): ThemePreset;
|
|
571
|
+
unregisterBySource(source: ThemePresetSource): number;
|
|
572
|
+
get(id: string): ThemePreset | undefined;
|
|
573
|
+
list(): ThemePreset[];
|
|
574
|
+
resolve(mode: ThemeResolveMode, systemAppearance?: ThemeAppearance, selection?: ThemePresetSelection): ThemePreset;
|
|
575
|
+
}
|
|
576
|
+
declare function createBuiltinThemeRegistry(): ThemeRegistry;
|
|
577
|
+
//#endregion
|
|
578
|
+
//#region src/i18n/types/index.d.ts
|
|
579
|
+
/**
|
|
580
|
+
* i18n-types.ts — 共享基础类型(Risk / Lang / LangMode)。
|
|
581
|
+
*
|
|
582
|
+
* 从 i18n.ts 提取,供所有子接口文件无循环依赖地引用。
|
|
583
|
+
*/
|
|
584
|
+
type Risk = 'low' | 'medium' | 'high';
|
|
585
|
+
type Lang = 'en' | 'zh';
|
|
586
|
+
type LangMode = Lang | 'auto';
|
|
587
|
+
//#endregion
|
|
588
|
+
//#region src/i18n/setup.d.ts
|
|
589
|
+
type Locale = 'en' | 'zh';
|
|
590
|
+
/** 初始化 i18next(幂等:已初始化则切 locale)。lng 由调用方按环境/配置解析后传入。 */
|
|
591
|
+
declare function initI18n(lng: Locale): i18n;
|
|
592
|
+
/**
|
|
593
|
+
* 全局翻译函数(= i18next.t,类型安全)。组件与非组件统一用它,避免 hook 放置约束。
|
|
594
|
+
* 运行时切语言经 changeLanguage + 全量重渲染刷新(P6 接线)。
|
|
595
|
+
*/
|
|
596
|
+
declare const t: typeof i18next.t;
|
|
597
|
+
//#endregion
|
|
598
|
+
//#region src/i18n/index.d.ts
|
|
599
|
+
/** 自动检测语言:读环境 LC_ALL/LC_MESSAGES/LANG,含 zh 即中文,否则英文。 */
|
|
600
|
+
declare function detectLanguage(): Lang;
|
|
601
|
+
//#endregion
|
|
602
|
+
//#region src/stores/store.d.ts
|
|
603
|
+
interface Store<T> {
|
|
604
|
+
getState: () => T;
|
|
605
|
+
setState: (update: Partial<T> | ((prev: T) => Partial<T>)) => void;
|
|
606
|
+
subscribe: (listener: () => void) => () => void;
|
|
607
|
+
/** 底层 zustand StoreApi,供需要 zustand 原生能力的高级消费方(devtools 等)使用;
|
|
608
|
+
* 常规消费走上面三个方法即可。 */
|
|
609
|
+
readonly zustand: StoreApi<T>;
|
|
610
|
+
}
|
|
611
|
+
declare function useAppState<T, R>(store: Store<T>, selector: (state: T) => R): R;
|
|
612
|
+
//#endregion
|
|
613
|
+
//#region src/stores/perf-store.d.ts
|
|
614
|
+
/** 内存快照——字段对齐 `@x-otto/coding` 的 `MemorySample`(不直接 import 跨包类型,
|
|
615
|
+
* tui 包不依赖 coding 包,由 cli 层组装时结构对齐即可,见 RFC-116 D2)。 */
|
|
616
|
+
interface PerfMemorySnapshot {
|
|
617
|
+
level: 'healthy' | 'warning' | 'critical';
|
|
618
|
+
heapUsed: number;
|
|
619
|
+
heapSizeLimit: number;
|
|
620
|
+
usedPct: number;
|
|
621
|
+
}
|
|
622
|
+
/** 渲染健康度快照——字段对齐 `NotifyStats`(M2 里程碑填充,M1 阶段为 undefined)。 */
|
|
623
|
+
interface PerfNotifySnapshot {
|
|
624
|
+
coalescedCalls: number;
|
|
625
|
+
coalescedFires: number;
|
|
626
|
+
immediateCalls: number;
|
|
627
|
+
flushFires: number;
|
|
628
|
+
coalesceRatio: number;
|
|
629
|
+
alert: 'healthy' | 'warning';
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* 单个插件采集器的结果。
|
|
633
|
+
* RFC-118 小修(S10):原 RFC-116 D2 的手动镜像定义已收口——类型本体上移
|
|
634
|
+
* `@x-otto/interchange`(coding 生产侧同源),此处别名保持 tui 内既有消费方命名兼容。
|
|
635
|
+
*/
|
|
636
|
+
type PluginMetricResult = _$_x_otto_interchange0.PluginPerfMetricResult;
|
|
637
|
+
interface PerfPaneState {
|
|
638
|
+
memory: PerfMemorySnapshot | undefined;
|
|
639
|
+
/** 内存采样历史(RFC-183 M4:PerfPane sparkline 趋势,环形窗口 ≤32 点,heapUsed 字节)。 */
|
|
640
|
+
memoryHistory: number[];
|
|
641
|
+
/** M1 阶段恒为 undefined(渲染区占位);M2 起由 CLI 层喂入真实值。 */
|
|
642
|
+
notify: PerfNotifySnapshot | undefined;
|
|
643
|
+
/**
|
|
644
|
+
* RFC-116 M3:footer 常驻指示器的实时分级——与 `memory`(面板手动刷新快照)解耦,
|
|
645
|
+
* 因为 footer 需要"异常时才浮现、健康时零宽度"的常驻感知(不依赖用户是否打开过
|
|
646
|
+
* `/perf` 面板),由 `MemoryGovernor.onLevelChange` 回调驱动(每次分级变化都推送,
|
|
647
|
+
* 含恢复到 healthy 的方向)。初始为 'healthy'(保守假设,避免启动瞬间误报)。
|
|
648
|
+
*/
|
|
649
|
+
indicatorLevel: 'healthy' | 'warning' | 'critical';
|
|
650
|
+
/**
|
|
651
|
+
* RFC-116 M5:插件贡献的性能采集器结果——手动刷新时喂入(对齐 D7 手动刷新决策,
|
|
652
|
+
* 不做自动轮询)。空数组 = 无插件贡献采集器或本次刷新尚未获取,两者在渲染层
|
|
653
|
+
* 不做区分(均不显示该区块),因为区分"无贡献"与"未刷新"对用户价值不大。
|
|
654
|
+
*/
|
|
655
|
+
pluginMetrics: PluginMetricResult[];
|
|
656
|
+
}
|
|
657
|
+
interface PerfStore {
|
|
658
|
+
store: Store<PerfPaneState>;
|
|
659
|
+
/** /clear 会话重置——全字段回初始值(indicatorLevel 回 'healthy' 保守假设)。
|
|
660
|
+
* RFC-256 收尾:面板可见性已改由 Router 栈单一真源派生(isInStack('/pane/perf')),
|
|
661
|
+
* store 不再持 `open` 布尔——原 toggle() 已删除。 */
|
|
662
|
+
reset(): void;
|
|
663
|
+
/** CLI 喂入最新内存快照(面板手动刷新)。 */
|
|
664
|
+
setMemory(snapshot: PerfMemorySnapshot): void;
|
|
665
|
+
/** CLI 喂入最新渲染健康度快照(M2 起使用;M1 阶段调用方不传,保持 undefined)。 */
|
|
666
|
+
setNotify(snapshot: PerfNotifySnapshot): void;
|
|
667
|
+
/** CLI 喂入 footer 常驻指示器的最新分级(`MemoryGovernor.onLevelChange` 驱动)。 */
|
|
668
|
+
setIndicatorLevel(level: 'healthy' | 'warning' | 'critical'): void;
|
|
669
|
+
/** CLI 喂入最新插件采集器结果(手动刷新触发)。 */
|
|
670
|
+
setPluginMetrics(results: PluginMetricResult[]): void;
|
|
671
|
+
}
|
|
672
|
+
//#endregion
|
|
673
|
+
//#region src/components/DataList.d.ts
|
|
674
|
+
type DataListTone = 'success' | 'warning' | 'error' | 'muted' | 'secondary';
|
|
675
|
+
interface DataListRow {
|
|
676
|
+
label: string;
|
|
677
|
+
value: string;
|
|
678
|
+
/** value 侧的可选强调色;不传走默认前景色。 */
|
|
679
|
+
tone?: DataListTone;
|
|
680
|
+
}
|
|
681
|
+
type DataListEntry = {
|
|
682
|
+
kind: 'group';
|
|
683
|
+
title: string;
|
|
684
|
+
} | ({
|
|
685
|
+
kind: 'row';
|
|
686
|
+
} & DataListRow) | {
|
|
687
|
+
kind: 'blank';
|
|
688
|
+
} /** 无 label/value 配对的纯文本行(如底部提示语),不参与组内标签对齐计算。 */ | {
|
|
689
|
+
kind: 'text';
|
|
690
|
+
value: string;
|
|
691
|
+
tone?: DataListTone;
|
|
692
|
+
};
|
|
693
|
+
interface DataListProps {
|
|
694
|
+
entries: readonly DataListEntry[];
|
|
695
|
+
}
|
|
696
|
+
declare function DataList({
|
|
697
|
+
entries
|
|
698
|
+
}: DataListProps): React.ReactElement;
|
|
699
|
+
//#endregion
|
|
700
|
+
//#region src/keybindings/types.d.ts
|
|
701
|
+
/**
|
|
702
|
+
* RFC-114 D1:按键谓词,对应 Ink `Key` 类型的同名字段,做逐字段相等比较。
|
|
703
|
+
*
|
|
704
|
+
* RFC-174 M1:新增 upArrow/downArrow 字段(控件导航层 registry 需要),
|
|
705
|
+
* 对既有 KEY_BINDINGS 零影响(所有现有记录这两个字段均为 undefined,
|
|
706
|
+
* 谓词匹配规则将 undefined 视为通配——向后兼容)。
|
|
707
|
+
*/
|
|
708
|
+
type KeyBindingPredicate = {
|
|
709
|
+
ctrl?: boolean;
|
|
710
|
+
shift?: boolean;
|
|
711
|
+
meta?: boolean; /** 单字符按键,如 'n'、'y'、'g'、'k'、'j'。 */
|
|
712
|
+
input?: string;
|
|
713
|
+
/**
|
|
714
|
+
* 修饰键外的命名按键——仅含全局命令实际使用的值。
|
|
715
|
+
* Ink `Key` 的 leftArrow/rightArrow 等继续控件级处理。
|
|
716
|
+
*/
|
|
717
|
+
key?: 'tab' | 'escape' | 'return'; /** 上箭头(RFC-174 M1 控件导航层)。 */
|
|
718
|
+
upArrow?: boolean; /** 下箭头(RFC-174 M1 控件导航层)。 */
|
|
719
|
+
downArrow?: boolean;
|
|
720
|
+
};
|
|
721
|
+
//#endregion
|
|
722
|
+
//#region src/dialogs/OnboardingDialog.d.ts
|
|
723
|
+
/** 引导两步的产出(cli 侧据此落盘;未设置的字段=用户跳过)。 */
|
|
724
|
+
interface OnboardingResult {
|
|
725
|
+
nickname?: string;
|
|
726
|
+
language?: 'en' | 'zh' | 'auto';
|
|
727
|
+
}
|
|
728
|
+
//#endregion
|
|
729
|
+
//#region src/stores/context-store.d.ts
|
|
730
|
+
/** 系统提示分段摘要(从 BudgetView + 静态 section 元数据推导)。 */
|
|
731
|
+
interface SystemSectionRow {
|
|
732
|
+
label: string;
|
|
733
|
+
lane: 'stable' | 'volatile';
|
|
734
|
+
estimatedTokens: number;
|
|
735
|
+
}
|
|
736
|
+
/** 对话回合摘要(CLI 从 trace 事件提取)。 */
|
|
737
|
+
interface ConversationTurnRow {
|
|
738
|
+
turnIndex: number;
|
|
739
|
+
role: 'user' | 'assistant';
|
|
740
|
+
messageCount: number;
|
|
741
|
+
estimatedTokens: number;
|
|
742
|
+
/** 该回合已被压缩替换为摘要(compaction.reactive 标记)。 */
|
|
743
|
+
compacted: boolean;
|
|
744
|
+
/** 该回合因 max_tokens 被截断(lifecycle:turn.truncated)。 */
|
|
745
|
+
truncated: boolean;
|
|
746
|
+
/** 该回合已从上下文中移出(lifecycle:memory.prune)。 */
|
|
747
|
+
pruned: boolean;
|
|
748
|
+
}
|
|
749
|
+
interface ContextDetailPaneState {
|
|
750
|
+
/** 面板开关态。 */
|
|
751
|
+
open: boolean;
|
|
752
|
+
/** 对话回合行(CLI 喂入,按 turnIndex 升序)。 */
|
|
753
|
+
conversationTurns: ConversationTurnRow[];
|
|
754
|
+
/** 系统提示分段(从 BudgetView.overheadTokens + 静态 section 表推导)。 */
|
|
755
|
+
systemSections: SystemSectionRow[];
|
|
756
|
+
/** 模型名(从 BudgetView 提取,供面板标题展示)。 */
|
|
757
|
+
modelName: string;
|
|
758
|
+
/** 上下文窗口总大小(token)。 */
|
|
759
|
+
contextWindow: number;
|
|
760
|
+
/** 上下文占用百分比。 */
|
|
761
|
+
contextPercent: number;
|
|
762
|
+
/** 全部已用 token */
|
|
763
|
+
totalUsed: number;
|
|
764
|
+
/** 可用 token */
|
|
765
|
+
free: number;
|
|
766
|
+
}
|
|
767
|
+
interface ContextStore {
|
|
768
|
+
store: Store<ContextDetailPaneState>;
|
|
769
|
+
/** 开/关面板;open 省略 = 翻转。 */
|
|
770
|
+
toggle(open?: boolean): void;
|
|
771
|
+
/** /clear 会话重置——全字段回初始值。 */
|
|
772
|
+
reset(): void;
|
|
773
|
+
/** CLI 追加一条回合行。 */
|
|
774
|
+
addTurn(row: ConversationTurnRow): void;
|
|
775
|
+
/** CLI 批量更新回合标记(compacted/truncated/pruned)。 */
|
|
776
|
+
markTurns(patch: {
|
|
777
|
+
turnIndex: number;
|
|
778
|
+
} & Partial<ConversationTurnRow>): void;
|
|
779
|
+
/** CLI 喂入 budget + 静态 section 元数据 → 推导 systemSections。 */
|
|
780
|
+
setBudget(budget: {
|
|
781
|
+
modelName: string;
|
|
782
|
+
contextWindow: number;
|
|
783
|
+
contextPercent: number;
|
|
784
|
+
totalUsed: number;
|
|
785
|
+
free: number;
|
|
786
|
+
overheadTokens: number;
|
|
787
|
+
}): void;
|
|
788
|
+
}
|
|
789
|
+
//#endregion
|
|
790
|
+
//#region src/dialogs/ErrorRetryDialog.d.ts
|
|
791
|
+
/** 硬额度限流类型(原定义于已并入本卡片的 RateLimitCountdown.tsx,RFC-147 M3 D-C4 迁移)。 */
|
|
792
|
+
type RateLimitType = 'five_hour' | 'seven_day' | 'seven_day_opus' | 'seven_day_sonnet' | 'seven_day_overage_included';
|
|
793
|
+
type ErrorRetryActionKind = 'retryNow' | 'login' | 'switchModel';
|
|
794
|
+
interface ErrorRetryAction {
|
|
795
|
+
kind: ErrorRetryActionKind;
|
|
796
|
+
label: string;
|
|
797
|
+
run: () => void;
|
|
798
|
+
}
|
|
799
|
+
interface ErrorRetryItem {
|
|
800
|
+
/** 触发本次错误的原因(单行截断展示)。 */
|
|
801
|
+
reason: string;
|
|
802
|
+
/** 当前 per-prompt 重投次数(1-based;0 表示首次失败尚未重试过)。 */
|
|
803
|
+
attempt: number;
|
|
804
|
+
/** per-prompt 最大重试配额(默认 5)。 */
|
|
805
|
+
max: number;
|
|
806
|
+
/** 'auto'=30s×5 自动重投;'resetsAt'=倒计时到官方 resetsAt;'manual'=无自动倒计时。 */
|
|
807
|
+
mode: 'auto' | 'resetsAt' | 'manual';
|
|
808
|
+
/** mode='resetsAt' 时为 Unix 秒时间戳;其余 mode 忽略。 */
|
|
809
|
+
resetsAt?: number;
|
|
810
|
+
/** mode='resetsAt'|'manual'(硬额度场景)时的限流类型标签;其余 mode 忽略。 */
|
|
811
|
+
limitType?: RateLimitType;
|
|
812
|
+
/** 按钮列表(不含取消——取消固定追加在末尾,见渲染逻辑)。至少 1 个动作按钮。 */
|
|
813
|
+
actions: ErrorRetryAction[];
|
|
814
|
+
/** 当前聚焦按钮索引(含隐式追加的取消按钮,取值范围 0..actions.length)。 */
|
|
815
|
+
focusIndex: number;
|
|
816
|
+
/** 倒计时到期回调(mode='auto'|'resetsAt' 时触发一次)。 */
|
|
817
|
+
onExpired: () => void;
|
|
818
|
+
/** 取消(Esc 或选中取消按钮触发)。 */
|
|
819
|
+
onCancel: () => void;
|
|
820
|
+
/** 终态:per-prompt 配额已耗尽(mode='auto' 且 attempt>=max 仍失败)——不再自动倒计时,
|
|
821
|
+
* 保留手动重试(重置计数)与取消。 */
|
|
822
|
+
exhausted: boolean;
|
|
823
|
+
/** RFC-153 D6:错误来源插件 id(`CodedError.pluginSource`/`ToolResult.pluginSource` 透传);
|
|
824
|
+
* undefined 表示非插件来源(内建能力),不展示来源行(规则 8:只标记来源,不改变重试策略)。 */
|
|
825
|
+
pluginSource?: string;
|
|
826
|
+
/** RFC-230:mode='auto' 自动倒计时秒数(默认 30)。随 item 一起流转(`showErrorRetry` 的
|
|
827
|
+
* `...item` 展开自动透传新增字段),不单独开辟传递路径。 */
|
|
828
|
+
intervalSeconds?: number;
|
|
829
|
+
}
|
|
830
|
+
//#endregion
|
|
831
|
+
//#region src/panes/EditedFilesPane.d.ts
|
|
832
|
+
interface EditedFileEntry {
|
|
833
|
+
/** 文件路径(相对项目根或绝对) */
|
|
834
|
+
path: string;
|
|
835
|
+
/** 操作类型 */
|
|
836
|
+
operation: 'edit' | 'write' | 'delete';
|
|
837
|
+
/** 旧内容(edit/delete 时有值) */
|
|
838
|
+
oldContent?: string;
|
|
839
|
+
/** 新内容(edit/write 时有值) */
|
|
840
|
+
newContent?: string;
|
|
841
|
+
/** 新增行数 */
|
|
842
|
+
addedLines: number;
|
|
843
|
+
/** 删除行数 */
|
|
844
|
+
removedLines: number;
|
|
845
|
+
/** 工具调用时间戳(epoch ms) */
|
|
846
|
+
timestamp: number;
|
|
847
|
+
/** 关联的 turn ID(可选) */
|
|
848
|
+
turnId?: string;
|
|
849
|
+
/** 工具调用 ID(去重用) */
|
|
850
|
+
toolCallId?: string;
|
|
851
|
+
}
|
|
852
|
+
//#endregion
|
|
853
|
+
//#region src/status-bar/background-task-indicator-logic.d.ts
|
|
854
|
+
/**
|
|
855
|
+
* RFC-223:委托后台进程的服务协议分类——从运行时输出识别,best-effort。
|
|
856
|
+
* 结构上与 `@x-otto/tools`/`@x-otto/runtime` 的同名类型一致(不 import,tui 零运行时
|
|
857
|
+
* 依赖 tools/runtime,靠结构化类型满足契约,同既有 tools↔runtime 解耦策略)。
|
|
858
|
+
*/
|
|
859
|
+
type ServiceProtocol = 'http' | 'ws' | 'tcp';
|
|
860
|
+
/** RFC-223:从后台进程运行时输出识别到的服务信息(url 优先,退化到纯端口)。 */
|
|
861
|
+
interface DetectedService {
|
|
862
|
+
url?: string;
|
|
863
|
+
port?: number;
|
|
864
|
+
protocol: ServiceProtocol;
|
|
865
|
+
}
|
|
866
|
+
type BackgroundTaskType = 'process' | 'agent-session';
|
|
867
|
+
/** 来源:user = 用户 /delegate 委派;main = 主对话(模型)起的;plugin = 插件经
|
|
868
|
+
* agent.dispatch 自主发起(RFC-287 D2)。分类上与 main 同归 'subagent'(非人手委派)。 */
|
|
869
|
+
type BackgroundTaskOrigin = 'user' | 'main' | 'plugin';
|
|
870
|
+
type AgentJobUiStatus = 'running' | 'needs_input' | 'ready' | 'applied' | 'failed' | 'canceled';
|
|
871
|
+
interface BackgroundTaskSummary {
|
|
872
|
+
id: string;
|
|
873
|
+
/** 进程=command;agent-session=作业 title。 */
|
|
874
|
+
command: string;
|
|
875
|
+
status: 'running' | 'exited' | 'killed' | 'failed';
|
|
876
|
+
/** kind(缺省 process,向后兼容既有进程喂入)。 */
|
|
877
|
+
type?: BackgroundTaskType;
|
|
878
|
+
/** 来源(缺省 user):面板分组用——用户委派 vs 主对话委派。 */
|
|
879
|
+
origin?: BackgroundTaskOrigin;
|
|
880
|
+
port?: number;
|
|
881
|
+
startedAt: number;
|
|
882
|
+
exitCode?: number;
|
|
883
|
+
/** 作业状态(真源;type==='agent-session' 时用它而非 status)。 */
|
|
884
|
+
agentStatus?: AgentJobUiStatus;
|
|
885
|
+
/** 完整的委托提示词(供 SubagentsPane / 详情面板展示)。 */
|
|
886
|
+
prompt?: string;
|
|
887
|
+
/** ready 后的 diff 概况,如 "+5/-2"。 */
|
|
888
|
+
diffStat?: string;
|
|
889
|
+
/** 当前 turn 序号。 */
|
|
890
|
+
turnIndex?: number;
|
|
891
|
+
/** 累积工具调用数。 */
|
|
892
|
+
toolUseCount?: number;
|
|
893
|
+
/** 累积文件编辑次数(子代理编辑的 pod 信号)。 */
|
|
894
|
+
filesEdited?: number;
|
|
895
|
+
/** 累积输出 token。 */
|
|
896
|
+
tokenCount?: number;
|
|
897
|
+
/** 分配模型 id(供 SubagentsPane 面板显示)。 */
|
|
898
|
+
model?: string;
|
|
899
|
+
/** 模型决策层(explicit/slot/category/default/fallback)——面板显示「为何用这个模型」。 */
|
|
900
|
+
modelDecidedBy?: string;
|
|
901
|
+
/** 当前活动(thinking / responding / using <tool> / awaiting approval …)。 */
|
|
902
|
+
lastActivity?: string;
|
|
903
|
+
/** stall 级别(派生:none/warn/stalled)——驱动行图标变色 + 诊断块。 */
|
|
904
|
+
stall?: 'none' | 'warn' | 'stalled';
|
|
905
|
+
/** 距上次事件毫秒(stall 时显示 "idle 4s")。 */
|
|
906
|
+
idleMs?: number;
|
|
907
|
+
/** 当前等待类别:model_io / approval / process。 */
|
|
908
|
+
blockedOn?: string;
|
|
909
|
+
/** 父 abort 能否中断它(false 时诊断块显式标注 NOT abortable)。 */
|
|
910
|
+
abortable?: boolean;
|
|
911
|
+
/** RFC-223:运行时输出识别到的服务信息(仅 process 类任务有意义)。 */
|
|
912
|
+
detectedService?: DetectedService;
|
|
913
|
+
}
|
|
914
|
+
/** 观测快照里 cli 喂面板用到的字段(与 runtime AgentObservationSnapshot 同形子集;tui 不依赖 runtime)。 */
|
|
915
|
+
interface ObservationLike {
|
|
916
|
+
id: string;
|
|
917
|
+
agentName: string;
|
|
918
|
+
origin: 'user' | 'main';
|
|
919
|
+
status: string;
|
|
920
|
+
/** 完整的委托提示词(供 SubagentsPane / 详情面板展示)。 */
|
|
921
|
+
prompt?: string;
|
|
922
|
+
startedAt: number;
|
|
923
|
+
turnIndex?: number;
|
|
924
|
+
toolUseCount?: number;
|
|
925
|
+
/** 累积文件编辑次数(子代理编辑的 pod 信号;≥1 时面板末行追加 "~N files")。 */
|
|
926
|
+
filesEdited?: number;
|
|
927
|
+
tokenCount?: number;
|
|
928
|
+
/** 分配模型 id(供 SubagentsPane 面板显示)。 */
|
|
929
|
+
model?: string;
|
|
930
|
+
/** 模型决策层。 */
|
|
931
|
+
modelDecidedBy?: string;
|
|
932
|
+
lastActivity?: string;
|
|
933
|
+
stall?: 'none' | 'warn' | 'stalled';
|
|
934
|
+
idleMs?: number;
|
|
935
|
+
blockedOn?: string;
|
|
936
|
+
abortable?: boolean;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* BackgroundTaskSummary → 持久化 SubagentEntry.status 的归一映射。
|
|
940
|
+
* agentStatus(agent-session 真源)优先;缺省回退通用 status。供 cli persistSubagents 写盘。
|
|
941
|
+
*/
|
|
942
|
+
declare function subagentEntryStatus(t: Pick<BackgroundTaskSummary, 'agentStatus' | 'status'>): 'running' | 'done' | 'error' | 'killed';
|
|
943
|
+
/**
|
|
944
|
+
* 持久化 SubagentEntry.status → 恢复行的 BackgroundTaskSummary 字段(反向)。
|
|
945
|
+
* status=agent-session 真源 agentStatus(驱动行图标)+ 通用 status。供 tui addSubagent 重建面板行。
|
|
946
|
+
*/
|
|
947
|
+
declare function subagentRestoreFields(status: 'running' | 'done' | 'error' | 'killed'): {
|
|
948
|
+
agentStatus: AgentJobUiStatus;
|
|
949
|
+
status: BackgroundTaskSummary['status'];
|
|
950
|
+
};
|
|
951
|
+
/** 观测 → 面板行的 live 字段子集(用于富化已有 detached /job 行)。 */
|
|
952
|
+
declare function observationLiveFields(o: ObservationLike): Partial<BackgroundTaskSummary>;
|
|
953
|
+
/** 观测 → 完整面板行(用于 swarm 成员等不在 jobRegistry 的被观测 agent)。 */
|
|
954
|
+
declare function observationRow(o: ObservationLike): BackgroundTaskSummary;
|
|
955
|
+
/**
|
|
956
|
+
* 视图B:turn timeline 文本行(形如「turn 6 ✓ 3 tools 2.1s」/「▸ turn 7 … 8s」)。
|
|
957
|
+
* 已完成轮 `✓`,当前轮 `▸ … `(用 now 算 in-flight 时长)。空 → []。
|
|
958
|
+
*/
|
|
959
|
+
declare function formatTurnTimeline(turns: TurnRecord[], now: number): string[];
|
|
960
|
+
/**
|
|
961
|
+
* 诊断块的**纯文本**行(供 o-键详情视图顶部,复用 DelegateOutputPane 不碰 App.tsx)。
|
|
962
|
+
* 非被观测 agent → []。`! ` 前缀标 warn 行(stalled / 不可中止)。
|
|
963
|
+
*/
|
|
964
|
+
declare function formatAgentDiagnosticsText(t: BackgroundTaskSummary, now: number): string[];
|
|
965
|
+
//#endregion
|
|
966
|
+
//#region src/panes/DelegatesPane.d.ts
|
|
967
|
+
/** 单个后台进程的实时输出视图(cli 每 ~500ms 读 logPath 末尾回喂 text)。 */
|
|
968
|
+
interface DelegateOutputView {
|
|
969
|
+
id: string;
|
|
970
|
+
command: string;
|
|
971
|
+
status: BackgroundTaskSummary['status'];
|
|
972
|
+
/** 完整的委托提示词(设置即启用 Prompt tab)。 */
|
|
973
|
+
prompt?: string;
|
|
974
|
+
/** 已废弃——子代理对话流改用 messages 渲染(同 SubagentContextView),不再走纯文本 text。 */
|
|
975
|
+
text: string;
|
|
976
|
+
/** 被观测子代理的诊断摘要(activity/blocked/tokens/abortable + turn timeline,纯文本)。
|
|
977
|
+
* 真实用户反馈修复:此前本字段撑起一个独占的 "Response" tab,但子代理内容以 markdown
|
|
978
|
+
* 对话为主,诊断信息本身没有独立可读性——已改为渲在 header 里的一行摘要,不占 tab。 */
|
|
979
|
+
responseText?: string;
|
|
980
|
+
/** 结构化转录消息——渲染时走 renderMessageLines(同 SubagentContextView 的对话流)。 */
|
|
981
|
+
messages?: ChatMessage[];
|
|
982
|
+
/** 运行中 in-flight 流式文本(接在 messages 末尾,跟随最新输出)。 */
|
|
983
|
+
streamText?: string;
|
|
984
|
+
/** 作业产出的统一 diff(ready/applied 的 agent-session 作业)——设置即启用 Diff tab,
|
|
985
|
+
* 人审 diff 的唯一 TUI 入口(此前 diff 全程不可见,只有 +N/-M stat)。 */
|
|
986
|
+
diff?: string;
|
|
987
|
+
}
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/input/shell-complete-backend.d.ts
|
|
990
|
+
/**
|
|
991
|
+
* shell-complete-backend.ts — Shell completion backends.
|
|
992
|
+
* BashBackend (compgen), ZshBackend (_comps), BuiltinBackend (PATH+fs).
|
|
993
|
+
* RFC-121: user input via env vars, never string interpolation.
|
|
994
|
+
*/
|
|
995
|
+
interface CompletionItem {
|
|
996
|
+
/** 补全候选值 */
|
|
997
|
+
value: string;
|
|
998
|
+
/** 显示标签(可选,与 value 不同时用于展示) */
|
|
999
|
+
display?: string;
|
|
1000
|
+
/** 候选类型 */
|
|
1001
|
+
type: 'command' | 'file' | 'dir' | 'arg';
|
|
1002
|
+
/** 描述(可选) */
|
|
1003
|
+
description?: string;
|
|
1004
|
+
}
|
|
1005
|
+
interface CompletedWord {
|
|
1006
|
+
/** 单词原始文本 */
|
|
1007
|
+
word: string;
|
|
1008
|
+
/** 在原始输入中的偏移 */
|
|
1009
|
+
offset: number;
|
|
1010
|
+
}
|
|
1011
|
+
interface CompletionRequest {
|
|
1012
|
+
/** 要补全的文本(不含 ! 前缀) */
|
|
1013
|
+
text: string;
|
|
1014
|
+
/** 光标在 text 中的偏移 */
|
|
1015
|
+
cursorOffset: number;
|
|
1016
|
+
/** 解析后的单词数组(供 COMP_WORDS/COMP_CWORD 使用) */
|
|
1017
|
+
words: CompletedWord[];
|
|
1018
|
+
/** 光标所在的单词索引(COMP_CWORD) */
|
|
1019
|
+
wordIndex: number;
|
|
1020
|
+
/** 工作目录 */
|
|
1021
|
+
cwd: string;
|
|
1022
|
+
/** 取消信号 */
|
|
1023
|
+
signal?: AbortSignal;
|
|
1024
|
+
}
|
|
1025
|
+
interface ShellBackend {
|
|
1026
|
+
/** 后端名称(用于诊断日志) */
|
|
1027
|
+
name: string;
|
|
1028
|
+
/** 获取命令列表(首词补全),prefix 为空时返回全部 */
|
|
1029
|
+
getCommands(prefix: string): Promise<CompletionItem[]>;
|
|
1030
|
+
/** 获取参数补全(后续词补全) */
|
|
1031
|
+
getCompletions(request: CompletionRequest): Promise<CompletionItem[]>;
|
|
1032
|
+
/** 销毁后端(清理资源) */
|
|
1033
|
+
destroy(): void;
|
|
1034
|
+
}
|
|
1035
|
+
//#endregion
|
|
1036
|
+
//#region src/input/shell-complete.d.ts
|
|
1037
|
+
/**
|
|
1038
|
+
* shell-complete.ts — Shell tab completion for ! (bash) mode.
|
|
1039
|
+
* Sources: command (PATH) / path (filesystem). Tab: common-prefix then cycle. Zero React dependency.
|
|
1040
|
+
*/
|
|
1041
|
+
interface ShellCompletion {
|
|
1042
|
+
completions: string[];
|
|
1043
|
+
selectedIndex: number;
|
|
1044
|
+
prefix: string;
|
|
1045
|
+
wordStart: number;
|
|
1046
|
+
visible: boolean;
|
|
1047
|
+
commonPrefixApplied: boolean;
|
|
1048
|
+
}
|
|
1049
|
+
//#endregion
|
|
1050
|
+
//#region src/input/shell-complete-orchestrator.d.ts
|
|
1051
|
+
interface CompleterOptions {
|
|
1052
|
+
/** 命令补全超时(ms) */
|
|
1053
|
+
commandTimeoutMs: number;
|
|
1054
|
+
/** 参数补全超时(ms) */
|
|
1055
|
+
argTimeoutMs: number;
|
|
1056
|
+
/** 最大结果数 */
|
|
1057
|
+
maxResults: number;
|
|
1058
|
+
/** 命令列表缓存 TTL(ms,默认 30s) */
|
|
1059
|
+
commandCacheTtlMs: number;
|
|
1060
|
+
/** 参数补全缓存 TTL(ms,默认 30s,含 CWD 信息) */
|
|
1061
|
+
argCacheTtlMs: number;
|
|
1062
|
+
/** 缓存最大条目数 */
|
|
1063
|
+
maxCacheEntries: number;
|
|
1064
|
+
}
|
|
1065
|
+
declare class Completer {
|
|
1066
|
+
private backend;
|
|
1067
|
+
private opts;
|
|
1068
|
+
private commandCache;
|
|
1069
|
+
/** 参数补全缓存:键 = `${cwd}|${command}`,TTL 30s */
|
|
1070
|
+
private argCache;
|
|
1071
|
+
private abortController;
|
|
1072
|
+
constructor(backend: ShellBackend | null, opts?: Partial<CompleterOptions>);
|
|
1073
|
+
/**
|
|
1074
|
+
* 取消当前正在进行的补全查询。
|
|
1075
|
+
*/
|
|
1076
|
+
cancelPending(): void;
|
|
1077
|
+
/**
|
|
1078
|
+
* 获取命令列表(首词补全),异步。
|
|
1079
|
+
*
|
|
1080
|
+
* 策略:
|
|
1081
|
+
* 1. 会话级缓存(TTL 30s,不依赖 CWD,因 PATH 全局不变)
|
|
1082
|
+
* 2. shell 后端查询(超时 commandTimeoutMs)
|
|
1083
|
+
* 3. PATH 扫描兜底(instant)
|
|
1084
|
+
* 4. 合并去重后返回
|
|
1085
|
+
*/
|
|
1086
|
+
getCommands(prefix: string): Promise<string[]>;
|
|
1087
|
+
/**
|
|
1088
|
+
* 发起异步参数补全查询。
|
|
1089
|
+
*/
|
|
1090
|
+
getCompletions(request: {
|
|
1091
|
+
text: string;
|
|
1092
|
+
cursorOffset: number;
|
|
1093
|
+
cwd: string;
|
|
1094
|
+
}): Promise<string[]>;
|
|
1095
|
+
/**
|
|
1096
|
+
* 设置参数补全缓存,超限时淘汰最旧条目。
|
|
1097
|
+
*/
|
|
1098
|
+
private setArgCache;
|
|
1099
|
+
/**
|
|
1100
|
+
* 桥接方法:从字符串补全结果创建 ShellCompletion 状态。
|
|
1101
|
+
*/
|
|
1102
|
+
makeShellCompletion(completions: string[], wordStart: number, prefix: string): ShellCompletion;
|
|
1103
|
+
/**
|
|
1104
|
+
* 销毁编排器及后端。
|
|
1105
|
+
*/
|
|
1106
|
+
destroy(): void;
|
|
1107
|
+
}
|
|
1108
|
+
//#endregion
|
|
1109
|
+
//#region src/input/paste-refs.d.ts
|
|
1110
|
+
/**
|
|
1111
|
+
* paste-refs.ts — Paste reference folding/expansion + memory lifecycle (M48-06, RFC-198).
|
|
1112
|
+
* LRU with pressure-graded capacity (healthy=1x, warning=½, critical=¼).
|
|
1113
|
+
* nextId monotonic (never reset). findMissingIds before expandAll.
|
|
1114
|
+
* Known: image refs not managed (RFC-181 gap).
|
|
1115
|
+
*
|
|
1116
|
+
* RFC-338:新增跨重启持久化支持(hydrate/toSnapshot)。本文件仍是**纯内存 + 纯函数**,
|
|
1117
|
+
* 不碰文件系统——落盘由宿主(cli)经 `@x-otto/persistence` 完成,本层只负责
|
|
1118
|
+
* 「内存状态 ⇄ 可序列化快照」的转换。
|
|
1119
|
+
*/
|
|
1120
|
+
/**
|
|
1121
|
+
* 压力分级来源的自描述接口——不直接 import `ResidencyGovernor` 类,只声明所需的最小读取面
|
|
1122
|
+
* (`currentLevel`),避免 `paste-refs.ts` 对 `@x-otto/runtime` 产生编译期类型依赖(tui 包当前
|
|
1123
|
+
* 零 `@x-otto/runtime` 依赖)。`App` 侧的 `ResidencyGovernor` 实例满足这个接口的结构化子集,
|
|
1124
|
+
* 传递时无需显式转换(TypeScript 结构化类型天然兼容)。
|
|
1125
|
+
*/
|
|
1126
|
+
interface PasteStoreResidencySource {
|
|
1127
|
+
readonly currentLevel: 'healthy' | 'warning' | 'critical';
|
|
1128
|
+
}
|
|
1129
|
+
interface CreatePasteStoreOptions {
|
|
1130
|
+
/** 压力分级来源;省略时退化为固定的 healthy 上限(测试/无 governor 场景兼容)。 */
|
|
1131
|
+
residencyGovernor?: PasteStoreResidencySource;
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* RFC-338:可序列化的粘贴条目。
|
|
1135
|
+
*
|
|
1136
|
+
* 结构与 `@x-otto/persistence` 的 `PasteStateEntry` **刻意保持一致但不 import**——
|
|
1137
|
+
* tui 包零 `@x-otto/persistence` 依赖(同 `PasteStoreResidencySource` 对
|
|
1138
|
+
* `@x-otto/runtime` 的既有处理方式),靠 TypeScript 结构化类型在 cli 装配层天然兼容。
|
|
1139
|
+
*/
|
|
1140
|
+
interface PasteSnapshotEntry {
|
|
1141
|
+
id: number;
|
|
1142
|
+
text: string;
|
|
1143
|
+
byteLength: number;
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* RFC-338:粘贴缓存快照(内存 ⇄ 持久化的交换格式)。
|
|
1147
|
+
*
|
|
1148
|
+
* `entries` 的**数组顺序即 LRU 顺序**(头 = 最久未访问,尾 = 最近访问),
|
|
1149
|
+
* 与内存 `Map` 的插入顺序一一对应——不引入独立 seq/时间戳字段(D2:那会与
|
|
1150
|
+
* Map 顺序构成双真源;且时间源违反引擎确定性重放约束)。
|
|
1151
|
+
*/
|
|
1152
|
+
interface PasteSnapshot {
|
|
1153
|
+
entries: PasteSnapshotEntry[];
|
|
1154
|
+
/** id 分配游标,单调不回退(重要事项规则 1,红线)。 */
|
|
1155
|
+
nextId: number;
|
|
1156
|
+
}
|
|
1157
|
+
interface PasteStore {
|
|
1158
|
+
foldIfLarge(text: string): string;
|
|
1159
|
+
/** 展开占位符为原文。missingIds 非空即存在无法解析的引用——调用方应先用
|
|
1160
|
+
* `findMissingIds` 做提交前校验,不要依赖本方法的 missingIds 做阻断判定(本方法会
|
|
1161
|
+
* 同时产生副作用:续命或释放,不是纯查询)。 */
|
|
1162
|
+
expandAll(text: string): {
|
|
1163
|
+
text: string;
|
|
1164
|
+
missingIds: number[];
|
|
1165
|
+
};
|
|
1166
|
+
/** 提交前的纯校验(不消费、不改变 LRU 状态),返回文本中引用但当前不可解析的 id 列表。 */
|
|
1167
|
+
findMissingIds(text: string): number[];
|
|
1168
|
+
/**
|
|
1169
|
+
* RFC-212 D3:只读查看单条 paste 内容(不消费、不改变 LRU 访问顺序/字节计数/驱逐计数),
|
|
1170
|
+
* 供 chip 内容查看器展示原文——与 `expandAll` 的关键差异:`expandAll` 会触发续命
|
|
1171
|
+
* (healthy 分级)或释放(warning/critical 分级)的副作用,查看操作不应影响该副作用时序
|
|
1172
|
+
* (用户只是看一眼,不代表"已经真正使用/提交"这次引用)。id 不存在(已失效)返回 undefined。
|
|
1173
|
+
*/
|
|
1174
|
+
peek(id: number): string | undefined;
|
|
1175
|
+
truncateIfNeeded(text: string): string;
|
|
1176
|
+
addImageRef(): string;
|
|
1177
|
+
/**
|
|
1178
|
+
* RFC-338 D5:一次提交完成后的收尾。**取代此前无条件的 `clear()`**。
|
|
1179
|
+
*
|
|
1180
|
+
* - healthy:保留全部条目(仅按容量做 LRU 裁剪)——这正是本 RFC 的核心价值:
|
|
1181
|
+
* 用户从输入历史 recall 出旧命令后,其中的 chip 仍能展开。
|
|
1182
|
+
* - warning/critical:沿用「用完即释放」。注意 `expandAll` 在这两档已经删过命中的
|
|
1183
|
+
* 条目,本方法**不重复扣减**,只清理那些本次提交引用过、但 expandAll 未覆盖的残留。
|
|
1184
|
+
*
|
|
1185
|
+
* @param submittedText 本次提交的原始文本(含 `[@paste:#N]` 占位符)
|
|
1186
|
+
*/
|
|
1187
|
+
afterSubmit(submittedText: string): void;
|
|
1188
|
+
/**
|
|
1189
|
+
* RFC-338:导出可持久化快照。数组顺序 = 当前 LRU 顺序。
|
|
1190
|
+
*
|
|
1191
|
+
* 落盘字节上限(`OTTO_PASTE_STORE_PERSIST_MAX_BYTES`,默认 8MB)在此处生效——
|
|
1192
|
+
* 从**最久未访问端**(数组头)开始裁剪,保证留下的是最可能被 recall 的近期条目。
|
|
1193
|
+
* 这不改变内存状态,只影响写盘内容(内存仍受 32MB 闸约束)。
|
|
1194
|
+
*/
|
|
1195
|
+
toSnapshot(): PasteSnapshot;
|
|
1196
|
+
/**
|
|
1197
|
+
* RFC-338:从持久化快照恢复(整份替换当前状态)。
|
|
1198
|
+
*
|
|
1199
|
+
* `nextId` 取 `max(快照声明值, 全部 id + 1, 当前 nextId)` —— 三者取最大,
|
|
1200
|
+
* 保证游标既不回退也不与既存 id 碰撞(重要事项规则 1,红线)。
|
|
1201
|
+
* 快照中的非法条目被静默丢弃(fail-open),但**丢弃不会让出 id 空间**。
|
|
1202
|
+
*/
|
|
1203
|
+
hydrate(snapshot: PasteSnapshot | null | undefined): void;
|
|
1204
|
+
readonly size: number;
|
|
1205
|
+
/** 当前 store 占用字节数(LRU 容量判据的另一维度)。 */
|
|
1206
|
+
readonly bytesUsed: number;
|
|
1207
|
+
/** 累计驱逐次数(LRU 超限淘汰 + 内存紧张分级用完即释放,两者都计数)。纯计数器,不驱动
|
|
1208
|
+
* 任何行为,供未来 `/perf` 面板或调试场景观测。 */
|
|
1209
|
+
readonly evictionCount: number;
|
|
1210
|
+
/**
|
|
1211
|
+
* 清空全部映射。
|
|
1212
|
+
*
|
|
1213
|
+
* RFC-338 D5 起**不再挂在提交路径上**(提交走 `afterSubmit`),仅供显式清理场景
|
|
1214
|
+
* (如 `/clear`)使用。`nextId` 不复位——见实现处注释。
|
|
1215
|
+
*/
|
|
1216
|
+
clear(): void;
|
|
1217
|
+
}
|
|
1218
|
+
declare function createPasteStore(options?: CreatePasteStoreOptions): PasteStore;
|
|
1219
|
+
//#endregion
|
|
1220
|
+
//#region src/input/use-typeahead.d.ts
|
|
1221
|
+
/**
|
|
1222
|
+
* useTypeahead.ts — Slash command completion engine (CC useTypeahead port, M48-07).
|
|
1223
|
+
*
|
|
1224
|
+
* / slash command completion only. Pure functions, zero React dependency.
|
|
1225
|
+
* RFC-036 T036-11: @ file/agent/MCP dead code removed — replaced by SigilPane + registry.search().
|
|
1226
|
+
*
|
|
1227
|
+
* Usage:
|
|
1228
|
+
* const reg = createCommandRegistry([{name:'help', description:'Show help'}])
|
|
1229
|
+
* const sug = getCommandSuggestions('/he', 3, reg)
|
|
1230
|
+
* if (sug) renderList(sug.suggestions, sug.selectedIndex)
|
|
1231
|
+
*/
|
|
1232
|
+
interface CommandEntry {
|
|
1233
|
+
name: string;
|
|
1234
|
+
description?: string;
|
|
1235
|
+
disabled?: boolean;
|
|
1236
|
+
/**
|
|
1237
|
+
* 命令别名(如 `auth` 的 `['login']`)——**参与 typeahead 模糊匹配**。
|
|
1238
|
+
*
|
|
1239
|
+
* 缺失此字段曾导致:`/login` 在斜杠面板零结果(用户报告"login 没有入口"),
|
|
1240
|
+
* 且 `/log` 只匹配到 `logout`(退出登录)——想登录的人看到的唯一选项是退出。
|
|
1241
|
+
* CLI 侧 `registerBuiltinTuiCommands` 一直在传 `aliases`(目录条目 `auth` 确有
|
|
1242
|
+
* `aliases: ['login']`),但本接口此前无该字段,值被静默丢弃,从未参与匹配。
|
|
1243
|
+
*/
|
|
1244
|
+
aliases?: string[];
|
|
1245
|
+
/**
|
|
1246
|
+
* 排序键(RFC-158 D5):缺省用 `name`。用于展示名与排序键需要解耦的场景——如
|
|
1247
|
+
* `/pin`⇄`/unpin` 动态展示名,排序始终固定用原始指令 id(`'pin'`),避免展示名
|
|
1248
|
+
* 切换导致列表位置跳动。
|
|
1249
|
+
*/
|
|
1250
|
+
sortKey?: string;
|
|
1251
|
+
}
|
|
1252
|
+
type SlashNavigateAction = 'prev' | 'next' | 'accept' | 'dismiss';
|
|
1253
|
+
interface TypeaheadState {
|
|
1254
|
+
suggestions: CommandEntry[];
|
|
1255
|
+
selectedIndex: number;
|
|
1256
|
+
prefix: string;
|
|
1257
|
+
/** 边框候选列表是否可见;slash 有匹配时自动 true(RFC-128 D3)。 */
|
|
1258
|
+
panelOpen: boolean;
|
|
1259
|
+
/**
|
|
1260
|
+
* 命中「命令参数补全」(`registerArgumentSuggester`)时的宿主命令名,如 `'model'`。
|
|
1261
|
+
* 未设置(`undefined`)表示 `suggestions` 是「命令名候选」(`/mo` → `/model`)。
|
|
1262
|
+
* 消费方(PromptInput 边框列表 accept 分支)据此区分调用 `applyArgCompletion`
|
|
1263
|
+
* (只替换参数段)还是 `applySlashCompletion`(替换命令名段)——回归修复:此前恒调用
|
|
1264
|
+
* 后者,导致接受参数建议时把命令名整段误替换成参数值(如 `/model gpt` 选中 `gpt-4`
|
|
1265
|
+
* 后变成 `/gpt-4 gpt`)。
|
|
1266
|
+
*/
|
|
1267
|
+
argCommand?: string;
|
|
1268
|
+
}
|
|
1269
|
+
/**
|
|
1270
|
+
* Argument suggestion provider for specific commands.
|
|
1271
|
+
* Maps command name → function that suggests arguments.
|
|
1272
|
+
*/
|
|
1273
|
+
type ArgumentSuggester = (prefix: string, maxResults?: number) => Array<{
|
|
1274
|
+
name: string;
|
|
1275
|
+
description?: string;
|
|
1276
|
+
}>;
|
|
1277
|
+
interface CommandRegistry {
|
|
1278
|
+
register(commands: CommandEntry[]): void;
|
|
1279
|
+
search(prefix: string, maxResults?: number): CommandEntry[];
|
|
1280
|
+
getAll(): readonly CommandEntry[];
|
|
1281
|
+
find(name: string): CommandEntry | undefined;
|
|
1282
|
+
registerArgumentSuggester(command: string, suggester: ArgumentSuggester): void;
|
|
1283
|
+
getArgumentSuggester(command: string): ArgumentSuggester | undefined;
|
|
1284
|
+
}
|
|
1285
|
+
declare function createCommandRegistry(initial?: CommandEntry[]): CommandRegistry;
|
|
1286
|
+
/**
|
|
1287
|
+
* 仅行首触发 `/` typeahead(trimStart 后以 / 开头)。
|
|
1288
|
+
* 旧正则 `(?:^|\s)` 太宽:`ls /tmp`、`cd /usr` 都会误弹面板。
|
|
1289
|
+
* 新正则 `/^\/(.*)$/` 允许空格(用于 `/command arg` 参数补全)。
|
|
1290
|
+
*/
|
|
1291
|
+
declare function extractSlashPrefix(input: string, cursorOffset: number): string | null;
|
|
1292
|
+
declare function getCommandSuggestions(input: string, cursorOffset: number, registry: CommandRegistry): TypeaheadState | null;
|
|
1293
|
+
declare function navigateSuggestions(state: TypeaheadState, action: SlashNavigateAction): TypeaheadState | 'accept' | 'dismiss';
|
|
1294
|
+
declare function applySlashCompletion(input: string, cursorOffset: number, command: CommandEntry): {
|
|
1295
|
+
text: string;
|
|
1296
|
+
offset: number;
|
|
1297
|
+
};
|
|
1298
|
+
//#endregion
|
|
1299
|
+
//#region src/panes/sigil-types.d.ts
|
|
1300
|
+
/**
|
|
1301
|
+
* RFC-036 T036-07:TUI 侧 sigil 类型(本地结构镜像)。
|
|
1302
|
+
*
|
|
1303
|
+
* R3:TUI 是叶子包,零 `@x-otto/*` 运行时依赖。故不 import `@x-otto/coding`,
|
|
1304
|
+
* 而是在此定义与 coding `SigilEntry`/`PluginInputRegistry` **结构同构**的本地类型。
|
|
1305
|
+
* App.tsx 接线点处 coding 的具体 registry 经 props 流入——结构类型使其可赋值。
|
|
1306
|
+
*
|
|
1307
|
+
* 若 coding 侧契约变更,需同步此镜像(两处保持一致是 R3 解耦的成本)。
|
|
1308
|
+
*/
|
|
1309
|
+
type SigilPrefix = '#' | '@';
|
|
1310
|
+
type SigilKind = 'hashtag' | 'file' | 'person' | 'agent' | 'skill' | 'mcp' | 'plugin' | 'model' | 'resource' | 'shortcut';
|
|
1311
|
+
/** 面板条目:label 展示 / value 替换,严格分离(R2)。 */
|
|
1312
|
+
interface SigilEntry {
|
|
1313
|
+
label: string;
|
|
1314
|
+
value: string;
|
|
1315
|
+
description?: string;
|
|
1316
|
+
kind: SigilKind;
|
|
1317
|
+
source?: string;
|
|
1318
|
+
/** 预览内容(@file 等):非空时 Enter 先弹出预览弹窗再确认插入。TUI 消费方可选。 */
|
|
1319
|
+
preview?: string;
|
|
1320
|
+
/** RFC-210 D2:resolve 引用(结构镜像,语义见 @x-otto/interchange input.ts 同名字段)。 */
|
|
1321
|
+
resolverId?: string;
|
|
1322
|
+
}
|
|
1323
|
+
/** TUI 仅消费 search——渲染数据源。其余生命周期方法 TUI 不触及。 */
|
|
1324
|
+
interface SigilSearchRegistry {
|
|
1325
|
+
search(query: string, sigil?: SigilPrefix, maxResults?: number): SigilEntry[];
|
|
1326
|
+
/**
|
|
1327
|
+
* 异步搜索:含 @file 等动态 provider 结果(RFC-044 M044-07)。
|
|
1328
|
+
* 可选——registry 未实现时 SigilPane 退回同步 search。
|
|
1329
|
+
*/
|
|
1330
|
+
searchAsync?(query: string, sigil?: SigilPrefix, maxResults?: number): Promise<SigilEntry[]>;
|
|
1331
|
+
}
|
|
1332
|
+
//#endregion
|
|
1333
|
+
//#region src/input/PromptInput.d.ts
|
|
1334
|
+
type SubmitMode = 'send' | 'bash' | 'bash_async' | 'memory';
|
|
1335
|
+
interface PromptInputProps {
|
|
1336
|
+
columns?: number;
|
|
1337
|
+
/** RFC-306 后修复(光标锚定):终端总行数——用于把光标锚定到输入行(Ink 输出原点相对坐标)。 */
|
|
1338
|
+
rows?: number;
|
|
1339
|
+
placeholder?: string;
|
|
1340
|
+
/** RFC-294 D7:真禁用(强制升级/确认框占据交互)→ 塌缩为单行提示。 */
|
|
1341
|
+
disabled?: boolean;
|
|
1342
|
+
/** RFC-300 优化:回看态(滚动回看中)——保留完整外观(不塌缩),仅不注册键盘
|
|
1343
|
+
* (滚动独占)且不渲染光标。区别于 disabled:disabled 塌缩,reviewing 不塌缩。 */
|
|
1344
|
+
reviewing?: boolean;
|
|
1345
|
+
/** 空闲提示卡片是否可见——卡片在输入框上方占 3+ 行且有 480ms 动画,
|
|
1346
|
+
* 出现时物理光标隐藏(光标残影防护)。 */
|
|
1347
|
+
idleTipVisible?: boolean;
|
|
1348
|
+
/** 斜杠命令表(typeahead 数据源) */
|
|
1349
|
+
commands?: CommandEntry[];
|
|
1350
|
+
/** force=true 表示修饰键+Enter(Alt/Ctrl/Cmd)——上层据此映射为 followUp/排队;plain Enter→steer/send。 */
|
|
1351
|
+
/**
|
|
1352
|
+
* 提交回调。
|
|
1353
|
+
*
|
|
1354
|
+
* 返回 `'rejected'` 表示宿主**拒绝了本次提交**(如 FTUE 未就绪、无可用模型),
|
|
1355
|
+
* 此时输入框**保留原文**,用户修完配置可直接重发(RFC-326 §6.7:
|
|
1356
|
+
* "未发出的 prompt 保留在输入框")。返回 void/其它值一律按已受理处理并清空。
|
|
1357
|
+
*
|
|
1358
|
+
* 背景:此前 `setText('')` 在 onSubmit 之后**无条件**执行——CLI 侧虽然在
|
|
1359
|
+
* `!modelReady` 时 early-return 且注释写着"输入不回显、不丢失",但那只保证
|
|
1360
|
+
* 不进对话流,输入框其实已经被清掉了。用户敲完一整段 prompt、按下回车、
|
|
1361
|
+
* 看到一个转瞬即逝的 toast,然后**文字没了**。
|
|
1362
|
+
*/
|
|
1363
|
+
onSubmit?: (text: string, mode: SubmitMode, force?: boolean) => void | 'rejected';
|
|
1364
|
+
onInterrupt?: () => void;
|
|
1365
|
+
onClear?: () => void;
|
|
1366
|
+
/** 输入为空时的 Esc 委托(App:关 inspector→删队列→中断)。输入有内容时 Esc 先逐行清空,不调此回调——
|
|
1367
|
+
* 以此让 Esc 单一归属,消除"输入有内容+队列有内容时按 Esc 同帧既清输入又删队列"的双吃 bug。 */
|
|
1368
|
+
onEscape?: () => void;
|
|
1369
|
+
/** Ctrl+R 打开 history 模式的 SigilPane(宿主处理面板状态/路由)。 */
|
|
1370
|
+
onHistorySearch?: () => void;
|
|
1371
|
+
/** history 面板是否在场(宿主传入)——在场时关闭 typeahead 建议,避免与面板叠显。 */
|
|
1372
|
+
historySearchOpen?: boolean;
|
|
1373
|
+
/** toast 通知回调(ctrl+s 存草稿 / ctrl+x 外部编辑) */
|
|
1374
|
+
onToast?: (title: string, content: string) => void;
|
|
1375
|
+
/** ctrl+s 保存当前输入为一条自动命名的草稿(随会话快照持久化)。 */
|
|
1376
|
+
onDraftSave?: (text: string) => void;
|
|
1377
|
+
/** 用户快捷键覆盖表(settings `keybinding_overrides`)——`save-draft` 键位据此解析。 */
|
|
1378
|
+
keybindingOverrides?: Record<string, KeyBindingPredicate>;
|
|
1379
|
+
/** 大段粘贴确认回调(>800 字符或 >20 行时弹确认对话框)。
|
|
1380
|
+
* text 为原始粘贴内容(供对话框预览);handlers.confirm() 折叠为 #paste_N 插入;
|
|
1381
|
+
* handlers.cancel() 丢弃。 */
|
|
1382
|
+
onPasteConfirm?: (text: string, handlers: {
|
|
1383
|
+
confirm: () => void;
|
|
1384
|
+
cancel: () => void;
|
|
1385
|
+
}) => void;
|
|
1386
|
+
/** 是否启用 #/@ sigil 检测(无 pluginInput 数据源时 false,行为完全旁路)。 */
|
|
1387
|
+
sigilEnabled?: boolean;
|
|
1388
|
+
/**
|
|
1389
|
+
* RFC-212 D3:光标停靠在"面板来源" chip(file/agent/skill/mcp/person/plugin/model
|
|
1390
|
+
* 等)上按 Enter——重新拉起 @ 面板做范围替换。与 `onSigilTrigger`(正常 @ 输入触发)
|
|
1391
|
+
* 是独立回调,不复用其 handlers(chip 重开的替换区间是 `[chipRange.start,
|
|
1392
|
+
* chipRange.end)`,与 `onSigilTrigger` 依赖的 anchor/cursor 触发上下文语义不同)。
|
|
1393
|
+
*/
|
|
1394
|
+
onChipReopen?: (kind: string, chipRange: {
|
|
1395
|
+
start: number;
|
|
1396
|
+
end: number;
|
|
1397
|
+
}, handlers: {
|
|
1398
|
+
select: (entry: SigilEntry) => void;
|
|
1399
|
+
cancel: () => void;
|
|
1400
|
+
}) => void;
|
|
1401
|
+
/**
|
|
1402
|
+
* RFC-212 D3:光标停靠在 paste chip 上按 Enter——打开只读内容查看器。pasteId 已失效
|
|
1403
|
+
* (不在 PasteStore 中)时不调用本回调,由 PromptInput 自行 toast 提示。
|
|
1404
|
+
*/
|
|
1405
|
+
onChipViewPaste?: (label: string, content: string) => void;
|
|
1406
|
+
/** shell-complete 的工作目录(路径补全的依据),由 App 传入 welcome.cwd。 */
|
|
1407
|
+
cwd?: string;
|
|
1408
|
+
/** /history 面板选中后回填文本——PromptInput 在 mount 时将 fill() 写入此 ref。
|
|
1409
|
+
* App 持有此 ref,用户选择历史条目后调用 ref.current.fill(text)。 */
|
|
1410
|
+
historyInsertRef?: {
|
|
1411
|
+
current: {
|
|
1412
|
+
fill: (text: string) => void;
|
|
1413
|
+
append?: (text: string) => void;
|
|
1414
|
+
} | null;
|
|
1415
|
+
};
|
|
1416
|
+
/**
|
|
1417
|
+
* RFC-338 D7a:粘贴缓存的树外桥接句柄(宿主 cli 用于 hydrate/落盘)。
|
|
1418
|
+
* 与 `historyInsertRef` 同款命令式 ref 模式——paste store 是本组件的 useRef
|
|
1419
|
+
* 单例,且组件不感知 sessionId,会话切换时的重绑必须由 cli 侧驱动。
|
|
1420
|
+
*/
|
|
1421
|
+
pasteBridgeRef?: {
|
|
1422
|
+
current: {
|
|
1423
|
+
hydrate: (snapshot: PasteSnapshot | null | undefined) => void;
|
|
1424
|
+
export: () => PasteSnapshot;
|
|
1425
|
+
} | null;
|
|
1426
|
+
};
|
|
1427
|
+
/** 持久化输入历史初始条目(从磁盘恢复)。PromptInput 用此初始化 InputHistory。 */
|
|
1428
|
+
initialHistory?: readonly string[];
|
|
1429
|
+
/** RFC-129:外部 shell 历史(只读,供 ghost/Ctrl+R;不落盘)。 */
|
|
1430
|
+
externalHistoryCommands?: readonly string[];
|
|
1431
|
+
/** 每次 push 新历史条目时回调——携带完整 entries 列表供外层落盘。 */
|
|
1432
|
+
onHistoryPush?: (entries: readonly string[]) => void;
|
|
1433
|
+
/**
|
|
1434
|
+
* 历史导航态变化回调——会话头 logo 旁 HUD 据此展示「N/total + 当前条目」。
|
|
1435
|
+
* 导航中传 { position, total, entry },回到底部/开始打新字/提交后传 null。
|
|
1436
|
+
*/
|
|
1437
|
+
onHistoryNavChange?: (nav: {
|
|
1438
|
+
position: number;
|
|
1439
|
+
total: number;
|
|
1440
|
+
entry: string;
|
|
1441
|
+
} | null) => void;
|
|
1442
|
+
/** RFC-198 §4.4:PasteStore 内存压力分级来源只读视图(省略时固定 healthy 上限)。 */
|
|
1443
|
+
residencyGovernor?: PasteStoreResidencySource;
|
|
1444
|
+
/** 检测到 #/@ 触发时上报 App(App 持有面板状态/焦点,F-focus)。
|
|
1445
|
+
* handlers.select(entry) / handlers.cancel(deleteSigil) 由 App 在选择/关闭时回调,
|
|
1446
|
+
* PromptInput 据此把替换/删除应用到文本(走 applyText 'completion' 来源刷新 mode,D7/R7)。 */
|
|
1447
|
+
onSigilTrigger?: (sigil: SigilPrefix, query: string, handlers: {
|
|
1448
|
+
select: (entry: SigilEntry) => void;
|
|
1449
|
+
cancel: (deleteSigil: boolean) => void;
|
|
1450
|
+
}) => void;
|
|
1451
|
+
/**
|
|
1452
|
+
* RFC-215 D3:sigil 触发条件被编辑破坏(decision.action === 'close')时通知宿主关面板。
|
|
1453
|
+
* 不传时退化为 suppress 行为(面板关闭交由既有失焦/Esc 机制,向后兼容不回归)。
|
|
1454
|
+
*/
|
|
1455
|
+
onSigilClose?: () => void;
|
|
1456
|
+
/** 向外暴露命令 registry(用于在 TUI 初始化后注册参数补全函数)。 */
|
|
1457
|
+
registryRef?: {
|
|
1458
|
+
current: ReturnType<typeof createCommandRegistry> | null;
|
|
1459
|
+
};
|
|
1460
|
+
/** Shell 补全编排器引用。由外层创建并注入。 */
|
|
1461
|
+
shellBackendRef?: {
|
|
1462
|
+
current: Completer | null;
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
declare function PromptInput({
|
|
1466
|
+
columns,
|
|
1467
|
+
placeholder,
|
|
1468
|
+
disabled,
|
|
1469
|
+
reviewing,
|
|
1470
|
+
commands,
|
|
1471
|
+
onSubmit,
|
|
1472
|
+
onInterrupt,
|
|
1473
|
+
onClear,
|
|
1474
|
+
onEscape,
|
|
1475
|
+
onHistorySearch,
|
|
1476
|
+
historySearchOpen,
|
|
1477
|
+
sigilEnabled,
|
|
1478
|
+
onSigilTrigger,
|
|
1479
|
+
onSigilClose,
|
|
1480
|
+
onChipReopen,
|
|
1481
|
+
onChipViewPaste,
|
|
1482
|
+
onToast,
|
|
1483
|
+
onDraftSave,
|
|
1484
|
+
keybindingOverrides,
|
|
1485
|
+
onPasteConfirm,
|
|
1486
|
+
cwd,
|
|
1487
|
+
historyInsertRef,
|
|
1488
|
+
pasteBridgeRef,
|
|
1489
|
+
initialHistory,
|
|
1490
|
+
externalHistoryCommands,
|
|
1491
|
+
onHistoryPush,
|
|
1492
|
+
onHistoryNavChange,
|
|
1493
|
+
residencyGovernor,
|
|
1494
|
+
registryRef,
|
|
1495
|
+
shellBackendRef
|
|
1496
|
+
}: PromptInputProps): React.ReactElement;
|
|
1497
|
+
//#endregion
|
|
1498
|
+
//#region src/input/QueuedCommands.d.ts
|
|
1499
|
+
interface QueuedItem {
|
|
1500
|
+
text: string;
|
|
1501
|
+
mode: SubmitMode;
|
|
1502
|
+
}
|
|
1503
|
+
interface QueuedCommandsProps {
|
|
1504
|
+
items: QueuedItem[];
|
|
1505
|
+
}
|
|
1506
|
+
declare function QueuedCommands({
|
|
1507
|
+
items
|
|
1508
|
+
}: QueuedCommandsProps): React.ReactElement | null;
|
|
1509
|
+
//#endregion
|
|
1510
|
+
//#region src/panes/DraftPane.d.ts
|
|
1511
|
+
interface DraftItemView$1 {
|
|
1512
|
+
id: string;
|
|
1513
|
+
name: string;
|
|
1514
|
+
text: string;
|
|
1515
|
+
savedAt: number;
|
|
1516
|
+
}
|
|
1517
|
+
//#endregion
|
|
1518
|
+
//#region src/status-bar/provider-usage-badge.d.ts
|
|
1519
|
+
type ProviderUsageLimitType = 'five_hour' | 'seven_day' | 'seven_day_opus' | 'seven_day_sonnet' | 'seven_day_overage_included';
|
|
1520
|
+
/** 'unknown' = 无订阅配额数据(OpenAI 等无 unified 头族的 provider,RFC-118 S11)——中性态,不判额度充足也不报警。 */
|
|
1521
|
+
type ProviderUsageStatusKind = 'allowed' | 'allowed_warning' | 'rejected' | 'unknown';
|
|
1522
|
+
interface ProviderUsageBadgeItem {
|
|
1523
|
+
status: ProviderUsageStatusKind;
|
|
1524
|
+
limitType?: ProviderUsageLimitType;
|
|
1525
|
+
resetsAt?: number;
|
|
1526
|
+
usedPercent?: number;
|
|
1527
|
+
overageStatus?: ProviderUsageStatusKind;
|
|
1528
|
+
overageResetsAt?: number;
|
|
1529
|
+
}
|
|
1530
|
+
/** 完整人类可读标签(/usage 命令用,区别于状态栏紧凑短标签)。未知类型兜底原始字符串。 */
|
|
1531
|
+
declare function formatProviderUsageLimitTypeFull(limitType: ProviderUsageLimitType | string): string;
|
|
1532
|
+
/**
|
|
1533
|
+
* Overage 判定——标准额度已耗尽但其额外用量池仍可用。
|
|
1534
|
+
* 逻辑:`status === 'rejected' && overage in (allowed, warning)`。
|
|
1535
|
+
*/
|
|
1536
|
+
declare function isUsingOverage(status: ProviderUsageStatusKind, overageStatus?: ProviderUsageStatusKind): boolean;
|
|
1537
|
+
//#endregion
|
|
1538
|
+
//#region src/services/status-widget-registry.d.ts
|
|
1539
|
+
/**
|
|
1540
|
+
* 宿主组装的只读快照。`providerUsage` 用 TUI 内部 `ProviderUsageBadgeItem`(App.tsx 状态栏
|
|
1541
|
+
* 实际持有的类型,`overageStatus` 含 `'unknown'` 中性态,见 RFC-118 S11)而非 `@x-otto/interchange
|
|
1542
|
+
* ProviderUsageSnapshot`(更严格的协议层类型,不含 `'unknown'`)——两者跨包各自定义同构类型是
|
|
1543
|
+
* 既有纹理(同 `RegisteredRenderer` 先例),`@x-otto/coding status-widget-loader.ts` 侧的
|
|
1544
|
+
* `StatusWidgetContext` 是装载模块的文档性类型镜像,实际快照组装与 render 调用只发生在本侧。
|
|
1545
|
+
*/
|
|
1546
|
+
interface StatusWidgetContext {
|
|
1547
|
+
nowMs: number;
|
|
1548
|
+
model: string;
|
|
1549
|
+
providerUsage: ProviderUsageBadgeItem | null;
|
|
1550
|
+
columns: number;
|
|
1551
|
+
}
|
|
1552
|
+
type StatusWidgetColorKind = 'warning' | 'inactive';
|
|
1553
|
+
type PluginStatusWidgetRenderFn = (ctx: StatusWidgetContext) => {
|
|
1554
|
+
text: string;
|
|
1555
|
+
color?: StatusWidgetColorKind;
|
|
1556
|
+
} | null;
|
|
1557
|
+
interface RegisteredStatusWidget {
|
|
1558
|
+
id: string;
|
|
1559
|
+
pluginId: string;
|
|
1560
|
+
render: PluginStatusWidgetRenderFn;
|
|
1561
|
+
tickMs?: number;
|
|
1562
|
+
order?: number;
|
|
1563
|
+
}
|
|
1564
|
+
//#endregion
|
|
1565
|
+
//#region src/views/recovery-card.d.ts
|
|
1566
|
+
/**
|
|
1567
|
+
* recovery-card.ts — RFC-326 §6.7:Home 常驻恢复卡的纯呈现逻辑。
|
|
1568
|
+
*
|
|
1569
|
+
* 问题:用户 Esc 退出向导后,Home 上**没有任何**"还差什么"的线索——配置状态只
|
|
1570
|
+
* 活在一个转瞬即逝的 toast 里,之后就只能靠用户记住 `/setup`。§6.7 要求把它变成
|
|
1571
|
+
* 常驻可见的事实:每个未就绪阶段给一个明确的主行动。
|
|
1572
|
+
*
|
|
1573
|
+
* 本模块只做「阶段 → 文案键 + 单一 CTA」的映射与窄屏降级,不碰渲染:
|
|
1574
|
+
* - 纯函数,便于穷举每个阶段的产物;
|
|
1575
|
+
* - 文案返回 **i18n key** 而非成品字符串,避免纯逻辑层耦合语言资源。
|
|
1576
|
+
*
|
|
1577
|
+
* 设计约束(§6.7 明文):
|
|
1578
|
+
* - **单一 CTA**:每张卡只给一个推荐动作,不并列 `/login` `/model` `/plugin`
|
|
1579
|
+
* 让新用户猜(§4 原则 4)。
|
|
1580
|
+
* - **常态 ≤4 行**、窄屏(<80 列)降为两行标题+CTA。
|
|
1581
|
+
* - 卡片走文档流,不得占用 ChatInputArea / StatusBar 的稳定行位——这条由渲染层
|
|
1582
|
+
* 保证(放在 Home 主区域内),本模块只负责把行数压在预算内。
|
|
1583
|
+
*/
|
|
1584
|
+
/** 与 `FtueStage` 同构;此处独立声明避免 tui 反向依赖 cli 的 ftue 模块。 */
|
|
1585
|
+
type RecoveryStage = 'provider' | 'authentication' | 'model' | 'ready' | 'first-prompt';
|
|
1586
|
+
//#endregion
|
|
1587
|
+
//#region src/views/Home.d.ts
|
|
1588
|
+
interface SessionListItem {
|
|
1589
|
+
id: string;
|
|
1590
|
+
title: string;
|
|
1591
|
+
status: 'busy' | 'idle' | 'needs-input' | 'idle-cold';
|
|
1592
|
+
lastActivityAt: string;
|
|
1593
|
+
isCurrent: boolean;
|
|
1594
|
+
isPinned: boolean;
|
|
1595
|
+
isArchived: boolean;
|
|
1596
|
+
isReadOnly: boolean;
|
|
1597
|
+
}
|
|
1598
|
+
interface HomeProps {
|
|
1599
|
+
version?: string;
|
|
1600
|
+
/** build ID(git rev-list --count HEAD),非空时在版本号后显示 "(build N)"。 */
|
|
1601
|
+
buildId?: number;
|
|
1602
|
+
cwd?: string;
|
|
1603
|
+
width?: number;
|
|
1604
|
+
/** 用户昵称(settings.nickname):织入问候语并以 accent 高亮;缺省回退无名问候。 */
|
|
1605
|
+
nickname?: string;
|
|
1606
|
+
/** 更新提示:非空时在 version 行后展示新版通知。 */
|
|
1607
|
+
updateAvailable?: {
|
|
1608
|
+
latest: string;
|
|
1609
|
+
current: string;
|
|
1610
|
+
newer: boolean;
|
|
1611
|
+
forced: boolean;
|
|
1612
|
+
};
|
|
1613
|
+
/** 天气信息(可选,未实现时留空)。 */
|
|
1614
|
+
weather?: {
|
|
1615
|
+
condition: string;
|
|
1616
|
+
temp: number;
|
|
1617
|
+
location: string;
|
|
1618
|
+
};
|
|
1619
|
+
/**
|
|
1620
|
+
* RFC-326 §6.7:FTUE 阶段——非 ready 时在首屏渲染常驻恢复卡。
|
|
1621
|
+
* 省略/ready 时不渲染,老用户零干扰。
|
|
1622
|
+
*/
|
|
1623
|
+
ftueStage?: RecoveryStage;
|
|
1624
|
+
/** RFC-234 P2-b:多会话列表。未提供时不渲染。 */
|
|
1625
|
+
sessionList?: readonly SessionListItem[];
|
|
1626
|
+
/** RFC-234 P2-b:选择会话回调。 */
|
|
1627
|
+
onSessionSelect?: (id: string) => void;
|
|
1628
|
+
/** 当前语言检测 */
|
|
1629
|
+
lang?: string;
|
|
1630
|
+
/** RFC-345 D6:影子会话——在首屏横幅下方展示保证/不保证清单。 */
|
|
1631
|
+
shadow?: boolean;
|
|
1632
|
+
}
|
|
1633
|
+
/**
|
|
1634
|
+
* 品牌像素字标 "otto" 及其扫光动画抽取至 `./Wordmark`,Home 首屏与对话中
|
|
1635
|
+
* SessionHeader 共用(避免像素行/扫光逻辑双份维护)。
|
|
1636
|
+
*/
|
|
1637
|
+
declare function Home({
|
|
1638
|
+
version,
|
|
1639
|
+
buildId,
|
|
1640
|
+
cwd,
|
|
1641
|
+
width,
|
|
1642
|
+
nickname,
|
|
1643
|
+
updateAvailable,
|
|
1644
|
+
weather: _weather,
|
|
1645
|
+
ftueStage,
|
|
1646
|
+
shadow
|
|
1647
|
+
}: HomeProps): React.ReactElement;
|
|
1648
|
+
//#endregion
|
|
1649
|
+
//#region src/stores/task-store.d.ts
|
|
1650
|
+
interface TaskState {
|
|
1651
|
+
tasks: TaskItem$1[];
|
|
1652
|
+
tasksTitle: string | undefined;
|
|
1653
|
+
turnBoundaries: number[];
|
|
1654
|
+
editedFiles: EditedFileEntry[];
|
|
1655
|
+
backgroundTasks: BackgroundTaskSummary[];
|
|
1656
|
+
subagentsAccum: Map<string, BackgroundTaskSummary>;
|
|
1657
|
+
scheduleTasks: Array<{
|
|
1658
|
+
id: string;
|
|
1659
|
+
name: string;
|
|
1660
|
+
cronExpression: string;
|
|
1661
|
+
enabled: boolean;
|
|
1662
|
+
recurring: boolean;
|
|
1663
|
+
nextFireAt: number;
|
|
1664
|
+
lastFiredAt?: number;
|
|
1665
|
+
}>;
|
|
1666
|
+
drafts: DraftItemView$1[];
|
|
1667
|
+
/** 最近复制字符数(SignalBar 剪贴板信号,TTL 后归零) */
|
|
1668
|
+
clipboardChars: number;
|
|
1669
|
+
/** 最近一次复制的正文(供剪贴板面板/查看器展示;单条覆盖式,随每次复制更新)。
|
|
1670
|
+
* 与 clipboardChars 的 TTL 无关——TTL 只控制 SignalBar 那行提示显隐,正文保留到
|
|
1671
|
+
* 下次复制或会话结束(否则 12s 后就没有查看入口了)。 */
|
|
1672
|
+
clipboardText: string;
|
|
1673
|
+
/** 复制写入两路通道均失败(SignalBar 显示失败兜底信号,非 Toast)。TTL 后归零。 */
|
|
1674
|
+
clipboardFailed: boolean;
|
|
1675
|
+
queued: QueuedItem[];
|
|
1676
|
+
pendingPermission: unknown | null;
|
|
1677
|
+
backgroundOutput: DelegateOutputView | null;
|
|
1678
|
+
subagentContext: unknown | null;
|
|
1679
|
+
forcedUpgrade: string | null;
|
|
1680
|
+
modelName: string;
|
|
1681
|
+
pluginStatusItems: readonly {
|
|
1682
|
+
id: string;
|
|
1683
|
+
text: string;
|
|
1684
|
+
}[];
|
|
1685
|
+
/** 状态栏代码式徽标(RFC-184 D2/D3)——`setPluginRegistrations` 同步写入,同 pluginStatusItems 语义。 */
|
|
1686
|
+
statusWidgets: readonly RegisteredStatusWidget[];
|
|
1687
|
+
needsSetup: boolean;
|
|
1688
|
+
permissionMode: string;
|
|
1689
|
+
commands: unknown[];
|
|
1690
|
+
paneOwnsViewportFlag: boolean;
|
|
1691
|
+
/** 刚 echo、模型尚未返回首字节的 user 消息——ESC 击键据此走『撤回』而非 abort 对话框。 */
|
|
1692
|
+
pendingEcho: {
|
|
1693
|
+
text: string;
|
|
1694
|
+
mode: string;
|
|
1695
|
+
} | null;
|
|
1696
|
+
/** RFC-337 D3:运行中追加(steer)但尚未被模型消费的消息(延迟 commit,live 区渲染)。
|
|
1697
|
+
* ESC 撤回最近一条(列表末尾);被模型 drain 时经 steer.consumed 转正 commit 到 scrollback。 */
|
|
1698
|
+
pendingSteers: readonly {
|
|
1699
|
+
text: string;
|
|
1700
|
+
id: string;
|
|
1701
|
+
}[];
|
|
1702
|
+
/** shellExecution + shellTimer 成对出现,不进 store(timer 是副作用句柄)。 */
|
|
1703
|
+
shellExecution: unknown;
|
|
1704
|
+
/** 最近 @ 到的条目(MRU,最多 5 条,最近在前);SigilPane「最近使用」分组数据源。
|
|
1705
|
+
* 持久化真源在 cli 侧 settings.recent_mentions(.otto/config.json 项目层),
|
|
1706
|
+
* 经 setRecentMentions() 单向下发到本 store(cli→tui,与 setDrafts 同款模式)。 */
|
|
1707
|
+
recentMentions: SigilEntry[];
|
|
1708
|
+
/** RFC-234 P2-b:Home 多会话列表。 */
|
|
1709
|
+
sessionList: readonly SessionListItem[];
|
|
1710
|
+
/** 当前会话标题(对话中 SessionHeader 展示)——cli 侧 resolveSessionTitle 单一真源下推。 */
|
|
1711
|
+
sessionTitle: string;
|
|
1712
|
+
}
|
|
1713
|
+
interface TaskStore {
|
|
1714
|
+
store: Store<TaskState>;
|
|
1715
|
+
reset(): void;
|
|
1716
|
+
/**
|
|
1717
|
+
* 注入渲染触发器(RFC-333 M2-A)。store 创建早于 notify(main.ts:192 vs :304),
|
|
1718
|
+
* 故沿用 perfStore.setNotify 的 post-creation 注入范式。未注入时 actions 内 notify 为 no-op
|
|
1719
|
+
* (供无渲染环境的纯 store 单测)。
|
|
1720
|
+
*/
|
|
1721
|
+
setNotify(notify: () => void): void;
|
|
1722
|
+
/**
|
|
1723
|
+
* 注入副作用钩子(RFC-335 T335-07 前置 P0a)。原 TuiHandle 残留 setter 是"字段 setter
|
|
1724
|
+
* + 副作用"混合体(如 setForcedUpgrade = setState + syncOverlayRoute + notify)——
|
|
1725
|
+
* 直接变纯 action 会丢副作用。setEffects 把副作用接入口子化注入(仿 setNotify 的
|
|
1726
|
+
* post-creation 注入范式),store 层不 import 树外 ref(routerRef/plugin registry),
|
|
1727
|
+
* 由 main.ts 接线处把闭包函数传进来。未注入时副作用为 no-op(对齐 notify 防过早调用)。
|
|
1728
|
+
*/
|
|
1729
|
+
setEffects(effects: TaskStoreEffects): void;
|
|
1730
|
+
/**
|
|
1731
|
+
* store action 出口(RFC-333 M2-A)。封装原 TuiHandle setter 的派生逻辑(sort/merge/
|
|
1732
|
+
* Map 累积)+ notify,使写入方(现为 TuiHandle setter 转发,M2-B 后为 cli 直调、
|
|
1733
|
+
* T335-07 后为 service-client adapter)调 action 即获得一致语义,store 成为唯一写入汇聚点。
|
|
1734
|
+
*/
|
|
1735
|
+
actions: TaskActions;
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* taskStore 副作用接入口子。注入方(main.ts)把闭包函数绑进来——这些闭包内部可
|
|
1739
|
+
* `getRouterRef()` 取真 router / `registerPlugin` 调中央 registry,故接口不把 router/
|
|
1740
|
+
* registry 作为参数传递(保持 store 层不引用任何树外类型)。这是"store 不依赖树外
|
|
1741
|
+
* 全局"的类型层体现(P0c 先导)。
|
|
1742
|
+
*/
|
|
1743
|
+
interface TaskStoreEffects {
|
|
1744
|
+
/** 强制升级 overlay 开/关(router 副作用);true→开、false→关。注入方内部 syncOverlayRoute。 */
|
|
1745
|
+
syncForcedUpgradeRoute?(open: boolean): void;
|
|
1746
|
+
/** 后台输出视图 follow:true→navigate '/pane/delegates/output';false 且正停该 path→goBack。 */
|
|
1747
|
+
backgroundOutputRoute?(open: boolean): void;
|
|
1748
|
+
/** 后台输出变更后若空闲则冲刷滚动缓冲(原 inline 的 flushScrollbackIfIdle())。 */
|
|
1749
|
+
flushScrollbackIfIdle?(): void;
|
|
1750
|
+
/** 注册插件状态条目到中央 registry(原 inline 的 registerPlugin('cli-status', ...))。 */
|
|
1751
|
+
registerStatusItems?(items: readonly {
|
|
1752
|
+
id: string;
|
|
1753
|
+
text: string;
|
|
1754
|
+
}[]): void;
|
|
1755
|
+
}
|
|
1756
|
+
interface TaskActions {
|
|
1757
|
+
setTasks(tasks: TaskItem$1[], title?: string): void;
|
|
1758
|
+
setEditedFiles(files: EditedFileEntry[]): void;
|
|
1759
|
+
addEditedFile(entry: EditedFileEntry): void;
|
|
1760
|
+
setBackgroundTasks(tasks: BackgroundTaskSummary[]): void;
|
|
1761
|
+
setTurnBoundaries(boundaries: number[]): void;
|
|
1762
|
+
addTurnBoundary(messageIndex: number): void;
|
|
1763
|
+
setDrafts(drafts: DraftItemView$1[]): void;
|
|
1764
|
+
setScheduleTasks(tasks: TaskState['scheduleTasks']): void;
|
|
1765
|
+
setRecentMentions(entries: SigilEntry[]): void;
|
|
1766
|
+
setModelName(name: string): void;
|
|
1767
|
+
setSessionList(list: TaskState['sessionList']): void;
|
|
1768
|
+
setSessionTitle(title: string): void;
|
|
1769
|
+
setNeedsSetup(value: boolean): void;
|
|
1770
|
+
setPermissionMode(mode: string): void;
|
|
1771
|
+
/** 强制升级提示(RFC-335 P0a 自 TuiHandle.setForcedUpgrade 下沉):字段 + overlay 路由 + notify。 */
|
|
1772
|
+
setForcedUpgrade(msg: string | null): void;
|
|
1773
|
+
/** 插件状态栏条目(RFC-335 P0a 自 TuiHandle.setPluginStatusItems):字段 + 注册中央 registry + notify。 */
|
|
1774
|
+
setPluginStatusItems(items: readonly {
|
|
1775
|
+
id: string;
|
|
1776
|
+
text: string;
|
|
1777
|
+
}[]): void;
|
|
1778
|
+
/** 实时输出跟随视图(RFC-335 P0a 自 TuiHandle.setBackgroundOutput):字段 + 路由 follow + 空闲冲刷 + notify。 */
|
|
1779
|
+
setBackgroundOutput(view: DelegateOutputView | null): void;
|
|
1780
|
+
}
|
|
1781
|
+
//#endregion
|
|
1782
|
+
//#region src/stores/budget-store.d.ts
|
|
1783
|
+
interface BudgetView {
|
|
1784
|
+
/** 模型名(展示用)。 */
|
|
1785
|
+
modelName: string;
|
|
1786
|
+
/** 上下文窗口总大小(token)。 */
|
|
1787
|
+
contextWindow: number;
|
|
1788
|
+
/** 上下文占用 %(totalUsed / contextWindow * 100)。 */
|
|
1789
|
+
contextPercent: number;
|
|
1790
|
+
/** 固定开销 token = estimateTokens(systemPrompt) + getToolTokens(tools)。 */
|
|
1791
|
+
overheadTokens: number;
|
|
1792
|
+
/** 消息 token = 真实已用 − 固定开销(totalUsed − overheadTokens);prompt cache 下含历史。 */
|
|
1793
|
+
messageTokens: number;
|
|
1794
|
+
/** 当前会话消息条数(messages 段显示为 token(条数))。 */
|
|
1795
|
+
messageCount: number;
|
|
1796
|
+
/** 全部已用 token = cacheReadTokens + cacheWriteTokens + inputTokens。 */
|
|
1797
|
+
totalUsed: number;
|
|
1798
|
+
/** 可用 token = contextWindow − overhead − messages(三段恒闭合;正常态 = window − totalUsed)。 */
|
|
1799
|
+
free: number;
|
|
1800
|
+
/** prune 触发线 token 数(70% contextWindow)。 */
|
|
1801
|
+
pruneLine: number;
|
|
1802
|
+
/** compact 触发线 token 数(85% contextWindow)。 */
|
|
1803
|
+
compactLine: number;
|
|
1804
|
+
/** 最近一轮 input(非 cache 部分,API 返回)。 */
|
|
1805
|
+
lastInput: number;
|
|
1806
|
+
/** 最近一轮 output。 */
|
|
1807
|
+
lastOutput: number;
|
|
1808
|
+
/** 全会话累计 input。 */
|
|
1809
|
+
totalInput: number;
|
|
1810
|
+
/** 全会话累计 output。 */
|
|
1811
|
+
totalOutput: number;
|
|
1812
|
+
/** 估算成本(USD,按模型费率;未知/0 时省略)。 */
|
|
1813
|
+
cost?: number;
|
|
1814
|
+
/**
|
|
1815
|
+
* true = 本次读数含"尚未被 provider usage 结算"的本地实时估算(agent 工作中:prompt 已提交/
|
|
1816
|
+
* 工具结果已产出/正在流式输出)。UI 据此标注 `~`,避免用户把 live 估算当成权威值、
|
|
1817
|
+
* 在回合结算校准后误以为占用"回退"了。false/缺省 = provider usage 结算后的权威快照。
|
|
1818
|
+
*/
|
|
1819
|
+
live?: boolean;
|
|
1820
|
+
}
|
|
1821
|
+
interface BudgetState {
|
|
1822
|
+
/** 尚未收到任何预算快照时为 null(状态栏据此不渲染占用条)。 */
|
|
1823
|
+
budget: BudgetView | null;
|
|
1824
|
+
}
|
|
1825
|
+
interface BudgetStore {
|
|
1826
|
+
store: Store<BudgetState>;
|
|
1827
|
+
setBudget(v: BudgetView): void;
|
|
1828
|
+
/** `/clear` 等会话重置:回到"无预算"初值,避免旧会话读数残留。 */
|
|
1829
|
+
reset(): void;
|
|
1830
|
+
}
|
|
1831
|
+
declare function createBudgetStore(): BudgetStore;
|
|
1832
|
+
//#endregion
|
|
1833
|
+
//#region src/stores/cache-store.d.ts
|
|
1834
|
+
/** 单模型的缓存用量明细(对齐 `@x-otto/ai` 的 `ModelCost` 子集,不跨包 import 类型)。 */
|
|
1835
|
+
interface CacheModelRow {
|
|
1836
|
+
modelId: string;
|
|
1837
|
+
modelName: string;
|
|
1838
|
+
cacheReadTokens: number;
|
|
1839
|
+
cacheWriteTokens: number;
|
|
1840
|
+
inputTokens: number;
|
|
1841
|
+
/**
|
|
1842
|
+
* 该模型的命中率(R1 = cacheRead / totalInput)。`null` = 该模型的 api 不在
|
|
1843
|
+
* 缓存报告白名单内(供应商没有相应缓存 API),或本模型累计 totalInput 为 0。
|
|
1844
|
+
*/
|
|
1845
|
+
hitRatio: number | null;
|
|
1846
|
+
}
|
|
1847
|
+
interface CacheView {
|
|
1848
|
+
/** 最近一回合的命中率(`AgentSession.getLastCacheHitRatio()`);`null` = 无数据或供应商不支持。 */
|
|
1849
|
+
lastTurnHitRatio: number | null;
|
|
1850
|
+
/** 会话级加权命中率 = 全会话 cacheReadTokens / 全会话 totalInputTokens;`null` = 无可计算数据。 */
|
|
1851
|
+
sessionHitRatio: number | null;
|
|
1852
|
+
/** 会话累计缓存读取 token。 */
|
|
1853
|
+
totalCacheReadTokens: number;
|
|
1854
|
+
/** 会话累计缓存写入 token。 */
|
|
1855
|
+
totalCacheWriteTokens: number;
|
|
1856
|
+
/** 会话累计非缓存 input token。 */
|
|
1857
|
+
totalInputTokens: number;
|
|
1858
|
+
/** 估算的会话总成本(USD);无定价数据时为 undefined。 */
|
|
1859
|
+
totalCostUSD?: number;
|
|
1860
|
+
/** 按模型拆分(多模型会话时展示每个模型各自的命中率)。 */
|
|
1861
|
+
perModel: CacheModelRow[];
|
|
1862
|
+
}
|
|
1863
|
+
interface CachePaneState {
|
|
1864
|
+
view: CacheView | null;
|
|
1865
|
+
}
|
|
1866
|
+
interface CacheStore {
|
|
1867
|
+
store: Store<CachePaneState>;
|
|
1868
|
+
/** CLI 喂入最新缓存统计视图(`/cache-stats` 命令触发)。
|
|
1869
|
+
* RFC-256 收尾:面板可见性由 Router 栈单一真源派生(isInStack('/pane/cache')),
|
|
1870
|
+
* store 不再持 `open` 布尔——原 toggle() 已删除。 */
|
|
1871
|
+
setView(view: CacheView): void;
|
|
1872
|
+
}
|
|
1873
|
+
//#endregion
|
|
1874
|
+
//#region src/stores/proxy-store.d.ts
|
|
1875
|
+
/** 探测状态机:idle(未测过)→ probing(进行中)→ ok / failed。 */
|
|
1876
|
+
type ProxyProbeState = {
|
|
1877
|
+
status: 'idle';
|
|
1878
|
+
} | {
|
|
1879
|
+
status: 'probing';
|
|
1880
|
+
} | {
|
|
1881
|
+
status: 'ok';
|
|
1882
|
+
latencyMs: number;
|
|
1883
|
+
target: string;
|
|
1884
|
+
} | {
|
|
1885
|
+
status: 'failed';
|
|
1886
|
+
reason: string;
|
|
1887
|
+
blamesProxy: boolean;
|
|
1888
|
+
target: string;
|
|
1889
|
+
};
|
|
1890
|
+
interface ProxyPanelView {
|
|
1891
|
+
/** 代理地址(http:// 或 https://),未配置时为 undefined。 */
|
|
1892
|
+
url?: string;
|
|
1893
|
+
/** 代理是否已启用(false = 已配置但停用)。缺省=未配置时不显示。 */
|
|
1894
|
+
enabled?: boolean;
|
|
1895
|
+
/** 配置文件路径(展示用)。 */
|
|
1896
|
+
configPath: string;
|
|
1897
|
+
/**
|
|
1898
|
+
* 当前**进程内实际生效**的代理(`getDefaultProxy()`),与 `url`/`enabled` 表达的
|
|
1899
|
+
* **配置态**区分(RFC-288 D3)。二者一致是常态,面板据此保持静默;不一致才说明
|
|
1900
|
+
* "改了配置但尚未生效",需要显式告警——否则用户无从回答"我设了为什么没用"。
|
|
1901
|
+
*/
|
|
1902
|
+
effectiveUrl?: string;
|
|
1903
|
+
/**
|
|
1904
|
+
* 启动时从环境变量检测到的系统代理(RFC-288 D5)。此前 `interactive-setup.ts` 检测到
|
|
1905
|
+
* 后只弹一次 toast 就丢弃,面板完全不知情,用户环境里明明有可用地址却仍需手打。
|
|
1906
|
+
* **仅作建议值**:必须用户显式确认才落盘(沿用前身 RFC 规则 5,避免"代理突然生效
|
|
1907
|
+
* 但用户不知道")。
|
|
1908
|
+
*/
|
|
1909
|
+
detectedEnvProxy?: {
|
|
1910
|
+
value: string; /** 来源变量名(`HTTP_PROXY`/`HTTPS_PROXY`…)——用户需要知道它从哪来才敢采用。 */
|
|
1911
|
+
source: string;
|
|
1912
|
+
};
|
|
1913
|
+
/** 连通性探测状态(RFC-288 D4),由面板动作行触发、CLI 侧回推。 */
|
|
1914
|
+
probe?: ProxyProbeState;
|
|
1915
|
+
}
|
|
1916
|
+
interface ProxyStoreState {
|
|
1917
|
+
view: ProxyPanelView;
|
|
1918
|
+
}
|
|
1919
|
+
interface ProxyStore {
|
|
1920
|
+
store: Store<ProxyStoreState>;
|
|
1921
|
+
setView(view: ProxyPanelView): void;
|
|
1922
|
+
}
|
|
1923
|
+
//#endregion
|
|
1924
|
+
//#region src/overlays/Toast.d.ts
|
|
1925
|
+
interface ToastItem {
|
|
1926
|
+
id: number;
|
|
1927
|
+
title: string;
|
|
1928
|
+
content: string;
|
|
1929
|
+
}
|
|
1930
|
+
//#endregion
|
|
1931
|
+
//#region src/dialogs/RetryDialog.d.ts
|
|
1932
|
+
interface RetryDialogItem {
|
|
1933
|
+
attempt: number;
|
|
1934
|
+
max: number;
|
|
1935
|
+
delayMs: number;
|
|
1936
|
+
/** 共享可变引用——TUI 置位,agent 轮询检测后跳过剩余 sleep。 */
|
|
1937
|
+
accelerate: {
|
|
1938
|
+
skip: boolean;
|
|
1939
|
+
};
|
|
1940
|
+
/** 倒计时到期回调(清除渲染)。 */
|
|
1941
|
+
onExpired: () => void;
|
|
1942
|
+
/** 触发本次重试的错误原因(如 "socket hang up")——为空/undefined 时不渲染原因行。 */
|
|
1943
|
+
reason?: string;
|
|
1944
|
+
/**
|
|
1945
|
+
* 停止按钮 / Esc 回调(用户请求:重试倒计时浮层此前无法关闭、也无法真正终止
|
|
1946
|
+
* 底层重试循环——唯一出路是隐藏快捷键 Ctrl+C 且会额外弹二次确认框)。
|
|
1947
|
+
* undefined 时(如画廊静态演示无真实重试循环可停)Esc 退化为默认路由 goBack,
|
|
1948
|
+
* 不渲染 Stop 按钮语义之外的强行为——调用方(`interactive-agent-toasts.ts`)始终
|
|
1949
|
+
* 传入真实回调,直接中止当前 agent 回合(不二次确认,见 RFC-303 决策)。
|
|
1950
|
+
*/
|
|
1951
|
+
onStop?: () => void;
|
|
1952
|
+
}
|
|
1953
|
+
//#endregion
|
|
1954
|
+
//#region src/stores/notification-store.d.ts
|
|
1955
|
+
interface NotificationState {
|
|
1956
|
+
toast: ToastItem | null;
|
|
1957
|
+
retryCountdown: RetryDialogItem | null;
|
|
1958
|
+
/** RFC-147 M3:替代原 rateLimitCountdown 字段——统一错误重试卡片(覆盖硬额度+通用错误场景)。 */
|
|
1959
|
+
errorRetry: ErrorRetryItem | null;
|
|
1960
|
+
providerUsage: ProviderUsageBadgeItem | null;
|
|
1961
|
+
notifications: AppNotification[];
|
|
1962
|
+
/**
|
|
1963
|
+
* RFC-180 D7:turn 边界软停止已生效(AgentSession.pauseRequested 镜像,经
|
|
1964
|
+
* run.paused/run.resumed 事件由 cli 层 tui.setPaused() 下推)。状态栏据此渲染
|
|
1965
|
+
* 常驻"已暂停"提示;agentBusy() 判忙组合链(submit-routing.busyWithPause)据此
|
|
1966
|
+
* 挡住 drainQueue 自动出队。
|
|
1967
|
+
*/
|
|
1968
|
+
paused: boolean;
|
|
1969
|
+
/**
|
|
1970
|
+
* RFC-186 D7:暂停浮层数据。非 null 时 App.tsx 渲染 PauseDialog。
|
|
1971
|
+
* M3 的 interactive-events.ts 负责任意时刻写入本字段。
|
|
1972
|
+
*/
|
|
1973
|
+
pauseDialog: PauseDialogItem | null;
|
|
1974
|
+
/**
|
|
1975
|
+
* RFC-186 D7:暂停等待中的状态栏实时信息(工具计数 + 已等待秒数)。
|
|
1976
|
+
* 由 M3 的 interactive-events.ts 每秒推送;null = 无暂停等待态。
|
|
1977
|
+
*/
|
|
1978
|
+
pausePending: {
|
|
1979
|
+
elapsedSec: number;
|
|
1980
|
+
toolCount: number;
|
|
1981
|
+
} | null;
|
|
1982
|
+
/**
|
|
1983
|
+
* RFC-208:满意度脉冲调查浮层数据。非 null 时 App.tsx 渲染 PulseSurveyOverlay。
|
|
1984
|
+
* interactive-events.ts 的 prompt.end case 负责写入(触发判定命中时)。
|
|
1985
|
+
*/
|
|
1986
|
+
pulseSurvey: PulseSurveyItem | null;
|
|
1987
|
+
}
|
|
1988
|
+
interface NotificationStore {
|
|
1989
|
+
store: Store<NotificationState>;
|
|
1990
|
+
reset(): void;
|
|
1991
|
+
/**
|
|
1992
|
+
* 注入渲染触发器(RFC-333 M2-B4)。providerUsage 是 C-class(无 useAppState 消费方,
|
|
1993
|
+
* 经 TuiRoot snapshot prop + 手动 notify 渲染),故 action 必须保留 notify,不得裸删。
|
|
1994
|
+
*/
|
|
1995
|
+
setNotify(notify: () => void): void;
|
|
1996
|
+
/**
|
|
1997
|
+
* 注入副作用钩子(RFC-335 T335-07 前置 P0a)。同 taskStore.setEffects——残留
|
|
1998
|
+
* TuiHandle setter(setPaused/setPulseSurvey)是"字段 setter + 副作用"混合体,须
|
|
1999
|
+
* 注入 side-effect 闭包才能下沉为 store action 而不丢路由/出队行为。未注入时 no-op。
|
|
2000
|
+
*/
|
|
2001
|
+
setEffects(effects: NotificationStoreEffects): void;
|
|
2002
|
+
/** provider usage 徽标数据(cli 回推)。C-class:写后必须 notify 触发全树重渲染。 */
|
|
2003
|
+
setProviderUsage(item: ProviderUsageBadgeItem | null): void;
|
|
2004
|
+
/** pause pending 信息(cli 回推)。C-class:无 useAppState 消费方,写后必须 notify。 */
|
|
2005
|
+
setPausePending(info: NotificationState['pausePending']): void;
|
|
2006
|
+
/** paused 字段(RFC-335 P0a 自 TuiHandle.setPaused):字段 + paused=false 时 drainQueue + notify。 */
|
|
2007
|
+
setPaused(paused: boolean): void;
|
|
2008
|
+
/** 满意度调查浮层(RFC-335 P0a 自 TuiHandle.setPulseSurvey):字段 + overlay 路由 + notify。 */
|
|
2009
|
+
setPulseSurvey(item: NotificationState['pulseSurvey']): void;
|
|
2010
|
+
}
|
|
2011
|
+
/**
|
|
2012
|
+
* notificationStore 副作用接入口子。注入方(main.ts)闭包内取真 router / drainQueue —
|
|
2013
|
+
* —接口不暴露树外类型,与 taskStore 同款。
|
|
2014
|
+
*/
|
|
2015
|
+
interface NotificationStoreEffects {
|
|
2016
|
+
/** paused 由 true→false 时尝试出队(原 inline 的 drainQueue())。 */
|
|
2017
|
+
drainQueueOnResume?(): void;
|
|
2018
|
+
/** 满意度调查 overlay 开/关(router 副作用);true→开、false→关。 */
|
|
2019
|
+
syncPulseSurveyRoute?(open: boolean): void;
|
|
2020
|
+
}
|
|
2021
|
+
//#endregion
|
|
2022
|
+
//#region src/messages/plugin-renderer-registry.d.ts
|
|
2023
|
+
type PluginMessageRenderer = (message: unknown, columns: number) => string[];
|
|
2024
|
+
interface RegisteredRenderer {
|
|
2025
|
+
/** 全局唯一 id(`pluginId:rendererId`),用于日志与 unregister。 */
|
|
2026
|
+
id: string;
|
|
2027
|
+
matcher: {
|
|
2028
|
+
role?: string;
|
|
2029
|
+
toolName?: string;
|
|
2030
|
+
contentType?: string;
|
|
2031
|
+
};
|
|
2032
|
+
render: PluginMessageRenderer;
|
|
2033
|
+
}
|
|
2034
|
+
/** 幂等注册(RFC-131:委托到中央注册表,source='cli')。 */
|
|
2035
|
+
declare function registerPluginRenderers(next: readonly RegisteredRenderer[]): void;
|
|
2036
|
+
/** 清空全部注册(RFC-131:委托到中央注册表)。 */
|
|
2037
|
+
declare function clearPluginRenderers(): void;
|
|
2038
|
+
//#endregion
|
|
2039
|
+
//#region src/messages/plugin-file-viewer-registry.d.ts
|
|
2040
|
+
type PluginFileViewerRenderFn = (content: string, path: string, columns: number) => {
|
|
2041
|
+
lines: string[];
|
|
2042
|
+
wrapMode?: 'pre-wrap' | 'truncate';
|
|
2043
|
+
} | null;
|
|
2044
|
+
interface RegisteredFileViewer {
|
|
2045
|
+
/** 全局唯一 id(`pluginId:entryId`)。 */
|
|
2046
|
+
id: string;
|
|
2047
|
+
pluginId: string;
|
|
2048
|
+
label: string;
|
|
2049
|
+
matcher: {
|
|
2050
|
+
extensions?: string[];
|
|
2051
|
+
filenames?: string[];
|
|
2052
|
+
glob?: string[];
|
|
2053
|
+
};
|
|
2054
|
+
render: PluginFileViewerRenderFn;
|
|
2055
|
+
order?: number;
|
|
2056
|
+
}
|
|
2057
|
+
//#endregion
|
|
2058
|
+
//#region src/components/Button.d.ts
|
|
2059
|
+
type ButtonVariant = 'solid' | 'outline' | 'ghost';
|
|
2060
|
+
type ButtonColor = 'accent' | 'amber' | 'red' | 'green' | 'gray';
|
|
2061
|
+
interface ButtonProps {
|
|
2062
|
+
label: string;
|
|
2063
|
+
variant?: ButtonVariant;
|
|
2064
|
+
/** 语义色彩(ghost 变体下忽略,始终用 accent 蓝)。默认 accent。 */
|
|
2065
|
+
color?: ButtonColor;
|
|
2066
|
+
/** @deprecated 使用 tabIndex 替代。向后兼容:传入时覆盖 useTabable 结果。 */
|
|
2067
|
+
focused?: boolean;
|
|
2068
|
+
disabled?: boolean;
|
|
2069
|
+
/** 强制方括号格式(outline 默认 true;solid/ghost 默认 false)。
|
|
2070
|
+
* solid+brackets=true 时 unfocused 用 inactive 灰色(而非 color 色)。 */
|
|
2071
|
+
brackets?: boolean;
|
|
2072
|
+
/** tabIndex for focus traversal(默认 -1 = 不参与;0+ = 参与)。 */
|
|
2073
|
+
tabIndex?: number;
|
|
2074
|
+
/** Enter 触发的 action(tabIndex ≥ 0 时通过 useTabable onAction 注册)。 */
|
|
2075
|
+
onAction?: () => void;
|
|
2076
|
+
}
|
|
2077
|
+
declare function Button({
|
|
2078
|
+
label,
|
|
2079
|
+
variant,
|
|
2080
|
+
color,
|
|
2081
|
+
focused: focusedProp,
|
|
2082
|
+
disabled,
|
|
2083
|
+
brackets,
|
|
2084
|
+
tabIndex,
|
|
2085
|
+
onAction
|
|
2086
|
+
}: ButtonProps): React.ReactElement;
|
|
2087
|
+
//#endregion
|
|
2088
|
+
//#region src/panes/PluginPane.d.ts
|
|
2089
|
+
/**
|
|
2090
|
+
* PluginPane.tsx — 插件面板组件的动态加载 + 错误隔离(RFC-081)。
|
|
2091
|
+
*
|
|
2092
|
+
* `PluginPane`:只加载并渲染插件组件(无外框/标题),嵌进独立的 `PluginDialog`
|
|
2093
|
+
* (RFC-167:插件面板全屏 dialog,取代此前内嵌 `ExtensionDetailDialog` body 槽位的方案)。
|
|
2094
|
+
* `PanelErrorBoundary` 隔离坏插件 render 抛错为一行降级提示。dynamic import 编译后的 ESM
|
|
2095
|
+
* 模块(而非 React.lazy + Suspense,避 Ink 对 Suspense 支持不确定)。
|
|
2096
|
+
*
|
|
2097
|
+
* 崩溃兜底(RFC-166 D9 P0 修复思路延续,RFC-167 精简为单向信号):面板一旦在**加载期**
|
|
2098
|
+
* (`import()` 失败)、**渲染期**(`PanelErrorBoundary` 捕获)或**异步期**
|
|
2099
|
+
* (`usePanelAsyncErrorGuard` 捕获)三条路径中的任意一条崩溃,面板组件本身会立即卸载/
|
|
2100
|
+
* 停渲染——不会再有任何面板代码调用 `requestClose()`,`PluginDialog` 若不感知这次
|
|
2101
|
+
* 崩溃,会永久停留在"面板已死、无人监听键盘"的死区(用户只能强杀 TUI 进程)。三条错误
|
|
2102
|
+
* 路径命中即调用 `panelFocusBridge.reportCrashed()`,`PluginDialog` 订阅后激活自己
|
|
2103
|
+
* 的兜底 `useInput`(用户至少能 Esc 关闭独立面板 dialog,退回详情页)。
|
|
2104
|
+
*/
|
|
2105
|
+
interface PanelInfo {
|
|
2106
|
+
title: string;
|
|
2107
|
+
modulePath: string;
|
|
2108
|
+
exportName: string;
|
|
2109
|
+
/**
|
|
2110
|
+
* RFC-165 M2 T7:面板所属插件 id——`usePanelBackend()` 据此定位对应的 backend MCP
|
|
2111
|
+
* server 连接。可选(历史构造点可能未透传,见 `PluginPane` 挂载前注入逻辑的
|
|
2112
|
+
* fail-soft 处理:缺失时 `usePanelBackend()` 恒返回 `status:'disabled'`,不崩溃面板)。
|
|
2113
|
+
*/
|
|
2114
|
+
pluginId?: string;
|
|
2115
|
+
}
|
|
2116
|
+
//#endregion
|
|
2117
|
+
//#region src/dialogs/ExtensionDetailDialog.d.ts
|
|
2118
|
+
/**
|
|
2119
|
+
* ExtensionDetailDialog.tsx — `/extension` 扩展详情统一 dialog(取代 /panels 独立面板视图)。
|
|
2120
|
+
*
|
|
2121
|
+
* 结构:标题 + 元信息 → 控制按钮行(启用/禁用 · 重载 · 重连 · 信任/不信任 · 打开面板,由调用方
|
|
2122
|
+
* 按类别/状态组装)→ body(`dataListEntries`/`info` 回退展示)。
|
|
2123
|
+
*
|
|
2124
|
+
* RFC-167(架构重设计,取代 RFC-166 D9 键盘归属桥):插件面板不再内嵌本 dialog 的 body 槽位
|
|
2125
|
+
* ——此前面板一旦需要真实交互(Tab 切子标签/编辑字段/登录流程),必须与本 dialog 互斥仲裁
|
|
2126
|
+
* 键盘归属(`panelFocusBridge`),导致宿主控制按钮在面板接管期间完全不可达(真实用户反馈:
|
|
2127
|
+
* "看得见按钮按不动"),且面板内部 Tab 语义与"跨区域焦点移动"直觉冲突。现在插件面板改为
|
|
2128
|
+
* 独立顶层 dialog(`PluginDialog`,见该文件),本组件对有 `panelInfo` 的详情追加一个
|
|
2129
|
+
* "打开面板 →"控制按钮(`value: 'open-panel'`),点击后经 `req.onOpenPanel()` 回调打开独立
|
|
2130
|
+
* dialog——两层模态各自拥有 100% 键盘,不再需要互斥仲裁。本组件因此恢复最初设计意图
|
|
2131
|
+
* (首个提交注释:"body 为被动展示,不夺焦点"):← → 切按钮、Enter 执行、Esc 关闭,全程统一
|
|
2132
|
+
* 行为,不再有"键位由面板接管"这种运行时切换的复杂度。
|
|
2133
|
+
*
|
|
2134
|
+
* "extension 默认面板"(无自定义 panel 时的回退展示)走 `DataList`(`dataListEntries`)渲染
|
|
2135
|
+
* ——分组标题 + label 弱化/value 正常前景双色,与 `/about` 视觉统一。`info` 仍保留作为更简单
|
|
2136
|
+
* 场景的向后兼容路径(`dataListEntries` 提供时优先)。
|
|
2137
|
+
*
|
|
2138
|
+
* 正文查看子视图(Skill/Agent 详情页"查看正文"按钮):`req.fullText` 提供时,`onAction`
|
|
2139
|
+
* 命中约定 value(`'view-full-text'`)触发本组件内部子状态切到 `FileContentViewer`(对齐
|
|
2140
|
+
* `MemoryDialog`/`PasteConfirmDialog` 的"列表/详情 → 全文查看"三段式先例),Esc 退回本
|
|
2141
|
+
* dialog(不触发 `onClose`——只读浏览不代表用户想关闭详情页)。正文可能很长(SKILL.md 正文/
|
|
2142
|
+
* agent systemPromptTemplate),不适合塞进 DataList 行内,故复用滚动查看器而非展开渲染。
|
|
2143
|
+
*/
|
|
2144
|
+
interface ExtensionDetailAction {
|
|
2145
|
+
label: string;
|
|
2146
|
+
value: string;
|
|
2147
|
+
color?: ButtonColor;
|
|
2148
|
+
}
|
|
2149
|
+
/** RFC-153 D4:插件健康度摘要(PluginHealthTracker.query() 的投影,全零不展示该行)。 */
|
|
2150
|
+
interface ExtensionHealthSummary {
|
|
2151
|
+
hookTimeouts: number;
|
|
2152
|
+
toolTimeouts: number;
|
|
2153
|
+
lastError?: {
|
|
2154
|
+
message: string;
|
|
2155
|
+
timestamp: number;
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
/** RFC-153 D4:单条插件日志(readPluginLogTail() 的投影)。 */
|
|
2159
|
+
interface ExtensionLogEntry {
|
|
2160
|
+
ts: number;
|
|
2161
|
+
level: string;
|
|
2162
|
+
msg: string;
|
|
2163
|
+
}
|
|
2164
|
+
interface ExtensionDetailRequest {
|
|
2165
|
+
title: string;
|
|
2166
|
+
/**
|
|
2167
|
+
* 元信息行前缀,如 "plugin · user"(不含启用态词——启用态走 `metaStatus` 独立着色渲染,
|
|
2168
|
+
* 真实用户反馈修复:灰底一整行文本无法区分"启用"应为绿色、"禁用"应为红色的语义强调)。
|
|
2169
|
+
*/
|
|
2170
|
+
meta?: string;
|
|
2171
|
+
/** 启用态:渲染在 `meta` 之后,`enabled` 为 true 时用 colors.success(绿),false 用 colors.error(红)。 */
|
|
2172
|
+
metaStatus?: {
|
|
2173
|
+
label: string;
|
|
2174
|
+
enabled: boolean;
|
|
2175
|
+
};
|
|
2176
|
+
/** `metaStatus` 之后的尾随文本(如 plugin 详情页的信任状态),仍走默认灰色。 */
|
|
2177
|
+
metaSuffix?: string;
|
|
2178
|
+
/** 控制按钮(启用/禁用 · 重载 · 重连 · 信任/不信任 …,不含"打开面板"——由 `panelInfo` 派生)。 */
|
|
2179
|
+
actions: ExtensionDetailAction[];
|
|
2180
|
+
/**
|
|
2181
|
+
* 该插件贡献的面板(RFC-167:不再内嵌渲染,仅用于判断是否展示"打开面板 →"按钮)。
|
|
2182
|
+
* 提供时本组件在 `actions` 末尾追加该按钮,点击触发 `onOpenPanel()`。
|
|
2183
|
+
*/
|
|
2184
|
+
panelInfo?: PanelInfo;
|
|
2185
|
+
/** 点击"打开面板 →"按钮时调用(宿主经 `openModal('pluginPanel', ...)` 打开独立 dialog)。 */
|
|
2186
|
+
onOpenPanel?: () => void;
|
|
2187
|
+
/**
|
|
2188
|
+
* 无 panel 时的回退展示——分组键值信息(经 `DataList` 渲染,`/about` 同款双色排版)。
|
|
2189
|
+
* 提供时优先于 `info`(RFC-166 D10 后续:"extension 默认面板"统一走 DataList)。
|
|
2190
|
+
*/
|
|
2191
|
+
dataListEntries?: DataListEntry[];
|
|
2192
|
+
/** 无 panel、无 `dataListEntries` 时的回退信息行(如 MCP 的 command/url,纯文本兼容路径)。 */
|
|
2193
|
+
info?: string[];
|
|
2194
|
+
/** RFC-153 D4:健康度摘要(挂起/超时计数);undefined 或全零时不展示该行。 */
|
|
2195
|
+
healthStats?: ExtensionHealthSummary;
|
|
2196
|
+
/** RFC-153 D4:最近日志(最多 20 条,已按时间正序排列);undefined/空数组时展示"暂无日志"占位。 */
|
|
2197
|
+
logEntries?: ExtensionLogEntry[];
|
|
2198
|
+
/** RFC-153 D4:手动刷新键(r,对齐 /perf 面板同款绑定)——重新查询健康度+日志并回填。 */
|
|
2199
|
+
onRefresh?: () => void;
|
|
2200
|
+
/**
|
|
2201
|
+
* "查看正文"子视图内容(可选,Skill/Agent 详情页用)——提供时 `actions` 里应包含一个
|
|
2202
|
+
* `value: 'view-full-text'` 的按钮,命中后本组件内部切到 `FileContentViewer` 展示这段
|
|
2203
|
+
* 长文本(SKILL.md 正文 / agent systemPromptTemplate),Esc 退回本 dialog。未提供时
|
|
2204
|
+
* `'view-full-text'` action 不会有任何特殊处理(调用方也不应该注册该 value 的按钮)。
|
|
2205
|
+
*
|
|
2206
|
+
* RFC-187 M0:正文经 `resolveFileContentViews` 统一调度渲染(此前是裸文本 bug)。两类
|
|
2207
|
+
* 正文(SKILL.md 正文 / agent systemPromptTemplate)均为 markdown 风格散文,`kind` 缺省
|
|
2208
|
+
* 为 `'markdown'` 时以合成路径 `${title}.md` 送入调度函数,获得 rendered/raw 双候选;
|
|
2209
|
+
* 未来若有非 markdown 正文来源,可扩展 `kind: 'plain'` 跳过 markdown 候选。
|
|
2210
|
+
*/
|
|
2211
|
+
fullText?: {
|
|
2212
|
+
title: string;
|
|
2213
|
+
content: string;
|
|
2214
|
+
kind?: 'markdown' | 'plain';
|
|
2215
|
+
};
|
|
2216
|
+
/** 执行某控制按钮(value)。 */
|
|
2217
|
+
onAction: (value: string) => void;
|
|
2218
|
+
onClose: () => void;
|
|
2219
|
+
}
|
|
2220
|
+
//#endregion
|
|
2221
|
+
//#region src/dialogs/FileViewerDialog.d.ts
|
|
2222
|
+
interface FileViewerRequest {
|
|
2223
|
+
/** 展示用路径(可以是相对路径,仅用于 header 展示与语言判定,不做文件系统操作)。 */
|
|
2224
|
+
path: string;
|
|
2225
|
+
/** 文件原始内容(由 `handleOpen` 读取,已过二进制探测——见 RFC-189 R5)。 */
|
|
2226
|
+
content: string;
|
|
2227
|
+
/**
|
|
2228
|
+
* 调用方是否已在读取阶段用 `readFileCapped` 截断内容(RFC-189 追加修复)——
|
|
2229
|
+
* true 时强制走大文件降级候选,不依赖 `content.length` 判断(截断后长度恒不超阈值,
|
|
2230
|
+
* 单凭长度判断会误判为"文件不大"而漏显示"文件过大"提示)。
|
|
2231
|
+
*/
|
|
2232
|
+
preTruncated?: boolean;
|
|
2233
|
+
onDismiss: () => void;
|
|
2234
|
+
}
|
|
2235
|
+
//#endregion
|
|
2236
|
+
//#region src/dialogs/HelpViewerDialog.d.ts
|
|
2237
|
+
interface HelpViewerRequest {
|
|
2238
|
+
/** 标题(上边框下方展示,如 "Help" / "Commands")。 */
|
|
2239
|
+
title: string;
|
|
2240
|
+
/** 已组装好的正文行(分组标题 + 对齐后的命令行,见 `buildHelpLines`/`handleHelp`)。 */
|
|
2241
|
+
lines: string[];
|
|
2242
|
+
onDismiss: () => void;
|
|
2243
|
+
}
|
|
2244
|
+
//#endregion
|
|
2245
|
+
//#region src/dialogs/ExtensionsListDialog.d.ts
|
|
2246
|
+
interface ExtensionListEntry {
|
|
2247
|
+
category: string;
|
|
2248
|
+
id: string;
|
|
2249
|
+
name: string;
|
|
2250
|
+
enabled: boolean;
|
|
2251
|
+
description?: string;
|
|
2252
|
+
/** 'live' | 'next-turn' 等——非 'live' 时在 detail 追加提示。 */
|
|
2253
|
+
applies?: string;
|
|
2254
|
+
}
|
|
2255
|
+
/** 全局菜单贡献条目(RFC-105 D5/M105-4)——独立分组,追加在内置列表之后。 */
|
|
2256
|
+
interface ExtensionMenuContribution {
|
|
2257
|
+
id: string;
|
|
2258
|
+
title: string;
|
|
2259
|
+
}
|
|
2260
|
+
interface ExtensionsListRequest {
|
|
2261
|
+
entries: ExtensionListEntry[];
|
|
2262
|
+
menuContributions?: ExtensionMenuContribution[];
|
|
2263
|
+
/**
|
|
2264
|
+
* 上次选中的条目 value(`category:id` / `contrib:id`)——进入详情后 Esc 退回列表时,
|
|
2265
|
+
* 列表 Select.Root 用 `defaultValue` 恢复游标到该条目(不重置为第一条)。
|
|
2266
|
+
*/
|
|
2267
|
+
lastSelectedValue?: string;
|
|
2268
|
+
onSelect: (value: string) => void;
|
|
2269
|
+
onCancel?: () => void;
|
|
2270
|
+
}
|
|
2271
|
+
//#endregion
|
|
2272
|
+
//#region src/dialogs/PluginDialog.d.ts
|
|
2273
|
+
/**
|
|
2274
|
+
* PluginDialog.tsx — 插件面板独立全屏 dialog(RFC-167)。
|
|
2275
|
+
*
|
|
2276
|
+
* 背景:插件面板此前内嵌在 `ExtensionDetailDialog` 的 body 槽位,与宿主详情页的控制按钮
|
|
2277
|
+
* (启用/禁用·重载·信任)共享同一屏——面板一旦需要真实交互(Tab 切子标签、编辑字段、
|
|
2278
|
+
* 登录流程),键盘归属就必须在宿主/面板之间做互斥仲裁(RFC-166 D9 `panel-focus-bridge.ts`),
|
|
2279
|
+
* 导致两个真实可用性问题:① 宿主按钮在面板接管键盘期间完全不可达(用户反馈"看得见按不动");
|
|
2280
|
+
* ② Tab 键在"面板内部切子标签"与"跨区域移动焦点"两种语义间冲突,无法两全。
|
|
2281
|
+
*
|
|
2282
|
+
* 本方案根治:插件面板从宿主详情页拆出,改为独立的顶层 hard modal(同 `extensionDetail`/
|
|
2283
|
+
* `extensionsList` 走 `FOCUS_REGISTRY` Band A,任意时刻与其他模态互斥)。面板挂载即拥有
|
|
2284
|
+
* 100% 键盘(不再需要与宿主协商),`ExtensionDetailDialog` 一侧只渲染"打开面板 →"入口按钮,
|
|
2285
|
+
* 点击后经 `openModal('pluginPanel')` 打开本 dialog;Esc 关闭本 dialog、退回详情页(不是
|
|
2286
|
+
* "关闭详情页"——两层模态各自独立,符合用户对"进一层、退一层"的直觉)。
|
|
2287
|
+
*
|
|
2288
|
+
* 键盘归属桥(`panel-focus-bridge.ts`)随本改造整体退休:面板不再需要 claim/release,
|
|
2289
|
+
* `usePanelFocusClaimed()`/`claimPanelFocus()`/`releasePanelFocus()` 三个 banner 注入
|
|
2290
|
+
* 标识符改为恒定桩实现(见 `panel-compiler.ts`),面板产物无需改动即可在新架构下正常工作
|
|
2291
|
+
* (`usePanelFocusClaimed()` 恒返回 `true` — 面板挂载即天然独占键盘,无需再"声明接管")。
|
|
2292
|
+
* `requestPanelClose()` 的语义随之改变:从"把控制权交还宿主 dialog"变为"关闭本 dialog",
|
|
2293
|
+
* 两种场景下面板侧代码调用方式完全一致(`requestPanelClose()`),无需感知底层机制变化。
|
|
2294
|
+
*/
|
|
2295
|
+
interface PluginPanelRequest {
|
|
2296
|
+
panelInfo: PanelInfo;
|
|
2297
|
+
onClose: () => void;
|
|
2298
|
+
}
|
|
2299
|
+
//#endregion
|
|
2300
|
+
//#region src/dialogs/InfoDialog.d.ts
|
|
2301
|
+
interface InfoDialogAction {
|
|
2302
|
+
/**
|
|
2303
|
+
* 'retry':重试原请求;'login':唤起 /login 面板(认证失效场景,重试必然复现同一失败);
|
|
2304
|
+
* 'extension':唤起 /extension 面板(插件高危能力待授权场景——用户需要的是去信任插件
|
|
2305
|
+
* 授予能力,而非重新登录/重试,见 /model refresh 结果 dialog 的"待授权"分支)。
|
|
2306
|
+
*/
|
|
2307
|
+
kind: 'retry' | 'login' | 'extension';
|
|
2308
|
+
run: () => void;
|
|
2309
|
+
}
|
|
2310
|
+
/**
|
|
2311
|
+
* 单行语义色调(RFC-126 附带修复:/model refresh 结果三态视觉分离):
|
|
2312
|
+
* 'success' = 正向反馈(绿,如 provider 已可用);'muted' = 中性/可忽略状态(灰弱化,
|
|
2313
|
+
* 如未认证——不是错误,无需处理);'warning' = 需要用户动作(琥珀,如能力待授权);
|
|
2314
|
+
* 未指定 = 默认前景色(既有行为,兼容全部现有调用点)。
|
|
2315
|
+
*/
|
|
2316
|
+
type InfoLineTone = 'success' | 'muted' | 'warning';
|
|
2317
|
+
interface InfoDialogProps {
|
|
2318
|
+
/** 标题行(上边框下方第一行,blue bold)。 */
|
|
2319
|
+
title: string;
|
|
2320
|
+
/** 正文行列表。`dataListEntries` 提供时忽略(见下)。 */
|
|
2321
|
+
lines: string[];
|
|
2322
|
+
/**
|
|
2323
|
+
* 按行索引指定色调(可选,稀疏映射——只需给需要着色的行索引赋值)。
|
|
2324
|
+
* 不提供时全部行走默认前景色,与既有 ~12 处 openInfo 调用点零行为变化。仅在 `lines`
|
|
2325
|
+
* 路径生效(`dataListEntries` 路径下由 `DataList` 自行控制着色)。
|
|
2326
|
+
*/
|
|
2327
|
+
lineTones?: Record<number, InfoLineTone>;
|
|
2328
|
+
onDismiss: () => void;
|
|
2329
|
+
/** 底部单个可操作按钮(非空时渲染,Enter 触发)。取代原 onRetry——语义由 kind 决定文案/颜色。 */
|
|
2330
|
+
action?: InfoDialogAction;
|
|
2331
|
+
/**
|
|
2332
|
+
* 分组键值正文(可选)——供需要「分组标题 + 行内 label/value 双色」的场景(如 `/about`)
|
|
2333
|
+
* 替代 `lines` 纯文本渲染,经 `DataList` 渲染。提供时优先于 `lines`(`lines` 仍需传
|
|
2334
|
+
* 空数组占位,类型上不做互斥以保持向后兼容——~12 处既有 `lines` 调用点零改动)。
|
|
2335
|
+
* 用纯数据(非 `ReactNode`)传递,避免 `@x-otto/cli` 引入 `react` 依赖。
|
|
2336
|
+
*/
|
|
2337
|
+
dataListEntries?: DataListEntry[];
|
|
2338
|
+
}
|
|
2339
|
+
declare function InfoDialog({
|
|
2340
|
+
title,
|
|
2341
|
+
lines,
|
|
2342
|
+
lineTones,
|
|
2343
|
+
onDismiss,
|
|
2344
|
+
action,
|
|
2345
|
+
dataListEntries
|
|
2346
|
+
}: InfoDialogProps): React.ReactElement;
|
|
2347
|
+
//#endregion
|
|
2348
|
+
//#region src/dialogs/MemoryDialog.d.ts
|
|
2349
|
+
type MemoryEntrySource = 'project' | 'user';
|
|
2350
|
+
interface MemoryEntry {
|
|
2351
|
+
name: string;
|
|
2352
|
+
slug: string;
|
|
2353
|
+
description: string;
|
|
2354
|
+
source: MemoryEntrySource;
|
|
2355
|
+
}
|
|
2356
|
+
interface MemoryDialogProps {
|
|
2357
|
+
/** 项目记忆索引文本(.otto/memory)。空串 = 无条目。 */
|
|
2358
|
+
projectIndex: string;
|
|
2359
|
+
/** 用户记忆索引文本(~/.otto/memory)。空串 = 无条目。 */
|
|
2360
|
+
userIndex: string;
|
|
2361
|
+
/** 查看选中条目全文(异步);返回 null 表示未找到/读取失败。 */
|
|
2362
|
+
onViewEntry: (entry: MemoryEntry) => Promise<string | null>;
|
|
2363
|
+
/** 确认删除选中条目(异步)。 */
|
|
2364
|
+
onForget: (entry: MemoryEntry) => Promise<void>;
|
|
2365
|
+
onDismiss: () => void;
|
|
2366
|
+
/** 终端总行数(RFC-301:列表窗口 + DetailView 内 FileContentViewer 共用)。 */
|
|
2367
|
+
rows?: number;
|
|
2368
|
+
/** 终端总列宽(DetailView 内 FileContentViewer 需要,默认 80)。 */
|
|
2369
|
+
columns?: number;
|
|
2370
|
+
}
|
|
2371
|
+
declare function MemoryDialog({
|
|
2372
|
+
projectIndex,
|
|
2373
|
+
userIndex,
|
|
2374
|
+
onViewEntry,
|
|
2375
|
+
onForget,
|
|
2376
|
+
onDismiss,
|
|
2377
|
+
rows,
|
|
2378
|
+
columns
|
|
2379
|
+
}: MemoryDialogProps): React.ReactElement;
|
|
2380
|
+
//#endregion
|
|
2381
|
+
//#region src/messages/notify-scheduler.d.ts
|
|
2382
|
+
/**
|
|
2383
|
+
* notify-scheduler.ts — RFC-038 P1:notify 入口合帧。
|
|
2384
|
+
*
|
|
2385
|
+
* 区别于 stream-coalesce(折叠「数据值」apply(v)),本调度器折叠「React 触发」——
|
|
2386
|
+
* 即无参的 `listener()`(= startTui 的 setTick → 全树 reconcile)。
|
|
2387
|
+
*
|
|
2388
|
+
* 根因(RFC-038 §1):现状 `notify()` 每个流式 token 都立即触发全树 reconcile,与用户
|
|
2389
|
+
* 输入争抢 React 渲染管线;Ink 只在输出末端 throttle 丢帧,被丢帧的 reconcile+yoga 已白做。
|
|
2390
|
+
* 采用请求入口合帧的调度模型:合并发生在「请求入口」,被合并的请求
|
|
2391
|
+
* 零成本(reconcile 根本没发生)。
|
|
2392
|
+
*
|
|
2393
|
+
* 两条路径(RFC-038 §5.1 · R1/R2):
|
|
2394
|
+
* - `coalesced()`:流式触发走此路。窗口内多次调用只触发一次 `listener`(窗口末),消灭无效
|
|
2395
|
+
* reconcile。无 leading edge——流式预览容忍 1 帧延迟;即时反馈由 `immediate` 路径负责。
|
|
2396
|
+
* - `immediate()`:用户交互(输入/模态/resize)走此路,立即触发 `listener`,零延迟(G2)。
|
|
2397
|
+
* 并冲掉任何挂起的合帧 timer,避免随后多余触发。
|
|
2398
|
+
* - `flush()`:finalize(块/回合结束/stop)立即触发挂起的 coalesced,禁丢尾段(R2)。
|
|
2399
|
+
* - `cancel()`:unmount 时丢弃挂起触发。
|
|
2400
|
+
*
|
|
2401
|
+
* `intervalMs` 必须与 stream-coalesce / Ink stdout throttle 对齐(`coalesceIntervalForFps(maxFps)`),
|
|
2402
|
+
* 三者错位会让多余触发与输入争管线(RFC-019 已坐实,R6)。
|
|
2403
|
+
*/
|
|
2404
|
+
interface NotifyStats {
|
|
2405
|
+
/** coalesced() 被调用次数(含被合并跳过的) */
|
|
2406
|
+
coalescedCalls: number;
|
|
2407
|
+
/** listener 实际被触发次数(从 coalesced 路径) */
|
|
2408
|
+
coalescedFires: number;
|
|
2409
|
+
/** immediate() 被调用次数 */
|
|
2410
|
+
immediateCalls: number;
|
|
2411
|
+
/** flush() 实际触发 listener 的次数 */
|
|
2412
|
+
flushFires: number;
|
|
2413
|
+
}
|
|
2414
|
+
interface NotifyScheduler {
|
|
2415
|
+
/** 流式路径:入口合并,窗口内多次只触发一次 listener(窗口末)。 */
|
|
2416
|
+
coalesced(): void;
|
|
2417
|
+
/** 交互路径:立即触发 listener,并冲掉挂起的合帧 timer。 */
|
|
2418
|
+
immediate(): void;
|
|
2419
|
+
/** finalize:立即触发挂起的 coalesced(若有),禁丢尾段。 */
|
|
2420
|
+
flush(): void;
|
|
2421
|
+
/** unmount:丢弃挂起触发。 */
|
|
2422
|
+
cancel(): void;
|
|
2423
|
+
/** 获取统计(P3-01 可观测)。 */
|
|
2424
|
+
getStats(): NotifyStats;
|
|
2425
|
+
}
|
|
2426
|
+
interface NotifySchedulerOptions {
|
|
2427
|
+
/** 实际触发 React 重渲的回调(= startTui 的 state.listener,无参)。 */
|
|
2428
|
+
listener: () => void;
|
|
2429
|
+
/** 合帧窗口(ms),须与 stream-coalesce / Ink throttle 对齐。 */
|
|
2430
|
+
intervalMs: number;
|
|
2431
|
+
}
|
|
2432
|
+
declare function makeNotifyScheduler(opts: NotifySchedulerOptions): NotifyScheduler;
|
|
2433
|
+
//#endregion
|
|
2434
|
+
//#region src/messages/a2ui-renderer.d.ts
|
|
2435
|
+
/**
|
|
2436
|
+
* 提取自 a2ui content block 的 Button 交互元数据(M-N3)。
|
|
2437
|
+
* 由调用方(startTui/App)用于注册快捷键路由,实现无需手动输入 /a2ui-action 的数字键触发。
|
|
2438
|
+
*/
|
|
2439
|
+
interface A2uiButtonInfo {
|
|
2440
|
+
/** 快捷键("1"-"9",按渲染顺序自动分配)。 */
|
|
2441
|
+
key: string;
|
|
2442
|
+
/** 按钮显示标签。 */
|
|
2443
|
+
label: string;
|
|
2444
|
+
/** A2UI 组件 id。 */
|
|
2445
|
+
componentId: string;
|
|
2446
|
+
/** 声明的 action(如 "click"/"submit")。 */
|
|
2447
|
+
action: string;
|
|
2448
|
+
/** 可选的附加 payload(当前 Button 组件不支持,预留扩展)。 */
|
|
2449
|
+
payload?: Record<string, unknown>;
|
|
2450
|
+
}
|
|
2451
|
+
//#endregion
|
|
2452
|
+
//#region src/dialogs/select.d.ts
|
|
2453
|
+
/** color 仅 layout='buttons' 模式生效:调用方为每个按钮指定语义色(缺省按位置回退)。 */
|
|
2454
|
+
interface SelectOption {
|
|
2455
|
+
label: string;
|
|
2456
|
+
value: string;
|
|
2457
|
+
disabled?: boolean;
|
|
2458
|
+
hotkey?: number;
|
|
2459
|
+
group?: string;
|
|
2460
|
+
detail?: string;
|
|
2461
|
+
color?: ButtonColor;
|
|
2462
|
+
/** 条目行前导空白(`Select.Item` 的 `indent` prop 透传,默认一个空格)。 */
|
|
2463
|
+
indent?: string;
|
|
2464
|
+
/**
|
|
2465
|
+
* 序号标记(`Select.Item` 的 `marker` prop 透传):
|
|
2466
|
+
* - `'number'`:渲染该项在列表中的序数(1-based,跨分组连续计数)
|
|
2467
|
+
* - `'-'` / `'·'`:渲染固定项目符
|
|
2468
|
+
* 不传 = 不渲染任何标记(默认现状)。
|
|
2469
|
+
*/
|
|
2470
|
+
marker?: 'number' | '-' | '·';
|
|
2471
|
+
/** `marker='number'` 时使用的序数(compileOptions 自动计算,1-based)。 */
|
|
2472
|
+
ordinal?: number;
|
|
2473
|
+
/**
|
|
2474
|
+
* 行内尾随文案(`Select.Item` 的 `trailingLabel` prop 透传):渲染在条目同一行右侧
|
|
2475
|
+
* (非另起一行的 `detail`),用于 Welcome 扩展列表这类"名称 + 状态"同行双栏布局。
|
|
2476
|
+
*/
|
|
2477
|
+
trailingLabel?: string;
|
|
2478
|
+
/** `trailingLabel` 的颜色(默认 THEME.inactive)。 */
|
|
2479
|
+
trailingColor?: string;
|
|
2480
|
+
/**
|
|
2481
|
+
* label 颜色覆盖(独立于 `disabled`——`disabled` 会额外追加 " (disabled)" 后缀文案,
|
|
2482
|
+
* 不适合"仅需弱化配色、不需要追加文案"的场景,如 Welcome 未启用扩展行)。
|
|
2483
|
+
*
|
|
2484
|
+
* 缺省 = `colors.inactive`(未选中项统一灰,与选中态的品牌紫拉开对比)。
|
|
2485
|
+
*/
|
|
2486
|
+
labelColor?: string;
|
|
2487
|
+
/**
|
|
2488
|
+
* 模糊搜索用纯语义文本(RFC-125 review 修复):`label` 常含渲染态装饰(当前项标记 `●`/
|
|
2489
|
+
* 空格 padding/上下文窗口后缀等),直接对其模糊评分会因短 query 命中装饰字符产生假阳性
|
|
2490
|
+
* (如 "dsk" 因 "200k" 的 k 误中不相关模型)。提供 `searchText` 时 searchable 模式改为
|
|
2491
|
+
* 对它评分(缺省回退 `label`,向后兼容不提供该字段的调用方)。
|
|
2492
|
+
*/
|
|
2493
|
+
searchText?: string;
|
|
2494
|
+
}
|
|
2495
|
+
interface SelectOptions {
|
|
2496
|
+
maxVisible?: number;
|
|
2497
|
+
onBoundary?: (dir: 'top' | 'bottom') => void;
|
|
2498
|
+
}
|
|
2499
|
+
interface SelectState {
|
|
2500
|
+
readonly selectedIndex: number;
|
|
2501
|
+
readonly scrollOffset: number;
|
|
2502
|
+
getVisibleOptions(): SelectOption[];
|
|
2503
|
+
getOptionAt(index: number): SelectOption | undefined;
|
|
2504
|
+
hasMoreAbove(): boolean;
|
|
2505
|
+
hasMoreBelow(): boolean;
|
|
2506
|
+
getSelected(): SelectOption | null;
|
|
2507
|
+
moveUp(): void;
|
|
2508
|
+
moveDown(): void;
|
|
2509
|
+
accept(): SelectOption | null;
|
|
2510
|
+
selectByHotkey(key: number): SelectOption | null;
|
|
2511
|
+
selectByIndex(index: number): void;
|
|
2512
|
+
}
|
|
2513
|
+
declare function createSelectState(options: SelectOption[], opts?: SelectOptions): SelectState;
|
|
2514
|
+
//#endregion
|
|
2515
|
+
//#region src/dialogs/questions-dialog-logic.d.ts
|
|
2516
|
+
interface QuestionOption {
|
|
2517
|
+
label: string;
|
|
2518
|
+
description?: string;
|
|
2519
|
+
}
|
|
2520
|
+
interface Question {
|
|
2521
|
+
/** 短标签(标签页/答案键)。 */
|
|
2522
|
+
header: string;
|
|
2523
|
+
/** 完整问题文本。 */
|
|
2524
|
+
question: string;
|
|
2525
|
+
/** 是否多选(多选用 Space 切换;单选 Enter/Space 选定并自动前进)。 */
|
|
2526
|
+
multiSelect: boolean;
|
|
2527
|
+
options: QuestionOption[];
|
|
2528
|
+
/** grill_me allowFreeform:选项页底部渲染补充文本输入。 */
|
|
2529
|
+
freeformInput?: boolean;
|
|
2530
|
+
/** 补充文本输入框占位文字。 */
|
|
2531
|
+
freeformPlaceholder?: string;
|
|
2532
|
+
}
|
|
2533
|
+
//#endregion
|
|
2534
|
+
//#region src/stores/message-store.d.ts
|
|
2535
|
+
/** 窗口模式 store 条目:ChatMessage + M2 边界定位预留 seq(DB 主键 seq)。 */
|
|
2536
|
+
type StoredMessage = ChatMessage & {
|
|
2537
|
+
seq?: number;
|
|
2538
|
+
};
|
|
2539
|
+
interface MessageState {
|
|
2540
|
+
/** 转录消息数组(scrollbackMode=false 的 legacy 路径 + RFC-300 窗口模式使用;直写模式恒空)。 */
|
|
2541
|
+
messages: StoredMessage[];
|
|
2542
|
+
}
|
|
2543
|
+
interface MessageStore {
|
|
2544
|
+
store: Store<MessageState>;
|
|
2545
|
+
/** 追加一条消息(不可变 append,自动补 id)。seq 为 M2 边界定位预留(DB 主键)。 */
|
|
2546
|
+
append(msg: ChatMessage, id: string, seq?: number): void;
|
|
2547
|
+
/** 批量追加。 */
|
|
2548
|
+
appendMany(msgs: readonly ChatMessage[], makeId: () => string): void;
|
|
2549
|
+
/**
|
|
2550
|
+
* RFC-300 M2:头部插入更早历史(DB 补页)——消息带 seq(StoredMessage.seq,
|
|
2551
|
+
* DB 主键边界定位),插入数组头部;触发 ScrollableTranscript 全量重建(头部
|
|
2552
|
+
* 连续性断裂)+ 视口补偿(新增行数由渲染层上报)。
|
|
2553
|
+
*/
|
|
2554
|
+
prependMany(msgs: readonly ChatMessage[]): void;
|
|
2555
|
+
/** 原地更新最后一条消息(不可变 patch)。用于 pending→转正等就地标记切换。
|
|
2556
|
+
* @deprecated 竞态敏感——若 pushMessage 在 echoUserInput 与 setPendingEcho/clearPendingEcho
|
|
2557
|
+
* 之间追加了新消息,patchLast 会更新错误的消息。新代码使用 patchById(ID-based,无竞态)。 */
|
|
2558
|
+
patchLast(patch: Partial<ChatMessage>): void;
|
|
2559
|
+
/** 通过 id 定位并更新一条消息(不可变 patch)。用于 pending→转正,解决 patchLast
|
|
2560
|
+
* 的竞态:若 pushMessage 在 echoUserInput 与 setPendingEcho/clearPendingEcho
|
|
2561
|
+
* 之间追加了新消息,patchLast 会更新错误的消息而非用户 pending 消息。 */
|
|
2562
|
+
patchById(id: string, patch: Partial<ChatMessage>): void;
|
|
2563
|
+
/** 移除最后一条消息(不可变)。用于 ESC 撤回 pending user 消息。
|
|
2564
|
+
* @deprecated 竞态敏感——若 pushMessage 在 echoUserInput 与 withdrawPendingEcho
|
|
2565
|
+
* 之间追加了新消息,removeLast 会移除错误的消息。新代码使用 removeById(ID-based,无竞态)。 */
|
|
2566
|
+
removeLast(): void;
|
|
2567
|
+
/** 通过 id 定位并移除一条消息(不可变)。用于 ESC 撤回,解决 removeLast 的竞态:
|
|
2568
|
+
* 若 pushMessage 在 echoUserInput 与 withdrawPendingEcho 之间追加了新消息,
|
|
2569
|
+
* removeById 会移除错误的消息而非用户 pending 消息。 */
|
|
2570
|
+
removeById(id: string): void;
|
|
2571
|
+
/** /clear 会话重置。 */
|
|
2572
|
+
reset(): void;
|
|
2573
|
+
}
|
|
2574
|
+
//#endregion
|
|
2575
|
+
//#region src/bootstrap/session-data-source.d.ts
|
|
2576
|
+
/** service `SessionSnapshot.session` 的最小消费面(字段名与 service DTO 一致)。 */
|
|
2577
|
+
interface RemoteSessionSnapshot {
|
|
2578
|
+
session: {
|
|
2579
|
+
id: string;
|
|
2580
|
+
status: string;
|
|
2581
|
+
messages: ReadonlyArray<StoredMessage>;
|
|
2582
|
+
};
|
|
2583
|
+
/** 快照时刻的事件游标(M3)。作为 subscribe.since 传回以补发期间事件。 */
|
|
2584
|
+
cursor: number;
|
|
2585
|
+
}
|
|
2586
|
+
/** service `Session.subscribe(since)` 之后到达的单条 Session.event(包一层 seq 去重)。 */
|
|
2587
|
+
interface RemoteSessionEvent {
|
|
2588
|
+
/** 服务端单调分配;客户端按它去重 + 检测乱序/缺口。 */
|
|
2589
|
+
seq: number;
|
|
2590
|
+
/** 事件负载(类型形如 Session.event 的 kind 集合;具体译码在 S1 映射表)。 */
|
|
2591
|
+
payload: unknown;
|
|
2592
|
+
}
|
|
2593
|
+
/**
|
|
2594
|
+
* 远端 session 的传输端口。attach 模式下的 client(otto service WS client)实现它;
|
|
2595
|
+
* 本模块只依赖该最小面,可注入 mock(单测不需要真 WS/网络)。
|
|
2596
|
+
*/
|
|
2597
|
+
interface SessionTransport {
|
|
2598
|
+
/** 取 session 快照(messages + cursor)。连接建立后首个动作。 */
|
|
2599
|
+
fetchSnapshot(sessionId: string): Promise<RemoteSessionSnapshot>;
|
|
2600
|
+
/**
|
|
2601
|
+
* 订阅该 session 的实时事件流;`since` 传 snapshot.cursor 由服务端补发期间事件。
|
|
2602
|
+
* 返回取消函数。断线重连由实现方负责(对齐 web-ui otto-client.resubscribeAll 语义)。
|
|
2603
|
+
*/
|
|
2604
|
+
subscribe(sessionId: string, since: number, onEvent: (event: RemoteSessionEvent) => void, onGap: (info: {
|
|
2605
|
+
reason: 'gap';
|
|
2606
|
+
oldestAvailable: number;
|
|
2607
|
+
}) => void): () => void;
|
|
2608
|
+
}
|
|
2609
|
+
/**
|
|
2610
|
+
* 数据源注入后受驱动的 store 面(本地 zustand store 的最小可写接口——用 setState 而非
|
|
2611
|
+
* action,因为远端译码直接产出字段值;调用方在 main.ts 装配时传入具体 store)。
|
|
2612
|
+
*/
|
|
2613
|
+
interface SessionDataTarget {
|
|
2614
|
+
/** 镜像 messages 数组(追加/重设)。 */
|
|
2615
|
+
messageStore: {
|
|
2616
|
+
setState: Store<unknown>['setState'];
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2619
|
+
/**
|
|
2620
|
+
* Session 数据源抽象:local = 现行(cli 在进程内嵌 session、经 TuiHandle/setters 喂),
|
|
2621
|
+
* attach = 服务 Authority(snapshot+subscribe 灌入本地 store)。
|
|
2622
|
+
*
|
|
2623
|
+
* 这是 P0b 的核心 deliverable:把"数据来源"显式化成一个可注入、可替换的端口,
|
|
2624
|
+
* 取代 RFC-333 之前"数据硬编码来自 cli 回调"的隐含耦合。详见 RFC-335-milestone-m3-t335-07.md §8.2。
|
|
2625
|
+
*/
|
|
2626
|
+
interface SessionDataSource {
|
|
2627
|
+
/**
|
|
2628
|
+
* 启动数据源并开始驱动 target stores。返回停止函数。
|
|
2629
|
+
* local 模式可在无网络下返回 no-op(由 cli 侧现行 writer 继续喂 store)。
|
|
2630
|
+
*/
|
|
2631
|
+
start(target: SessionDataTarget): Promise<() => void> | (() => void);
|
|
2632
|
+
}
|
|
2633
|
+
/** 现行本地模式:全部为 no-op——store 由 cli/main.ts 既有的 handle/stores writer 喂。 */
|
|
2634
|
+
declare function createLocalSessionDataSource(): SessionDataSource;
|
|
2635
|
+
interface AttachDataSourceDeps {
|
|
2636
|
+
transport: SessionTransport;
|
|
2637
|
+
sessionId: string;
|
|
2638
|
+
/**
|
|
2639
|
+
* 远端 Session.event → 本地 store 增量 的译码回调。S1 契约映射表产出;本模块只
|
|
2640
|
+
* 负责"按 seq 有序、去重后逐条给它"。返回 void;副作用(调 store action)由实现方做。
|
|
2641
|
+
*/
|
|
2642
|
+
onSessionEvent: (event: RemoteSessionEvent) => void;
|
|
2643
|
+
/** 快照 messages 灌入 messageStore 的写函数(避免本模块直接 import messageStore)。 */
|
|
2644
|
+
hydrateMessages: (target: SessionDataTarget, messages: ReadonlyArray<StoredMessage>) => void;
|
|
2645
|
+
/** gap 显式通知(EVENT_LOG_GAP)——实现方应显式呈"丢事件、需重水合",绝不静默少发。 */
|
|
2646
|
+
onGap: (info: {
|
|
2647
|
+
reason: 'gap';
|
|
2648
|
+
oldestAvailable: number;
|
|
2649
|
+
}) => void;
|
|
2650
|
+
}
|
|
2651
|
+
/**
|
|
2652
|
+
* attach 模式数据源。snapshot(cursor) → subscribe(since) → onSessionEvent 逐条驱动。
|
|
2653
|
+
* 事件按 seq 去重(M3 客户端 MUST);遇 gap → onGap 显式上报(调用方决定重水合/报错)。
|
|
2654
|
+
*
|
|
2655
|
+
* 注:本数据源**只做 Session.event 域的驱动**。首期 attach 的下行写(prompt 经
|
|
2656
|
+
* Chat.query)在 cli 侧,不流经本模块。
|
|
2657
|
+
*/
|
|
2658
|
+
declare function createAttachSessionDataSource(deps: AttachDataSourceDeps): SessionDataSource;
|
|
2659
|
+
//#endregion
|
|
2660
|
+
//#region src/bootstrap/types.d.ts
|
|
2661
|
+
/**
|
|
2662
|
+
* M-N3b:高频流式引擎事件判别联合——收敛原 TuiHandle 8 个独立 setter
|
|
2663
|
+
* (setAgentProcessing/setStreamingText/setStreamingThinking/setActiveTool/setSpinnerMode
|
|
2664
|
+
* /setOutputTokensThisTurn/setMaxOutputTokens/setToolBudget)为单一 pushEngineEvent 通道。
|
|
2665
|
+
*/
|
|
2666
|
+
type TuiStreamEvent = {
|
|
2667
|
+
kind: 'agentProcessing';
|
|
2668
|
+
value: boolean;
|
|
2669
|
+
} | {
|
|
2670
|
+
kind: 'streamingText';
|
|
2671
|
+
text: string;
|
|
2672
|
+
} | {
|
|
2673
|
+
kind: 'streamingThinking';
|
|
2674
|
+
text: string;
|
|
2675
|
+
} | {
|
|
2676
|
+
kind: 'activeTool';
|
|
2677
|
+
name: string | null;
|
|
2678
|
+
} | {
|
|
2679
|
+
kind: 'spinnerMode';
|
|
2680
|
+
mode: 'requesting' | 'responding' | null;
|
|
2681
|
+
} | {
|
|
2682
|
+
kind: 'outputTokensThisTurn';
|
|
2683
|
+
n: number;
|
|
2684
|
+
} | {
|
|
2685
|
+
kind: 'maxOutputTokens';
|
|
2686
|
+
n: number;
|
|
2687
|
+
} | {
|
|
2688
|
+
kind: 'toolBudget';
|
|
2689
|
+
toolTurnCount: number;
|
|
2690
|
+
maxToolTurns: number;
|
|
2691
|
+
outputTokens?: number;
|
|
2692
|
+
outputTokenBudget?: number;
|
|
2693
|
+
} | {
|
|
2694
|
+
kind: 'perf';
|
|
2695
|
+
memory?: PerfMemorySnapshot;
|
|
2696
|
+
notify?: PerfNotifySnapshot;
|
|
2697
|
+
indicatorLevel?: 'healthy' | 'warning' | 'critical';
|
|
2698
|
+
pluginMetrics?: PluginMetricResult[];
|
|
2699
|
+
} | ({
|
|
2700
|
+
kind: 'compactionLog';
|
|
2701
|
+
entryKind: 'compact';
|
|
2702
|
+
before: number;
|
|
2703
|
+
after: number;
|
|
2704
|
+
summary?: string;
|
|
2705
|
+
} | {
|
|
2706
|
+
kind: 'compactionLog';
|
|
2707
|
+
entryKind: 'prune';
|
|
2708
|
+
tokensSaved: number;
|
|
2709
|
+
prunedCount?: number;
|
|
2710
|
+
} | {
|
|
2711
|
+
kind: 'compactionLog';
|
|
2712
|
+
entryKind: 'history_capped';
|
|
2713
|
+
removedCount: number;
|
|
2714
|
+
});
|
|
2715
|
+
/**
|
|
2716
|
+
* 提交意图(前端无关语义层):cli 据此决定如何处理一次提交。
|
|
2717
|
+
* - 'send' : 起新回合(空闲时的普通提交,或斜杠命令分发)。
|
|
2718
|
+
* - 'steer' : agent 运行中时注入当前回合(session.steer)。
|
|
2719
|
+
* followUp/排队 由 TUI 自身的 state.queued 承载(空闲即出队),不经此枚举。
|
|
2720
|
+
* 后续移植 GUI:同一 intent 层,GUI 直接绑 Enter→steer / Cmd+Enter→followUp,语义零改。
|
|
2721
|
+
*/
|
|
2722
|
+
type SubmitIntent = 'send' | 'steer';
|
|
2723
|
+
/**
|
|
2724
|
+
* RFC-148 M3:模态对话框判别联合——收敛原 TuiHandle 9 个独立 open* 方法
|
|
2725
|
+
* (openInfo/openPermissions/openContext/openMemory/openSelect/openExtensionDetail/
|
|
2726
|
+
* openInput/openQuestions/openConfirm)为单一 openModal 通道。(RFC-253 M-T6:底层
|
|
2727
|
+
* modalStore 已删除,dialog 改由 <Route>+resolvers 渲染,openModal 通道语义不变。)
|
|
2728
|
+
*
|
|
2729
|
+
* 不收编 openAlert/openPrompt(全仓 grep 零调用点,见 findings-backlog.md 死代码候选)。
|
|
2730
|
+
* infoDialog 三种来源(openInfo/openPermissions/openContext)在此拆分为三个判别联合
|
|
2731
|
+
* 成员(而非合一个 'info' 成员塞可选字段),保留各自原有的固定语义(如 openContext
|
|
2732
|
+
* 的空 lines 数组是有意为之,非可选省略)。
|
|
2733
|
+
*/
|
|
2734
|
+
type ModalRequest = {
|
|
2735
|
+
kind: 'info';
|
|
2736
|
+
title: string;
|
|
2737
|
+
lines: string[];
|
|
2738
|
+
action?: InfoDialogAction;
|
|
2739
|
+
lineTones?: Record<number, InfoLineTone>;
|
|
2740
|
+
/**
|
|
2741
|
+
* 分组键值正文(可选,优先于 `lines`)——见 `InfoDialog.tsx` `dataListEntries` prop 注释。
|
|
2742
|
+
* 纯数据(非 `ReactNode`),`@x-otto/cli` 可零依赖 `react` 地构造。
|
|
2743
|
+
*/
|
|
2744
|
+
dataListEntries?: DataListEntry[];
|
|
2745
|
+
} | {
|
|
2746
|
+
kind: 'permissions';
|
|
2747
|
+
lines: string[];
|
|
2748
|
+
} | {
|
|
2749
|
+
kind: 'context';
|
|
2750
|
+
} | {
|
|
2751
|
+
kind: 'memory';
|
|
2752
|
+
projectIndex: string;
|
|
2753
|
+
userIndex: string; /** 查看选中条目全文(异步);返回 null 表示未找到/读取失败。 */
|
|
2754
|
+
onViewEntry: (entry: MemoryEntry) => Promise<string | null>; /** 确认删除选中条目(异步)。 */
|
|
2755
|
+
onForget: (entry: MemoryEntry) => Promise<void>;
|
|
2756
|
+
} | ({
|
|
2757
|
+
kind: 'select';
|
|
2758
|
+
} & SelectRequest) | ({
|
|
2759
|
+
kind: 'extensionDetail';
|
|
2760
|
+
} & ExtensionDetailRequest) /** RFC-166:`/extension` 列表页——独立 hard modal(对齐 memory 走 Select.Group 组合式规范)。 */ | ({
|
|
2761
|
+
kind: 'extensionsList';
|
|
2762
|
+
} & ExtensionsListRequest) /** RFC-167:插件面板独立全屏 dialog(取代面板内嵌 extensionDetail body 槽位的方案)。 */ | ({
|
|
2763
|
+
kind: 'pluginPanel';
|
|
2764
|
+
} & PluginPanelRequest) | ({
|
|
2765
|
+
kind: 'input';
|
|
2766
|
+
} & InputRequest) | ({
|
|
2767
|
+
kind: 'questions';
|
|
2768
|
+
} & QuestionsRequest) | ({
|
|
2769
|
+
kind: 'confirm';
|
|
2770
|
+
} & ConfirmRequest) /** RFC-174 M5:/keybindings 命令打开可视化快捷键面板(独立 hard modal,Band A)。 */ | {
|
|
2771
|
+
kind: 'keybindingPanel';
|
|
2772
|
+
overrides: Record<string, KeyBindingPredicate> | undefined;
|
|
2773
|
+
onSave: (commandId: string, predicate: KeyBindingPredicate, target: 'global' | 'project') => void;
|
|
2774
|
+
onSaveReplace: (actions: Array<{
|
|
2775
|
+
commandId: string;
|
|
2776
|
+
predicate: KeyBindingPredicate;
|
|
2777
|
+
}>, target: 'global' | 'project') => void;
|
|
2778
|
+
onReset: (commandId: string) => void;
|
|
2779
|
+
onResetAll: () => void;
|
|
2780
|
+
} /** RFC-233:/shortcuts 命令打开用户自定义快捷方式管理面板(独立 hard modal,Band A)。 */ | {
|
|
2781
|
+
kind: 'shortcutsPanel';
|
|
2782
|
+
shortcuts: ReadonlyArray<{
|
|
2783
|
+
name: string;
|
|
2784
|
+
text: string;
|
|
2785
|
+
}>;
|
|
2786
|
+
onSave: (name: string, text: string, previousName?: string) => void;
|
|
2787
|
+
onDelete: (name: string) => void;
|
|
2788
|
+
} /** RFC-189 D4:`/open <path>` 命令打开的文件查看器独立 dialog(Band A hard modal)。 */ | ({
|
|
2789
|
+
kind: 'fileViewer';
|
|
2790
|
+
} & FileViewerRequest) /** `/help` 命令面板独立查看器(Band A hard modal,复用 FileContentViewer 固定高度+滚动逻辑)。 */ | ({
|
|
2791
|
+
kind: 'helpViewer';
|
|
2792
|
+
} & HelpViewerRequest) /** install 进度条 dialog(Band A hard modal 阻断输入,不可取消)。 */ | ({
|
|
2793
|
+
kind: 'progress';
|
|
2794
|
+
} & ProgressDialogProps) /** Setup 向导弹窗(五步线性引导:Provider→Trust→Login→Model→Start)。 */ | ({
|
|
2795
|
+
kind: 'wizard';
|
|
2796
|
+
} & WizardRequest) /** 首次启动引导单弹层(昵称→语言→主题三步合一);resolve 携带用户已设置的字段。 */ | {
|
|
2797
|
+
kind: 'onboarding'; /** 语言步选中时立即切换界面语言(后续步骤文案即时生效)。 */
|
|
2798
|
+
onLanguagePreview?: (language: 'en' | 'zh' | 'auto') => void;
|
|
2799
|
+
} /** RFC-211 M2:a2ui Form 组件交互式弹窗。 */ | {
|
|
2800
|
+
kind: 'a2uiForm'; /** Form 组件的完整定义(含字段列表)。 */
|
|
2801
|
+
component: A2uiComponent; /** 提交回调:收集字段值 → onA2uiAction(componentId, action, payload)。 */
|
|
2802
|
+
onAction: (componentId: string, action: string, payload?: Record<string, unknown>) => void;
|
|
2803
|
+
};
|
|
2804
|
+
/** install 进度条 dialog props。 */
|
|
2805
|
+
interface ProgressDialogProps {
|
|
2806
|
+
/** 标题,如 "Installing browser-use" */
|
|
2807
|
+
title: string;
|
|
2808
|
+
/** 四个阶段标签 */
|
|
2809
|
+
phases: string[];
|
|
2810
|
+
}
|
|
2811
|
+
/** Setup 向导弹窗请求(openModal({kind:'wizard',...}) 入参)。 */
|
|
2812
|
+
/**
|
|
2813
|
+
* OAuth 流程句柄——向导内嵌授权,不跳转独立面板。
|
|
2814
|
+
* RFC-274 M2:补 `code`/`instructions`(对齐真实 `OAuthInfo` 字段),供等待态渲染
|
|
2815
|
+
* device-flow 场景(有 code 展示设备码 UI,无 code 展示纯浏览器 UI)——不在选项列表层
|
|
2816
|
+
* 区分 pkce/device-flow,只在这个等待态句柄层区分。
|
|
2817
|
+
*/
|
|
2818
|
+
/**
|
|
2819
|
+
* OAuth 轮询失败分类(RFC-326 §6.3)——决定 UI 给出哪个主 CTA。
|
|
2820
|
+
* - `network`:连不上授权服务(含代理不通)→ 主 CTA 为「打开代理设置」
|
|
2821
|
+
* - `cancelled`:用户主动取消 → 静默回选择态,不当作错误
|
|
2822
|
+
* - `rejected`:provider 明确拒绝/超时 → 建议重试或换授权方式
|
|
2823
|
+
*/
|
|
2824
|
+
type OAuthFailureReason = 'network' | 'cancelled' | 'rejected';
|
|
2825
|
+
/** 轮询结果:兼容旧的裸字符串形态,新实现可返回带分类的对象。 */
|
|
2826
|
+
type OAuthPollResult = 'pending' | 'done' | 'error' | {
|
|
2827
|
+
status: 'pending' | 'done';
|
|
2828
|
+
} | {
|
|
2829
|
+
status: 'error';
|
|
2830
|
+
reason: OAuthFailureReason;
|
|
2831
|
+
};
|
|
2832
|
+
interface OAuthHandle {
|
|
2833
|
+
authorizationUrl: string;
|
|
2834
|
+
/** 设备码流程的 user code(`OAuthInfo.code`);pkce 浏览器流程通常为空。 */
|
|
2835
|
+
code?: string;
|
|
2836
|
+
/** provider 侧提示语(`OAuthInfo.instructions`),如 "Enter code: XXXX-XXXX"。 */
|
|
2837
|
+
instructions?: string;
|
|
2838
|
+
/**
|
|
2839
|
+
* 轮询授权结果。
|
|
2840
|
+
*
|
|
2841
|
+
* RFC-326 §6.3:失败必须可分类——`'error'` 一把梭会让 UI 无法给出对症的下一步
|
|
2842
|
+
* (网络/代理不通该引导去配代理,用户主动取消不该报错,provider 拒绝该建议换个
|
|
2843
|
+
* 方式)。返回对象形态时携带 `reason`;仍支持返回裸字符串以兼容旧实现。
|
|
2844
|
+
*
|
|
2845
|
+
* **不传 raw error/stack**:§6.3 明确"不要把 raw stack 放在第一屏",故契约层
|
|
2846
|
+
* 只允许受限分类,从类型上杜绝调用方顺手把异常原文塞进 UI。
|
|
2847
|
+
*/
|
|
2848
|
+
poll: () => Promise<OAuthPollResult>;
|
|
2849
|
+
cancel: () => void;
|
|
2850
|
+
/**
|
|
2851
|
+
* 重新打开授权页(RFC-326 §6.3 "Open again")。
|
|
2852
|
+
*
|
|
2853
|
+
* 浏览器没弹出来是 OAuth 最常见的失败形态——无头环境、默认浏览器未配置、
|
|
2854
|
+
* 焦点被抢走后用户误关了标签页。此前等待态只有 Esc(取消整个授权),用户必须
|
|
2855
|
+
* 退出重来才能再看一眼链接。省略时 UI 不显示该动作(向后兼容)。
|
|
2856
|
+
*/
|
|
2857
|
+
openAgain?: () => void;
|
|
2858
|
+
}
|
|
2859
|
+
interface WizardRequest {
|
|
2860
|
+
kind: 'wizard';
|
|
2861
|
+
title: string;
|
|
2862
|
+
/** 五步名称(i18n),按顺序:Provider/Trust/Login/Model/Start。 */
|
|
2863
|
+
stepNames: readonly string[];
|
|
2864
|
+
/** 五步副标题(i18n),按顺序。 */
|
|
2865
|
+
stepSubtitles: readonly string[];
|
|
2866
|
+
/** 已完成步骤索引集(0-based)。 */
|
|
2867
|
+
initialCompleted: readonly number[];
|
|
2868
|
+
/** 初始显示的步骤(0-based)。所有步骤需在 range 内。 */
|
|
2869
|
+
initialCurrent: number;
|
|
2870
|
+
/** Welcome 页 i18n 文案。 */
|
|
2871
|
+
welcomeTitle: string;
|
|
2872
|
+
welcomeGreeting: string;
|
|
2873
|
+
welcomeDescription: string;
|
|
2874
|
+
welcomeDontShowAgainLabel: string;
|
|
2875
|
+
welcomeStartLabel: string;
|
|
2876
|
+
welcomeCancelLabel: string;
|
|
2877
|
+
providerOptions: Array<{
|
|
2878
|
+
label: string;
|
|
2879
|
+
value: string;
|
|
2880
|
+
detail?: string;
|
|
2881
|
+
}>;
|
|
2882
|
+
/**
|
|
2883
|
+
* Step 1 (Provider Auth) — 函数而非静态数组:根据 Step 0 用户选择的 provider 动态计算。
|
|
2884
|
+
* RFC-274 M2:从硬编码白名单改为查 `OAuthRegistry`(不区分 pkce/device-flow,理由见
|
|
2885
|
+
* RFC-274 §4"实施修正记录")。命名对齐"provider 授权≠账号登录"语义切分(RFC-274 §0.1)
|
|
2886
|
+
* ——历史名 `loginOptions` 已改名,避免与未来 `/login`(Otto/Aniwei 账号登录)语义混淆。
|
|
2887
|
+
*/
|
|
2888
|
+
providerAuthOptions: (providerId: string) => Array<{
|
|
2889
|
+
label: string;
|
|
2890
|
+
value: string;
|
|
2891
|
+
detail?: string;
|
|
2892
|
+
}>;
|
|
2893
|
+
/** Provider Auth 面板中显示的 provider 名称(如 "Anthropic")。 */
|
|
2894
|
+
authProviderName?: string;
|
|
2895
|
+
/**
|
|
2896
|
+
* Step 2 模型选项。
|
|
2897
|
+
*
|
|
2898
|
+
* RFC-326 §6.4:不能是"无排序的技术清单"——`recommended` 标出首选(至多一个),
|
|
2899
|
+
* `unusableReason` 说明为何不可用(缺凭据 / 订阅 429 风险)。两个字段均可选:
|
|
2900
|
+
* 省略时退化为原来的平列表渲染,旧调用方无需改动。
|
|
2901
|
+
*/
|
|
2902
|
+
modelOptions: Array<{
|
|
2903
|
+
label: string;
|
|
2904
|
+
value: string;
|
|
2905
|
+
detail?: string;
|
|
2906
|
+
recommended?: boolean;
|
|
2907
|
+
unusableReason?: 'unauthenticated' | 'oauth-429-risk';
|
|
2908
|
+
}>;
|
|
2909
|
+
examplePrompts: readonly string[];
|
|
2910
|
+
/** 信任步骤(Step 1)中显示的工作区路径。 */
|
|
2911
|
+
workspacePath?: string;
|
|
2912
|
+
/**
|
|
2913
|
+
* `capabilities`(RFC-326):安装过程中**实际被授予**的高危能力 id 列表,供成功终态
|
|
2914
|
+
* 向用户披露。向导走 `autoTrust` 跳过了确认弹窗,但授权照常发生——不披露会让用户
|
|
2915
|
+
* 在毫无感知的情况下授出 provider 级权限(详见 WizardDialog 成功态注释)。
|
|
2916
|
+
* 空数组/省略 = 该插件未声明任何高危能力,无需披露。
|
|
2917
|
+
*
|
|
2918
|
+
* `pendingCapabilities`(RFC-326 M2-05):安装后 reload 时该插件仍有**未授予**
|
|
2919
|
+
* 的高危能力。此时它的 providers 被 fail-closed 整体跳过——装上了却贡献零个
|
|
2920
|
+
* 模型。必须在成功态显式告知,否则用户只看到 "✓ Installed" 就继续下一步,
|
|
2921
|
+
* 到模型步才发现列表是空的、却不知道原因。
|
|
2922
|
+
*/
|
|
2923
|
+
onInstallProvider: (value: string, onProgress: (phase: string) => void) => Promise<{
|
|
2924
|
+
ok: true;
|
|
2925
|
+
providerId?: string;
|
|
2926
|
+
capabilities?: readonly string[];
|
|
2927
|
+
pendingCapabilities?: boolean;
|
|
2928
|
+
} | {
|
|
2929
|
+
ok: false;
|
|
2930
|
+
error: string;
|
|
2931
|
+
}>;
|
|
2932
|
+
/**
|
|
2933
|
+
* 发起 provider OAuth 授权——向导内嵌等待态,不弹出独立面板。
|
|
2934
|
+
* RFC-274 M2:补 `providerId` 显式传参,禁止调用方继续用 `providers[0]` 猜测
|
|
2935
|
+
* (多 provider 场景下 Step 0 选中的 provider 必须与实际授权目标一致)。
|
|
2936
|
+
*/
|
|
2937
|
+
onProviderOAuthStart?: (providerId: string) => Promise<OAuthHandle | null>;
|
|
2938
|
+
/**
|
|
2939
|
+
* 打开代理设置(RFC-326 §6.3:网络/代理错误的主 CTA)。
|
|
2940
|
+
* 省略时该动作不显示——宿主未提供代理配置面板的场景下不给假入口。
|
|
2941
|
+
*/
|
|
2942
|
+
onOpenProxySettings?: () => void;
|
|
2943
|
+
/**
|
|
2944
|
+
* 验证并保存 provider API key——向导内嵌输入框,不弹 InputDialog。
|
|
2945
|
+
* RFC-274 M2:补 `providerId` 显式传参,同上。
|
|
2946
|
+
*/
|
|
2947
|
+
onSubmitProviderApiKey?: (providerId: string, key: string) => Promise<{
|
|
2948
|
+
ok: true;
|
|
2949
|
+
} | {
|
|
2950
|
+
ok: false;
|
|
2951
|
+
error: string;
|
|
2952
|
+
}>;
|
|
2953
|
+
onSelectModel: (modelId: string) => Promise<void>;
|
|
2954
|
+
onComplete: () => void;
|
|
2955
|
+
onDismiss: () => void;
|
|
2956
|
+
/** 用户在欢迎页勾选/取消"不再提示"。 */
|
|
2957
|
+
onDontShowAgain: (value: boolean) => void;
|
|
2958
|
+
}
|
|
2959
|
+
/** ProgressDialog 运行时状态更新(由 updateProgress 推送)。 */
|
|
2960
|
+
interface ProgressUpdate {
|
|
2961
|
+
phaseIndex?: number;
|
|
2962
|
+
phaseStatuses?: Array<'pending' | 'active' | 'done' | 'error'>;
|
|
2963
|
+
percent?: number;
|
|
2964
|
+
detail?: string;
|
|
2965
|
+
subProgress?: {
|
|
2966
|
+
current: number;
|
|
2967
|
+
total: number;
|
|
2968
|
+
};
|
|
2969
|
+
/**
|
|
2970
|
+
* RFC-286 D2:`partial` = 部分成功(N 成功 / M 失败)的一等终态。
|
|
2971
|
+
*
|
|
2972
|
+
* 多 skill 安装遵循 RFC-130 D5「独立安装、失败不回滚」,半成功是**合法常态**,
|
|
2973
|
+
* 因此 UI 必须有对应的第一等表达:用 `success` 近似会假绿(失败项静默隐藏),
|
|
2974
|
+
* 用 `error` 近似会假红(用户误以为需要全部重装)。`partial` 亦用于
|
|
2975
|
+
* 「产物已落盘但能力刷新失败」的 degraded success(D5)。
|
|
2976
|
+
*/
|
|
2977
|
+
status?: 'running' | 'success' | 'partial' | 'error';
|
|
2978
|
+
errorMessage?: string;
|
|
2979
|
+
/**
|
|
2980
|
+
* RFC-290 D2:终态「下一步」建议——**必须由调用方结构化下发**,组件零推断。
|
|
2981
|
+
*
|
|
2982
|
+
* 严禁改为在组件内对 `errorMessage` 做子串匹配(如判断是否含"已存在"):错误文案
|
|
2983
|
+
* 会随 locale 变化,文本嗅探在英文环境必然失效;且调用方本就掌握 `InstallResult`
|
|
2984
|
+
* 的结构化信息,无需猜测。判定不出时**不下发本字段**,组件即不渲染建议行——
|
|
2985
|
+
* 错误的建议比没有建议更有害。
|
|
2986
|
+
*
|
|
2987
|
+
* `label` 由调用方本地化后传入(组件不持有安装领域文案)。
|
|
2988
|
+
*/
|
|
2989
|
+
nextStep?: {
|
|
2990
|
+
kind: 'force' | 'reload';
|
|
2991
|
+
label: string;
|
|
2992
|
+
};
|
|
2993
|
+
}
|
|
2994
|
+
/** openModal 的 'input' 分支入参(供重载签名引用)。 */
|
|
2995
|
+
type ModalRequestInput = Extract<ModalRequest, {
|
|
2996
|
+
kind: 'input';
|
|
2997
|
+
}>;
|
|
2998
|
+
/** openModal 的 'questions' 分支入参(供重载签名引用)。 */
|
|
2999
|
+
type ModalRequestQuestions = Extract<ModalRequest, {
|
|
3000
|
+
kind: 'questions';
|
|
3001
|
+
}>;
|
|
3002
|
+
/** openModal 的 'onboarding' 分支入参(供重载签名引用)。 */
|
|
3003
|
+
type ModalRequestOnboarding = Extract<ModalRequest, {
|
|
3004
|
+
kind: 'onboarding';
|
|
3005
|
+
}>;
|
|
3006
|
+
/** openModal 的其余 8 个同步分支入参(供重载签名引用)。 */
|
|
3007
|
+
type ModalRequestVoid = Exclude<ModalRequest, {
|
|
3008
|
+
kind: 'input';
|
|
3009
|
+
} | {
|
|
3010
|
+
kind: 'questions';
|
|
3011
|
+
} | {
|
|
3012
|
+
kind: 'onboarding';
|
|
3013
|
+
}>;
|
|
3014
|
+
/** openQuestions 的返回值类型(供 openModal 'questions' 重载引用)。 */
|
|
3015
|
+
type QuestionsAnswer = {
|
|
3016
|
+
answers: Record<string, string[]>;
|
|
3017
|
+
freeformText?: string;
|
|
3018
|
+
};
|
|
3019
|
+
/**
|
|
3020
|
+
* RFC-148 M3:面板 toggle 判别联合——收敛原 TuiHandle 10 个独立 toggle 类/"伪 open"方法
|
|
3021
|
+
* (toggleHistory/toggleBackgroundTasks/toggleDraftPane/toggleQueuePane/toggleNotifications/
|
|
3022
|
+
* toggleInspector/openSchedulePane/openPerf/openCacheStats/openGallery)为单一
|
|
3023
|
+
* togglePane 通道。open 省略=翻转(对齐原 toggle* 方法的既有语义);伪 open 类
|
|
3024
|
+
* (原本只能"开"不能"关")保留同样只开的语义,togglePane 调用时省略 open 参数即可。
|
|
3025
|
+
*
|
|
3026
|
+
* 不收编 toggleEditedFiles(全仓 grep 零调用点,见 findings-backlog.md 死代码候选)。
|
|
3027
|
+
*/
|
|
3028
|
+
type PaneName = 'history' | 'backgroundTasks' | 'draftPane' | 'queuePane' | 'notifications' | 'schedulePane' | 'perf' | 'cacheStats' | 'compactionLog' | 'gallery' | 'proxy' | 'prompts';
|
|
3029
|
+
interface TuiOptions {
|
|
3030
|
+
stdin: NodeJS.ReadStream;
|
|
3031
|
+
stdout: NodeJS.WriteStream;
|
|
3032
|
+
columns?: number;
|
|
3033
|
+
/** 终端总行数(自适应流式预览高度用;缺省读 stdout.rows)。 */
|
|
3034
|
+
rows?: number;
|
|
3035
|
+
/** 已完成历史改由 insertHistory 直写终端 scrollback(不进 Ink Static)。
|
|
3036
|
+
* 缺省读 env OTTO_TUI_SCROLLBACK=1。开启后 Ink 只渲底部恒小 live 区。 */
|
|
3037
|
+
scrollback?: boolean;
|
|
3038
|
+
/** RFC-345 D5/D6:影子模式——TUI 侧渲染常驻可见性(状态栏徽标 + 输入区 chip + Home 横幅)。 */
|
|
3039
|
+
shadow?: boolean;
|
|
3040
|
+
modelName?: string;
|
|
3041
|
+
/** 初始「无可用模型」态(未登录/无凭证)→ 输入框显 promptSetup 引导。 */
|
|
3042
|
+
needsSetup?: boolean;
|
|
3043
|
+
/** 斜杠命令表(typeahead) */
|
|
3044
|
+
commands?: CommandEntry[];
|
|
3045
|
+
/** #/@ sigil 条目数据源(coding 层 PluginInputRegistry,结构同构)。
|
|
3046
|
+
* 静态注入(启动时一次),透传给 App 渲染 SigilPane。 */
|
|
3047
|
+
pluginInput?: SigilSearchRegistry;
|
|
3048
|
+
/**
|
|
3049
|
+
* RFC-253 M-T5:初始路由。resume 到有历史会话时传 '/'(直接进对话,消除首帧闪 Home);
|
|
3050
|
+
* 全新会话缺省 '/home'。
|
|
3051
|
+
*/
|
|
3052
|
+
initialPath?: string;
|
|
3053
|
+
/** 启动横幅(version/cwd);未提供则不显示 */
|
|
3054
|
+
welcome?: {
|
|
3055
|
+
version?: string;
|
|
3056
|
+
buildId?: number;
|
|
3057
|
+
cwd?: string; /** 用户昵称(settings.nickname):Welcome 具名问候;缺省无名版。 */
|
|
3058
|
+
nickname?: string;
|
|
3059
|
+
updateAvailable?: {
|
|
3060
|
+
latest: string;
|
|
3061
|
+
current: string;
|
|
3062
|
+
newer: boolean;
|
|
3063
|
+
forced: boolean;
|
|
3064
|
+
};
|
|
3065
|
+
weather?: {
|
|
3066
|
+
condition: string;
|
|
3067
|
+
temp: number;
|
|
3068
|
+
location: string;
|
|
3069
|
+
};
|
|
3070
|
+
};
|
|
3071
|
+
/** RFC-234 P2-b:选择会话回调。 */
|
|
3072
|
+
onSessionSelect?: (id: string) => void;
|
|
3073
|
+
/** RFC-198 §4.4:PasteStore 的内存压力分级来源只读视图(cli 层传入 App._residencyGovernor
|
|
3074
|
+
* 的结构化子集,零 @x-otto/runtime 编译期依赖)。省略时 PasteStore 固定 healthy 上限。 */
|
|
3075
|
+
residencyGovernor?: PasteStoreResidencySource;
|
|
3076
|
+
/**
|
|
3077
|
+
* RFC-217 D1:EditedFileFullPane「整个文件 diff」(vs git HEAD)异步取数 provider。
|
|
3078
|
+
* cli 层绑定 projectRoot 调用 `gitFallbackEditedFileContentAsync`(`@x-otto/cli`)注入;
|
|
3079
|
+
* 缺省 `undefined` 时该模式不可用,`f` 键三态循环退化为现状 diff/full 二态。永远异步
|
|
3080
|
+
* ——TUI 单线程渲染循环不可被子进程调用阻塞。
|
|
3081
|
+
*/
|
|
3082
|
+
resolveWholeFileDiff?: (path: string, operation: EditedFileEntry['operation']) => Promise<{
|
|
3083
|
+
oldContent?: string;
|
|
3084
|
+
newContent?: string;
|
|
3085
|
+
error?: string;
|
|
3086
|
+
}>;
|
|
3087
|
+
/** 界面语言(en/zh/auto);缺省 auto(按环境 LANG 检测)。 */
|
|
3088
|
+
language?: LangMode;
|
|
3089
|
+
/** TUI 主题模式(RFC-263 M5);缺省 dark。'system' 时 startTui 在 render 前经 OSC 11 探测终端背景明暗。 */
|
|
3090
|
+
theme?: 'dark' | 'light' | 'system';
|
|
3091
|
+
/**
|
|
3092
|
+
* RFC-277 M6:主题预设注册表(builtin + extension 贡献,见 `@x-otto/cli`
|
|
3093
|
+
* `theme-preset-wiring.ts` 装配)。未传时落回内置 dark/light(M1-M5 既有行为)。
|
|
3094
|
+
*/
|
|
3095
|
+
themeRegistry?: ThemeRegistry;
|
|
3096
|
+
/** RFC-277 M6:按 appearance 分槽的 preset 初值(settings `theme_preset` 字段)。 */
|
|
3097
|
+
presetSelection?: ThemePresetSelection;
|
|
3098
|
+
/**
|
|
3099
|
+
* 用户快捷键覆盖表(settings `keybinding_overrides`)——**运行时按键分发的输入**。
|
|
3100
|
+
*
|
|
3101
|
+
* RFC-174 M4/M5 交付了 `/keybindings` 面板与持久化,却漏接运行时消费:`matchKeyBinding`
|
|
3102
|
+
* 曾直接吃编译期 `KEY_BINDINGS`,导致用户改完键位、settings.json 也写了,但按键行为
|
|
3103
|
+
* 不变(且无"需重启"提示)。此字段补上那条线;与 `language`/`theme`/`presetSelection`
|
|
3104
|
+
* 同属"settings 派生的启动期配置",故走 TuiOptions 而非新增 `TuiHandle.set*`
|
|
3105
|
+
* (后者会撞 tuihandle-growth-gate 门禁,且键位覆盖不是流式数据推送)。
|
|
3106
|
+
*
|
|
3107
|
+
* ⚠️ 生效时机:**启动期读取一次**,运行时改绑需重启会话才生效(cli
|
|
3108
|
+
* `handlers/keybindings.ts` 的四条写入路径均会 toast 提示这一点——没有该提示时,
|
|
3109
|
+
* 用户"存了却没动静"的观感与修复前"改了永远不生效"完全相同)。
|
|
3110
|
+
*/
|
|
3111
|
+
keybindingOverrides?: Record<string, KeyBindingPredicate>;
|
|
3112
|
+
/** 当前权限 mode:confirm/auto/bypass。状态栏初值。 */
|
|
3113
|
+
permissionMode?: string;
|
|
3114
|
+
/** 快捷键(Shift+Tab)循环切换权限 mode 回调;cli 据此切并落盘。 */
|
|
3115
|
+
onCyclePermissionMode?: () => void;
|
|
3116
|
+
/** DEC1004 终端焦点变化(opt-in OTTO_TUI_FOCUS=1);cli 喂 app.setTerminalFocus。 */
|
|
3117
|
+
onFocusChange?: (focused: boolean) => void;
|
|
3118
|
+
/** /proxy 面板内提交代理地址(编辑/设置);cli 据此 settings.persist 落盘并回推 setProxyView。 */
|
|
3119
|
+
onProxySubmitUrl?: (url: string) => void;
|
|
3120
|
+
/** /proxy 面板内切换启用/停用;cli 据此 settings.persist 落盘并回推 setProxyView。 */
|
|
3121
|
+
onProxyToggleEnabled?: () => void;
|
|
3122
|
+
/** /proxy 面板内清除代理配置(ConfirmDialog 确认后);cli 据此 settings.persist 落盘并回推 setProxyView。 */
|
|
3123
|
+
onProxyClear?: () => void;
|
|
3124
|
+
/** /proxy 面板内触发连通性探测(RFC-288 D4);cli 探测后回推 setProxyView。 */
|
|
3125
|
+
onProxyTest?: () => void;
|
|
3126
|
+
/** 流式合帧 fps(缺省 30):流式 token 在 App 级 coalescer 按此压帧,限流式渲染 CPU。 */
|
|
3127
|
+
maxFps?: number;
|
|
3128
|
+
/** Ink 渲染节流 fps(缺省 90,输入回显响应度):与流式 fps 解耦——输入渲染只被 Ink maxFps 节流,
|
|
3129
|
+
* 调高即解放输入(修「打字/删除卡顿」),流式仍由 App coalescer 压在 maxFps。 */
|
|
3130
|
+
renderMaxFps?: number;
|
|
3131
|
+
/** RFC-089 M8 spike:Ink ConcurrentRoot(键击 DiscreteEventPriority 插队 + 可中断 reconcile)。
|
|
3132
|
+
* 缺省读 OTTO_TUI_CONCURRENT=1;A/B 稳定后再定默认。 */
|
|
3133
|
+
concurrent?: boolean;
|
|
3134
|
+
/** intent='steer' 时 cli 应注入当前运行回合(session.steer)而非起新回合;缺省/'send' 走原路径。 */
|
|
3135
|
+
/**
|
|
3136
|
+
* 提交回调(fire-and-forget)。
|
|
3137
|
+
*
|
|
3138
|
+
* **返回值不参与"是否保留草稿"的判定**(RFC-326 §6.7 定稿):cli 侧实现是 async,
|
|
3139
|
+
* 且真正的阻断点位于若干 `await` 之后(命令派发 / 文件命令展开),同步拿不到结论——
|
|
3140
|
+
* 曾把本签名放宽为 `void | 'rejected'` 试图让宿主回传拒绝信号,但 async 实现返回的
|
|
3141
|
+
* 恒是 `Promise`、永远不等于 `'rejected'`,该通道是**恒不生效的空契约**(且使
|
|
3142
|
+
* cli 的 `Promise<void>` 与本类型不兼容,全仓 typecheck 红)。
|
|
3143
|
+
*
|
|
3144
|
+
* 草稿保留的真实实现在 TUI 侧:`InputRegion.handleSubmitWithDraftGuard` 用同步可得的
|
|
3145
|
+
* `needsSetup` 判据返回 `'rejected'` 给 `PromptInput`(见其头注释)——判据更早、更准,
|
|
3146
|
+
* 不依赖宿主异步结论。故此处收窄回 `void`,不留误导性的死契约。
|
|
3147
|
+
*/
|
|
3148
|
+
onSubmit?: (text: string, mode: SubmitMode, intent?: SubmitIntent) => void;
|
|
3149
|
+
/**
|
|
3150
|
+
* 引擎真·忙判定探针(session.isBusy)。提交分流(routeSubmit)与出队(drainQueue)的判忙以此为准,
|
|
3151
|
+
* 不再信 TUI 的 state.processing 镜像态——镜像态会被断点暂停 setAgentProcessing(false)、完成事件
|
|
3152
|
+
* 抢跑等窗口骗成"空闲",导致消息在引擎仍忙时漏到起新回合 → 撞裸 prompt() 抛 "Agent is processing"。
|
|
3153
|
+
* 缺省(未接线)回落到 state.processing,保持纯前端可单测。
|
|
3154
|
+
*/
|
|
3155
|
+
isAgentBusy?: () => boolean;
|
|
3156
|
+
/**
|
|
3157
|
+
* RFC-180 D6:turn 边界暂停态探针(AgentSession.isPaused)。与 isAgentBusy 正交——
|
|
3158
|
+
* 暂停生效后 isAgentBusy() 天然变回 false,但暂停仍应阻止 drainQueue 自动出队,故
|
|
3159
|
+
* agentBusy() 组合链需额外 OR 本探针。缺省(未接线)视为未暂停,行为与改动前一致
|
|
3160
|
+
* (fail-open,同 isAgentBusy 缺省语义)。
|
|
3161
|
+
*/
|
|
3162
|
+
isPaused?: () => boolean;
|
|
3163
|
+
/**
|
|
3164
|
+
* 命令名(小写,无 /)是否为「本地立即处理、不起 agent 回合」的注册命令(cli 的 CLI_COMMANDS)。
|
|
3165
|
+
* 决定运行中斜杠命令立即执行 vs 入队——未注册命令(fallthrough)放行会撞 isBusy,必须入队。
|
|
3166
|
+
*/
|
|
3167
|
+
isImmediateCommand?: (command: string) => boolean;
|
|
3168
|
+
/**
|
|
3169
|
+
* 命令名是否为「中止当前回合」命令(/abort)。运行中也立即放行→onSubmit 直接走中断入口,
|
|
3170
|
+
* 不被当普通斜杠命令入队(否则中止要等当前回合跑完才回放,彻底失效)。
|
|
3171
|
+
*/
|
|
3172
|
+
isInterruptCommand?: (command: string) => boolean;
|
|
3173
|
+
onInterrupt?: () => void;
|
|
3174
|
+
/**
|
|
3175
|
+
* 问 AI(RFC-225 M2):shell 面板错误态下 `a` 键触发。cli 侧应读取
|
|
3176
|
+
* `tui.getShellExecutionSnapshot()` 组装消息,经自身 `onSubmit`/`handleSubmit`
|
|
3177
|
+
* 提交到当前会话,并在提交后关闭对应面板(`dismissShellExecution()` /
|
|
3178
|
+
* `setShellFullOutput(null)`,具体哪个由触发来源决定,cli 侧不感知触发来源,
|
|
3179
|
+
* TUI 侧统一在两处调用点各自负责关闭,见 AppProps.onShellAskAi 的两个消费方)。
|
|
3180
|
+
*/
|
|
3181
|
+
onShellAskAi?: () => void;
|
|
3182
|
+
/**
|
|
3183
|
+
* ESC 撤回 pending 消息时触发——TUI 侧已完成 UI 清理(占位消息/文本回填/清 pendingEcho),
|
|
3184
|
+
* CLI 侧据此判定是否需直接 abort(不弹对话框)。text=原文、mode=提交模式。
|
|
3185
|
+
*/
|
|
3186
|
+
onWithdrawPending?: (text: string, mode: string) => void;
|
|
3187
|
+
/**
|
|
3188
|
+
* RFC-337 D3:ESC 撤回一条运行中追加(steer)时触发。CLI 侧 `session.removeSteer(id)`
|
|
3189
|
+
* 命中(未被模型消费)→ `withdrawPendingSteer` 清 live 回显;未命中(已 drain)→ 退化
|
|
3190
|
+
* `requestStop('abort')` 中止整回合。id = steer 稳定 id(setPendingSteer 记录)。
|
|
3191
|
+
*/
|
|
3192
|
+
onWithdrawSteer?: (id: string) => void;
|
|
3193
|
+
/**
|
|
3194
|
+
* M-N3:A2UI Button 真交互回调——用户按数字键 1-9 触发时,TUI 据此通知 CLI 执行对应 action。
|
|
3195
|
+
* CLI 侧收到后经 dispatchCliCommand('a2ui-action', [componentId, action, ...]) 分流到 handleA2uiAction。
|
|
3196
|
+
*/
|
|
3197
|
+
onA2uiAction?: (componentId: string, action: string, payload?: Record<string, unknown>) => void;
|
|
3198
|
+
/**
|
|
3199
|
+
* RFC-116 M5:`/perf` 面板内手动刷新键(r)触发——CLI 侧重新执行 `handlePerf` 的核心
|
|
3200
|
+
* 采集逻辑(内存/渲染/插件三类数据源),回填后面板自动重渲(数据经 setPerf* 系列
|
|
3201
|
+
* TuiHandle 方法喂回,不由本回调直接返回值)。手动触发,不做自动轮询(对齐 D7)。
|
|
3202
|
+
*/
|
|
3203
|
+
onPerfRefresh?: () => void;
|
|
3204
|
+
/** /tasks 面板:k 杀选中后台进程。 */
|
|
3205
|
+
onBackgroundKill?: (id: string) => void;
|
|
3206
|
+
/** /tasks 面板:o 看选中后台进程输出(cli 据此启动 logPath tail 轮询)。 */
|
|
3207
|
+
onBackgroundViewOutput?: (id: string) => void;
|
|
3208
|
+
/** 退出实时输出跟随(esc):cli 据此停轮询并清空视图。 */
|
|
3209
|
+
onBackgroundOutputClose?: () => void;
|
|
3210
|
+
/** a 键应用 ready 的 agent-session 作业 diff 到主仓。 */
|
|
3211
|
+
onBackgroundApply?: (id: string) => void;
|
|
3212
|
+
/** 向运行中的 delegate 补充信息(输出视图内打字 + Enter)。 */
|
|
3213
|
+
onDelegateSupply?: (id: string, text: string) => void;
|
|
3214
|
+
/** ctrl+s 保存当前输入为一条自动命名的草稿(随会话快照持久化,cli 侧写 session.setDrafts + save)。 */
|
|
3215
|
+
onDraftSave?: (text: string) => void;
|
|
3216
|
+
/**
|
|
3217
|
+
* `@` 面板选中一条条目后回调(`#` hashtag 不计入——@ 面板 MRU 语义只服务 @ sigil)。
|
|
3218
|
+
* cli 侧据此写入 `settings.recent_mentions`(MRU push + 落盘)并调用
|
|
3219
|
+
* `tui.setRecentMentions()` 回推最新列表——单向数据流对齐 onDraftSave/setDrafts。
|
|
3220
|
+
*/
|
|
3221
|
+
onSigilSelect?: (entry: SigilEntry) => void;
|
|
3222
|
+
/** DraftPane 内 d 删除选中草稿(cli 侧从 session.setDrafts 移除 + save)。 */
|
|
3223
|
+
onDraftDelete?: (id: string) => void;
|
|
3224
|
+
/** DraftPane 内 d 批量删除全部勾选(Space 多选)的草稿——单次 setDrafts + 单次 save,
|
|
3225
|
+
* 避免 N 条依次调用 onDraftDelete 触发 N 次并发落盘。 */
|
|
3226
|
+
onDraftDeleteMany?: (ids: string[]) => void;
|
|
3227
|
+
/**
|
|
3228
|
+
* QueueEditDialog「直接发送」:TUI 侧已把该项出队,text/mode 为出队前的原始内容——
|
|
3229
|
+
* cli 层按 mode 分流:'send' 复用 handleSubmit 的 steer/send 语义(busy→steer 注入
|
|
3230
|
+
* 当前回合,idle→立即起新回合);'bash'/'bash_async'/'memory' 走各自原始执行通道
|
|
3231
|
+
* (不套 steer 语义)。见 QueueEditDialog.tsx 头注释。
|
|
3232
|
+
*/
|
|
3233
|
+
onQueueSendNow?: (text: string, mode: SubmitMode) => void;
|
|
3234
|
+
/** enter 键切换对话流到 sub-agent。 */
|
|
3235
|
+
onBackgroundSwitch?: (id: string) => void;
|
|
3236
|
+
/** d 键删除已终结的委派项(cli 据类型分派到对应 registry.remove)。 */
|
|
3237
|
+
onBackgroundDelete?: (id: string) => void;
|
|
3238
|
+
/** esc 退出 sub-agent 对话流(CLI 停轮询 + unpin + retain(false))。 */
|
|
3239
|
+
onSubagentExit?: () => void;
|
|
3240
|
+
/** 持久化输入历史初始条目(从磁盘恢复,传给 PromptInput)。 */
|
|
3241
|
+
initialHistory?: string[];
|
|
3242
|
+
/** RFC-129:外部 shell 历史命令(只读,ghost/Ctrl+R)。 */
|
|
3243
|
+
externalHistoryCommands?: readonly string[];
|
|
3244
|
+
/** 持久化草稿初始列表(随会话快照恢复,cli 侧从 session.session.getDrafts() 读取)。 */
|
|
3245
|
+
initialDrafts?: DraftItemView[];
|
|
3246
|
+
/** 持久化「最近 @ 到的资源」初始列表(cli 侧从 app.settings.get('recent_mentions') 读取,
|
|
3247
|
+
* 结构随 RecentMentionEntry→SigilEntry 转换,见 recent-mentions.ts)。 */
|
|
3248
|
+
initialRecentMentions?: SigilEntry[];
|
|
3249
|
+
/** 每次 push 新历史条目时回调——携带完整 entries 供 CLI 落盘。 */
|
|
3250
|
+
onHistoryPush?: (entries: readonly string[]) => void;
|
|
3251
|
+
/**
|
|
3252
|
+
* RFC-300 M2:加载更早历史(DB 补页)。上滚到内存顶部折叠接缝时调用——
|
|
3253
|
+
* 补页锚由 CLI 侧闭包维护(resume 尾窗口 / 实时启动时 entryCount),TUI 只发
|
|
3254
|
+
* `{limit}` 请求;返回更早消息数组(带稳定 id `hist-<seq>` 与 seq)或 null
|
|
3255
|
+
* (无更早——优雅结束补页)。
|
|
3256
|
+
*/
|
|
3257
|
+
loadHistory?: (req: {
|
|
3258
|
+
limit: number;
|
|
3259
|
+
}) => Promise<ChatMessage[] | null>;
|
|
3260
|
+
onStop?: () => void;
|
|
3261
|
+
}
|
|
3262
|
+
/** 插件面板注册(TUI 侧镜像,同 PluginPane.PanelInfo 但含 id)。 */
|
|
3263
|
+
interface TuiPanelRegistration {
|
|
3264
|
+
/** 面板唯一 id(`pluginId:panelId`)。 */
|
|
3265
|
+
id: string;
|
|
3266
|
+
/** 面板标题。 */
|
|
3267
|
+
title: string;
|
|
3268
|
+
/** 已编译组件的绝对路径(同 PluginPane.PanelInfo.modulePath)。 */
|
|
3269
|
+
modulePath: string;
|
|
3270
|
+
/** 导出名('default' 或具名)。 */
|
|
3271
|
+
exportName: string;
|
|
3272
|
+
/** 面板所属插件 id(RFC-165 M2 T7,供 `usePanelBackend()` 定位 backend server)。 */
|
|
3273
|
+
pluginId?: string;
|
|
3274
|
+
}
|
|
3275
|
+
/**
|
|
3276
|
+
* a2ui 组件渲染函数签名(RFC-105 D1/D6, RFC-155 M155-3),与 `@x-otto/coding
|
|
3277
|
+
* a2ui-component-loader.ts` 的 `PluginA2uiRenderFn` 同构(结构相同、跨包各自定义类型,
|
|
3278
|
+
* 避免 tui→coding 反向类型依赖)。`resolveChild` 由宿主(`a2ui-renderer.ts`)闭包持有
|
|
3279
|
+
* `visited` 循环引用防护,插件侧不可绕过——见 RFC-155 §3 D4。
|
|
3280
|
+
*/
|
|
3281
|
+
type PluginA2uiRenderFn = (component: unknown, columns: number, resolveChild: (id: string) => string[]) => string[];
|
|
3282
|
+
/** 单条已注册的 a2ui 组件(TUI 侧运行时形态)。 */
|
|
3283
|
+
interface RegisteredA2uiComponent {
|
|
3284
|
+
/** 组件类型名(跨插件全局命名空间,供渲染分发按 type 查表)。 */
|
|
3285
|
+
type: string;
|
|
3286
|
+
pluginId: string;
|
|
3287
|
+
render: PluginA2uiRenderFn;
|
|
3288
|
+
}
|
|
3289
|
+
/** 单插件注册数据(宿主侧构造,经 TuiHandle.setPluginRegistrations 喂入)。 */
|
|
3290
|
+
interface PluginRegistration {
|
|
3291
|
+
/** 插件 id(宿主侧传入的 plugin.id,唯一标识)。 */
|
|
3292
|
+
pluginId: string;
|
|
3293
|
+
/** 消息渲染器(原 registerPluginRenderers 的数据)。 */
|
|
3294
|
+
renderers?: readonly RegisteredRenderer[];
|
|
3295
|
+
/** 状态栏文本条目(原 setPluginStatusItems 的数据)。 */
|
|
3296
|
+
statusItems?: readonly {
|
|
3297
|
+
id: string;
|
|
3298
|
+
text: string;
|
|
3299
|
+
}[];
|
|
3300
|
+
/** 插件面板注册。 */
|
|
3301
|
+
panels?: readonly TuiPanelRegistration[];
|
|
3302
|
+
/** 命令表(typeahead 数据源,原 setCommands 的数据)。 */
|
|
3303
|
+
commands?: readonly CommandEntry[];
|
|
3304
|
+
/** a2ui 组件扩展(RFC-105 D1/D6, RFC-155 M155-3:插件扩展 a2ui 渲染 catalog)。 */
|
|
3305
|
+
a2uiComponents?: readonly RegisteredA2uiComponent[];
|
|
3306
|
+
/** 状态栏代码式徽标(RFC-184 D2/D3:插件贡献带颜色语义/动态数据的状态栏徽标)。 */
|
|
3307
|
+
statusWidgets?: readonly RegisteredStatusWidget[];
|
|
3308
|
+
/** 文件查看器候选视图(RFC-187 D3/D5:插件贡献的文件类型专属渲染候选)。 */
|
|
3309
|
+
fileViewers?: readonly RegisteredFileViewer[];
|
|
3310
|
+
}
|
|
3311
|
+
interface TuiModalHandle {
|
|
3312
|
+
/**
|
|
3313
|
+
* 模态对话框统一通道——收敛原 openInfo/openPermissions/openContext/openMemory/
|
|
3314
|
+
* openSelect/openExtensionDetail/openInput/openQuestions/openConfirm 九个独立方法。
|
|
3315
|
+
* 'input'/'questions' 分支返回 Promise(等待用户输入/选择后 resolve),其余七个分支同步
|
|
3316
|
+
* void(fire 回调后立即返回)。三组重载覆盖返回类型正确推断,与判别联合 kind 一一对应。
|
|
3317
|
+
*
|
|
3318
|
+
* ⚠️ 同一 dialog 生命周期内禁止重复调用 openModal(RFC-285)。
|
|
3319
|
+
* 同步路径每次调用都是 router push 新栈条目(非 replace),重复调用会导致对话框堆积、
|
|
3320
|
+
* 用户需多次 Esc 退出。需要更新已打开 dialog 内容时:
|
|
3321
|
+
* - select:使用 `async` 字段(RFC-227),框架自动 replace
|
|
3322
|
+
* - progress:使用 `updateProgress()`,框架自动 replace
|
|
3323
|
+
* - 其他 kind:先关闭当前 dialog(用户操作触发 goBack)再 openModal
|
|
3324
|
+
*/
|
|
3325
|
+
openModal(req: ModalRequestInput): Promise<string | null>;
|
|
3326
|
+
openModal(req: ModalRequestQuestions): Promise<QuestionsAnswer | null>;
|
|
3327
|
+
openModal(req: ModalRequestOnboarding): Promise<OnboardingResult>;
|
|
3328
|
+
openModal(req: ModalRequestVoid): void;
|
|
3329
|
+
/** 通用提示对话框(只读信息 + [OK]):Enter/Esc 解除,回调 onOk。 */
|
|
3330
|
+
openAlert(req: AlertRequest): void;
|
|
3331
|
+
/** 通用单行输入对话框:Enter 提交当前输入,Esc 取消。
|
|
3332
|
+
* 返回 Promise:Enter 提交→输入串,Esc 取消→null。 */
|
|
3333
|
+
openPrompt(req: PromptRequest): Promise<string | null>;
|
|
3334
|
+
/** 更新 install 进度条 dialog 状态(progress modal 打开后调用)。 */
|
|
3335
|
+
updateProgress(partial: ProgressUpdate): void;
|
|
3336
|
+
/**
|
|
3337
|
+
* 程序化 settle 当前在场的 confirm 对话框(等价用户点按钮)。
|
|
3338
|
+
*
|
|
3339
|
+
* 唯一消费方是 `requestStop().escalateToExit()`(Ctrl+C 升级阶梯二级):把在场的停止框
|
|
3340
|
+
* 就地升级为「终止并退出」后,必须**经本方法**走 resolver 通道 settle,而不是绕过它直接
|
|
3341
|
+
* 执行副作用——绕过会导致 resolver 不清空、路由不 goBack,留下无法关闭的孤儿条目。
|
|
3342
|
+
*
|
|
3343
|
+
* 幂等:无 confirm 在场(resolver 已空)时为 no-op。
|
|
3344
|
+
*
|
|
3345
|
+
* @param confirmed true = 确认(触发 onConfirm);false = 取消(触发 onCancel)
|
|
3346
|
+
*/
|
|
3347
|
+
resolveConfirm(confirmed: boolean): void;
|
|
3348
|
+
/** 权限请求:渲染对话框并等用户决定(工具使用确认队列)。
|
|
3349
|
+
* 返回 approved + mode('always'=用户选「始终允许」,cli 据此持久化)。 */
|
|
3350
|
+
requestPermission(req: {
|
|
3351
|
+
tool: string;
|
|
3352
|
+
input: string;
|
|
3353
|
+
risk?: 'low' | 'medium' | 'high';
|
|
3354
|
+
description?: string; /** bash「始终允许」拟持久化的命令前缀(如 `git status`),弹窗显式呈现给用户。 */
|
|
3355
|
+
alwaysAllowLabel?: string;
|
|
3356
|
+
}): Promise<PermissionDecision>;
|
|
3357
|
+
}
|
|
3358
|
+
interface TuiPendingHandle {
|
|
3359
|
+
/** 标记最后一条 user echo 为『pending』——ESC 撤回窗口的起点。 */
|
|
3360
|
+
setPendingEcho(text: string, mode: string): void;
|
|
3361
|
+
/** 模型已接起首字节,关闭 ESC 撤回窗口(pending 转正)。 */
|
|
3362
|
+
clearPendingEcho(): void;
|
|
3363
|
+
/** ESC 撤回 pending 消息——从对话流移除最后一条 user echo + 回填输入框 + 清 pendingEcho。 */
|
|
3364
|
+
withdrawPendingEcho(): void;
|
|
3365
|
+
/** RFC-337 D3:注入一条运行中追加(steer)的待定 echo(延迟 commit,live 区渲染)。 */
|
|
3366
|
+
setPendingSteer(text: string, id: string): void;
|
|
3367
|
+
/** RFC-337 D3:steer 被模型消费 → 转正 commit 到 scrollback(此后不再可撤回)。 */
|
|
3368
|
+
commitPendingSteer(id: string): void;
|
|
3369
|
+
/** RFC-337 D3:ESC 撤回未被消费的 steer 追加——清 live 区渲染,不 commit。 */
|
|
3370
|
+
withdrawPendingSteer(id: string): void;
|
|
3371
|
+
/** RFC-337 D3:回合结束时清空所有仍待定的 steer(未被消费的 steer 不会再进上下文,防跨回合残留)。 */
|
|
3372
|
+
clearPendingSteers(): void;
|
|
3373
|
+
/** 把指定文本回填到 PromptInput(ESC 撤回时用)。 */
|
|
3374
|
+
restoreInputText(text: string): void;
|
|
3375
|
+
/** RFC-338:把持久化的粘贴缓存恢复进输入框 store(启动/切会话/fork 时调用)。 */
|
|
3376
|
+
hydratePaste(snapshot: PasteSnapshot | null | undefined): void;
|
|
3377
|
+
/** RFC-338:导出当前粘贴缓存快照供落盘;桥未就绪(TUI 未挂载)时返回 null。 */
|
|
3378
|
+
exportPaste(): PasteSnapshot | null;
|
|
3379
|
+
}
|
|
3380
|
+
interface TuiPanesHandle {
|
|
3381
|
+
/** 面板 open/toggle 统一通道——收敛原 toggleHistory/toggleBackgroundTasks/
|
|
3382
|
+
* toggleDraftPane/toggleQueuePane/toggleNotifications/toggleInspector/openSchedulePane/
|
|
3383
|
+
* openPerf/openCacheStats/openGallery 十个独立方法。 */
|
|
3384
|
+
togglePane(name: PaneName, open?: boolean): void;
|
|
3385
|
+
/** 打开/关闭 /services 进程服务列表面板。 */
|
|
3386
|
+
setServices(open: boolean): void;
|
|
3387
|
+
/** 切换到 sub-agent 对话流。传入 null 清除(esc)。 */
|
|
3388
|
+
switchToSubagentContext(ctx: SubagentContext | null): void;
|
|
3389
|
+
/** 开关编辑文件面板(Ctrl+V)。open 省略=翻转。 */
|
|
3390
|
+
toggleEditedFiles(open?: boolean): void;
|
|
3391
|
+
/** 清空编辑文件列表。 */
|
|
3392
|
+
clearEditedFiles(): void;
|
|
3393
|
+
/** 按索引删除一条排队项(QueuePane 内 d 键)。 */
|
|
3394
|
+
removeQueuedAt(index: number): void;
|
|
3395
|
+
/** 清空全部排队项(/queue clear)。 */
|
|
3396
|
+
clearQueue(): void;
|
|
3397
|
+
/** 把队列中 index 处的项移动 delta 位(-1=上移/下移+1,越界时 no-op)(QueuePane 内 J/K 键)。 */
|
|
3398
|
+
moveQueuedItem(index: number, delta: number): void;
|
|
3399
|
+
}
|
|
3400
|
+
interface TuiPluginsHandle {
|
|
3401
|
+
/** 统一插件注册入口——替代 setPluginStatusItems 等 4 个独立方法。 */
|
|
3402
|
+
setPluginRegistrations(regs: readonly PluginRegistration[]): void;
|
|
3403
|
+
/** 按源卸载插件全部贡献(热重载/禁用时调用)。 */
|
|
3404
|
+
unregisterPluginSource(pluginId: string): void;
|
|
3405
|
+
/** 存量委托:插件状态栏文本条目(被 setPluginRegistrations 替代)。 */
|
|
3406
|
+
setPluginStatusItems: (items: Array<{
|
|
3407
|
+
icon: string;
|
|
3408
|
+
text: string;
|
|
3409
|
+
color?: 'warning' | 'default';
|
|
3410
|
+
}>) => void;
|
|
3411
|
+
/** 更新斜杠命令表(typeahead 数据源);语言切换后 cli 回推本地化描述。 */
|
|
3412
|
+
setCommands(commands: CommandEntry[]): void;
|
|
3413
|
+
/** 注册斜杠命令的参数补全函数。 */
|
|
3414
|
+
registerArgumentSuggester(command: string, suggester: (prefix: string, maxResults?: number) => Array<{
|
|
3415
|
+
name: string;
|
|
3416
|
+
description?: string;
|
|
3417
|
+
}>): void;
|
|
3418
|
+
/** 注册当前消息流中的 A2UI 按钮(用于数字键 1-9 快捷触发)。 */
|
|
3419
|
+
setA2uiButtons(buttons: A2uiButtonInfo[]): void;
|
|
3420
|
+
/** 注入持久化恢复的子代理条目到累计 Map(--continue 重建面板)。 */
|
|
3421
|
+
addSubagent(entry: {
|
|
3422
|
+
id: string;
|
|
3423
|
+
name: string;
|
|
3424
|
+
status: 'running' | 'done' | 'error' | 'killed';
|
|
3425
|
+
startedAt?: number;
|
|
3426
|
+
}): void;
|
|
3427
|
+
/** 获取子代理累计 Map(供持久化,stat-only)。 */
|
|
3428
|
+
getSubagents(): ReadonlyMap<string, BackgroundTaskSummary>;
|
|
3429
|
+
/** 清空子代理累计列表(跨回合重置)。 */
|
|
3430
|
+
clearSubagents(): void;
|
|
3431
|
+
}
|
|
3432
|
+
interface TuiInfoHandle {
|
|
3433
|
+
/** 推送一条通知到通知中心(状态栏铃铛 +1,ctrl+n 查看)。 */
|
|
3434
|
+
pushNotification(title: string, message: string, source?: AppNotification['source'], level?: AppNotification['level']): void;
|
|
3435
|
+
/** 消除单条通知。 */
|
|
3436
|
+
dismissNotification(id: number): void;
|
|
3437
|
+
/** 全部标已读(esc 关闭通知中心时)。 */
|
|
3438
|
+
markAllNotificationsRead(): void;
|
|
3439
|
+
/** 读取 notify scheduler 统计(coalesced 调用/触发、immediate 调用、flush 触发)。 */
|
|
3440
|
+
getNotifyStats(): NotifyStats;
|
|
3441
|
+
/** 当前路由路径(树外只读探针)。 */
|
|
3442
|
+
getCurrentPath(): string;
|
|
3443
|
+
/** 当前是否有强制升级横幅在场(taskStore.forcedUpgrade 非 null)。 */
|
|
3444
|
+
isForcedUpgradeActive(): boolean;
|
|
3445
|
+
/** 是否有全屏/独占视口面板在场(子代理详情、后台任务输出、编辑文件全屏、shell 执行面板等)。 */
|
|
3446
|
+
isFullScreenPaneActive(): boolean;
|
|
3447
|
+
/** 读取当前 shell 执行的结构化快照(RFC-225 M2)。 */
|
|
3448
|
+
getShellExecutionSnapshot(): {
|
|
3449
|
+
command: string;
|
|
3450
|
+
output: string;
|
|
3451
|
+
exitCode: number | null;
|
|
3452
|
+
terminated?: boolean;
|
|
3453
|
+
} | null;
|
|
3454
|
+
/** 追加一条对话回合行到 ContextDetailPane(CLI 从会话消息构建)。 */
|
|
3455
|
+
addContextTurn(row: ConversationTurnRow): void;
|
|
3456
|
+
/** 批量更新回合标记(compacted/truncated/pruned —— trace 事件驱动)。 */
|
|
3457
|
+
markContextTurns(patch: {
|
|
3458
|
+
turnIndex: number;
|
|
3459
|
+
} & Partial<ConversationTurnRow>): void;
|
|
3460
|
+
/** 弹出 toast 通知(自动 2 秒消失,不占用对话历史)。 */
|
|
3461
|
+
showToast(title: string, content: string): void;
|
|
3462
|
+
/** 从 Home 进入某会话视图。cli 首次 prompt(interactive-events prompt.start)
|
|
3463
|
+
* 或切会话/resume 后单向下推。 */
|
|
3464
|
+
setTopView(view: {
|
|
3465
|
+
session: string;
|
|
3466
|
+
}): void;
|
|
3467
|
+
}
|
|
3468
|
+
interface TuiEngineHandle {
|
|
3469
|
+
/** 高频流式事件统一通道——收敛原 8 个独立 setter 为单一判别联合方法。 */
|
|
3470
|
+
pushEngineEvent(event: TuiStreamEvent): void;
|
|
3471
|
+
/** 是否有待跑的 follow-up(state.queued 非空)——cli 喂 app 抑制完成通知。 */
|
|
3472
|
+
hasQueuedFollowUp(): boolean;
|
|
3473
|
+
/** 取出最近追加的 follow-up。错误重试优先消费最近追加意图,而非最早失败原 prompt。 */
|
|
3474
|
+
takeLastQueuedFollowUp?(): {
|
|
3475
|
+
text: string;
|
|
3476
|
+
mode: SubmitMode;
|
|
3477
|
+
} | undefined;
|
|
3478
|
+
/**
|
|
3479
|
+
* 把一条提交塞进"回合之后"队列(state.queued,与 Shift+Enter 同一队列),引擎空闲时自动出队起新回合。
|
|
3480
|
+
* 供 cli 兜底:若消息因镜像态去同步漏到"引擎仍忙却走起新回合"的路,按此回落到回合后队列,
|
|
3481
|
+
* 而非撞裸 prompt() 抛错。出队由 drainQueue 以引擎真·忙判定为闸,不会在忙时立即回拉打转。
|
|
3482
|
+
*/
|
|
3483
|
+
enqueueFollowUp(text: string, mode?: SubmitMode): void;
|
|
3484
|
+
/** 设置暂停浮层数据。非 null 时 App.tsx 渲染 PauseDialog 组件。 */
|
|
3485
|
+
setPauseDialog(item: PauseDialogItem | null): void;
|
|
3486
|
+
/** 展示退避重试倒计时条。 */
|
|
3487
|
+
showRetryDialog(attempt: number, max: number, delayMs: number, accelerate: {
|
|
3488
|
+
skip: boolean;
|
|
3489
|
+
}, onExpired: () => void, reason?: string, onStop?: () => void): void;
|
|
3490
|
+
/** 强制清除当前退避倒计时。 */
|
|
3491
|
+
clearRetryDialog(): void;
|
|
3492
|
+
/** 展示统一错误重试卡片(覆盖回合终止性错误的全部场景)。 */
|
|
3493
|
+
showErrorRetry(item: {
|
|
3494
|
+
reason: string;
|
|
3495
|
+
attempt: number;
|
|
3496
|
+
max: number;
|
|
3497
|
+
mode: 'auto' | 'resetsAt' | 'manual';
|
|
3498
|
+
resetsAt?: number;
|
|
3499
|
+
limitType?: RateLimitType;
|
|
3500
|
+
actions: Array<{
|
|
3501
|
+
kind: ErrorRetryActionKind;
|
|
3502
|
+
label: string;
|
|
3503
|
+
run: () => void;
|
|
3504
|
+
}>;
|
|
3505
|
+
exhausted?: boolean;
|
|
3506
|
+
onExpired: () => void;
|
|
3507
|
+
onCancel: () => void; /** RFC-153 D6:错误来源插件 id;undefined=非插件来源,卡片不展示来源行。 */
|
|
3508
|
+
pluginSource?: string; /** RFC-230:mode='auto' 自动倒计时秒数(默认 30,可经 ResilienceConfig.errorRetry.intervalMs 覆盖)。 */
|
|
3509
|
+
intervalSeconds?: number;
|
|
3510
|
+
}): void;
|
|
3511
|
+
/** 强制清除当前错误重试卡片。 */
|
|
3512
|
+
clearErrorRetry(): void;
|
|
3513
|
+
}
|
|
3514
|
+
interface TuiMessagesHandle {
|
|
3515
|
+
/** 追加一条对话消息到转录(scrollback/window 双模内部分流)。 */
|
|
3516
|
+
pushMessage(msg: ChatMessage): void;
|
|
3517
|
+
/** 批量提交多条历史(resume/会话切换回放):scrollback 模式下合成单次写出 →
|
|
3518
|
+
* 避免逐条 inkWrite 的 N 次 live 区清/还原抖动(缓冲整段后单次 flush)。 */
|
|
3519
|
+
pushMessages(msgs: readonly ChatMessage[]): void;
|
|
3520
|
+
/** 回显用户输入。`pending=true` 标记为 pending 态(dim 渲染 + ESC 可撤回)。 */
|
|
3521
|
+
echoUserInput(text: string, opts?: {
|
|
3522
|
+
pending?: boolean;
|
|
3523
|
+
}): void;
|
|
3524
|
+
/** 按回合编号获取对应消息列表(turn 1-based)。 */
|
|
3525
|
+
getTurnMessages(turn: number): ChatMessage[];
|
|
3526
|
+
/** 获取当前回合边界数组快照。 */
|
|
3527
|
+
getTurnBoundaries(): number[];
|
|
3528
|
+
/** 获取当前编辑文件列表快照(持久化用)。 */
|
|
3529
|
+
getEditedFiles(): EditedFileEntry[];
|
|
3530
|
+
}
|
|
3531
|
+
interface TuiLifecycleHandle {
|
|
3532
|
+
/** 停止 TUI(卸载 Ink 渲染树 + 清理平台副作用)。 */
|
|
3533
|
+
stop(): void;
|
|
3534
|
+
/** 清屏并重置会话界面状态(/clear):
|
|
3535
|
+
* - 清终端(ANSI \x1B[2J\x1B[H)和 scrollback 状态
|
|
3536
|
+
* - 清除任务面板、委托面板、动态区状态
|
|
3537
|
+
* - 重新显示欢迎横幅
|
|
3538
|
+
*/
|
|
3539
|
+
clearSession(): void;
|
|
3540
|
+
/** 运行时切语言(/lang 或 Ctrl+Y);返回最终生效的具体语言。notify 全树重渲即时生效。 */
|
|
3541
|
+
setLanguage(mode: LangMode): Lang;
|
|
3542
|
+
/**
|
|
3543
|
+
* RFC-277 M6 / RFC-283:运行时切换/预览 preset 选择(`/preference theme` 高亮移动即预览、确认
|
|
3544
|
+
* 后落定;传 `undefined` 清空回退到各 appearance 的 builtin preset)。深浅自动跟随终端背景色。
|
|
3545
|
+
*/
|
|
3546
|
+
setPresetSelection?(selection: ThemePresetSelection | undefined): void;
|
|
3547
|
+
/** 写入终端窗口标题(OSC 0,\x1b]0;...\x07)。非 tty 时无操作。
|
|
3548
|
+
* 标题经 sanitize 后写入:strip 控制字符、零宽字符、压缩空白、truncate 240 字符。 */
|
|
3549
|
+
setTerminalTitle(title: string): void;
|
|
3550
|
+
/** RFC-312 D5:切换鼠标协议(应用内选择 ↔ 终端原生选择)。返回切换后状态。
|
|
3551
|
+
* 闭包捕获 handle 引用——调用时 handle.info.showToast 已存在(非构造期)。 */
|
|
3552
|
+
toggleMouse(): boolean;
|
|
3553
|
+
/** RFC-335 T335-07:attach source belongs to this TUI root; lifecycle.stop detaches it. */
|
|
3554
|
+
attachSessionSource(source: SessionDataSource): Promise<() => void>;
|
|
3555
|
+
/** Stop the attached source explicitly; idempotent. */
|
|
3556
|
+
detachSessionSource(): void;
|
|
3557
|
+
}
|
|
3558
|
+
interface TuiShellHandle {
|
|
3559
|
+
/** 开始异步 shell 执行面板(`!! <cmd>`)。显示固定高度输出区,non-blocking。 */
|
|
3560
|
+
startShellExecution(command: string): void;
|
|
3561
|
+
/** 追加输出到 shell 执行面板。 */
|
|
3562
|
+
appendShellOutput(text: string): void;
|
|
3563
|
+
/** 完成 shell 执行:更新退出码/状态。面板保持打开,由用户 Esc 手动关闭。 */
|
|
3564
|
+
finishShellExecution(exitCode: number | null, error?: string, terminated?: boolean): void;
|
|
3565
|
+
/** 手动关闭 shell 执行面板。 */
|
|
3566
|
+
dismissShellExecution(): void;
|
|
3567
|
+
/** 复制当前 shell 执行的完整输出到系统剪贴板(OSC 52,RFC-225 M1)。纯读操作。 */
|
|
3568
|
+
copyShellOutput(): void;
|
|
3569
|
+
/** 读取当前 shell 执行的结构化快照(RFC-225 M2,供 cli 层组装"问 AI"消息)。 */
|
|
3570
|
+
getShellExecutionSnapshot(): {
|
|
3571
|
+
command: string;
|
|
3572
|
+
output: string;
|
|
3573
|
+
exitCode: number | null;
|
|
3574
|
+
terminated?: boolean;
|
|
3575
|
+
} | null;
|
|
3576
|
+
}
|
|
3577
|
+
interface TuiHandle {
|
|
3578
|
+
/**
|
|
3579
|
+
* RFC-347 M1:模态对话框/问询/权限确认能力的领域命名空间。
|
|
3580
|
+
* 调用方应使用 `tui.modal.openModal(...)`/`tui.modal.openAlert(...)`/...
|
|
3581
|
+
*/
|
|
3582
|
+
readonly modal: TuiModalHandle;
|
|
3583
|
+
/**
|
|
3584
|
+
* RFC-347 M1.1:pending echo/pending steer/输入框回填/粘贴缓存的领域命名空间。
|
|
3585
|
+
* 调用方应使用 `tui.pending.setPendingEcho(...)`/`tui.pending.withdrawPendingEcho(...)`/...
|
|
3586
|
+
*/
|
|
3587
|
+
readonly pending: TuiPendingHandle;
|
|
3588
|
+
/**
|
|
3589
|
+
* RFC-347 M1.2:生命周期/全局配置能力(stop/clearSession/语言/主题/终端元信息/鼠标切换)。
|
|
3590
|
+
* 调用方应使用 `tui.lifecycle.stop()`/`tui.lifecycle.setLanguage(...)`/...
|
|
3591
|
+
*/
|
|
3592
|
+
readonly lifecycle: TuiLifecycleHandle;
|
|
3593
|
+
/**
|
|
3594
|
+
* RFC-347 M1.3:消息回显/转录获取能力的领域命名空间。
|
|
3595
|
+
* 调用方应使用 `tui.messages.pushMessage(...)`/`tui.messages.getTurnMessages(...)`/...
|
|
3596
|
+
*/
|
|
3597
|
+
readonly messages: TuiMessagesHandle;
|
|
3598
|
+
/**
|
|
3599
|
+
* RFC-347 M1.4:引擎事件推送 + 暂停/重试/错误卡片浮层 + 回合后队列管理的领域命名空间。
|
|
3600
|
+
* 调用方应使用 `tui.engine.pushEngineEvent(...)`/`tui.engine.showErrorRetry(...)`/...
|
|
3601
|
+
*/
|
|
3602
|
+
readonly engine: TuiEngineHandle;
|
|
3603
|
+
/**
|
|
3604
|
+
* RFC-347 M1.5:面板开关(togglePane/setServices/switchToSubagentContext 等 +
|
|
3605
|
+
* 队列管理(removeQueuedAt/clearQueue/moveQueuedItem)领域命名空间。
|
|
3606
|
+
* 调用方应使用 `tui.panes.togglePane(...)`/`tui.panes.setServices(...)`/...。
|
|
3607
|
+
*/
|
|
3608
|
+
readonly panes: TuiPanesHandle;
|
|
3609
|
+
/**
|
|
3610
|
+
* RFC-347 M1.5:插件注册(setPluginRegistrations/unregisterPluginSource 等 +
|
|
3611
|
+
* 子代理数据(addSubagent/getSubagents/clearSubagents)领域命名空间。
|
|
3612
|
+
*/
|
|
3613
|
+
readonly plugins: TuiPluginsHandle;
|
|
3614
|
+
/**
|
|
3615
|
+
* RFC-347 M1.5:通知中心(pushNotification/dismissNotification 等 + 状态读取
|
|
3616
|
+
* (getNotifyStats/getCurrentPath/isForcedUpgradeActive 等 + context feed + toast + topView。
|
|
3617
|
+
*/
|
|
3618
|
+
readonly info: TuiInfoHandle;
|
|
3619
|
+
/** RFC-347 终局:shell 执行面板生命周期域。调用方经 `tui.shell.*` 访问。 */
|
|
3620
|
+
readonly shell: TuiShellHandle;
|
|
3621
|
+
/**
|
|
3622
|
+
* RFC-333 M2-B:store 引用出口(D1 方案A)。cli 经此直接调 store action 写数据,
|
|
3623
|
+
* 逐步替代 TuiHandle 上的字段 setter——store 成为唯一写入汇聚点(T335-07 换 writer 的 seam)。
|
|
3624
|
+
* 迁移期只暴露已收敛为 action 的 store 域;每迁完一组即从本对象加入、并从 TuiHandle 删对应 setter。
|
|
3625
|
+
*/
|
|
3626
|
+
stores: {
|
|
3627
|
+
tasks: TaskActions;
|
|
3628
|
+
budget: Pick<BudgetStore, 'setBudget'>;
|
|
3629
|
+
context: Pick<ContextStore, 'setBudget' | 'addTurn' | 'markTurns'>;
|
|
3630
|
+
cache: Pick<CacheStore, 'setView'>;
|
|
3631
|
+
proxy: Pick<ProxyStore, 'setView'>;
|
|
3632
|
+
notification: Pick<NotificationStore, 'setProviderUsage' | 'setPausePending' | 'setPaused' | 'setPulseSurvey'>;
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3635
|
+
/** 一条草稿记录(DraftPane 数据源 · /draft 命令 · Ctrl+S/O)。 */
|
|
3636
|
+
interface DraftItemView {
|
|
3637
|
+
id: string;
|
|
3638
|
+
name: string;
|
|
3639
|
+
text: string;
|
|
3640
|
+
savedAt: number;
|
|
3641
|
+
}
|
|
3642
|
+
/** 模态单选请求(openSelect 入参)。 */
|
|
3643
|
+
interface SelectRequest {
|
|
3644
|
+
title?: string;
|
|
3645
|
+
subtitle?: string;
|
|
3646
|
+
/** 副标题语义色调:default=普通弱化提示;warning=需要用户处理的醒目提示。 */
|
|
3647
|
+
subtitleTone?: 'default' | 'warning';
|
|
3648
|
+
options: SelectOption[];
|
|
3649
|
+
onSelect: (value: string) => void;
|
|
3650
|
+
onCancel?: () => void;
|
|
3651
|
+
/** 单屏可见物理行数(默认 10;/model、/resume 可加高)。 */
|
|
3652
|
+
maxVisible?: number;
|
|
3653
|
+
/** 开启搜索过滤输入框(如 /resume 会话列表)。 */
|
|
3654
|
+
searchable?: boolean;
|
|
3655
|
+
/** 渲染形式:'list'(默认)|'buttons'(横排 [ 按钮 ] 行,Tab 切换)|'tabs'(横排选项卡,Tab 切换)。 */
|
|
3656
|
+
layout?: 'list' | 'buttons' | 'tabs';
|
|
3657
|
+
/** 副标题内联动作按钮(list 模式逃生口,如无可用模型时的 [登录]/[配置凭证]);触发经 onSelect 回吐其 value。 */
|
|
3658
|
+
subtitleActions?: Array<{
|
|
3659
|
+
label: string;
|
|
3660
|
+
value: string;
|
|
3661
|
+
}>;
|
|
3662
|
+
/**
|
|
3663
|
+
* detail 排布位置(RFC-292 D1):`'below'`(缺省)detail 独占条目下方一行(适合变长
|
|
3664
|
+
* 多段文本,如 `/model` 的 `coding/reasoning/knowledge`);`'inline'` detail 并入 label
|
|
3665
|
+
* 同一行右侧、按组内最大宽度对齐(适合短徽章,如 `/login` provider 选择的 `订阅`/`密钥`)。
|
|
3666
|
+
*/
|
|
3667
|
+
detailPlacement?: 'below' | 'inline';
|
|
3668
|
+
/**
|
|
3669
|
+
* 初始过滤文本(searchable 模式)——modal 被销毁重建的场景下恢复用户上次输入的
|
|
3670
|
+
* 过滤词(如 `/open` 目录浏览器)。缺省空串。
|
|
3671
|
+
*/
|
|
3672
|
+
initialFilter?: string;
|
|
3673
|
+
/** 过滤文本变化回调——调用方据此持久化过滤词,供下次重建时经 initialFilter 回灌。 */
|
|
3674
|
+
onFilterChange?: (text: string) => void;
|
|
3675
|
+
/**
|
|
3676
|
+
* RFC-277 M6:高亮项变化回调(移动即预览,语义同 `SelectDialogProps.onHighlight`)。
|
|
3677
|
+
* 与 `onSelect`(Enter 确认)分离,调用方不应假定 onHighlight 代表用户已确认。
|
|
3678
|
+
*/
|
|
3679
|
+
onHighlight?: (value: string) => void;
|
|
3680
|
+
/** 初始游标位置——按 value 匹配 options(偏好面板返回父级时保留游标位置)。 */
|
|
3681
|
+
defaultSelectedValue?: string;
|
|
3682
|
+
/**
|
|
3683
|
+
* RFC-253 续/偏好面板闪动修复:就地替换当前 select 弹窗的 state(不 push 新栈条目)。
|
|
3684
|
+
* 用于「布尔项就地翻转」这类**同一弹窗内容原地更新**场景——避免每次翻转都 openModal
|
|
3685
|
+
* 重开导致整屏闪动/Esc 栈堆积(RFC-285 D2 的 re-entrant push 问题)。仅当当前路由已是
|
|
3686
|
+
* `/dialog/select` 时生效(等价 async 路径的 `navigate(replace:true)` 语义);否则退化为
|
|
3687
|
+
* 正常 push。SelectDialog 组件不重挂 → 本地 useState(过滤/游标)保留、无闪动。
|
|
3688
|
+
*/
|
|
3689
|
+
replace?: boolean;
|
|
3690
|
+
/**
|
|
3691
|
+
* RFC-227:异步内容加载 promise——调用方声明"options/subtitle/title 不是同步可用的",
|
|
3692
|
+
* 需经一次 async 操作(如网络请求、SQLite 扫描)才能构造。框架层自动展示 loading 占位
|
|
3693
|
+
* (options=[] 空数组,subtitle 展示 loading 文案),resolve 后原地过渡为真实内容。
|
|
3694
|
+
*
|
|
3695
|
+
* ⚠️ 仅对 `kind: 'select'` 有效——传入其他 modal 类型时被框架层静默丢弃(R1)。
|
|
3696
|
+
* 与 `options` 互斥——传了 `async` 就不该传 `options`(框架层以 async 优先),
|
|
3697
|
+
* 但 TypeScript 类型层面不会报错(非类型级互斥)。
|
|
3698
|
+
*/
|
|
3699
|
+
async?: Promise<SelectAsyncContent>;
|
|
3700
|
+
}
|
|
3701
|
+
/**
|
|
3702
|
+
* RFC-227 D3:`SelectRequest.async` resolve 的返回值——框架层 merge 回原始
|
|
3703
|
+
* `SelectRequest` 的不变字段(`onSelect`/`onCancel`/`layout`/`searchable`/
|
|
3704
|
+
* `subtitleActions` 等),实现"一次声明、自动过渡"。
|
|
3705
|
+
*
|
|
3706
|
+
* merge 策略:`{ ...req, ...content }`——content 中的字段覆盖 req 中的同名字段,
|
|
3707
|
+
* 不在本接口中的字段保持调用方原始值不变(纯透传,lesson_104 纪律)。
|
|
3708
|
+
*/
|
|
3709
|
+
interface SelectAsyncContent {
|
|
3710
|
+
/** 异步加载完成后替换 loading title 的新标题(可选;缺省保持 loading 态 title)。
|
|
3711
|
+
* 例:/search loading title "Search 'keyword'" → resolve 后 "Search 'keyword' — 20 hits"。 */
|
|
3712
|
+
title?: string;
|
|
3713
|
+
/** 异步加载完成后替换 loading subtitle 的新文案(可选)。 */
|
|
3714
|
+
subtitle?: string;
|
|
3715
|
+
/** 异步加载完成后的真实选项列表。 */
|
|
3716
|
+
options: SelectOption[];
|
|
3717
|
+
}
|
|
3718
|
+
/** 模态输入请求(openInput 入参)。 */
|
|
3719
|
+
interface InputRequest {
|
|
3720
|
+
title?: string;
|
|
3721
|
+
/** 正文描述行(如 OAuth 授权 URL),展示在标题与输入框之间,支持多行、自动换行。 */
|
|
3722
|
+
description?: string[];
|
|
3723
|
+
placeholder?: string;
|
|
3724
|
+
/** 初始值(预填输入框,如 /fork 的命名预填源会话标题)。 */
|
|
3725
|
+
defaultValue?: string;
|
|
3726
|
+
mask?: boolean;
|
|
3727
|
+
/** 外部取消信号(如 OAuth loopback 回调先完成):abort 时关闭输入框并 resolve null。 */
|
|
3728
|
+
signal?: AbortSignal;
|
|
3729
|
+
/** 输入框下方可选的 action 按钮(如 OAuth 流程里的「打开浏览器」)。 */
|
|
3730
|
+
actionButton?: {
|
|
3731
|
+
label: string;
|
|
3732
|
+
onPress: () => void;
|
|
3733
|
+
};
|
|
3734
|
+
}
|
|
3735
|
+
/** 多问题复核请求(openQuestions 入参)。 */
|
|
3736
|
+
interface QuestionsRequest {
|
|
3737
|
+
title?: string;
|
|
3738
|
+
questions: Question[];
|
|
3739
|
+
}
|
|
3740
|
+
/** 通用确认对话框请求(openConfirm 入参)。 */
|
|
3741
|
+
interface ConfirmRequest {
|
|
3742
|
+
title: string;
|
|
3743
|
+
/** 正文(单行或多行)。 */
|
|
3744
|
+
message: string | string[];
|
|
3745
|
+
/** 确认按钮文案(默认 i18next.t('common.confirmButton'))。 */
|
|
3746
|
+
confirmLabel?: string;
|
|
3747
|
+
/** 取消按钮文案(默认 i18next.t('common.genericCancelButton'))。 */
|
|
3748
|
+
cancelLabel?: string;
|
|
3749
|
+
/** 确认按钮颜色(默认 'accent')。 */
|
|
3750
|
+
confirmColor?: 'accent' | 'amber' | 'red' | 'green';
|
|
3751
|
+
/** 破坏性确认:默认焦点落「取消」(中止/删除等防误触)。 */
|
|
3752
|
+
dangerous?: boolean;
|
|
3753
|
+
/** 可选的第三个按钮(位置在确认和取消之间)。不传=双按钮。 */
|
|
3754
|
+
extraLabel?: string;
|
|
3755
|
+
/** 第三个按钮颜色(默认 'amber')。 */
|
|
3756
|
+
extraColor?: 'accent' | 'amber' | 'red' | 'green';
|
|
3757
|
+
onConfirm: () => void;
|
|
3758
|
+
onCancel?: () => void;
|
|
3759
|
+
/** 第三个按钮回调(仅在 extraLabel 提供时生效)。 */
|
|
3760
|
+
onExtra?: () => void;
|
|
3761
|
+
}
|
|
3762
|
+
/** 通用提示对话框请求(openAlert 入参)。 */
|
|
3763
|
+
interface AlertRequest {
|
|
3764
|
+
title: string;
|
|
3765
|
+
/** 正文(单行或多行)。 */
|
|
3766
|
+
message: string | string[];
|
|
3767
|
+
/** OK 按钮文案(默认 i18next.t('common.okButton'))。 */
|
|
3768
|
+
okLabel?: string;
|
|
3769
|
+
onOk?: () => void;
|
|
3770
|
+
}
|
|
3771
|
+
/** 通用单行文本输入对话框请求(openPrompt 入参)。 */
|
|
3772
|
+
interface PromptRequest {
|
|
3773
|
+
title?: string;
|
|
3774
|
+
/** 提示正文(单行或多行)。 */
|
|
3775
|
+
message?: string | string[];
|
|
3776
|
+
placeholder?: string;
|
|
3777
|
+
initialValue?: string;
|
|
3778
|
+
/** 提交按钮文案(默认 i18next.t('prompt.submitButton'))。 */
|
|
3779
|
+
submitLabel?: string;
|
|
3780
|
+
/** 取消按钮文案(默认 i18next.t('common.genericCancelButton'))。 */
|
|
3781
|
+
cancelLabel?: string;
|
|
3782
|
+
}
|
|
3783
|
+
interface PermissionDecision {
|
|
3784
|
+
approved: boolean;
|
|
3785
|
+
mode?: 'once' | 'always';
|
|
3786
|
+
}
|
|
3787
|
+
/** sub-agent 对话流上下文切换时 TuiHandle.switchToSubagentContext 的入参。 */
|
|
3788
|
+
interface SubagentContext {
|
|
3789
|
+
id: string;
|
|
3790
|
+
title: string;
|
|
3791
|
+
messages: ChatMessage[];
|
|
3792
|
+
status: 'running' | 'needs_input' | 'ready' | 'applied' | 'failed' | 'canceled';
|
|
3793
|
+
/** 诊断块(卡死/空闲/blockedOn 等,来自 agentDiagnostics)。 */
|
|
3794
|
+
diagnostics?: string[];
|
|
3795
|
+
/** turn timeline 行。 */
|
|
3796
|
+
timeline?: string[];
|
|
3797
|
+
/** 流式中 in-flight 文本(running 态持续刷新)。 */
|
|
3798
|
+
streamText?: string;
|
|
3799
|
+
}
|
|
3800
|
+
//#endregion
|
|
3801
|
+
//#region src/dialogs/ConfirmDialog.d.ts
|
|
3802
|
+
interface ConfirmDialogProps {
|
|
3803
|
+
title: string;
|
|
3804
|
+
/** 正文(单行或多行)。 */
|
|
3805
|
+
message: string | string[];
|
|
3806
|
+
/** 确认按钮文案(默认 i18next.t('common.confirmButton'))。 */
|
|
3807
|
+
confirmLabel?: string;
|
|
3808
|
+
/** 取消按钮文案(默认 i18next.t('common.genericCancelButton'))。 */
|
|
3809
|
+
cancelLabel?: string;
|
|
3810
|
+
/** 确认按钮颜色(默认 'accent')。 */
|
|
3811
|
+
confirmColor?: 'accent' | 'amber' | 'red' | 'green';
|
|
3812
|
+
/** 破坏性确认(如中止/删除):默认焦点落在安全的「取消」上,防 Enter 误触。 */
|
|
3813
|
+
dangerous?: boolean;
|
|
3814
|
+
/** 可选的第三个按钮(位置在确认和取消之间)。不传=双按钮。 */
|
|
3815
|
+
extraLabel?: string;
|
|
3816
|
+
/** 第三个按钮颜色(默认 'amber')。 */
|
|
3817
|
+
extraColor?: 'accent' | 'amber' | 'red' | 'green';
|
|
3818
|
+
/** 可选的勾选框文案(如"不再提醒")。不传=不渲染勾选框。 */
|
|
3819
|
+
checkLabel?: string;
|
|
3820
|
+
/** 勾选框初始状态(默认未勾选)。 */
|
|
3821
|
+
checked?: boolean;
|
|
3822
|
+
onConfirm: () => void;
|
|
3823
|
+
onCancel: () => void;
|
|
3824
|
+
/** 第三个按钮回调(仅在 extraLabel 提供时生效)。 */
|
|
3825
|
+
onExtra?: () => void;
|
|
3826
|
+
/** 勾选框变化回调(仅在 checkLabel 提供时生效)。 */
|
|
3827
|
+
onCheckChange?: (checked: boolean) => void;
|
|
3828
|
+
}
|
|
3829
|
+
declare function ConfirmDialog({
|
|
3830
|
+
title,
|
|
3831
|
+
message,
|
|
3832
|
+
confirmLabel,
|
|
3833
|
+
cancelLabel,
|
|
3834
|
+
confirmColor,
|
|
3835
|
+
dangerous,
|
|
3836
|
+
extraLabel,
|
|
3837
|
+
extraColor,
|
|
3838
|
+
checkLabel,
|
|
3839
|
+
checked,
|
|
3840
|
+
onConfirm,
|
|
3841
|
+
onCancel,
|
|
3842
|
+
onExtra,
|
|
3843
|
+
onCheckChange
|
|
3844
|
+
}: ConfirmDialogProps): React.ReactElement;
|
|
3845
|
+
//#endregion
|
|
3846
|
+
//#region src/router/Tabable.d.ts
|
|
3847
|
+
type FocusStyle = 'pointer' | 'highlight' | 'background' | 'border' | 'cursor' | 'none';
|
|
3848
|
+
interface TabableContextValue {
|
|
3849
|
+
/** 是否拥有焦点 */
|
|
3850
|
+
focused: boolean;
|
|
3851
|
+
/** 注册 ID */
|
|
3852
|
+
id: string;
|
|
3853
|
+
/** 是否 disabled */
|
|
3854
|
+
disabled: boolean;
|
|
3855
|
+
/** 当前聚焦样式 */
|
|
3856
|
+
focusStyle: FocusStyle;
|
|
3857
|
+
}
|
|
3858
|
+
/**
|
|
3859
|
+
* 子组件读取最近 <Tabable> 的聚焦状态。
|
|
3860
|
+
* focusStyle='none' 时组件自己根据 focused 自绘。
|
|
3861
|
+
*/
|
|
3862
|
+
declare function useTabableContext(): TabableContextValue;
|
|
3863
|
+
interface TabableEntry {
|
|
3864
|
+
id: string;
|
|
3865
|
+
tabIndex: number;
|
|
3866
|
+
disabled: boolean;
|
|
3867
|
+
order: number;
|
|
3868
|
+
routePath: string;
|
|
3869
|
+
autoFocus: boolean;
|
|
3870
|
+
/** Enter 拦截器。返回 true = 阻止默认穿透。 */
|
|
3871
|
+
onAction?: () => boolean | void;
|
|
3872
|
+
/** Esc 拦截器。返回 true = 阻止默认 goBack。 */
|
|
3873
|
+
onEscape?: () => boolean | void;
|
|
3874
|
+
/** Tab 拦截器。返回 true = 阻止默认焦点切换。 */
|
|
3875
|
+
onTab?: (shift: boolean) => boolean | void;
|
|
3876
|
+
}
|
|
3877
|
+
declare class TabableRegistry {
|
|
3878
|
+
private entries;
|
|
3879
|
+
private focusMemory;
|
|
3880
|
+
register(entry: TabableEntry): void;
|
|
3881
|
+
unregister(id: string): void;
|
|
3882
|
+
getTabable(routePath: string): TabableEntry[];
|
|
3883
|
+
getInitialFocus(routePath: string): string | null;
|
|
3884
|
+
next(currentId: string, routePath: string): string | null;
|
|
3885
|
+
prev(currentId: string, routePath: string): string | null;
|
|
3886
|
+
rememberFocus(routePath: string, id: string): void;
|
|
3887
|
+
get(id: string): TabableEntry | undefined;
|
|
3888
|
+
static nextOrder(): number;
|
|
3889
|
+
}
|
|
3890
|
+
interface RouteContextValue {
|
|
3891
|
+
routePath: string;
|
|
3892
|
+
currentPath: string;
|
|
3893
|
+
activeId: string | null;
|
|
3894
|
+
registry: TabableRegistry;
|
|
3895
|
+
onFocusFallback?: (nextId: string | null) => void;
|
|
3896
|
+
/** true when inside a real <Router> provider (vs default context) */
|
|
3897
|
+
hasRouter?: boolean;
|
|
3898
|
+
}
|
|
3899
|
+
declare const RouteContext: React.Context<RouteContextValue>;
|
|
3900
|
+
interface UseTabableOptions {
|
|
3901
|
+
tabIndex?: number;
|
|
3902
|
+
disabled?: boolean;
|
|
3903
|
+
autoFocus?: boolean;
|
|
3904
|
+
/** Enter 拦截器。返回 true = 阻止默认穿透。 */
|
|
3905
|
+
onAction?: () => boolean | void;
|
|
3906
|
+
/** Esc 拦截器。返回 true = 阻止默认 goBack。 */
|
|
3907
|
+
onEscape?: () => boolean | void;
|
|
3908
|
+
/** Tab 拦截器。返回 true = 阻止默认焦点切换。 */
|
|
3909
|
+
onTab?: (shift: boolean) => boolean | void;
|
|
3910
|
+
id?: string;
|
|
3911
|
+
}
|
|
3912
|
+
declare function useTabable(opts?: UseTabableOptions): {
|
|
3913
|
+
focused: boolean;
|
|
3914
|
+
id: string;
|
|
3915
|
+
};
|
|
3916
|
+
interface TabableProps {
|
|
3917
|
+
tabIndex?: number;
|
|
3918
|
+
disabled?: boolean;
|
|
3919
|
+
autoFocus?: boolean;
|
|
3920
|
+
onAction?: () => boolean | void;
|
|
3921
|
+
onEscape?: () => boolean | void;
|
|
3922
|
+
onTab?: (shift: boolean) => boolean | void;
|
|
3923
|
+
id?: string;
|
|
3924
|
+
/** 聚焦时的视觉样式。默认 'pointer'(▶ + 蓝色 + bold) */
|
|
3925
|
+
focusStyle?: FocusStyle;
|
|
3926
|
+
children: React.ReactNode;
|
|
3927
|
+
}
|
|
3928
|
+
declare function Tabable({
|
|
3929
|
+
tabIndex,
|
|
3930
|
+
disabled,
|
|
3931
|
+
autoFocus,
|
|
3932
|
+
onAction,
|
|
3933
|
+
onEscape,
|
|
3934
|
+
id,
|
|
3935
|
+
focusStyle,
|
|
3936
|
+
children
|
|
3937
|
+
}: TabableProps): React.ReactElement;
|
|
3938
|
+
//#endregion
|
|
3939
|
+
export { ExtensionListEntry as $, ToolCompletionMessage as $n, observationRow as $t, RemoteSessionSnapshot as A, ThemePresetSource as An, SigilKind as At, SelectState as B, STATUS as Bn, getCommandSuggestions as Bt, TuiHandle as C, LangMode as Cn, ProviderUsageBadgeItem as Ct, WizardRequest as D, ThemePreset as Dn, PromptInput as Dt, TuiStreamEvent as E, ThemeAppearance as En, QueuedCommands as Et, createLocalSessionDataSource as F, DIALOG_BORDER as Fn, SlashNavigateAction as Ft, makeNotifyScheduler as G, ChatMessage as Gn, PasteStore as Gt, A2uiButtonInfo as H, ThemeColors as Hn, CreatePasteStoreOptions as Ht, MessageStore as I, PANEL_BORDER as In, TypeaheadState as It, MemoryEntry as J, StopReason as Jn, Completer as Jt, MemoryDialog as K, MessageContent as Kn, PasteStoreResidencySource as Kt, Question as L, FIGURES as Ln, applySlashCompletion as Lt, SessionDataTarget as M, createBuiltinThemeRegistry as Mn, SigilSearchRegistry as Mt, SessionTransport as N, LAYOUT as Nn, CommandEntry as Nt, AttachDataSourceDeps as O, ThemePresetInput as On, SubmitMode as Ot, createAttachSessionDataSource as P, SPACING as Pn, CommandRegistry as Pt, InfoDialogProps as Q, ToolCall as Qn, observationLiveFields as Qt, SelectOption as R, FiguresMap as Rn, createCommandRegistry as Rt, SubagentContext as S, Lang as Sn, SessionListItem as St, TuiPanelRegistration as T, MarkdownThemeOverrides as Tn, isUsingOverage as Tt, NotifyScheduler as U, A2uiContent as Un, PasteSnapshot as Ut, createSelectState as V, THEME as Vn, navigateSuggestions as Vt, NotifyStats as W, AssistantMessage as Wn, PasteSnapshotEntry as Wt, InfoDialog as X, TextContent as Xn, formatAgentDiagnosticsText as Xt, MemoryEntrySource as Y, StreamEvent as Yn, ObservationLike as Yt, InfoDialogAction as Z, ThinkingContent as Zn, formatTurnTimeline as Zt, ModalRequestInput as _, useAppState as _n, BudgetView as _t, TabableContextValue as a, ErrorRetryItem as an, ButtonColor as at, PluginRegistration as b, initI18n as bn, Home as bt, TabableRegistry as c, OnboardingResult as cn, PluginMessageRenderer as ct, useTabableContext as d, DataListEntry as dn, registerPluginRenderers as dt, subagentEntryStatus as en, ToolMessage as er, ExtensionMenuContribution as et, ConfirmDialog as f, DataListProps as fn, NotificationStore as ft, DraftItemView as g, Store as gn, BudgetStore as gt, ConfirmRequest as h, PerfStore as hn, BudgetState as ht, Tabable as i, ErrorRetryActionKind as in, Button as it, SessionDataSource as j, ThemeRegistry as jn, SigilPrefix as jt, RemoteSessionEvent as k, ThemePresetSelection as kn, SigilEntry as kt, UseTabableOptions as l, KeyBindingPredicate as ln, RegisteredRenderer as lt, AlertRequest as m, DataListTone as mn, CacheStore as mt, RouteContext as n, EditedFileEntry as nn, ExtensionDetailAction as nt, TabableEntry as o, RateLimitType as on, ButtonProps as ot, ConfirmDialogProps as p, DataListRow as pn, ProxyStore as pt, MemoryDialogProps as q, PulseSurveyItem as qn, createPasteStore as qt, RouteContextValue as r, ErrorRetryAction as rn, ExtensionDetailRequest as rt, TabableProps as s, ContextStore as sn, ButtonVariant as st, FocusStyle as t, subagentRestoreFields as tn, UserMessage as tr, ExtensionsListRequest as tt, useTabable as u, DataList as un, clearPluginRenderers as ut, ModalRequestVoid as v, detectLanguage as vn, createBudgetStore as vt, TuiOptions as w, Risk as wn, formatProviderUsageLimitTypeFull as wt, PromptRequest as x, t as xn, HomeProps as xt, PermissionDecision as y, i18next as yn, TaskStore as yt, SelectOptions as z, PALETTE as zn, extractSlashPrefix as zt };
|
|
3940
|
+
//# sourceMappingURL=Tabable-B7PtwING.d.ts.map
|