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,86 @@
|
|
|
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 extract_function: Tool = {
|
|
6
|
+
name: 'extract_function',
|
|
7
|
+
description: '从代码中提取指定函数',
|
|
8
|
+
category: 'code',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: { type: 'string', description: '文件路径' },
|
|
13
|
+
function_name: { type: 'string', description: '函数名' },
|
|
14
|
+
},
|
|
15
|
+
required: ['file_path', 'function_name'],
|
|
16
|
+
},
|
|
17
|
+
dangerous: false,
|
|
18
|
+
requiresApproval: false,
|
|
19
|
+
async execute(params) {
|
|
20
|
+
try {
|
|
21
|
+
const filePath = resolve(params.file_path as string);
|
|
22
|
+
const funcName = params.function_name as string;
|
|
23
|
+
|
|
24
|
+
if (!existsSync(filePath)) {
|
|
25
|
+
return { success: false, error: `文件不存在: ${filePath}`, output: '' };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
29
|
+
const lines = content.split('\n');
|
|
30
|
+
|
|
31
|
+
const funcRegex = new RegExp(
|
|
32
|
+
`(?:function\\s+${escapeRegex(funcName)}|` +
|
|
33
|
+
`(?:const|let|var)\\s+${escapeRegex(funcName)}\\s*=|` +
|
|
34
|
+
`(?:public|private|protected|static|async\\s+)?${escapeRegex(funcName)}\\s*\\([^)]*\\)\\s*[\\{:]|` +
|
|
35
|
+
`(?:export\\s+)?(?:async\\s+)?${escapeRegex(funcName)}\\s*\\([^)]*\\)\\s*[\\{:]|` +
|
|
36
|
+
`(?:get |set )?${escapeRegex(funcName)}\\s*\\([^)]*\\)\\s*\\{)`,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
let startLine = -1;
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
if (funcRegex.test(lines[i])) {
|
|
42
|
+
startLine = i;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (startLine === -1) {
|
|
48
|
+
return { success: false, error: `未找到函数: ${funcName}`, output: '' };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let braceCount = 0;
|
|
52
|
+
let endLine = -1;
|
|
53
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
54
|
+
for (const ch of lines[i]) {
|
|
55
|
+
if (ch === '{') braceCount++;
|
|
56
|
+
else if (ch === '}') {
|
|
57
|
+
braceCount--;
|
|
58
|
+
if (braceCount === 0) {
|
|
59
|
+
endLine = i;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (endLine !== -1) break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (endLine === -1) {
|
|
68
|
+
endLine = Math.min(startLine + 50, lines.length - 1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const extracted = lines.slice(startLine, endLine + 1).join('\n');
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
output: `提取函数 "${funcName}" (${filePath}:${startLine + 1}-${endLine + 1}):\n\n${extracted}`,
|
|
76
|
+
metadata: { functionName: funcName, file: filePath, startLine: startLine + 1, endLine: endLine + 1 },
|
|
77
|
+
};
|
|
78
|
+
} catch (err: unknown) {
|
|
79
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function escapeRegex(s: string): string {
|
|
85
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
86
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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 format_code: Tool = {
|
|
6
|
+
name: 'format_code',
|
|
7
|
+
description: '格式化代码(建议使用 prettier)',
|
|
8
|
+
category: 'code',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: { type: 'string', description: '文件路径' },
|
|
13
|
+
language: { type: 'string', description: '语言类型', enum: ['typescript', 'javascript', 'json', 'css', 'html', 'python'] },
|
|
14
|
+
},
|
|
15
|
+
required: ['file_path'],
|
|
16
|
+
},
|
|
17
|
+
dangerous: false,
|
|
18
|
+
requiresApproval: true,
|
|
19
|
+
async execute(params) {
|
|
20
|
+
try {
|
|
21
|
+
const filePath = resolve(params.file_path as string);
|
|
22
|
+
const language = (params.language as string) ?? 'typescript';
|
|
23
|
+
|
|
24
|
+
if (!existsSync(filePath)) {
|
|
25
|
+
return { success: false, error: `文件不存在: ${filePath}`, output: '' };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const { execSync } = await import('node:child_process');
|
|
30
|
+
const ext = filePath.split('.').pop() ?? 'ts';
|
|
31
|
+
execSync(`npx prettier --write "${filePath}"`, {
|
|
32
|
+
encoding: 'utf-8',
|
|
33
|
+
timeout: 30000,
|
|
34
|
+
stdio: 'pipe',
|
|
35
|
+
});
|
|
36
|
+
const formatted = readFileSync(filePath, 'utf-8');
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
output: `已格式化: ${filePath}\n\n${formatted.slice(0, 10000)}`,
|
|
40
|
+
metadata: { formatted: true, tool: 'prettier' },
|
|
41
|
+
};
|
|
42
|
+
} catch {
|
|
43
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
44
|
+
return {
|
|
45
|
+
success: true,
|
|
46
|
+
output: `代码格式化建议 (${language}):\n\n` +
|
|
47
|
+
'- 运行 npx prettier --write . 来批量格式化\n' +
|
|
48
|
+
'- 使用 ESLint: npx eslint --fix .\n\n' +
|
|
49
|
+
`当前文件内容:\n${content.slice(0, 10000)}`,
|
|
50
|
+
metadata: { formatted: false, suggestion: 'prettier' },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
} catch (err: unknown) {
|
|
54
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Tool } from '../../tool-types.js';
|
|
2
|
+
|
|
3
|
+
export const generate_code: Tool = {
|
|
4
|
+
name: 'generate_code',
|
|
5
|
+
description: 'AI 辅助代码生成(提供代码模板和最佳实践)',
|
|
6
|
+
category: 'code',
|
|
7
|
+
parameters: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
description: { type: 'string', description: '功能描述' },
|
|
11
|
+
language: { type: 'string', description: '语言类型', enum: ['typescript', 'javascript', 'python', 'java', 'go', 'rust'] },
|
|
12
|
+
template: { type: 'string', description: '模板类型: function, class, component, api, test', enum: ['function', 'class', 'component', 'api', 'test'] },
|
|
13
|
+
file_path: { type: 'string', description: '输出文件路径' },
|
|
14
|
+
},
|
|
15
|
+
required: ['description'],
|
|
16
|
+
},
|
|
17
|
+
dangerous: false,
|
|
18
|
+
requiresApproval: false,
|
|
19
|
+
async execute(params) {
|
|
20
|
+
try {
|
|
21
|
+
const description = params.description as string;
|
|
22
|
+
const language = (params.language as string) ?? 'typescript';
|
|
23
|
+
const template = (params.template as string) ?? 'function';
|
|
24
|
+
const filePath = params.file_path as string | undefined;
|
|
25
|
+
|
|
26
|
+
const output = [
|
|
27
|
+
`代码生成请求: ${language}/${template}`,
|
|
28
|
+
`描述: ${description}`,
|
|
29
|
+
filePath ? `输出: ${filePath}` : '',
|
|
30
|
+
'',
|
|
31
|
+
'此工具由 AI Agent 调用。生成代码由 AI 模型在上下文中完成。',
|
|
32
|
+
'以下是相关的最佳实践建议:',
|
|
33
|
+
'',
|
|
34
|
+
...getBestPractices(language, template),
|
|
35
|
+
].filter(Boolean).join('\n');
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
output,
|
|
40
|
+
metadata: { description, language, template, filePath },
|
|
41
|
+
};
|
|
42
|
+
} catch (err: unknown) {
|
|
43
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
function getBestPractices(lang: string, tmpl: string): string[] {
|
|
49
|
+
const tips: string[] = [];
|
|
50
|
+
if (lang === 'typescript') {
|
|
51
|
+
tips.push('- 使用 strict 模式,避免 any 类型');
|
|
52
|
+
tips.push('- 优先使用 interface/type 定义数据结构');
|
|
53
|
+
}
|
|
54
|
+
if (tmpl === 'function') {
|
|
55
|
+
tips.push('- 单一职责,每个函数只做一件事');
|
|
56
|
+
tips.push('- 添加类型标注和参数验证');
|
|
57
|
+
}
|
|
58
|
+
if (tmpl === 'class') {
|
|
59
|
+
tips.push('- 使用 private/public 控制访问');
|
|
60
|
+
tips.push('- 考虑使用 composition 替代 inheritance');
|
|
61
|
+
}
|
|
62
|
+
if (tmpl === 'component') {
|
|
63
|
+
tips.push('- 拆分大组件为小组件');
|
|
64
|
+
tips.push('- 使用 hooks 管理状态');
|
|
65
|
+
}
|
|
66
|
+
if (tmpl === 'api') {
|
|
67
|
+
tips.push('- 实现输入验证和错误处理');
|
|
68
|
+
tips.push('- 添加请求日志和限流');
|
|
69
|
+
}
|
|
70
|
+
if (tmpl === 'test') {
|
|
71
|
+
tips.push('- 遵循 AAA 模式 (Arrange, Act, Assert)');
|
|
72
|
+
tips.push('- 每个测试只测一个行为');
|
|
73
|
+
}
|
|
74
|
+
return tips;
|
|
75
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import type { Tool } from '../../tool-types.js';
|
|
4
|
+
|
|
5
|
+
export const import_organizer: Tool = {
|
|
6
|
+
name: 'import_organizer',
|
|
7
|
+
description: '整理和组织导入语句',
|
|
8
|
+
category: 'code',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: { type: 'string', description: '文件路径' },
|
|
13
|
+
group_by: { type: 'string', description: '分组方式: none, type, source', enum: ['none', 'type', 'source'] },
|
|
14
|
+
sort: { type: 'boolean', description: '是否排序' },
|
|
15
|
+
remove_unused: { type: 'boolean', description: '是否移除未使用导入' },
|
|
16
|
+
},
|
|
17
|
+
required: ['file_path'],
|
|
18
|
+
},
|
|
19
|
+
dangerous: false,
|
|
20
|
+
requiresApproval: true,
|
|
21
|
+
async execute(params) {
|
|
22
|
+
try {
|
|
23
|
+
const filePath = resolve(params.file_path as string);
|
|
24
|
+
const groupBy = (params.group_by as string) ?? 'source';
|
|
25
|
+
const sort = (params.sort as boolean) ?? true;
|
|
26
|
+
const removeUnused = (params.remove_unused as boolean) ?? false;
|
|
27
|
+
|
|
28
|
+
if (!existsSync(filePath)) {
|
|
29
|
+
return { success: false, error: `文件不存在: ${filePath}`, output: '' };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
33
|
+
const lines = content.split('\n');
|
|
34
|
+
const importLines: { index: number; line: string; isRelative: boolean }[] = [];
|
|
35
|
+
const otherLines: { index: number; line: string }[] = [];
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < lines.length; i++) {
|
|
38
|
+
const trimmed = lines[i].trim();
|
|
39
|
+
if (/^(import\s+|require\(|from\s+|import\(|import\s*\{)/.test(trimmed)) {
|
|
40
|
+
importLines.push({
|
|
41
|
+
index: i,
|
|
42
|
+
line: trimmed,
|
|
43
|
+
isRelative: trimmed.includes("'./") || trimmed.includes("'../") || trimmed.includes('"./') || trimmed.includes('"../'),
|
|
44
|
+
});
|
|
45
|
+
} else {
|
|
46
|
+
otherLines.push({ index: i, line: trimmed });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let organized: string[];
|
|
51
|
+
if (groupBy === 'source') {
|
|
52
|
+
const external = importLines.filter(i => !i.isRelative).map(i => i.line).sort();
|
|
53
|
+
const internal = importLines.filter(i => i.isRelative).map(i => i.line).sort();
|
|
54
|
+
organized = [...external, ...(external.length && internal.length ? [''] : []), ...internal];
|
|
55
|
+
} else if (groupBy === 'type') {
|
|
56
|
+
const typeImports = importLines.filter(i => i.line.includes('import type')).map(i => i.line).sort();
|
|
57
|
+
const valueImports = importLines.filter(i => !i.line.includes('import type')).map(i => i.line).sort();
|
|
58
|
+
organized = [...typeImports, ...(typeImports.length && valueImports.length ? [''] : []), ...valueImports];
|
|
59
|
+
} else {
|
|
60
|
+
organized = sort ? importLines.map(i => i.line).sort() : importLines.map(i => i.line);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const updated = [...organized, '', ...otherLines.map(l => l.line)].join('\n');
|
|
64
|
+
|
|
65
|
+
if (removeUnused) {
|
|
66
|
+
return {
|
|
67
|
+
success: true,
|
|
68
|
+
output: `导入已整理: ${filePath}\n\n建议: 使用 'npx eslint --fix' 或 'organize-imports-cli' 自动移除未使用导入。\n\n整理后:\n${updated.slice(0, 10000)}`,
|
|
69
|
+
metadata: { filePath, importCount: organized.length, removeUnused },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
output: `导入已整理: ${filePath}\n整理后:\n${updated.slice(0, 10000)}`,
|
|
76
|
+
metadata: { filePath, importCount: organized.length },
|
|
77
|
+
};
|
|
78
|
+
} catch (err: unknown) {
|
|
79
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import type { Tool } from '../../tool-types.js';
|
|
4
|
+
|
|
5
|
+
export const lint_code: Tool = {
|
|
6
|
+
name: 'lint_code',
|
|
7
|
+
description: '运行代码检查(ESLint)',
|
|
8
|
+
category: 'code',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: { type: 'string', description: '文件或目录路径' },
|
|
13
|
+
fix: { type: 'boolean', description: '是否自动修复' },
|
|
14
|
+
},
|
|
15
|
+
required: [],
|
|
16
|
+
},
|
|
17
|
+
dangerous: false,
|
|
18
|
+
requiresApproval: false,
|
|
19
|
+
async execute(params) {
|
|
20
|
+
try {
|
|
21
|
+
const filePath = params.file_path as string | undefined;
|
|
22
|
+
const fix = (params.fix as boolean) ?? false;
|
|
23
|
+
|
|
24
|
+
const target = filePath ? resolve(filePath) : '.';
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const cmd = fix ? `npx eslint "${target}" --fix` : `npx eslint "${target}"`;
|
|
28
|
+
const output = execSync(cmd, {
|
|
29
|
+
encoding: 'utf-8',
|
|
30
|
+
timeout: 60000,
|
|
31
|
+
stdio: 'pipe',
|
|
32
|
+
});
|
|
33
|
+
return { success: true, output: output || '代码检查通过,无问题!', metadata: { target, fix } };
|
|
34
|
+
} catch (err: unknown) {
|
|
35
|
+
const e = err as { stdout?: string; stderr?: string };
|
|
36
|
+
const issues = e.stdout || e.stderr || String(err);
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: '代码检查发现问题',
|
|
40
|
+
output: issues,
|
|
41
|
+
metadata: { target, hasIssues: true },
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
} catch (err: unknown) {
|
|
45
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import type { Tool } from '../../tool-types.js';
|
|
4
|
+
|
|
5
|
+
export const parse_ast: Tool = {
|
|
6
|
+
name: 'parse_ast',
|
|
7
|
+
description: '解析代码结构(简化 AST 分析)',
|
|
8
|
+
category: 'code',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: { type: 'string', description: '源代码文件路径' },
|
|
13
|
+
language: { type: 'string', description: '语言类型: typescript, javascript, python', enum: ['typescript', 'javascript', 'python'] },
|
|
14
|
+
},
|
|
15
|
+
required: ['file_path'],
|
|
16
|
+
},
|
|
17
|
+
dangerous: false,
|
|
18
|
+
requiresApproval: false,
|
|
19
|
+
async execute(params) {
|
|
20
|
+
try {
|
|
21
|
+
const filePath = resolve(params.file_path as string);
|
|
22
|
+
const language = (params.language as string) ?? 'typescript';
|
|
23
|
+
|
|
24
|
+
if (!existsSync(filePath)) {
|
|
25
|
+
return { success: false, error: `文件不存在: ${filePath}`, output: '' };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
29
|
+
const lines = content.split('\n');
|
|
30
|
+
|
|
31
|
+
const functions: string[] = [];
|
|
32
|
+
const classes: string[] = [];
|
|
33
|
+
const imports: string[] = [];
|
|
34
|
+
const exports: string[] = [];
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
const line = lines[i].trim();
|
|
38
|
+
const lineNum = i + 1;
|
|
39
|
+
|
|
40
|
+
if (/^(export\s+)?(async\s+)?function\s+(\w+)/i.test(line)) {
|
|
41
|
+
functions.push(`${lineNum}: ${line.slice(0, 120)}`);
|
|
42
|
+
}
|
|
43
|
+
if (/^(export\s+)?class\s+(\w+)/i.test(line)) {
|
|
44
|
+
classes.push(`${lineNum}: ${line.slice(0, 120)}`);
|
|
45
|
+
}
|
|
46
|
+
if (/^(import\s+|from\s+|require\()/i.test(line)) {
|
|
47
|
+
imports.push(`${lineNum}: ${line.slice(0, 120)}`);
|
|
48
|
+
}
|
|
49
|
+
if (/^export\s+/.test(line)) {
|
|
50
|
+
exports.push(`${lineNum}: ${line.slice(0, 120)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const output = [
|
|
55
|
+
`=== 代码结构分析: ${filePath} ===`,
|
|
56
|
+
`语言: ${language} | 行数: ${lines.length}`,
|
|
57
|
+
'',
|
|
58
|
+
`--- 函数 (${functions.length}) ---`,
|
|
59
|
+
...functions.slice(0, 50),
|
|
60
|
+
'',
|
|
61
|
+
`--- 类 (${classes.length}) ---`,
|
|
62
|
+
...classes.slice(0, 20),
|
|
63
|
+
'',
|
|
64
|
+
`--- 导入 (${imports.length}) ---`,
|
|
65
|
+
...imports.slice(0, 30),
|
|
66
|
+
'',
|
|
67
|
+
`--- 导出 (${exports.length}) ---`,
|
|
68
|
+
...exports.slice(0, 30),
|
|
69
|
+
].join('\n');
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
output,
|
|
74
|
+
metadata: {
|
|
75
|
+
functions: functions.length,
|
|
76
|
+
classes: classes.length,
|
|
77
|
+
imports: imports.length,
|
|
78
|
+
exports: exports.length,
|
|
79
|
+
lines: lines.length,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
} catch (err: unknown) {
|
|
83
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
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 refactor_code: Tool = {
|
|
6
|
+
name: 'refactor_code',
|
|
7
|
+
description: '提供代码重构建议和执行常见重构操作',
|
|
8
|
+
category: 'code',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: { type: 'string', description: '文件路径' },
|
|
13
|
+
action: { type: 'string', description: '重构操作: rename, extract, inline, move', enum: ['rename', 'extract', 'inline', 'move'] },
|
|
14
|
+
target: { type: 'string', description: '目标符号名' },
|
|
15
|
+
new_name: { type: 'string', description: '新名称' },
|
|
16
|
+
},
|
|
17
|
+
required: ['file_path', 'action'],
|
|
18
|
+
},
|
|
19
|
+
dangerous: false,
|
|
20
|
+
requiresApproval: true,
|
|
21
|
+
async execute(params) {
|
|
22
|
+
try {
|
|
23
|
+
const filePath = resolve(params.file_path as string);
|
|
24
|
+
const action = params.action as string;
|
|
25
|
+
const target = params.target as string | undefined;
|
|
26
|
+
const newName = params.new_name as string | undefined;
|
|
27
|
+
|
|
28
|
+
if (!existsSync(filePath)) {
|
|
29
|
+
return { success: false, error: `文件不存在: ${filePath}`, output: '' };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
33
|
+
const lines = content.split('\n');
|
|
34
|
+
|
|
35
|
+
let output = `=== 代码重构: ${filePath} ===\n操作: ${action}\n`;
|
|
36
|
+
|
|
37
|
+
switch (action) {
|
|
38
|
+
case 'rename': {
|
|
39
|
+
if (!target || !newName) {
|
|
40
|
+
return { success: false, error: 'rename 需要 target 和 new_name 参数', output: '' };
|
|
41
|
+
}
|
|
42
|
+
const escaped = escapeRegex(target);
|
|
43
|
+
const count = (content.match(new RegExp(`\\b${escaped}\\b`, 'g')) || []).length;
|
|
44
|
+
output += `目标: ${target} → ${newName}\n`;
|
|
45
|
+
output += `找到 ${count} 处引用\n`;
|
|
46
|
+
output += '请使用 edit_file 工具执行精确替换,或使用 IDE 的重构功能。';
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
default:
|
|
50
|
+
output += `重构操作 "${action}" 的分析已提供。\n`;
|
|
51
|
+
output += '建议使用 IDE (VS Code, WebStorm) 的内置重构工具以获得最佳结果。';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { success: true, output, metadata: { filePath, action, target, newName } };
|
|
55
|
+
} catch (err: unknown) {
|
|
56
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function escapeRegex(s: string): string {
|
|
62
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
63
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import type { Tool } from '../../tool-types.js';
|
|
4
|
+
|
|
5
|
+
export const type_check: Tool = {
|
|
6
|
+
name: 'type_check',
|
|
7
|
+
description: '运行 TypeScript 类型检查',
|
|
8
|
+
category: 'code',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
project: { type: 'string', description: 'tsconfig.json 路径' },
|
|
13
|
+
strict: { type: 'boolean', description: '是否严格模式' },
|
|
14
|
+
},
|
|
15
|
+
required: [],
|
|
16
|
+
},
|
|
17
|
+
dangerous: false,
|
|
18
|
+
requiresApproval: false,
|
|
19
|
+
async execute(params) {
|
|
20
|
+
try {
|
|
21
|
+
const project = params.project as string | undefined;
|
|
22
|
+
const strict = (params.strict as boolean) ?? true;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const args = ['tsc', '--noEmit'];
|
|
26
|
+
if (project) args.push('--project', resolve(project));
|
|
27
|
+
if (strict) args.push('--strict');
|
|
28
|
+
|
|
29
|
+
const output = execSync(args.join(' '), {
|
|
30
|
+
encoding: 'utf-8',
|
|
31
|
+
timeout: 120000,
|
|
32
|
+
stdio: 'pipe',
|
|
33
|
+
});
|
|
34
|
+
return { success: true, output: output || '类型检查通过!', metadata: { passed: true } };
|
|
35
|
+
} catch (err: unknown) {
|
|
36
|
+
const e = err as { stdout?: string; stderr?: string };
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: '类型检查发现错误',
|
|
40
|
+
output: e.stdout || e.stderr || String(err),
|
|
41
|
+
metadata: { passed: false },
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
} catch (err: unknown) {
|
|
45
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Tool } from '../../tool-types.js';
|
|
2
|
+
|
|
3
|
+
export const chart_generate: Tool = {
|
|
4
|
+
name: 'chart_generate',
|
|
5
|
+
description: '生成数据图表(输出图表描述和配置)',
|
|
6
|
+
category: 'data',
|
|
7
|
+
parameters: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
data: { type: 'string', description: 'JSON 格式的数据' },
|
|
11
|
+
chart_type: { type: 'string', description: '图表类型: bar, line, pie, scatter, area', enum: ['bar', 'line', 'pie', 'scatter', 'area'] },
|
|
12
|
+
x_key: { type: 'string', description: 'X 轴数据键名' },
|
|
13
|
+
y_key: { type: 'string', description: 'Y 轴数据键名' },
|
|
14
|
+
title: { type: 'string', description: '图表标题' },
|
|
15
|
+
},
|
|
16
|
+
required: ['data', 'chart_type'],
|
|
17
|
+
},
|
|
18
|
+
dangerous: false,
|
|
19
|
+
requiresApproval: true,
|
|
20
|
+
async execute(params) {
|
|
21
|
+
try {
|
|
22
|
+
const data = JSON.parse(params.data as string);
|
|
23
|
+
const chartType = params.chart_type as string;
|
|
24
|
+
const xKey = params.x_key as string | undefined;
|
|
25
|
+
const yKey = params.y_key as string | undefined;
|
|
26
|
+
const title = (params.title as string) ?? 'Chart';
|
|
27
|
+
|
|
28
|
+
const config = {
|
|
29
|
+
title,
|
|
30
|
+
type: chartType,
|
|
31
|
+
data: Array.isArray(data) ? data : [data],
|
|
32
|
+
xKey,
|
|
33
|
+
yKey,
|
|
34
|
+
timestamp: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const output = [
|
|
38
|
+
`图表配置: ${title} (${chartType})`,
|
|
39
|
+
'',
|
|
40
|
+
'```json',
|
|
41
|
+
JSON.stringify(config, null, 2),
|
|
42
|
+
'```',
|
|
43
|
+
'',
|
|
44
|
+
'提示: 可以使用以下工具渲染图表:',
|
|
45
|
+
'- Chart.js + Canvas (Node.js)',
|
|
46
|
+
'- Apache ECharts',
|
|
47
|
+
'- D3.js',
|
|
48
|
+
'- Matplotlib (Python)',
|
|
49
|
+
'',
|
|
50
|
+
'使用建议: 安装 chartjs-node-canvas 或使用 web 前端渲染。',
|
|
51
|
+
].join('\n');
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
success: true,
|
|
55
|
+
output,
|
|
56
|
+
metadata: { chartType, dataPoints: Array.isArray(data) ? data.length : 1 },
|
|
57
|
+
};
|
|
58
|
+
} catch (err: unknown) {
|
|
59
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Tool } from '../../tool-types.js';
|
|
2
|
+
|
|
3
|
+
export const csv_parse: Tool = {
|
|
4
|
+
name: 'csv_parse',
|
|
5
|
+
description: '解析 CSV 内容',
|
|
6
|
+
category: 'data',
|
|
7
|
+
parameters: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
content: { type: 'string', description: 'CSV 字符串' },
|
|
11
|
+
file_path: { type: 'string', description: 'CSV 文件路径' },
|
|
12
|
+
delimiter: { type: 'string', description: '列分隔符,默认逗号' },
|
|
13
|
+
has_header: { type: 'boolean', description: '是否有标题行' },
|
|
14
|
+
},
|
|
15
|
+
required: [],
|
|
16
|
+
},
|
|
17
|
+
dangerous: false,
|
|
18
|
+
requiresApproval: false,
|
|
19
|
+
async execute(params) {
|
|
20
|
+
try {
|
|
21
|
+
let csvContent = '';
|
|
22
|
+
const filePath = params.file_path as string | undefined;
|
|
23
|
+
const content = params.content as string | undefined;
|
|
24
|
+
const delimiter = (params.delimiter as string) ?? ',';
|
|
25
|
+
const hasHeader = (params.has_header as boolean) ?? true;
|
|
26
|
+
|
|
27
|
+
if (filePath) {
|
|
28
|
+
const { readFileSync, existsSync } = await import('node:fs');
|
|
29
|
+
const { resolve } = await import('node:path');
|
|
30
|
+
const abs = resolve(filePath);
|
|
31
|
+
if (!existsSync(abs)) return { success: false, error: `文件不存在: ${abs}`, output: '' };
|
|
32
|
+
csvContent = readFileSync(abs, 'utf-8');
|
|
33
|
+
} else if (content) {
|
|
34
|
+
csvContent = content;
|
|
35
|
+
} else {
|
|
36
|
+
return { success: false, error: '请提供 content 或 file_path 参数', output: '' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { parse } = await import('csv-parse/sync');
|
|
40
|
+
const records = parse(csvContent, {
|
|
41
|
+
delimiter,
|
|
42
|
+
columns: hasHeader,
|
|
43
|
+
skip_empty_lines: true,
|
|
44
|
+
trim: true,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
output: JSON.stringify(records, null, 2),
|
|
50
|
+
metadata: { rows: Array.isArray(records) ? records.length : 0 },
|
|
51
|
+
};
|
|
52
|
+
} catch (err: unknown) {
|
|
53
|
+
return { success: false, error: (err as Error).message, output: '' };
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
};
|