aegiscode 3.1.10 → 3.2.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 (209) hide show
  1. package/bin/aegis-cli-linux-x64 +0 -0
  2. package/bin/cli.js +68 -0
  3. package/package.json +11 -48
  4. package/scripts/download-binary.mjs +155 -0
  5. package/dist/main.js +0 -2171
  6. package/gui/run-gui.cjs +0 -13
  7. package/src/agent/Agent.ts +0 -903
  8. package/src/agent/SimpleAgent.ts +0 -48
  9. package/src/agent/index.ts +0 -54
  10. package/src/agent/orchestrator/AppBuilder.ts +0 -443
  11. package/src/agent/orchestrator/CouncilAgent.ts +0 -310
  12. package/src/agent/orchestrator/DiscussionRoom.ts +0 -462
  13. package/src/agent/orchestrator/OrchestratorAgent.ts +0 -637
  14. package/src/agent/orchestrator/index.ts +0 -38
  15. package/src/agent/orchestrator/utils.ts +0 -397
  16. package/src/agent/pricing.ts +0 -115
  17. package/src/agent/router.ts +0 -74
  18. package/src/agent/routerStats.ts +0 -121
  19. package/src/agent/types.ts +0 -318
  20. package/src/auth/login.ts +0 -383
  21. package/src/cli/config.ts +0 -189
  22. package/src/cli/index.ts +0 -17
  23. package/src/cli/middleware.ts +0 -119
  24. package/src/cli/types.ts +0 -75
  25. package/src/config/ConfigManager.ts +0 -587
  26. package/src/config/index.ts +0 -7
  27. package/src/config/types.ts +0 -584
  28. package/src/context/CompactionService.ts +0 -300
  29. package/src/context/ContextManager.ts +0 -450
  30. package/src/context/FileAnalyzer.ts +0 -267
  31. package/src/context/TokenCounter.ts +0 -265
  32. package/src/context/index.ts +0 -27
  33. package/src/context/storage/CacheStore.ts +0 -176
  34. package/src/context/storage/JSONLStore.ts +0 -201
  35. package/src/context/storage/MemoryStore.ts +0 -205
  36. package/src/context/storage/PersistentStore.ts +0 -327
  37. package/src/context/storage/index.ts +0 -9
  38. package/src/context/storage/pathUtils.ts +0 -114
  39. package/src/context/test.ts +0 -309
  40. package/src/context/types.ts +0 -268
  41. package/src/hooks/HookExecutor.ts +0 -434
  42. package/src/hooks/HookManager.ts +0 -596
  43. package/src/hooks/HookService.ts +0 -269
  44. package/src/hooks/Matcher.ts +0 -157
  45. package/src/hooks/index.ts +0 -63
  46. package/src/hooks/types.ts +0 -424
  47. package/src/main.tsx +0 -596
  48. package/src/mcp/HealthMonitor.ts +0 -150
  49. package/src/mcp/McpClient.ts +0 -491
  50. package/src/mcp/McpRegistry.ts +0 -321
  51. package/src/mcp/createMcpTool.ts +0 -251
  52. package/src/mcp/index.ts +0 -15
  53. package/src/mcp/server.ts +0 -334
  54. package/src/mcp/test-server.ts +0 -88
  55. package/src/mcp/test.ts +0 -372
  56. package/src/mcp/types.ts +0 -247
  57. package/src/memory/AgentMemoryBus.ts +0 -432
  58. package/src/memory/CloudSync.ts +0 -99
  59. package/src/memory/DriveSync.ts +0 -106
  60. package/src/memory/SharedMemory.ts +0 -951
  61. package/src/memory/index.ts +0 -14
  62. package/src/memory/machineFingerprint.ts +0 -40
  63. package/src/orchestrator/SubAgentMetadata.ts +0 -136
  64. package/src/prompts/builder.ts +0 -213
  65. package/src/prompts/default.ts +0 -144
  66. package/src/prompts/index.ts +0 -16
  67. package/src/prompts/plan.ts +0 -64
  68. package/src/prompts/test.ts +0 -78
  69. package/src/services/AnthropicChatService.ts +0 -341
  70. package/src/services/ChatService.ts +0 -347
  71. package/src/services/ClaudeCliChatService.ts +0 -256
  72. package/src/services/CloudSync.ts +0 -168
  73. package/src/services/CostLedger.ts +0 -211
  74. package/src/services/Heartbeat.ts +0 -135
  75. package/src/services/LearningCollector.ts +0 -291
  76. package/src/services/OllamaInstaller.ts +0 -342
  77. package/src/services/VersionChecker.ts +0 -445
  78. package/src/services/index.ts +0 -57
  79. package/src/services/streaming/OpenAIEventAdapter.ts +0 -126
  80. package/src/services/streaming/RenderingProfile.ts +0 -90
  81. package/src/services/streaming/StreamEventParser.ts +0 -181
  82. package/src/services/streaming/ThrottledRenderer.ts +0 -139
  83. package/src/services/streaming/TranscriptBuffer.ts +0 -574
  84. package/src/services/streaming/eventStatusMap.ts +0 -52
  85. package/src/services/streaming/index.ts +0 -46
  86. package/src/services/streaming/renderFormatting.ts +0 -79
  87. package/src/services/streaming/types.ts +0 -234
  88. package/src/skills/SkillLoader.ts +0 -126
  89. package/src/skills/SkillRegistry.ts +0 -366
  90. package/src/skills/index.ts +0 -48
  91. package/src/skills/types.ts +0 -146
  92. package/src/slash-commands/billing.ts +0 -70
  93. package/src/slash-commands/build.ts +0 -413
  94. package/src/slash-commands/builtinCommands.ts +0 -2733
  95. package/src/slash-commands/clone.ts +0 -242
  96. package/src/slash-commands/council.ts +0 -125
  97. package/src/slash-commands/custom/CustomCommandExecutor.ts +0 -143
  98. package/src/slash-commands/custom/CustomCommandLoader.ts +0 -251
  99. package/src/slash-commands/custom/CustomCommandRegistry.ts +0 -144
  100. package/src/slash-commands/custom/index.ts +0 -7
  101. package/src/slash-commands/debate.ts +0 -254
  102. package/src/slash-commands/gmail.ts +0 -105
  103. package/src/slash-commands/index.ts +0 -388
  104. package/src/slash-commands/mcpCommand.ts +0 -205
  105. package/src/slash-commands/types.ts +0 -201
  106. package/src/store/index.ts +0 -76
  107. package/src/store/selectors.ts +0 -246
  108. package/src/store/slices/appSlice.ts +0 -205
  109. package/src/store/slices/commandSlice.ts +0 -115
  110. package/src/store/slices/configSlice.ts +0 -46
  111. package/src/store/slices/focusSlice.ts +0 -64
  112. package/src/store/slices/index.ts +0 -9
  113. package/src/store/slices/sessionSlice.ts +0 -424
  114. package/src/store/streaming-buffer.ts +0 -425
  115. package/src/store/test.ts +0 -296
  116. package/src/store/types.ts +0 -274
  117. package/src/store/vanilla.ts +0 -186
  118. package/src/tools/builtin/bash.ts +0 -236
  119. package/src/tools/builtin/council.ts +0 -105
  120. package/src/tools/builtin/edit.ts +0 -213
  121. package/src/tools/builtin/glob.ts +0 -136
  122. package/src/tools/builtin/grep.ts +0 -263
  123. package/src/tools/builtin/index.ts +0 -61
  124. package/src/tools/builtin/memory.ts +0 -66
  125. package/src/tools/builtin/read.ts +0 -168
  126. package/src/tools/builtin/skill.ts +0 -97
  127. package/src/tools/builtin/snapshot.ts +0 -40
  128. package/src/tools/builtin/task.ts +0 -106
  129. package/src/tools/builtin/write.ts +0 -134
  130. package/src/tools/createTool.ts +0 -221
  131. package/src/tools/execution/ExecutionPipeline.ts +0 -263
  132. package/src/tools/execution/index.ts +0 -40
  133. package/src/tools/execution/stages/CacheStage.ts +0 -131
  134. package/src/tools/execution/stages/ConfirmationStage.ts +0 -203
  135. package/src/tools/execution/stages/DiscoveryStage.ts +0 -46
  136. package/src/tools/execution/stages/ExecutionStage.ts +0 -48
  137. package/src/tools/execution/stages/FormattingStage.ts +0 -44
  138. package/src/tools/execution/stages/HookStage.ts +0 -72
  139. package/src/tools/execution/stages/PermissionStage.ts +0 -287
  140. package/src/tools/execution/stages/PostHookStage.ts +0 -71
  141. package/src/tools/execution/stages/index.ts +0 -12
  142. package/src/tools/execution/test.ts +0 -266
  143. package/src/tools/execution/types.ts +0 -273
  144. package/src/tools/index.ts +0 -81
  145. package/src/tools/registry.ts +0 -304
  146. package/src/tools/schemas.ts +0 -109
  147. package/src/tools/test.ts +0 -220
  148. package/src/tools/types.ts +0 -175
  149. package/src/tools/validation/PermissionChecker.ts +0 -242
  150. package/src/tools/validation/SensitiveFileDetector.ts +0 -210
  151. package/src/tools/validation/index.ts +0 -11
  152. package/src/ui/App.tsx +0 -166
  153. package/src/ui/components/AegisInterface.tsx +0 -484
  154. package/src/ui/components/common/ChatSearch.tsx +0 -150
  155. package/src/ui/components/common/ErrorBoundary.tsx +0 -82
  156. package/src/ui/components/common/ExitMessage.tsx +0 -120
  157. package/src/ui/components/common/LoadingIndicator.tsx +0 -49
  158. package/src/ui/components/common/index.ts +0 -6
  159. package/src/ui/components/dialog/ConfirmationPrompt.tsx +0 -208
  160. package/src/ui/components/dialog/InteractiveSelector.tsx +0 -149
  161. package/src/ui/components/dialog/SetupWizard.tsx +0 -297
  162. package/src/ui/components/dialog/UpdatePrompt.tsx +0 -155
  163. package/src/ui/components/dialog/index.ts +0 -8
  164. package/src/ui/components/index.ts +0 -28
  165. package/src/ui/components/input/CommandSuggestions.tsx +0 -139
  166. package/src/ui/components/input/CustomTextInput.tsx +0 -220
  167. package/src/ui/components/input/InputArea.tsx +0 -361
  168. package/src/ui/components/input/PromptSuggestions.tsx +0 -66
  169. package/src/ui/components/input/index.ts +0 -6
  170. package/src/ui/components/layout/ChatStatusBar.tsx +0 -90
  171. package/src/ui/components/layout/ContextBar.tsx +0 -79
  172. package/src/ui/components/layout/MessageArea.tsx +0 -96
  173. package/src/ui/components/layout/MessageList.tsx +0 -647
  174. package/src/ui/components/layout/MessageSeparator.tsx +0 -26
  175. package/src/ui/components/layout/WelcomeMessage.tsx +0 -93
  176. package/src/ui/components/layout/index.ts +0 -7
  177. package/src/ui/components/markdown/CodeHighlighter.tsx +0 -292
  178. package/src/ui/components/markdown/MessageRenderer.tsx +0 -1211
  179. package/src/ui/components/markdown/index.ts +0 -8
  180. package/src/ui/components/markdown/parser.ts +0 -336
  181. package/src/ui/components/markdown/types.ts +0 -66
  182. package/src/ui/focus/FocusManager.ts +0 -137
  183. package/src/ui/focus/index.ts +0 -13
  184. package/src/ui/focus/types.ts +0 -54
  185. package/src/ui/focus/useFocus.ts +0 -75
  186. package/src/ui/hooks/index.ts +0 -11
  187. package/src/ui/hooks/useAgent.ts +0 -284
  188. package/src/ui/hooks/useCommandHistory.ts +0 -87
  189. package/src/ui/hooks/useCommandProcessor.ts +0 -443
  190. package/src/ui/hooks/useConfirmation.ts +0 -99
  191. package/src/ui/hooks/useCtrlCHandler.ts +0 -100
  192. package/src/ui/hooks/useInputBuffer.ts +0 -122
  193. package/src/ui/hooks/useTerminalSize.ts +0 -68
  194. package/src/ui/hooks/useTerminalWidth.ts +0 -5
  195. package/src/ui/hooks/useWindowedList.ts +0 -118
  196. package/src/ui/render-debugger.ts +0 -621
  197. package/src/ui/test.ts +0 -189
  198. package/src/ui/themes/ThemeManager.ts +0 -332
  199. package/src/ui/themes/aegisTheme.ts +0 -87
  200. package/src/ui/themes/darkTheme.ts +0 -87
  201. package/src/ui/themes/defaultTheme.ts +0 -85
  202. package/src/ui/themes/index.ts +0 -10
  203. package/src/ui/themes/lightTheme.ts +0 -89
  204. package/src/ui/themes/popularThemes.ts +0 -187
  205. package/src/ui/themes/types.ts +0 -130
  206. package/src/utils/clipboard.ts +0 -48
  207. package/src/utils/debug.ts +0 -43
  208. package/src/utils/environment.ts +0 -68
  209. package/src/utils/index.ts +0 -10
@@ -1,66 +0,0 @@
1
- /**
2
- * Memory 工具 - 按需检索共享记
3
- *
4
- * Shared memory is intentionally NOT injected into every turn's system
5
- * prompt by default — auto-injecting semantically-similar past memories
6
- * caused models to recall and repeat their own past mistakes (e.g. a stuck
7
- * session's hallucinated text got stored, then recalled as "context" in
8
- * later sessions, reinforcing itself). Memory is opt-in: the model calls
9
- * this tool only when it decides recalling past conversations would help.
10
- */
11
-
12
- import { z } from 'zod';
13
- import { createTool } from '../createTool.js';
14
- import { ToolKind } from '../types.js';
15
- import { sharedMemory } from '../../memory/SharedMemory.js';
16
-
17
- const MemorySchema = z.object({
18
- query: z.string()
19
- .min(1, 'query 不能为空')
20
- .describe('What to recall — a topic, decision, or past conversation to search for'),
21
- maxEntries: z.number().int().min(1).max(10).optional()
22
- .describe('Maximum number of memory entries to return (default 4)'),
23
- });
24
-
25
- export const memoryTool = createTool({
26
- name: 'Memory',
27
- displayName: 'Recall Memory',
28
- kind: ToolKind.ReadOnly,
29
- schema: MemorySchema,
30
-
31
- description: {
32
- short: 'Recall relevant context from past conversations and sessions',
33
- long: `Searches shared long-term memory for past conversations, decisions, and summaries
34
- relevant to a query. This is opt-in — call it only when recalling prior context would
35
- genuinely help (e.g. "what did we decide about X last time", "have we hit this error before").`,
36
- usageNotes: [
37
- 'Do NOT call this by default at the start of every task — only when past context is actually useful',
38
- 'Treat results as recollections that may be incomplete, outdated, or about a different situation — verify against the current codebase/state before relying on them',
39
- 'Never treat a past assistant message recalled here as proof that something is currently blocked, broken, or unavailable — confirm directly instead',
40
- ],
41
- },
42
-
43
- category: '记忆',
44
- tags: ['memory', 'recall', 'context'],
45
-
46
- execute: async (params, context) => {
47
- const { query, maxEntries } = params;
48
- const result = await sharedMemory.buildContext(query, maxEntries || 4, context?.sessionId);
49
-
50
- if (!result) {
51
- return {
52
- success: true,
53
- llmContent: 'No relevant memory found for this query.',
54
- displayContent: 'No relevant memory found',
55
- };
56
- }
57
-
58
- return {
59
- success: true,
60
- llmContent: result,
61
- displayContent: `Recalled memory for: ${query}`,
62
- };
63
- },
64
- });
65
-
66
- export default memoryTool;
@@ -1,168 +0,0 @@
1
- /**
2
- * Read 工具 - 文件读取
3
- */
4
-
5
- import fs from 'fs/promises';
6
- import path from 'path';
7
- import { z } from 'zod';
8
- import { createTool } from '../createTool.js';
9
- import { ToolKind, ToolErrorType } from '../types.js';
10
-
11
- /**
12
- *
13
- */
14
- const DEFAULT_LINE_LIMIT = 2000;
15
-
16
- /**
17
- * Read 工具 Schema
18
- */
19
- const ReadSchema = z.object({
20
- file_path: z.string()
21
- .min(1, '文件路径不能为空')
22
- .describe('The absolute path to the file to read'),
23
-
24
- offset: z.number()
25
- .int()
26
- .min(0)
27
- .optional()
28
- .describe('The line number to start reading from (0-based)'),
29
-
30
- limit: z.number()
31
- .int()
32
- .min(1)
33
- .max(10000)
34
- .optional()
35
- .describe('The number of lines to read'),
36
- });
37
-
38
- /**
39
- * Read 工具
40
- */
41
- export const readTool = createTool({
42
- name: 'Read',
43
- displayName: 'File Read',
44
- kind: ToolKind.ReadOnly,
45
- schema: ReadSchema,
46
-
47
- description: {
48
- short: 'Reads a file from the local filesystem',
49
- long: `Reads a file from the local filesystem. You can access any file directly by using this tool.
50
- If the User provides a path to a file assume that path is valid.`,
51
- usageNotes: [
52
- 'The file_path parameter must be an absolute path, not a relative path',
53
- `By default, it reads up to ${DEFAULT_LINE_LIMIT} lines starting from the beginning`,
54
- 'You can optionally specify a line offset and limit for long files',
55
- 'Lines in the output are numbered starting at 1',
56
- 'You can call multiple Read tools in parallel to read multiple files at once',
57
- ],
58
- examples: [
59
- {
60
- description: 'Read entire file',
61
- params: { file_path: '/path/to/file.ts' },
62
- },
63
- {
64
- description: 'Read with offset and limit',
65
- params: { file_path: '/path/to/file.ts', offset: 100, limit: 50 },
66
- },
67
- ],
68
- important: [
69
- 'file_path must be an absolute path',
70
- 'Prefer reading the whole file by not providing offset/limit',
71
- ],
72
- },
73
-
74
- category: '文件操作',
75
- tags: ['file', 'read', 'io'],
76
-
77
- async execute(params, context) {
78
- const { file_path, offset = 0, limit } = params;
79
- const effectiveLimit = limit ?? DEFAULT_LINE_LIMIT;
80
-
81
- try {
82
- // 检查文件是否存
83
- try {
84
- await fs.access(file_path);
85
- } catch {
86
- return {
87
- success: false,
88
- llmContent: `File not found: ${file_path}`,
89
- displayContent: `error: file not found: ${file_path}`,
90
- error: {
91
- type: ToolErrorType.EXECUTION_ERROR,
92
- message: 'File not found',
93
- },
94
- };
95
- }
96
-
97
- // 获取文件信
98
- const stat = await fs.stat(file_path);
99
-
100
- // 检查是否为目
101
- if (stat.isDirectory()) {
102
- return {
103
- success: false,
104
- llmContent: `Path is a directory, not a file: ${file_path}`,
105
- displayContent: `error: ${file_path} is a directory`,
106
- error: {
107
- type: ToolErrorType.VALIDATION_ERROR,
108
- message: 'Path is a directory',
109
- },
110
- };
111
- }
112
-
113
- // 读取文件内
114
- const content = await fs.readFile(file_path, 'utf-8');
115
- const lines = content.split('\n');
116
- const totalLines = lines.length;
117
-
118
- // 应用 offset
119
- const selectedLines = lines.slice(offset, offset + effectiveLimit);
120
-
121
- // 格式化输出(带行
122
- const formattedContent = selectedLines
123
- .map((line, i) => {
124
- const lineNum = (offset + i + 1).toString().padStart(6, ' ');
125
- return `${lineNum}|${line}`;
126
- })
127
- .join('\n');
128
-
129
- // 计算是否有更多内
130
- const hasMore = offset + effectiveLimit < totalLines;
131
- const fileName = path.basename(file_path);
132
-
133
- let summary = fileName;
134
- if (offset > 0 || limit) {
135
- summary += ` lines ${offset + 1}–${Math.min(offset + effectiveLimit, totalLines)} of ${totalLines}`;
136
- } else {
137
- summary += ` ${totalLines} lines`;
138
- }
139
- if (hasMore) {
140
- summary += ` ···`;
141
- }
142
-
143
- return {
144
- success: true,
145
- llmContent: formattedContent,
146
- displayContent: summary,
147
- metadata: {
148
- file_path,
149
- total_lines: totalLines,
150
- lines_read: selectedLines.length,
151
- offset,
152
- has_more: hasMore,
153
- },
154
- };
155
- } catch (error) {
156
- const errorMessage = error instanceof Error ? error.message : 'unknown error';
157
- return {
158
- success: false,
159
- llmContent: `Failed to read file: ${errorMessage}`,
160
- displayContent: `error: ${errorMessage}`,
161
- error: {
162
- type: ToolErrorType.EXECUTION_ERROR,
163
- message: errorMessage,
164
- },
165
- };
166
- }
167
- },
168
- });
@@ -1,97 +0,0 @@
1
- /**
2
- * Skill 工具
3
- *
4
- *
5
- *
6
- */
7
-
8
- import { z } from 'zod';
9
- import { createTool } from '../createTool.js';
10
- import { ToolKind } from '../types.js';
11
- import { getSkillRegistry } from '../../skills/index.js';
12
-
13
- /**
14
- * Skill 工具参数 Schema
15
- */
16
- const SkillSchema = z.object({
17
- skill: z.string().describe('The name of the skill to load'),
18
- args: z.string().optional().describe('Optional arguments to pass to the skill'),
19
- });
20
-
21
- /**
22
- * Skill 工具
23
- *
24
- *
25
- *
26
- */
27
- export const skillTool = createTool({
28
- name: 'Skill',
29
- displayName: 'Load Skill',
30
- kind: ToolKind.ReadOnly,
31
- schema: SkillSchema,
32
-
33
- description: {
34
- short: 'Load a skill to get specialized instructions',
35
- long: `Load a skill to get specialized instructions for a task.
36
-
37
- Use this tool when:
38
- - You need specific guidance for a task that matches an available skill
39
- - The user explicitly requests to use a skill
40
- - You want to follow best practices defined in a skill
41
-
42
- The skill's instructions will be returned and you should follow them.`,
43
- },
44
-
45
- execute: async ({ skill, args }) => {
46
- const registry = getSkillRegistry();
47
-
48
- // 检查 Skill 是否存
49
- if (!registry.hasSkill(skill)) {
50
- const allSkills = registry.getAllSkills();
51
- const availableNames = allSkills.map(s => s.name).join(', ');
52
- const errorMsg = `Skill "${skill}" not found. Available skills: ${availableNames || 'none'}`;
53
-
54
- return {
55
- success: false,
56
- llmContent: errorMsg,
57
- displayContent: errorMsg,
58
- };
59
- }
60
-
61
- // 加载完整内
62
- const content = await registry.loadContent(skill);
63
-
64
- if (!content) {
65
- const errorMsg = `Failed to load skill "${skill}"`;
66
- return {
67
- success: false,
68
- llmContent: errorMsg,
69
- displayContent: errorMsg,
70
- };
71
- }
72
-
73
- // 构建返回内
74
- let result = `## Skill: ${content.metadata.name}\n\n`;
75
-
76
- // 如果有工具限制,提
77
- if (content.metadata.allowedTools && content.metadata.allowedTools.length > 0) {
78
- result += `**Allowed tools for this skill:** ${content.metadata.allowedTools.join(', ')}\n\n`;
79
- }
80
-
81
- // 添加指令内
82
- result += content.instructions;
83
-
84
- // 如果有参数,添加到末
85
- if (args) {
86
- result += `\n\n## Arguments\n\n${args}`;
87
- }
88
-
89
- return {
90
- success: true,
91
- llmContent: result,
92
- displayContent: `✓ Loaded skill: ${content.metadata.name}`,
93
- };
94
- },
95
- });
96
-
97
- export default skillTool;
@@ -1,40 +0,0 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- import os from 'os';
4
-
5
- const SNAPSHOTS_DIR = path.join(os.homedir(), '.aegiscode', 'snapshots');
6
- const MAX_SNAPSHOTS = 50;
7
-
8
- export async function createSnapshot(filePath: string): Promise<string | null> {
9
- try {
10
- await fs.mkdir(SNAPSHOTS_DIR, { recursive: true });
11
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
12
- const basename = path.basename(filePath);
13
- const snapshotPath = path.join(SNAPSHOTS_DIR, `${timestamp}_${basename}.bak`);
14
- await fs.copyFile(filePath, snapshotPath);
15
- await pruneSnapshots();
16
- return snapshotPath;
17
- } catch {
18
- return null;
19
- }
20
- }
21
-
22
- async function pruneSnapshots(): Promise<void> {
23
- try {
24
- const entries = await fs.readdir(SNAPSHOTS_DIR);
25
- if (entries.length <= MAX_SNAPSHOTS) return;
26
- const files = await Promise.all(
27
- entries.map(async (name) => {
28
- const p = path.join(SNAPSHOTS_DIR, name);
29
- const stat = await fs.stat(p);
30
- return { path: p, mtime: stat.mtime.getTime() };
31
- })
32
- );
33
- files.sort((a, b) => a.mtime - b.mtime);
34
- await Promise.all(
35
- files.slice(0, files.length - MAX_SNAPSHOTS).map(f => fs.unlink(f.path))
36
- );
37
- } catch {
38
- // ignore prune errors
39
- }
40
- }
@@ -1,106 +0,0 @@
1
- /**
2
- * Task tool — lets the running agent delegate read-only investigation
3
- * work to parallel sub-agents, mid-conversation, without the user typing
4
- * a slash command. Same machinery as /multi, restricted to Read/Grep/Glob
5
- * (see plan: no confirmationHandler reaches a tool's execute(), so only
6
- * ReadOnly-kind work is safe to trigger from inside a tool call).
7
- */
8
-
9
- import { z } from 'zod';
10
- import { createTool } from '../createTool.js';
11
- import { ToolKind } from '../types.js';
12
- import { OrchestratorAgent, type SubAgentConfig } from '../../agent/orchestrator/OrchestratorAgent.js';
13
- import { requireModelConfig, buildSourceContext } from '../../agent/orchestrator/utils.js';
14
-
15
- const TaskSchema = z.object({
16
- tasks: z.array(z.object({
17
- description: z.string().describe('Short label for this investigation, e.g. "find auth bugs"'),
18
- prompt: z.string().describe('Detailed instructions for the sub-agent'),
19
- })).min(1).max(5).describe('One or more independent investigations to run in parallel'),
20
- });
21
-
22
- export const taskTool = createTool({
23
- name: 'Task',
24
- displayName: 'Delegate Task',
25
- kind: ToolKind.ReadOnly,
26
- schema: TaskSchema,
27
-
28
- description: {
29
- short: 'Delegate read-only investigation work to parallel sub-agents',
30
- long: `Spin up one or more read-only sub-agents (Read/Grep/Glob only) to investigate
31
- the codebase in parallel, then return their findings.
32
-
33
- Use this when:
34
- - A question has multiple independent angles worth exploring at once
35
- - You want a focused sub-agent to dig into one area without cluttering the main conversation
36
-
37
- Sub-agents cannot write files or run commands — they only read and report back.
38
- You're responsible for synthesizing their findings into your final answer.`,
39
- },
40
-
41
- execute: async ({ tasks }, context) => {
42
- let modelConfig;
43
- try {
44
- modelConfig = requireModelConfig();
45
- } catch (e) {
46
- const msg = (e as Error).message;
47
- return { success: false, llmContent: msg, displayContent: msg };
48
- }
49
-
50
- const agentConfig = {
51
- apiKey: modelConfig.apiKey,
52
- baseURL: modelConfig.baseURL,
53
- model: modelConfig.model,
54
- timeout: modelConfig.timeout,
55
- };
56
-
57
- const cwd = context?.cwd || process.cwd();
58
- const sourceCtx = buildSourceContext(cwd);
59
- const codeContext = sourceCtx
60
- ? `\n\nWorkspace context (project metadata + file tree + structure summaries + git changes):\n${sourceCtx}\n\nUse Read / Grep / Glob to examine these.`
61
- : '\n\nUse Read / Grep / Glob to explore the codebase before responding.';
62
-
63
- const orchestrator = new OrchestratorAgent(
64
- 'Task-Orchestrator',
65
- 'You coordinate read-only investigation sub-agents.',
66
- );
67
-
68
- tasks.forEach((task, i) => {
69
- const agentCfg: SubAgentConfig = {
70
- name: `agent-${i}`,
71
- role: 'Investigator',
72
- systemPrompt: `You are a focused investigation sub-agent. ${task.prompt}${codeContext}`,
73
- config: agentConfig,
74
- tools: ['Read', 'Grep', 'Glob'],
75
- };
76
- orchestrator.registerAgent(agentCfg);
77
- });
78
-
79
- try {
80
- const responses = await orchestrator.delegateParallel(
81
- tasks.map((task, i) => ({ agentName: `agent-${i}`, task: task.prompt })),
82
- tasks.length,
83
- context?.sessionId,
84
- );
85
-
86
- const lines: string[] = [];
87
- responses.forEach((res, i) => {
88
- lines.push(`### ${tasks[i]?.description || res.agentName}`);
89
- lines.push(res.content || '*No response*');
90
- lines.push('');
91
- });
92
-
93
- const formatted = lines.join('\n').trim();
94
- return {
95
- success: true,
96
- llmContent: formatted,
97
- displayContent: `✓ Ran ${tasks.length} investigation${tasks.length > 1 ? 's' : ''} in parallel`,
98
- };
99
- } catch (e) {
100
- const msg = `Task delegation failed: ${(e as Error).message}`;
101
- return { success: false, llmContent: msg, displayContent: msg };
102
- }
103
- },
104
- });
105
-
106
- export default taskTool;
@@ -1,134 +0,0 @@
1
- /**
2
- * Write 工具
3
- *
4
- *
5
- */
6
-
7
- import fs from 'fs/promises';
8
- import path from 'path';
9
- import { z } from 'zod';
10
- import { createTool } from '../createTool.js';
11
- import { ToolKind, ToolErrorType } from '../types.js';
12
- import { createSnapshot } from './snapshot.js';
13
-
14
- // ========== Schema 定
15
-
16
- const WriteSchema = z.object({
17
- file_path: z.string()
18
- .min(1, '文件路径不能为空')
19
- .describe('The absolute path to the file to write'),
20
- contents: z.string()
21
- .describe('The contents to write to the file'),
22
- });
23
-
24
- // ========== Write 工
25
-
26
- export const writeTool = createTool({
27
- name: 'Write',
28
- displayName: 'File Write',
29
- kind: ToolKind.Write,
30
- schema: WriteSchema,
31
-
32
- description: {
33
- short: 'Writes a file to the local filesystem',
34
- long: 'Creates a new file or overwrites an existing file with the specified contents.',
35
- usageNotes: [
36
- 'This tool will overwrite the existing file if there is one at the provided path',
37
- 'ALWAYS prefer editing existing files in the codebase using Edit tool',
38
- 'NEVER write new files unless explicitly required',
39
- 'NEVER proactively create documentation files (*.md) or README files',
40
- 'Parent directories will be created automatically if they do not exist',
41
- ],
42
- examples: [
43
- {
44
- description: 'Create a new TypeScript file',
45
- params: {
46
- file_path: '/path/to/new-file.ts',
47
- contents: 'export const hello = "world";',
48
- },
49
- },
50
- ],
51
- important: [
52
- 'Only create files that are absolutely necessary',
53
- 'Do not create README or documentation files unless explicitly requested',
54
- ],
55
- },
56
-
57
- category: '文件操作',
58
- tags: ['file', 'io', 'write', 'create'],
59
-
60
- // 提取签名内容(用于权限规
61
- extractSignatureContent: (params: unknown) => {
62
- const p = params as { file_path: string };
63
- return p.file_path;
64
- },
65
-
66
- // 抽象权限规
67
- abstractPermissionRule: (params: unknown) => {
68
- const p = params as { file_path: string };
69
- const dir = path.dirname(p.file_path);
70
- return `Write:${dir}/*`;
71
- },
72
-
73
- async execute(params, context) {
74
- const { file_path, contents } = params;
75
-
76
- try {
77
- // 1. 检查目标是否是目
78
- try {
79
- const stat = await fs.stat(file_path);
80
- if (stat.isDirectory()) {
81
- return {
82
- success: false,
83
- llmContent: `Error: ${file_path} is a directory, cannot write to it`,
84
- displayContent: `error: ${file_path} is a directory`,
85
- error: {
86
- type: ToolErrorType.VALIDATION_ERROR,
87
- message: 'Path is a directory',
88
- },
89
- };
90
- }
91
- } catch {
92
- // 文件不存在,这是允许
93
- }
94
-
95
- // 2. 确保父目录存
96
- const dir = path.dirname(file_path);
97
- await fs.mkdir(dir, { recursive: true });
98
-
99
- // 3. 快照原始文件(如果已存在)
100
- let snapshotPath: string | null = null;
101
- try { await fs.access(file_path); snapshotPath = await createSnapshot(file_path); } catch { /* new file */ }
102
-
103
- // 4. 写入文
104
- await fs.writeFile(file_path, contents, 'utf8');
105
-
106
- // 5. 计算写入信
107
- const lines = contents.split('\n').length;
108
- const bytes = Buffer.byteLength(contents, 'utf8');
109
-
110
- return {
111
- success: true,
112
- llmContent: `Successfully wrote to ${file_path} (${lines} lines, ${bytes} bytes)`,
113
- displayContent: `${path.basename(file_path)} ${lines} lines`,
114
- metadata: {
115
- file_path,
116
- lines,
117
- bytes,
118
- snapshot: snapshotPath,
119
- },
120
- };
121
- } catch (error) {
122
- const errorMessage = error instanceof Error ? error.message : 'unknown error';
123
- return {
124
- success: false,
125
- llmContent: `Error writing file: ${errorMessage}`,
126
- displayContent: `error: ${errorMessage}`,
127
- error: {
128
- type: ToolErrorType.EXECUTION_ERROR,
129
- message: errorMessage,
130
- },
131
- };
132
- }
133
- },
134
- });