xibecode 0.0.1
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/README.md +434 -0
- package/dist/commands/chat.d.ts +8 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +259 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/config.d.ts +10 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +196 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/run.d.ts +11 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +143 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/core/agent.d.ts +49 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +392 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/context.d.ts +82 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +273 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/editor.d.ts +68 -0
- package/dist/core/editor.d.ts.map +1 -0
- package/dist/core/editor.js +271 -0
- package/dist/core/editor.js.map +1 -0
- package/dist/core/tools.d.ts +34 -0
- package/dist/core/tools.d.ts.map +1 -0
- package/dist/core/tools.js +675 -0
- package/dist/core/tools.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/ui/enhanced-tui.d.ts +51 -0
- package/dist/ui/enhanced-tui.d.ts.map +1 -0
- package/dist/ui/enhanced-tui.js +438 -0
- package/dist/ui/enhanced-tui.js.map +1 -0
- package/dist/utils/config.d.ts +76 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +144 -0
- package/dist/utils/config.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import fg from 'fast-glob';
|
|
4
|
+
export class ContextManager {
|
|
5
|
+
workingDir;
|
|
6
|
+
maxContextTokens = 100000; // ~100k tokens
|
|
7
|
+
loadedFiles = new Map();
|
|
8
|
+
// Files to exclude from context
|
|
9
|
+
excludePatterns = [
|
|
10
|
+
'**/node_modules/**',
|
|
11
|
+
'**/dist/**',
|
|
12
|
+
'**/build/**',
|
|
13
|
+
'**/.git/**',
|
|
14
|
+
'**/coverage/**',
|
|
15
|
+
'**/*.min.js',
|
|
16
|
+
'**/*.map',
|
|
17
|
+
'**/package-lock.json',
|
|
18
|
+
'**/yarn.lock',
|
|
19
|
+
];
|
|
20
|
+
constructor(workingDir, maxTokens) {
|
|
21
|
+
this.workingDir = workingDir;
|
|
22
|
+
if (maxTokens)
|
|
23
|
+
this.maxContextTokens = maxTokens;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Smart context builder - automatically includes relevant files
|
|
27
|
+
*/
|
|
28
|
+
async buildContext(primaryFiles = []) {
|
|
29
|
+
const context = {
|
|
30
|
+
files: [],
|
|
31
|
+
totalTokens: 0,
|
|
32
|
+
maxTokens: this.maxContextTokens,
|
|
33
|
+
};
|
|
34
|
+
// Load primary files first (highest priority)
|
|
35
|
+
for (const filePath of primaryFiles) {
|
|
36
|
+
const fileContext = await this.loadFile(filePath);
|
|
37
|
+
if (fileContext) {
|
|
38
|
+
context.files.push(fileContext);
|
|
39
|
+
context.totalTokens += this.estimateTokens(fileContext.content);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Auto-discover related files
|
|
43
|
+
const relatedFiles = await this.findRelatedFiles(primaryFiles);
|
|
44
|
+
for (const filePath of relatedFiles) {
|
|
45
|
+
if (context.totalTokens >= this.maxContextTokens * 0.8) {
|
|
46
|
+
break; // Stop at 80% capacity
|
|
47
|
+
}
|
|
48
|
+
if (!this.loadedFiles.has(filePath)) {
|
|
49
|
+
const fileContext = await this.loadFile(filePath);
|
|
50
|
+
if (fileContext) {
|
|
51
|
+
context.files.push(fileContext);
|
|
52
|
+
context.totalTokens += this.estimateTokens(fileContext.content);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return context;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Load a single file with metadata
|
|
60
|
+
*/
|
|
61
|
+
async loadFile(filePath) {
|
|
62
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
63
|
+
try {
|
|
64
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
65
|
+
const stats = await fs.stat(fullPath);
|
|
66
|
+
// Skip binary files or very large files
|
|
67
|
+
if (stats.size > 1024 * 1024) { // 1MB limit
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const fileContext = {
|
|
71
|
+
path: filePath,
|
|
72
|
+
content,
|
|
73
|
+
lines: content.split('\n').length,
|
|
74
|
+
size: stats.size,
|
|
75
|
+
language: this.detectLanguage(filePath),
|
|
76
|
+
};
|
|
77
|
+
this.loadedFiles.set(filePath, fileContext);
|
|
78
|
+
return fileContext;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Find files related to the given files (imports, configs, tests)
|
|
86
|
+
*/
|
|
87
|
+
async findRelatedFiles(files) {
|
|
88
|
+
const related = new Set();
|
|
89
|
+
for (const file of files) {
|
|
90
|
+
const fileContext = this.loadedFiles.get(file);
|
|
91
|
+
if (!fileContext)
|
|
92
|
+
continue;
|
|
93
|
+
// Find imports/requires
|
|
94
|
+
const imports = this.extractImports(fileContext.content);
|
|
95
|
+
for (const imp of imports) {
|
|
96
|
+
const resolved = await this.resolveImport(imp, file);
|
|
97
|
+
if (resolved)
|
|
98
|
+
related.add(resolved);
|
|
99
|
+
}
|
|
100
|
+
// Find test files
|
|
101
|
+
const testFile = this.findTestFile(file);
|
|
102
|
+
if (testFile) {
|
|
103
|
+
const exists = await this.fileExists(testFile);
|
|
104
|
+
if (exists)
|
|
105
|
+
related.add(testFile);
|
|
106
|
+
}
|
|
107
|
+
// Find config files in same directory
|
|
108
|
+
const dir = path.dirname(file);
|
|
109
|
+
const configs = await this.findConfigFiles(dir);
|
|
110
|
+
configs.forEach(c => related.add(c));
|
|
111
|
+
}
|
|
112
|
+
return Array.from(related);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Extract import statements from code
|
|
116
|
+
*/
|
|
117
|
+
extractImports(content) {
|
|
118
|
+
const imports = [];
|
|
119
|
+
// ES6 imports
|
|
120
|
+
const es6Regex = /import\s+.*?\s+from\s+['"](.+?)['"]/g;
|
|
121
|
+
let match;
|
|
122
|
+
while ((match = es6Regex.exec(content)) !== null) {
|
|
123
|
+
imports.push(match[1]);
|
|
124
|
+
}
|
|
125
|
+
// CommonJS requires
|
|
126
|
+
const cjsRegex = /require\s*\(\s*['"](.+?)['"]\s*\)/g;
|
|
127
|
+
while ((match = cjsRegex.exec(content)) !== null) {
|
|
128
|
+
imports.push(match[1]);
|
|
129
|
+
}
|
|
130
|
+
return imports;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Resolve import path to actual file
|
|
134
|
+
*/
|
|
135
|
+
async resolveImport(importPath, fromFile) {
|
|
136
|
+
// Skip node_modules
|
|
137
|
+
if (!importPath.startsWith('.'))
|
|
138
|
+
return null;
|
|
139
|
+
const dir = path.dirname(fromFile);
|
|
140
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx', ''];
|
|
141
|
+
for (const ext of extensions) {
|
|
142
|
+
const resolved = path.join(dir, importPath + ext);
|
|
143
|
+
if (await this.fileExists(resolved)) {
|
|
144
|
+
return resolved;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Find test file for a given source file
|
|
151
|
+
*/
|
|
152
|
+
findTestFile(filePath) {
|
|
153
|
+
const parsed = path.parse(filePath);
|
|
154
|
+
const testPatterns = [
|
|
155
|
+
`${parsed.name}.test${parsed.ext}`,
|
|
156
|
+
`${parsed.name}.spec${parsed.ext}`,
|
|
157
|
+
path.join('__tests__', `${parsed.name}${parsed.ext}`),
|
|
158
|
+
];
|
|
159
|
+
for (const pattern of testPatterns) {
|
|
160
|
+
const testPath = path.join(parsed.dir, pattern);
|
|
161
|
+
return testPath;
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Find config files in directory
|
|
167
|
+
*/
|
|
168
|
+
async findConfigFiles(dir) {
|
|
169
|
+
const configPatterns = [
|
|
170
|
+
'package.json',
|
|
171
|
+
'tsconfig.json',
|
|
172
|
+
'.eslintrc*',
|
|
173
|
+
'.prettierrc*',
|
|
174
|
+
];
|
|
175
|
+
const configs = [];
|
|
176
|
+
for (const pattern of configPatterns) {
|
|
177
|
+
const configPath = path.join(dir, pattern);
|
|
178
|
+
if (await this.fileExists(configPath)) {
|
|
179
|
+
configs.push(configPath);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return configs;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Search for files matching pattern
|
|
186
|
+
*/
|
|
187
|
+
async searchFiles(pattern, options) {
|
|
188
|
+
const maxResults = options?.maxResults || 100;
|
|
189
|
+
try {
|
|
190
|
+
const files = await fg(pattern, {
|
|
191
|
+
cwd: this.workingDir,
|
|
192
|
+
ignore: this.excludePatterns,
|
|
193
|
+
absolute: false,
|
|
194
|
+
onlyFiles: true,
|
|
195
|
+
});
|
|
196
|
+
return files.slice(0, maxResults);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get file chunk for large files (prevents token overflow)
|
|
204
|
+
*/
|
|
205
|
+
async getFileChunk(filePath, startLine, endLine) {
|
|
206
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
207
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
208
|
+
const lines = content.split('\n');
|
|
209
|
+
const chunk = lines.slice(startLine - 1, endLine).join('\n');
|
|
210
|
+
return chunk;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Detect programming language from file extension
|
|
214
|
+
*/
|
|
215
|
+
detectLanguage(filePath) {
|
|
216
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
217
|
+
const langMap = {
|
|
218
|
+
'.ts': 'typescript',
|
|
219
|
+
'.tsx': 'typescript',
|
|
220
|
+
'.js': 'javascript',
|
|
221
|
+
'.jsx': 'javascript',
|
|
222
|
+
'.py': 'python',
|
|
223
|
+
'.java': 'java',
|
|
224
|
+
'.cpp': 'cpp',
|
|
225
|
+
'.c': 'c',
|
|
226
|
+
'.go': 'go',
|
|
227
|
+
'.rs': 'rust',
|
|
228
|
+
'.rb': 'ruby',
|
|
229
|
+
'.php': 'php',
|
|
230
|
+
'.swift': 'swift',
|
|
231
|
+
'.kt': 'kotlin',
|
|
232
|
+
};
|
|
233
|
+
return langMap[ext] || 'plaintext';
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Estimate token count (rough approximation: 1 token ≈ 4 chars)
|
|
237
|
+
*/
|
|
238
|
+
estimateTokens(text) {
|
|
239
|
+
return Math.ceil(text.length / 4);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Check if file exists
|
|
243
|
+
*/
|
|
244
|
+
async fileExists(filePath) {
|
|
245
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
246
|
+
try {
|
|
247
|
+
await fs.access(fullPath);
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Clear loaded files cache
|
|
256
|
+
*/
|
|
257
|
+
clearCache() {
|
|
258
|
+
this.loadedFiles.clear();
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get loaded files summary
|
|
262
|
+
*/
|
|
263
|
+
getSummary() {
|
|
264
|
+
let totalSize = 0;
|
|
265
|
+
const files = [];
|
|
266
|
+
for (const [path, context] of this.loadedFiles) {
|
|
267
|
+
files.push(path);
|
|
268
|
+
totalSize += context.size;
|
|
269
|
+
}
|
|
270
|
+
return { fileCount: files.length, totalSize, files };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export interface EditResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
message: string;
|
|
4
|
+
diff?: string;
|
|
5
|
+
linesChanged?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface SearchReplaceEdit {
|
|
8
|
+
search: string;
|
|
9
|
+
replace: string;
|
|
10
|
+
all?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface LineRangeEdit {
|
|
13
|
+
startLine: number;
|
|
14
|
+
endLine: number;
|
|
15
|
+
newContent: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class FileEditor {
|
|
18
|
+
private workingDir;
|
|
19
|
+
private backupDir;
|
|
20
|
+
constructor(workingDir: string);
|
|
21
|
+
/**
|
|
22
|
+
* Smart edit - searches for unique section and replaces it
|
|
23
|
+
* This is the most reliable way to edit files
|
|
24
|
+
*/
|
|
25
|
+
smartEdit(filePath: string, edit: SearchReplaceEdit): Promise<EditResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Edit specific line range - good for large files
|
|
28
|
+
*/
|
|
29
|
+
editLineRange(filePath: string, edit: LineRangeEdit): Promise<EditResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Insert content at specific line
|
|
32
|
+
*/
|
|
33
|
+
insertAtLine(filePath: string, line: number, content: string): Promise<EditResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Apply unified diff patch
|
|
36
|
+
*/
|
|
37
|
+
applyPatch(filePath: string, patch: string): Promise<EditResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Revert file to backup
|
|
40
|
+
*/
|
|
41
|
+
revertToBackup(filePath: string, backupIndex?: number): Promise<EditResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Create backup of file
|
|
44
|
+
*/
|
|
45
|
+
private createBackup;
|
|
46
|
+
/**
|
|
47
|
+
* List backups for a file
|
|
48
|
+
*/
|
|
49
|
+
private listBackups;
|
|
50
|
+
/**
|
|
51
|
+
* Count changed lines in diff
|
|
52
|
+
*/
|
|
53
|
+
private countChangedLines;
|
|
54
|
+
/**
|
|
55
|
+
* Escape special regex characters
|
|
56
|
+
*/
|
|
57
|
+
private escapeRegex;
|
|
58
|
+
/**
|
|
59
|
+
* Get file info for display
|
|
60
|
+
*/
|
|
61
|
+
getFileInfo(filePath: string): Promise<{
|
|
62
|
+
exists: boolean;
|
|
63
|
+
lines?: number;
|
|
64
|
+
size?: number;
|
|
65
|
+
preview?: string;
|
|
66
|
+
}>;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/core/editor.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;gBAEd,UAAU,EAAE,MAAM;IAK9B;;;OAGG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC;IAqD/E;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC;IA8C/E;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAqCxF;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA2CtE;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,GAAE,MAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAoCpF;;OAEG;YACW,YAAY;IAU1B;;OAEG;YACW,WAAW;IAoBzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3C,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CAqBH"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as diff from 'diff';
|
|
4
|
+
export class FileEditor {
|
|
5
|
+
workingDir;
|
|
6
|
+
backupDir;
|
|
7
|
+
constructor(workingDir) {
|
|
8
|
+
this.workingDir = workingDir;
|
|
9
|
+
this.backupDir = path.join(workingDir, '.xibecode_backups');
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Smart edit - searches for unique section and replaces it
|
|
13
|
+
* This is the most reliable way to edit files
|
|
14
|
+
*/
|
|
15
|
+
async smartEdit(filePath, edit) {
|
|
16
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
17
|
+
try {
|
|
18
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
19
|
+
// Count occurrences
|
|
20
|
+
const occurrences = (content.match(new RegExp(this.escapeRegex(edit.search), 'g')) || []).length;
|
|
21
|
+
if (occurrences === 0) {
|
|
22
|
+
return {
|
|
23
|
+
success: false,
|
|
24
|
+
message: `Search string not found in ${filePath}`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (occurrences > 1 && !edit.all) {
|
|
28
|
+
return {
|
|
29
|
+
success: false,
|
|
30
|
+
message: `Search string appears ${occurrences} times. Please be more specific or use all:true`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Perform replacement
|
|
34
|
+
const newContent = edit.all
|
|
35
|
+
? content.replaceAll(edit.search, edit.replace)
|
|
36
|
+
: content.replace(edit.search, edit.replace);
|
|
37
|
+
// Create backup
|
|
38
|
+
await this.createBackup(filePath, content);
|
|
39
|
+
// Write new content
|
|
40
|
+
await fs.writeFile(fullPath, newContent, 'utf-8');
|
|
41
|
+
// Generate diff
|
|
42
|
+
const patches = diff.createPatch(filePath, content, newContent);
|
|
43
|
+
const linesChanged = this.countChangedLines(patches);
|
|
44
|
+
return {
|
|
45
|
+
success: true,
|
|
46
|
+
message: `Successfully edited ${filePath}`,
|
|
47
|
+
diff: patches,
|
|
48
|
+
linesChanged,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
message: `Failed to edit ${filePath}: ${error.message}`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Edit specific line range - good for large files
|
|
60
|
+
*/
|
|
61
|
+
async editLineRange(filePath, edit) {
|
|
62
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
63
|
+
try {
|
|
64
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
65
|
+
const lines = content.split('\n');
|
|
66
|
+
if (edit.startLine < 1 || edit.endLine > lines.length) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
message: `Invalid line range: ${edit.startLine}-${edit.endLine} (file has ${lines.length} lines)`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
// Create backup
|
|
73
|
+
await this.createBackup(filePath, content);
|
|
74
|
+
// Replace lines
|
|
75
|
+
const newLines = [
|
|
76
|
+
...lines.slice(0, edit.startLine - 1),
|
|
77
|
+
...edit.newContent.split('\n'),
|
|
78
|
+
...lines.slice(edit.endLine),
|
|
79
|
+
];
|
|
80
|
+
const newContent = newLines.join('\n');
|
|
81
|
+
await fs.writeFile(fullPath, newContent, 'utf-8');
|
|
82
|
+
// Generate diff
|
|
83
|
+
const patches = diff.createPatch(filePath, content, newContent);
|
|
84
|
+
const linesChanged = this.countChangedLines(patches);
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
message: `Successfully edited lines ${edit.startLine}-${edit.endLine} in ${filePath}`,
|
|
88
|
+
diff: patches,
|
|
89
|
+
linesChanged,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
message: `Failed to edit ${filePath}: ${error.message}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Insert content at specific line
|
|
101
|
+
*/
|
|
102
|
+
async insertAtLine(filePath, line, content) {
|
|
103
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
104
|
+
try {
|
|
105
|
+
const originalContent = await fs.readFile(fullPath, 'utf-8');
|
|
106
|
+
const lines = originalContent.split('\n');
|
|
107
|
+
if (line < 1 || line > lines.length + 1) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
message: `Invalid line number: ${line} (file has ${lines.length} lines)`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Create backup
|
|
114
|
+
await this.createBackup(filePath, originalContent);
|
|
115
|
+
// Insert content
|
|
116
|
+
lines.splice(line - 1, 0, content);
|
|
117
|
+
const newContent = lines.join('\n');
|
|
118
|
+
await fs.writeFile(fullPath, newContent, 'utf-8');
|
|
119
|
+
return {
|
|
120
|
+
success: true,
|
|
121
|
+
message: `Successfully inserted content at line ${line} in ${filePath}`,
|
|
122
|
+
linesChanged: content.split('\n').length,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
return {
|
|
127
|
+
success: false,
|
|
128
|
+
message: `Failed to insert in ${filePath}: ${error.message}`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Apply unified diff patch
|
|
134
|
+
*/
|
|
135
|
+
async applyPatch(filePath, patch) {
|
|
136
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
137
|
+
try {
|
|
138
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
139
|
+
// Create backup
|
|
140
|
+
await this.createBackup(filePath, content);
|
|
141
|
+
// Apply patch
|
|
142
|
+
const patches = diff.parsePatch(patch);
|
|
143
|
+
if (patches.length === 0) {
|
|
144
|
+
return {
|
|
145
|
+
success: false,
|
|
146
|
+
message: 'Invalid patch format',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const result = diff.applyPatch(content, patches[0]);
|
|
150
|
+
if (result === false) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
message: 'Patch could not be applied (content may have changed)',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
await fs.writeFile(fullPath, result, 'utf-8');
|
|
157
|
+
return {
|
|
158
|
+
success: true,
|
|
159
|
+
message: `Successfully applied patch to ${filePath}`,
|
|
160
|
+
diff: patch,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
message: `Failed to apply patch to ${filePath}: ${error.message}`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Revert file to backup
|
|
172
|
+
*/
|
|
173
|
+
async revertToBackup(filePath, backupIndex = 0) {
|
|
174
|
+
const backups = await this.listBackups(filePath);
|
|
175
|
+
if (backups.length === 0) {
|
|
176
|
+
return {
|
|
177
|
+
success: false,
|
|
178
|
+
message: `No backups found for ${filePath}`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (backupIndex >= backups.length) {
|
|
182
|
+
return {
|
|
183
|
+
success: false,
|
|
184
|
+
message: `Backup index ${backupIndex} not found (have ${backups.length} backups)`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const backupPath = backups[backupIndex];
|
|
188
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
189
|
+
try {
|
|
190
|
+
const backupContent = await fs.readFile(backupPath, 'utf-8');
|
|
191
|
+
await fs.writeFile(fullPath, backupContent, 'utf-8');
|
|
192
|
+
return {
|
|
193
|
+
success: true,
|
|
194
|
+
message: `Successfully reverted ${filePath} to backup ${backupIndex}`,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
message: `Failed to revert: ${error.message}`,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Create backup of file
|
|
206
|
+
*/
|
|
207
|
+
async createBackup(filePath, content) {
|
|
208
|
+
await fs.mkdir(this.backupDir, { recursive: true });
|
|
209
|
+
const timestamp = Date.now();
|
|
210
|
+
const backupName = `${filePath.replace(/[\/\\]/g, '_')}.${timestamp}.backup`;
|
|
211
|
+
const backupPath = path.join(this.backupDir, backupName);
|
|
212
|
+
await fs.writeFile(backupPath, content, 'utf-8');
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* List backups for a file
|
|
216
|
+
*/
|
|
217
|
+
async listBackups(filePath) {
|
|
218
|
+
try {
|
|
219
|
+
const backupPrefix = filePath.replace(/[\/\\]/g, '_');
|
|
220
|
+
const files = await fs.readdir(this.backupDir);
|
|
221
|
+
const backups = files
|
|
222
|
+
.filter(f => f.startsWith(backupPrefix) && f.endsWith('.backup'))
|
|
223
|
+
.sort((a, b) => {
|
|
224
|
+
const timeA = parseInt(a.split('.')[1]);
|
|
225
|
+
const timeB = parseInt(b.split('.')[1]);
|
|
226
|
+
return timeB - timeA; // Most recent first
|
|
227
|
+
})
|
|
228
|
+
.map(f => path.join(this.backupDir, f));
|
|
229
|
+
return backups;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Count changed lines in diff
|
|
237
|
+
*/
|
|
238
|
+
countChangedLines(patch) {
|
|
239
|
+
const lines = patch.split('\n');
|
|
240
|
+
return lines.filter(l => l.startsWith('+') || l.startsWith('-')).length;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Escape special regex characters
|
|
244
|
+
*/
|
|
245
|
+
escapeRegex(str) {
|
|
246
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get file info for display
|
|
250
|
+
*/
|
|
251
|
+
async getFileInfo(filePath) {
|
|
252
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
253
|
+
try {
|
|
254
|
+
const stats = await fs.stat(fullPath);
|
|
255
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
256
|
+
const lines = content.split('\n');
|
|
257
|
+
// Get first 10 lines as preview
|
|
258
|
+
const preview = lines.slice(0, 10).join('\n');
|
|
259
|
+
return {
|
|
260
|
+
exists: true,
|
|
261
|
+
lines: lines.length,
|
|
262
|
+
size: stats.size,
|
|
263
|
+
preview,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return { exists: false };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=editor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.js","sourceRoot":"","sources":["../../src/core/editor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Tool } from '@anthropic-ai/sdk/resources/messages';
|
|
2
|
+
export interface ToolExecutor {
|
|
3
|
+
execute(toolName: string, input: any): Promise<any>;
|
|
4
|
+
getTools(): Tool[];
|
|
5
|
+
}
|
|
6
|
+
export declare class CodingToolExecutor implements ToolExecutor {
|
|
7
|
+
private workingDir;
|
|
8
|
+
private contextManager;
|
|
9
|
+
private fileEditor;
|
|
10
|
+
private platform;
|
|
11
|
+
constructor(workingDir?: string);
|
|
12
|
+
/**
|
|
13
|
+
* Safely parse tool input - handles string JSON, null, undefined
|
|
14
|
+
*/
|
|
15
|
+
private parseInput;
|
|
16
|
+
execute(toolName: string, input: any): Promise<any>;
|
|
17
|
+
getTools(): Tool[];
|
|
18
|
+
private resolvePath;
|
|
19
|
+
private readFile;
|
|
20
|
+
private readMultipleFiles;
|
|
21
|
+
private writeFile;
|
|
22
|
+
private editFile;
|
|
23
|
+
private editLines;
|
|
24
|
+
private insertAtLine;
|
|
25
|
+
private listDirectory;
|
|
26
|
+
private searchFiles;
|
|
27
|
+
private runCommand;
|
|
28
|
+
private createDirectory;
|
|
29
|
+
private deleteFile;
|
|
30
|
+
private moveFile;
|
|
31
|
+
private getContext;
|
|
32
|
+
private revertFile;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=tools.d.ts.map
|