@xagent-ai/cli 1.2.0 → 1.2.2

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 (80) hide show
  1. package/README.md +1 -1
  2. package/README_CN.md +1 -1
  3. package/dist/agents.js +164 -164
  4. package/dist/agents.js.map +1 -1
  5. package/dist/ai-client.d.ts +4 -6
  6. package/dist/ai-client.d.ts.map +1 -1
  7. package/dist/ai-client.js +137 -115
  8. package/dist/ai-client.js.map +1 -1
  9. package/dist/auth.js +4 -4
  10. package/dist/auth.js.map +1 -1
  11. package/dist/cli.js +184 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/config.js +3 -3
  14. package/dist/config.js.map +1 -1
  15. package/dist/context-compressor.d.ts.map +1 -1
  16. package/dist/context-compressor.js +65 -81
  17. package/dist/context-compressor.js.map +1 -1
  18. package/dist/conversation.d.ts +1 -1
  19. package/dist/conversation.d.ts.map +1 -1
  20. package/dist/conversation.js +5 -31
  21. package/dist/conversation.js.map +1 -1
  22. package/dist/memory.d.ts +5 -1
  23. package/dist/memory.d.ts.map +1 -1
  24. package/dist/memory.js +77 -37
  25. package/dist/memory.js.map +1 -1
  26. package/dist/remote-ai-client.d.ts +1 -8
  27. package/dist/remote-ai-client.d.ts.map +1 -1
  28. package/dist/remote-ai-client.js +55 -65
  29. package/dist/remote-ai-client.js.map +1 -1
  30. package/dist/retry.d.ts +35 -0
  31. package/dist/retry.d.ts.map +1 -0
  32. package/dist/retry.js +166 -0
  33. package/dist/retry.js.map +1 -0
  34. package/dist/session.d.ts +0 -5
  35. package/dist/session.d.ts.map +1 -1
  36. package/dist/session.js +243 -312
  37. package/dist/session.js.map +1 -1
  38. package/dist/slash-commands.d.ts +1 -0
  39. package/dist/slash-commands.d.ts.map +1 -1
  40. package/dist/slash-commands.js +91 -9
  41. package/dist/slash-commands.js.map +1 -1
  42. package/dist/smart-approval.d.ts.map +1 -1
  43. package/dist/smart-approval.js +18 -17
  44. package/dist/smart-approval.js.map +1 -1
  45. package/dist/system-prompt-generator.d.ts.map +1 -1
  46. package/dist/system-prompt-generator.js +149 -139
  47. package/dist/system-prompt-generator.js.map +1 -1
  48. package/dist/theme.d.ts +48 -0
  49. package/dist/theme.d.ts.map +1 -1
  50. package/dist/theme.js +254 -0
  51. package/dist/theme.js.map +1 -1
  52. package/dist/tools/edit-diff.d.ts +32 -0
  53. package/dist/tools/edit-diff.d.ts.map +1 -0
  54. package/dist/tools/edit-diff.js +185 -0
  55. package/dist/tools/edit-diff.js.map +1 -0
  56. package/dist/tools/edit.d.ts +11 -0
  57. package/dist/tools/edit.d.ts.map +1 -0
  58. package/dist/tools/edit.js +129 -0
  59. package/dist/tools/edit.js.map +1 -0
  60. package/dist/tools.d.ts +19 -5
  61. package/dist/tools.d.ts.map +1 -1
  62. package/dist/tools.js +979 -631
  63. package/dist/tools.js.map +1 -1
  64. package/dist/types.d.ts +6 -31
  65. package/dist/types.d.ts.map +1 -1
  66. package/package.json +3 -2
  67. package/src/agents.ts +504 -504
  68. package/src/ai-client.ts +1559 -1458
  69. package/src/auth.ts +4 -4
  70. package/src/cli.ts +195 -1
  71. package/src/config.ts +3 -3
  72. package/src/memory.ts +55 -14
  73. package/src/remote-ai-client.ts +663 -683
  74. package/src/retry.ts +217 -0
  75. package/src/session.ts +1736 -1840
  76. package/src/slash-commands.ts +98 -9
  77. package/src/smart-approval.ts +626 -625
  78. package/src/system-prompt-generator.ts +853 -843
  79. package/src/theme.ts +284 -0
  80. package/src/tools.ts +390 -70
package/dist/tools.js CHANGED
@@ -35,34 +35,34 @@ const execAsync = promisify(exec);
35
35
  //
36
36
  export class ReadTool {
37
37
  name = 'Read';
38
- description = `Read the contents of a file. This is your PRIMARY tool for understanding existing code, configuration, and documentation.
39
-
40
- # When to Use
41
- - When you need to understand existing code before making changes
42
- - When user asks you to "read", "show", "view", or "check" a file
43
- - When debugging and need to inspect source files
44
- - When analyzing project structure by reading key files
45
- - When examining configuration files (package.json, tsconfig.json, etc.)
46
- - When checking documentation or README files
47
-
48
- # When NOT to Use
49
- - For files you've already read in the same conversation (use memory instead)
50
- - When you only need file metadata (use ListDirectory or Bash with ls instead)
51
- - For binary files that cannot be read as text
52
-
53
- # Parameters
54
- - \`filePath\`: Absolute path or path relative to project root
55
- - \`offset\`: (Optional) Line number to start reading from (0-based)
56
- - \`limit\`: (Optional) Maximum number of lines to read
57
-
58
- # Examples
59
- - Read specific file: Read(filePath="/path/to/file.ts")
60
- - Read with pagination: Read(filePath="src/app.ts", offset=0, limit=100)
61
-
62
- # Best Practices
63
- - Use absolute paths or paths relative to the project root
64
- - Use offset and limit for large files to avoid loading entire content
65
- - Combine with ListDirectory to explore project structure first
38
+ description = `Read the contents of a file. This is your PRIMARY tool for understanding existing code, configuration, and documentation.
39
+
40
+ # When to Use
41
+ - When you need to understand existing code before making changes
42
+ - When user asks you to "read", "show", "view", or "check" a file
43
+ - When debugging and need to inspect source files
44
+ - When analyzing project structure by reading key files
45
+ - When examining configuration files (package.json, tsconfig.json, etc.)
46
+ - When checking documentation or README files
47
+
48
+ # When NOT to Use
49
+ - For files you've already read in the same conversation (use memory instead)
50
+ - When you only need file metadata (use ListDirectory or Bash with ls instead)
51
+ - For binary files that cannot be read as text
52
+
53
+ # Parameters
54
+ - \`filePath\`: Absolute path or path relative to project root
55
+ - \`offset\`: (Optional) Line number to start reading from (0-based)
56
+ - \`limit\`: (Optional) Maximum number of lines to read
57
+
58
+ # Examples
59
+ - Read specific file: Read(filePath="/path/to/file.ts")
60
+ - Read with pagination: Read(filePath="src/app.ts", offset=0, limit=100)
61
+
62
+ # Best Practices
63
+ - Use absolute paths or paths relative to the project root
64
+ - Use offset and limit for large files to avoid loading entire content
65
+ - Combine with ListDirectory to explore project structure first
66
66
  - Don't re-read files unnecessarily`;
67
67
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
68
68
  async execute(params) {
@@ -104,32 +104,32 @@ export class ReadTool {
104
104
  }
105
105
  export class WriteTool {
106
106
  name = 'Write';
107
- description = `Create a new file or completely overwrite an existing file with new content.
108
-
109
- # When to Use
110
- - Creating new files (source code, configuration, documentation)
111
- - Completely replacing file content (not partial edits)
112
- - Generating files from templates or scratch
113
- - When user explicitly asks to "create", "write", or "generate" a file
114
-
115
- # When NOT to Use
116
- - For making small edits to existing files (use Replace instead)
117
- - When you only need to append content (read file first, then write)
118
- - For creating directories (use CreateDirectory instead)
119
-
120
- # Parameters
121
- - \`filePath\`: Absolute path or path relative to project root
122
- - \`content\`: The complete content to write to the file
123
-
124
- # Examples
125
- - Create new file: Write(filePath="src/utils.ts", content="...")
126
- - Create config file: Write(filePath=".env.example", content="API_KEY=...")
127
-
128
- # Best Practices
129
- - Parent directories are created automatically
130
- - Use appropriate file extensions
131
- - Ensure content is complete and syntactically correct
132
- - For partial edits, use Replace tool instead`;
107
+ description = `Create a new file or completely overwrite an existing file with new content.
108
+
109
+ # When to Use
110
+ - Creating new files (source code, configuration, documentation)
111
+ - Completely replacing file content (not partial edits)
112
+ - Generating files from templates or scratch
113
+ - When user explicitly asks to "create", "write", or "generate" a file
114
+
115
+ # When NOT to Use
116
+ - For making small edits to existing files (use edit instead)
117
+ - When you only need to append content (read file first, then write)
118
+ - For creating directories (use CreateDirectory instead)
119
+
120
+ # Parameters
121
+ - \`filePath\`: Absolute path or path relative to project root
122
+ - \`content\`: The complete content to write to the file
123
+
124
+ # Examples
125
+ - Create new file: Write(filePath="src/utils.ts", content="...")
126
+ - Create config file: Write(filePath=".env.example", content="API_KEY=...")
127
+
128
+ # Best Practices
129
+ - Parent directories are created automatically
130
+ - Use appropriate file extensions
131
+ - Ensure content is complete and syntactically correct
132
+ - For partial edits, use Edit tool instead`;
133
133
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
134
134
  async execute(params) {
135
135
  const { filePath, content } = params;
@@ -138,9 +138,15 @@ export class WriteTool {
138
138
  const dir = path.dirname(absolutePath);
139
139
  await fs.mkdir(dir, { recursive: true });
140
140
  await fs.writeFile(absolutePath, content, 'utf-8');
141
+ const lineCount = content.split('\n').length;
142
+ const preview = content.split('\n').slice(0, 10).join('\n');
143
+ const isTruncated = lineCount > 10;
141
144
  return {
142
145
  success: true,
143
- message: `Successfully wrote to ${filePath}`
146
+ message: `Successfully wrote to ${filePath}`,
147
+ filePath,
148
+ lineCount,
149
+ preview: isTruncated ? preview + '\n...' : preview
144
150
  };
145
151
  }
146
152
  catch (error) {
@@ -150,39 +156,39 @@ export class WriteTool {
150
156
  }
151
157
  export class GrepTool {
152
158
  name = 'Grep';
153
- description = `Search for text patterns within files using regex or literal string matching. This is your PRIMARY tool for finding specific code, functions, or content.
154
-
155
- # When to Use
156
- - Finding specific function definitions or calls
157
- - Searching for variable usages or imports
158
- - Locating error messages or log statements
159
- - Finding all occurrences of a pattern across the codebase
160
- - When you need line-by-line results with context
161
-
162
- # When NOT to Use
163
- - When you only need to find files containing text (use SearchCodebase instead)
164
- - When searching by file pattern rather than content (use SearchCodebase)
165
- - For very large codebases where you only need file names (SearchCodebase is faster)
166
-
167
- # Parameters
168
- - \`pattern\`: Regex or literal string to search for
169
- - \`path\`: (Optional) Directory to search in, default: "."
170
- - \`include\`: (Optional) File glob pattern to include
171
- - \`exclude\`: (Optional) File glob pattern to exclude
172
- - \`case_sensitive\`: (Optional) Case-sensitive search, default: false
173
- - \`fixed_strings\`: (Optional) Treat pattern as literal string, default: false
174
- - \`context\`: (Optional) Lines of context before/after matches
175
- - \`no_ignore\`: (Optional) Don't ignore node_modules/.git, default: false
176
-
177
- # Examples
178
- - Find function: Grep(pattern="function myFunction")
179
- - Find with context: Grep(pattern="TODO", context=3)
180
- - TypeScript only: Grep(pattern="interface", include="*.ts")
181
-
182
- # Best Practices
183
- - Use case_sensitive=true for short patterns to reduce false positives
184
- - Use fixed_strings=true if your pattern has special regex characters
185
- - Use context to see the surrounding code for each match
159
+ description = `Search for text patterns within files using regex or literal string matching. This is your PRIMARY tool for finding specific code, functions, or content.
160
+
161
+ # When to Use
162
+ - Finding specific function definitions or calls
163
+ - Searching for variable usages or imports
164
+ - Locating error messages or log statements
165
+ - Finding all occurrences of a pattern across the codebase
166
+ - When you need line-by-line results with context
167
+
168
+ # When NOT to Use
169
+ - When you only need to find files containing text (use SearchFiles instead)
170
+ - When searching by file pattern rather than content (use SearchFiles)
171
+ - For very large codebases where you only need file names (SearchFiles is faster)
172
+
173
+ # Parameters
174
+ - \`pattern\`: Regex or literal string to search for
175
+ - \`path\`: (Optional) Directory to search in, default: "."
176
+ - \`include\`: (Optional) File glob pattern to include
177
+ - \`exclude\`: (Optional) File glob pattern to exclude
178
+ - \`case_sensitive\`: (Optional) Case-sensitive search, default: false
179
+ - \`fixed_strings\`: (Optional) Treat pattern as literal string, default: false
180
+ - \`context\`: (Optional) Lines of context before/after matches
181
+ - \`no_ignore\`: (Optional) Don't ignore node_modules/.git, default: false
182
+
183
+ # Examples
184
+ - Find function: Grep(pattern="function myFunction")
185
+ - Find with context: Grep(pattern="TODO", context=3)
186
+ - TypeScript only: Grep(pattern="interface", include="*.ts")
187
+
188
+ # Best Practices
189
+ - Use case_sensitive=true for short patterns to reduce false positives
190
+ - Use fixed_strings=true if your pattern has special regex characters
191
+ - Use context to see the surrounding code for each match
186
192
  - Combine with include/exclude to narrow down file types`;
187
193
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
188
194
  async execute(params) {
@@ -258,40 +264,40 @@ export class GrepTool {
258
264
  }
259
265
  export class BashTool {
260
266
  name = 'Bash';
261
- description = `Execute shell commands in the terminal. This is your PRIMARY tool for running commands, scripts, and system operations.
262
-
263
- # When to Use
264
- - Running build commands (npm run build, tsc, etc.)
265
- - Installing dependencies (npm install, pip install, etc.)
266
- - Running tests (npm test, pytest, etc.)
267
- - Git operations (git commit, git push, etc.)
268
- - Running linters or formatters
269
- - Any command-line operations
270
-
271
- # When NOT to Use
272
- - For file operations (use Read/Write/Replace/CreateDirectory instead)
273
- - For searching file content (use Grep instead)
274
- - For finding files (use SearchCodebase or ListDirectory instead)
275
- - For commands that require user interaction (non-interactive only)
276
- - For dangerous commands without understanding the impact
277
-
278
- # Parameters
279
- - \`command\`: The shell command to execute
280
- - \`cwd\`: (Optional) Working directory for the command
281
- - \`description\`: (Optional) Description of what the command does
282
- - \`timeout\`: (Optional) Timeout in seconds, default: 120
283
- - \`run_in_bg\`: (Optional) Run in background, default: false
284
-
285
- # Examples
286
- - Install dependencies: Bash(command="npm install", description="Install npm dependencies")
287
- - Run tests: Bash(command="npm test", description="Run unit tests")
288
- - Build project: Bash(command="npm run build", description="Build the project")
289
-
290
- # Best Practices
291
- - Always provide a description for context
292
- - Set appropriate timeout for long-running commands
293
- - Use run_in_bg=true for commands that take a long time
294
- - Check the command is safe before executing
267
+ description = `Execute shell commands in the terminal. This is your PRIMARY tool for running commands, scripts, and system operations.
268
+
269
+ # When to Use
270
+ - Running build commands (npm run build, tsc, etc.)
271
+ - Installing dependencies (npm install, pip install, etc.)
272
+ - Running tests (npm test, pytest, etc.)
273
+ - Git operations (git commit, git push, etc.)
274
+ - Running linters or formatters
275
+ - Any command-line operations
276
+
277
+ # When NOT to Use
278
+ - For file operations (use Read/Write/Edit/CreateDirectory instead)
279
+ - For searching file content (use Grep instead)
280
+ - For finding files (use SearchFiles or ListDirectory instead)
281
+ - For commands that require user interaction (non-interactive only)
282
+ - For dangerous commands without understanding the impact
283
+
284
+ # Parameters
285
+ - \`command\`: The shell command to execute
286
+ - \`cwd\`: (Optional) Working directory for the command
287
+ - \`description\`: (Optional) Description of what the command does
288
+ - \`timeout\`: (Optional) Timeout in seconds, default: 120
289
+ - \`run_in_bg\`: (Optional) Run in background, default: false
290
+
291
+ # Examples
292
+ - Install dependencies: Bash(command="npm install", description="Install npm dependencies")
293
+ - Run tests: Bash(command="npm test", description="Run unit tests")
294
+ - Build project: Bash(command="npm run build", description="Build the project")
295
+
296
+ # Best Practices
297
+ - Always provide a description for context
298
+ - Set appropriate timeout for long-running commands
299
+ - Use run_in_bg=true for commands that take a long time
300
+ - Check the command is safe before executing
295
301
  - Use absolute paths or paths relative to project root`;
296
302
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
297
303
  async execute(params) {
@@ -382,33 +388,33 @@ export class BashTool {
382
388
  }
383
389
  export class ListDirectoryTool {
384
390
  name = 'ListDirectory';
385
- description = `List files and directories in a path. This is your PRIMARY tool for exploring project structure.
386
-
387
- # When to Use
388
- - Exploring project structure and organization
389
- - Finding what files exist in a directory
390
- - Getting an overview of the codebase layout
391
- - When user asks to "list files" or "show directory contents"
392
- - Navigating through project directories
393
-
394
- # When NOT to Use
395
- - When you need to read file contents (use Read instead)
396
- - For recursive exploration of entire codebase (use recursive=true)
397
- - When you need to search for specific files (use SearchCodebase instead)
398
-
399
- # Parameters
400
- - \`path\`: (Optional) Directory path, default: "."
401
- - \`recursive\`: (Optional) List recursively, default: false
402
-
403
- # Examples
404
- - List current directory: ListDirectory(path=".")
405
- - List src directory: ListDirectory(path="src")
406
- - List all files recursively: ListDirectory(path=".", recursive=true)
407
-
408
- # Best Practices
409
- - Use recursive=true to see entire subtree
410
- - Results are absolute paths
411
- - Ignores node_modules and .git by default
391
+ description = `List files and directories in a path. This is your PRIMARY tool for exploring project structure.
392
+
393
+ # When to Use
394
+ - Exploring project structure and organization
395
+ - Finding what files exist in a directory
396
+ - Getting an overview of the codebase layout
397
+ - When user asks to "list files" or "show directory contents"
398
+ - Navigating through project directories
399
+
400
+ # When NOT to Use
401
+ - When you need to read file contents (use Read instead)
402
+ - For recursive exploration of entire codebase (use recursive=true)
403
+ - When you need to search for specific files (use SearchFiles instead)
404
+
405
+ # Parameters
406
+ - \`path\`: (Optional) Directory path, default: "."
407
+ - \`recursive\`: (Optional) List recursively, default: false
408
+
409
+ # Examples
410
+ - List current directory: ListDirectory(path=".")
411
+ - List src directory: ListDirectory(path="src")
412
+ - List all files recursively: ListDirectory(path=".", recursive=true)
413
+
414
+ # Best Practices
415
+ - Use recursive=true to see entire subtree
416
+ - Results are absolute paths
417
+ - Ignores node_modules and .git by default
412
418
  - Combine with Read to examine file contents`;
413
419
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
414
420
  async execute(params) {
@@ -432,49 +438,59 @@ export class ListDirectoryTool {
432
438
  }
433
439
  }
434
440
  }
435
- export class SearchCodebaseTool {
436
- name = 'SearchCodebase';
437
- description = `Search for files matching a glob pattern. This is your PRIMARY tool for finding files by name or extension.
438
-
439
- # When to Use
440
- - Finding all files of a certain type (*.ts, *.json, *.md)
441
- - Locating files in specific directories or subdirectories
442
- - Finding configuration files, test files, or source files
443
- - When you need a list of file paths, not content
444
-
445
- # When NOT to Use
446
- - When you need to search file contents (use Grep instead)
447
- - When you need to find specific text within files (use Grep instead)
448
- - For searching non-file patterns (use Grep or Bash)
449
-
450
- # Parameters
451
- - \`pattern\`: Glob pattern (e.g., "**/*.ts", "src/**/*.test.ts")
452
- - \`path\`: (Optional) Directory to search in, default: "."
453
-
454
- # Examples
455
- - Find all TypeScript files: SearchCodebase(pattern="**/*.ts")
456
- - Find test files: SearchCodebase(pattern="**/*.test.ts")
457
- - Find config files: SearchCodebase(pattern="**/config.*")
458
-
459
- # Glob Patterns
460
- - \`*\` matches any characters except /
461
- - \`**\` matches any characters including /
462
- - \`?\` matches single character
463
- - Use brackets for character classes: [abc]
464
-
465
- # Best Practices
466
- - Use **/*.ts for recursive search in all directories
467
- - Combine with path parameter to search specific directories
441
+ export class SearchFilesTool {
442
+ name = 'SearchFiles';
443
+ description = `Search for files matching a glob pattern. This is your PRIMARY tool for finding files by name or extension.
444
+
445
+ # When to Use
446
+ - Finding all files of a certain type (*.ts, *.json, *.md)
447
+ - Locating files in specific directories or subdirectories
448
+ - Finding configuration files, test files, or source files
449
+ - When you need a list of file paths, not content
450
+
451
+ # When NOT to Use
452
+ - When you need to search file contents (use Grep instead)
453
+ - When you need to find specific text within files (use Grep instead)
454
+ - For searching non-file patterns (use Grep or Bash)
455
+
456
+ # Parameters
457
+ - \`pattern\`: Glob pattern (e.g., "**/*.ts", "src/**/*.test.ts")
458
+ - \`path\`: (Optional) Directory to search in, default: "."
459
+ - \`limit\`: (Optional) Maximum number of results to return, default: 1000
460
+
461
+ # Examples
462
+ - Find all TypeScript files: SearchFiles(pattern="**/*.ts")
463
+ - Find test files: SearchFiles(pattern="**/*.test.ts")
464
+ - Find config files: SearchFiles(pattern="**/config.*")
465
+ - Limit results: SearchFiles(pattern="**/*.ts", limit=100)
466
+
467
+ # Glob Patterns
468
+ - \`*\` matches any characters except /
469
+ - \`**\` matches any characters including /
470
+ - \`?\` matches single character
471
+ - Use brackets for character classes: [abc]
472
+
473
+ # Best Practices
474
+ - Use **/*.ts for recursive search in all directories
475
+ - Combine with path parameter to search specific directories
476
+ - Use limit parameter to avoid huge result sets
468
477
  - Results are file paths, not content (use Grep on results if needed)`;
469
478
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
470
479
  async execute(params) {
471
- const { pattern, path: searchPath = '.' } = params;
480
+ const { pattern, path: searchPath = '.', limit = 1000 } = params;
472
481
  try {
473
482
  const files = await glob(pattern, {
474
483
  cwd: searchPath,
475
484
  ignore: ['node_modules/**', '.git/**', 'dist/**', 'build/**']
476
485
  });
477
- return files;
486
+ const total = files.length;
487
+ const truncated = total > limit;
488
+ const result = truncated ? files.slice(0, limit) : files;
489
+ return {
490
+ files: result,
491
+ total,
492
+ truncated
493
+ };
478
494
  }
479
495
  catch (error) {
480
496
  throw new Error(`Search failed: ${error.message}`);
@@ -483,29 +499,29 @@ export class SearchCodebaseTool {
483
499
  }
484
500
  export class DeleteFileTool {
485
501
  name = 'DeleteFile';
486
- description = `Delete a file from the filesystem.
487
-
488
- # When to Use
489
- - Removing temporary or debug files
490
- - Cleaning up generated files
491
- - Removing files as part of a refactoring task
492
- - When user explicitly requests file deletion
493
-
494
- # When NOT to Use
495
- - For removing directories (use Bash with rm -rf instead)
496
- - When uncertain if a file should be deleted (confirm with user first)
497
- - For removing important source files without explicit user request
498
-
499
- # Parameters
500
- - \`filePath\`: Absolute path to the file to delete
501
-
502
- # Examples
503
- - Delete temporary file: DeleteFile(filePath="debug.log")
504
- - Remove unused file: DeleteFile(filePath="src/old-component.tsx")
505
-
506
- # Best Practices
507
- - Ensure you have the correct file path
508
- - Consider if the file might be needed later
502
+ description = `Delete a file from the filesystem.
503
+
504
+ # When to Use
505
+ - Removing temporary or debug files
506
+ - Cleaning up generated files
507
+ - Removing files as part of a refactoring task
508
+ - When user explicitly requests file deletion
509
+
510
+ # When NOT to Use
511
+ - For removing directories (use Bash with rm -rf instead)
512
+ - When uncertain if a file should be deleted (confirm with user first)
513
+ - For removing important source files without explicit user request
514
+
515
+ # Parameters
516
+ - \`filePath\`: Absolute path to the file to delete
517
+
518
+ # Examples
519
+ - Delete temporary file: DeleteFile(filePath="debug.log")
520
+ - Remove unused file: DeleteFile(filePath="src/old-component.tsx")
521
+
522
+ # Best Practices
523
+ - Ensure you have the correct file path
524
+ - Consider if the file might be needed later
509
525
  - This action is irreversible - be certain before executing`;
510
526
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
511
527
  async execute(params) {
@@ -515,7 +531,8 @@ export class DeleteFileTool {
515
531
  await fs.unlink(absolutePath);
516
532
  return {
517
533
  success: true,
518
- message: `Successfully deleted ${filePath}`
534
+ message: `Successfully deleted ${filePath}`,
535
+ filePath
519
536
  };
520
537
  }
521
538
  catch (error) {
@@ -525,29 +542,29 @@ export class DeleteFileTool {
525
542
  }
526
543
  export class CreateDirectoryTool {
527
544
  name = 'CreateDirectory';
528
- description = `Create a new directory (folder) in the filesystem.
529
-
530
- # When to Use
531
- - Creating project structure (src/components, tests/unit, etc.)
532
- - Setting up directories for new features or modules
533
- - Organizing files into appropriate folders
534
- - When user requests to create a folder structure
535
-
536
- # When NOT to Use
537
- - For creating parent directories while writing files (Write tool does this automatically)
538
- - For creating multiple nested directories at once (create step by step or use Bash)
539
-
540
- # Parameters
541
- - \`dirPath\`: Path of the directory to create
542
- - \`recursive\`: (Optional, default: true) Create parent directories if they don't exist
543
-
544
- # Examples
545
- - Create single directory: CreateDirectory(dirPath="src/utils")
546
- - Create nested structure: CreateDirectory(dirPath="src/components/buttons", recursive=true)
547
-
548
- # Best Practices
549
- - recursive=true (default) creates all intermediate parent directories
550
- - Use appropriate naming conventions (kebab-case for directories)
545
+ description = `Create a new directory (folder) in the filesystem.
546
+
547
+ # When to Use
548
+ - Creating project structure (src/components, tests/unit, etc.)
549
+ - Setting up directories for new features or modules
550
+ - Organizing files into appropriate folders
551
+ - When user requests to create a folder structure
552
+
553
+ # When NOT to Use
554
+ - For creating parent directories while writing files (Write tool does this automatically)
555
+ - For creating multiple nested directories at once (create step by step or use Bash)
556
+
557
+ # Parameters
558
+ - \`dirPath\`: Path of the directory to create
559
+ - \`recursive\`: (Optional, default: true) Create parent directories if they don't exist
560
+
561
+ # Examples
562
+ - Create single directory: CreateDirectory(dirPath="src/utils")
563
+ - Create nested structure: CreateDirectory(dirPath="src/components/buttons", recursive=true)
564
+
565
+ # Best Practices
566
+ - recursive=true (default) creates all intermediate parent directories
567
+ - Use appropriate naming conventions (kebab-case for directories)
551
568
  - Consider the overall project structure before creating`;
552
569
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
553
570
  async execute(params) {
@@ -565,103 +582,286 @@ export class CreateDirectoryTool {
565
582
  }
566
583
  }
567
584
  }
568
- export class ReplaceTool {
569
- name = 'replace';
570
- description = `Replace specific text within an existing file. This is your PRIMARY tool for making targeted edits to code.
571
-
572
- # When to Use
573
- - Modifying specific code sections without rewriting entire files
574
- - Changing function implementations, variable values, or configurations
575
- - Fixing bugs by editing specific lines
576
- - Updating imports, exports, or references
577
-
578
- # When NOT to Use
579
- - When you need to create a completely new file (use Write instead)
580
- - When you want to append content to a file (read first, then Write)
581
- - When making changes across multiple files (use Grep to find, then Replace individually)
582
-
583
- # Parameters
584
- - \`file_path\`: Path to the file to edit
585
- - \`instruction\`: Description of what to change (for your own tracking)
586
- - \`old_string\`: The exact text to find and replace (must match exactly)
587
- - \`new_string\`: The new text to replace with
588
-
589
- # Critical Requirements
590
- - \`old_string\` MUST be an EXACT match, including whitespace and indentation
591
- - Include at least 3 lines of context before and after the target text
592
- - Ensure unique matching to avoid unintended replacements
593
-
594
- # Examples
595
- replace(
596
- file_path="src/app.ts",
597
- instruction="Update API endpoint",
598
- old_string="const API_URL = 'https://api.old.com';",
599
- new_string="const API_URL = 'https://api.new.com';"
600
- )
601
-
602
- # Best Practices
603
- - Read the file first to understand the exact content
604
- - Include sufficient context in old_string to ensure unique match
605
- - Be careful with special regex characters in old_string (they're escaped automatically)
606
- - If multiple occurrences exist, all will be replaced`;
585
+ // 编辑工具辅助函数
586
+ function detectLineEnding(content) {
587
+ const crlfIdx = content.indexOf("\r\n");
588
+ const lfIdx = content.indexOf("\n");
589
+ if (lfIdx === -1)
590
+ return "\n";
591
+ if (crlfIdx === -1)
592
+ return "\n";
593
+ return crlfIdx < lfIdx ? "\r\n" : "\n";
594
+ }
595
+ function normalizeToLF(text) {
596
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
597
+ }
598
+ function restoreLineEndings(text, ending) {
599
+ return ending === "\r\n" ? text.replace(/\n/g, "\r\n") : text;
600
+ }
601
+ function normalizeForFuzzyMatch(text) {
602
+ return (text
603
+ .split("\n")
604
+ .map((line) => line.trimEnd())
605
+ .join("\n")
606
+ .replace(/['‘’""]/g, "'")
607
+ .replace(/["""]/g, '"')
608
+ .replace(/[—–‑−]/g, "-")
609
+ .replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g, " "));
610
+ }
611
+ function fuzzyFindText(content, oldText) {
612
+ const exactIndex = content.indexOf(oldText);
613
+ if (exactIndex !== -1) {
614
+ return {
615
+ found: true,
616
+ index: exactIndex,
617
+ matchLength: oldText.length,
618
+ usedFuzzyMatch: false,
619
+ contentForReplacement: content,
620
+ };
621
+ }
622
+ const fuzzyContent = normalizeForFuzzyMatch(content);
623
+ const fuzzyOldText = normalizeForFuzzyMatch(oldText);
624
+ const fuzzyIndex = fuzzyContent.indexOf(fuzzyOldText);
625
+ if (fuzzyIndex === -1) {
626
+ return {
627
+ found: false,
628
+ index: -1,
629
+ matchLength: 0,
630
+ usedFuzzyMatch: false,
631
+ contentForReplacement: content,
632
+ };
633
+ }
634
+ return {
635
+ found: true,
636
+ index: fuzzyIndex,
637
+ matchLength: fuzzyOldText.length,
638
+ usedFuzzyMatch: true,
639
+ contentForReplacement: fuzzyContent,
640
+ };
641
+ }
642
+ function stripBom(content) {
643
+ return content.startsWith("\uFEFF") ? { bom: "\uFEFF", text: content.slice(1) } : { bom: "", text: content };
644
+ }
645
+ async function generateDiffString(oldContent, newContent, contextLines = 4) {
646
+ const diffModule = await import("diff");
647
+ const parts = diffModule.diffLines(oldContent, newContent);
648
+ const output = [];
649
+ const oldLines = oldContent.split("\n");
650
+ const newLines = newContent.split("\n");
651
+ const maxLineNum = Math.max(oldLines.length, newLines.length);
652
+ const lineNumWidth = String(maxLineNum).length;
653
+ let oldLineNum = 1;
654
+ let newLineNum = 1;
655
+ let lastWasChange = false;
656
+ let firstChangedLine;
657
+ for (let i = 0; i < parts.length; i++) {
658
+ const part = parts[i];
659
+ const raw = part.value.split("\n");
660
+ if (raw[raw.length - 1] === "") {
661
+ raw.pop();
662
+ }
663
+ if (part.added || part.removed) {
664
+ if (firstChangedLine === undefined) {
665
+ firstChangedLine = newLineNum;
666
+ }
667
+ for (const line of raw) {
668
+ if (part.added) {
669
+ const lineNum = String(newLineNum).padStart(lineNumWidth, " ");
670
+ output.push(`+${lineNum} ${line}`);
671
+ newLineNum++;
672
+ }
673
+ else {
674
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
675
+ output.push(`-${lineNum} ${line}`);
676
+ oldLineNum++;
677
+ }
678
+ }
679
+ lastWasChange = true;
680
+ }
681
+ else {
682
+ const nextPartIsChange = i < parts.length - 1 && (parts[i + 1].added || parts[i + 1].removed);
683
+ if (lastWasChange || nextPartIsChange) {
684
+ let linesToShow = raw;
685
+ let skipStart = 0;
686
+ let skipEnd = 0;
687
+ if (!lastWasChange) {
688
+ skipStart = Math.max(0, raw.length - contextLines);
689
+ linesToShow = raw.slice(skipStart);
690
+ }
691
+ if (!nextPartIsChange && linesToShow.length > contextLines) {
692
+ skipEnd = linesToShow.length - contextLines;
693
+ linesToShow = linesToShow.slice(0, contextLines);
694
+ }
695
+ if (skipStart > 0) {
696
+ output.push(` ${"".padStart(lineNumWidth, " ")} ...`);
697
+ oldLineNum += skipStart;
698
+ newLineNum += skipStart;
699
+ }
700
+ for (const line of linesToShow) {
701
+ const lineNum = String(oldLineNum).padStart(lineNumWidth, " ");
702
+ output.push(` ${lineNum} ${line}`);
703
+ oldLineNum++;
704
+ newLineNum++;
705
+ }
706
+ if (skipEnd > 0) {
707
+ output.push(` ${"".padStart(lineNumWidth, " ")} ...`);
708
+ }
709
+ }
710
+ else {
711
+ oldLineNum += raw.length;
712
+ newLineNum += raw.length;
713
+ }
714
+ lastWasChange = false;
715
+ }
716
+ }
717
+ return { diff: output.join("\n"), firstChangedLine };
718
+ }
719
+ export class EditTool {
720
+ name = 'Edit';
721
+ description = `Edit a file by replacing exact text. This is your PRIMARY tool for making targeted edits to code.
722
+
723
+ # When to Use
724
+ - Modifying specific code sections without rewriting entire files
725
+ - Changing function implementations, variable values, or configurations
726
+ - Fixing bugs by editing specific lines
727
+ - Updating imports, exports, or references
728
+
729
+ # When NOT to Use
730
+ - When you need to create a completely new file (use Write instead)
731
+ - When you want to append content to a file (read first, then Write)
732
+ - When making changes across multiple files (use Grep to find, then edit individually)
733
+
734
+ # Parameters
735
+ - \`file_path\`: Path to the file to edit (relative or absolute)
736
+ - \`instruction\`: Description of what to change (for your own tracking)
737
+ - \`old_string\`: The exact text to find and replace (must match exactly)
738
+ - \`new_string\`: The new text to replace with
739
+
740
+ # Critical Requirements
741
+ - \`old_string\` MUST be an EXACT match, including whitespace and indentation
742
+ - Include sufficient context (at least 3 lines) before and after the target text to ensure unique matching
743
+ - The file must exist before editing
744
+
745
+ # Fuzzy Matching
746
+ This tool supports fuzzy matching to handle minor formatting differences:
747
+ - Trailing whitespace is ignored
748
+ - Smart quotes (', ", , ) are normalized to ASCII
749
+ - Unicode dashes/hyphens are normalized to ASCII hyphen
750
+ - Special Unicode spaces are normalized to regular space
751
+
752
+ # Examples
753
+ edit(
754
+ file_path="src/app.ts",
755
+ instruction="Update API endpoint",
756
+ old_string="const API_URL = 'https://api.old.com'\\nconst PORT = 8080;",
757
+ new_string="const API_URL = 'https://api.new.com'\\nconst PORT = 3000;"
758
+ )
759
+
760
+ # Best Practices
761
+ - Read the file first to understand the exact content
762
+ - Include sufficient context in old_string to ensure unique match
763
+ - If fuzzy matching is needed, the tool will automatically apply it
764
+ - Check the diff output to verify the change is correct`;
607
765
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
608
766
  async execute(params) {
609
767
  const { file_path, instruction, old_string, new_string } = params;
610
768
  try {
611
769
  const absolutePath = path.resolve(file_path);
612
- const content = await fs.readFile(absolutePath, 'utf-8');
613
- const occurrences = (content.match(new RegExp(this.escapeRegExp(old_string), 'g')) || []).length;
614
- if (occurrences === 0) {
770
+ // Check if file exists
771
+ try {
772
+ await fs.access(absolutePath);
773
+ }
774
+ catch {
775
+ return {
776
+ success: false,
777
+ message: `File not found: ${file_path}`,
778
+ };
779
+ }
780
+ // Read the file
781
+ const buffer = await fs.readFile(absolutePath);
782
+ const rawContent = buffer.toString("utf-8");
783
+ // Strip BOM before matching
784
+ const { bom, text: content } = stripBom(rawContent);
785
+ const originalEnding = detectLineEnding(content);
786
+ const normalizedContent = normalizeToLF(content);
787
+ const normalizedOldText = normalizeToLF(old_string);
788
+ const normalizedNewText = normalizeToLF(new_string);
789
+ // Find the old text using fuzzy matching
790
+ const matchResult = fuzzyFindText(normalizedContent, normalizedOldText);
791
+ if (!matchResult.found) {
792
+ return {
793
+ success: false,
794
+ message: `Could not find the exact text in ${file_path}. The old text must match exactly including all whitespace and newlines.`,
795
+ };
796
+ }
797
+ // Count occurrences using fuzzy-normalized content
798
+ const fuzzyContent = normalizeForFuzzyMatch(normalizedContent);
799
+ const fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);
800
+ const occurrences = fuzzyContent.split(fuzzyOldText).length - 1;
801
+ if (occurrences > 1) {
802
+ return {
803
+ success: false,
804
+ message: `Found ${occurrences} occurrences of the text in ${file_path}. The text must be unique. Please provide more context to make it unique.`,
805
+ };
806
+ }
807
+ // Perform replacement
808
+ const baseContent = matchResult.contentForReplacement;
809
+ const newContent = baseContent.substring(0, matchResult.index) +
810
+ normalizedNewText +
811
+ baseContent.substring(matchResult.index + matchResult.matchLength);
812
+ // Verify the replacement actually changed something
813
+ if (baseContent === newContent) {
615
814
  return {
616
815
  success: false,
617
- message: `No occurrences found to replace in ${file_path}`,
618
- changes: 0
816
+ message: `No changes made to ${file_path}. The replacement produced identical content.`,
619
817
  };
620
818
  }
621
- const newContent = content.replace(new RegExp(this.escapeRegExp(old_string), 'g'), new_string);
622
- await fs.writeFile(absolutePath, newContent, 'utf-8');
819
+ const finalContent = bom + restoreLineEndings(newContent, originalEnding);
820
+ await fs.writeFile(absolutePath, finalContent, "utf-8");
821
+ const diffResult = await generateDiffString(baseContent, newContent);
623
822
  return {
624
823
  success: true,
625
- message: `Successfully replaced ${occurrences} occurrence(s) in ${file_path}`,
626
- changes: occurrences
824
+ message: `Successfully replaced text in ${file_path}.`,
825
+ diff: diffResult.diff,
826
+ firstChangedLine: diffResult.firstChangedLine,
627
827
  };
628
828
  }
629
829
  catch (error) {
630
- throw new Error(`Failed to replace in file ${file_path}: ${error.message}`);
830
+ return {
831
+ success: false,
832
+ message: `Failed to edit file ${file_path}: ${error.message}`,
833
+ };
631
834
  }
632
835
  }
633
- escapeRegExp(string) {
634
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
635
- }
636
836
  }
637
837
  export class WebSearchTool {
638
838
  name = 'web_search';
639
- description = `Search the web for information. This tool queries a search API to find relevant results.
640
-
641
- # When to Use
642
- - When you need current information not in your training data
643
- - Finding documentation, tutorials, or guides
644
- - Researching APIs, libraries, or tools
645
- - Getting up-to-date information on technical topics
646
- - When user asks for "latest", "recent", or "current" information
647
-
648
- # When NOT to Use
649
- - When information is likely in the codebase or project files
650
- - For information that doesn't change frequently (check docs first)
651
- - When you can use web_fetch with a known URL instead
652
- - For purely conversational queries
653
-
654
- # Parameters
655
- - \`query\`: Search query string
656
-
657
- # Examples
658
- - Find React documentation: web_search(query="React useEffect documentation")
659
- - Get latest Node.js version: web_search(query="Node.js latest LTS version 2024")
660
-
661
- # Best Practices
662
- - Be specific in your query for better results
663
- - Combine with web_fetch to get full content from relevant URLs
664
- - Use quotes for exact phrase matching
839
+ description = `Search the web for information. This tool queries a search API to find relevant results.
840
+
841
+ # When to Use
842
+ - When you need current information not in your training data
843
+ - Finding documentation, tutorials, or guides
844
+ - Researching APIs, libraries, or tools
845
+ - Getting up-to-date information on technical topics
846
+ - When user asks for "latest", "recent", or "current" information
847
+
848
+ # When NOT to Use
849
+ - When information is likely in the codebase or project files
850
+ - For information that doesn't change frequently (check docs first)
851
+ - When you can use web_fetch with a known URL instead
852
+ - For purely conversational queries
853
+
854
+ # Parameters
855
+ - \`query\`: Search query string
856
+
857
+ # Examples
858
+ - Find React documentation: web_search(query="React useEffect documentation")
859
+ - Get latest Node.js version: web_search(query="Node.js latest LTS version 2024")
860
+
861
+ # Best Practices
862
+ - Be specific in your query for better results
863
+ - Combine with web_fetch to get full content from relevant URLs
864
+ - Use quotes for exact phrase matching
665
865
  - Consider adding context like year or version in query`;
666
866
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
667
867
  async execute(params) {
@@ -694,51 +894,51 @@ export class WebSearchTool {
694
894
  }
695
895
  export class TodoWriteTool {
696
896
  name = 'todo_write';
697
- description = `Create and manage structured task todo lists. Use this tool VERY frequently to track your progress and give users visibility into what needs to be done.
698
-
699
- # When to Use
700
- - Complex, multi-step tasks (3+ steps)
701
- - User explicitly requests a todo list
702
- - User provides multiple tasks to accomplish
703
- - Immediately when starting work on a new feature
704
- - After completing a task (update status immediately)
705
- - Breaking down large features into smaller steps
706
- - Tracking independent subtasks that can be worked on
707
-
708
- # When NOT to Use
709
- - Single, straightforward task
710
- - Trivial operations in less than 3 steps
711
- - Purely conversational or informational responses
712
- - When you already have an up-to-date todo list
713
-
714
- # Task States
715
- - **pending** - Not started, waiting to be worked on
716
- - **in_progress** - Currently working on (limit ONE at a time)
717
- - **completed** - Finished successfully
718
- - **failed** - Could not complete due to errors
719
-
720
- # Task Descriptions
721
- Each task needs:
722
- - \`id\`: Unique identifier
723
- - \`task\`: Clear, actionable description in imperative form (e.g., "Run tests")
724
- - \`status\`: Current state
725
- - \`priority\`: high/medium/low
726
-
727
- # Examples
728
- \`\`\`json
729
- {
730
- "todos": [
731
- { "id": "1", "task": "Run the build and check for errors", "status": "in_progress", "priority": "high" },
732
- { "id": "2", "task": "Fix any type errors found", "status": "pending", "priority": "high" },
733
- { "id": "3", "task": "Write unit tests for new feature", "status": "pending", "priority": "medium" }
734
- ]
735
- }
736
- \`\`\`
737
-
738
- # Best Practices
739
- - Mark tasks as completed IMMEDIATELY after finishing
740
- - Don't batch multiple completions - update as you go
741
- - Keep task descriptions clear and actionable
897
+ description = `Create and manage structured task todo lists. Use this tool VERY frequently to track your progress and give users visibility into what needs to be done.
898
+
899
+ # When to Use
900
+ - Complex, multi-step tasks (3+ steps)
901
+ - User explicitly requests a todo list
902
+ - User provides multiple tasks to accomplish
903
+ - Immediately when starting work on a new feature
904
+ - After completing a task (update status immediately)
905
+ - Breaking down large features into smaller steps
906
+ - Tracking independent subtasks that can be worked on
907
+
908
+ # When NOT to Use
909
+ - Single, straightforward task
910
+ - Trivial operations in less than 3 steps
911
+ - Purely conversational or informational responses
912
+ - When you already have an up-to-date todo list
913
+
914
+ # Task States
915
+ - **pending** - Not started, waiting to be worked on
916
+ - **in_progress** - Currently working on (limit ONE at a time)
917
+ - **completed** - Finished successfully
918
+ - **failed** - Could not complete due to errors
919
+
920
+ # Task Descriptions
921
+ Each task needs:
922
+ - \`id\`: Unique identifier
923
+ - \`task\`: Clear, actionable description in imperative form (e.g., "Run tests")
924
+ - \`status\`: Current state
925
+ - \`priority\`: high/medium/low
926
+
927
+ # Examples
928
+ \`\`\`json
929
+ {
930
+ "todos": [
931
+ { "id": "1", "task": "Run the build and check for errors", "status": "in_progress", "priority": "high" },
932
+ { "id": "2", "task": "Fix any type errors found", "status": "pending", "priority": "high" },
933
+ { "id": "3", "task": "Write unit tests for new feature", "status": "pending", "priority": "medium" }
934
+ ]
935
+ }
936
+ \`\`\`
937
+
938
+ # Best Practices
939
+ - Mark tasks as completed IMMEDIATELY after finishing
940
+ - Don't batch multiple completions - update as you go
941
+ - Keep task descriptions clear and actionable
742
942
  - Use appropriate priority levels to indicate urgency`;
743
943
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
744
944
  todoList = [];
@@ -768,24 +968,24 @@ Each task needs:
768
968
  }
769
969
  export class TodoReadTool {
770
970
  name = 'todo_read';
771
- description = `Read the current session's todo list and get a summary of all tasks. Use this to check what tasks remain and their current status.
772
-
773
- # When to Use
774
- - Before starting work to understand what needs to be done
775
- - After completing a task to verify the todo list is updated
776
- - When user asks about progress or remaining tasks
777
- - To get an overview of task distribution (pending, in_progress, completed)
778
-
779
- # What It Returns
780
- - Full list of all todos with their IDs, tasks, statuses, and priorities
781
- - Summary counts: total, pending, in_progress, completed, failed
782
-
783
- # Examples
784
- - User asks: "What are we working on right now?" → Use todo_read to show current state
785
- - After a task completes → Check todo_read to confirm the list is accurate
786
-
787
- # Best Practices
788
- - Use todo_write to modify the list, not todo_read
971
+ description = `Read the current session's todo list and get a summary of all tasks. Use this to check what tasks remain and their current status.
972
+
973
+ # When to Use
974
+ - Before starting work to understand what needs to be done
975
+ - After completing a task to verify the todo list is updated
976
+ - When user asks about progress or remaining tasks
977
+ - To get an overview of task distribution (pending, in_progress, completed)
978
+
979
+ # What It Returns
980
+ - Full list of all todos with their IDs, tasks, statuses, and priorities
981
+ - Summary counts: total, pending, in_progress, completed, failed
982
+
983
+ # Examples
984
+ - User asks: "What are we working on right now?" → Use todo_read to show current state
985
+ - After a task completes → Check todo_read to confirm the list is accurate
986
+
987
+ # Best Practices
988
+ - Use todo_write to modify the list, not todo_read
789
989
  - Check todo_read after todo_write to verify updates`;
790
990
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
791
991
  todoWriteTool;
@@ -814,42 +1014,42 @@ export class TodoReadTool {
814
1014
  }
815
1015
  export class TaskTool {
816
1016
  name = 'task';
817
- description = `Launch specialized AI subagents to handle complex, multi-step tasks. Subagents are expert agents designed for specific domains like planning, code exploration, frontend testing, and more.
818
-
819
- # When to Use
820
- - Complex tasks requiring specialized expertise (planning, analysis, testing)
821
- - Multi-step workflows that benefit from dedicated focus
822
- - When you need to delegate work to avoid context overload
823
- - Parallel execution of independent tasks across different domains
824
- - User explicitly requests a specific type of agent (e.g., "use the frontend tester")
825
-
826
- # Available SubAgents
827
- 1. **plan-agent** - Task planning and breakdown, risk analysis, implementation roadmaps
828
- 2. **explore-agent** - Codebase exploration, architecture analysis, finding specific code
829
- 3. **frontend-tester** - Writing and running frontend tests, UI validation
830
- 4. **code-reviewer** - Code review, security checks, bug detection
831
- 5. **frontend-developer** - Frontend development (React, TypeScript, modern web)
832
- 6. **backend-developer** - Backend development (Node.js, APIs, databases)
833
- 7. **gui-subagent** - Browser automation, visual web interactions, desktop application automation
834
-
835
- # When NOT to Use
836
- - Simple, straightforward tasks you can handle directly
837
- - Tasks that don't require specialized expertise
838
- - Single-step operations (use other tools instead)
839
-
840
- # Examples
841
- - "Analyze the authentication module and create a security report" → explore-agent
842
- - "Create a detailed implementation plan for feature X" → plan-agent
843
- - "Write unit tests for this React component" → frontend-tester
844
- - "Review my changes for potential bugs" → code-reviewer
845
- - "Automatically fill out this form and navigate the website" → gui-subagent
846
- - "Test the login process on the desktop application" → gui-subagent
847
- - "send a message to the my mom on the desktop application wechat" → gui-subagent
848
-
849
- # Best Practices
850
- - Provide clear, specific prompts to subagents
851
- - Include relevant context (file paths, requirements, constraints)
852
- - Set appropriate executionMode if needed
1017
+ description = `Launch specialized AI subagents to handle complex, multi-step tasks. Subagents are expert agents designed for specific domains like planning, code exploration, frontend testing, and more.
1018
+
1019
+ # When to Use
1020
+ - Complex tasks requiring specialized expertise (planning, analysis, testing)
1021
+ - Multi-step workflows that benefit from dedicated focus
1022
+ - When you need to delegate work to avoid context overload
1023
+ - Parallel execution of independent tasks across different domains
1024
+ - User explicitly requests a specific type of agent (e.g., "use the frontend tester")
1025
+
1026
+ # Available SubAgents
1027
+ 1. **plan-agent** - Task planning and breakdown, risk analysis, implementation roadmaps
1028
+ 2. **explore-agent** - Codebase exploration, architecture analysis, finding specific code
1029
+ 3. **frontend-tester** - Writing and running frontend tests, UI validation
1030
+ 4. **code-reviewer** - Code review, security checks, bug detection
1031
+ 5. **frontend-developer** - Frontend development (React, TypeScript, modern web)
1032
+ 6. **backend-developer** - Backend development (Node.js, APIs, databases)
1033
+ 7. **gui-subagent** - Browser automation, visual web interactions, desktop application automation
1034
+
1035
+ # When NOT to Use
1036
+ - Simple, straightforward tasks you can handle directly
1037
+ - Tasks that don't require specialized expertise
1038
+ - Single-step operations (use other tools instead)
1039
+
1040
+ # Examples
1041
+ - "Analyze the authentication module and create a security report" → explore-agent
1042
+ - "Create a detailed implementation plan for feature X" → plan-agent
1043
+ - "Write unit tests for this React component" → frontend-tester
1044
+ - "Review my changes for potential bugs" → code-reviewer
1045
+ - "Automatically fill out this form and navigate the website" → gui-subagent
1046
+ - "Test the login process on the desktop application" → gui-subagent
1047
+ - "send a message to the my mom on the desktop application wechat" → gui-subagent
1048
+
1049
+ # Best Practices
1050
+ - Provide clear, specific prompts to subagents
1051
+ - Include relevant context (file paths, requirements, constraints)
1052
+ - Set appropriate executionMode if needed
853
1053
  - For parallel execution, ensure tasks are truly independent`;
854
1054
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
855
1055
  async execute(params, _executionMode) {
@@ -870,10 +1070,21 @@ export class TaskTool {
870
1070
  if (params.agents && params.agents.length > 0) {
871
1071
  return await this.executeParallelAgents(params.agents, params.description, mode, agentManager, toolRegistry, aiClient);
872
1072
  }
873
- if (!params.subagent_type || !params.prompt) {
874
- throw new Error('Either subagent_type and prompt, or agents array must be provided');
875
- }
876
- const result = await this.executeSingleAgent(params.subagent_type, params.prompt, params.description, params.useContext ?? true, params.constraints || [], mode, agentManager, toolRegistry, aiClient, config);
1073
+ if (!params.subagent_type) {
1074
+ throw new Error('subagent_type is required for Task tool');
1075
+ }
1076
+ // Support both 'prompt' and 'query' parameter names (tool definition uses 'query')
1077
+ const prompt = params.prompt || params.query;
1078
+ if (!prompt) {
1079
+ throw new Error('Task query/prompt is required. Received params: ' + JSON.stringify({
1080
+ subagent_type: params.subagent_type,
1081
+ prompt: params.prompt,
1082
+ query: params.query,
1083
+ description: params.description,
1084
+ agents: params.agents?.length
1085
+ }));
1086
+ }
1087
+ const result = await this.executeSingleAgent(params.subagent_type, prompt, params.description, params.useContext ?? true, params.constraints || [], mode, agentManager, toolRegistry, aiClient, config);
877
1088
  return result;
878
1089
  }
879
1090
  catch (error) {
@@ -1186,6 +1397,8 @@ export class TaskTool {
1186
1397
  const indent = ' '.repeat(indentLevel);
1187
1398
  const indentNext = ' '.repeat(indentLevel + 1);
1188
1399
  const agentName = agent.name || subagent_type;
1400
+ // Track execution history for better reporting to main agent
1401
+ const executionHistory = [];
1189
1402
  // Helper function to indent multi-line content
1190
1403
  const indentMultiline = (content, baseIndent) => {
1191
1404
  return content.split('\n').map(line => `${baseIndent} ${line}`).join('\n');
@@ -1291,6 +1504,7 @@ export class TaskTool {
1291
1504
  }
1292
1505
  const choice = result.choices[0];
1293
1506
  const messageContent = choice.message?.content;
1507
+ const reasoningContent = choice.message?.reasoning_content || '';
1294
1508
  const toolCalls = choice.message.tool_calls;
1295
1509
  let contentStr;
1296
1510
  let hasValidContent = false;
@@ -1319,6 +1533,13 @@ export class TaskTool {
1319
1533
  }
1320
1534
  // Add assistant message to conversation
1321
1535
  messages.push({ role: 'assistant', content: contentStr });
1536
+ // Display reasoning content if present
1537
+ if (reasoningContent) {
1538
+ console.log(`\n${indent}${colors.textDim(`${icons.brain} Thinking Process:`)}`);
1539
+ const truncatedReasoning = reasoningContent.length > 500 ? reasoningContent.substring(0, 500) + '...' : reasoningContent;
1540
+ const indentedReasoning = indentMultiline(truncatedReasoning, indent);
1541
+ console.log(`${indentedReasoning}\n`);
1542
+ }
1322
1543
  // Display assistant response (if there's any text content) with proper indentation
1323
1544
  if (contentStr) {
1324
1545
  console.log(`\n${indent}${colors.primaryBright(agentName)}: ${description}`);
@@ -1342,11 +1563,92 @@ export class TaskTool {
1342
1563
  // Check cancellation before tool execution
1343
1564
  checkCancellation();
1344
1565
  const toolResult = await cancellationManager.withCancellation(toolRegistry.execute(name, parsedParams, mode, indent), `subagent-${subagent_type}-${name}-${iteration}`);
1345
- // Display tool result with proper indentation for multi-line content
1566
+ // Get showToolDetails config to control result display
1567
+ const showToolDetails = config.get('showToolDetails') || false;
1568
+ // Prepare result preview for history
1346
1569
  const resultPreview = typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult, null, 2);
1347
1570
  const truncatedPreview = resultPreview.length > 200 ? resultPreview.substring(0, 200) + '...' : resultPreview;
1348
- const indentedPreview = indentMultiline(truncatedPreview, indent);
1349
- console.log(`${indent}${colors.success(`${icons.check} Completed`)}\n${indentedPreview}\n`);
1571
+ // Special handling for different tools (consistent with session.ts display logic)
1572
+ const isTodoTool = name === 'todo_write' || name === 'todo_read';
1573
+ const isEditTool = name === 'Edit';
1574
+ const isWriteTool = name === 'Write';
1575
+ const isDeleteTool = name === 'DeleteFile';
1576
+ const hasDiff = isEditTool && toolResult?.diff;
1577
+ const hasFilePreview = isWriteTool && toolResult?.preview;
1578
+ const hasDeleteInfo = isDeleteTool && toolResult?.filePath;
1579
+ // Import render functions for consistent display
1580
+ const { renderDiff, renderLines } = await import('./theme.js');
1581
+ if (isTodoTool) {
1582
+ // Display todo list
1583
+ console.log(`${indent}${colors.success(`${icons.check} Todo List:`)}`);
1584
+ const todos = toolResult?.todos || [];
1585
+ if (todos.length === 0) {
1586
+ console.log(`${indent} ${colors.textMuted('No tasks')}`);
1587
+ }
1588
+ else {
1589
+ const statusConfig = {
1590
+ 'pending': { icon: icons.circle, color: colors.textMuted, label: 'Pending' },
1591
+ 'in_progress': { icon: icons.loading, color: colors.warning, label: 'In Progress' },
1592
+ 'completed': { icon: icons.success, color: colors.success, label: 'Completed' },
1593
+ 'failed': { icon: icons.error, color: colors.error, label: 'Failed' }
1594
+ };
1595
+ for (const todo of todos) {
1596
+ const status = statusConfig[todo.status] || statusConfig['pending'];
1597
+ console.log(`${indent} ${status.color(status.icon)} ${status.color(status.label)}: ${colors.text(todo.task)}`);
1598
+ }
1599
+ }
1600
+ if (toolResult?.message) {
1601
+ console.log(`${indent}${colors.textDim(toolResult.message)}`);
1602
+ }
1603
+ console.log('');
1604
+ }
1605
+ else if (hasDiff) {
1606
+ // Display edit result with diff
1607
+ console.log('');
1608
+ const diffOutput = renderDiff(toolResult.diff);
1609
+ const indentedDiff = diffOutput.split('\n').map(line => `${indent} ${line}`).join('\n');
1610
+ console.log(`${indentedDiff}\n`);
1611
+ }
1612
+ else if (hasFilePreview) {
1613
+ // Display new file content in preview style
1614
+ console.log('');
1615
+ console.log(`${indent}${colors.success(`${icons.file} ${toolResult.filePath}`)}`);
1616
+ console.log(`${indent}${colors.textDim(` ${toolResult.lineCount} lines`)}`);
1617
+ console.log('');
1618
+ console.log(renderLines(toolResult.preview, { maxLines: 10, indent: indent + ' ' }));
1619
+ console.log('');
1620
+ }
1621
+ else if (hasDeleteInfo) {
1622
+ // Display DeleteFile result
1623
+ console.log('');
1624
+ console.log(`${indent}${colors.success(`${icons.check} Deleted: ${toolResult.filePath}`)}`);
1625
+ console.log('');
1626
+ }
1627
+ else if (showToolDetails) {
1628
+ // Show full result details
1629
+ const indentedPreview = indentMultiline(resultPreview, indent);
1630
+ console.log(`${indent}${colors.success(`${icons.check} Tool Result:`)}\n${indentedPreview}\n`);
1631
+ }
1632
+ else if (toolResult && toolResult.success === false) {
1633
+ // Tool failed
1634
+ console.log(`${indent}${colors.error(`${icons.cross} ${toolResult.message || 'Failed'}`)}\n`);
1635
+ }
1636
+ else if (toolResult) {
1637
+ // Show brief preview by default
1638
+ const indentedPreview = indentMultiline(truncatedPreview, indent);
1639
+ console.log(`${indent}${colors.success(`${icons.check} Completed`)}\n${indentedPreview}\n`);
1640
+ }
1641
+ else {
1642
+ console.log(`${indent}${colors.textDim('(no result)')}\n`);
1643
+ }
1644
+ // Record successful tool execution in history (use truncated preview to save memory)
1645
+ executionHistory.push({
1646
+ tool: name,
1647
+ status: 'success',
1648
+ params: parsedParams,
1649
+ result: truncatedPreview,
1650
+ timestamp: new Date().toISOString()
1651
+ });
1350
1652
  messages.push({
1351
1653
  role: 'tool',
1352
1654
  content: JSON.stringify(toolResult),
@@ -1358,13 +1660,32 @@ export class TaskTool {
1358
1660
  console.log(`${indent}${colors.warning(`⚠️ Operation cancelled`)}\n`);
1359
1661
  cancellationManager.off('cancelled', cancelHandler);
1360
1662
  cleanupStdinPolling();
1663
+ const summaryPreview = contentStr.length > 300 ? contentStr.substring(0, 300) + '...' : contentStr;
1361
1664
  return {
1362
1665
  success: false,
1363
1666
  message: `Task "${description}" cancelled by user`,
1364
- result: contentStr
1667
+ result: {
1668
+ summary: summaryPreview,
1669
+ executionHistory: {
1670
+ totalIterations: iteration,
1671
+ toolsExecuted: executionHistory.length,
1672
+ successfulTools: executionHistory.filter(t => t.status === 'success').length,
1673
+ failedTools: executionHistory.filter(t => t.status === 'error').length,
1674
+ history: executionHistory,
1675
+ cancelled: true
1676
+ }
1677
+ }
1365
1678
  };
1366
1679
  }
1367
1680
  console.log(`${indent}${colors.error(`${icons.cross} Error:`)} ${error.message}\n`);
1681
+ // Record failed tool execution in history
1682
+ executionHistory.push({
1683
+ tool: name,
1684
+ status: 'error',
1685
+ params: parsedParams,
1686
+ error: error.message,
1687
+ timestamp: new Date().toISOString()
1688
+ });
1368
1689
  messages.push({
1369
1690
  role: 'tool',
1370
1691
  content: JSON.stringify({ error: error.message }),
@@ -1375,25 +1696,48 @@ export class TaskTool {
1375
1696
  console.log('');
1376
1697
  continue; // Continue to next iteration to get final response
1377
1698
  }
1378
- // No more tool calls, return the result
1699
+ // No more tool calls, return the result with execution history
1379
1700
  cancellationManager.off('cancelled', cancelHandler);
1380
1701
  cleanupStdinPolling();
1702
+ const summaryPreview = contentStr.length > 300 ? contentStr.substring(0, 300) + '...' : contentStr;
1381
1703
  return {
1382
1704
  success: true,
1383
1705
  message: `Task "${description}" completed by ${subagent_type}`,
1384
- result: contentStr
1706
+ result: {
1707
+ summary: summaryPreview,
1708
+ executionHistory: {
1709
+ totalIterations: iteration,
1710
+ toolsExecuted: executionHistory.length,
1711
+ successfulTools: executionHistory.filter(t => t.status === 'success').length,
1712
+ failedTools: executionHistory.filter(t => t.status === 'error').length,
1713
+ history: executionHistory
1714
+ }
1715
+ }
1385
1716
  };
1386
1717
  }
1387
1718
  // Max iterations reached - return accumulated results instead of throwing error
1388
1719
  // Get the last assistant message content
1389
1720
  const lastAssistantMsg = messages.filter(m => m.role === 'assistant').pop();
1390
- const lastContent = lastAssistantMsg?.content || '';
1721
+ const lastContentStr = typeof lastAssistantMsg?.content === 'string'
1722
+ ? lastAssistantMsg.content
1723
+ : JSON.stringify(lastAssistantMsg?.content || '');
1391
1724
  cancellationManager.off('cancelled', cancelHandler);
1392
1725
  cleanupStdinPolling();
1726
+ const summaryPreview = lastContentStr.length > 300 ? lastContentStr.substring(0, 300) + '...' : lastContentStr;
1393
1727
  return {
1394
1728
  success: true,
1395
1729
  message: `Task "${description}" completed (max iterations reached) by ${subagent_type}`,
1396
- result: lastContent
1730
+ result: {
1731
+ summary: summaryPreview,
1732
+ executionHistory: {
1733
+ totalIterations: iteration,
1734
+ toolsExecuted: executionHistory.length,
1735
+ successfulTools: executionHistory.filter(t => t.status === 'success').length,
1736
+ failedTools: executionHistory.filter(t => t.status === 'error').length,
1737
+ history: executionHistory,
1738
+ maxIterationsReached: true
1739
+ }
1740
+ }
1397
1741
  };
1398
1742
  }
1399
1743
  async executeParallelAgents(agents, description, mode, agentManager, toolRegistry, aiClient, indentLevel = 1) {
@@ -1512,31 +1856,31 @@ export class TaskTool {
1512
1856
  }
1513
1857
  export class ReadBashOutputTool {
1514
1858
  name = 'ReadBashOutput';
1515
- description = `Retrieve output from a background task that was started with Bash(run_in_bg=true).
1516
-
1517
- # When to Use
1518
- - Checking the output of a long-running background process
1519
- - Monitoring progress of builds, tests, or servers
1520
- - Retrieving logs from background tasks
1521
- - When you started a task with run_in_bg=true and need results
1522
-
1523
- # When NOT to Use
1524
- - For synchronous commands (they return output directly)
1525
- - When the background task hasn't been started yet
1526
- - For tasks that have already completed (use Bash directly)
1527
-
1528
- # Parameters
1529
- - \`task_id\`: The ID returned from the background Bash command
1530
- - \`poll_interval\`: (Optional) Seconds to wait before checking, default: 10
1531
-
1532
- # Examples
1533
- - Check build output: ReadBashOutput(task_id="task_1234567890")
1534
- - Wait and check: ReadBashOutput(task_id="task_123", poll_interval=5)
1535
-
1536
- # Best Practices
1537
- - Save the task_id from Bash response for later use
1538
- - Use appropriate poll_interval based on expected task duration
1539
- - Check status to see if task is still running or completed
1859
+ description = `Retrieve output from a background task that was started with Bash(run_in_bg=true).
1860
+
1861
+ # When to Use
1862
+ - Checking the output of a long-running background process
1863
+ - Monitoring progress of builds, tests, or servers
1864
+ - Retrieving logs from background tasks
1865
+ - When you started a task with run_in_bg=true and need results
1866
+
1867
+ # When NOT to Use
1868
+ - For synchronous commands (they return output directly)
1869
+ - When the background task hasn't been started yet
1870
+ - For tasks that have already completed (use Bash directly)
1871
+
1872
+ # Parameters
1873
+ - \`task_id\`: The ID returned from the background Bash command
1874
+ - \`poll_interval\`: (Optional) Seconds to wait before checking, default: 10
1875
+
1876
+ # Examples
1877
+ - Check build output: ReadBashOutput(task_id="task_1234567890")
1878
+ - Wait and check: ReadBashOutput(task_id="task_123", poll_interval=5)
1879
+
1880
+ # Best Practices
1881
+ - Save the task_id from Bash response for later use
1882
+ - Use appropriate poll_interval based on expected task duration
1883
+ - Check status to see if task is still running or completed
1540
1884
  - Combine with todo_write to track background task progress`;
1541
1885
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
1542
1886
  async execute(params) {
@@ -1566,31 +1910,31 @@ export class ReadBashOutputTool {
1566
1910
  }
1567
1911
  export class WebFetchTool {
1568
1912
  name = 'web_fetch';
1569
- description = `Fetch and extract content from a specific URL. This tool retrieves the full content of a webpage.
1570
-
1571
- # When to Use
1572
- - When you have a specific URL and need its content
1573
- - Extracting documentation from web pages
1574
- - Fetching API documentation or guides
1575
- - Getting content from known URLs (not for searching)
1576
-
1577
- # When NOT to Use
1578
- - When you need to search but don't have a specific URL (use web_search first)
1579
- - For pages requiring authentication or login
1580
- - For very large files or pages (may timeout)
1581
- - When the URL format is unknown (use web_search first)
1582
-
1583
- # Parameters
1584
- - \`prompt\`: A prompt containing the URL to fetch (e.g., "Summarize https://example.com/docs")
1585
-
1586
- # Examples
1587
- - Fetch documentation: web_fetch(prompt="Extract key points from https://react.dev/docs")
1588
- - Get API spec: web_fetch(prompt="Fetch the OpenAPI spec from https://api.example.com/openapi.json")
1589
-
1590
- # Best Practices
1591
- - Ensure the URL is accessible and doesn't require authentication
1592
- - Use specific prompts to extract relevant information
1593
- - Check if the page is accessible if you get errors
1913
+ description = `Fetch and extract content from a specific URL. This tool retrieves the full content of a webpage.
1914
+
1915
+ # When to Use
1916
+ - When you have a specific URL and need its content
1917
+ - Extracting documentation from web pages
1918
+ - Fetching API documentation or guides
1919
+ - Getting content from known URLs (not for searching)
1920
+
1921
+ # When NOT to Use
1922
+ - When you need to search but don't have a specific URL (use web_search first)
1923
+ - For pages requiring authentication or login
1924
+ - For very large files or pages (may timeout)
1925
+ - When the URL format is unknown (use web_search first)
1926
+
1927
+ # Parameters
1928
+ - \`prompt\`: A prompt containing the URL to fetch (e.g., "Summarize https://example.com/docs")
1929
+
1930
+ # Examples
1931
+ - Fetch documentation: web_fetch(prompt="Extract key points from https://react.dev/docs")
1932
+ - Get API spec: web_fetch(prompt="Fetch the OpenAPI spec from https://api.example.com/openapi.json")
1933
+
1934
+ # Best Practices
1935
+ - Ensure the URL is accessible and doesn't require authentication
1936
+ - Use specific prompts to extract relevant information
1937
+ - Check if the page is accessible if you get errors
1594
1938
  - Large pages may be truncated due to size limits`;
1595
1939
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
1596
1940
  async execute(params) {
@@ -1623,36 +1967,36 @@ export class WebFetchTool {
1623
1967
  }
1624
1968
  export class AskUserQuestionTool {
1625
1969
  name = 'ask_user_question';
1626
- description = `Ask the user questions during execution to gather input, preferences, or clarifications.
1627
-
1628
- # When to Use
1629
- - When you need user input or preferences to proceed
1630
- - When a task has multiple options and user should choose
1631
- - When clarification is needed for ambiguous requests
1632
- - When user explicitly asks to be prompted
1633
-
1634
- # When NOT to Use
1635
- - When you can make reasonable assumptions
1636
- - For simple confirmations (just proceed with reasonable default)
1637
- - When the information is already available in context
1638
- - For information you should know or can infer
1639
-
1640
- # Parameters
1641
- - \`questions\`: Array of questions with:
1642
- - \`question\`: The question text
1643
- - \`header\`: (Optional) Short label for the question
1644
- - \`options\`: (Optional) Multiple choice options
1645
- - \`multiSelect\`: (Optional) Allow multiple selections
1646
-
1647
- # Examples
1648
- - Simple input: Ask user their preferred name
1649
- - Multiple choice: Ask which framework to use (React, Vue, Angular)
1650
- - Multi-select: Ask which features to include (with checkboxes)
1651
-
1652
- # Best Practices
1653
- - Limit to 1-4 questions at a time
1654
- - Provide options when possible for faster response
1655
- - Use multiSelect=true when multiple answers are valid
1970
+ description = `Ask the user questions during execution to gather input, preferences, or clarifications.
1971
+
1972
+ # When to Use
1973
+ - When you need user input or preferences to proceed
1974
+ - When a task has multiple options and user should choose
1975
+ - When clarification is needed for ambiguous requests
1976
+ - When user explicitly asks to be prompted
1977
+
1978
+ # When NOT to Use
1979
+ - When you can make reasonable assumptions
1980
+ - For simple confirmations (just proceed with reasonable default)
1981
+ - When the information is already available in context
1982
+ - For information you should know or can infer
1983
+
1984
+ # Parameters
1985
+ - \`questions\`: Array of questions with:
1986
+ - \`question\`: The question text
1987
+ - \`header\`: (Optional) Short label for the question
1988
+ - \`options\`: (Optional) Multiple choice options
1989
+ - \`multiSelect\`: (Optional) Allow multiple selections
1990
+
1991
+ # Examples
1992
+ - Simple input: Ask user their preferred name
1993
+ - Multiple choice: Ask which framework to use (React, Vue, Angular)
1994
+ - Multi-select: Ask which features to include (with checkboxes)
1995
+
1996
+ # Best Practices
1997
+ - Limit to 1-4 questions at a time
1998
+ - Provide options when possible for faster response
1999
+ - Use multiSelect=true when multiple answers are valid
1656
2000
  - Be clear and concise in question wording`;
1657
2001
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
1658
2002
  async execute(params) {
@@ -1695,32 +2039,32 @@ export class AskUserQuestionTool {
1695
2039
  }
1696
2040
  export class SaveMemoryTool {
1697
2041
  name = 'save_memory';
1698
- description = `Save specific information to long-term memory for future sessions. Useful for remembering user preferences, project conventions, or important facts.
1699
-
1700
- # When to Use
1701
- - User explicitly asks to "remember" something
1702
- - User provides preferences or configuration details
1703
- - Important project conventions or patterns to remember
1704
- - Information that should persist across sessions
1705
-
1706
- # When NOT to Use
1707
- - For temporary information only needed in current session
1708
- - For information already in project files or configuration
1709
- - For obvious or trivial facts
1710
- - When user doesn't explicitly want information saved
1711
-
1712
- # Parameters
1713
- - \`fact\`: The specific fact or information to remember
1714
-
1715
- # Examples
1716
- - Remember user preference: save_memory(fact="User prefers TypeScript over JavaScript")
1717
- - Remember project convention: save_memory(fact="Project uses kebab-case for component files")
1718
- - Remember important context: save_memory(fact="API endpoint is https://api.example.com/v2")
1719
-
1720
- # Best Practices
1721
- - Save only when user explicitly requests or provides clear preference
1722
- - Keep facts concise and specific
1723
- - Remember project-specific conventions for consistency
2042
+ description = `Save specific information to long-term memory for future sessions. Useful for remembering user preferences, project conventions, or important facts.
2043
+
2044
+ # When to Use
2045
+ - User explicitly asks to "remember" something
2046
+ - User provides preferences or configuration details
2047
+ - Important project conventions or patterns to remember
2048
+ - Information that should persist across sessions
2049
+
2050
+ # When NOT to Use
2051
+ - For temporary information only needed in current session
2052
+ - For information already in project files or configuration
2053
+ - For obvious or trivial facts
2054
+ - When user doesn't explicitly want information saved
2055
+
2056
+ # Parameters
2057
+ - \`fact\`: The specific fact or information to remember
2058
+
2059
+ # Examples
2060
+ - Remember user preference: save_memory(fact="User prefers TypeScript over JavaScript")
2061
+ - Remember project convention: save_memory(fact="Project uses kebab-case for component files")
2062
+ - Remember important context: save_memory(fact="API endpoint is https://api.example.com/v2")
2063
+
2064
+ # Best Practices
2065
+ - Save only when user explicitly requests or provides clear preference
2066
+ - Keep facts concise and specific
2067
+ - Remember project-specific conventions for consistency
1724
2068
  - This persists across sessions (global memory)`;
1725
2069
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
1726
2070
  async execute(params) {
@@ -1741,31 +2085,31 @@ export class SaveMemoryTool {
1741
2085
  }
1742
2086
  export class ExitPlanModeTool {
1743
2087
  name = 'exit_plan_mode';
1744
- description = `Complete plan presentation in plan mode and transition to execution. This tool is used when you have finished planning and are ready to implement.
1745
-
1746
- # When to Use
1747
- - When you have completed creating a plan or design document
1748
- - When the plan is ready for review and execution
1749
- - After presenting the full implementation plan to the user
1750
- - When ready to transition from planning to coding
1751
-
1752
- # When NOT to Use
1753
- - When still in the middle of planning (continue planning first)
1754
- - When the plan needs revision based on feedback
1755
- - When user hasn't reviewed the plan yet
1756
- - In non-plan execution modes
1757
-
1758
- # Parameters
1759
- - \`plan\`: The complete plan text to be saved and executed
1760
-
1761
- # Examples
1762
- - Exit after creating implementation plan
1763
- - Present final design and exit to implementation
1764
-
1765
- # Best Practices
1766
- - Ensure the plan is complete and comprehensive
1767
- - Include all necessary steps and considerations
1768
- - The plan will be saved for reference during execution
2088
+ description = `Complete plan presentation in plan mode and transition to execution. This tool is used when you have finished planning and are ready to implement.
2089
+
2090
+ # When to Use
2091
+ - When you have completed creating a plan or design document
2092
+ - When the plan is ready for review and execution
2093
+ - After presenting the full implementation plan to the user
2094
+ - When ready to transition from planning to coding
2095
+
2096
+ # When NOT to Use
2097
+ - When still in the middle of planning (continue planning first)
2098
+ - When the plan needs revision based on feedback
2099
+ - When user hasn't reviewed the plan yet
2100
+ - In non-plan execution modes
2101
+
2102
+ # Parameters
2103
+ - \`plan\`: The complete plan text to be saved and executed
2104
+
2105
+ # Examples
2106
+ - Exit after creating implementation plan
2107
+ - Present final design and exit to implementation
2108
+
2109
+ # Best Practices
2110
+ - Ensure the plan is complete and comprehensive
2111
+ - Include all necessary steps and considerations
2112
+ - The plan will be saved for reference during execution
1769
2113
  - Use this only when truly ready to start coding`;
1770
2114
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
1771
2115
  async execute(params) {
@@ -1784,28 +2128,28 @@ export class ExitPlanModeTool {
1784
2128
  }
1785
2129
  export class XmlEscapeTool {
1786
2130
  name = 'xml_escape';
1787
- description = `Automatically escape special characters in XML/HTML files to make them valid.
1788
-
1789
- # When to Use
1790
- - When content contains special XML characters (<, >, &, ", ')
1791
- - When generating XML/HTML from raw content
1792
- - When fixing encoding issues in markup files
1793
-
1794
- # When NOT to Use
1795
- - For files that should contain raw XML/HTML
1796
- - For JavaScript, CSS, or other non-XML files
1797
- - When escaping should be done manually
1798
-
1799
- # Parameters
1800
- - \`file_path\`: Path to the file to escape
1801
- - \`escape_all\`: (Optional) Also escape additional entities (©, ®, €)
1802
-
1803
- # Examples
1804
- - Escape XML content in HTML file
1805
- - Fix special characters in generated markup
1806
-
1807
- # Best Practices
1808
- - Backup files before escaping if unsure
2131
+ description = `Automatically escape special characters in XML/HTML files to make them valid.
2132
+
2133
+ # When to Use
2134
+ - When content contains special XML characters (<, >, &, ", ')
2135
+ - When generating XML/HTML from raw content
2136
+ - When fixing encoding issues in markup files
2137
+
2138
+ # When NOT to Use
2139
+ - For files that should contain raw XML/HTML
2140
+ - For JavaScript, CSS, or other non-XML files
2141
+ - When escaping should be done manually
2142
+
2143
+ # Parameters
2144
+ - \`file_path\`: Path to the file to escape
2145
+ - \`escape_all\`: (Optional) Also escape additional entities (©, ®, €)
2146
+
2147
+ # Examples
2148
+ - Escape XML content in HTML file
2149
+ - Fix special characters in generated markup
2150
+
2151
+ # Best Practices
2152
+ - Backup files before escaping if unsure
1809
2153
  - escape_all=true adds common HTML entities`;
1810
2154
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
1811
2155
  async execute(params) {
@@ -1861,32 +2205,32 @@ export class XmlEscapeTool {
1861
2205
  }
1862
2206
  export class ImageReadTool {
1863
2207
  name = 'image_read';
1864
- description = `Read image files and generate detailed analysis using a vision-language model.
1865
-
1866
- # When to Use
1867
- - Analyzing UI designs or mockups
1868
- - Examining screenshots or diagrams
1869
- - Extracting information from images
1870
- - Validating visual content or assets
1871
-
1872
- # When NOT to Use
1873
- - For text-based file analysis (use Read instead)
1874
- - When the image is not relevant to the task
1875
- - For very large images (may have size limits)
1876
-
1877
- # Parameters
1878
- - \`image_input\`: Path to image or base64 data
1879
- - \`prompt\`: Instructions for what to analyze
1880
- - \`input_type\`: (Optional) 'file_path' or 'base64'
1881
- - \`task_brief\`: (Optional) Brief task description
1882
-
1883
- # Examples
1884
- - Analyze UI mockup: image_read(image_input="design.png", prompt="Describe the UI components")
1885
- - Validate screenshot: image_read(image_input="screenshot.jpg", prompt="Check if login form is visible")
1886
-
1887
- # Best Practices
1888
- - Provide clear prompts for what to look for
1889
- - Use task_brief for context
2208
+ description = `Read image files and generate detailed analysis using a vision-language model.
2209
+
2210
+ # When to Use
2211
+ - Analyzing UI designs or mockups
2212
+ - Examining screenshots or diagrams
2213
+ - Extracting information from images
2214
+ - Validating visual content or assets
2215
+
2216
+ # When NOT to Use
2217
+ - For text-based file analysis (use Read instead)
2218
+ - When the image is not relevant to the task
2219
+ - For very large images (may have size limits)
2220
+
2221
+ # Parameters
2222
+ - \`image_input\`: Path to image or base64 data
2223
+ - \`prompt\`: Instructions for what to analyze
2224
+ - \`input_type\`: (Optional) 'file_path' or 'base64'
2225
+ - \`task_brief\`: (Optional) Brief task description
2226
+
2227
+ # Examples
2228
+ - Analyze UI mockup: image_read(image_input="design.png", prompt="Describe the UI components")
2229
+ - Validate screenshot: image_read(image_input="screenshot.jpg", prompt="Check if login form is visible")
2230
+
2231
+ # Best Practices
2232
+ - Provide clear prompts for what to look for
2233
+ - Use task_brief for context
1890
2234
  - Supports PNG, JPG, GIF, WEBP, SVG, BMP`;
1891
2235
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.PLAN, ExecutionMode.SMART];
1892
2236
  async execute(params) {
@@ -1990,31 +2334,31 @@ export class ImageReadTool {
1990
2334
  // }
1991
2335
  export class InvokeSkillTool {
1992
2336
  name = 'InvokeSkill';
1993
- description = `Invoke a specialized skill to handle domain-specific tasks. Skills are AI-powered capabilities that understand complex requirements and generate high-quality outputs (see Available Skills section below for the list of skills).
1994
-
1995
- # When to Use
1996
- - When user requests involve document processing (Word, PDF, PowerPoint)
1997
- - When user wants to create frontend interfaces or web applications
1998
- - When user needs visual design, posters, or generative art
1999
- - When user asks for documentation or internal communications
2000
- - When the task matches a specific skill domain
2001
-
2002
- # When NOT to Use
2003
- - For simple file operations (use Read/Write instead)
2004
- - For basic code changes (use Replace/Write instead)
2005
- - When a regular tool can accomplish the task
2006
-
2007
- # Parameters
2008
- - \`skillId\`: The skill identifier (see Available Skills section)
2009
- - \`taskDescription\`: Detailed description of what to accomplish
2010
- - \`inputFile\`: (Optional) Path to input file if applicable
2011
- - \`outputFile\`: (Optional) Desired output file path
2012
- - \`options\`: (Optional) Additional options for the skill
2013
-
2014
- # Best Practices
2015
- - Provide detailed task descriptions for better results
2016
- - Include relevant file paths when working with existing files
2017
- - Match the skill to the domain (e.g., don't use frontend-design for Word docs)
2337
+ description = `Invoke a specialized skill to handle domain-specific tasks. Skills are AI-powered capabilities that understand complex requirements and generate high-quality outputs (see Available Skills section below for the list of skills).
2338
+
2339
+ # When to Use
2340
+ - When user requests involve document processing (Word, PDF, PowerPoint)
2341
+ - When user wants to create frontend interfaces or web applications
2342
+ - When user needs visual design, posters, or generative art
2343
+ - When user asks for documentation or internal communications
2344
+ - When the task matches a specific skill domain
2345
+
2346
+ # When NOT to Use
2347
+ - For simple file operations (use Read/Write instead)
2348
+ - For basic code changes (use Edit/Write instead)
2349
+ - When a regular tool can accomplish the task
2350
+
2351
+ # Parameters
2352
+ - \`skillId\`: The skill identifier (see Available Skills section)
2353
+ - \`taskDescription\`: Detailed description of what to accomplish
2354
+ - \`inputFile\`: (Optional) Path to input file if applicable
2355
+ - \`outputFile\`: (Optional) Desired output file path
2356
+ - \`options\`: (Optional) Additional options for the skill
2357
+
2358
+ # Best Practices
2359
+ - Provide detailed task descriptions for better results
2360
+ - Include relevant file paths when working with existing files
2361
+ - Match the skill to the domain (e.g., don't use frontend-design for Word docs)
2018
2362
  - Skills will guide you through their specific workflows`;
2019
2363
  allowedModes = [ExecutionMode.YOLO, ExecutionMode.ACCEPT_EDITS, ExecutionMode.SMART];
2020
2364
  async execute(params, _executionMode) {
@@ -2161,10 +2505,10 @@ export class ToolRegistry {
2161
2505
  this.register(new GrepTool());
2162
2506
  this.register(new BashTool());
2163
2507
  this.register(new ListDirectoryTool());
2164
- this.register(new SearchCodebaseTool());
2508
+ this.register(new SearchFilesTool());
2165
2509
  this.register(new DeleteFileTool());
2166
2510
  this.register(new CreateDirectoryTool());
2167
- this.register(new ReplaceTool());
2511
+ this.register(new EditTool());
2168
2512
  this.register(new WebSearchTool());
2169
2513
  this.register(this.todoWriteTool);
2170
2514
  this.register(new TodoReadTool(this.todoWriteTool));
@@ -2393,7 +2737,7 @@ export class ToolRegistry {
2393
2737
  required: []
2394
2738
  };
2395
2739
  break;
2396
- case 'SearchCodebase':
2740
+ case 'SearchFiles':
2397
2741
  parameters = {
2398
2742
  type: 'object',
2399
2743
  properties: {
@@ -2404,6 +2748,10 @@ export class ToolRegistry {
2404
2748
  path: {
2405
2749
  type: 'string',
2406
2750
  description: 'Optional: The path to search in (default: current directory)'
2751
+ },
2752
+ limit: {
2753
+ type: 'integer',
2754
+ description: 'Optional: Maximum number of results to return (default: 1000)'
2407
2755
  }
2408
2756
  },
2409
2757
  required: ['pattern']
@@ -2437,13 +2785,13 @@ export class ToolRegistry {
2437
2785
  required: ['dirPath']
2438
2786
  };
2439
2787
  break;
2440
- case 'replace':
2788
+ case 'Edit':
2441
2789
  parameters = {
2442
2790
  type: 'object',
2443
2791
  properties: {
2444
2792
  file_path: {
2445
2793
  type: 'string',
2446
- description: 'The absolute path to the file'
2794
+ description: 'The absolute path to the file to edit'
2447
2795
  },
2448
2796
  instruction: {
2449
2797
  type: 'string',
@@ -2451,11 +2799,11 @@ export class ToolRegistry {
2451
2799
  },
2452
2800
  old_string: {
2453
2801
  type: 'string',
2454
- description: 'The exact text to replace'
2802
+ description: 'The exact text to replace (supports fuzzy matching)'
2455
2803
  },
2456
2804
  new_string: {
2457
2805
  type: 'string',
2458
- description: 'The exact text to replace with'
2806
+ description: 'The new text to replace with'
2459
2807
  }
2460
2808
  },
2461
2809
  required: ['file_path', 'instruction', 'old_string', 'new_string']