@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.
Files changed (135) hide show
  1. package/dist/cli/help.js +1 -1
  2. package/dist/cli/session-commands.d.ts.map +1 -1
  3. package/dist/cli/session-commands.js +4 -3
  4. package/dist/cli/session-commands.js.map +1 -1
  5. package/dist/index.js +73 -12
  6. package/dist/index.js.map +1 -1
  7. package/dist/tui/activity-verb.d.ts +29 -0
  8. package/dist/tui/activity-verb.d.ts.map +1 -0
  9. package/dist/tui/activity-verb.js +81 -0
  10. package/dist/tui/activity-verb.js.map +1 -0
  11. package/dist/tui/app.d.ts +29 -28
  12. package/dist/tui/app.d.ts.map +1 -1
  13. package/dist/tui/app.js +259 -132
  14. package/dist/tui/app.js.map +1 -1
  15. package/dist/tui/diff-count.d.ts +14 -0
  16. package/dist/tui/diff-count.d.ts.map +1 -0
  17. package/dist/tui/diff-count.js +21 -0
  18. package/dist/tui/diff-count.js.map +1 -0
  19. package/dist/tui/hint-bar.d.ts +12 -0
  20. package/dist/tui/hint-bar.d.ts.map +1 -0
  21. package/dist/tui/hint-bar.js +14 -0
  22. package/dist/tui/hint-bar.js.map +1 -0
  23. package/dist/tui/history-entry.d.ts +11 -0
  24. package/dist/tui/history-entry.d.ts.map +1 -0
  25. package/dist/tui/history-entry.js +35 -0
  26. package/dist/tui/history-entry.js.map +1 -0
  27. package/dist/tui/history-item.d.ts +40 -0
  28. package/dist/tui/history-item.d.ts.map +1 -0
  29. package/dist/tui/history-item.js +8 -0
  30. package/dist/tui/history-item.js.map +1 -0
  31. package/dist/tui/keys-help.d.ts +5 -0
  32. package/dist/tui/keys-help.d.ts.map +1 -0
  33. package/dist/tui/keys-help.js +36 -0
  34. package/dist/tui/keys-help.js.map +1 -0
  35. package/dist/tui/live-block.d.ts +54 -0
  36. package/dist/tui/live-block.d.ts.map +1 -0
  37. package/dist/tui/live-block.js +72 -0
  38. package/dist/tui/live-block.js.map +1 -0
  39. package/dist/tui/main-area.d.ts +40 -0
  40. package/dist/tui/main-area.d.ts.map +1 -0
  41. package/dist/tui/main-area.js +9 -0
  42. package/dist/tui/main-area.js.map +1 -0
  43. package/dist/tui/markdown.d.ts +14 -0
  44. package/dist/tui/markdown.d.ts.map +1 -0
  45. package/dist/tui/markdown.js +134 -0
  46. package/dist/tui/markdown.js.map +1 -0
  47. package/dist/tui/notice-panel.d.ts +20 -0
  48. package/dist/tui/notice-panel.d.ts.map +1 -0
  49. package/dist/tui/notice-panel.js +19 -0
  50. package/dist/tui/notice-panel.js.map +1 -0
  51. package/dist/tui/response-panel.d.ts +12 -16
  52. package/dist/tui/response-panel.d.ts.map +1 -1
  53. package/dist/tui/response-panel.js +8 -11
  54. package/dist/tui/response-panel.js.map +1 -1
  55. package/dist/tui/run-ink.d.ts +12 -0
  56. package/dist/tui/run-ink.d.ts.map +1 -1
  57. package/dist/tui/run-ink.js +2 -1
  58. package/dist/tui/run-ink.js.map +1 -1
  59. package/dist/tui/slash/menu.d.ts +16 -0
  60. package/dist/tui/slash/menu.d.ts.map +1 -0
  61. package/dist/tui/slash/menu.js +11 -0
  62. package/dist/tui/slash/menu.js.map +1 -0
  63. package/dist/tui/slash/parse.d.ts +21 -0
  64. package/dist/tui/slash/parse.d.ts.map +1 -0
  65. package/dist/tui/slash/parse.js +32 -0
  66. package/dist/tui/slash/parse.js.map +1 -0
  67. package/dist/tui/slash/registry.d.ts +20 -0
  68. package/dist/tui/slash/registry.d.ts.map +1 -0
  69. package/dist/tui/slash/registry.js +28 -0
  70. package/dist/tui/slash/registry.js.map +1 -0
  71. package/dist/tui/spinner.d.ts +11 -0
  72. package/dist/tui/spinner.d.ts.map +1 -0
  73. package/dist/tui/spinner.js +21 -0
  74. package/dist/tui/spinner.js.map +1 -0
  75. package/dist/tui/status-bar.d.ts +42 -0
  76. package/dist/tui/status-bar.d.ts.map +1 -0
  77. package/dist/tui/status-bar.js +32 -0
  78. package/dist/tui/status-bar.js.map +1 -0
  79. package/dist/tui/tail-visual.d.ts +11 -0
  80. package/dist/tui/tail-visual.d.ts.map +1 -0
  81. package/dist/tui/tail-visual.js +30 -0
  82. package/dist/tui/tail-visual.js.map +1 -0
  83. package/dist/tui/text-input.d.ts +20 -22
  84. package/dist/tui/text-input.d.ts.map +1 -1
  85. package/dist/tui/text-input.js +211 -81
  86. package/dist/tui/text-input.js.map +1 -1
  87. package/dist/tui/theme/context.d.ts +16 -0
  88. package/dist/tui/theme/context.d.ts.map +1 -0
  89. package/dist/tui/theme/context.js +28 -0
  90. package/dist/tui/theme/context.js.map +1 -0
  91. package/dist/tui/theme/persist.d.ts +11 -0
  92. package/dist/tui/theme/persist.d.ts.map +1 -0
  93. package/dist/tui/theme/persist.js +41 -0
  94. package/dist/tui/theme/persist.js.map +1 -0
  95. package/dist/tui/theme/theme.d.ts +26 -0
  96. package/dist/tui/theme/theme.d.ts.map +1 -0
  97. package/dist/tui/theme/theme.js +51 -0
  98. package/dist/tui/theme/theme.js.map +1 -0
  99. package/dist/tui/thinking-panel.d.ts +11 -20
  100. package/dist/tui/thinking-panel.d.ts.map +1 -1
  101. package/dist/tui/thinking-panel.js +29 -7
  102. package/dist/tui/thinking-panel.js.map +1 -1
  103. package/dist/tui/tool-cards.d.ts +5 -17
  104. package/dist/tui/tool-cards.d.ts.map +1 -1
  105. package/dist/tui/tool-cards.js +4 -5
  106. package/dist/tui/tool-cards.js.map +1 -1
  107. package/dist/tui/tool-summary.d.ts +2 -0
  108. package/dist/tui/tool-summary.d.ts.map +1 -0
  109. package/dist/tui/tool-summary.js +93 -0
  110. package/dist/tui/tool-summary.js.map +1 -0
  111. package/dist/tui/use-elapsed.d.ts +2 -0
  112. package/dist/tui/use-elapsed.d.ts.map +1 -0
  113. package/dist/tui/use-elapsed.js +22 -0
  114. package/dist/tui/use-elapsed.js.map +1 -0
  115. package/dist/tui/use-plan-state.d.ts +20 -1
  116. package/dist/tui/use-plan-state.d.ts.map +1 -1
  117. package/dist/tui/use-plan-state.js +52 -46
  118. package/dist/tui/use-plan-state.js.map +1 -1
  119. package/dist/tui/use-terminal-width.d.ts +2 -0
  120. package/dist/tui/use-terminal-width.d.ts.map +1 -0
  121. package/dist/tui/use-terminal-width.js +23 -0
  122. package/dist/tui/use-terminal-width.js.map +1 -0
  123. package/dist/tui/use-viewport.d.ts +15 -0
  124. package/dist/tui/use-viewport.d.ts.map +1 -0
  125. package/dist/tui/use-viewport.js +37 -0
  126. package/dist/tui/use-viewport.js.map +1 -0
  127. package/dist/tui/welcome.d.ts +29 -0
  128. package/dist/tui/welcome.d.ts.map +1 -0
  129. package/dist/tui/welcome.js +41 -0
  130. package/dist/tui/welcome.js.map +1 -0
  131. package/package.json +3 -2
  132. package/dist/tui/header.d.ts +0 -24
  133. package/dist/tui/header.d.ts.map +0 -1
  134. package/dist/tui/header.js +0 -26
  135. 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":"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"}
@@ -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
- * App 层订阅 EventBus 的 `tool_call_start/end` / `step_start/end` / `cache_stat`
7
- * 等事件,以及 LLM 流式的 `content_delta`(通过 onStream 回调,因为 content_delta
8
- * 还没进 EventBus —— 它属于 LLM 流式层,与 EventBus 的语义层级不同)
6
+ * - 移除"仅字符数摘要"的应急显示,恢复**逐字流式**:streaming 时直接渲染正文
7
+ * 末尾 maxLines 个视觉行(按终端宽度折算),末行带 `▍` 光标。
8
+ * - 响应结束后完整正文进入 <Static>(App 负责),动态区只保留完成信号。
9
+ * - 错误展示已移至独立的 NoticePanel(M8),本组件不再承担 error。
9
10
  *
10
- * 为了 M1 范围可控,本组件只渲染:
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
- error?: string;
41
+ /** 流式区最大视觉行数(默认 6) */
42
+ maxLines?: number;
47
43
  }
48
- export declare function ResponsePanel({ streamingText, streaming, activeTools, lastCompleted, error, }: ResponsePanelProps): React.ReactElement;
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;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,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;CACxB;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,yDAAyD;IACzD,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,4BAA4B;IAC5B,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,eAAe;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,EAC5B,aAAa,EACb,SAAS,EACT,WAAW,EACX,aAAa,EACb,KAAK,GACN,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CA+CzC"}
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 { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Text, Box } from 'ink';
3
- export function ResponsePanel({ streamingText, streaming, activeTools, lastCompleted, error, }) {
4
- const chars = streamingText.length;
5
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [error && (_jsx(Box, { marginBottom: error ? 1 : 0, children: _jsxs(Text, { color: "red", bold: true, children: ["\u274C ", error] }) })), streaming && (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: "\u231B \u6B63\u5728\u751F\u6210\u54CD\u5E94\u2026 " }), _jsxs(Text, { dimColor: true, children: ["(", chars, " \u5B57\u7B26,\u5B8C\u6210\u540E\u5C55\u793A\u5B8C\u6574\u5185\u5BB9)"] })] })), activeTools.length > 0 && (_jsx(Box, { flexDirection: "column", marginY: streaming ? 1 : 0, children: activeTools.map((t) => (_jsx(ToolCallRow, { tool: t }, t.toolCallId))) })), !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)"] })] }))] }));
6
- }
7
- function ToolCallRow({ tool }) {
8
- const now = Date.now();
9
- const elapsed = ((tool.endedAt ?? now) - tool.startedAt) / 1000;
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":";AAiBA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAgChC,MAAM,UAAU,aAAa,CAAC,EAC5B,aAAa,EACb,SAAS,EACT,WAAW,EACX,aAAa,EACb,KAAK,GACc;IACnB,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC;IACnC,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,aAEpC,KAAK,IAAI,CACR,KAAC,GAAG,IAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAC9B,MAAC,IAAI,IAAC,KAAK,EAAC,KAAK,EAAC,IAAI,8BAAI,KAAK,IAAQ,GACnC,CACP,EAOA,SAAS,IAAI,CACZ,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,mEAAkB,EACpC,MAAC,IAAI,IAAC,QAAQ,wBAAG,KAAK,6EAAsB,IACxC,CACP,EAGA,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,CACzB,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YACnD,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACtB,KAAC,WAAW,IAAoB,IAAI,EAAE,CAAC,IAArB,CAAC,CAAC,UAAU,CAAa,CAC5C,CAAC,GACE,CACP,EAOA,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,kCAAU,aAAa,CAAC,KAAK,qBAAO,CAAC,aAAa,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UACzH,IACH,CACP,IACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,IAAI,EAA2B;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IACrF,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,IAAI,GAAQ,EACjC,MAAC,IAAI,IAAC,QAAQ,+BAAK,IAAI,CAAC,IAAI,IAAQ,EACpC,MAAC,IAAI,IAAC,QAAQ,yBAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,EAC7C,IAAI,CAAC,aAAa,IAAI,CACrB,MAAC,IAAI,IAAC,QAAQ,wBAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAQ,CACzD,IACI,CACR,CAAC;AACJ,CAAC"}
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"}
@@ -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;AAErD,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;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAexD"}
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"}
@@ -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
  };
@@ -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;AAoBrD;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,IAAmB;IACxC,MAAM,WAAW,GAAG,MAAM,CACxB,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,GACjC,CACH,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE;KACrC,CAAC;AACJ,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"}