deeper-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +254 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +12067 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +415 -0
- package/dist/index.js +1599 -0
- package/dist/index.js.map +1 -0
- package/docs/superpowers/plans/2026-05-14-deepercode-implementation.md +24 -0
- package/docs/superpowers/plans/2026-05-14-deepercode-plan.md +1248 -0
- package/docs/superpowers/specs/2026-05-14-deepercode-design.md +560 -0
- package/package.json +60 -0
- package/src/cli/bootstrap.ts +69 -0
- package/src/cli/chat-repl.ts +932 -0
- package/src/cli/commands/chat.ts +39 -0
- package/src/cli/commands/chat.tsx +39 -0
- package/src/cli/commands/config.ts +133 -0
- package/src/cli/commands/mcp.ts +172 -0
- package/src/cli/commands/run.ts +147 -0
- package/src/cli/commands/skill.ts +152 -0
- package/src/cli/index.ts +184 -0
- package/src/core/bugscan.ts +145 -0
- package/src/core/config.ts +285 -0
- package/src/core/constants.ts +49 -0
- package/src/core/eventbus.ts +202 -0
- package/src/core/logger.ts +109 -0
- package/src/core/storage.ts +96 -0
- package/src/index.ts +26 -0
- package/src/mcp/ConfigLoader.ts +74 -0
- package/src/mcp/MCPClient.ts +326 -0
- package/src/mcp/ResourceAdapter.ts +58 -0
- package/src/mcp/SSETransport.ts +133 -0
- package/src/mcp/StdioTransport.ts +116 -0
- package/src/mcp/ToolAdapter.ts +71 -0
- package/src/mcp/types.ts +58 -0
- package/src/memory/xmemory.ts +275 -0
- package/src/model/DeepSeekClient.ts +292 -0
- package/src/model/MessageBuilder.ts +155 -0
- package/src/model/RetryManager.ts +82 -0
- package/src/model/StreamHandler.ts +158 -0
- package/src/model/types.ts +86 -0
- package/src/skills/SkillCreator.ts +153 -0
- package/src/skills/SkillEngine.ts +158 -0
- package/src/skills/SkillExecutor.ts +107 -0
- package/src/skills/SkillLoader.ts +182 -0
- package/src/skills/SkillRegistry.ts +73 -0
- package/src/skills/SkillTrigger.ts +82 -0
- package/src/skills/types.ts +28 -0
- package/src/tools/ToolExecutor.ts +103 -0
- package/src/tools/ToolRegistry.ts +71 -0
- package/src/tools/ToolValidator.ts +103 -0
- package/src/tools/builtin/ai/context_summarize.ts +76 -0
- package/src/tools/builtin/ai/memory_store.ts +86 -0
- package/src/tools/builtin/ai/prompt_template.ts +71 -0
- package/src/tools/builtin/ai/skill_create.ts +53 -0
- package/src/tools/builtin/ai/subagent.ts +39 -0
- package/src/tools/builtin/ai/todo_manager.ts +157 -0
- package/src/tools/builtin/ai/token_count.ts +196 -0
- package/src/tools/builtin/ai/tool_create.ts +52 -0
- package/src/tools/builtin/code/analyze_deps.ts +72 -0
- package/src/tools/builtin/code/bug_scan.ts +80 -0
- package/src/tools/builtin/code/code_metrics.ts +111 -0
- package/src/tools/builtin/code/extract_function.ts +86 -0
- package/src/tools/builtin/code/format_code.ts +57 -0
- package/src/tools/builtin/code/generate_code.ts +75 -0
- package/src/tools/builtin/code/import_organizer.ts +82 -0
- package/src/tools/builtin/code/lint_code.ts +48 -0
- package/src/tools/builtin/code/parse_ast.ts +86 -0
- package/src/tools/builtin/code/refactor_code.ts +63 -0
- package/src/tools/builtin/code/type_check.ts +48 -0
- package/src/tools/builtin/data/chart_generate.ts +62 -0
- package/src/tools/builtin/data/csv_parse.ts +56 -0
- package/src/tools/builtin/data/data_diff.ts +79 -0
- package/src/tools/builtin/data/data_transform.ts +74 -0
- package/src/tools/builtin/data/data_validate.ts +75 -0
- package/src/tools/builtin/data/json_parse.ts +71 -0
- package/src/tools/builtin/data/template_render.ts +58 -0
- package/src/tools/builtin/data/toml_parse.ts +42 -0
- package/src/tools/builtin/data/xml_parse.ts +79 -0
- package/src/tools/builtin/data/yaml_parse.ts +42 -0
- package/src/tools/builtin/database/db_backup.ts +53 -0
- package/src/tools/builtin/database/db_restore.ts +51 -0
- package/src/tools/builtin/database/db_schema.ts +66 -0
- package/src/tools/builtin/database/nosql_query.ts +50 -0
- package/src/tools/builtin/database/orm_generate.ts +66 -0
- package/src/tools/builtin/database/redis_command.ts +46 -0
- package/src/tools/builtin/database/sql_migrate.ts +55 -0
- package/src/tools/builtin/database/sql_query.ts +60 -0
- package/src/tools/builtin/filesystem/batch_read.ts +56 -0
- package/src/tools/builtin/filesystem/batch_write.ts +67 -0
- package/src/tools/builtin/filesystem/copy_file.ts +36 -0
- package/src/tools/builtin/filesystem/create_dir.ts +30 -0
- package/src/tools/builtin/filesystem/delete_file.ts +30 -0
- package/src/tools/builtin/filesystem/diff_files.ts +47 -0
- package/src/tools/builtin/filesystem/edit_file.ts +47 -0
- package/src/tools/builtin/filesystem/file_info.ts +52 -0
- package/src/tools/builtin/filesystem/glob_find.ts +44 -0
- package/src/tools/builtin/filesystem/list_dir.ts +51 -0
- package/src/tools/builtin/filesystem/merge_files.ts +44 -0
- package/src/tools/builtin/filesystem/move_file.ts +37 -0
- package/src/tools/builtin/filesystem/read_file.ts +55 -0
- package/src/tools/builtin/filesystem/watch_file.ts +33 -0
- package/src/tools/builtin/filesystem/write_file.ts +45 -0
- package/src/tools/builtin/index.ts +244 -0
- package/src/tools/builtin/network/api_call.ts +79 -0
- package/src/tools/builtin/network/browser_action.ts +54 -0
- package/src/tools/builtin/network/check_url.ts +59 -0
- package/src/tools/builtin/network/download_file.ts +64 -0
- package/src/tools/builtin/network/graphql_query.ts +46 -0
- package/src/tools/builtin/network/http_request.ts +61 -0
- package/src/tools/builtin/network/parse_html.ts +101 -0
- package/src/tools/builtin/network/proxy_request.ts +53 -0
- package/src/tools/builtin/network/screenshot_page.ts +58 -0
- package/src/tools/builtin/network/web_fetch.ts +70 -0
- package/src/tools/builtin/network/web_search.ts +128 -0
- package/src/tools/builtin/network/websocket_connect.ts +70 -0
- package/src/tools/builtin/project/build_project.ts +68 -0
- package/src/tools/builtin/project/config_manage.ts +99 -0
- package/src/tools/builtin/project/coverage_report.ts +59 -0
- package/src/tools/builtin/project/docker_manage.ts +90 -0
- package/src/tools/builtin/project/env_manage.ts +88 -0
- package/src/tools/builtin/project/npm_manage.ts +71 -0
- package/src/tools/builtin/project/project_init.ts +59 -0
- package/src/tools/builtin/project/run_test.ts +74 -0
- package/src/tools/builtin/search/codebase_search.ts +76 -0
- package/src/tools/builtin/search/find_definition.ts +84 -0
- package/src/tools/builtin/search/find_references.ts +75 -0
- package/src/tools/builtin/search/fuzzy_find.ts +75 -0
- package/src/tools/builtin/search/grep_search.ts +90 -0
- package/src/tools/builtin/search/regex_find.ts +91 -0
- package/src/tools/builtin/search/search_docs.ts +51 -0
- package/src/tools/builtin/search/search_package.ts +50 -0
- package/src/tools/builtin/search/symbol_search.ts +82 -0
- package/src/tools/builtin/search/text_search.ts +63 -0
- package/src/tools/builtin/security/decrypt_file.ts +54 -0
- package/src/tools/builtin/security/encrypt_file.ts +52 -0
- package/src/tools/builtin/security/hash_generate.ts +48 -0
- package/src/tools/builtin/security/jwt_decode.ts +53 -0
- package/src/tools/builtin/security/secret_scan.ts +82 -0
- package/src/tools/builtin/security/vulnerability_check.ts +71 -0
- package/src/tools/builtin/shell/background_terminal.ts +38 -0
- package/src/tools/builtin/shell/check_status.ts +48 -0
- package/src/tools/builtin/shell/interactive_terminal.ts +31 -0
- package/src/tools/builtin/shell/kill_terminal.ts +29 -0
- package/src/tools/builtin/shell/list_terminals.ts +61 -0
- package/src/tools/builtin/shell/pipe_commands.ts +55 -0
- package/src/tools/builtin/shell/process-pool.ts +150 -0
- package/src/tools/builtin/shell/run_async.ts +73 -0
- package/src/tools/builtin/shell/run_command.ts +60 -0
- package/src/tools/builtin/shell/send_ctrl_keys.ts +43 -0
- package/src/tools/builtin/shell/send_keys.ts +36 -0
- package/src/tools/builtin/shell/send_text.ts +35 -0
- package/src/tools/builtin/shell/shell_script.ts +65 -0
- package/src/tools/builtin/shell/stop_command.ts +40 -0
- package/src/tools/builtin/shell/terminal_resize.ts +31 -0
- package/src/tools/builtin/shell/terminal_screenshot.ts +28 -0
- package/src/tools/builtin/system/log_viewer.ts +89 -0
- package/src/tools/builtin/system/notify_user.ts +55 -0
- package/src/tools/builtin/system/process_list.ts +66 -0
- package/src/tools/builtin/system/resource_monitor.ts +66 -0
- package/src/tools/builtin/system/system_info.ts +41 -0
- package/src/tools/tool-types.ts +97 -0
- package/src/ui/AgentTree.tsx +98 -0
- package/src/ui/App.tsx +46 -0
- package/src/ui/ChatView.tsx +278 -0
- package/src/ui/ConfirmDialog.tsx +68 -0
- package/src/ui/DiffView.tsx +64 -0
- package/src/ui/FilePreview.tsx +59 -0
- package/src/ui/InputBox.tsx +267 -0
- package/src/ui/MessageBubble.tsx +30 -0
- package/src/ui/Spinner.tsx +35 -0
- package/src/ui/StatusBar.tsx +41 -0
- package/src/ui/ToolCallCard.tsx +73 -0
- package/src/ui/ansi.ts +50 -0
- package/src/ui/markdown.ts +238 -0
- package/src/ui/themes/dark.ts +4 -0
- package/src/ui/themes/default.ts +25 -0
- package/src/ui/themes/light.ts +14 -0
- package/tests/unit/BuiltinTools.test.ts +129 -0
- package/tests/unit/BuiltinToolsIntegration.test.ts +111 -0
- package/tests/unit/FilesystemTools.test.ts +211 -0
- package/tests/unit/SkillLoader.test.ts +141 -0
- package/tests/unit/SkillRegistry.test.ts +113 -0
- package/tests/unit/ToolExecutor.test.ts +160 -0
- package/tests/unit/ToolRegistry.test.ts +103 -0
- package/tests/unit/ToolValidator.test.ts +137 -0
- package/tsconfig.json +28 -0
- package/tsup.config.ts +17 -0
- package/vitest.config.ts +20 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Tool } from '../../tool-types.js';
|
|
2
|
+
|
|
3
|
+
export const terminal_screenshot: Tool = {
|
|
4
|
+
name: 'terminal_screenshot',
|
|
5
|
+
description: '获取终端状态快照(文本形式)',
|
|
6
|
+
category: 'shell',
|
|
7
|
+
parameters: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
terminal_id: { type: 'string', description: '终端标识' },
|
|
11
|
+
},
|
|
12
|
+
required: ['terminal_id'],
|
|
13
|
+
},
|
|
14
|
+
dangerous: false,
|
|
15
|
+
requiresApproval: false,
|
|
16
|
+
async execute(params) {
|
|
17
|
+
try {
|
|
18
|
+
const terminalId = params.terminal_id as string;
|
|
19
|
+
return {
|
|
20
|
+
success: true,
|
|
21
|
+
output: `终端快照: ${terminalId}\n(终端屏幕截图功能在 CLI 环境中以文本输出替代)`,
|
|
22
|
+
metadata: { terminalId, method: 'text-snapshot' },
|
|
23
|
+
};
|
|
24
|
+
} catch (err: unknown) {
|
|
25
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import type { Tool } from '../../tool-types.js';
|
|
4
|
+
|
|
5
|
+
export const log_viewer: Tool = {
|
|
6
|
+
name: 'log_viewer',
|
|
7
|
+
description: '查看和管理日志文件',
|
|
8
|
+
category: 'system',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
action: { type: 'string', description: '操作: read, tail, search, clear', enum: ['read', 'tail', 'search', 'clear'] },
|
|
13
|
+
file_path: { type: 'string', description: '日志文件路径' },
|
|
14
|
+
lines: { type: 'number', description: '读取行数(tail 模式)' },
|
|
15
|
+
query: { type: 'string', description: '搜索关键词' },
|
|
16
|
+
},
|
|
17
|
+
required: ['action'],
|
|
18
|
+
},
|
|
19
|
+
dangerous: false,
|
|
20
|
+
requiresApproval: false,
|
|
21
|
+
async execute(params) {
|
|
22
|
+
try {
|
|
23
|
+
const action = params.action as string;
|
|
24
|
+
const filePath = params.file_path as string | undefined;
|
|
25
|
+
const lineCount = (params.lines as number) ?? 50;
|
|
26
|
+
const query = params.query as string | undefined;
|
|
27
|
+
|
|
28
|
+
if (action !== 'clear' && !filePath) {
|
|
29
|
+
const defaultLogs = ['npm-debug.log', 'yarn-error.log', '.log', 'logs/'];
|
|
30
|
+
const cwd = process.cwd();
|
|
31
|
+
const found = defaultLogs.filter(f => existsSync(resolve(cwd, f)));
|
|
32
|
+
return {
|
|
33
|
+
success: true,
|
|
34
|
+
output: `请指定 file_path。项目目录中的日志文件:\n${found.length > 0 ? found.join('\n') : ' (未找到)'}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const abs = resolve(filePath!);
|
|
39
|
+
|
|
40
|
+
if (action === 'clear') {
|
|
41
|
+
const { writeFileSync } = await import('node:fs');
|
|
42
|
+
writeFileSync(abs, '', 'utf-8');
|
|
43
|
+
return { success: true, output: `日志已清空: ${abs}` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!existsSync(abs)) {
|
|
47
|
+
return { success: false, error: `日志文件不存在: ${abs}`, output: '' };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const content = readFileSync(abs, 'utf-8');
|
|
51
|
+
const allLines = content.split('\n');
|
|
52
|
+
|
|
53
|
+
switch (action) {
|
|
54
|
+
case 'read': {
|
|
55
|
+
const sub = allLines.slice(0, lineCount).join('\n');
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
output: sub,
|
|
59
|
+
metadata: { lines: allLines.length, shown: Math.min(lineCount, allLines.length) },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
case 'tail': {
|
|
63
|
+
const sub = allLines.slice(-lineCount).join('\n');
|
|
64
|
+
return {
|
|
65
|
+
success: true,
|
|
66
|
+
output: `最后 ${Math.min(lineCount, allLines.length)} 行:\n${sub}`,
|
|
67
|
+
metadata: { totalLines: allLines.length },
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
case 'search': {
|
|
71
|
+
if (!query) return { success: false, error: 'search 需要 query 参数', output: '' };
|
|
72
|
+
const matches = allLines
|
|
73
|
+
.map((line, i) => line.includes(query) ? `${i + 1}:${line.trim()}` : null)
|
|
74
|
+
.filter(Boolean)
|
|
75
|
+
.slice(0, 200);
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
output: matches.join('\n') || '未找到匹配行',
|
|
79
|
+
metadata: { matches: matches.length, totalLines: allLines.length },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
default:
|
|
83
|
+
return { success: false, error: `不支持的操作: ${action}`, output: '' };
|
|
84
|
+
}
|
|
85
|
+
} catch (err: unknown) {
|
|
86
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Tool } from '../../tool-types.js';
|
|
2
|
+
|
|
3
|
+
export const notify_user: Tool = {
|
|
4
|
+
name: 'notify_user',
|
|
5
|
+
description: '发送系统通知给用户',
|
|
6
|
+
category: 'system',
|
|
7
|
+
parameters: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
title: { type: 'string', description: '通知标题' },
|
|
11
|
+
message: { type: 'string', description: '通知详情' },
|
|
12
|
+
level: { type: 'string', description: '通知级别: info, warn, error, success', enum: ['info', 'warn', 'error', 'success'] },
|
|
13
|
+
},
|
|
14
|
+
required: ['message'],
|
|
15
|
+
},
|
|
16
|
+
dangerous: false,
|
|
17
|
+
requiresApproval: false,
|
|
18
|
+
async execute(params) {
|
|
19
|
+
try {
|
|
20
|
+
const title = (params.title as string) ?? 'DeeperCode';
|
|
21
|
+
const message = params.message as string;
|
|
22
|
+
const level = (params.level as string) ?? 'info';
|
|
23
|
+
|
|
24
|
+
const icons: Record<string, string> = {
|
|
25
|
+
info: 'ℹ',
|
|
26
|
+
warn: '⚠',
|
|
27
|
+
error: '✗',
|
|
28
|
+
success: '✓',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const output = `${icons[level] || ''} [${level.toUpperCase()}] ${title}: ${message}`;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (process.platform === 'win32') {
|
|
35
|
+
const { execSync } = await import('node:child_process');
|
|
36
|
+
execSync(`powershell -Command "Add-Type -AssemblyName System.Windows.Forms; $notify = New-Object System.Windows.Forms.NotifyIcon; $notify.Icon = [System.Drawing.SystemIcons]::Information; $notify.Visible = $true; $notify.ShowBalloonTip(5000, '${title}', '${message}', [System.Windows.Forms.ToolTipIcon]::${level === 'error' ? 'Error' : 'Info'}); Start-Sleep -Seconds 6; $notify.Dispose()"`, {
|
|
37
|
+
timeout: 10000,
|
|
38
|
+
stdio: 'ignore',
|
|
39
|
+
});
|
|
40
|
+
} else if (process.platform === 'darwin') {
|
|
41
|
+
const { execSync } = await import('node:child_process');
|
|
42
|
+
execSync(`osascript -e 'display notification "${message}" with title "${title}"'`, { stdio: 'ignore' });
|
|
43
|
+
} else {
|
|
44
|
+
const { execSync } = await import('node:child_process');
|
|
45
|
+
execSync(`notify-send "${title}" "${message}"`, { stdio: 'ignore' });
|
|
46
|
+
}
|
|
47
|
+
return { success: true, output, metadata: { title, level, notified: true } };
|
|
48
|
+
} catch {
|
|
49
|
+
return { success: true, output, metadata: { title, level, notified: false } };
|
|
50
|
+
}
|
|
51
|
+
} catch (err: unknown) {
|
|
52
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import type { Tool } from '../../tool-types.js';
|
|
3
|
+
|
|
4
|
+
export const process_list: Tool = {
|
|
5
|
+
name: 'process_list',
|
|
6
|
+
description: '列出当前运行的进程',
|
|
7
|
+
category: 'system',
|
|
8
|
+
parameters: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
filter: { type: 'string', description: '进程名过滤' },
|
|
12
|
+
count: { type: 'number', description: '显示数量' },
|
|
13
|
+
},
|
|
14
|
+
required: [],
|
|
15
|
+
},
|
|
16
|
+
dangerous: false,
|
|
17
|
+
requiresApproval: false,
|
|
18
|
+
async execute(params) {
|
|
19
|
+
try {
|
|
20
|
+
const filter = params.filter as string | undefined;
|
|
21
|
+
const count = (params.count as number) ?? 20;
|
|
22
|
+
const platform = process.platform;
|
|
23
|
+
|
|
24
|
+
let cmd: string;
|
|
25
|
+
if (platform === 'win32') {
|
|
26
|
+
cmd = 'tasklist /FO CSV /NH';
|
|
27
|
+
} else {
|
|
28
|
+
cmd = 'ps aux --sort=-%mem';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
let output = execSync(cmd, { encoding: 'utf-8', timeout: 10000, stdio: 'pipe' });
|
|
33
|
+
const lines = output.split('\n');
|
|
34
|
+
|
|
35
|
+
if (filter) {
|
|
36
|
+
const filtered = lines.filter(l => l.toLowerCase().includes(filter.toLowerCase()));
|
|
37
|
+
output = filtered.slice(0, count).join('\n');
|
|
38
|
+
} else {
|
|
39
|
+
output = lines.slice(0, count).join('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
success: true,
|
|
44
|
+
output: `进程列表 (${platform}):\n${output}`,
|
|
45
|
+
metadata: { platform, filter, lines: Math.min(lines.length, count) },
|
|
46
|
+
};
|
|
47
|
+
} catch {
|
|
48
|
+
const os = await import('node:os');
|
|
49
|
+
return {
|
|
50
|
+
success: true,
|
|
51
|
+
output: [
|
|
52
|
+
`当前进程信息:`,
|
|
53
|
+
`PID: ${process.pid}`,
|
|
54
|
+
`平台: ${os.platform()}`,
|
|
55
|
+
`架构: ${os.arch()}`,
|
|
56
|
+
`Node.js: ${process.version}`,
|
|
57
|
+
`CPU 数: ${os.cpus().length}`,
|
|
58
|
+
].join('\n'),
|
|
59
|
+
metadata: { pid: process.pid },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
} catch (err: unknown) {
|
|
63
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Tool } from '../../tool-types.js';
|
|
2
|
+
|
|
3
|
+
export const resource_monitor: Tool = {
|
|
4
|
+
name: 'resource_monitor',
|
|
5
|
+
description: '监控系统资源使用情况',
|
|
6
|
+
category: 'system',
|
|
7
|
+
parameters: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
interval_ms: { type: 'number', description: '采样间隔毫秒' },
|
|
11
|
+
samples: { type: 'number', description: '采样次数' },
|
|
12
|
+
},
|
|
13
|
+
required: [],
|
|
14
|
+
},
|
|
15
|
+
dangerous: false,
|
|
16
|
+
requiresApproval: false,
|
|
17
|
+
async execute(params) {
|
|
18
|
+
try {
|
|
19
|
+
const intervalMs = (params.interval_ms as number) ?? 1000;
|
|
20
|
+
const samples = (params.samples as number) ?? 3;
|
|
21
|
+
|
|
22
|
+
const os = await import('node:os');
|
|
23
|
+
const results: Record<string, unknown>[] = [];
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < samples; i++) {
|
|
26
|
+
const cpus = os.cpus();
|
|
27
|
+
const totalIdle = cpus.reduce((s, c) => s + c.times.idle, 0);
|
|
28
|
+
const totalTick = cpus.reduce((s, c) => s + c.times.user + c.times.nice + c.times.sys + c.times.idle + c.times.irq, 0);
|
|
29
|
+
const cpuUsage = totalTick > 0 ? ((1 - totalIdle / totalTick) * 100).toFixed(1) : '0';
|
|
30
|
+
|
|
31
|
+
results.push({
|
|
32
|
+
sample: i + 1,
|
|
33
|
+
cpu: `${cpuUsage}%`,
|
|
34
|
+
memory: {
|
|
35
|
+
total: `${(os.totalmem() / 1024 / 1024 / 1024).toFixed(1)} GB`,
|
|
36
|
+
free: `${(os.freemem() / 1024 / 1024 / 1024).toFixed(1)} GB`,
|
|
37
|
+
used: `${((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(1)}%`,
|
|
38
|
+
},
|
|
39
|
+
uptime: `${Math.floor(os.uptime() / 3600)}h ${Math.floor((os.uptime() % 3600) / 60)}m`,
|
|
40
|
+
loadAverage: os.loadavg().map(l => l.toFixed(2)),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (i < samples - 1) {
|
|
44
|
+
await new Promise(r => setTimeout(r, intervalMs));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const latest = results[results.length - 1];
|
|
49
|
+
const output = [
|
|
50
|
+
`资源监控 (${samples} 采样,间隔 ${intervalMs}ms):`,
|
|
51
|
+
`CPU 使用率: ${(latest as Record<string, unknown>).cpu}`,
|
|
52
|
+
`内存: ${JSON.stringify((latest as Record<string, unknown>).memory)}`,
|
|
53
|
+
`运行时间: ${(latest as Record<string, unknown>).uptime}`,
|
|
54
|
+
`平均负载: ${JSON.stringify((latest as Record<string, unknown>).loadAverage)}`,
|
|
55
|
+
].join('\n');
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
success: true,
|
|
59
|
+
output,
|
|
60
|
+
metadata: { samples, intervalMs, latest },
|
|
61
|
+
};
|
|
62
|
+
} catch (err: unknown) {
|
|
63
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Tool } from '../../tool-types.js';
|
|
2
|
+
|
|
3
|
+
export const system_info: Tool = {
|
|
4
|
+
name: 'system_info',
|
|
5
|
+
description: '获取系统信息',
|
|
6
|
+
category: 'system',
|
|
7
|
+
parameters: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {},
|
|
10
|
+
required: [],
|
|
11
|
+
},
|
|
12
|
+
dangerous: false,
|
|
13
|
+
requiresApproval: false,
|
|
14
|
+
async execute() {
|
|
15
|
+
try {
|
|
16
|
+
const os = await import('node:os');
|
|
17
|
+
|
|
18
|
+
const info = {
|
|
19
|
+
platform: os.platform(),
|
|
20
|
+
arch: os.arch(),
|
|
21
|
+
hostname: os.hostname(),
|
|
22
|
+
cpus: os.cpus().length,
|
|
23
|
+
totalMemory: `${(os.totalmem() / 1024 / 1024 / 1024).toFixed(1)} GB`,
|
|
24
|
+
freeMemory: `${(os.freemem() / 1024 / 1024 / 1024).toFixed(1)} GB`,
|
|
25
|
+
uptime: `${Math.floor(os.uptime() / 3600)}h ${Math.floor((os.uptime() % 3600) / 60)}m`,
|
|
26
|
+
nodeVersion: process.version,
|
|
27
|
+
homeDir: os.homedir(),
|
|
28
|
+
tmpDir: os.tmpdir(),
|
|
29
|
+
cwd: process.cwd(),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const output = Object.entries(info)
|
|
33
|
+
.map(([k, v]) => `${k}: ${v}`)
|
|
34
|
+
.join('\n');
|
|
35
|
+
|
|
36
|
+
return { success: true, output, metadata: info };
|
|
37
|
+
} catch (err: unknown) {
|
|
38
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export interface JSONSchema {
|
|
2
|
+
type: string;
|
|
3
|
+
properties?: Record<string, JSONSchema>;
|
|
4
|
+
required?: string[];
|
|
5
|
+
description?: string;
|
|
6
|
+
enum?: string[];
|
|
7
|
+
items?: JSONSchema;
|
|
8
|
+
additionalProperties?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ToolParameter {
|
|
12
|
+
name: string;
|
|
13
|
+
type: string;
|
|
14
|
+
description: string;
|
|
15
|
+
required: boolean;
|
|
16
|
+
default?: unknown;
|
|
17
|
+
enum?: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ToolDefinition {
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
category: string;
|
|
24
|
+
parameters: JSONSchema;
|
|
25
|
+
dangerous?: boolean;
|
|
26
|
+
requiresApproval?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ToolResult {
|
|
30
|
+
success: boolean;
|
|
31
|
+
output: string;
|
|
32
|
+
error?: string;
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ToolExecutor {
|
|
37
|
+
execute(params: Record<string, unknown>, signal?: AbortSignal): Promise<ToolResult>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type Tool = ToolDefinition & ToolExecutor;
|
|
41
|
+
|
|
42
|
+
export interface ToolCall {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
arguments: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ToolCallResult {
|
|
49
|
+
callId: string;
|
|
50
|
+
result: ToolResult;
|
|
51
|
+
timestamp: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type ToolSafetyLevel = 'safe' | 'confirm' | 'dangerous';
|
|
55
|
+
|
|
56
|
+
export const TOOL_SAFETY_MAP: Record<string, ToolSafetyLevel> = {
|
|
57
|
+
read_file: 'safe', list_dir: 'safe', glob_find: 'safe', file_info: 'safe',
|
|
58
|
+
grep_search: 'safe', text_search: 'safe', fuzzy_find: 'safe', regex_find: 'safe',
|
|
59
|
+
find_references: 'safe', find_definition: 'safe', symbol_search: 'safe',
|
|
60
|
+
search_package: 'safe', search_docs: 'safe', codebase_search: 'safe',
|
|
61
|
+
token_count: 'safe', system_info: 'safe', process_list: 'safe',
|
|
62
|
+
resource_monitor: 'safe', log_viewer: 'safe', bug_scan: 'safe',
|
|
63
|
+
web_fetch: 'safe', web_search: 'safe', check_url: 'safe',
|
|
64
|
+
parse_html: 'safe', http_request: 'safe',
|
|
65
|
+
watch_file: 'safe', batch_read: 'safe', create_dir: 'safe',
|
|
66
|
+
json_parse: 'safe', csv_parse: 'safe', xml_parse: 'safe', yaml_parse: 'safe', toml_parse: 'safe',
|
|
67
|
+
data_validate: 'safe', data_diff: 'safe', hash_generate: 'safe', jwt_decode: 'safe',
|
|
68
|
+
coverage_report: 'safe', config_manage: 'safe', notify_user: 'safe',
|
|
69
|
+
format_code: 'safe', lint_code: 'safe', type_check: 'safe', code_metrics: 'safe',
|
|
70
|
+
analyze_deps: 'safe', import_organizer: 'safe', parse_ast: 'safe',
|
|
71
|
+
db_schema: 'safe',
|
|
72
|
+
context_summarize: 'safe', prompt_template: 'safe',
|
|
73
|
+
skill_create: 'safe', tool_create: 'safe', memory_store: 'safe',
|
|
74
|
+
todo_manager: 'safe', subagent: 'safe',
|
|
75
|
+
background_terminal: 'safe', list_terminals: 'safe', read_terminal: 'safe',
|
|
76
|
+
send_keys: 'safe', send_ctrl_keys: 'safe', send_text: 'safe', kill_terminal: 'safe',
|
|
77
|
+
terminal_screenshot: 'safe', terminal_resize: 'safe', check_status: 'safe', stop_command: 'safe',
|
|
78
|
+
download_file: 'safe', api_call: 'safe', graphql_query: 'safe', websocket_connect: 'safe',
|
|
79
|
+
|
|
80
|
+
write_file: 'safe', edit_file: 'safe',
|
|
81
|
+
delete_file: 'confirm', move_file: 'confirm', copy_file: 'confirm', batch_write: 'safe',
|
|
82
|
+
merge_files: 'confirm', diff_files: 'confirm',
|
|
83
|
+
run_command: 'safe', run_async: 'safe', pipe_commands: 'safe',
|
|
84
|
+
shell_script: 'confirm', npm_manage: 'confirm',
|
|
85
|
+
project_init: 'confirm', build_project: 'confirm', run_test: 'confirm',
|
|
86
|
+
docker_manage: 'confirm', env_manage: 'confirm',
|
|
87
|
+
sql_query: 'confirm', sql_migrate: 'confirm', nosql_query: 'confirm',
|
|
88
|
+
db_backup: 'confirm', db_restore: 'confirm', redis_command: 'confirm',
|
|
89
|
+
encrypt_file: 'confirm', decrypt_file: 'confirm',
|
|
90
|
+
template_render: 'confirm', chart_generate: 'confirm',
|
|
91
|
+
secret_scan: 'confirm', vulnerability_check: 'confirm',
|
|
92
|
+
orm_generate: 'confirm', generate_code: 'confirm', refactor_code: 'confirm',
|
|
93
|
+
extract_function: 'confirm', data_transform: 'confirm', proxy_request: 'confirm',
|
|
94
|
+
|
|
95
|
+
interactive_terminal: 'confirm',
|
|
96
|
+
browser_action: 'confirm', screenshot_page: 'confirm',
|
|
97
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Text, Box } from 'ink';
|
|
2
|
+
import { defaultTheme } from './themes/default.ts';
|
|
3
|
+
|
|
4
|
+
interface AgentNode {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
status: 'idle' | 'running' | 'completed' | 'failed';
|
|
8
|
+
children?: AgentNode[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface AgentTreeProps {
|
|
12
|
+
agents: AgentNode[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const statusIcon: Record<AgentNode['status'], string> = {
|
|
16
|
+
idle: '⏸',
|
|
17
|
+
running: '🔄',
|
|
18
|
+
completed: '✅',
|
|
19
|
+
failed: '❌',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const statusColor: Record<AgentNode['status'], string> = {
|
|
23
|
+
idle: defaultTheme.dimText,
|
|
24
|
+
running: defaultTheme.primary,
|
|
25
|
+
completed: defaultTheme.success,
|
|
26
|
+
failed: defaultTheme.error,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function AgentNodeRow({
|
|
30
|
+
node,
|
|
31
|
+
depth,
|
|
32
|
+
isLast,
|
|
33
|
+
}: {
|
|
34
|
+
node: AgentNode;
|
|
35
|
+
depth: number;
|
|
36
|
+
isLast: boolean;
|
|
37
|
+
}) {
|
|
38
|
+
const prefix = depth === 0
|
|
39
|
+
? ''
|
|
40
|
+
: ' '.repeat(depth - 1) + (isLast ? '└─' : '├─');
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Box flexDirection="column">
|
|
44
|
+
<Box>
|
|
45
|
+
<Text dimColor>{prefix}</Text>
|
|
46
|
+
<Text color={statusColor[node.status]}>{statusIcon[node.status]}</Text>
|
|
47
|
+
<Text bold color={statusColor[node.status]}> {node.name}</Text>
|
|
48
|
+
</Box>
|
|
49
|
+
{node.children?.map((child, i) => (
|
|
50
|
+
<AgentNodeRow
|
|
51
|
+
key={child.id}
|
|
52
|
+
node={child}
|
|
53
|
+
depth={depth + 1}
|
|
54
|
+
isLast={i === (node.children?.length || 0) - 1}
|
|
55
|
+
/>
|
|
56
|
+
))}
|
|
57
|
+
</Box>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function AgentTree({ agents }: AgentTreeProps) {
|
|
62
|
+
const total = agents.length;
|
|
63
|
+
const running = agents.filter((a) => a.status === 'running').length;
|
|
64
|
+
const completed = agents.filter((a) => a.status === 'completed').length;
|
|
65
|
+
const failed = agents.filter((a) => a.status === 'failed').length;
|
|
66
|
+
|
|
67
|
+
const countChildren = (ns: AgentNode[]): number =>
|
|
68
|
+
ns.reduce((sum, n) => sum + 1 + countChildren(n.children || []), 0);
|
|
69
|
+
|
|
70
|
+
const totalWithChildren = countChildren(agents);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<Box flexDirection="column" borderStyle="round" borderColor={defaultTheme.border} paddingX={1}>
|
|
74
|
+
<Box>
|
|
75
|
+
<Text bold>🤖 Agent 树</Text>
|
|
76
|
+
<Text dimColor>
|
|
77
|
+
{' '}
|
|
78
|
+
[{totalWithChildren} 节点:
|
|
79
|
+
{' '}<Text color={defaultTheme.success}>{completed} 完成</Text>
|
|
80
|
+
{running > 0 ? <Text color={defaultTheme.primary}> {running} 运行</Text> : null}
|
|
81
|
+
{failed > 0 ? <Text color={defaultTheme.error}> {failed} 失败</Text> : null}
|
|
82
|
+
]
|
|
83
|
+
</Text>
|
|
84
|
+
</Box>
|
|
85
|
+
|
|
86
|
+
<Box flexDirection="column" marginTop={0}>
|
|
87
|
+
{agents.map((agent, i) => (
|
|
88
|
+
<AgentNodeRow
|
|
89
|
+
key={agent.id}
|
|
90
|
+
node={agent}
|
|
91
|
+
depth={0}
|
|
92
|
+
isLast={i === total - 1}
|
|
93
|
+
/>
|
|
94
|
+
))}
|
|
95
|
+
</Box>
|
|
96
|
+
</Box>
|
|
97
|
+
);
|
|
98
|
+
}
|
package/src/ui/App.tsx
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useEffect, useState, useRef } from 'react';
|
|
2
|
+
import { Text, Box } from 'ink';
|
|
3
|
+
import { ChatView } from './ChatView.tsx';
|
|
4
|
+
import { StatusBar } from './StatusBar.tsx';
|
|
5
|
+
import { eventbus } from '../core/eventbus.ts';
|
|
6
|
+
import type { ChatMessage } from '../model/types.ts';
|
|
7
|
+
|
|
8
|
+
interface AppProps {
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
model?: string;
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
autoRun?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function App({ apiKey, model, autoRun }: AppProps) {
|
|
16
|
+
const [initialMessages, setInitialMessages] = useState<ChatMessage[]>([]);
|
|
17
|
+
const startTimeRef = useRef(Date.now());
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const memTimer = setInterval(() => {
|
|
21
|
+
eventbus.emitStatusUpdate({
|
|
22
|
+
memoryUsage: Math.round(process.memoryUsage().heapUsed / (1024 * 1024)),
|
|
23
|
+
uptime: Date.now() - startTimeRef.current,
|
|
24
|
+
});
|
|
25
|
+
}, 5000);
|
|
26
|
+
|
|
27
|
+
if (autoRun) {
|
|
28
|
+
setInitialMessages([{
|
|
29
|
+
id: `auto-${Date.now()}`, role: 'user', content: autoRun, timestamp: Date.now(),
|
|
30
|
+
}]);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return () => { clearInterval(memTimer); eventbus.reset(); };
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Box flexDirection="column" width="100%">
|
|
38
|
+
<ChatView
|
|
39
|
+
initialMessages={initialMessages}
|
|
40
|
+
apiKey={apiKey}
|
|
41
|
+
model={model}
|
|
42
|
+
/>
|
|
43
|
+
<StatusBar />
|
|
44
|
+
</Box>
|
|
45
|
+
);
|
|
46
|
+
}
|