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.
Files changed (188) hide show
  1. package/README.md +254 -0
  2. package/dist/cli/index.d.ts +1 -0
  3. package/dist/cli/index.js +12067 -0
  4. package/dist/cli/index.js.map +1 -0
  5. package/dist/index.d.ts +415 -0
  6. package/dist/index.js +1599 -0
  7. package/dist/index.js.map +1 -0
  8. package/docs/superpowers/plans/2026-05-14-deepercode-implementation.md +24 -0
  9. package/docs/superpowers/plans/2026-05-14-deepercode-plan.md +1248 -0
  10. package/docs/superpowers/specs/2026-05-14-deepercode-design.md +560 -0
  11. package/package.json +60 -0
  12. package/src/cli/bootstrap.ts +69 -0
  13. package/src/cli/chat-repl.ts +932 -0
  14. package/src/cli/commands/chat.ts +39 -0
  15. package/src/cli/commands/chat.tsx +39 -0
  16. package/src/cli/commands/config.ts +133 -0
  17. package/src/cli/commands/mcp.ts +172 -0
  18. package/src/cli/commands/run.ts +147 -0
  19. package/src/cli/commands/skill.ts +152 -0
  20. package/src/cli/index.ts +184 -0
  21. package/src/core/bugscan.ts +145 -0
  22. package/src/core/config.ts +285 -0
  23. package/src/core/constants.ts +49 -0
  24. package/src/core/eventbus.ts +202 -0
  25. package/src/core/logger.ts +109 -0
  26. package/src/core/storage.ts +96 -0
  27. package/src/index.ts +26 -0
  28. package/src/mcp/ConfigLoader.ts +74 -0
  29. package/src/mcp/MCPClient.ts +326 -0
  30. package/src/mcp/ResourceAdapter.ts +58 -0
  31. package/src/mcp/SSETransport.ts +133 -0
  32. package/src/mcp/StdioTransport.ts +116 -0
  33. package/src/mcp/ToolAdapter.ts +71 -0
  34. package/src/mcp/types.ts +58 -0
  35. package/src/memory/xmemory.ts +275 -0
  36. package/src/model/DeepSeekClient.ts +292 -0
  37. package/src/model/MessageBuilder.ts +155 -0
  38. package/src/model/RetryManager.ts +82 -0
  39. package/src/model/StreamHandler.ts +158 -0
  40. package/src/model/types.ts +86 -0
  41. package/src/skills/SkillCreator.ts +153 -0
  42. package/src/skills/SkillEngine.ts +158 -0
  43. package/src/skills/SkillExecutor.ts +107 -0
  44. package/src/skills/SkillLoader.ts +182 -0
  45. package/src/skills/SkillRegistry.ts +73 -0
  46. package/src/skills/SkillTrigger.ts +82 -0
  47. package/src/skills/types.ts +28 -0
  48. package/src/tools/ToolExecutor.ts +103 -0
  49. package/src/tools/ToolRegistry.ts +71 -0
  50. package/src/tools/ToolValidator.ts +103 -0
  51. package/src/tools/builtin/ai/context_summarize.ts +76 -0
  52. package/src/tools/builtin/ai/memory_store.ts +86 -0
  53. package/src/tools/builtin/ai/prompt_template.ts +71 -0
  54. package/src/tools/builtin/ai/skill_create.ts +53 -0
  55. package/src/tools/builtin/ai/subagent.ts +39 -0
  56. package/src/tools/builtin/ai/todo_manager.ts +157 -0
  57. package/src/tools/builtin/ai/token_count.ts +196 -0
  58. package/src/tools/builtin/ai/tool_create.ts +52 -0
  59. package/src/tools/builtin/code/analyze_deps.ts +72 -0
  60. package/src/tools/builtin/code/bug_scan.ts +80 -0
  61. package/src/tools/builtin/code/code_metrics.ts +111 -0
  62. package/src/tools/builtin/code/extract_function.ts +86 -0
  63. package/src/tools/builtin/code/format_code.ts +57 -0
  64. package/src/tools/builtin/code/generate_code.ts +75 -0
  65. package/src/tools/builtin/code/import_organizer.ts +82 -0
  66. package/src/tools/builtin/code/lint_code.ts +48 -0
  67. package/src/tools/builtin/code/parse_ast.ts +86 -0
  68. package/src/tools/builtin/code/refactor_code.ts +63 -0
  69. package/src/tools/builtin/code/type_check.ts +48 -0
  70. package/src/tools/builtin/data/chart_generate.ts +62 -0
  71. package/src/tools/builtin/data/csv_parse.ts +56 -0
  72. package/src/tools/builtin/data/data_diff.ts +79 -0
  73. package/src/tools/builtin/data/data_transform.ts +74 -0
  74. package/src/tools/builtin/data/data_validate.ts +75 -0
  75. package/src/tools/builtin/data/json_parse.ts +71 -0
  76. package/src/tools/builtin/data/template_render.ts +58 -0
  77. package/src/tools/builtin/data/toml_parse.ts +42 -0
  78. package/src/tools/builtin/data/xml_parse.ts +79 -0
  79. package/src/tools/builtin/data/yaml_parse.ts +42 -0
  80. package/src/tools/builtin/database/db_backup.ts +53 -0
  81. package/src/tools/builtin/database/db_restore.ts +51 -0
  82. package/src/tools/builtin/database/db_schema.ts +66 -0
  83. package/src/tools/builtin/database/nosql_query.ts +50 -0
  84. package/src/tools/builtin/database/orm_generate.ts +66 -0
  85. package/src/tools/builtin/database/redis_command.ts +46 -0
  86. package/src/tools/builtin/database/sql_migrate.ts +55 -0
  87. package/src/tools/builtin/database/sql_query.ts +60 -0
  88. package/src/tools/builtin/filesystem/batch_read.ts +56 -0
  89. package/src/tools/builtin/filesystem/batch_write.ts +67 -0
  90. package/src/tools/builtin/filesystem/copy_file.ts +36 -0
  91. package/src/tools/builtin/filesystem/create_dir.ts +30 -0
  92. package/src/tools/builtin/filesystem/delete_file.ts +30 -0
  93. package/src/tools/builtin/filesystem/diff_files.ts +47 -0
  94. package/src/tools/builtin/filesystem/edit_file.ts +47 -0
  95. package/src/tools/builtin/filesystem/file_info.ts +52 -0
  96. package/src/tools/builtin/filesystem/glob_find.ts +44 -0
  97. package/src/tools/builtin/filesystem/list_dir.ts +51 -0
  98. package/src/tools/builtin/filesystem/merge_files.ts +44 -0
  99. package/src/tools/builtin/filesystem/move_file.ts +37 -0
  100. package/src/tools/builtin/filesystem/read_file.ts +55 -0
  101. package/src/tools/builtin/filesystem/watch_file.ts +33 -0
  102. package/src/tools/builtin/filesystem/write_file.ts +45 -0
  103. package/src/tools/builtin/index.ts +244 -0
  104. package/src/tools/builtin/network/api_call.ts +79 -0
  105. package/src/tools/builtin/network/browser_action.ts +54 -0
  106. package/src/tools/builtin/network/check_url.ts +59 -0
  107. package/src/tools/builtin/network/download_file.ts +64 -0
  108. package/src/tools/builtin/network/graphql_query.ts +46 -0
  109. package/src/tools/builtin/network/http_request.ts +61 -0
  110. package/src/tools/builtin/network/parse_html.ts +101 -0
  111. package/src/tools/builtin/network/proxy_request.ts +53 -0
  112. package/src/tools/builtin/network/screenshot_page.ts +58 -0
  113. package/src/tools/builtin/network/web_fetch.ts +70 -0
  114. package/src/tools/builtin/network/web_search.ts +128 -0
  115. package/src/tools/builtin/network/websocket_connect.ts +70 -0
  116. package/src/tools/builtin/project/build_project.ts +68 -0
  117. package/src/tools/builtin/project/config_manage.ts +99 -0
  118. package/src/tools/builtin/project/coverage_report.ts +59 -0
  119. package/src/tools/builtin/project/docker_manage.ts +90 -0
  120. package/src/tools/builtin/project/env_manage.ts +88 -0
  121. package/src/tools/builtin/project/npm_manage.ts +71 -0
  122. package/src/tools/builtin/project/project_init.ts +59 -0
  123. package/src/tools/builtin/project/run_test.ts +74 -0
  124. package/src/tools/builtin/search/codebase_search.ts +76 -0
  125. package/src/tools/builtin/search/find_definition.ts +84 -0
  126. package/src/tools/builtin/search/find_references.ts +75 -0
  127. package/src/tools/builtin/search/fuzzy_find.ts +75 -0
  128. package/src/tools/builtin/search/grep_search.ts +90 -0
  129. package/src/tools/builtin/search/regex_find.ts +91 -0
  130. package/src/tools/builtin/search/search_docs.ts +51 -0
  131. package/src/tools/builtin/search/search_package.ts +50 -0
  132. package/src/tools/builtin/search/symbol_search.ts +82 -0
  133. package/src/tools/builtin/search/text_search.ts +63 -0
  134. package/src/tools/builtin/security/decrypt_file.ts +54 -0
  135. package/src/tools/builtin/security/encrypt_file.ts +52 -0
  136. package/src/tools/builtin/security/hash_generate.ts +48 -0
  137. package/src/tools/builtin/security/jwt_decode.ts +53 -0
  138. package/src/tools/builtin/security/secret_scan.ts +82 -0
  139. package/src/tools/builtin/security/vulnerability_check.ts +71 -0
  140. package/src/tools/builtin/shell/background_terminal.ts +38 -0
  141. package/src/tools/builtin/shell/check_status.ts +48 -0
  142. package/src/tools/builtin/shell/interactive_terminal.ts +31 -0
  143. package/src/tools/builtin/shell/kill_terminal.ts +29 -0
  144. package/src/tools/builtin/shell/list_terminals.ts +61 -0
  145. package/src/tools/builtin/shell/pipe_commands.ts +55 -0
  146. package/src/tools/builtin/shell/process-pool.ts +150 -0
  147. package/src/tools/builtin/shell/run_async.ts +73 -0
  148. package/src/tools/builtin/shell/run_command.ts +60 -0
  149. package/src/tools/builtin/shell/send_ctrl_keys.ts +43 -0
  150. package/src/tools/builtin/shell/send_keys.ts +36 -0
  151. package/src/tools/builtin/shell/send_text.ts +35 -0
  152. package/src/tools/builtin/shell/shell_script.ts +65 -0
  153. package/src/tools/builtin/shell/stop_command.ts +40 -0
  154. package/src/tools/builtin/shell/terminal_resize.ts +31 -0
  155. package/src/tools/builtin/shell/terminal_screenshot.ts +28 -0
  156. package/src/tools/builtin/system/log_viewer.ts +89 -0
  157. package/src/tools/builtin/system/notify_user.ts +55 -0
  158. package/src/tools/builtin/system/process_list.ts +66 -0
  159. package/src/tools/builtin/system/resource_monitor.ts +66 -0
  160. package/src/tools/builtin/system/system_info.ts +41 -0
  161. package/src/tools/tool-types.ts +97 -0
  162. package/src/ui/AgentTree.tsx +98 -0
  163. package/src/ui/App.tsx +46 -0
  164. package/src/ui/ChatView.tsx +278 -0
  165. package/src/ui/ConfirmDialog.tsx +68 -0
  166. package/src/ui/DiffView.tsx +64 -0
  167. package/src/ui/FilePreview.tsx +59 -0
  168. package/src/ui/InputBox.tsx +267 -0
  169. package/src/ui/MessageBubble.tsx +30 -0
  170. package/src/ui/Spinner.tsx +35 -0
  171. package/src/ui/StatusBar.tsx +41 -0
  172. package/src/ui/ToolCallCard.tsx +73 -0
  173. package/src/ui/ansi.ts +50 -0
  174. package/src/ui/markdown.ts +238 -0
  175. package/src/ui/themes/dark.ts +4 -0
  176. package/src/ui/themes/default.ts +25 -0
  177. package/src/ui/themes/light.ts +14 -0
  178. package/tests/unit/BuiltinTools.test.ts +129 -0
  179. package/tests/unit/BuiltinToolsIntegration.test.ts +111 -0
  180. package/tests/unit/FilesystemTools.test.ts +211 -0
  181. package/tests/unit/SkillLoader.test.ts +141 -0
  182. package/tests/unit/SkillRegistry.test.ts +113 -0
  183. package/tests/unit/ToolExecutor.test.ts +160 -0
  184. package/tests/unit/ToolRegistry.test.ts +103 -0
  185. package/tests/unit/ToolValidator.test.ts +137 -0
  186. package/tsconfig.json +28 -0
  187. package/tsup.config.ts +17 -0
  188. package/vitest.config.ts +20 -0
@@ -0,0 +1,50 @@
1
+ import { execSync } from 'node:child_process';
2
+ import type { Tool } from '../../tool-types.js';
3
+
4
+ export const search_package: Tool = {
5
+ name: 'search_package',
6
+ description: '搜索 npm 包',
7
+ category: 'search',
8
+ parameters: {
9
+ type: 'object',
10
+ properties: {
11
+ name: { type: 'string', description: '包名关键词' },
12
+ count: { type: 'number', description: '返回数量' },
13
+ },
14
+ required: ['name'],
15
+ },
16
+ dangerous: false,
17
+ requiresApproval: false,
18
+ async execute(params) {
19
+ try {
20
+ const name = params.name as string;
21
+ const count = (params.count as number) ?? 10;
22
+ const output = execSync(
23
+ `npm search "${name}" --registry https://registry.npmmirror.com --json 2>&1`,
24
+ { encoding: 'utf-8', timeout: 15000 }
25
+ );
26
+ const results = JSON.parse(output);
27
+ const items = (Array.isArray(results) ? results.slice(0, count) : [results]).map(
28
+ (pkg: Record<string, unknown>) => ({
29
+ name: pkg.name as string,
30
+ version: pkg.version as string,
31
+ description: pkg.description as string,
32
+ author: (pkg.author as Record<string, unknown> | undefined)?.name || pkg.author,
33
+ })
34
+ );
35
+ return {
36
+ success: true,
37
+ output: items.map((i: Record<string, unknown>) =>
38
+ `${i.name}@${i.version}\n ${i.description}\n Author: ${i.author}`
39
+ ).join('\n\n'),
40
+ metadata: { count: items.length },
41
+ };
42
+ } catch {
43
+ return {
44
+ success: true,
45
+ output: `请在 npm 官网搜索: https://www.npmjs.com/search?q=${encodeURIComponent(params.name as string)}`,
46
+ metadata: { fallback: true },
47
+ };
48
+ }
49
+ },
50
+ };
@@ -0,0 +1,82 @@
1
+ import { readFileSync, existsSync, statSync } from 'node:fs';
2
+ import { resolve, relative } from 'node:path';
3
+ import type { Tool } from '../../tool-types.js';
4
+
5
+ export const symbol_search: Tool = {
6
+ name: 'symbol_search',
7
+ description: '在代码库中搜索符号(函数、类、变量定义)',
8
+ category: 'search',
9
+ parameters: {
10
+ type: 'object',
11
+ properties: {
12
+ name: { type: 'string', description: '符号名称' },
13
+ cwd: { type: 'string', description: '搜索根目录' },
14
+ type: { type: 'string', description: '符号类型: function, class, variable, interface, type', enum: ['function', 'class', 'variable', 'interface', 'type', 'all'] },
15
+ max_results: { type: 'number', description: '最大结果数' },
16
+ },
17
+ required: ['name'],
18
+ },
19
+ dangerous: false,
20
+ requiresApproval: false,
21
+ async execute(params) {
22
+ try {
23
+ const name = params.name as string;
24
+ const cwd = (params.cwd as string) ? resolve(params.cwd as string) : process.cwd();
25
+ const symbolType = (params.type as string) ?? 'all';
26
+ const maxResults = (params.max_results as number) ?? 50;
27
+
28
+ const patterns: [string, RegExp][] = [];
29
+ if (symbolType === 'all' || symbolType === 'function') {
30
+ patterns.push(['function', new RegExp(`(?:function\\s+${name}|${name}\\s*[=:]\\s*(?:async\\s+)?(?:function|\\([^)]*\\)\\s*=>)|(?:async\\s+)?${name}\\s*\\([^)]*\\)\\s*\\{`, 'gmi')]);
31
+ }
32
+ if (symbolType === 'all' || symbolType === 'class') {
33
+ patterns.push(['class', new RegExp(`class\\s+${name}\\b`, 'gmi')]);
34
+ }
35
+ if (symbolType === 'all' || symbolType === 'variable') {
36
+ patterns.push(['variable', new RegExp(`(?:const|let|var)\\s+${name}\\b`, 'gmi')]);
37
+ }
38
+ if (symbolType === 'all' || symbolType === 'interface') {
39
+ patterns.push(['interface', new RegExp(`interface\\s+${name}\\b`, 'gmi')]);
40
+ }
41
+ if (symbolType === 'all' || symbolType === 'type') {
42
+ patterns.push(['type', new RegExp(`type\\s+${name}\\b`, 'gmi')]);
43
+ }
44
+
45
+ const fg = await import('fast-glob');
46
+ const files = await fg.default('**/*.{ts,js,tsx,jsx}', {
47
+ cwd,
48
+ absolute: true,
49
+ ignore: ['node_modules/**', '.git/**', 'dist/**'],
50
+ onlyFiles: true,
51
+ });
52
+
53
+ const results: string[] = [];
54
+ const maxFileSize = 2 * 1024 * 1024;
55
+
56
+ for (const fp of files) {
57
+ if (results.length >= maxResults) break;
58
+ try {
59
+ const stat = statSync(fp);
60
+ if (stat.size > maxFileSize) continue;
61
+ const content = readFileSync(fp, 'utf-8');
62
+ for (const [type, regex] of patterns) {
63
+ regex.lastIndex = 0;
64
+ let match;
65
+ while ((match = regex.exec(content)) !== null && results.length < maxResults) {
66
+ const line = content.slice(0, match.index).split('\n').length;
67
+ results.push(`${relative(cwd, fp)}:${line}: [${type}] ${match[0].trim()}`);
68
+ }
69
+ }
70
+ } catch { /* skip */ }
71
+ }
72
+
73
+ return {
74
+ success: true,
75
+ output: results.join('\n') || '未找到匹配符号',
76
+ metadata: { count: results.length },
77
+ };
78
+ } catch (err: unknown) {
79
+ return { success: false, error: (err as Error).message, output: '' };
80
+ }
81
+ },
82
+ };
@@ -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 text_search: Tool = {
6
+ name: 'text_search',
7
+ description: '全文搜索,在文件内容中查找文本',
8
+ category: 'search',
9
+ parameters: {
10
+ type: 'object',
11
+ properties: {
12
+ text: { type: 'string', description: '搜索文本' },
13
+ dir_path: { type: 'string', description: '搜索目录' },
14
+ file_pattern: { type: 'string', description: '文件匹配模式,如 *.md' },
15
+ max_results: { type: 'number', description: '最大结果数' },
16
+ },
17
+ required: ['text', 'dir_path'],
18
+ },
19
+ dangerous: false,
20
+ requiresApproval: false,
21
+ async execute(params) {
22
+ try {
23
+ const text = params.text as string;
24
+ const dirPath = resolve(params.dir_path as string);
25
+ const filePattern = (params.file_pattern as string) ?? '**/*';
26
+ const maxResults = (params.max_results as number) ?? 100;
27
+
28
+ const fg = await import('fast-glob');
29
+ const files = await fg.default(filePattern, {
30
+ cwd: dirPath,
31
+ absolute: true,
32
+ ignore: ['node_modules/**', '.git/**', 'dist/**', '*.min.*', '*.jpg', '*.png', '*.gif', '*.ico', '*.svg'],
33
+ onlyFiles: true,
34
+ });
35
+
36
+ const results: string[] = [];
37
+ const maxFileSize = 2 * 1024 * 1024;
38
+
39
+ for (const fp of files) {
40
+ if (results.length >= maxResults) break;
41
+ try {
42
+ const stat = await import('node:fs').then(m => m.statSync(fp));
43
+ if (stat.size > maxFileSize) continue;
44
+ const content = readFileSync(fp, 'utf-8');
45
+ const lines = content.split('\n');
46
+ for (let i = 0; i < lines.length && results.length < maxResults; i++) {
47
+ if (lines[i].includes(text)) {
48
+ results.push(`${fp}:${i + 1}:${lines[i].trim()}`);
49
+ }
50
+ }
51
+ } catch { /* skip */ }
52
+ }
53
+
54
+ return {
55
+ success: true,
56
+ output: results.join('\n') || '未找到匹配结果',
57
+ metadata: { matches: results.length, dir: dirPath },
58
+ };
59
+ } catch (err: unknown) {
60
+ return { success: false, error: (err as Error).message, output: '' };
61
+ }
62
+ },
63
+ };
@@ -0,0 +1,54 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import type { Tool } from '../../tool-types.js';
4
+
5
+ export const decrypt_file: Tool = {
6
+ name: 'decrypt_file',
7
+ description: '解密文件内容 (AES-256-CBC)',
8
+ category: 'security',
9
+ parameters: {
10
+ type: 'object',
11
+ properties: {
12
+ file_path: { type: 'string', description: '要解密的文件路径' },
13
+ output: { type: 'string', description: '解密输出文件路径' },
14
+ password: { type: 'string', description: '解密密钥' },
15
+ algorithm: { type: 'string', description: '算法', enum: ['aes-256-cbc', 'aes-128-cbc'] },
16
+ },
17
+ required: ['file_path', 'output'],
18
+ },
19
+ dangerous: false,
20
+ requiresApproval: true,
21
+ async execute(params) {
22
+ try {
23
+ const filePath = resolve(params.file_path as string);
24
+ const output = resolve(params.output as string);
25
+ const password = params.password as string | undefined;
26
+ const algorithm = (params.algorithm as string) ?? 'aes-256-cbc';
27
+
28
+ if (!existsSync(filePath)) return { success: false, error: `文件不存在: ${filePath}`, output: '' };
29
+
30
+ const crypto = await import('node:crypto');
31
+ const encrypted = readFileSync(filePath);
32
+
33
+ const iv = encrypted.subarray(0, 16);
34
+ const data = encrypted.subarray(16);
35
+
36
+ const key = crypto.scryptSync(password || 'default-secret-key', 'salt', algorithm === 'aes-256-cbc' ? 32 : 16);
37
+ const decipher = crypto.createDecipheriv(algorithm, key, iv);
38
+
39
+ const decrypted = Buffer.concat([decipher.update(data), decipher.final()]);
40
+
41
+ const outDir = dirname(output);
42
+ if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
43
+ writeFileSync(output, decrypted);
44
+
45
+ return {
46
+ success: true,
47
+ output: `文件已解密: ${filePath} → ${output}`,
48
+ metadata: { algorithm, decryptedSize: decrypted.length },
49
+ };
50
+ } catch (err: unknown) {
51
+ return { success: false, error: (err as Error).message, output: '' };
52
+ }
53
+ },
54
+ };
@@ -0,0 +1,52 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { resolve, dirname } from 'node:path';
3
+ import type { Tool } from '../../tool-types.js';
4
+
5
+ export const encrypt_file: Tool = {
6
+ name: 'encrypt_file',
7
+ description: '加密文件内容 (AES-256-CBC)',
8
+ category: 'security',
9
+ parameters: {
10
+ type: 'object',
11
+ properties: {
12
+ file_path: { type: 'string', description: '要加密的文件路径' },
13
+ output: { type: 'string', description: '加密输出文件路径' },
14
+ password: { type: 'string', description: '加密密钥' },
15
+ algorithm: { type: 'string', description: '加密算法', enum: ['aes-256-cbc', 'aes-128-cbc'] },
16
+ },
17
+ required: ['file_path', 'output'],
18
+ },
19
+ dangerous: false,
20
+ requiresApproval: true,
21
+ async execute(params) {
22
+ try {
23
+ const filePath = resolve(params.file_path as string);
24
+ const output = resolve(params.output as string);
25
+ const password = params.password as string | undefined;
26
+ const algorithm = (params.algorithm as string) ?? 'aes-256-cbc';
27
+
28
+ if (!existsSync(filePath)) return { success: false, error: `文件不存在: ${filePath}`, output: '' };
29
+
30
+ const crypto = await import('node:crypto');
31
+ const content = readFileSync(filePath);
32
+
33
+ const key = crypto.scryptSync(password || 'default-secret-key', 'salt', algorithm === 'aes-256-cbc' ? 32 : 16);
34
+ const iv = crypto.randomBytes(16);
35
+ const cipher = crypto.createCipheriv(algorithm, key, iv);
36
+
37
+ const encrypted = Buffer.concat([iv, cipher.update(content), cipher.final()]);
38
+
39
+ const outDir = dirname(output);
40
+ if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
41
+ writeFileSync(output, encrypted);
42
+
43
+ return {
44
+ success: true,
45
+ output: `文件已加密: ${filePath} → ${output}`,
46
+ metadata: { algorithm, encryptedSize: encrypted.length },
47
+ };
48
+ } catch (err: unknown) {
49
+ return { success: false, error: (err as Error).message, output: '' };
50
+ }
51
+ },
52
+ };
@@ -0,0 +1,48 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import type { Tool } from '../../tool-types.js';
5
+
6
+ export const hash_generate: Tool = {
7
+ name: 'hash_generate',
8
+ description: '生成文件或字符串的哈希值',
9
+ category: 'security',
10
+ parameters: {
11
+ type: 'object',
12
+ properties: {
13
+ content: { type: 'string', description: '要哈希的字符串' },
14
+ file_path: { type: 'string', description: '文件路径' },
15
+ algorithm: { type: 'string', description: '算法', enum: ['sha256', 'sha512', 'md5'] },
16
+ },
17
+ required: [],
18
+ },
19
+ dangerous: false,
20
+ requiresApproval: false,
21
+ async execute(params) {
22
+ try {
23
+ const content = params.content as string | undefined;
24
+ const filePath = params.file_path as string | undefined;
25
+ const algorithm = (params.algorithm as string) ?? 'sha256';
26
+
27
+ let hash: string;
28
+ if (filePath) {
29
+ const abs = resolve(filePath);
30
+ if (!existsSync(abs)) return { success: false, error: `文件不存在: ${abs}`, output: '' };
31
+ const fileContent = readFileSync(abs);
32
+ hash = createHash(algorithm).update(fileContent).digest('hex');
33
+ } else if (content) {
34
+ hash = createHash(algorithm).update(content, 'utf-8').digest('hex');
35
+ } else {
36
+ return { success: false, error: '请提供 content 或 file_path 参数', output: '' };
37
+ }
38
+
39
+ return {
40
+ success: true,
41
+ output: `${algorithm.toUpperCase()}: ${hash}`,
42
+ metadata: { algorithm, hash },
43
+ };
44
+ } catch (err: unknown) {
45
+ return { success: false, error: (err as Error).message, output: '' };
46
+ }
47
+ },
48
+ };
@@ -0,0 +1,53 @@
1
+ import type { Tool } from '../../tool-types.js';
2
+
3
+ export const jwt_decode: Tool = {
4
+ name: 'jwt_decode',
5
+ description: '解码 JWT Token(不验证签名)',
6
+ category: 'security',
7
+ parameters: {
8
+ type: 'object',
9
+ properties: {
10
+ token: { type: 'string', description: 'JWT Token 字符串' },
11
+ },
12
+ required: ['token'],
13
+ },
14
+ dangerous: false,
15
+ requiresApproval: false,
16
+ async execute(params) {
17
+ try {
18
+ const token = params.token as string;
19
+ const parts = token.split('.');
20
+
21
+ if (parts.length !== 3) {
22
+ return { success: false, error: '无效的 JWT 格式(需要3部分)', output: '' };
23
+ }
24
+
25
+ const decodeBase64 = (str: string): string => {
26
+ const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
27
+ return Buffer.from(base64, 'base64').toString('utf-8');
28
+ };
29
+
30
+ const header = JSON.parse(decodeBase64(parts[0]));
31
+ const payload = JSON.parse(decodeBase64(parts[1]));
32
+
33
+ const output = [
34
+ '=== JWT Token 解码 ===',
35
+ '',
36
+ '--- Header ---',
37
+ JSON.stringify(header, null, 2),
38
+ '',
39
+ '--- Payload ---',
40
+ JSON.stringify(payload, null, 2),
41
+ '',
42
+ payload.exp ? `过期时间: ${new Date(payload.exp * 1000).toISOString()}${Date.now() > payload.exp * 1000 ? ' (已过期)' : ''}` : '',
43
+ payload.iat ? `签发时间: ${new Date(payload.iat * 1000).toISOString()}` : '',
44
+ '',
45
+ '注意: 签名未验证,仅解码。',
46
+ ].filter(Boolean).join('\n');
47
+
48
+ return { success: true, output, metadata: { ...header, sub: payload.sub } };
49
+ } catch (err: unknown) {
50
+ return { success: false, error: (err as Error).message, output: '' };
51
+ }
52
+ },
53
+ };
@@ -0,0 +1,82 @@
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 secret_scan: Tool = {
6
+ name: 'secret_scan',
7
+ description: '扫描代码中的密钥和敏感信息',
8
+ category: 'security',
9
+ parameters: {
10
+ type: 'object',
11
+ properties: {
12
+ dir_path: { type: 'string', description: '扫描目录' },
13
+ file_path: { type: 'string', description: '扫描文件' },
14
+ max_results: { type: 'number', description: '最大结果数' },
15
+ },
16
+ required: [],
17
+ },
18
+ dangerous: false,
19
+ requiresApproval: true,
20
+ async execute(params) {
21
+ try {
22
+ const dirPath = params.dir_path as string | undefined;
23
+ const filePath = params.file_path as string | undefined;
24
+ const maxResults = (params.max_results as number) ?? 100;
25
+
26
+ const patterns: [string, RegExp][] = [
27
+ ['API Key', /(?:api[_-]?key|apikey|api[_-]?secret)\s*[:=]\s*['"]([^'"]+)['"]/gi],
28
+ ['Password', /(?:password|passwd|pwd)\s*[:=]\s*['"]([^'"]+)['"]/gi],
29
+ ['Token', /(?:token|jwt|bearer)\s*[:=]\s*['"]([^'"]+)['"]/gi],
30
+ ['Secret', /(?:secret|secret[_-]key)\s*[:=]\s*['"]([^'"]+)['"]/gi],
31
+ ['Private Key', /-----BEGIN\s+(?:RSA|EC|DSA|OPENSSH)\s+PRIVATE\s+KEY-----/g],
32
+ ['AWS Key', /(?:AKIA[0-9A-Z]{16})/g],
33
+ ['GitHub Token', /(?:gh[pousr]_[A-Za-z0-9_]{36,})/g],
34
+ ];
35
+
36
+ const fg = await import('fast-glob');
37
+ let files: string[];
38
+ if (filePath) {
39
+ files = [resolve(filePath)];
40
+ } else {
41
+ const target = dirPath ? resolve(dirPath) : process.cwd();
42
+ files = await fg.default('**/*.{ts,js,tsx,jsx,py,yml,yaml,json,env,properties,xml,toml}', {
43
+ cwd: target,
44
+ absolute: true,
45
+ ignore: ['node_modules/**', '.git/**', 'dist/**'],
46
+ onlyFiles: true,
47
+ });
48
+ }
49
+
50
+ const results: string[] = [];
51
+ for (const fp of files.slice(0, 500)) {
52
+ if (results.length >= maxResults) break;
53
+ try {
54
+ const stat = await import('node:fs').then(m => m.statSync(fp));
55
+ if (stat.size > 1048576) continue;
56
+ const content = readFileSync(fp, 'utf-8');
57
+ for (const [type, regex] of patterns) {
58
+ regex.lastIndex = 0;
59
+ let match;
60
+ while ((match = regex.exec(content)) !== null && results.length < maxResults) {
61
+ const line = content.slice(0, match.index).split('\n').length;
62
+ const redacted = match[0].replace(/[:=]\s*['"][^'"]+/g, '=****');
63
+ results.push(`${fp}:${line}: [${type}] ${redacted.slice(0, 120)}`);
64
+ }
65
+ }
66
+ } catch { /* skip */ }
67
+ }
68
+
69
+ const output = results.length > 0
70
+ ? `发现 ${results.length} 个疑似敏感信息:\n\n${results.join('\n')}\n\n建议立即处理这些信息!`
71
+ : '未发现疑似敏感信息';
72
+
73
+ return {
74
+ success: true,
75
+ output,
76
+ metadata: { count: results.length, scanned: files.length },
77
+ };
78
+ } catch (err: unknown) {
79
+ return { success: false, error: (err as Error).message, output: '' };
80
+ }
81
+ },
82
+ };
@@ -0,0 +1,71 @@
1
+ import { execSync } from 'node:child_process';
2
+ import type { Tool } from '../../tool-types.js';
3
+
4
+ export const vulnerability_check: Tool = {
5
+ name: 'vulnerability_check',
6
+ description: '检查项目依赖漏洞 (npm audit)',
7
+ category: 'security',
8
+ parameters: {
9
+ type: 'object',
10
+ properties: {
11
+ project_path: { type: 'string', description: '项目路径' },
12
+ },
13
+ required: [],
14
+ },
15
+ dangerous: false,
16
+ requiresApproval: true,
17
+ async execute(params) {
18
+ try {
19
+ const projectPath = params.project_path as string | undefined;
20
+ const cwd = projectPath ?? process.cwd();
21
+
22
+ try {
23
+ const output = execSync('npm audit --json', {
24
+ cwd,
25
+ encoding: 'utf-8',
26
+ timeout: 120000,
27
+ stdio: 'pipe',
28
+ });
29
+ const audit = JSON.parse(output);
30
+ const vulns = audit.vulnerabilities || {};
31
+
32
+ const summary = [
33
+ `漏洞扫描结果:`,
34
+ `发现 ${Object.keys(vulns).length} 个漏洞`,
35
+ '',
36
+ '操作建议:',
37
+ ' npm audit fix # 自动修复(不破坏性更改)',
38
+ ' npm audit fix --force # 强制修复(可能包含破坏性更改)',
39
+ ' npm audit # 查看详细报告',
40
+ ].join('\n');
41
+
42
+ return {
43
+ success: true,
44
+ output: summary,
45
+ metadata: { vulnerabilityCount: Object.keys(vulns).length },
46
+ };
47
+ } catch (err: unknown) {
48
+ const e = err as { stdout?: string };
49
+ if (e.stdout) {
50
+ try {
51
+ const audit = JSON.parse(e.stdout);
52
+ const vulns = audit.vulnerabilities || {};
53
+ return {
54
+ success: false,
55
+ error: `发现 ${Object.keys(vulns).length} 个漏洞`,
56
+ output: `运行 'npm audit' 查看详情,或 'npm audit fix' 自动修复。`,
57
+ metadata: { vulnerabilityCount: Object.keys(vulns).length },
58
+ };
59
+ } catch { /* fall through */ }
60
+ }
61
+ return {
62
+ success: false,
63
+ error: 'npm audit 执行失败',
64
+ output: String(err),
65
+ };
66
+ }
67
+ } catch (err: unknown) {
68
+ return { success: false, error: (err as Error).message, output: '' };
69
+ }
70
+ },
71
+ };
@@ -0,0 +1,38 @@
1
+ import { startBgProcess } from './process-pool.js';
2
+ import type { Tool } from '../../tool-types.js';
3
+
4
+ export const background_terminal: Tool = {
5
+ name: 'background_terminal',
6
+ description: '在后台终端中运行持久进程 (npm run dev, 服务器等)。启动后立即返回,可用 read_terminal 查看输出、list_terminals 查看状态、kill_terminal 终止。',
7
+ category: 'shell',
8
+ parameters: {
9
+ type: 'object',
10
+ properties: {
11
+ command: { type: 'string', description: '要运行的命令,如 npm run dev' },
12
+ cwd: { type: 'string', description: '工作目录' },
13
+ terminal_id: { type: 'string', description: '终端标识 (可选,自动生成)' },
14
+ env: { type: 'object', description: '额外环境变量' },
15
+ },
16
+ required: ['command'],
17
+ },
18
+ dangerous: false,
19
+ requiresApproval: false,
20
+ async execute(params) {
21
+ try {
22
+ const command = params.command as string;
23
+ const cwd = params.cwd as string | undefined;
24
+ const terminalId = params.terminal_id as string | undefined;
25
+ const env = params.env as Record<string, string> | undefined;
26
+
27
+ const { terminalId: tid, pid } = startBgProcess({ command, cwd, terminalId, env });
28
+
29
+ return {
30
+ success: true,
31
+ output: `后台终端已启动\n ID: ${tid}\n PID: ${pid}\n 命令: ${command}\n 目录: ${cwd || process.cwd()}\n\n启动后等待 1-2 秒即可用 read_terminal 查看输出。`,
32
+ metadata: { terminalId: tid, pid },
33
+ };
34
+ } catch (err: unknown) {
35
+ return { success: false, error: (err as Error).message, output: '' };
36
+ }
37
+ },
38
+ };
@@ -0,0 +1,48 @@
1
+ import { runningProcesses } from './run_async.js';
2
+ import type { Tool } from '../../tool-types.js';
3
+
4
+ export const check_status: Tool = {
5
+ name: 'check_status',
6
+ description: '检查异步命令的执行状态',
7
+ category: 'shell',
8
+ parameters: {
9
+ type: 'object',
10
+ properties: {
11
+ task_id: { type: 'string', description: '任务标识' },
12
+ show_all: { type: 'boolean', description: '显示所有运行中的任务' },
13
+ },
14
+ required: [],
15
+ },
16
+ dangerous: false,
17
+ requiresApproval: false,
18
+ async execute(params) {
19
+ try {
20
+ const taskId = params.task_id as string | undefined;
21
+ const showAll = (params.show_all as boolean) ?? false;
22
+
23
+ if (showAll || !taskId) {
24
+ const tasks = Array.from(runningProcesses.keys());
25
+ return {
26
+ success: true,
27
+ output: tasks.length > 0
28
+ ? `运行中的任务 (${tasks.length}):\n${tasks.map(t => ` - ${t}`).join('\n')}`
29
+ : '没有运行中的任务',
30
+ metadata: { tasks },
31
+ };
32
+ }
33
+
34
+ const proc = runningProcesses.get(taskId);
35
+ if (!proc) {
36
+ return { success: false, error: `任务不存在或已完成: ${taskId}`, output: '' };
37
+ }
38
+
39
+ return {
40
+ success: true,
41
+ output: `任务 "${taskId}" 正在运行 (PID: ${proc.pid ?? 'unknown'})`,
42
+ metadata: { taskId, pid: proc.pid, running: true },
43
+ };
44
+ } catch (err: unknown) {
45
+ return { success: false, error: (err as Error).message, output: '' };
46
+ }
47
+ },
48
+ };
@@ -0,0 +1,31 @@
1
+ import type { Tool } from '../../tool-types.js';
2
+
3
+ export const interactive_terminal: Tool = {
4
+ name: 'interactive_terminal',
5
+ description: '启动交互式终端会话(在当前 CLI 环境中限制使用)',
6
+ category: 'shell',
7
+ parameters: {
8
+ type: 'object',
9
+ properties: {
10
+ command: { type: 'string', description: '要运行的交互式命令' },
11
+ terminal_id: { type: 'string', description: '终端标识' },
12
+ },
13
+ required: ['command'],
14
+ },
15
+ dangerous: true,
16
+ requiresApproval: true,
17
+ async execute(params) {
18
+ try {
19
+ const command = params.command as string;
20
+ const terminalId = (params.terminal_id as string) ?? `interactive_${Date.now()}`;
21
+
22
+ return {
23
+ success: true,
24
+ output: `交互式终端请求已记录: ${terminalId}\n命令: ${command}\n\n注意: 当前运行在非交互式环境,建议使用 background_terminal 运行此命令。`,
25
+ metadata: { terminalId, command, interactive: false },
26
+ };
27
+ } catch (err: unknown) {
28
+ return { success: false, error: (err as Error).message, output: '' };
29
+ }
30
+ },
31
+ };