@wukonglabs/wukong 0.0.8 → 0.0.10
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.d.ts.map +1 -1
- package/dist/cli/help.js +10 -9
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/session-commands.d.ts +28 -0
- package/dist/cli/session-commands.d.ts.map +1 -0
- package/dist/cli/session-commands.js +274 -0
- package/dist/cli/session-commands.js.map +1 -0
- package/dist/cli/summary.js +2 -6
- package/dist/cli/summary.js.map +1 -1
- package/dist/cli/workspace-commands.d.ts +15 -0
- package/dist/cli/workspace-commands.d.ts.map +1 -0
- package/dist/cli/workspace-commands.js +98 -0
- package/dist/cli/workspace-commands.js.map +1 -0
- package/dist/index.js +429 -131
- 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 +194 -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 +29 -0
- package/dist/tui/plan-panel.d.ts.map +1 -0
- package/dist/tui/plan-panel.js +26 -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 +13 -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 +31 -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 +52 -0
- package/dist/tui/text-input.d.ts.map +1 -0
- package/dist/tui/text-input.js +321 -0
- package/dist/tui/text-input.js.map +1 -0
- package/dist/tui/thinking-panel.d.ts +40 -0
- package/dist/tui/thinking-panel.d.ts.map +1 -0
- package/dist/tui/thinking-panel.js +54 -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 +34 -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 +73 -0
- package/dist/tui/use-plan-state.js.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/tui/header.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 授权卡片组件(§3.6 M2)。
|
|
3
|
+
*
|
|
4
|
+
* 当 agent 调用"有副作用"工具时,阻塞主输入,展示工具参数摘要,
|
|
5
|
+
* 让用户选择四挡决策:
|
|
6
|
+
* - y / Enter:once(仅本次)
|
|
7
|
+
* - s:session(本次 session 内)
|
|
8
|
+
* - l:always-local(本项目永久)
|
|
9
|
+
* - g:always-global(所有项目永久)
|
|
10
|
+
* - n:no(拒绝本次)
|
|
11
|
+
* - N:no-always(永久拒绝)
|
|
12
|
+
*
|
|
13
|
+
* ## 设计
|
|
14
|
+
*
|
|
15
|
+
* 纯展示组件,接收 request + onSubmit 回调。
|
|
16
|
+
* App 层负责把 ToolAuthorizer 的 requestAuthorization 桥接到本组件。
|
|
17
|
+
*/
|
|
18
|
+
import React from 'react';
|
|
19
|
+
import type { AuthorizationRequest, AuthorizationResult } from '@wukonglabs/wukong-agent-sdk';
|
|
20
|
+
export interface PermissionCardProps {
|
|
21
|
+
/** 授权请求 */
|
|
22
|
+
request: AuthorizationRequest;
|
|
23
|
+
/** 用户决策回调 */
|
|
24
|
+
onSubmit: (result: AuthorizationResult) => void;
|
|
25
|
+
}
|
|
26
|
+
export declare function PermissionCard({ request, onSubmit }: PermissionCardProps): React.ReactElement;
|
|
27
|
+
//# sourceMappingURL=permission-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-card.d.ts","sourceRoot":"","sources":["../../src/tui/permission-card.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAyB,MAAM,8BAA8B,CAAC;AAErH,MAAM,WAAW,mBAAmB;IAClC,WAAW;IACX,OAAO,EAAE,oBAAoB,CAAC;IAC9B,aAAa;IACb,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACjD;AAED,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CA+E7F"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* 授权卡片组件(§3.6 M2)。
|
|
4
|
+
*
|
|
5
|
+
* 当 agent 调用"有副作用"工具时,阻塞主输入,展示工具参数摘要,
|
|
6
|
+
* 让用户选择四挡决策:
|
|
7
|
+
* - y / Enter:once(仅本次)
|
|
8
|
+
* - s:session(本次 session 内)
|
|
9
|
+
* - l:always-local(本项目永久)
|
|
10
|
+
* - g:always-global(所有项目永久)
|
|
11
|
+
* - n:no(拒绝本次)
|
|
12
|
+
* - N:no-always(永久拒绝)
|
|
13
|
+
*
|
|
14
|
+
* ## 设计
|
|
15
|
+
*
|
|
16
|
+
* 纯展示组件,接收 request + onSubmit 回调。
|
|
17
|
+
* App 层负责把 ToolAuthorizer 的 requestAuthorization 桥接到本组件。
|
|
18
|
+
*/
|
|
19
|
+
import { useState } from 'react';
|
|
20
|
+
import { Box, Text, useInput } from 'ink';
|
|
21
|
+
export function PermissionCard({ request, onSubmit }) {
|
|
22
|
+
const [showFullArgs, setShowFullArgs] = useState(false);
|
|
23
|
+
useInput((input, key) => {
|
|
24
|
+
const c = input.toLowerCase();
|
|
25
|
+
let result = null;
|
|
26
|
+
switch (c) {
|
|
27
|
+
case 'y':
|
|
28
|
+
case '': // Enter(ink useInput 的 return 会被当成空字符串)
|
|
29
|
+
result = { approved: true, decision: 'once' };
|
|
30
|
+
break;
|
|
31
|
+
case 's':
|
|
32
|
+
result = { approved: true, decision: 'session' };
|
|
33
|
+
break;
|
|
34
|
+
case 'l':
|
|
35
|
+
result = { approved: true, decision: 'always-local' };
|
|
36
|
+
break;
|
|
37
|
+
case 'g':
|
|
38
|
+
result = { approved: true, decision: 'always-global' };
|
|
39
|
+
break;
|
|
40
|
+
case 'n':
|
|
41
|
+
result = { approved: false, decision: 'no' };
|
|
42
|
+
break;
|
|
43
|
+
case 'x': // 大写 N 不好按,用 x 代表 no-always
|
|
44
|
+
result = { approved: false, decision: 'no-always' };
|
|
45
|
+
break;
|
|
46
|
+
case 'v':
|
|
47
|
+
setShowFullArgs((v) => !v);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (key.return) {
|
|
51
|
+
result = { approved: true, decision: 'once' };
|
|
52
|
+
}
|
|
53
|
+
if (result) {
|
|
54
|
+
onSubmit(result);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const argsPreview = formatArgsPreview(request.argumentsJson, showFullArgs ? undefined : 200);
|
|
58
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "yellow", bold: true, children: "\uD83D\uDD12 \u6388\u6743\u8BF7\u6C42" }), _jsxs(Text, { dimColor: true, children: [" (step ", request.step, ")"] })] }), _jsxs(Box, { children: [_jsx(Text, { bold: true, children: "\u5DE5\u5177: " }), _jsx(Text, { color: "cyan", children: request.toolName })] }), _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "\u53C2\u6570:" }), _jsx(Text, { dimColor: true, children: argsPreview }), !showFullArgs && request.argumentsJson.length > 200 && (_jsx(Text, { dimColor: true, color: "gray", children: "(\u6309 v \u67E5\u770B\u5B8C\u6574\u53C2\u6570)" }))] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { bold: true, children: "\u9009\u62E9: " }) }), _jsxs(Box, { children: [_jsx(Text, { color: "green", children: "[y]" }), _jsx(Text, { children: " \u4EC5\u672C\u6B21 " }), _jsx(Text, { color: "green", children: "[s]" }), _jsx(Text, { children: " \u672C\u6B21session " }), _jsx(Text, { color: "green", children: "[l]" }), _jsx(Text, { children: " \u672C\u9879\u76EE\u6C38\u4E45 " }), _jsx(Text, { color: "green", children: "[g]" }), _jsx(Text, { children: " \u5168\u5C40\u6C38\u4E45" })] }), _jsxs(Box, { children: [_jsx(Text, { color: "red", children: "[n]" }), _jsx(Text, { children: " \u62D2\u7EDD " }), _jsx(Text, { color: "red", children: "[x]" }), _jsx(Text, { children: " \u6C38\u4E45\u62D2\u7EDD " }), _jsx(Text, { dimColor: true, children: "[v] \u67E5\u770B\u53C2\u6570" })] })] }));
|
|
59
|
+
}
|
|
60
|
+
/** 格式化参数预览(截断到 maxLen) */
|
|
61
|
+
function formatArgsPreview(argsJson, maxLen) {
|
|
62
|
+
let formatted;
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(argsJson);
|
|
65
|
+
formatted = JSON.stringify(parsed, null, 2);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
formatted = argsJson;
|
|
69
|
+
}
|
|
70
|
+
if (maxLen !== undefined && formatted.length > maxLen) {
|
|
71
|
+
return formatted.slice(0, maxLen) + '\n…(截断)';
|
|
72
|
+
}
|
|
73
|
+
return formatted;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=permission-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-card.js","sourceRoot":"","sources":["../../src/tui/permission-card.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan panel —— 展示 todo 进度。
|
|
3
|
+
*
|
|
4
|
+
* ## 设计
|
|
5
|
+
*
|
|
6
|
+
* 本组件是**纯展示**组件,接收 todos 列表作为 props。
|
|
7
|
+
* 事件订阅(PlanUpdateEvent → todos 增删改)由 App 层负责,通过 `usePlanState` hook。
|
|
8
|
+
* 这样 PlanPanel 可独立测试,不依赖 EventBus 时序。
|
|
9
|
+
*
|
|
10
|
+
* ## 渲染
|
|
11
|
+
*
|
|
12
|
+
* ```
|
|
13
|
+
* ▶ Plan (3/5)
|
|
14
|
+
* ✓ 1. 分析项目结构
|
|
15
|
+
* ⏳ 2. 找出重复代码 ← 当前
|
|
16
|
+
* ○ 3. 重构工具函数
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import React from 'react';
|
|
20
|
+
export interface TodoItem {
|
|
21
|
+
id: string;
|
|
22
|
+
content: string;
|
|
23
|
+
status: 'pending' | 'in_progress' | 'completed' | 'cancelled';
|
|
24
|
+
}
|
|
25
|
+
export interface PlanPanelProps {
|
|
26
|
+
todos: TodoItem[];
|
|
27
|
+
}
|
|
28
|
+
export declare function PlanPanel({ todos }: PlanPanelProps): React.ReactElement | null;
|
|
29
|
+
//# sourceMappingURL=plan-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-panel.d.ts","sourceRoot":"","sources":["../../src/tui/plan-panel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,CAAC;CAC/D;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAgB9E"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function PlanPanel({ todos }) {
|
|
4
|
+
if (todos.length === 0)
|
|
5
|
+
return null;
|
|
6
|
+
const completed = todos.filter((t) => t.status === 'completed').length;
|
|
7
|
+
const total = todos.length;
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", marginY: 0, children: [_jsxs(Text, { color: "cyan", bold: true, children: ["\u25B6 Plan (", completed, "/", total, ")"] }), todos.map((t, i) => (_jsx(TodoRow, { index: i + 1, todo: t }, t.id)))] }));
|
|
9
|
+
}
|
|
10
|
+
function TodoRow({ index, todo }) {
|
|
11
|
+
const { icon, color } = statusIcon(todo.status);
|
|
12
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: color, children: icon }), _jsxs(Text, { dimColor: true, children: [" ", index, ". "] }), _jsxs(Text, { color: color === 'gray' ? undefined : color, children: [todo.content, todo.status === 'in_progress' ? ' ← 当前' : ''] })] }));
|
|
13
|
+
}
|
|
14
|
+
function statusIcon(status) {
|
|
15
|
+
switch (status) {
|
|
16
|
+
case 'completed':
|
|
17
|
+
return { icon: '✓', color: 'green' };
|
|
18
|
+
case 'in_progress':
|
|
19
|
+
return { icon: '⏳', color: 'yellow' };
|
|
20
|
+
case 'cancelled':
|
|
21
|
+
return { icon: '✗', color: 'red' };
|
|
22
|
+
default:
|
|
23
|
+
return { icon: '○', color: 'gray' };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=plan-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-panel.js","sourceRoot":"","sources":["../../src/tui/plan-panel.tsx"],"names":[],"mappings":";AAmBA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAYhC,MAAM,UAAU,SAAS,CAAC,EAAE,KAAK,EAAkB;IACjD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,CAAC;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;IAE3B,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,MAAC,IAAI,IAAC,KAAK,EAAC,MAAM,EAAC,IAAI,oCACZ,SAAS,OAAG,KAAK,SACrB,EACN,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACnB,KAAC,OAAO,IAAY,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,IAA3B,CAAC,CAAC,EAAE,CAA2B,CAC9C,CAAC,IACE,CACP,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAqC;IACjE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChD,OAAO,CACL,MAAC,GAAG,eACF,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,IAAI,GAAQ,EACjC,MAAC,IAAI,IAAC,QAAQ,wBAAG,KAAK,UAAU,EAChC,MAAC,IAAI,IAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,aAC9C,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IACxC,IACH,CACP,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,MAA0B;IAC5C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,WAAW;YACd,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QACvC,KAAK,aAAa;YAChB,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;QACxC,KAAK,WAAW;YACd,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACrC;YACE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACxC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response panel —— 流式渲染 agent 响应。
|
|
3
|
+
*
|
|
4
|
+
* ## 数据源
|
|
5
|
+
*
|
|
6
|
+
* App 层订阅 EventBus 的 `tool_call_start/end` / `step_start/end` / `cache_stat`
|
|
7
|
+
* 等事件,以及 LLM 流式的 `content_delta`(通过 onStream 回调,因为 content_delta
|
|
8
|
+
* 还没进 EventBus —— 它属于 LLM 流式层,与 EventBus 的语义层级不同)。
|
|
9
|
+
*
|
|
10
|
+
* 为了 M1 范围可控,本组件只渲染:
|
|
11
|
+
* - 当前正在生成的响应文本(流式)
|
|
12
|
+
* - 最近一次完成的响应(带步骤/Token 统计)
|
|
13
|
+
* - 进行中的 tool call 摘要(状态 + 耗时)
|
|
14
|
+
*
|
|
15
|
+
* 完整的 Tool cards / Plan panel 留到 M3-M5。
|
|
16
|
+
*/
|
|
17
|
+
import React from 'react';
|
|
18
|
+
export interface ToolCallState {
|
|
19
|
+
toolCallId: string;
|
|
20
|
+
name: string;
|
|
21
|
+
step: number;
|
|
22
|
+
startedAt: number;
|
|
23
|
+
endedAt?: number;
|
|
24
|
+
success?: boolean;
|
|
25
|
+
resultPreview?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface CompletedRun {
|
|
28
|
+
response: string;
|
|
29
|
+
steps: number;
|
|
30
|
+
totalTokens: {
|
|
31
|
+
prompt: number;
|
|
32
|
+
completion: number;
|
|
33
|
+
};
|
|
34
|
+
durationMs: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ResponsePanelProps {
|
|
37
|
+
/** 正在流式输出的文本(content_delta 累积) */
|
|
38
|
+
streamingText: string;
|
|
39
|
+
/** 流式是否正在进行 */
|
|
40
|
+
streaming: boolean;
|
|
41
|
+
/** 当前活跃的 tool call(tool_call_start 后、tool_call_end 前) */
|
|
42
|
+
activeTools: ToolCallState[];
|
|
43
|
+
/** 最近一次完成的 run(用于展示历史响应) */
|
|
44
|
+
lastCompleted?: CompletedRun;
|
|
45
|
+
/** 错误信息(若有) */
|
|
46
|
+
error?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function ResponsePanel({ streamingText, streaming, activeTools, lastCompleted, error, }: ResponsePanelProps): React.ReactElement;
|
|
49
|
+
//# sourceMappingURL=response-panel.d.ts.map
|
|
@@ -0,0 +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,CA4CzC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
export function ResponsePanel({ streamingText, streaming, activeTools, lastCompleted, error, }) {
|
|
4
|
+
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, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Wukong:" }), _jsx(Text, { children: streamingText }), _jsx(Text, { dimColor: true, children: "\u258B" })] })), 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, { flexDirection: "column", children: [_jsx(Text, { color: "cyan", bold: true, children: "Wukong:" }), _jsx(Text, { children: lastCompleted.response }), _jsxs(Text, { dimColor: true, children: ['\n [步骤: ', lastCompleted.steps, ' | Token: ', lastCompleted.totalTokens.prompt + lastCompleted.totalTokens.completion, ' (prompt=', lastCompleted.totalTokens.prompt, ', completion=', lastCompleted.totalTokens.completion, ')', ' | 耗时: ', (lastCompleted.durationMs / 1000).toFixed(1), "s", ']'] })] }))] }));
|
|
5
|
+
}
|
|
6
|
+
function ToolCallRow({ tool }) {
|
|
7
|
+
const now = Date.now();
|
|
8
|
+
const elapsed = ((tool.endedAt ?? now) - tool.startedAt) / 1000;
|
|
9
|
+
const icon = tool.success === undefined ? '⏳' : tool.success ? '✓' : '✗';
|
|
10
|
+
const color = tool.success === undefined ? 'yellow' : tool.success ? 'green' : 'red';
|
|
11
|
+
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)] }))] }));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=response-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-panel.js","sourceRoot":"","sources":["../../src/tui/response-panel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AppHandlers } from './app.js';
|
|
2
|
+
export interface InkRunOptions {
|
|
3
|
+
model: string;
|
|
4
|
+
sessionUuidShort: string;
|
|
5
|
+
workspaceRoot: string;
|
|
6
|
+
handlers: AppHandlers;
|
|
7
|
+
initialHistory?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface InkRunHandle {
|
|
10
|
+
/** 传给 agent.createAgent({ onStream }) 的回调 */
|
|
11
|
+
onStream: (event: import('@wukonglabs/wukong-agent-sdk').StreamEvent) => void;
|
|
12
|
+
/** 卸载 Ink 实例(退出时调用) */
|
|
13
|
+
unmount: () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 启动 Ink TUI,返回 onStream callback 供 agent 使用。
|
|
17
|
+
*
|
|
18
|
+
* 注意:render 是同步阻塞的(Ink 内部用 fiber),调用方在拿到 onStream 后
|
|
19
|
+
* 再去 init agent。
|
|
20
|
+
*/
|
|
21
|
+
export declare function runInk(opts: InkRunOptions): InkRunHandle;
|
|
22
|
+
//# sourceMappingURL=run-ink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-ink.d.ts","sourceRoot":"","sources":["../../src/tui/run-ink.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAO,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,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;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,8BAA8B,EAAE,WAAW,KAAK,IAAI,CAAC;IAC9E,uBAAuB;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAuBxD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* 启动 Ink TUI 的入口。
|
|
4
|
+
*
|
|
5
|
+
* 由 `runInteractive` 在判定 `shouldUseTui()` 为 true 时调用。
|
|
6
|
+
* 负责:
|
|
7
|
+
* 1. 创建 streamSinkRef(桥接 onStream → App)
|
|
8
|
+
* 2. render <App />,把 handlers 注入
|
|
9
|
+
* 3. 返回一个 onStream callback,由 index.ts 传给 agent
|
|
10
|
+
*/
|
|
11
|
+
import { render } from 'ink';
|
|
12
|
+
import { App } from './app.js';
|
|
13
|
+
/**
|
|
14
|
+
* 启动 Ink TUI,返回 onStream callback 供 agent 使用。
|
|
15
|
+
*
|
|
16
|
+
* 注意:render 是同步阻塞的(Ink 内部用 fiber),调用方在拿到 onStream 后
|
|
17
|
+
* 再去 init agent。
|
|
18
|
+
*/
|
|
19
|
+
export function runInk(opts) {
|
|
20
|
+
// streamSinkRef 用普通对象(App 接受 SinkRef 接口,不依赖 React useRef)
|
|
21
|
+
const sinkRef = { current: null };
|
|
22
|
+
const inkInstance = render(_jsx(App, { model: opts.model, sessionUuidShort: opts.sessionUuidShort, workspaceRoot: opts.workspaceRoot, handlers: opts.handlers, initialHistory: opts.initialHistory, streamSinkRef: sinkRef }));
|
|
23
|
+
const onStream = (event) => {
|
|
24
|
+
sinkRef.current?.(event);
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
onStream,
|
|
28
|
+
unmount: () => inkInstance.unmount(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=run-ink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-ink.js","sourceRoot":"","sources":["../../src/tui/run-ink.tsx"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAe,MAAM,UAAU,CAAC;AAiB5C;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,IAAmB;IACxC,0DAA0D;IAC1D,MAAM,OAAO,GAA+B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAE9D,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,OAAO,GACtB,CACH,CAAC;IAEF,MAAM,QAAQ,GAA6B,CAAC,KAAK,EAAE,EAAE;QACnD,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC;IAEF,OAAO;QACL,QAAQ;QACR,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE;KACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI 降级矩阵判定(§3.1 M1 红线)。
|
|
3
|
+
*
|
|
4
|
+
* 判定规则(任一为真 → 降级到 readline):
|
|
5
|
+
* - `WUKONG_TUI=off` 显式关闭(feature flag 出口,灰度期必备)
|
|
6
|
+
* - `CI=true` 环境变量(CI 模式不该有 UI)
|
|
7
|
+
* - stdin 或 stdout 非 TTY(pipe/重定向)
|
|
8
|
+
* - `TERM=dumb`(SSH pipe / 朴素终端)
|
|
9
|
+
*
|
|
10
|
+
* `NO_COLOR=1` 不触发降级(Ink 自身会关颜色,但保留 UI 结构)。
|
|
11
|
+
*/
|
|
12
|
+
export interface TuiEnvironment {
|
|
13
|
+
env: NodeJS.ProcessEnv;
|
|
14
|
+
stdinIsTTY: boolean;
|
|
15
|
+
stdoutIsTTY: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 返回 true 表示应该启用 Ink TUI;false 表示降级到 readline。
|
|
19
|
+
*/
|
|
20
|
+
export declare function shouldUseTui(env: TuiEnvironment): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* 便于在测试中直接用 process 构造环境。
|
|
23
|
+
*/
|
|
24
|
+
export declare function shouldUseTuiFromProcess(): boolean;
|
|
25
|
+
//# sourceMappingURL=should-use-tui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"should-use-tui.d.ts","sourceRoot":"","sources":["../../src/tui/should-use-tui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAczD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAMjD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 返回 true 表示应该启用 Ink TUI;false 表示降级到 readline。
|
|
3
|
+
*/
|
|
4
|
+
export function shouldUseTui(env) {
|
|
5
|
+
// 1. 显式 feature flag 出口
|
|
6
|
+
if (env.env.WUKONG_TUI === 'off')
|
|
7
|
+
return false;
|
|
8
|
+
// 2. CI 模式
|
|
9
|
+
if (env.env.CI === 'true')
|
|
10
|
+
return false;
|
|
11
|
+
// 3. 非 TTY(pipe / 重定向 / 嵌入式调用)
|
|
12
|
+
if (!env.stdinIsTTY || !env.stdoutIsTTY)
|
|
13
|
+
return false;
|
|
14
|
+
// 4. TERM=dumb
|
|
15
|
+
if (env.env.TERM === 'dumb')
|
|
16
|
+
return false;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 便于在测试中直接用 process 构造环境。
|
|
21
|
+
*/
|
|
22
|
+
export function shouldUseTuiFromProcess() {
|
|
23
|
+
return shouldUseTui({
|
|
24
|
+
env: process.env,
|
|
25
|
+
stdinIsTTY: process.stdin.isTTY === true,
|
|
26
|
+
stdoutIsTTY: process.stdout.isTTY === true,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=should-use-tui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"should-use-tui.js","sourceRoot":"","sources":["../../src/tui/should-use-tui.ts"],"names":[],"mappings":"AAiBA;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,GAAmB;IAC9C,wBAAwB;IACxB,IAAI,GAAG,CAAC,GAAG,CAAC,UAAU,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAE/C,WAAW;IACX,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAExC,+BAA+B;IAC/B,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC;IAEtD,eAAe;IACf,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAE1C,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,YAAY,CAAC;QAClB,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI;QACxC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;KAC3C,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 多行文本输入组件(自研,Ink 自带 ink-text-input 不支持多行 + Ctrl+R)。
|
|
3
|
+
*
|
|
4
|
+
* ## 交互
|
|
5
|
+
*
|
|
6
|
+
* - **Enter**:提交(若 `multiline` 为 false,任何 Enter 都提交)
|
|
7
|
+
* - **Shift+Enter / Alt+Enter**:换行(仅 multiline=true 时)
|
|
8
|
+
* - **Ctrl+J**:换行(终端友好,Ctrl+J = LF)
|
|
9
|
+
* - **↑ / ↓**(单行时):浏览历史
|
|
10
|
+
* - **↑ / ↓**(多行时):移动光标到上/下一行
|
|
11
|
+
* - **Ctrl+R**:进入反查模式;再按跳下一条匹配;Enter 提交当前匹配;Esc 退出
|
|
12
|
+
* - **Ctrl+C**:清理后退出(由 App 层接管 graceful shutdown)
|
|
13
|
+
* - **Ctrl+L**:清屏(Ink 原生 clear)
|
|
14
|
+
*
|
|
15
|
+
* ## 粘贴检测
|
|
16
|
+
*
|
|
17
|
+
* Ink 没有原生 paste 事件。通过监听 `stdin` 的 data chunk,当一次 chunk 中
|
|
18
|
+
* 含多个字符(特别是含换行)时,判定为粘贴,直接整体插入(不走逐字符 input)。
|
|
19
|
+
* 这避免了粘贴中文/长文本时每个字符都触发一次 re-render 的性能问题。
|
|
20
|
+
*
|
|
21
|
+
* ## 可访问性
|
|
22
|
+
*
|
|
23
|
+
* `multiline` 模式下不依赖光标可视化(终端光标控制在不同终端差异大),
|
|
24
|
+
* 用 `▋` 字符标记光标位置;`NO_COLOR` 时仍可见。
|
|
25
|
+
*/
|
|
26
|
+
import React from 'react';
|
|
27
|
+
import { useInputHistory } from './use-input-history.js';
|
|
28
|
+
export interface TextInputProps {
|
|
29
|
+
/** 当前值(受控) */
|
|
30
|
+
value: string;
|
|
31
|
+
/** 值变更回调 */
|
|
32
|
+
onChange: (value: string) => void;
|
|
33
|
+
/** 提交回调(Enter) */
|
|
34
|
+
onSubmit: (value: string) => void;
|
|
35
|
+
/** 是否启用多行(默认 true) */
|
|
36
|
+
multiline?: boolean;
|
|
37
|
+
/** 输入历史 hook(可选) */
|
|
38
|
+
history?: ReturnType<typeof useInputHistory>;
|
|
39
|
+
/** 提示符前缀(默认 "> ") */
|
|
40
|
+
prompt?: string;
|
|
41
|
+
/** placeholder(空输入时显示) */
|
|
42
|
+
placeholder?: string;
|
|
43
|
+
/** 是否禁用(等待 agent 响应时) */
|
|
44
|
+
disabled?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Ctrl+C 回调(§3.3 M3):由 App 层实现两次 Ctrl+C 语义。
|
|
47
|
+
* Ink raw mode 拦截 Ctrl+C,不走 process SIGINT,故需显式回调。
|
|
48
|
+
*/
|
|
49
|
+
onAbort?: () => void;
|
|
50
|
+
}
|
|
51
|
+
export declare function TextInput({ value, onChange, onSubmit, multiline, history, prompt, placeholder, disabled, onAbort, }: TextInputProps): React.ReactElement;
|
|
52
|
+
//# sourceMappingURL=text-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-input.d.ts","sourceRoot":"","sources":["../../src/tui/text-input.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAmD,MAAM,OAAO,CAAC;AAExE,OAAO,EACL,eAAe,EAGhB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,cAAc;IAC7B,cAAc;IACd,KAAK,EAAE,MAAM,CAAC;IACd,YAAY;IACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,kBAAkB;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sBAAsB;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB;IACpB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;IAC7C,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAeD,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,SAAgB,EAChB,OAAO,EACP,MAAa,EACb,WAAgB,EAChB,QAAgB,EAChB,OAAO,GACR,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAsRrC"}
|