xibecode 0.3.5 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +80 -973
- package/dist/core/modes.d.ts +302 -14
- package/dist/core/modes.d.ts.map +1 -1
- package/dist/core/modes.js +74 -1
- package/dist/core/modes.js.map +1 -1
- package/dist/core/tools.d.ts +355 -0
- package/dist/core/tools.d.ts.map +1 -1
- package/dist/core/tools.js +460 -1
- package/dist/core/tools.js.map +1 -1
- package/dist/tools/browser.d.ts +112 -0
- package/dist/tools/browser.d.ts.map +1 -1
- package/dist/tools/browser.js +396 -13
- package/dist/tools/browser.js.map +1 -1
- package/package.json +18 -12
package/dist/core/tools.js
CHANGED
|
@@ -13,6 +13,51 @@ import { BrowserManager } from '../tools/browser.js';
|
|
|
13
13
|
import * as os from 'os';
|
|
14
14
|
import { SkillManager } from './skills.js';
|
|
15
15
|
const execAsync = promisify(exec);
|
|
16
|
+
/**
|
|
17
|
+
* Main tool executor for XibeCode agent
|
|
18
|
+
*
|
|
19
|
+
* Provides 95+ tools across 8 categories for autonomous coding operations:
|
|
20
|
+
* - File Operations: read, write, edit, delete files
|
|
21
|
+
* - Git Operations: status, diff, commit, reset
|
|
22
|
+
* - Shell Commands: run commands, interactive shell
|
|
23
|
+
* - Web Operations: search, fetch URLs, HTTP requests
|
|
24
|
+
* - Context Operations: code search, file finding, context discovery
|
|
25
|
+
* - Test Operations: run tests, get results
|
|
26
|
+
* - Memory Operations: update neural memory
|
|
27
|
+
* - Browser Operations: web automation with Playwright
|
|
28
|
+
*
|
|
29
|
+
* Features:
|
|
30
|
+
* - Mode-based tool permissions
|
|
31
|
+
* - Safety checking for dangerous operations
|
|
32
|
+
* - Plugin support for custom tools
|
|
33
|
+
* - MCP integration for external tools
|
|
34
|
+
* - Dry-run mode for safe previews
|
|
35
|
+
* - Backup system for file operations
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const executor = new CodingToolExecutor('/project', {
|
|
40
|
+
* dryRun: false,
|
|
41
|
+
* pluginManager,
|
|
42
|
+
* memory
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* executor.setMode('agent');
|
|
46
|
+
*
|
|
47
|
+
* // Read a file
|
|
48
|
+
* const result = await executor.execute('read_file', { path: 'src/app.ts' });
|
|
49
|
+
*
|
|
50
|
+
* // Edit a file
|
|
51
|
+
* await executor.execute('edit_file', {
|
|
52
|
+
* path: 'src/app.ts',
|
|
53
|
+
* search: 'old code',
|
|
54
|
+
* replace: 'new code'
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @category Tool Execution
|
|
59
|
+
* @since 0.1.0
|
|
60
|
+
*/
|
|
16
61
|
export class CodingToolExecutor {
|
|
17
62
|
workingDir;
|
|
18
63
|
contextManager;
|
|
@@ -28,6 +73,37 @@ export class CodingToolExecutor {
|
|
|
28
73
|
platform;
|
|
29
74
|
dryRun;
|
|
30
75
|
testCommandOverride;
|
|
76
|
+
/**
|
|
77
|
+
* Creates a new CodingToolExecutor instance
|
|
78
|
+
*
|
|
79
|
+
* Initializes all tool subsystems including file operations, git utilities,
|
|
80
|
+
* test runner, safety checker, plugin manager, and optional MCP integration.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* // Basic usage
|
|
85
|
+
* const executor = new CodingToolExecutor('/project');
|
|
86
|
+
*
|
|
87
|
+
* // With options
|
|
88
|
+
* const executor = new CodingToolExecutor('/project', {
|
|
89
|
+
* dryRun: true,
|
|
90
|
+
* pluginManager: new PluginManager(),
|
|
91
|
+
* memory: new NeuralMemory('./.xibecode/memory.json')
|
|
92
|
+
* });
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @param workingDir - Working directory for file operations (default: process.cwd())
|
|
96
|
+
* @param options - Configuration options
|
|
97
|
+
* @param options.dryRun - Enable dry-run mode (preview changes without executing)
|
|
98
|
+
* @param options.testCommandOverride - Override test command detection
|
|
99
|
+
* @param options.pluginManager - Plugin manager instance for custom tools
|
|
100
|
+
* @param options.mcpClientManager - MCP client manager for external tool integration
|
|
101
|
+
* @param options.memory - Neural memory instance for persistent learning
|
|
102
|
+
* @param options.skillManager - Skill manager for loading custom workflows
|
|
103
|
+
*
|
|
104
|
+
* @category Constructor
|
|
105
|
+
* @since 0.1.0
|
|
106
|
+
*/
|
|
31
107
|
constructor(workingDir = process.cwd(), options) {
|
|
32
108
|
this.workingDir = workingDir;
|
|
33
109
|
this.contextManager = new ContextManager(workingDir);
|
|
@@ -46,6 +122,26 @@ export class CodingToolExecutor {
|
|
|
46
122
|
this.testCommandOverride = options?.testCommandOverride;
|
|
47
123
|
}
|
|
48
124
|
currentMode = 'agent';
|
|
125
|
+
/**
|
|
126
|
+
* Set the current agent mode
|
|
127
|
+
*
|
|
128
|
+
* Changes the tool executor's operating mode, which affects:
|
|
129
|
+
* - Tool permissions (what tools are available)
|
|
130
|
+
* - Dry-run default (some modes preview changes by default)
|
|
131
|
+
* - Risk tolerance for operations
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* executor.setMode('plan'); // Read-only mode
|
|
136
|
+
* executor.setMode('agent'); // Full capabilities
|
|
137
|
+
* executor.setMode('security'); // Security-focused mode
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* @param mode - Agent mode to switch to
|
|
141
|
+
*
|
|
142
|
+
* @category Mode Management
|
|
143
|
+
* @since 0.1.0
|
|
144
|
+
*/
|
|
49
145
|
setMode(mode) {
|
|
50
146
|
this.currentMode = mode;
|
|
51
147
|
const config = MODE_CONFIG[mode];
|
|
@@ -53,6 +149,11 @@ export class CodingToolExecutor {
|
|
|
53
149
|
}
|
|
54
150
|
/**
|
|
55
151
|
* Safely parse tool input - handles string JSON, null, undefined
|
|
152
|
+
*
|
|
153
|
+
* @param input - Raw tool input (string, object, null, or undefined)
|
|
154
|
+
* @returns Parsed input as object
|
|
155
|
+
*
|
|
156
|
+
* @internal
|
|
56
157
|
*/
|
|
57
158
|
parseInput(input) {
|
|
58
159
|
if (!input)
|
|
@@ -69,6 +170,49 @@ export class CodingToolExecutor {
|
|
|
69
170
|
return input;
|
|
70
171
|
return {};
|
|
71
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Execute a tool with given input
|
|
175
|
+
*
|
|
176
|
+
* Main tool execution pipeline that:
|
|
177
|
+
* 1. Checks tool permissions for current mode
|
|
178
|
+
* 2. Routes MCP tools to external servers
|
|
179
|
+
* 3. Routes plugin tools to plugin manager
|
|
180
|
+
* 4. Performs safety assessment for risky operations
|
|
181
|
+
* 5. Executes the tool implementation
|
|
182
|
+
* 6. Returns structured result
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* // Read a file
|
|
187
|
+
* const result = await executor.execute('read_file', {
|
|
188
|
+
* path: 'src/app.ts'
|
|
189
|
+
* });
|
|
190
|
+
*
|
|
191
|
+
* if (result.success) {
|
|
192
|
+
* console.log(result.content);
|
|
193
|
+
* }
|
|
194
|
+
*
|
|
195
|
+
* // Edit a file
|
|
196
|
+
* await executor.execute('edit_file', {
|
|
197
|
+
* path: 'src/app.ts',
|
|
198
|
+
* search: 'const old = 1;',
|
|
199
|
+
* replace: 'const new = 2;'
|
|
200
|
+
* });
|
|
201
|
+
*
|
|
202
|
+
* // Run a command
|
|
203
|
+
* await executor.execute('run_command', {
|
|
204
|
+
* command: 'npm test'
|
|
205
|
+
* });
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @param toolName - Name of the tool to execute (e.g., 'read_file', 'edit_file')
|
|
209
|
+
* @param input - Tool input parameters (varies by tool)
|
|
210
|
+
* @returns Tool execution result with success/error status
|
|
211
|
+
*
|
|
212
|
+
* @see {@link getTools} for list of available tools
|
|
213
|
+
* @category Tool Execution
|
|
214
|
+
* @since 0.1.0
|
|
215
|
+
*/
|
|
72
216
|
async execute(toolName, input) {
|
|
73
217
|
// Check tool permissions first
|
|
74
218
|
const permission = isToolAllowed(this.currentMode, toolName);
|
|
@@ -327,6 +471,44 @@ export class CodingToolExecutor {
|
|
|
327
471
|
return { error: true, success: false, message: 'Missing url' };
|
|
328
472
|
return this.browserManager.getConsoleLogs(p.url);
|
|
329
473
|
}
|
|
474
|
+
case 'run_visual_test': {
|
|
475
|
+
if (!p.url || typeof p.url !== 'string')
|
|
476
|
+
return { error: true, success: false, message: 'Missing url' };
|
|
477
|
+
if (!p.baseline_path || typeof p.baseline_path !== 'string')
|
|
478
|
+
return { error: true, success: false, message: 'Missing baseline_path' };
|
|
479
|
+
const outputDir = p.output_dir || '.playwright-baselines';
|
|
480
|
+
return this.browserManager.runVisualTest(p.url, this.resolvePath(p.baseline_path), this.resolvePath(outputDir));
|
|
481
|
+
}
|
|
482
|
+
case 'check_accessibility': {
|
|
483
|
+
if (!p.url || typeof p.url !== 'string')
|
|
484
|
+
return { error: true, success: false, message: 'Missing url' };
|
|
485
|
+
return this.browserManager.checkAccessibility(p.url);
|
|
486
|
+
}
|
|
487
|
+
case 'measure_performance': {
|
|
488
|
+
if (!p.url || typeof p.url !== 'string')
|
|
489
|
+
return { error: true, success: false, message: 'Missing url' };
|
|
490
|
+
return this.browserManager.measurePerformance(p.url);
|
|
491
|
+
}
|
|
492
|
+
case 'test_responsive': {
|
|
493
|
+
if (!p.url || typeof p.url !== 'string')
|
|
494
|
+
return { error: true, success: false, message: 'Missing url' };
|
|
495
|
+
const outputDir = p.output_dir || '.responsive-screenshots';
|
|
496
|
+
return this.browserManager.testResponsive(p.url, this.resolvePath(outputDir), p.viewports);
|
|
497
|
+
}
|
|
498
|
+
case 'capture_network': {
|
|
499
|
+
if (!p.url || typeof p.url !== 'string')
|
|
500
|
+
return { error: true, success: false, message: 'Missing url' };
|
|
501
|
+
return this.browserManager.captureNetworkRequests(p.url);
|
|
502
|
+
}
|
|
503
|
+
case 'run_playwright_test': {
|
|
504
|
+
if (!p.test_path || typeof p.test_path !== 'string')
|
|
505
|
+
return { error: true, success: false, message: 'Missing test_path' };
|
|
506
|
+
return this.browserManager.runPlaywrightTest(this.resolvePath(p.test_path), {
|
|
507
|
+
headed: p.headed,
|
|
508
|
+
browser: p.browser,
|
|
509
|
+
timeout: p.timeout,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
330
512
|
case 'search_skills_sh': {
|
|
331
513
|
if (!p.query || typeof p.query !== 'string') {
|
|
332
514
|
return { error: true, success: false, message: 'Missing required parameter: query (string)' };
|
|
@@ -340,9 +522,43 @@ export class CodingToolExecutor {
|
|
|
340
522
|
return this.installSkillFromSkillsSh(p.skill_id);
|
|
341
523
|
}
|
|
342
524
|
default:
|
|
343
|
-
return { error: true, success: false, message: `Unknown tool: ${toolName}. Available tools: read_file, read_multiple_files, write_file, edit_file, edit_lines, insert_at_line, verified_edit, list_directory, search_files, run_command, create_directory, delete_file, move_file, get_context, revert_file, run_tests, get_test_status, get_git_status, get_git_diff_summary, get_git_changed_files, create_git_checkpoint, revert_to_git_checkpoint, git_show_diff, get_mcp_status, grep_code, web_search, fetch_url, remember_lesson, take_screenshot, get_console_logs, search_skills_sh, install_skill_from_skills_sh` };
|
|
525
|
+
return { error: true, success: false, message: `Unknown tool: ${toolName}. Available tools: read_file, read_multiple_files, write_file, edit_file, edit_lines, insert_at_line, verified_edit, list_directory, search_files, run_command, create_directory, delete_file, move_file, get_context, revert_file, run_tests, get_test_status, get_git_status, get_git_diff_summary, get_git_changed_files, create_git_checkpoint, revert_to_git_checkpoint, git_show_diff, get_mcp_status, grep_code, web_search, fetch_url, remember_lesson, take_screenshot, get_console_logs, run_visual_test, check_accessibility, measure_performance, test_responsive, capture_network, run_playwright_test, search_skills_sh, install_skill_from_skills_sh` };
|
|
344
526
|
}
|
|
345
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Get all available tools for the agent
|
|
530
|
+
*
|
|
531
|
+
* Returns an array of tool definitions including core tools, plugin tools,
|
|
532
|
+
* and MCP tools. Each tool includes:
|
|
533
|
+
* - name: Tool identifier
|
|
534
|
+
* - description: What the tool does (for Claude AI)
|
|
535
|
+
* - input_schema: JSON Schema for input validation
|
|
536
|
+
*
|
|
537
|
+
* Tools are grouped by category:
|
|
538
|
+
* - File Operations: read_file, write_file, edit_file, etc.
|
|
539
|
+
* - Git Operations: get_git_status, git_commit, etc.
|
|
540
|
+
* - Shell Commands: run_command, interactive_shell
|
|
541
|
+
* - Web Operations: web_search, fetch_url, http_request
|
|
542
|
+
* - Context Operations: grep_code, search_files, get_context
|
|
543
|
+
* - Test Operations: run_tests, get_test_status
|
|
544
|
+
* - Memory Operations: update_memory
|
|
545
|
+
* - Browser Operations: open_browser, browser_click, etc.
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* const tools = executor.getTools();
|
|
550
|
+
* console.log(`${tools.length} tools available`);
|
|
551
|
+
*
|
|
552
|
+
* // Find a specific tool
|
|
553
|
+
* const readFile = tools.find(t => t.name === 'read_file');
|
|
554
|
+
* console.log(readFile.description);
|
|
555
|
+
* ```
|
|
556
|
+
*
|
|
557
|
+
* @returns Array of tool definitions with schemas
|
|
558
|
+
*
|
|
559
|
+
* @category Tool Management
|
|
560
|
+
* @since 0.1.0
|
|
561
|
+
*/
|
|
346
562
|
getTools() {
|
|
347
563
|
const coreTools = [
|
|
348
564
|
{
|
|
@@ -852,6 +1068,90 @@ export class CodingToolExecutor {
|
|
|
852
1068
|
required: ['url']
|
|
853
1069
|
}
|
|
854
1070
|
},
|
|
1071
|
+
{
|
|
1072
|
+
name: 'run_visual_test',
|
|
1073
|
+
description: 'Run visual regression testing by comparing screenshots. Creates baseline on first run, then compares subsequent screenshots against it. Perfect for catching unintended UI changes.',
|
|
1074
|
+
input_schema: {
|
|
1075
|
+
type: 'object',
|
|
1076
|
+
properties: {
|
|
1077
|
+
url: { type: 'string', description: 'URL to test (e.g., http://localhost:3000)' },
|
|
1078
|
+
baseline_path: { type: 'string', description: 'Path to baseline screenshot file (e.g., baselines/homepage.png)' },
|
|
1079
|
+
output_dir: { type: 'string', description: 'Directory for test output (default: .playwright-baselines)' }
|
|
1080
|
+
},
|
|
1081
|
+
required: ['url', 'baseline_path']
|
|
1082
|
+
}
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
name: 'check_accessibility',
|
|
1086
|
+
description: 'Run accessibility audit on a webpage. Checks for missing alt text, form labels, heading hierarchy, color contrast, and other WCAG issues. Returns errors, warnings, and notices.',
|
|
1087
|
+
input_schema: {
|
|
1088
|
+
type: 'object',
|
|
1089
|
+
properties: {
|
|
1090
|
+
url: { type: 'string', description: 'URL to audit (e.g., http://localhost:3000)' }
|
|
1091
|
+
},
|
|
1092
|
+
required: ['url']
|
|
1093
|
+
}
|
|
1094
|
+
},
|
|
1095
|
+
{
|
|
1096
|
+
name: 'measure_performance',
|
|
1097
|
+
description: 'Measure Core Web Vitals and performance metrics: First Contentful Paint (FCP), Largest Contentful Paint (LCP), Cumulative Layout Shift (CLS), Time to Interactive (TTI), and DOM Content Loaded. Essential for UX and SEO.',
|
|
1098
|
+
input_schema: {
|
|
1099
|
+
type: 'object',
|
|
1100
|
+
properties: {
|
|
1101
|
+
url: { type: 'string', description: 'URL to measure (e.g., http://localhost:3000)' }
|
|
1102
|
+
},
|
|
1103
|
+
required: ['url']
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
{
|
|
1107
|
+
name: 'test_responsive',
|
|
1108
|
+
description: 'Test a page across multiple viewport sizes (mobile, tablet, desktop). Takes screenshots at each breakpoint and reports any JavaScript errors. Perfect for responsive design testing.',
|
|
1109
|
+
input_schema: {
|
|
1110
|
+
type: 'object',
|
|
1111
|
+
properties: {
|
|
1112
|
+
url: { type: 'string', description: 'URL to test (e.g., http://localhost:3000)' },
|
|
1113
|
+
output_dir: { type: 'string', description: 'Directory for screenshots (default: .responsive-screenshots)' },
|
|
1114
|
+
viewports: {
|
|
1115
|
+
type: 'array',
|
|
1116
|
+
items: {
|
|
1117
|
+
type: 'object',
|
|
1118
|
+
properties: {
|
|
1119
|
+
name: { type: 'string' },
|
|
1120
|
+
width: { type: 'number' },
|
|
1121
|
+
height: { type: 'number' }
|
|
1122
|
+
}
|
|
1123
|
+
},
|
|
1124
|
+
description: 'Custom viewports. Default: mobile (375x667), tablet (768x1024), desktop (1280x800), desktop-large (1920x1080)'
|
|
1125
|
+
}
|
|
1126
|
+
},
|
|
1127
|
+
required: ['url']
|
|
1128
|
+
}
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
name: 'capture_network',
|
|
1132
|
+
description: 'Capture all network requests made during page load. Shows URLs, methods, status codes, resource types, and timing. Useful for debugging API calls, detecting failed requests, and performance analysis.',
|
|
1133
|
+
input_schema: {
|
|
1134
|
+
type: 'object',
|
|
1135
|
+
properties: {
|
|
1136
|
+
url: { type: 'string', description: 'URL to load and monitor (e.g., http://localhost:3000)' }
|
|
1137
|
+
},
|
|
1138
|
+
required: ['url']
|
|
1139
|
+
}
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
name: 'run_playwright_test',
|
|
1143
|
+
description: 'Execute a Playwright test file. Runs the test and returns pass/fail results with output. Great for running E2E tests, integration tests, and component tests.',
|
|
1144
|
+
input_schema: {
|
|
1145
|
+
type: 'object',
|
|
1146
|
+
properties: {
|
|
1147
|
+
test_path: { type: 'string', description: 'Path to the Playwright test file (e.g., tests/homepage.spec.ts)' },
|
|
1148
|
+
headed: { type: 'boolean', description: 'Run with visible browser window (default: false)' },
|
|
1149
|
+
browser: { type: 'string', enum: ['chromium', 'firefox', 'webkit'], description: 'Browser to use (default: chromium)' },
|
|
1150
|
+
timeout: { type: 'number', description: 'Test timeout in milliseconds (default: 120000)' }
|
|
1151
|
+
},
|
|
1152
|
+
required: ['test_path']
|
|
1153
|
+
}
|
|
1154
|
+
},
|
|
855
1155
|
{
|
|
856
1156
|
name: 'fetch_url',
|
|
857
1157
|
description: 'Fetch and read content from any URL. HTML is automatically stripped to plain text. Use this to read documentation pages, API references, blog posts, or any web content. Supports HTML, JSON, and plain text.',
|
|
@@ -933,9 +1233,50 @@ export class CodingToolExecutor {
|
|
|
933
1233
|
const pluginTools = this.pluginManager.getPluginTools();
|
|
934
1234
|
return [...coreTools, ...mcpTools, ...pluginTools];
|
|
935
1235
|
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Resolve relative file path to absolute path
|
|
1238
|
+
*
|
|
1239
|
+
* @param filePath - Relative or absolute file path
|
|
1240
|
+
* @returns Absolute path resolved against working directory
|
|
1241
|
+
*
|
|
1242
|
+
* @internal
|
|
1243
|
+
*/
|
|
936
1244
|
resolvePath(filePath) {
|
|
937
1245
|
return path.resolve(this.workingDir, filePath);
|
|
938
1246
|
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Read file contents
|
|
1249
|
+
*
|
|
1250
|
+
* Reads a file from the filesystem. Supports partial reading by line range
|
|
1251
|
+
* to avoid token limits for large files. Always returns UTF-8 encoded text.
|
|
1252
|
+
*
|
|
1253
|
+
* @example
|
|
1254
|
+
* ```typescript
|
|
1255
|
+
* // Read entire file
|
|
1256
|
+
* const result = await executor.execute('read_file', {
|
|
1257
|
+
* path: 'src/app.ts'
|
|
1258
|
+
* });
|
|
1259
|
+
*
|
|
1260
|
+
* // Read specific line range
|
|
1261
|
+
* const partial = await executor.execute('read_file', {
|
|
1262
|
+
* path: 'src/large-file.ts',
|
|
1263
|
+
* start_line: 100,
|
|
1264
|
+
* end_line: 200
|
|
1265
|
+
* });
|
|
1266
|
+
* ```
|
|
1267
|
+
*
|
|
1268
|
+
* @param filePath - Path to file (relative to working directory)
|
|
1269
|
+
* @param startLine - Optional start line for partial read (1-indexed)
|
|
1270
|
+
* @param endLine - Optional end line for partial read (inclusive)
|
|
1271
|
+
* @returns Object with path, content, and line info
|
|
1272
|
+
*
|
|
1273
|
+
* @throws {FileNotFoundError} If file doesn't exist
|
|
1274
|
+
* @throws {PermissionError} If file is not readable
|
|
1275
|
+
*
|
|
1276
|
+
* @category File Operations
|
|
1277
|
+
* @mode All modes
|
|
1278
|
+
* @since 0.1.0
|
|
1279
|
+
*/
|
|
939
1280
|
async readFile(filePath, startLine, endLine) {
|
|
940
1281
|
const fullPath = this.resolvePath(filePath);
|
|
941
1282
|
try {
|
|
@@ -977,6 +1318,33 @@ export class CodingToolExecutor {
|
|
|
977
1318
|
.map((r, i) => ({ path: paths[i], error: r.reason.message })),
|
|
978
1319
|
};
|
|
979
1320
|
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Write content to file
|
|
1323
|
+
*
|
|
1324
|
+
* Creates or overwrites a file with the given content. Automatically creates
|
|
1325
|
+
* parent directories if they don't exist. Creates a backup before overwriting
|
|
1326
|
+
* existing files.
|
|
1327
|
+
*
|
|
1328
|
+
* In dry-run mode, shows what would be written without making changes.
|
|
1329
|
+
*
|
|
1330
|
+
* @example
|
|
1331
|
+
* ```typescript
|
|
1332
|
+
* await executor.execute('write_file', {
|
|
1333
|
+
* path: 'src/new-file.ts',
|
|
1334
|
+
* content: 'export const hello = "world";'
|
|
1335
|
+
* });
|
|
1336
|
+
* ```
|
|
1337
|
+
*
|
|
1338
|
+
* @param filePath - Path to file (relative to working directory)
|
|
1339
|
+
* @param content - File content to write
|
|
1340
|
+
* @returns Object with success status, path, and file info
|
|
1341
|
+
*
|
|
1342
|
+
* @throws {PermissionError} If directory is not writable
|
|
1343
|
+
*
|
|
1344
|
+
* @category File Operations
|
|
1345
|
+
* @mode Write modes (agent, engineer, architect)
|
|
1346
|
+
* @since 0.1.0
|
|
1347
|
+
*/
|
|
980
1348
|
async writeFile(filePath, content) {
|
|
981
1349
|
const fullPath = this.resolvePath(filePath);
|
|
982
1350
|
if (this.dryRun) {
|
|
@@ -1005,6 +1373,47 @@ export class CodingToolExecutor {
|
|
|
1005
1373
|
return { error: true, success: false, message: `Failed to write ${filePath}: ${error.message}` };
|
|
1006
1374
|
}
|
|
1007
1375
|
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Edit file using search and replace
|
|
1378
|
+
*
|
|
1379
|
+
* Performs intelligent search-and-replace editing using the FileEditor's
|
|
1380
|
+
* smart edit strategy. Searches for exact string matches and replaces them.
|
|
1381
|
+
* Automatically handles multi-line strings and special characters.
|
|
1382
|
+
*
|
|
1383
|
+
* Creates a backup before editing. In dry-run mode, shows what would be
|
|
1384
|
+
* changed without modifying the file.
|
|
1385
|
+
*
|
|
1386
|
+
* @example
|
|
1387
|
+
* ```typescript
|
|
1388
|
+
* // Replace first occurrence
|
|
1389
|
+
* await executor.execute('edit_file', {
|
|
1390
|
+
* path: 'src/app.ts',
|
|
1391
|
+
* search: 'const oldValue = 1;',
|
|
1392
|
+
* replace: 'const newValue = 2;'
|
|
1393
|
+
* });
|
|
1394
|
+
*
|
|
1395
|
+
* // Replace all occurrences
|
|
1396
|
+
* await executor.execute('edit_file', {
|
|
1397
|
+
* path: 'src/app.ts',
|
|
1398
|
+
* search: 'oldName',
|
|
1399
|
+
* replace: 'newName',
|
|
1400
|
+
* all: true
|
|
1401
|
+
* });
|
|
1402
|
+
* ```
|
|
1403
|
+
*
|
|
1404
|
+
* @param filePath - Path to file (relative to working directory)
|
|
1405
|
+
* @param search - Exact string to search for (can be multi-line)
|
|
1406
|
+
* @param replace - Replacement string
|
|
1407
|
+
* @param all - Replace all occurrences (default: false, replaces first only)
|
|
1408
|
+
* @returns Object with success status, changes made, and diff
|
|
1409
|
+
*
|
|
1410
|
+
* @throws {FileNotFoundError} If file doesn't exist
|
|
1411
|
+
* @throws {SearchNotFoundError} If search string not found
|
|
1412
|
+
*
|
|
1413
|
+
* @category File Operations
|
|
1414
|
+
* @mode Write modes (agent, engineer, architect)
|
|
1415
|
+
* @since 0.1.0
|
|
1416
|
+
*/
|
|
1008
1417
|
async editFile(filePath, search, replace, all) {
|
|
1009
1418
|
if (this.dryRun) {
|
|
1010
1419
|
return {
|
|
@@ -1097,6 +1506,56 @@ export class CodingToolExecutor {
|
|
|
1097
1506
|
return { error: true, success: false, message: `Failed to search files: ${error.message}` };
|
|
1098
1507
|
}
|
|
1099
1508
|
}
|
|
1509
|
+
/**
|
|
1510
|
+
* Execute a shell command
|
|
1511
|
+
*
|
|
1512
|
+
* Runs a command in a shell (bash on Unix, PowerShell on Windows).
|
|
1513
|
+
* Captures stdout and stderr. Supports stdin input for interactive commands.
|
|
1514
|
+
* Automatically times out after 120 seconds (configurable).
|
|
1515
|
+
*
|
|
1516
|
+
* Safety checks are performed before execution to block dangerous commands
|
|
1517
|
+
* like `rm -rf /`, malicious scripts, and other high-risk operations.
|
|
1518
|
+
*
|
|
1519
|
+
* @example
|
|
1520
|
+
* ```typescript
|
|
1521
|
+
* // Run a simple command
|
|
1522
|
+
* const result = await executor.execute('run_command', {
|
|
1523
|
+
* command: 'npm test'
|
|
1524
|
+
* });
|
|
1525
|
+
*
|
|
1526
|
+
* // Run with specific working directory
|
|
1527
|
+
* await executor.execute('run_command', {
|
|
1528
|
+
* command: 'ls -la',
|
|
1529
|
+
* cwd: './src'
|
|
1530
|
+
* });
|
|
1531
|
+
*
|
|
1532
|
+
* // Run with stdin input
|
|
1533
|
+
* await executor.execute('run_command', {
|
|
1534
|
+
* command: 'cat > output.txt',
|
|
1535
|
+
* input: 'Hello World'
|
|
1536
|
+
* });
|
|
1537
|
+
*
|
|
1538
|
+
* // Run with custom timeout
|
|
1539
|
+
* await executor.execute('run_command', {
|
|
1540
|
+
* command: 'npm install',
|
|
1541
|
+
* timeout: 300 // 5 minutes
|
|
1542
|
+
* });
|
|
1543
|
+
* ```
|
|
1544
|
+
*
|
|
1545
|
+
* @param command - Shell command to execute
|
|
1546
|
+
* @param cwd - Working directory (default: executor's working directory)
|
|
1547
|
+
* @param input - Optional stdin input for interactive commands
|
|
1548
|
+
* @param timeout - Timeout in seconds (default: 120)
|
|
1549
|
+
* @returns Object with stdout, stderr, exit code, and execution time
|
|
1550
|
+
*
|
|
1551
|
+
* @throws {SafetyError} If command is blocked by safety checker
|
|
1552
|
+
* @throws {TimeoutError} If command exceeds timeout
|
|
1553
|
+
*
|
|
1554
|
+
* @category Shell Commands
|
|
1555
|
+
* @mode Command modes (agent, engineer, debugger, tester)
|
|
1556
|
+
* @risk-level High
|
|
1557
|
+
* @since 0.1.0
|
|
1558
|
+
*/
|
|
1100
1559
|
async runCommand(command, cwd, input, timeout) {
|
|
1101
1560
|
const workDir = cwd ? this.resolvePath(cwd) : this.workingDir;
|
|
1102
1561
|
const timeoutMs = (timeout || 120) * 1000;
|