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,103 @@
1
+ import type { Tool, ToolCall, ToolCallResult, ToolResult } from './tool-types.js';
2
+ import { TOOL_SAFETY_MAP } from './tool-types.js';
3
+ import { ToolRegistry } from './ToolRegistry.js';
4
+
5
+ export interface ToolExecutionOptions {
6
+ timeoutMs?: number;
7
+ }
8
+
9
+ export class ToolExecutor {
10
+ private registry: ToolRegistry;
11
+ private defaultTimeoutMs: number;
12
+
13
+ constructor(registry: ToolRegistry, options: ToolExecutionOptions = {}) {
14
+ this.registry = registry;
15
+ this.defaultTimeoutMs = options.timeoutMs ?? 60000;
16
+ }
17
+
18
+ async execute(call: ToolCall, signal?: AbortSignal, timeoutMs?: number): Promise<ToolCallResult> {
19
+ const startTime = Date.now();
20
+ const tool = this.registry.get(call.name);
21
+
22
+ if (!tool) {
23
+ return {
24
+ callId: call.id,
25
+ result: { success: false, error: `未知工具: ${call.name}`, output: '' },
26
+ timestamp: startTime,
27
+ };
28
+ }
29
+
30
+ const safetyLevel = TOOL_SAFETY_MAP[call.name] ?? 'safe';
31
+ if (tool.requiresApproval || safetyLevel === 'dangerous') {
32
+ return {
33
+ callId: call.id,
34
+ result: {
35
+ success: false,
36
+ error: `工具 "${call.name}" 需要在交互模式下确认才能执行`,
37
+ output: '',
38
+ metadata: { requiresUserApproval: true },
39
+ },
40
+ timestamp: startTime,
41
+ };
42
+ }
43
+
44
+ const effectiveTimeout = timeoutMs ?? this.defaultTimeoutMs;
45
+
46
+ try {
47
+ const resultPromise = tool.execute(call.arguments, signal);
48
+
49
+ let result: ToolResult;
50
+ if (effectiveTimeout > 0) {
51
+ const timeoutPromise = new Promise<ToolResult>((_, reject) => {
52
+ setTimeout(() => {
53
+ reject(new Error(`工具 "${call.name}" 执行超时 (${effectiveTimeout}ms)`));
54
+ }, effectiveTimeout);
55
+ });
56
+
57
+ result = await Promise.race([resultPromise, timeoutPromise]);
58
+ } else {
59
+ result = await resultPromise;
60
+ }
61
+
62
+ return {
63
+ callId: call.id,
64
+ result,
65
+ timestamp: Date.now(),
66
+ };
67
+ } catch (err: unknown) {
68
+ const message = err instanceof Error ? err.message : String(err);
69
+ return {
70
+ callId: call.id,
71
+ result: {
72
+ success: false,
73
+ error: message,
74
+ output: '',
75
+ metadata: { stack: err instanceof Error ? err.stack : undefined },
76
+ },
77
+ timestamp: Date.now(),
78
+ };
79
+ }
80
+ }
81
+
82
+ async executeBatch(calls: ToolCall[], signal?: AbortSignal): Promise<ToolCallResult[]> {
83
+ const results: ToolCallResult[] = [];
84
+ for (const call of calls) {
85
+ if (signal?.aborted) break;
86
+ results.push(await this.execute(call, signal));
87
+ }
88
+ return results;
89
+ }
90
+
91
+ async executeParallel(calls: ToolCall[], signal?: AbortSignal): Promise<ToolCallResult[]> {
92
+ return Promise.all(calls.map(call => {
93
+ if (signal?.aborted) {
94
+ return {
95
+ callId: call.id,
96
+ result: { success: false, error: '已取消', output: '' },
97
+ timestamp: Date.now(),
98
+ } as ToolCallResult;
99
+ }
100
+ return this.execute(call, signal);
101
+ }));
102
+ }
103
+ }
@@ -0,0 +1,71 @@
1
+ import { EventBus, globalEventBus } from '../core/eventbus.js';
2
+ import type { Tool, ToolDefinition } from './tool-types.js';
3
+
4
+ export class ToolRegistry {
5
+ private tools = new Map<string, Tool>();
6
+ private eventBus: EventBus;
7
+
8
+ constructor(eventBus: EventBus = globalEventBus) {
9
+ this.eventBus = eventBus;
10
+ }
11
+
12
+ register(tool: Tool): void {
13
+ if (this.tools.has(tool.name)) {
14
+ throw new Error(`工具已注册: ${tool.name}`);
15
+ }
16
+ this.tools.set(tool.name, tool);
17
+ this.eventBus.emit('tool:registered', { name: tool.name, category: tool.category });
18
+ }
19
+
20
+ registerAll(tools: Tool[]): void {
21
+ for (const tool of tools) {
22
+ this.register(tool);
23
+ }
24
+ }
25
+
26
+ unregister(name: string): void {
27
+ if (this.tools.delete(name)) {
28
+ this.eventBus.emit('tool:unregistered', { name });
29
+ }
30
+ }
31
+
32
+ get(name: string): Tool | undefined {
33
+ return this.tools.get(name);
34
+ }
35
+
36
+ has(name: string): boolean {
37
+ return this.tools.has(name);
38
+ }
39
+
40
+ getAll(): Tool[] {
41
+ return Array.from(this.tools.values());
42
+ }
43
+
44
+ getByCategory(category: string): Tool[] {
45
+ return this.getAll().filter(t => t.category === category);
46
+ }
47
+
48
+ getDefinitions(): ToolDefinition[] {
49
+ return this.getAll().map(t => ({
50
+ name: t.name,
51
+ description: t.description,
52
+ category: t.category,
53
+ parameters: t.parameters,
54
+ dangerous: t.dangerous,
55
+ requiresApproval: t.requiresApproval,
56
+ }));
57
+ }
58
+
59
+ count(): number {
60
+ return this.tools.size;
61
+ }
62
+
63
+ categories(): string[] {
64
+ return [...new Set(this.getAll().map(t => t.category))];
65
+ }
66
+
67
+ clear(): void {
68
+ this.tools.clear();
69
+ this.eventBus.emit('tool:cleared');
70
+ }
71
+ }
@@ -0,0 +1,103 @@
1
+ import type { Tool, ToolResult, JSONSchema } from './tool-types.js';
2
+
3
+ function getPropType(schema: JSONSchema, path: string): string {
4
+ return schema.type ?? 'any';
5
+ }
6
+
7
+ function checkRequired(
8
+ params: Record<string, unknown>,
9
+ schema: JSONSchema,
10
+ errors: string[]
11
+ ): void {
12
+ const required = schema.required ?? [];
13
+ for (const key of required) {
14
+ if (!(key in params) || params[key] === undefined) {
15
+ errors.push(`缺少必需参数: ${key}`);
16
+ }
17
+ }
18
+ }
19
+
20
+ function checkTypes(
21
+ params: Record<string, unknown>,
22
+ schema: JSONSchema,
23
+ path: string,
24
+ errors: string[]
25
+ ): void {
26
+ const props = schema.properties;
27
+ if (!props) return;
28
+
29
+ for (const [key, propSchema] of Object.entries(props)) {
30
+ const value = params[key];
31
+ const fullPath = path ? `${path}.${key}` : key;
32
+
33
+ if (value === undefined || value === null) continue;
34
+
35
+ switch (propSchema.type) {
36
+ case 'string':
37
+ if (typeof value !== 'string') {
38
+ errors.push(`参数 "${fullPath}" 应为字符串类型`);
39
+ }
40
+ if (propSchema.enum && !propSchema.enum.includes(value as string)) {
41
+ errors.push(`参数 "${fullPath}" 值不在允许范围内: ${propSchema.enum.join(', ')}`);
42
+ }
43
+ break;
44
+ case 'number':
45
+ case 'integer':
46
+ if (typeof value !== 'number') {
47
+ errors.push(`参数 "${fullPath}" 应为数字类型`);
48
+ }
49
+ break;
50
+ case 'boolean':
51
+ if (typeof value !== 'boolean') {
52
+ errors.push(`参数 "${fullPath}" 应为布尔类型`);
53
+ }
54
+ break;
55
+ case 'array':
56
+ if (!Array.isArray(value)) {
57
+ errors.push(`参数 "${fullPath}" 应为数组类型`);
58
+ } else if (propSchema.items) {
59
+ const itemSchema = propSchema.items;
60
+ for (let i = 0; i < value.length; i++) {
61
+ if (itemSchema.type === 'string' && typeof value[i] !== 'string') {
62
+ errors.push(`参数 "${fullPath}[${i}]" 应为字符串类型`);
63
+ } else if (itemSchema.type === 'number' && typeof value[i] !== 'number') {
64
+ errors.push(`参数 "${fullPath}[${i}]" 应为数字类型`);
65
+ }
66
+ }
67
+ }
68
+ break;
69
+ case 'object':
70
+ if (typeof value !== 'object' || value === null) {
71
+ errors.push(`参数 "${fullPath}" 应为对象类型`);
72
+ } else if (propSchema.properties) {
73
+ checkTypes(value as Record<string, unknown>, propSchema, fullPath, errors);
74
+ }
75
+ break;
76
+ }
77
+ }
78
+ }
79
+
80
+ export class ToolValidator {
81
+ validate(tool: Tool, params: Record<string, unknown>): ToolResult {
82
+ const errors: string[] = [];
83
+ const schema = tool.parameters;
84
+
85
+ checkRequired(params, schema, errors);
86
+ checkTypes(params, schema, '', errors);
87
+
88
+ if (errors.length > 0) {
89
+ return {
90
+ success: false,
91
+ output: '',
92
+ error: `参数验证失败:\n${errors.map(e => ` - ${e}`).join('\n')}`,
93
+ metadata: { validationErrors: errors },
94
+ };
95
+ }
96
+
97
+ return { success: true, output: '参数验证通过' };
98
+ }
99
+
100
+ validateMany(tool: Tool, calls: Record<string, unknown>[]): ToolResult[] {
101
+ return calls.map(params => this.validate(tool, params));
102
+ }
103
+ }
@@ -0,0 +1,76 @@
1
+ import type { Tool } from '../../tool-types.js';
2
+
3
+ export const context_summarize: Tool = {
4
+ name: 'context_summarize',
5
+ description: '对长文本进行摘要',
6
+ category: 'ai',
7
+ parameters: {
8
+ type: 'object',
9
+ properties: {
10
+ text: { type: 'string', description: '要摘要的文本' },
11
+ file_path: { type: 'string', description: '文件路径' },
12
+ max_length: { type: 'number', description: '摘要最大长度(字符)' },
13
+ },
14
+ required: [],
15
+ },
16
+ dangerous: false,
17
+ requiresApproval: false,
18
+ async execute(params) {
19
+ try {
20
+ const text = params.text as string | undefined;
21
+ const filePath = params.file_path as string | undefined;
22
+ const maxLength = (params.max_length as number) ?? 500;
23
+
24
+ let content = '';
25
+ if (filePath) {
26
+ const { readFileSync, existsSync } = await import('node:fs');
27
+ const { resolve } = await import('node:path');
28
+ const abs = resolve(filePath);
29
+ if (!existsSync(abs)) return { success: false, error: `文件不存在: ${abs}`, output: '' };
30
+ content = readFileSync(abs, 'utf-8');
31
+ } else if (text) {
32
+ content = text;
33
+ } else {
34
+ return { success: false, error: '请提供 text 或 file_path 参数', output: '' };
35
+ }
36
+
37
+ const lines = content.split('\n');
38
+ const words = content.split(/\s+/).filter(w => w.length > 0);
39
+ const summary = extractSummary(content, maxLength);
40
+
41
+ const output = [
42
+ `=== 上下文摘要 ===`,
43
+ `原文: ${lines.length} 行, ${words.length} 词, ${content.length} 字符`,
44
+ '',
45
+ summary,
46
+ ].join('\n');
47
+
48
+ return {
49
+ success: true,
50
+ output,
51
+ metadata: { originalLength: content.length, summaryLength: summary.length, lines: lines.length },
52
+ };
53
+ } catch (err: unknown) {
54
+ return { success: false, error: (err as Error).message, output: '' };
55
+ }
56
+ },
57
+ };
58
+
59
+ function extractSummary(text: string, maxLen: number): string {
60
+ const sentences = text.match(/[^.!?\n]+[.!?\n]*/g) || [text];
61
+ const important = sentences
62
+ .filter(s => s.trim().length > 10)
63
+ .slice(0, 10);
64
+
65
+ if (important.join(' ').length <= maxLen) {
66
+ return important.join(' ').trim();
67
+ }
68
+
69
+ let result = important[0];
70
+ for (let i = 1; i < important.length; i++) {
71
+ if (result.length + important[i].length > maxLen) break;
72
+ result += ' ' + important[i];
73
+ }
74
+
75
+ return result.trim() + (result.length < text.length ? '...' : '');
76
+ }
@@ -0,0 +1,86 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { resolve, dirname, join } from 'node:path';
3
+ import type { Tool } from '../../tool-types.js';
4
+
5
+ const MEMORY_DIR = join(process.env.HOME || process.env.USERPROFILE || process.cwd(), '.deepercode', 'memories');
6
+
7
+ export const memory_store: Tool = {
8
+ name: 'memory_store',
9
+ description: '持久化记忆存储',
10
+ category: 'ai',
11
+ parameters: {
12
+ type: 'object',
13
+ properties: {
14
+ action: { type: 'string', description: '操作: set, get, list, delete, search', enum: ['set', 'get', 'list', 'delete', 'search'] },
15
+ key: { type: 'string', description: '记忆键名' },
16
+ value: { type: 'string', description: '记忆值' },
17
+ query: { type: 'string', description: '搜索关键词' },
18
+ },
19
+ required: ['action'],
20
+ },
21
+ dangerous: false,
22
+ requiresApproval: false,
23
+ async execute(params) {
24
+ try {
25
+ const action = params.action as string;
26
+ const key = params.key as string | undefined;
27
+ const value = params.value as string | undefined;
28
+ const query = params.query as string | undefined;
29
+
30
+ if (!existsSync(MEMORY_DIR)) {
31
+ mkdirSync(MEMORY_DIR, { recursive: true });
32
+ }
33
+
34
+ switch (action) {
35
+ case 'set': {
36
+ if (!key || value === undefined) return { success: false, error: 'set 需要 key 和 value 参数', output: '' };
37
+ const memPath = join(MEMORY_DIR, `${key}.json`);
38
+ writeFileSync(memPath, JSON.stringify({ key, value, timestamp: Date.now() }), 'utf-8');
39
+ return { success: true, output: `记忆已保存: ${key}` };
40
+ }
41
+ case 'get': {
42
+ if (!key) return { success: false, error: 'get 需要 key 参数', output: '' };
43
+ const memPath = join(MEMORY_DIR, `${key}.json`);
44
+ if (!existsSync(memPath)) return { success: false, error: `记忆不存在: ${key}`, output: '' };
45
+ const data = JSON.parse(readFileSync(memPath, 'utf-8'));
46
+ return { success: true, output: data.value };
47
+ }
48
+ case 'delete': {
49
+ if (!key) return { success: false, error: 'delete 需要 key 参数', output: '' };
50
+ const memPath = join(MEMORY_DIR, `${key}.json`);
51
+ if (!existsSync(memPath)) return { success: false, error: `记忆不存在: ${key}`, output: '' };
52
+ const { unlinkSync } = await import('node:fs');
53
+ unlinkSync(memPath);
54
+ return { success: true, output: `记忆已删除: ${key}` };
55
+ }
56
+ case 'list': {
57
+ const { readdirSync } = await import('node:fs');
58
+ const files = readdirSync(MEMORY_DIR).filter(f => f.endsWith('.json'));
59
+ const keys = files.map(f => f.replace('.json', ''));
60
+ return {
61
+ success: true,
62
+ output: keys.join('\n') || '(暂无记忆)',
63
+ metadata: { count: keys.length },
64
+ };
65
+ }
66
+ case 'search': {
67
+ if (!query) return { success: false, error: 'search 需要 query 参数', output: '' };
68
+ const { readdirSync } = await import('node:fs');
69
+ const files = readdirSync(MEMORY_DIR).filter(f => f.endsWith('.json'));
70
+ const matches: string[] = [];
71
+ for (const f of files) {
72
+ const data = JSON.parse(readFileSync(join(MEMORY_DIR, f), 'utf-8'));
73
+ if (data.value.includes(query) || data.key.includes(query)) {
74
+ matches.push(`${data.key}: ${data.value.slice(0, 200)}`);
75
+ }
76
+ }
77
+ return { success: true, output: matches.join('\n') || '未找到匹配记忆', metadata: { count: matches.length } };
78
+ }
79
+ default:
80
+ return { success: false, error: `不支持的操作: ${action}`, output: '' };
81
+ }
82
+ } catch (err: unknown) {
83
+ return { success: false, error: (err as Error).message, output: '' };
84
+ }
85
+ },
86
+ };
@@ -0,0 +1,71 @@
1
+ import type { Tool } from '../../tool-types.js';
2
+
3
+ const templates: Record<string, { template: string; description: string }> = {
4
+ 'code-review': {
5
+ description: '代码审查提示',
6
+ template: '请审查以下代码的质量、安全性和可读性,并提供改进建议:\n\n语言: {{language}}\n文件: {{file_path}}\n```\n{{code}}\n```\n\n请关注: 代码风格、潜在 bug、安全问题、性能优化。',
7
+ },
8
+ 'commit-message': {
9
+ description: '生成 Commit 消息',
10
+ template: '基于以下更改生成一个规范的 commit 消息(Conventional Commits 格式):\n\n变更摘要: {{summary}}\n文件变更: {{files}}\n\n类型选择: feat, fix, docs, style, refactor, perf, test, chore, ci',
11
+ },
12
+ 'generate-tests': {
13
+ description: '生成测试用例',
14
+ template: '为以下代码生成完整的测试用例:\n\n语言: {{language}}\n框架: {{framework}}\n\n```\n{{code}}\n```\n\n请覆盖: 正常情况、边界情况、错误情况。',
15
+ },
16
+ 'explain-code': {
17
+ description: '解释代码',
18
+ template: '请详细解释以下代码的功能和实现原理:\n\n语言: {{language}}\n用途: {{purpose}}\n\n```\n{{code}}\n```\n\n请说明: 整体逻辑、关键变量、函数作用、潜在问题。',
19
+ },
20
+ };
21
+
22
+ export const prompt_template: Tool = {
23
+ name: 'prompt_template',
24
+ description: '管理 AI Prompt 模板',
25
+ category: 'ai',
26
+ parameters: {
27
+ type: 'object',
28
+ properties: {
29
+ template: { type: 'string', description: '模板名称', enum: [...Object.keys(templates), 'list'] },
30
+ params: { type: 'object', description: '模板参数' },
31
+ },
32
+ required: ['template'],
33
+ },
34
+ dangerous: false,
35
+ requiresApproval: false,
36
+ async execute(params) {
37
+ try {
38
+ const templateName = params.template as string;
39
+ const templateParams = params.params as Record<string, string> | undefined;
40
+
41
+ if (templateName === 'list') {
42
+ const list = Object.entries(templates).map(([name, t]) => ` ${name}: ${t.description}`);
43
+ return {
44
+ success: true,
45
+ output: `可用模板 (${Object.keys(templates).length}):\n${list.join('\n')}`,
46
+ metadata: { templates: Object.keys(templates) },
47
+ };
48
+ }
49
+
50
+ const tmpl = templates[templateName];
51
+ if (!tmpl) {
52
+ return { success: false, error: `未知模板: ${templateName}`, output: '' };
53
+ }
54
+
55
+ let rendered = tmpl.template;
56
+ if (templateParams) {
57
+ for (const [key, value] of Object.entries(templateParams)) {
58
+ rendered = rendered.replace(new RegExp(`\\{\\{\\s*${key}\\s*\\}\\}`, 'g'), value);
59
+ }
60
+ }
61
+
62
+ return {
63
+ success: true,
64
+ output: rendered,
65
+ metadata: { template: templateName, rendered: !!templateParams },
66
+ };
67
+ } catch (err: unknown) {
68
+ return { success: false, error: (err as Error).message, output: '' };
69
+ }
70
+ },
71
+ };
@@ -0,0 +1,53 @@
1
+ import { mkdirSync, existsSync } from 'node:fs';
2
+ import { writeFile } from 'node:fs/promises';
3
+ import { join, resolve } from 'node:path';
4
+ import { DEEPER_SKILLS_DIR } from '../../../core/constants.js';
5
+ import type { Tool } from '../../../tools/tool-types.js';
6
+
7
+ export const skill_create: Tool = {
8
+ name: 'skill_create',
9
+ description: '创建新 Skill(写入 ~/.deeper/skills/<name>/skill.md)。Skill 会在后续对话中被自动加载和识别。',
10
+ category: 'ai',
11
+ parameters: {
12
+ type: 'object',
13
+ properties: {
14
+ name: { type: 'string', description: 'Skill 名称(英文+连字符,如 "react-expert")' },
15
+ description: { type: 'string', description: 'Skill 用途描述' },
16
+ prompt: { type: 'string', description: 'Skill 的 Markdown 指令内容(包含操作步骤、最佳实践等)' },
17
+ triggers: { type: 'array', items: { type: 'string' }, description: '触发词(如 ["react", "component"])' },
18
+ },
19
+ required: ['name', 'prompt'],
20
+ },
21
+ dangerous: false,
22
+ requiresApproval: false,
23
+ async execute(params) {
24
+ try {
25
+ const name = params.name as string;
26
+ const description = (params.description as string) || `${name} 技能`;
27
+ const prompt = params.prompt as string;
28
+ const triggers = (params.triggers as string[]) || [];
29
+
30
+ const skillDir = join(DEEPER_SKILLS_DIR, name);
31
+ if (!existsSync(skillDir)) mkdirSync(skillDir, { recursive: true });
32
+
33
+ const yaml = [
34
+ `name: ${name}`,
35
+ `description: ${description}`,
36
+ `version: 1.0.0`,
37
+ `author: DeeperCode AI`,
38
+ triggers.length > 0 ? `triggers:\n${triggers.map(t => ` - ${t}`).join('\n')}` : '',
39
+ ].filter(Boolean).join('\n');
40
+
41
+ const md = `---\n${yaml}\n---\n\n${prompt}`;
42
+ await writeFile(join(skillDir, 'skill.md'), md, 'utf-8');
43
+
44
+ return {
45
+ success: true,
46
+ output: `Skill "${name}" 已创建\n 路径: ${skillDir}/skill.md\n 提示: 新对话开始时生效`,
47
+ metadata: { name, description, triggerCount: triggers.length },
48
+ };
49
+ } catch (err: unknown) {
50
+ return { success: false, error: (err as Error).message, output: '' };
51
+ }
52
+ },
53
+ };
@@ -0,0 +1,39 @@
1
+ import type { Tool } from '../../tool-types.js';
2
+
3
+ let subagentRunner: ((task: string, mode: 'foreground' | 'background') => Promise<string>) | null = null;
4
+
5
+ export function setSubagentRunner(fn: (task: string, mode: 'foreground' | 'background') => Promise<string>): void {
6
+ subagentRunner = fn;
7
+ }
8
+
9
+ export const subagent: Tool = {
10
+ name: 'subagent',
11
+ description: '启动子代理处理任务。默认前台模式等待完成返回结果,mode=background 后台执行不阻塞。用于: 代码分析、文件搜索、并行构建、测试运行等。',
12
+ category: 'ai',
13
+ parameters: {
14
+ type: 'object',
15
+ properties: {
16
+ task: { type: 'string', description: '分配给子代理的任务描述' },
17
+ mode: { type: 'string', description: 'foreground(等待完成) 或 background(后台执行)', enum: ['foreground', 'background'] },
18
+ },
19
+ required: ['task'],
20
+ },
21
+ dangerous: false,
22
+ requiresApproval: false,
23
+ async execute(params) {
24
+ const task = params.task as string;
25
+ const mode = (params.mode as string) === 'background' ? 'background' : 'foreground';
26
+ if (!task || task.trim().length < 2) {
27
+ return { success: false, error: '请提供有效的任务描述', output: '' };
28
+ }
29
+ if (subagentRunner) {
30
+ try {
31
+ const result = await subagentRunner(task, mode);
32
+ return { success: true, output: result, metadata: { mode } };
33
+ } catch (e: unknown) {
34
+ return { success: false, error: (e as Error).message, output: '' };
35
+ }
36
+ }
37
+ return { success: false, error: '子代理引擎未初始化', output: '' };
38
+ },
39
+ };