@wukonglabs/wukong 0.0.19 → 0.0.21
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/help.js +1 -1
- package/dist/cli/session-commands.d.ts.map +1 -1
- package/dist/cli/session-commands.js +4 -3
- package/dist/cli/session-commands.js.map +1 -1
- package/dist/index.js +73 -12
- package/dist/index.js.map +1 -1
- package/dist/tui/activity-verb.d.ts +29 -0
- package/dist/tui/activity-verb.d.ts.map +1 -0
- package/dist/tui/activity-verb.js +81 -0
- package/dist/tui/activity-verb.js.map +1 -0
- package/dist/tui/app.d.ts +29 -28
- package/dist/tui/app.d.ts.map +1 -1
- package/dist/tui/app.js +259 -132
- package/dist/tui/app.js.map +1 -1
- package/dist/tui/diff-count.d.ts +14 -0
- package/dist/tui/diff-count.d.ts.map +1 -0
- package/dist/tui/diff-count.js +21 -0
- package/dist/tui/diff-count.js.map +1 -0
- package/dist/tui/hint-bar.d.ts +12 -0
- package/dist/tui/hint-bar.d.ts.map +1 -0
- package/dist/tui/hint-bar.js +14 -0
- package/dist/tui/hint-bar.js.map +1 -0
- package/dist/tui/history-entry.d.ts +11 -0
- package/dist/tui/history-entry.d.ts.map +1 -0
- package/dist/tui/history-entry.js +35 -0
- package/dist/tui/history-entry.js.map +1 -0
- package/dist/tui/history-item.d.ts +40 -0
- package/dist/tui/history-item.d.ts.map +1 -0
- package/dist/tui/history-item.js +8 -0
- package/dist/tui/history-item.js.map +1 -0
- package/dist/tui/keys-help.d.ts +5 -0
- package/dist/tui/keys-help.d.ts.map +1 -0
- package/dist/tui/keys-help.js +36 -0
- package/dist/tui/keys-help.js.map +1 -0
- package/dist/tui/live-block.d.ts +54 -0
- package/dist/tui/live-block.d.ts.map +1 -0
- package/dist/tui/live-block.js +72 -0
- package/dist/tui/live-block.js.map +1 -0
- package/dist/tui/main-area.d.ts +40 -0
- package/dist/tui/main-area.d.ts.map +1 -0
- package/dist/tui/main-area.js +9 -0
- package/dist/tui/main-area.js.map +1 -0
- package/dist/tui/markdown.d.ts +14 -0
- package/dist/tui/markdown.d.ts.map +1 -0
- package/dist/tui/markdown.js +134 -0
- package/dist/tui/markdown.js.map +1 -0
- package/dist/tui/notice-panel.d.ts +20 -0
- package/dist/tui/notice-panel.d.ts.map +1 -0
- package/dist/tui/notice-panel.js +19 -0
- package/dist/tui/notice-panel.js.map +1 -0
- package/dist/tui/response-panel.d.ts +12 -16
- package/dist/tui/response-panel.d.ts.map +1 -1
- package/dist/tui/response-panel.js +8 -11
- package/dist/tui/response-panel.js.map +1 -1
- package/dist/tui/run-ink.d.ts +12 -0
- package/dist/tui/run-ink.d.ts.map +1 -1
- package/dist/tui/run-ink.js +2 -1
- package/dist/tui/run-ink.js.map +1 -1
- package/dist/tui/slash/menu.d.ts +16 -0
- package/dist/tui/slash/menu.d.ts.map +1 -0
- package/dist/tui/slash/menu.js +11 -0
- package/dist/tui/slash/menu.js.map +1 -0
- package/dist/tui/slash/parse.d.ts +21 -0
- package/dist/tui/slash/parse.d.ts.map +1 -0
- package/dist/tui/slash/parse.js +32 -0
- package/dist/tui/slash/parse.js.map +1 -0
- package/dist/tui/slash/registry.d.ts +20 -0
- package/dist/tui/slash/registry.d.ts.map +1 -0
- package/dist/tui/slash/registry.js +28 -0
- package/dist/tui/slash/registry.js.map +1 -0
- package/dist/tui/spinner.d.ts +11 -0
- package/dist/tui/spinner.d.ts.map +1 -0
- package/dist/tui/spinner.js +21 -0
- package/dist/tui/spinner.js.map +1 -0
- package/dist/tui/status-bar.d.ts +42 -0
- package/dist/tui/status-bar.d.ts.map +1 -0
- package/dist/tui/status-bar.js +32 -0
- package/dist/tui/status-bar.js.map +1 -0
- package/dist/tui/tail-visual.d.ts +11 -0
- package/dist/tui/tail-visual.d.ts.map +1 -0
- package/dist/tui/tail-visual.js +30 -0
- package/dist/tui/tail-visual.js.map +1 -0
- package/dist/tui/text-input.d.ts +20 -22
- package/dist/tui/text-input.d.ts.map +1 -1
- package/dist/tui/text-input.js +211 -81
- package/dist/tui/text-input.js.map +1 -1
- package/dist/tui/theme/context.d.ts +16 -0
- package/dist/tui/theme/context.d.ts.map +1 -0
- package/dist/tui/theme/context.js +28 -0
- package/dist/tui/theme/context.js.map +1 -0
- package/dist/tui/theme/persist.d.ts +11 -0
- package/dist/tui/theme/persist.d.ts.map +1 -0
- package/dist/tui/theme/persist.js +41 -0
- package/dist/tui/theme/persist.js.map +1 -0
- package/dist/tui/theme/theme.d.ts +26 -0
- package/dist/tui/theme/theme.d.ts.map +1 -0
- package/dist/tui/theme/theme.js +51 -0
- package/dist/tui/theme/theme.js.map +1 -0
- package/dist/tui/thinking-panel.d.ts +11 -20
- package/dist/tui/thinking-panel.d.ts.map +1 -1
- package/dist/tui/thinking-panel.js +29 -7
- package/dist/tui/thinking-panel.js.map +1 -1
- package/dist/tui/tool-cards.d.ts +5 -17
- package/dist/tui/tool-cards.d.ts.map +1 -1
- package/dist/tui/tool-cards.js +4 -5
- package/dist/tui/tool-cards.js.map +1 -1
- package/dist/tui/tool-summary.d.ts +2 -0
- package/dist/tui/tool-summary.d.ts.map +1 -0
- package/dist/tui/tool-summary.js +93 -0
- package/dist/tui/tool-summary.js.map +1 -0
- package/dist/tui/use-elapsed.d.ts +2 -0
- package/dist/tui/use-elapsed.d.ts.map +1 -0
- package/dist/tui/use-elapsed.js +22 -0
- package/dist/tui/use-elapsed.js.map +1 -0
- package/dist/tui/use-plan-state.d.ts +20 -1
- package/dist/tui/use-plan-state.d.ts.map +1 -1
- package/dist/tui/use-plan-state.js +52 -46
- package/dist/tui/use-plan-state.js.map +1 -1
- package/dist/tui/use-terminal-width.d.ts +2 -0
- package/dist/tui/use-terminal-width.d.ts.map +1 -0
- package/dist/tui/use-terminal-width.js +23 -0
- package/dist/tui/use-terminal-width.js.map +1 -0
- package/dist/tui/use-viewport.d.ts +15 -0
- package/dist/tui/use-viewport.d.ts.map +1 -0
- package/dist/tui/use-viewport.js +37 -0
- package/dist/tui/use-viewport.js.map +1 -0
- package/dist/tui/welcome.d.ts +29 -0
- package/dist/tui/welcome.d.ts.map +1 -0
- package/dist/tui/welcome.js +41 -0
- package/dist/tui/welcome.js.map +1 -0
- package/package.json +3 -2
- package/dist/tui/header.d.ts +0 -24
- package/dist/tui/header.d.ts.map +0 -1
- package/dist/tui/header.js +0 -26
- package/dist/tui/header.js.map +0 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { marked } from 'marked';
|
|
4
|
+
import { useTheme } from './theme/context.js';
|
|
5
|
+
export function Markdown({ text }) {
|
|
6
|
+
const { theme } = useTheme();
|
|
7
|
+
let tokens;
|
|
8
|
+
try {
|
|
9
|
+
tokens = marked.lexer(text || '');
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return _jsx(Text, { children: text });
|
|
13
|
+
}
|
|
14
|
+
return (_jsx(Box, { flexDirection: "column", children: tokens.map((t, i) => renderToken(t, i, theme)) }));
|
|
15
|
+
}
|
|
16
|
+
function renderToken(t, i, theme) {
|
|
17
|
+
switch (t.type) {
|
|
18
|
+
case 'heading': {
|
|
19
|
+
const h = t;
|
|
20
|
+
// 标题用主题色 + 加粗,depth 越大字号越弱(终端用颜色饱和度体现)
|
|
21
|
+
const color = h.depth <= 2 ? theme.status : theme.assistant;
|
|
22
|
+
return (_jsx(Text, { bold: true, color: color, children: h.text }, i));
|
|
23
|
+
}
|
|
24
|
+
case 'paragraph': {
|
|
25
|
+
const p = t;
|
|
26
|
+
return _jsx(Text, { children: renderInline(p.text, theme) }, i);
|
|
27
|
+
}
|
|
28
|
+
case 'code': {
|
|
29
|
+
const c = t;
|
|
30
|
+
return (_jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.dim, paddingX: 1, marginY: 0, children: _jsx(Text, { dimColor: true, children: c.text }) }, i));
|
|
31
|
+
}
|
|
32
|
+
case 'list': {
|
|
33
|
+
const l = t;
|
|
34
|
+
return (_jsx(Box, { flexDirection: "column", children: l.items.map((it, j) => (_jsxs(Text, { children: [l.ordered ? `${j + 1}. ` : '- ', renderInline(it.text, theme), it.task && (it.checked ? ' ✓' : ' ○')] }, j))) }, i));
|
|
35
|
+
}
|
|
36
|
+
case 'table': {
|
|
37
|
+
const tab = t;
|
|
38
|
+
// 按每列最大宽度对齐;窄终端时不做截断(交给终端 wrap)
|
|
39
|
+
const colCount = tab.header.length;
|
|
40
|
+
const widths = Array(colCount).fill(0);
|
|
41
|
+
for (const c of tab.header)
|
|
42
|
+
widths[tab.header.indexOf(c)] = c.text.length;
|
|
43
|
+
for (const row of tab.rows) {
|
|
44
|
+
row.forEach((c, k) => {
|
|
45
|
+
if (c.text.length > widths[k])
|
|
46
|
+
widths[k] = c.text.length;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const pad = (s, w) => s + ' '.repeat(Math.max(0, w - s.length));
|
|
50
|
+
const rowToText = (cells) => cells.map((c, k) => pad(c.text, widths[k])).join(' │ ');
|
|
51
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: theme.status, children: rowToText(tab.header) }), _jsx(Text, { dimColor: true, children: widths.map((w) => '─'.repeat(w)).join('─┼─') }), tab.rows.map((row, j) => (_jsx(Text, { children: rowToText(row) }, j)))] }, i));
|
|
52
|
+
}
|
|
53
|
+
case 'hr':
|
|
54
|
+
return (_jsx(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }, i));
|
|
55
|
+
case 'blockquote': {
|
|
56
|
+
const bq = t;
|
|
57
|
+
// 简单展开为 │ 前缀的多行
|
|
58
|
+
return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { dimColor: true, children: `│ ${bq.text}` }) }, i));
|
|
59
|
+
}
|
|
60
|
+
case 'space':
|
|
61
|
+
return null;
|
|
62
|
+
case 'def':
|
|
63
|
+
return null; // 链接定义,不影响渲染
|
|
64
|
+
default:
|
|
65
|
+
// 兜底:尝试拿 raw/text 字段
|
|
66
|
+
const fallback = t.raw
|
|
67
|
+
?? t.text
|
|
68
|
+
?? '';
|
|
69
|
+
return _jsx(Text, { children: fallback }, i);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 行内格式解析(粗体 / 行内代码)。
|
|
74
|
+
* 用状态机扫描,简单且可控;不解析 HTML 链接(终端里不可点)。
|
|
75
|
+
*/
|
|
76
|
+
function renderInline(text, theme) {
|
|
77
|
+
const parts = [];
|
|
78
|
+
let buf = '';
|
|
79
|
+
let bold = false;
|
|
80
|
+
let code = false;
|
|
81
|
+
const flush = () => {
|
|
82
|
+
if (buf)
|
|
83
|
+
parts.push({ text: buf, bold, code });
|
|
84
|
+
buf = '';
|
|
85
|
+
};
|
|
86
|
+
let i = 0;
|
|
87
|
+
while (i < text.length) {
|
|
88
|
+
// **bold**
|
|
89
|
+
if (text[i] === '*' && text[i + 1] === '*') {
|
|
90
|
+
flush();
|
|
91
|
+
bold = !bold;
|
|
92
|
+
i += 2;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
// *italic* (单 *)—— 简化:当 bold 已 true 时忽略
|
|
96
|
+
if (text[i] === '*' && !bold) {
|
|
97
|
+
flush();
|
|
98
|
+
// 终端里 italic 不可靠,降级为 dim
|
|
99
|
+
const dim = true;
|
|
100
|
+
const saved = bold;
|
|
101
|
+
bold = false;
|
|
102
|
+
// 找到下一个 *
|
|
103
|
+
const end = text.indexOf('*', i + 1);
|
|
104
|
+
if (end > i) {
|
|
105
|
+
parts.push({ text: text.slice(i + 1, end), bold: saved, dim });
|
|
106
|
+
i = end + 1;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// `code`
|
|
111
|
+
if (text[i] === '`') {
|
|
112
|
+
flush();
|
|
113
|
+
code = !code;
|
|
114
|
+
i += 1;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
buf += text[i];
|
|
118
|
+
i += 1;
|
|
119
|
+
}
|
|
120
|
+
flush();
|
|
121
|
+
return parts.map((p, j) => {
|
|
122
|
+
if (p.code) {
|
|
123
|
+
return (_jsx(Text, { color: theme.status, children: p.text }, j));
|
|
124
|
+
}
|
|
125
|
+
if (p.dim) {
|
|
126
|
+
return (_jsx(Text, { dimColor: true, children: p.text }, j));
|
|
127
|
+
}
|
|
128
|
+
if (p.bold) {
|
|
129
|
+
return (_jsx(Text, { bold: true, children: p.text }, j));
|
|
130
|
+
}
|
|
131
|
+
return _jsx(Text, { children: p.text }, j);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/tui/markdown.tsx"],"names":[],"mappings":";AAUA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,MAAM,EAAgC,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,EAAoB;IACjD,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC7B,IAAI,MAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAC,IAAI,cAAE,IAAI,GAAQ,CAAC;IAC7B,CAAC;IACD,OAAO,CACL,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,YACxB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,GAC3C,CACP,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAClB,CAAiB,EACjB,CAAS,EACT,KAAY;IAEZ,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,CAAmB,CAAC;YAC9B,uCAAuC;YACvC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;YAC5D,OAAO,CACL,KAAC,IAAI,IAAS,IAAI,QAAC,KAAK,EAAE,KAAK,YAC5B,CAAC,CAAC,IAAI,IADE,CAAC,CAEL,CACR,CAAC;QACJ,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,CAAC,GAAG,CAAqB,CAAC;YAChC,OAAO,KAAC,IAAI,cAAU,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,IAA/B,CAAC,CAAsC,CAAC;QAC5D,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,CAAC,GAAG,CAAgB,CAAC;YAC3B,OAAO,CACL,KAAC,GAAG,IAEF,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAC,OAAO,EACnB,WAAW,EAAE,KAAK,CAAC,GAAG,EACtB,QAAQ,EAAE,CAAC,EACX,OAAO,EAAE,CAAC,YAEV,KAAC,IAAI,IAAC,QAAQ,kBAAE,CAAC,CAAC,IAAI,GAAQ,IAPzB,CAAC,CAQF,CACP,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,CAAC,GAAG,CAAgB,CAAC;YAC3B,OAAO,CACL,KAAC,GAAG,IAAS,aAAa,EAAC,QAAQ,YAChC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,MAAC,IAAI,eACF,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAC5B,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAH/B,CAAC,CAIL,CACR,CAAC,IAPM,CAAC,CAQL,CACP,CAAC;QACJ,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,GAAG,GAAG,CAAiB,CAAC;YAC9B,gCAAgC;YAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC;YACnC,MAAM,MAAM,GAAa,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM;gBAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;YAC1E,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC3B,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;oBACnB,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;wBAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC3D,CAAC,CAAC,CAAC;YACL,CAAC;YACD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAChF,MAAM,SAAS,GAAG,CAAC,KAAyB,EAAE,EAAE,CAC9C,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1D,OAAO,CACL,MAAC,GAAG,IAAS,aAAa,EAAC,QAAQ,aACjC,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,KAAK,CAAC,MAAM,YAC3B,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,GACjB,EACP,KAAC,IAAI,IAAC,QAAQ,kBAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAQ,EACnE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACxB,KAAC,IAAI,cAAU,SAAS,CAAC,GAAG,CAAC,IAAlB,CAAC,CAAyB,CACtC,CAAC,KAPM,CAAC,CAQL,CACP,CAAC;QACJ,CAAC;QACD,KAAK,IAAI;YACP,OAAO,CACL,KAAC,IAAI,IAAS,QAAQ,sGAAX,CAAC,CAEL,CACR,CAAC;QACJ,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,EAAE,GAAG,CAAsB,CAAC;YAClC,gBAAgB;YAChB,OAAO,CACL,KAAC,GAAG,IAAS,aAAa,EAAC,QAAQ,YACjC,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,EAAE,CAAC,IAAI,EAAE,GAAQ,IAD9B,CAAC,CAEL,CACP,CAAC;QACJ,CAAC;QACD,KAAK,OAAO;YACV,OAAO,IAAI,CAAC;QACd,KAAK,KAAK;YACR,OAAO,IAAI,CAAC,CAAC,aAAa;QAC5B;YACE,qBAAqB;YACrB,MAAM,QAAQ,GAAI,CAAqC,CAAC,GAAG;mBACrD,CAAuB,CAAC,IAAI;mBAC7B,EAAE,CAAC;YACR,OAAO,KAAC,IAAI,cAAU,QAAQ,IAAZ,CAAC,CAAmB,CAAC;IAC3C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,KAAY;IAC9C,MAAM,KAAK,GAA2E,EAAE,CAAC;IACzF,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,GAAG,GAAG,EAAE,CAAC;IACX,CAAC,CAAC;IAEF,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,WAAW;QACX,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YAC3C,KAAK,EAAE,CAAC;YACR,IAAI,GAAG,CAAC,IAAI,CAAC;YACb,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QACD,wCAAwC;QACxC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7B,KAAK,EAAE,CAAC;YACR,yBAAyB;YACzB,MAAM,GAAG,GAAG,IAAI,CAAC;YACjB,MAAM,KAAK,GAAG,IAAI,CAAC;YACnB,IAAI,GAAG,KAAK,CAAC;YACb,UAAU;YACV,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;gBACZ,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC/D,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;gBACZ,SAAS;YACX,CAAC;QACH,CAAC;QACD,SAAS;QACT,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACpB,KAAK,EAAE,CAAC;YACR,IAAI,GAAG,CAAC,IAAI,CAAC;YACb,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QACD,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;QACf,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,KAAK,EAAE,CAAC;IAER,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACxB,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,CACL,KAAC,IAAI,IAAS,KAAK,EAAE,KAAK,CAAC,MAAM,YAC9B,CAAC,CAAC,IAAI,IADE,CAAC,CAEL,CACR,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;YACV,OAAO,CACL,KAAC,IAAI,IAAS,QAAQ,kBACnB,CAAC,CAAC,IAAI,IADE,CAAC,CAEL,CACR,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,CACL,KAAC,IAAI,IAAS,IAAI,kBACf,CAAC,CAAC,IAAI,IADE,CAAC,CAEL,CACR,CAAC;QACJ,CAAC;QACD,OAAO,KAAC,IAAI,cAAU,CAAC,CAAC,IAAI,IAAV,CAAC,CAAiB,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 通知 / 错误面板(M8)。
|
|
3
|
+
*
|
|
4
|
+
* 错误从 ResponsePanel 拆出,独立占最多 3 行,不与流式响应挤同一空间。
|
|
5
|
+
* Esc 清除(由 App 通过 onDismiss 控制,本组件只渲染)。
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export type NoticeKind = 'error' | 'warn' | 'info';
|
|
9
|
+
export interface Notice {
|
|
10
|
+
kind: NoticeKind;
|
|
11
|
+
text: string;
|
|
12
|
+
timestamp: number;
|
|
13
|
+
}
|
|
14
|
+
export interface NoticePanelProps {
|
|
15
|
+
notice: Notice | null;
|
|
16
|
+
/** 是否超出 3 行(用于显示 "… Esc 清除" 提示) */
|
|
17
|
+
onDismiss?: () => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function NoticePanel({ notice }: NoticePanelProps): React.ReactElement | null;
|
|
20
|
+
//# sourceMappingURL=notice-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notice-panel.d.ts","sourceRoot":"","sources":["../../src/tui/notice-panel.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnD,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,gBAAgB,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAsBnF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
import { useTheme } from './theme/context.js';
|
|
4
|
+
export function NoticePanel({ notice }) {
|
|
5
|
+
if (!notice)
|
|
6
|
+
return null;
|
|
7
|
+
const { theme } = useTheme();
|
|
8
|
+
const color = notice.kind === 'error'
|
|
9
|
+
? theme.toolFailed
|
|
10
|
+
: notice.kind === 'warn'
|
|
11
|
+
? theme.toolRunning
|
|
12
|
+
: theme.status;
|
|
13
|
+
const icon = notice.kind === 'error' ? '❌' : notice.kind === 'warn' ? '⚠️' : 'ℹ️';
|
|
14
|
+
const lines = notice.text.split('\n');
|
|
15
|
+
const overflow = lines.length > 3;
|
|
16
|
+
const display = (overflow ? lines.slice(0, 3).join('\n') : notice.text) + (overflow ? ' … (Esc 清除)' : '');
|
|
17
|
+
return (_jsx(Box, { flexDirection: "column", paddingX: 1, children: _jsxs(Text, { color: color, children: [icon, " ", display] }) }));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=notice-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notice-panel.js","sourceRoot":"","sources":["../../src/tui/notice-panel.tsx"],"names":[],"mappings":";AAOA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAgB9C,MAAM,UAAU,WAAW,CAAC,EAAE,MAAM,EAAoB;IACtD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC7B,MAAM,KAAK,GACT,MAAM,CAAC,IAAI,KAAK,OAAO;QACrB,CAAC,CAAC,KAAK,CAAC,UAAU;QAClB,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM;YACtB,CAAC,CAAC,KAAK,CAAC,WAAW;YACnB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IACrB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAElF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE1G,OAAO,CACL,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,YACrC,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,aACf,IAAI,OAAG,OAAO,IACV,GACH,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Response panel —— 流式渲染 agent
|
|
2
|
+
* Response panel —— 流式渲染 agent 响应(M3 改造)。
|
|
3
3
|
*
|
|
4
|
-
* ##
|
|
4
|
+
* ## 改造点(M3)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* - 移除"仅字符数摘要"的应急显示,恢复**逐字流式**:streaming 时直接渲染正文
|
|
7
|
+
* 末尾 maxLines 个视觉行(按终端宽度折算),末行带 `▍` 光标。
|
|
8
|
+
* - 响应结束后完整正文进入 <Static>(App 负责),动态区只保留完成信号。
|
|
9
|
+
* - 错误展示已移至独立的 NoticePanel(M8),本组件不再承担 error。
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
* - 当前正在生成的响应文本(流式)
|
|
12
|
-
* - 最近一次完成的响应(带步骤/Token 统计)
|
|
13
|
-
* - 进行中的 tool call 摘要(状态 + 耗时)
|
|
14
|
-
*
|
|
15
|
-
* 完整的 Tool cards / Plan panel 留到 M3-M5。
|
|
11
|
+
* 高度:streaming 时最多 maxLines(默认 6)行,避免超过动态区硬约束。
|
|
16
12
|
*/
|
|
17
13
|
import React from 'react';
|
|
18
14
|
export interface ToolCallState {
|
|
@@ -23,6 +19,8 @@ export interface ToolCallState {
|
|
|
23
19
|
endedAt?: number;
|
|
24
20
|
success?: boolean;
|
|
25
21
|
resultPreview?: string;
|
|
22
|
+
/** M4:工具调用参数 JSON(tool_call_start 提供) */
|
|
23
|
+
argsJson?: string;
|
|
26
24
|
}
|
|
27
25
|
export interface CompletedRun {
|
|
28
26
|
response: string;
|
|
@@ -38,12 +36,10 @@ export interface ResponsePanelProps {
|
|
|
38
36
|
streamingText: string;
|
|
39
37
|
/** 流式是否正在进行 */
|
|
40
38
|
streaming: boolean;
|
|
41
|
-
/** 当前活跃的 tool call(tool_call_start 后、tool_call_end 前) */
|
|
42
|
-
activeTools: ToolCallState[];
|
|
43
39
|
/** 最近一次完成的 run(用于展示历史响应) */
|
|
44
40
|
lastCompleted?: CompletedRun;
|
|
45
|
-
/**
|
|
46
|
-
|
|
41
|
+
/** 流式区最大视觉行数(默认 6) */
|
|
42
|
+
maxLines?: number;
|
|
47
43
|
}
|
|
48
|
-
export declare function ResponsePanel({ streamingText, streaming,
|
|
44
|
+
export declare function ResponsePanel({ streamingText, streaming, lastCompleted, maxLines, }: ResponsePanelProps): React.ReactElement;
|
|
49
45
|
//# sourceMappingURL=response-panel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-panel.d.ts","sourceRoot":"","sources":["../../src/tui/response-panel.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"response-panel.d.ts","sourceRoot":"","sources":["../../src/tui/response-panel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,aAAa,CAAC,EAC5B,aAAkB,EAClB,SAAS,EACT,aAAa,EACb,QAAY,GACb,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAiCzC"}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Text, Box } from 'ink';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const icon = tool.success === undefined ? '⏳' : tool.success ? '✓' : '✗';
|
|
11
|
-
const color = tool.success === undefined ? 'yellow' : tool.success ? 'green' : 'red';
|
|
12
|
-
return (_jsxs(Text, { children: [_jsx(Text, { color: color, children: icon }), _jsxs(Text, { dimColor: true, children: [" \u26A1 ", tool.name] }), _jsxs(Text, { dimColor: true, children: [" [", elapsed.toFixed(2), "s]"] }), tool.resultPreview && (_jsxs(Text, { dimColor: true, children: [" ", tool.resultPreview.slice(0, 80)] }))] }));
|
|
3
|
+
import { useTerminalWidth } from './use-terminal-width.js';
|
|
4
|
+
import { tailVisualLines } from './tail-visual.js';
|
|
5
|
+
export function ResponsePanel({ streamingText = '', streaming, lastCompleted, maxLines = 6, }) {
|
|
6
|
+
const cols = useTerminalWidth();
|
|
7
|
+
const tail = tailVisualLines(streamingText, maxLines, cols);
|
|
8
|
+
const tailLines = tail.length > 0 ? tail.split('\n') : [];
|
|
9
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [streaming && (_jsx(Box, { flexDirection: "column", children: tailLines.length === 0 ? (_jsx(Text, { color: "cyan", dimColor: true, children: "\u231B \u6B63\u5728\u751F\u6210\u54CD\u5E94\u2026" })) : (tailLines.map((line, i) => (_jsxs(Text, { color: "cyan", dimColor: true, children: [line, i === tailLines.length - 1 ? '▍' : ''] }, i)))) })), !streaming && lastCompleted && (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: "\u2713 " }), _jsxs(Text, { dimColor: true, children: ["\u672C\u8F6E\u54CD\u5E94\u5DF2\u5B8C\u6210(\u6B63\u6587\u89C1\u4E0A\u65B9,\u5171 ", lastCompleted.response.length, " \u5B57\u7B26, \u6B65\u9AA4", ' ', lastCompleted.steps, ", \u8017\u65F6 ", (lastCompleted.durationMs / 1000).toFixed(1), "s)"] })] }))] }));
|
|
13
10
|
}
|
|
14
11
|
//# sourceMappingURL=response-panel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-panel.js","sourceRoot":"","sources":["../../src/tui/response-panel.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"response-panel.js","sourceRoot":"","sources":["../../src/tui/response-panel.tsx"],"names":[],"mappings":";AAaA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAgCnD,MAAM,UAAU,aAAa,CAAC,EAC5B,aAAa,GAAG,EAAE,EAClB,SAAS,EACT,aAAa,EACb,QAAQ,GAAG,CAAC,GACO;IACnB,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,eAAe,CAAC,aAAa,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1D,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,aACpC,SAAS,IAAI,CACZ,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,YACxB,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACxB,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,QAAQ,wEAAiB,CAC7C,CAAC,CAAC,CAAC,CACF,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACzB,MAAC,IAAI,IAAS,KAAK,EAAC,MAAM,EAAC,QAAQ,mBAChC,IAAI,EACJ,CAAC,KAAK,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAF7B,CAAC,CAGL,CACR,CAAC,CACH,GACG,CACP,EAEA,CAAC,SAAS,IAAI,aAAa,IAAI,CAC9B,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,wBAAU,EAC7B,MAAC,IAAI,IAAC,QAAQ,wGACK,aAAa,CAAC,QAAQ,CAAC,MAAM,iCAAS,GAAG,EACzD,aAAa,CAAC,KAAK,qBAAO,CAAC,aAAa,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAClE,IACH,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
|
package/dist/tui/run-ink.d.ts
CHANGED
|
@@ -10,6 +10,18 @@ export interface InkRunOptions {
|
|
|
10
10
|
* 用于把 agent 的 onStream 事件转发给 Ink。runInk 只负责把 ref 挂到 App 上。
|
|
11
11
|
*/
|
|
12
12
|
streamSinkRef: SinkRef;
|
|
13
|
+
/** CLI 版本号,欢迎屏展示用 */
|
|
14
|
+
appVersion?: string;
|
|
15
|
+
/** 已解析到的配置文件路径(若有),欢迎屏展示用 */
|
|
16
|
+
configPath?: string;
|
|
17
|
+
/** 当前会话已有记录数 */
|
|
18
|
+
sessionRecordCount?: number;
|
|
19
|
+
/** 当前会话是否本次刚创建 */
|
|
20
|
+
sessionCreated?: boolean;
|
|
21
|
+
/** 已注册工具数量,欢迎屏展示用(替代原来刷屏的"✅ 已注册工具"日志) */
|
|
22
|
+
toolsCount?: number;
|
|
23
|
+
/** 已加载且可用的技能数量,欢迎屏展示用 */
|
|
24
|
+
skillsLoaded?: number;
|
|
13
25
|
}
|
|
14
26
|
export interface InkRunHandle {
|
|
15
27
|
/** 卸载 Ink 实例(退出时调用) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-ink.d.ts","sourceRoot":"","sources":["../../src/tui/run-ink.tsx"],"names":[],"mappings":"AASA,OAAO,EAAO,WAAW,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"run-ink.d.ts","sourceRoot":"","sources":["../../src/tui/run-ink.tsx"],"names":[],"mappings":"AASA,OAAO,EAAO,WAAW,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGrD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,WAAW,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAuBxD"}
|
package/dist/tui/run-ink.js
CHANGED
|
@@ -9,11 +9,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
9
9
|
*/
|
|
10
10
|
import { render } from 'ink';
|
|
11
11
|
import { App } from './app.js';
|
|
12
|
+
import { ThemeProvider } from './theme/context.js';
|
|
12
13
|
/**
|
|
13
14
|
* 启动 Ink TUI。onStream 由调用方通过 streamSinkRef 桥接,不再由此处返回。
|
|
14
15
|
*/
|
|
15
16
|
export function runInk(opts) {
|
|
16
|
-
const inkInstance = render(_jsx(App, { model: opts.model, sessionUuidShort: opts.sessionUuidShort, workspaceRoot: opts.workspaceRoot, handlers: opts.handlers, initialHistory: opts.initialHistory, streamSinkRef: opts.streamSinkRef }));
|
|
17
|
+
const inkInstance = render(_jsx(ThemeProvider, { children: _jsx(App, { model: opts.model, sessionUuidShort: opts.sessionUuidShort, workspaceRoot: opts.workspaceRoot, handlers: opts.handlers, initialHistory: opts.initialHistory, streamSinkRef: opts.streamSinkRef, appVersion: opts.appVersion, configPath: opts.configPath, sessionRecordCount: opts.sessionRecordCount, sessionCreated: opts.sessionCreated, toolsCount: opts.toolsCount, skillsLoaded: opts.skillsLoaded }) }));
|
|
17
18
|
return {
|
|
18
19
|
unmount: () => inkInstance.unmount(),
|
|
19
20
|
};
|
package/dist/tui/run-ink.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-ink.js","sourceRoot":"","sources":["../../src/tui/run-ink.tsx"],"names":[],"mappings":";AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAwB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"run-ink.js","sourceRoot":"","sources":["../../src/tui/run-ink.tsx"],"names":[],"mappings":";AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAwB,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAgCnD;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,IAAmB;IACxC,MAAM,WAAW,GAAG,MAAM,CACxB,KAAC,aAAa,cACZ,KAAC,GAAG,IACF,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EACvC,aAAa,EAAE,IAAI,CAAC,aAAa,EACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,cAAc,EAAE,IAAI,CAAC,cAAc,EACnC,aAAa,EAAE,IAAI,CAAC,aAAa,EACjC,UAAU,EAAE,IAAI,CAAC,UAAU,EAC3B,UAAU,EAAE,IAAI,CAAC,UAAU,EAC3B,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,EAC3C,cAAc,EAAE,IAAI,CAAC,cAAc,EACnC,UAAU,EAAE,IAAI,CAAC,UAAU,EAC3B,YAAY,EAAE,IAAI,CAAC,YAAY,GAC/B,GACY,CACjB,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE;KACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash 命令下拉菜单(纯展示)。
|
|
3
|
+
*
|
|
4
|
+
* 键盘导航(↑/↓ 选择、Enter 确认、Esc 取消)由 TextInput 的 useInput 统一处理,
|
|
5
|
+
* 本组件只负责"给定候选列表 + 当前高亮项"渲染高亮。这样既满足快照测试要求,
|
|
6
|
+
* 又避免第二个 useInput 与输入框抢焦点。
|
|
7
|
+
*/
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import type { SlashCommand } from './registry.js';
|
|
10
|
+
export interface SlashMenuProps {
|
|
11
|
+
commands: SlashCommand[];
|
|
12
|
+
/** 当前高亮索引(0-based) */
|
|
13
|
+
highlight: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function SlashMenu({ commands, highlight }: SlashMenuProps): React.ReactElement | null;
|
|
16
|
+
//# sourceMappingURL=menu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../../src/tui/slash/menu.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAiB5F"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function SlashMenu({ commands, highlight }) {
|
|
4
|
+
if (commands.length === 0)
|
|
5
|
+
return null;
|
|
6
|
+
return (_jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: commands.map((c, i) => {
|
|
7
|
+
const active = i === highlight;
|
|
8
|
+
return (_jsx(Box, { children: _jsxs(Text, { inverse: active, children: [_jsxs(Text, { color: active ? 'cyan' : undefined, children: ["/", c.name] }), _jsxs(Text, { children: [" \u2014 ", c.description] })] }) }, c.name));
|
|
9
|
+
}) }));
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.js","sourceRoot":"","sources":["../../../src/tui/slash/menu.tsx"],"names":[],"mappings":";AAQA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAShC,MAAM,UAAU,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAkB;IAC/D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,CACL,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAC,OAAO,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC,YAC3E,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrB,MAAM,MAAM,GAAG,CAAC,KAAK,SAAS,CAAC;YAC/B,OAAO,CACL,KAAC,GAAG,cACF,MAAC,IAAI,IAAC,OAAO,EAAE,MAAM,aACnB,MAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,kBAAI,CAAC,CAAC,IAAI,IAAQ,EAC1D,MAAC,IAAI,2BAAK,CAAC,CAAC,WAAW,IAAQ,IAC1B,IAJC,CAAC,CAAC,IAAI,CAKV,CACP,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析 slash 命令输入(纯函数,便于单测)。
|
|
3
|
+
*
|
|
4
|
+
* 规则:
|
|
5
|
+
* - 以 `/` 开头 → isSlash=true,解析 name + 可选 arg
|
|
6
|
+
* - name 取 `/` 后到第一个空白之间的子串(小写化)
|
|
7
|
+
* - arg 取 name 之后剩余的 trimmed 内容
|
|
8
|
+
* - 非 `/` 开头 → isSlash=false,原样返回
|
|
9
|
+
*/
|
|
10
|
+
export interface ParsedSlash {
|
|
11
|
+
/** 是否以 / 开头 */
|
|
12
|
+
isSlash: boolean;
|
|
13
|
+
/** 命令名(小写,不含 /);无有效名时为 undefined */
|
|
14
|
+
name?: string;
|
|
15
|
+
/** 参数(如 'dark');无则为 undefined */
|
|
16
|
+
arg?: string;
|
|
17
|
+
/** 去掉前导 / 后的原始 body(用于菜单过滤) */
|
|
18
|
+
raw: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function parseSlashCommand(input: string): ParsedSlash;
|
|
21
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/tui/slash/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,WAAW;IAC1B,eAAe;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAqB5D"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析 slash 命令输入(纯函数,便于单测)。
|
|
3
|
+
*
|
|
4
|
+
* 规则:
|
|
5
|
+
* - 以 `/` 开头 → isSlash=true,解析 name + 可选 arg
|
|
6
|
+
* - name 取 `/` 后到第一个空白之间的子串(小写化)
|
|
7
|
+
* - arg 取 name 之后剩余的 trimmed 内容
|
|
8
|
+
* - 非 `/` 开头 → isSlash=false,原样返回
|
|
9
|
+
*/
|
|
10
|
+
export function parseSlashCommand(input) {
|
|
11
|
+
const trimmed = input.trimStart();
|
|
12
|
+
if (!trimmed.startsWith('/')) {
|
|
13
|
+
return { isSlash: false, raw: input };
|
|
14
|
+
}
|
|
15
|
+
const body = trimmed.slice(1).trim();
|
|
16
|
+
if (body.length === 0) {
|
|
17
|
+
return { isSlash: true, name: undefined, raw: '' };
|
|
18
|
+
}
|
|
19
|
+
const spaceIdx = body.search(/\s/);
|
|
20
|
+
if (spaceIdx === -1) {
|
|
21
|
+
return { isSlash: true, name: body.toLowerCase(), raw: body };
|
|
22
|
+
}
|
|
23
|
+
const name = body.slice(0, spaceIdx).toLowerCase();
|
|
24
|
+
const arg = body.slice(spaceIdx + 1).trim();
|
|
25
|
+
return {
|
|
26
|
+
isSlash: true,
|
|
27
|
+
name: name || undefined,
|
|
28
|
+
arg: arg || undefined,
|
|
29
|
+
raw: body,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/tui/slash/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IAClC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IACxC,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IACrD,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAChE,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,IAAI,IAAI,SAAS;QACvB,GAAG,EAAE,GAAG,IAAI,SAAS;QACrB,GAAG,EAAE,IAAI;KACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash 命令注册表(纯数据 + 类型)。
|
|
3
|
+
*
|
|
4
|
+
* M1:输入 `/` 唤起命令菜单时,从这里过滤命令;提交时按 name 派发到 App 的
|
|
5
|
+
* dispatchSlash。命令执行逻辑在 app.tsx(因为多数命令需要操作 App 状态 /
|
|
6
|
+
* EventBus / 持久化),本文件只描述"有哪些命令、怎么展示"。
|
|
7
|
+
*/
|
|
8
|
+
export type SlashCommandName = 'help' | 'status' | 'clear' | 'quit' | 'exit' | 'model' | 'session' | 'theme' | 'compact' | 'think' | 'keys';
|
|
9
|
+
export interface SlashCommand {
|
|
10
|
+
name: SlashCommandName;
|
|
11
|
+
description: string;
|
|
12
|
+
/** 是否接受参数(如 theme 接受 dark/light/mono) */
|
|
13
|
+
takesArgument?: boolean;
|
|
14
|
+
/** 依赖尚未启用时的提示(命令已注册但执行返回此文案,不 crash) */
|
|
15
|
+
notEnabledHint?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const SLASH_COMMANDS: SlashCommand[];
|
|
18
|
+
/** 按命令名前缀过滤(菜单下拉用)。空前缀返回全部。 */
|
|
19
|
+
export declare function filterSlashCommands(prefix: string): SlashCommand[];
|
|
20
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/tui/slash/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,OAAO,GACP,SAAS,GACT,OAAO,GACP,MAAM,CAAC;AAEX,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,wCAAwC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,cAAc,EAAE,YAAY,EAYxC,CAAC;AAEF,+BAA+B;AAC/B,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAIlE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash 命令注册表(纯数据 + 类型)。
|
|
3
|
+
*
|
|
4
|
+
* M1:输入 `/` 唤起命令菜单时,从这里过滤命令;提交时按 name 派发到 App 的
|
|
5
|
+
* dispatchSlash。命令执行逻辑在 app.tsx(因为多数命令需要操作 App 状态 /
|
|
6
|
+
* EventBus / 持久化),本文件只描述"有哪些命令、怎么展示"。
|
|
7
|
+
*/
|
|
8
|
+
export const SLASH_COMMANDS = [
|
|
9
|
+
{ name: 'help', description: '打开完整帮助' },
|
|
10
|
+
{ name: 'status', description: '显示当前配置(模型/workspace/session)' },
|
|
11
|
+
{ name: 'clear', description: '清空对话历史' },
|
|
12
|
+
{ name: 'quit', description: '优雅退出' },
|
|
13
|
+
{ name: 'exit', description: '优雅退出' },
|
|
14
|
+
{ name: 'model', description: '显示当前模型' },
|
|
15
|
+
{ name: 'session', description: '显示 session 信息' },
|
|
16
|
+
{ name: 'theme', description: '切换主题(dark/light/mono)', takesArgument: true },
|
|
17
|
+
{ name: 'compact', description: '手动触发压缩', notEnabledHint: '压缩功能未启用' },
|
|
18
|
+
{ name: 'think', description: '展开 Thinking 到滚动历史', notEnabledHint: 'Thinking 展开未启用' },
|
|
19
|
+
{ name: 'keys', description: '打开键位帮助面板' },
|
|
20
|
+
];
|
|
21
|
+
/** 按命令名前缀过滤(菜单下拉用)。空前缀返回全部。 */
|
|
22
|
+
export function filterSlashCommands(prefix) {
|
|
23
|
+
const p = prefix.toLowerCase();
|
|
24
|
+
if (!p)
|
|
25
|
+
return SLASH_COMMANDS;
|
|
26
|
+
return SLASH_COMMANDS.filter((c) => c.name.startsWith(p));
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/tui/slash/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAwBH,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE;IACvC,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8BAA8B,EAAE;IAC/D,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE;IACxC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;IACrC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;IACrC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE;IACxC,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE;IACjD,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,aAAa,EAAE,IAAI,EAAE;IAC5E,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE;IACrE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE;IACrF,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE;CAC1C,CAAC;AAEF,+BAA+B;AAC/B,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IAC/B,IAAI,CAAC,CAAC;QAAE,OAAO,cAAc,CAAC;IAC9B,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自研 Spinner(braille 帧轮换),替代 Header 里静态的 "⏳ 思考中…"。
|
|
3
|
+
*
|
|
4
|
+
* M2:busy=true 时状态行显示转动的 spinner,消除"卡死"错觉。
|
|
5
|
+
* 80ms/帧,组件卸载时清定时器。
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
export declare function Spinner({ color }: {
|
|
9
|
+
color?: string;
|
|
10
|
+
}): React.ReactElement;
|
|
11
|
+
//# sourceMappingURL=spinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/tui/spinner.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,wBAAgB,OAAO,CAAC,EAAE,KAAgB,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,YAAY,CASpF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* 自研 Spinner(braille 帧轮换),替代 Header 里静态的 "⏳ 思考中…"。
|
|
4
|
+
*
|
|
5
|
+
* M2:busy=true 时状态行显示转动的 spinner,消除"卡死"错觉。
|
|
6
|
+
* 80ms/帧,组件卸载时清定时器。
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useEffect } from 'react';
|
|
9
|
+
import { Text } from 'ink';
|
|
10
|
+
const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
11
|
+
export function Spinner({ color = 'yellow' }) {
|
|
12
|
+
const [i, setI] = useState(0);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
// 12.5 FPS 太高,与流式 token 叠加会导致 Ink 帧缓冲频繁重绘(屏幕闪烁).
|
|
15
|
+
// 降到 5 FPS(200ms)视觉上仍顺滑,但 setState 次数减 60%,闪烁明显缓解.
|
|
16
|
+
const id = setInterval(() => setI((p) => (p + 1) % FRAMES.length), 200);
|
|
17
|
+
return () => clearInterval(id);
|
|
18
|
+
}, []);
|
|
19
|
+
return _jsx(Text, { color: color, children: FRAMES[i] });
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=spinner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/tui/spinner.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AACH,OAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE3B,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAElE,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,GAAG,QAAQ,EAAsB;IAC9D,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9B,SAAS,CAAC,GAAG,EAAE;QACb,iDAAiD;QACjD,mDAAmD;QACnD,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QACxE,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,MAAM,CAAC,CAAC,CAAC,GAAQ,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 状态栏(M2,替代原 Header)。
|
|
3
|
+
*
|
|
4
|
+
* 单行紧凑布局:wukong · <model> · <cwd> · <状态> · <耗时>
|
|
5
|
+
*
|
|
6
|
+
* ## 24-tui-redesign-viewport.md 改造(瘦身)
|
|
7
|
+
* - 去掉常驻 emoji 字段图标(📡=model / 📂=session / 🎯=step / 💾=cache):
|
|
8
|
+
* 这些对普通用户是噪声,且 emoji 语义错乱(📂 实为 session)。
|
|
9
|
+
* - 技术指标(step / cache% / session)移入 **devMode** 才显示(环境变量
|
|
10
|
+
* `WUKONG_DEV=1` 或显式 devMode prop),便于调试而不打扰日常使用。
|
|
11
|
+
* - 窄终端(cols < 60)省略 cwd,避免状态栏折行。
|
|
12
|
+
* - 颜色来自主题(M6);未提供 Provider 时 useTheme 降级为 dark。
|
|
13
|
+
*/
|
|
14
|
+
import React from 'react';
|
|
15
|
+
export interface StatusBarProps {
|
|
16
|
+
model: string;
|
|
17
|
+
workspaceRoot: string;
|
|
18
|
+
/** 当前是否在等待 agent 响应 */
|
|
19
|
+
busy: boolean;
|
|
20
|
+
/** 最近一次 run 的耗时(ms);undefined 表示尚未完成任何 run */
|
|
21
|
+
lastDurationMs?: number;
|
|
22
|
+
/** 当前 step(从 1 开始);0 表示尚未开始或已结束 */
|
|
23
|
+
currentStep?: number;
|
|
24
|
+
/** 最大 step 数 */
|
|
25
|
+
maxSteps?: number;
|
|
26
|
+
/** 累计 cache 命中率(0-1) */
|
|
27
|
+
cacheHitRate?: number;
|
|
28
|
+
/** 本轮 run 开始时间戳(ms);用于实时计时 */
|
|
29
|
+
runStartAt?: number | null;
|
|
30
|
+
/** 本轮已耗时(秒);由 App 用 useElapsed 集中计算后传入,避免重复 setInterval */
|
|
31
|
+
elapsedSec?: number;
|
|
32
|
+
/** 是否正在中断 */
|
|
33
|
+
aborting?: boolean;
|
|
34
|
+
/** 未消费的通知数;>0 时显示提示 */
|
|
35
|
+
noticeCount?: number;
|
|
36
|
+
/** dev 模式:显示 step / cache% / session 等技术指标 */
|
|
37
|
+
devMode?: boolean;
|
|
38
|
+
/** dev 模式下显示 session uuid 短码 */
|
|
39
|
+
sessionUuidShort?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function StatusBar({ model, workspaceRoot, busy, lastDurationMs, currentStep, maxSteps, cacheHitRate, runStartAt, aborting, noticeCount, devMode, sessionUuidShort, elapsedSec, }: StatusBarProps): React.ReactElement;
|
|
42
|
+
//# sourceMappingURL=status-bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-bar.d.ts","sourceRoot":"","sources":["../../src/tui/status-bar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,uBAAuB;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gCAAgC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,aAAa,EACb,IAAI,EACJ,cAAc,EACd,WAAe,EACf,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,WAAe,EACf,OAAwC,EACxC,gBAAgB,EAChB,UAAU,GACX,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAyDrC"}
|