@wukonglabs/wukong 0.0.9 → 0.0.11
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/dist/cli/exit-codes.js +12 -16
- package/dist/cli/exit-codes.js.map +1 -1
- package/dist/cli/help.js +4 -8
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/session-commands.js +1 -4
- package/dist/cli/session-commands.js.map +1 -1
- package/dist/cli/summary.js +2 -6
- package/dist/cli/summary.js.map +1 -1
- package/dist/cli/workspace-commands.js +1 -4
- package/dist/cli/workspace-commands.js.map +1 -1
- package/dist/index.js +373 -121
- package/dist/index.js.map +1 -1
- package/dist/sigint-handler.d.ts +62 -0
- package/dist/sigint-handler.d.ts.map +1 -0
- package/dist/sigint-handler.js +62 -0
- package/dist/sigint-handler.js.map +1 -0
- package/dist/tui/app.d.ts +57 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +268 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/header.d.ts +24 -0
- package/dist/tui/header.d.ts.map +1 -0
- package/dist/tui/header.js +26 -0
- package/dist/tui/header.js.map +1 -0
- package/dist/tui/permission-card.d.ts +27 -0
- package/dist/tui/permission-card.d.ts.map +1 -0
- package/dist/tui/permission-card.js +75 -0
- package/dist/tui/permission-card.js.map +1 -0
- package/dist/tui/plan-panel.d.ts +31 -0
- package/dist/tui/plan-panel.d.ts.map +1 -0
- package/dist/tui/plan-panel.js +30 -0
- package/dist/tui/plan-panel.js.map +1 -0
- package/dist/tui/response-panel.d.ts +49 -0
- package/dist/tui/response-panel.d.ts.map +1 -0
- package/dist/tui/response-panel.js +14 -0
- package/dist/tui/response-panel.js.map +1 -0
- package/dist/tui/run-ink.d.ts +22 -0
- package/dist/tui/run-ink.d.ts.map +1 -0
- package/dist/tui/run-ink.js +21 -0
- package/dist/tui/run-ink.js.map +1 -0
- package/dist/tui/should-use-tui.d.ts +25 -0
- package/dist/tui/should-use-tui.d.ts.map +1 -0
- package/dist/tui/should-use-tui.js +29 -0
- package/dist/tui/should-use-tui.js.map +1 -0
- package/dist/tui/text-input.d.ts +61 -0
- package/dist/tui/text-input.d.ts.map +1 -0
- package/dist/tui/text-input.js +318 -0
- package/dist/tui/text-input.js.map +1 -0
- package/dist/tui/thinking-panel.d.ts +32 -0
- package/dist/tui/thinking-panel.d.ts.map +1 -0
- package/dist/tui/thinking-panel.js +14 -0
- package/dist/tui/thinking-panel.js.map +1 -0
- package/dist/tui/tool-cards.d.ts +30 -0
- package/dist/tui/tool-cards.d.ts.map +1 -0
- package/dist/tui/tool-cards.js +37 -0
- package/dist/tui/tool-cards.js.map +1 -0
- package/dist/tui/use-input-history.d.ts +40 -0
- package/dist/tui/use-input-history.d.ts.map +1 -0
- package/dist/tui/use-input-history.js +123 -0
- package/dist/tui/use-input-history.js.map +1 -0
- package/dist/tui/use-plan-state.d.ts +4 -0
- package/dist/tui/use-plan-state.d.ts.map +1 -0
- package/dist/tui/use-plan-state.js +77 -0
- package/dist/tui/use-plan-state.js.map +1 -0
- package/package.json +9 -4
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* 多行文本输入组件(自研,Ink 自带 ink-text-input 不支持多行 + Ctrl+R)。
|
|
4
|
+
*
|
|
5
|
+
* ## 交互
|
|
6
|
+
*
|
|
7
|
+
* - **Enter**:提交(若 `multiline` 为 false,任何 Enter 都提交)
|
|
8
|
+
* - **Shift+Enter / Alt+Enter**:换行(仅 multiline=true 时)
|
|
9
|
+
* - **Ctrl+J**:换行(终端友好,Ctrl+J = LF)
|
|
10
|
+
* - **↑ / ↓**(单行时):浏览历史
|
|
11
|
+
* - **↑ / ↓**(多行时):移动光标到上/下一行
|
|
12
|
+
* - **Ctrl+R**:进入反查模式;再按跳下一条匹配;Enter 提交当前匹配;Esc 退出
|
|
13
|
+
* - **Ctrl+C**:清理后退出(由 App 层接管 graceful shutdown)
|
|
14
|
+
* - **Ctrl+L**:清屏(Ink 原生 clear)
|
|
15
|
+
*
|
|
16
|
+
* ## 粘贴检测
|
|
17
|
+
*
|
|
18
|
+
* Ink 没有原生 paste 事件。通过监听 `stdin` 的 data chunk,当一次 chunk 中
|
|
19
|
+
* 含多个字符(特别是含换行)时,判定为粘贴,直接整体插入(不走逐字符 input)。
|
|
20
|
+
* 这避免了粘贴中文/长文本时每个字符都触发一次 re-render 的性能问题。
|
|
21
|
+
*
|
|
22
|
+
* ## 可访问性
|
|
23
|
+
*
|
|
24
|
+
* `multiline` 模式下不依赖光标可视化(终端光标控制在不同终端差异大),
|
|
25
|
+
* 用 `▋` 字符标记光标位置;`NO_COLOR` 时仍可见。
|
|
26
|
+
*/
|
|
27
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
28
|
+
import { Text, useInput, useStdin } from 'ink';
|
|
29
|
+
import { reverseSearch, reverseSearchNext, } from './use-input-history.js';
|
|
30
|
+
const INITIAL_RS = {
|
|
31
|
+
active: false,
|
|
32
|
+
query: '',
|
|
33
|
+
matchIndex: -1,
|
|
34
|
+
};
|
|
35
|
+
export function TextInput({ value, onChange, onSubmit, multiline = true, history, prompt = '> ', placeholder = '', disabled = false, onAbort, }) {
|
|
36
|
+
const [cursor, setCursor] = useState(value.length);
|
|
37
|
+
const [rs, setRs] = useState(INITIAL_RS);
|
|
38
|
+
const { stdin, setRawMode } = useStdin();
|
|
39
|
+
// stdin 原始模式(捕获 Ctrl+C / Ctrl+R 等控制字符)
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (stdin && typeof setRawMode === 'function') {
|
|
42
|
+
setRawMode(true);
|
|
43
|
+
return () => setRawMode(false);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}, [stdin, setRawMode]);
|
|
47
|
+
// 插入文本到光标位置
|
|
48
|
+
const insertText = useCallback((text) => {
|
|
49
|
+
const newValue = value.slice(0, cursor) + text + value.slice(cursor);
|
|
50
|
+
onChange(newValue);
|
|
51
|
+
setCursor(cursor + text.length);
|
|
52
|
+
}, [value, cursor, onChange]);
|
|
53
|
+
// 提交当前输入
|
|
54
|
+
const submit = useCallback(() => {
|
|
55
|
+
const trimmed = value;
|
|
56
|
+
if (!trimmed)
|
|
57
|
+
return;
|
|
58
|
+
history?.push(trimmed);
|
|
59
|
+
onSubmit(trimmed);
|
|
60
|
+
onChange('');
|
|
61
|
+
setCursor(0);
|
|
62
|
+
setRs(INITIAL_RS);
|
|
63
|
+
}, [value, history, onSubmit, onChange]);
|
|
64
|
+
useInput((input, key) => {
|
|
65
|
+
if (disabled)
|
|
66
|
+
return;
|
|
67
|
+
// ── 多字符输入处理 ──
|
|
68
|
+
// Ink 把整段 stdin chunk 作为单次 useInput 调用(粘贴 / IME 选词 /
|
|
69
|
+
// 快速连击都会一次性到)。处理:整体插入(等价 paste 行为),不再逐字符。
|
|
70
|
+
//
|
|
71
|
+
// 原因:逐字符插入会触发 useCallback 闭包陷阱——第一次 insertText 的
|
|
72
|
+
// onChange 还没 flush,第二次 insertText 用的是旧 value/cursor,导致
|
|
73
|
+
// 多字符只保留最后一个字符(实测 "你好" 选词后只显示 "好")。
|
|
74
|
+
if (input && input.length >= 2 && !key.ctrl && !key.meta && !key.upArrow && !key.downArrow && !key.leftArrow && !key.rightArrow && !key.return && !key.escape && !key.backspace && !key.delete && !key.tab) {
|
|
75
|
+
const cleaned = input.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
76
|
+
history?.exitNavigation();
|
|
77
|
+
insertText(cleaned);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// ── Ctrl+R:反查模式 ──
|
|
81
|
+
if (key.ctrl && input === 'r') {
|
|
82
|
+
if (!history || history.entries.length === 0)
|
|
83
|
+
return;
|
|
84
|
+
if (!rs.active) {
|
|
85
|
+
// 进入反查模式,空 query → 找最近一条
|
|
86
|
+
const match = reverseSearch(history.entries, '', history.entries.length - 1);
|
|
87
|
+
setRs({ active: true, query: '', matchIndex: match.index });
|
|
88
|
+
if (match.text)
|
|
89
|
+
onChange(match.text);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// 已经在反查模式 → 跳下一条匹配
|
|
93
|
+
if (rs.matchIndex >= 0) {
|
|
94
|
+
const next = reverseSearchNext(history.entries, rs.query, rs.matchIndex);
|
|
95
|
+
setRs({ ...rs, matchIndex: next.index });
|
|
96
|
+
if (next.text)
|
|
97
|
+
onChange(next.text);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// ── 反查模式下的其他按键 ──
|
|
103
|
+
if (rs.active) {
|
|
104
|
+
if (key.escape) {
|
|
105
|
+
// Esc:退出反查,保留当前匹配作为输入
|
|
106
|
+
setRs(INITIAL_RS);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (key.return) {
|
|
110
|
+
// Enter:提交当前匹配
|
|
111
|
+
setRs(INITIAL_RS);
|
|
112
|
+
submit();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (key.backspace || key.delete) {
|
|
116
|
+
// 删除 query 最后一个字符,重新匹配
|
|
117
|
+
const newQuery = rs.query.slice(0, -1);
|
|
118
|
+
const match = reverseSearch(history.entries, newQuery);
|
|
119
|
+
setRs({ ...rs, query: newQuery, matchIndex: match.index });
|
|
120
|
+
if (match.text)
|
|
121
|
+
onChange(match.text);
|
|
122
|
+
else
|
|
123
|
+
onChange(newQuery);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// 可打印字符 → 追加到 query,重新匹配
|
|
127
|
+
if (input && !key.ctrl && !key.meta && input.length === 1 && input >= ' ') {
|
|
128
|
+
const newQuery = rs.query + input;
|
|
129
|
+
const match = reverseSearch(history.entries, newQuery);
|
|
130
|
+
setRs({ ...rs, query: newQuery, matchIndex: match.index });
|
|
131
|
+
if (match.text)
|
|
132
|
+
onChange(match.text);
|
|
133
|
+
else
|
|
134
|
+
onChange(newQuery);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// 其他控制键在反查模式下忽略
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// ── 普通模式 ──
|
|
141
|
+
if (key.return) {
|
|
142
|
+
// Shift+Enter / Meta+Enter → 换行(多行模式)
|
|
143
|
+
if (multiline && (key.shift || key.meta)) {
|
|
144
|
+
insertText('\n');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
// 普通 Enter → 提交
|
|
148
|
+
submit();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (key.ctrl && input === 'j') {
|
|
152
|
+
// Ctrl+J = LF,多行模式下换行
|
|
153
|
+
if (multiline) {
|
|
154
|
+
insertText('\n');
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
submit();
|
|
158
|
+
}
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (key.ctrl && input === 'c') {
|
|
162
|
+
// §3.3 M3:Ctrl+C 交给 App 层处理两次语义(graceful shutdown)
|
|
163
|
+
// Ink raw mode拦截 Ctrl+C 不走 process SIGINT,故需显式回调
|
|
164
|
+
onAbort?.();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (key.backspace || key.delete) {
|
|
168
|
+
if (cursor > 0) {
|
|
169
|
+
// 删除光标前一个字符(含跨行 \n)
|
|
170
|
+
const newValue = value.slice(0, cursor - 1) + value.slice(cursor);
|
|
171
|
+
onChange(newValue);
|
|
172
|
+
setCursor(cursor - 1);
|
|
173
|
+
}
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (key.leftArrow) {
|
|
177
|
+
setCursor(Math.max(0, cursor - 1));
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (key.rightArrow) {
|
|
181
|
+
setCursor(Math.min(value.length, cursor + 1));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (key.upArrow) {
|
|
185
|
+
// 多行模式:光标移到上一行(如果有)
|
|
186
|
+
if (multiline) {
|
|
187
|
+
const { lineStart, lineIndex, colInLine } = getLineInfo(value, cursor);
|
|
188
|
+
if (lineIndex > 0) {
|
|
189
|
+
// 上一行同列位置
|
|
190
|
+
const prevLineStart = value.lastIndexOf('\n', lineStart - 1) + 1;
|
|
191
|
+
const prevLineEnd = lineStart - 1;
|
|
192
|
+
const prevLineLen = prevLineEnd - prevLineStart;
|
|
193
|
+
const newCol = Math.min(colInLine, prevLineLen);
|
|
194
|
+
setCursor(prevLineStart + newCol);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// 单行模式 或 多行已在第一行 → 浏览历史
|
|
199
|
+
if (history) {
|
|
200
|
+
const text = history.navigate('up', value);
|
|
201
|
+
if (text !== null) {
|
|
202
|
+
onChange(text);
|
|
203
|
+
setCursor(text.length);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (key.downArrow) {
|
|
209
|
+
if (multiline) {
|
|
210
|
+
const { lineEnd, lineIndex, colInLine, totalLines } = getLineInfo(value, cursor);
|
|
211
|
+
if (lineIndex < totalLines - 1) {
|
|
212
|
+
const nextLineStart = lineEnd + 1;
|
|
213
|
+
const nextLineEnd = value.indexOf('\n', nextLineStart);
|
|
214
|
+
const nextLineLen = (nextLineEnd === -1 ? value.length : nextLineEnd) - nextLineStart;
|
|
215
|
+
const newCol = Math.min(colInLine, nextLineLen);
|
|
216
|
+
setCursor(nextLineStart + newCol);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// 单行 或 多行最后一行 → 浏览历史
|
|
221
|
+
if (history) {
|
|
222
|
+
const text = history.navigate('down', value);
|
|
223
|
+
if (text !== null) {
|
|
224
|
+
onChange(text);
|
|
225
|
+
setCursor(text.length);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
// 到底恢复草稿
|
|
229
|
+
history.exitNavigation();
|
|
230
|
+
onChange(history.draftBeforeNav);
|
|
231
|
+
setCursor(history.draftBeforeNav.length);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Home / End
|
|
237
|
+
if (key.ctrl && input === 'a') {
|
|
238
|
+
// 行首
|
|
239
|
+
const lineStart = value.lastIndexOf('\n', cursor - 1) + 1;
|
|
240
|
+
setCursor(lineStart);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (key.ctrl && input === 'e') {
|
|
244
|
+
// 行尾
|
|
245
|
+
const lineEnd = value.indexOf('\n', cursor);
|
|
246
|
+
setCursor(lineEnd === -1 ? value.length : lineEnd);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// 可打印字符
|
|
250
|
+
if (input && !key.ctrl && !key.meta && input.length === 1 && input >= ' ') {
|
|
251
|
+
// 任何编辑都退出历史导航
|
|
252
|
+
history?.exitNavigation();
|
|
253
|
+
insertText(input);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
// ── 渲染 ──
|
|
258
|
+
// 反查模式:显示 (reverse-i-search)`query`: match
|
|
259
|
+
if (rs.active) {
|
|
260
|
+
const matchText = rs.matchIndex >= 0 && history ? history.entries[rs.matchIndex] : '';
|
|
261
|
+
return (_jsxs(Text, { children: [_jsxs(Text, { dimColor: true, children: ["(reverse-i-search)`", rs.query, "`: "] }), _jsx(Text, { color: "cyan", children: matchText || '(无匹配)' })] }));
|
|
262
|
+
}
|
|
263
|
+
// 空输入 + placeholder
|
|
264
|
+
if (!value && placeholder) {
|
|
265
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: prompt }), _jsx(Text, { dimColor: true, children: placeholder })] }));
|
|
266
|
+
}
|
|
267
|
+
// 带光标渲染(▋ 标记光标位置)
|
|
268
|
+
const before = value.slice(0, cursor);
|
|
269
|
+
const at = value.slice(cursor, cursor + 1);
|
|
270
|
+
const after = value.slice(cursor + 1);
|
|
271
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: prompt }), before, _jsx(Text, { inverse: true, children: at || ' ' }), after] }));
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* 多字符输入是否为粘贴(纯函数,便于单测)。
|
|
275
|
+
*
|
|
276
|
+
* Ink useInput 把整段 stdin chunk 作为单次 input 传入。
|
|
277
|
+
* 视为粘贴的特征:含换行(多行粘贴)或长度 >= 5(普通打字不可能一次到 5 字符)。
|
|
278
|
+
* 短输入(2-4 字符无换行)可能是 IME 选词 / 快速连击,都按"整体插入"处理
|
|
279
|
+
* (不再逐字符,以避免 useCallback 闭包陷阱导致多字符只保留最后一个)。
|
|
280
|
+
*/
|
|
281
|
+
export function isPasteInput(input) {
|
|
282
|
+
if (!input || input.length < 2)
|
|
283
|
+
return false;
|
|
284
|
+
return input.includes('\n') || input.includes('\r') || input.length >= 5;
|
|
285
|
+
}
|
|
286
|
+
function getLineInfo(value, cursor) {
|
|
287
|
+
// 找当前行的起始
|
|
288
|
+
let lineStart = 0;
|
|
289
|
+
for (let i = cursor - 1; i >= 0; i--) {
|
|
290
|
+
if (value[i] === '\n') {
|
|
291
|
+
lineStart = i + 1;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// 找当前行的结束
|
|
296
|
+
let lineEnd = value.length;
|
|
297
|
+
for (let i = cursor; i < value.length; i++) {
|
|
298
|
+
if (value[i] === '\n') {
|
|
299
|
+
lineEnd = i;
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// 行号 + 总行数
|
|
304
|
+
let lineIndex = 0;
|
|
305
|
+
for (let i = 0; i < lineStart; i++) {
|
|
306
|
+
if (value[i] === '\n')
|
|
307
|
+
lineIndex++;
|
|
308
|
+
}
|
|
309
|
+
const totalLines = (value.match(/\n/g)?.length ?? 0) + 1;
|
|
310
|
+
return {
|
|
311
|
+
lineStart,
|
|
312
|
+
lineEnd,
|
|
313
|
+
lineIndex,
|
|
314
|
+
totalLines,
|
|
315
|
+
colInLine: cursor - lineStart,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=text-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-input.js","sourceRoot":"","sources":["../../src/tui/text-input.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thinking panel —— 渲染 agent 的思考过程摘要(thinking_delta)。
|
|
3
|
+
*
|
|
4
|
+
* ## 数据源
|
|
5
|
+
*
|
|
6
|
+
* onStream 回调的 `thinking_delta` 事件(不在 EventBus 里,属于 LLM 流式层)。
|
|
7
|
+
* App 层把 thinking_delta 转发到本组件的 props。
|
|
8
|
+
*
|
|
9
|
+
* ## 渲染策略(2026-07-15 修订)
|
|
10
|
+
*
|
|
11
|
+
* **永远折叠为 1 行摘要**,不再支持 `t` 键展开。
|
|
12
|
+
*
|
|
13
|
+
* 原因:动态区高度硬约束(见 App.tsx)。thinking 展开可能有几千字符,
|
|
14
|
+
* 一旦动态区高度超过终端可视高度,Ink 的重绘就会失败(vscode 内嵌终端里
|
|
15
|
+
* 表现为满屏空线框)。thinking 完整内容可通过 session trace 文件查看。
|
|
16
|
+
*
|
|
17
|
+
* `expanded` prop 保留是为了未来"展开时打进 <Static>"的扩展预留;
|
|
18
|
+
* `onToggleExpand` 已废弃,当前 App 也不再传入。
|
|
19
|
+
*/
|
|
20
|
+
import React from 'react';
|
|
21
|
+
export interface ThinkingPanelProps {
|
|
22
|
+
/** 当前累积的思考内容 */
|
|
23
|
+
thinking: string;
|
|
24
|
+
/** 是否正在流式接收 thinking */
|
|
25
|
+
streaming: boolean;
|
|
26
|
+
/** 是否展开(受控);当前实现只识别 false(永远折叠) */
|
|
27
|
+
expanded?: boolean;
|
|
28
|
+
/** @deprecated 折叠模式下无用;保留是为了向后兼容 */
|
|
29
|
+
onToggleExpand?: (expanded: boolean) => void;
|
|
30
|
+
}
|
|
31
|
+
export declare function ThinkingPanel({ thinking, streaming, expanded, }: ThinkingPanelProps): React.ReactElement | null;
|
|
32
|
+
//# sourceMappingURL=thinking-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinking-panel.d.ts","sourceRoot":"","sources":["../../src/tui/thinking-panel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,kBAAkB;IACjC,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CAC9C;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,QAAgB,GACjB,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CA0BhD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function ThinkingPanel({ thinking, streaming, expanded = false, }) {
|
|
4
|
+
// 无内容 → 不渲染
|
|
5
|
+
if (!thinking)
|
|
6
|
+
return null;
|
|
7
|
+
const icon = '💭';
|
|
8
|
+
if (!expanded) {
|
|
9
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: "magenta", children: [icon, " Thinking", streaming ? '…' : ''] }), _jsxs(Text, { dimColor: true, children: [" (", thinking.length, " \u5B57\u7B26,\u5B8C\u6574\u5185\u5BB9\u89C1 session trace)"] })] }));
|
|
10
|
+
}
|
|
11
|
+
// expanded=true 分支保留(未来可用于把 thinking 打进 <Static>);当前 App 不会走到这里。
|
|
12
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: _jsxs(Text, { color: "magenta", bold: true, children: [icon, " Thinking"] }) }), _jsx(Text, { dimColor: true, color: "magenta", children: thinking })] }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=thinking-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thinking-panel.js","sourceRoot":"","sources":["../../src/tui/thinking-panel.tsx"],"names":[],"mappings":";AAoBA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAahC,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,SAAS,EACT,QAAQ,GAAG,KAAK,GACG;IACnB,YAAY;IACZ,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3B,MAAM,IAAI,GAAG,IAAI,CAAC;IAElB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CACL,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,KAAK,EAAC,SAAS,aAAE,IAAI,eAAW,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAQ,EAClE,MAAC,IAAI,IAAC,QAAQ,yBAAI,QAAQ,CAAC,MAAM,mEAAgC,IAC7D,CACP,CAAC;IACJ,CAAC;IAED,iEAAiE;IACjE,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACzB,KAAC,GAAG,cACF,MAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,mBAAE,IAAI,iBAAiB,GAC7C,EACN,KAAC,IAAI,IAAC,QAAQ,QAAC,KAAK,EAAC,SAAS,YAC3B,QAAQ,GACJ,IACH,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool cards —— 每个工具调用一张卡片,展示状态/耗时/参数摘要。
|
|
3
|
+
*
|
|
4
|
+
* ## 数据源
|
|
5
|
+
*
|
|
6
|
+
* 订阅 EventBus 的 `tool_call_start` / `tool_call_end` 事件。
|
|
7
|
+
* 本组件接收 App 维护的 activeTools + completedTools 列表(由 App 订阅事件后传入),
|
|
8
|
+
* 保持组件本身纯展示,便于测试。
|
|
9
|
+
*
|
|
10
|
+
* ## 折叠
|
|
11
|
+
*
|
|
12
|
+
* 并行工具超过 `maxVisible`(默认 5)时,只展示最近 N 个 + "还有 X 个" 折叠提示。
|
|
13
|
+
* 避免一次 15 个 read_file 把终端刷爆(§3.1 性能预算)。
|
|
14
|
+
*
|
|
15
|
+
* ## 状态
|
|
16
|
+
*
|
|
17
|
+
* - ⏳ running(黄色)
|
|
18
|
+
* - ✓ done(绿色)
|
|
19
|
+
* - ✗ failed(红色)
|
|
20
|
+
*/
|
|
21
|
+
import React from 'react';
|
|
22
|
+
import type { ToolCallState } from './response-panel.js';
|
|
23
|
+
export interface ToolCardsProps {
|
|
24
|
+
/** 活跃 + 最近完成的 tool call(已完成但未过期的) */
|
|
25
|
+
tools: ToolCallState[];
|
|
26
|
+
/** 最大可见卡片数;超出折叠(默认 5) */
|
|
27
|
+
maxVisible?: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function ToolCards({ tools, maxVisible }: ToolCardsProps): React.ReactElement | null;
|
|
30
|
+
//# sourceMappingURL=tool-cards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-cards.d.ts","sourceRoot":"","sources":["../../src/tui/tool-cards.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,yBAAyB;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,UAAc,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAmB9F"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function ToolCards({ tools, maxVisible = 5 }) {
|
|
4
|
+
if (tools.length === 0)
|
|
5
|
+
return null;
|
|
6
|
+
// 按开始时间排序,最近在前
|
|
7
|
+
const sorted = [...tools].sort((a, b) => b.startedAt - a.startedAt);
|
|
8
|
+
const visible = sorted.slice(0, maxVisible);
|
|
9
|
+
const hidden = sorted.length - visible.length;
|
|
10
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 0, children: [_jsx(Text, { dimColor: true, bold: true, children: "\uD83D\uDD27 Tools" }), visible.map((t) => (_jsx(ToolCardRow, { tool: t }, t.toolCallId))), hidden > 0 && (_jsxs(Text, { dimColor: true, children: [" \u2026 \u8FD8\u6709 ", hidden, " \u4E2A\u5DE5\u5177\u8C03\u7528(\u5DF2\u6298\u53E0)"] }))] }));
|
|
11
|
+
}
|
|
12
|
+
function ToolCardRow({ tool }) {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
const elapsed = ((tool.endedAt ?? now) - tool.startedAt) / 1000;
|
|
15
|
+
const status = tool.success === undefined ? 'running' : tool.success ? 'done' : 'failed';
|
|
16
|
+
const { icon, color } = statusVisual(status);
|
|
17
|
+
// 高度控制:done 状态不展示 resultPreview(结果会在 assistant 响应里出现,无需重复)。
|
|
18
|
+
// running / failed 才展示,便于用户观察当前进度或排查失败原因。
|
|
19
|
+
const showPreview = tool.resultPreview && status !== 'done';
|
|
20
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: color, children: icon }), _jsxs(Text, { children: [" \u26A1 ", tool.name] }), _jsxs(Text, { dimColor: true, children: [" [", elapsed.toFixed(2), "s]"] }), tool.step > 0 && _jsxs(Text, { dimColor: true, children: [" (step ", tool.step, ")"] })] }), showPreview && (_jsxs(Text, { dimColor: true, children: [" \u21B3 ", truncate(tool.resultPreview, 100)] }))] }));
|
|
21
|
+
}
|
|
22
|
+
function statusVisual(status) {
|
|
23
|
+
switch (status) {
|
|
24
|
+
case 'done':
|
|
25
|
+
return { icon: '✓', color: 'green' };
|
|
26
|
+
case 'failed':
|
|
27
|
+
return { icon: '✗', color: 'red' };
|
|
28
|
+
default:
|
|
29
|
+
return { icon: '⏳', color: 'yellow' };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function truncate(s, max) {
|
|
33
|
+
if (s.length <= max)
|
|
34
|
+
return s;
|
|
35
|
+
return s.slice(0, max - 1) + '…';
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=tool-cards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-cards.js","sourceRoot":"","sources":["../../src/tui/tool-cards.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface InputHistoryState {
|
|
2
|
+
/** 当前已落盘的历史条目(已提交过的输入),最新在数组末尾 */
|
|
3
|
+
entries: string[];
|
|
4
|
+
/** 添加一条新历史(去重最后一条,空字符串不入) */
|
|
5
|
+
push: (entry: string) => void;
|
|
6
|
+
/** 当前导航到的历史索引;null 表示不在历史导航中(在编辑草稿) */
|
|
7
|
+
navIndex: number | null;
|
|
8
|
+
/** 跳到指定历史索引,并返回该条文本 */
|
|
9
|
+
navigate: (direction: 'up' | 'down', currentDraft: string) => string | null;
|
|
10
|
+
/** 退出历史导航,保留草稿 */
|
|
11
|
+
exitNavigation: () => void;
|
|
12
|
+
/** 保存进入历史导航前的草稿(用于下键到底时恢复) */
|
|
13
|
+
draftBeforeNav: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function useInputHistory(initial?: string[]): InputHistoryState;
|
|
16
|
+
export interface ReverseSearchResult {
|
|
17
|
+
/** 匹配到的历史索引;-1 表示无匹配 */
|
|
18
|
+
index: number;
|
|
19
|
+
/** 匹配到的文本(无匹配时为空串) */
|
|
20
|
+
text: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 在历史中从 `fromIndex`(含)向更早的方向找第一条包含 `query` 的条目。
|
|
24
|
+
*
|
|
25
|
+
* @param entries 历史条目(末尾为最新)
|
|
26
|
+
* @param query 查询子串(大小写不敏感)
|
|
27
|
+
* @param fromIndex 从哪个索引开始往前找(含);默认从末尾开始
|
|
28
|
+
* @returns 匹配结果;无匹配返回 { index: -1, text: '' }
|
|
29
|
+
*/
|
|
30
|
+
export declare function reverseSearch(entries: string[], query: string, fromIndex?: number): ReverseSearchResult;
|
|
31
|
+
/**
|
|
32
|
+
* 跳到当前匹配之前的下一条匹配(用于"再按 Ctrl+R")。
|
|
33
|
+
*
|
|
34
|
+
* @param entries 历史条目
|
|
35
|
+
* @param query 查询子串
|
|
36
|
+
* @param currentIndex 当前匹配的索引
|
|
37
|
+
* @returns 新的匹配结果;无更早匹配时返回原 currentIndex 的结果
|
|
38
|
+
*/
|
|
39
|
+
export declare function reverseSearchNext(entries: string[], query: string, currentIndex: number): ReverseSearchResult;
|
|
40
|
+
//# sourceMappingURL=use-input-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-input-history.d.ts","sourceRoot":"","sources":["../../src/tui/use-input-history.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6BAA6B;IAC7B,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,uCAAuC;IACvC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uBAAuB;IACvB,QAAQ,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC5E,kBAAkB;IAClB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,MAAM,EAAO,GAAG,iBAAiB,CAiEzE;AAMD,MAAM,WAAW,mBAAmB;IAClC,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EAAE,EACjB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAA2B,GACrC,mBAAmB,CASrB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EAAE,EACjB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GACnB,mBAAmB,CAOrB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 输入历史 hook —— 提供 readline 历史导航 + Ctrl+R 反查。
|
|
3
|
+
*
|
|
4
|
+
* ## 交互
|
|
5
|
+
*
|
|
6
|
+
* - **上下键**:浏览历史(和 readline / bash 一致)
|
|
7
|
+
* - 上键:回到更早的历史项;到顶不动
|
|
8
|
+
* - 下键:回到更近的历史项;到底恢复为"编辑中"的草稿
|
|
9
|
+
* - 浏览中按其他键修改 → 视为在新草稿上编辑(下次按上键回到当前选中)
|
|
10
|
+
* - **Ctrl+R**:进入反查模式
|
|
11
|
+
* - 输入字符 → 实时过滤匹配的最近一条历史
|
|
12
|
+
* - 再按 Ctrl+R → 跳到下一条匹配
|
|
13
|
+
* - Enter / Esc / 非 Ctrl+R 编辑键 → 退出反查模式(Enter 提交当前匹配)
|
|
14
|
+
*
|
|
15
|
+
* ## 持久化
|
|
16
|
+
*
|
|
17
|
+
* 本 hook 只维护**进程内**历史。跨 session 持久化(读 `~/.wukong/history`)
|
|
18
|
+
* 由调用方负责,见 `tui/app.tsx`。
|
|
19
|
+
*
|
|
20
|
+
* ## 设计取舍
|
|
21
|
+
*
|
|
22
|
+
* 不引第三方库(如 ink-use-input-history)的原因:这些库大多没覆盖 Ctrl+R,
|
|
23
|
+
* 且与我们的"草稿保留 + 反查"语义不完全一致;自研约 120 行,可控性更好。
|
|
24
|
+
*/
|
|
25
|
+
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
26
|
+
export function useInputHistory(initial = []) {
|
|
27
|
+
const [entries, setEntries] = useState(initial);
|
|
28
|
+
const [navIndex, setNavIndex] = useState(null);
|
|
29
|
+
const draftRef = useRef('');
|
|
30
|
+
const [draftBeforeNav, setDraftBeforeNav] = useState('');
|
|
31
|
+
const push = useCallback((entry) => {
|
|
32
|
+
const trimmed = entry.trim();
|
|
33
|
+
if (!trimmed)
|
|
34
|
+
return;
|
|
35
|
+
setEntries((prev) => {
|
|
36
|
+
// 与最后一条相同则不重复
|
|
37
|
+
if (prev.length > 0 && prev[prev.length - 1] === trimmed)
|
|
38
|
+
return prev;
|
|
39
|
+
// 上限 1000 条,避免无限增长
|
|
40
|
+
const next = [...prev, trimmed];
|
|
41
|
+
return next.length > 1000 ? next.slice(next.length - 1000) : next;
|
|
42
|
+
});
|
|
43
|
+
}, []);
|
|
44
|
+
const navigate = useCallback((direction, currentDraft) => {
|
|
45
|
+
if (entries.length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
// 进入导航前保存草稿
|
|
48
|
+
if (navIndex === null) {
|
|
49
|
+
draftRef.current = currentDraft;
|
|
50
|
+
setDraftBeforeNav(currentDraft);
|
|
51
|
+
}
|
|
52
|
+
if (direction === 'up') {
|
|
53
|
+
// 上键:navIndex 从 null → entries.length-1,否则 -1
|
|
54
|
+
const nextIdx = navIndex === null ? entries.length - 1 : Math.max(0, navIndex - 1);
|
|
55
|
+
setNavIndex(nextIdx);
|
|
56
|
+
return entries[nextIdx] ?? null;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// 下键:到底恢复草稿
|
|
60
|
+
if (navIndex === null)
|
|
61
|
+
return null;
|
|
62
|
+
const nextIdx = navIndex + 1;
|
|
63
|
+
if (nextIdx >= entries.length) {
|
|
64
|
+
setNavIndex(null);
|
|
65
|
+
return draftRef.current;
|
|
66
|
+
}
|
|
67
|
+
setNavIndex(nextIdx);
|
|
68
|
+
return entries[nextIdx] ?? null;
|
|
69
|
+
}
|
|
70
|
+
}, [entries, navIndex]);
|
|
71
|
+
const exitNavigation = useCallback(() => {
|
|
72
|
+
setNavIndex(null);
|
|
73
|
+
}, []);
|
|
74
|
+
// entries 外部更新(initial 变化)时重置导航
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
setNavIndex(null);
|
|
77
|
+
}, [entries]);
|
|
78
|
+
return {
|
|
79
|
+
entries,
|
|
80
|
+
push,
|
|
81
|
+
navIndex,
|
|
82
|
+
navigate,
|
|
83
|
+
exitNavigation,
|
|
84
|
+
draftBeforeNav,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 在历史中从 `fromIndex`(含)向更早的方向找第一条包含 `query` 的条目。
|
|
89
|
+
*
|
|
90
|
+
* @param entries 历史条目(末尾为最新)
|
|
91
|
+
* @param query 查询子串(大小写不敏感)
|
|
92
|
+
* @param fromIndex 从哪个索引开始往前找(含);默认从末尾开始
|
|
93
|
+
* @returns 匹配结果;无匹配返回 { index: -1, text: '' }
|
|
94
|
+
*/
|
|
95
|
+
export function reverseSearch(entries, query, fromIndex = entries.length - 1) {
|
|
96
|
+
if (!query || entries.length === 0)
|
|
97
|
+
return { index: -1, text: '' };
|
|
98
|
+
const q = query.toLowerCase();
|
|
99
|
+
for (let i = Math.min(fromIndex, entries.length - 1); i >= 0; i--) {
|
|
100
|
+
if (entries[i].toLowerCase().includes(q)) {
|
|
101
|
+
return { index: i, text: entries[i] };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { index: -1, text: '' };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 跳到当前匹配之前的下一条匹配(用于"再按 Ctrl+R")。
|
|
108
|
+
*
|
|
109
|
+
* @param entries 历史条目
|
|
110
|
+
* @param query 查询子串
|
|
111
|
+
* @param currentIndex 当前匹配的索引
|
|
112
|
+
* @returns 新的匹配结果;无更早匹配时返回原 currentIndex 的结果
|
|
113
|
+
*/
|
|
114
|
+
export function reverseSearchNext(entries, query, currentIndex) {
|
|
115
|
+
if (currentIndex <= 0) {
|
|
116
|
+
// 已经是最早的匹配,返回当前
|
|
117
|
+
if (currentIndex < 0)
|
|
118
|
+
return { index: -1, text: '' };
|
|
119
|
+
return { index: currentIndex, text: entries[currentIndex] };
|
|
120
|
+
}
|
|
121
|
+
return reverseSearch(entries, query, currentIndex - 1);
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=use-input-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-input-history.js","sourceRoot":"","sources":["../../src/tui/use-input-history.ts"],"names":[],"mappings":"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"}
|