codeep 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +576 -0
- package/dist/api/index.d.ts +8 -0
- package/dist/api/index.js +421 -0
- package/dist/app.d.ts +2 -0
- package/dist/app.js +1406 -0
- package/dist/components/AgentProgress.d.ts +33 -0
- package/dist/components/AgentProgress.js +97 -0
- package/dist/components/Export.d.ts +8 -0
- package/dist/components/Export.js +27 -0
- package/dist/components/Help.d.ts +2 -0
- package/dist/components/Help.js +3 -0
- package/dist/components/Input.d.ts +9 -0
- package/dist/components/Input.js +89 -0
- package/dist/components/Loading.d.ts +9 -0
- package/dist/components/Loading.js +31 -0
- package/dist/components/Login.d.ts +7 -0
- package/dist/components/Login.js +77 -0
- package/dist/components/Logo.d.ts +8 -0
- package/dist/components/Logo.js +89 -0
- package/dist/components/LogoutPicker.d.ts +8 -0
- package/dist/components/LogoutPicker.js +61 -0
- package/dist/components/Message.d.ts +10 -0
- package/dist/components/Message.js +234 -0
- package/dist/components/MessageList.d.ts +10 -0
- package/dist/components/MessageList.js +8 -0
- package/dist/components/ProjectPermission.d.ts +7 -0
- package/dist/components/ProjectPermission.js +52 -0
- package/dist/components/Search.d.ts +10 -0
- package/dist/components/Search.js +30 -0
- package/dist/components/SessionPicker.d.ts +9 -0
- package/dist/components/SessionPicker.js +88 -0
- package/dist/components/Sessions.d.ts +12 -0
- package/dist/components/Sessions.js +102 -0
- package/dist/components/Settings.d.ts +7 -0
- package/dist/components/Settings.js +162 -0
- package/dist/components/Status.d.ts +2 -0
- package/dist/components/Status.js +12 -0
- package/dist/config/config.test.d.ts +1 -0
- package/dist/config/config.test.js +157 -0
- package/dist/config/index.d.ts +121 -0
- package/dist/config/index.js +555 -0
- package/dist/config/providers.d.ts +43 -0
- package/dist/config/providers.js +82 -0
- package/dist/config/providers.test.d.ts +1 -0
- package/dist/config/providers.test.js +132 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +38 -0
- package/dist/utils/agent.d.ts +37 -0
- package/dist/utils/agent.js +627 -0
- package/dist/utils/codeReview.d.ts +36 -0
- package/dist/utils/codeReview.js +390 -0
- package/dist/utils/context.d.ts +49 -0
- package/dist/utils/context.js +216 -0
- package/dist/utils/diffPreview.d.ts +57 -0
- package/dist/utils/diffPreview.js +335 -0
- package/dist/utils/export.d.ts +19 -0
- package/dist/utils/export.js +94 -0
- package/dist/utils/git.d.ts +85 -0
- package/dist/utils/git.js +399 -0
- package/dist/utils/git.test.d.ts +1 -0
- package/dist/utils/git.test.js +193 -0
- package/dist/utils/history.d.ts +93 -0
- package/dist/utils/history.js +348 -0
- package/dist/utils/interactive.d.ts +34 -0
- package/dist/utils/interactive.js +206 -0
- package/dist/utils/keychain.d.ts +17 -0
- package/dist/utils/keychain.js +160 -0
- package/dist/utils/learning.d.ts +89 -0
- package/dist/utils/learning.js +330 -0
- package/dist/utils/logger.d.ts +33 -0
- package/dist/utils/logger.js +130 -0
- package/dist/utils/project.d.ts +86 -0
- package/dist/utils/project.js +415 -0
- package/dist/utils/project.test.d.ts +1 -0
- package/dist/utils/project.test.js +212 -0
- package/dist/utils/ratelimit.d.ts +26 -0
- package/dist/utils/ratelimit.js +132 -0
- package/dist/utils/ratelimit.test.d.ts +1 -0
- package/dist/utils/ratelimit.test.js +131 -0
- package/dist/utils/retry.d.ts +28 -0
- package/dist/utils/retry.js +109 -0
- package/dist/utils/retry.test.d.ts +1 -0
- package/dist/utils/retry.test.js +163 -0
- package/dist/utils/search.d.ts +11 -0
- package/dist/utils/search.js +29 -0
- package/dist/utils/shell.d.ts +45 -0
- package/dist/utils/shell.js +242 -0
- package/dist/utils/skills.d.ts +144 -0
- package/dist/utils/skills.js +1137 -0
- package/dist/utils/smartContext.d.ts +29 -0
- package/dist/utils/smartContext.js +441 -0
- package/dist/utils/tools.d.ts +224 -0
- package/dist/utils/tools.js +731 -0
- package/dist/utils/update.d.ts +22 -0
- package/dist/utils/update.js +128 -0
- package/dist/utils/validation.d.ts +28 -0
- package/dist/utils/validation.js +141 -0
- package/dist/utils/validation.test.d.ts +1 -0
- package/dist/utils/validation.test.js +164 -0
- package/dist/utils/verify.d.ts +78 -0
- package/dist/utils/verify.js +464 -0
- package/package.json +68 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Context - automatically gather relevant files for better understanding
|
|
3
|
+
*/
|
|
4
|
+
import { ProjectContext } from './project';
|
|
5
|
+
export interface RelatedFile {
|
|
6
|
+
path: string;
|
|
7
|
+
relativePath: string;
|
|
8
|
+
reason: string;
|
|
9
|
+
priority: number;
|
|
10
|
+
content?: string;
|
|
11
|
+
size: number;
|
|
12
|
+
}
|
|
13
|
+
export interface SmartContextResult {
|
|
14
|
+
files: RelatedFile[];
|
|
15
|
+
totalSize: number;
|
|
16
|
+
truncated: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Gather smart context for a target file or task
|
|
20
|
+
*/
|
|
21
|
+
export declare function gatherSmartContext(targetFile: string | null, projectContext: ProjectContext, taskDescription?: string): SmartContextResult;
|
|
22
|
+
/**
|
|
23
|
+
* Format smart context for system prompt
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatSmartContext(context: SmartContextResult): string;
|
|
26
|
+
/**
|
|
27
|
+
* Extract target file from task description
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractTargetFile(task: string): string | null;
|
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Context - automatically gather relevant files for better understanding
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync, statSync } from 'fs';
|
|
5
|
+
import { join, dirname, basename, extname, relative } from 'path';
|
|
6
|
+
// Max context size (characters)
|
|
7
|
+
const MAX_CONTEXT_SIZE = 50000;
|
|
8
|
+
const MAX_FILES = 15;
|
|
9
|
+
// File extensions we care about
|
|
10
|
+
const CODE_EXTENSIONS = new Set([
|
|
11
|
+
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
|
|
12
|
+
'.py', '.pyw',
|
|
13
|
+
'.go',
|
|
14
|
+
'.rs',
|
|
15
|
+
'.php', '.phtml',
|
|
16
|
+
'.java', '.kt', '.scala',
|
|
17
|
+
'.cs', '.fs',
|
|
18
|
+
'.rb',
|
|
19
|
+
'.swift',
|
|
20
|
+
'.c', '.cpp', '.h', '.hpp',
|
|
21
|
+
'.vue', '.svelte',
|
|
22
|
+
'.css', '.scss', '.less',
|
|
23
|
+
'.html', '.htm',
|
|
24
|
+
'.json', '.yaml', '.yml', '.toml',
|
|
25
|
+
'.sql',
|
|
26
|
+
'.md',
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* Extract imports/requires from file content
|
|
30
|
+
*/
|
|
31
|
+
function extractImports(content, ext) {
|
|
32
|
+
const imports = [];
|
|
33
|
+
if (['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'].includes(ext)) {
|
|
34
|
+
// ES imports: import X from 'path' or import 'path'
|
|
35
|
+
const esImports = content.matchAll(/import\s+(?:.*?\s+from\s+)?['"]([^'"]+)['"]/g);
|
|
36
|
+
for (const match of esImports) {
|
|
37
|
+
imports.push(match[1]);
|
|
38
|
+
}
|
|
39
|
+
// CommonJS: require('path')
|
|
40
|
+
const cjsImports = content.matchAll(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g);
|
|
41
|
+
for (const match of cjsImports) {
|
|
42
|
+
imports.push(match[1]);
|
|
43
|
+
}
|
|
44
|
+
// Dynamic imports: import('path')
|
|
45
|
+
const dynamicImports = content.matchAll(/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g);
|
|
46
|
+
for (const match of dynamicImports) {
|
|
47
|
+
imports.push(match[1]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (ext === '.py') {
|
|
51
|
+
// Python: import X, from X import Y
|
|
52
|
+
const pyImports = content.matchAll(/(?:from\s+(\S+)\s+import|import\s+(\S+))/g);
|
|
53
|
+
for (const match of pyImports) {
|
|
54
|
+
imports.push(match[1] || match[2]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (ext === '.go') {
|
|
58
|
+
// Go: import "path" or import (...)
|
|
59
|
+
const goImports = content.matchAll(/import\s+(?:\(\s*)?"([^"]+)"/g);
|
|
60
|
+
for (const match of goImports) {
|
|
61
|
+
imports.push(match[1]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (ext === '.php') {
|
|
65
|
+
// PHP: use Namespace\Class, require/include
|
|
66
|
+
const phpUse = content.matchAll(/use\s+([^;]+);/g);
|
|
67
|
+
for (const match of phpUse) {
|
|
68
|
+
imports.push(match[1]);
|
|
69
|
+
}
|
|
70
|
+
const phpRequire = content.matchAll(/(?:require|include)(?:_once)?\s*\(?['"]([^'"]+)['"]/g);
|
|
71
|
+
for (const match of phpRequire) {
|
|
72
|
+
imports.push(match[1]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (ext === '.rs') {
|
|
76
|
+
// Rust: use crate::path, mod name
|
|
77
|
+
const rustUse = content.matchAll(/use\s+(?:crate::)?([^;{]+)/g);
|
|
78
|
+
for (const match of rustUse) {
|
|
79
|
+
imports.push(match[1].trim());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return imports;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolve import path to actual file path
|
|
86
|
+
*/
|
|
87
|
+
function resolveImportPath(importPath, fromFile, projectRoot) {
|
|
88
|
+
const fromDir = dirname(fromFile);
|
|
89
|
+
const ext = extname(fromFile);
|
|
90
|
+
// Skip external packages
|
|
91
|
+
if (!importPath.startsWith('.') && !importPath.startsWith('/')) {
|
|
92
|
+
// Could be a local alias like @/components
|
|
93
|
+
if (importPath.startsWith('@/') || importPath.startsWith('~/')) {
|
|
94
|
+
const aliasPath = importPath.replace(/^[@~]\//, 'src/');
|
|
95
|
+
return resolveWithExtensions(join(projectRoot, aliasPath), ext);
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
// Resolve relative path
|
|
100
|
+
const resolved = join(fromDir, importPath);
|
|
101
|
+
return resolveWithExtensions(resolved, ext);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Try to resolve path with various extensions
|
|
105
|
+
*/
|
|
106
|
+
function resolveWithExtensions(basePath, preferredExt) {
|
|
107
|
+
// Try exact path first
|
|
108
|
+
if (existsSync(basePath) && statSync(basePath).isFile()) {
|
|
109
|
+
return basePath;
|
|
110
|
+
}
|
|
111
|
+
// Try with extensions
|
|
112
|
+
const extensions = [
|
|
113
|
+
preferredExt,
|
|
114
|
+
'.ts', '.tsx', '.js', '.jsx',
|
|
115
|
+
'.py', '.go', '.rs', '.php',
|
|
116
|
+
'/index.ts', '/index.tsx', '/index.js', '/index.jsx',
|
|
117
|
+
];
|
|
118
|
+
for (const ext of extensions) {
|
|
119
|
+
const withExt = basePath + ext;
|
|
120
|
+
if (existsSync(withExt) && statSync(withExt).isFile()) {
|
|
121
|
+
return withExt;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Find related files based on naming conventions
|
|
128
|
+
*/
|
|
129
|
+
function findRelatedByNaming(filePath, projectRoot) {
|
|
130
|
+
const related = [];
|
|
131
|
+
const fileName = basename(filePath);
|
|
132
|
+
const fileDir = dirname(filePath);
|
|
133
|
+
const ext = extname(filePath);
|
|
134
|
+
const baseName = fileName.replace(ext, '');
|
|
135
|
+
// Common related file patterns
|
|
136
|
+
const patterns = [
|
|
137
|
+
// Test files
|
|
138
|
+
{ suffix: '.test', reason: 'test file' },
|
|
139
|
+
{ suffix: '.spec', reason: 'spec file' },
|
|
140
|
+
{ suffix: '_test', reason: 'test file' },
|
|
141
|
+
// Type definitions
|
|
142
|
+
{ suffix: '.d', reason: 'type definitions' },
|
|
143
|
+
{ suffix: '.types', reason: 'type definitions' },
|
|
144
|
+
// Related modules
|
|
145
|
+
{ suffix: '.model', reason: 'model' },
|
|
146
|
+
{ suffix: '.service', reason: 'service' },
|
|
147
|
+
{ suffix: '.controller', reason: 'controller' },
|
|
148
|
+
{ suffix: '.repository', reason: 'repository' },
|
|
149
|
+
{ suffix: '.utils', reason: 'utilities' },
|
|
150
|
+
{ suffix: '.helper', reason: 'helper' },
|
|
151
|
+
{ suffix: '.interface', reason: 'interface' },
|
|
152
|
+
];
|
|
153
|
+
// Check if current file matches a pattern, find the base
|
|
154
|
+
for (const pattern of patterns) {
|
|
155
|
+
if (baseName.endsWith(pattern.suffix)) {
|
|
156
|
+
const realBase = baseName.replace(pattern.suffix, '');
|
|
157
|
+
const basePath = join(fileDir, realBase + ext);
|
|
158
|
+
if (existsSync(basePath)) {
|
|
159
|
+
try {
|
|
160
|
+
const stat = statSync(basePath);
|
|
161
|
+
related.push({
|
|
162
|
+
path: basePath,
|
|
163
|
+
relativePath: relative(projectRoot, basePath),
|
|
164
|
+
reason: 'main file',
|
|
165
|
+
priority: 8,
|
|
166
|
+
size: stat.size,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch { }
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Find files with same base name
|
|
174
|
+
for (const pattern of patterns) {
|
|
175
|
+
const relatedPath = join(fileDir, baseName + pattern.suffix + ext);
|
|
176
|
+
if (existsSync(relatedPath) && relatedPath !== filePath) {
|
|
177
|
+
try {
|
|
178
|
+
const stat = statSync(relatedPath);
|
|
179
|
+
related.push({
|
|
180
|
+
path: relatedPath,
|
|
181
|
+
relativePath: relative(projectRoot, relatedPath),
|
|
182
|
+
reason: pattern.reason,
|
|
183
|
+
priority: 5,
|
|
184
|
+
size: stat.size,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch { }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return related;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Find type definition files
|
|
194
|
+
*/
|
|
195
|
+
function findTypeDefinitions(projectRoot, imports) {
|
|
196
|
+
const related = [];
|
|
197
|
+
// Common type definition locations
|
|
198
|
+
const typePaths = [
|
|
199
|
+
'src/types/index.ts',
|
|
200
|
+
'src/types.ts',
|
|
201
|
+
'types/index.ts',
|
|
202
|
+
'types.ts',
|
|
203
|
+
'src/@types/index.d.ts',
|
|
204
|
+
'src/interfaces/index.ts',
|
|
205
|
+
];
|
|
206
|
+
for (const typePath of typePaths) {
|
|
207
|
+
const fullPath = join(projectRoot, typePath);
|
|
208
|
+
if (existsSync(fullPath)) {
|
|
209
|
+
try {
|
|
210
|
+
const stat = statSync(fullPath);
|
|
211
|
+
related.push({
|
|
212
|
+
path: fullPath,
|
|
213
|
+
relativePath: typePath,
|
|
214
|
+
reason: 'type definitions',
|
|
215
|
+
priority: 7,
|
|
216
|
+
size: stat.size,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
catch { }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return related;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Find config files
|
|
226
|
+
*/
|
|
227
|
+
function findConfigFiles(projectRoot) {
|
|
228
|
+
const related = [];
|
|
229
|
+
const configFiles = [
|
|
230
|
+
{ path: 'tsconfig.json', reason: 'TypeScript config' },
|
|
231
|
+
{ path: 'package.json', reason: 'package info' },
|
|
232
|
+
{ path: '.env.example', reason: 'environment variables' },
|
|
233
|
+
{ path: 'composer.json', reason: 'PHP dependencies' },
|
|
234
|
+
{ path: 'Cargo.toml', reason: 'Rust config' },
|
|
235
|
+
{ path: 'go.mod', reason: 'Go modules' },
|
|
236
|
+
{ path: 'requirements.txt', reason: 'Python dependencies' },
|
|
237
|
+
{ path: 'pyproject.toml', reason: 'Python config' },
|
|
238
|
+
];
|
|
239
|
+
for (const config of configFiles) {
|
|
240
|
+
const fullPath = join(projectRoot, config.path);
|
|
241
|
+
if (existsSync(fullPath)) {
|
|
242
|
+
try {
|
|
243
|
+
const stat = statSync(fullPath);
|
|
244
|
+
related.push({
|
|
245
|
+
path: fullPath,
|
|
246
|
+
relativePath: config.path,
|
|
247
|
+
reason: config.reason,
|
|
248
|
+
priority: 3,
|
|
249
|
+
size: stat.size,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
catch { }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return related;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Gather smart context for a target file or task
|
|
259
|
+
*/
|
|
260
|
+
export function gatherSmartContext(targetFile, projectContext, taskDescription) {
|
|
261
|
+
const projectRoot = projectContext.root || process.cwd();
|
|
262
|
+
const allRelated = new Map();
|
|
263
|
+
// If we have a target file, analyze it
|
|
264
|
+
if (targetFile) {
|
|
265
|
+
const targetPath = join(projectRoot, targetFile);
|
|
266
|
+
if (existsSync(targetPath)) {
|
|
267
|
+
try {
|
|
268
|
+
const content = readFileSync(targetPath, 'utf-8');
|
|
269
|
+
const ext = extname(targetPath);
|
|
270
|
+
const stat = statSync(targetPath);
|
|
271
|
+
// Add the target file itself
|
|
272
|
+
allRelated.set(targetPath, {
|
|
273
|
+
path: targetPath,
|
|
274
|
+
relativePath: targetFile,
|
|
275
|
+
reason: 'target file',
|
|
276
|
+
priority: 10,
|
|
277
|
+
content,
|
|
278
|
+
size: stat.size,
|
|
279
|
+
});
|
|
280
|
+
// Extract and resolve imports
|
|
281
|
+
const imports = extractImports(content, ext);
|
|
282
|
+
for (const imp of imports) {
|
|
283
|
+
const resolved = resolveImportPath(imp, targetPath, projectRoot);
|
|
284
|
+
if (resolved && !allRelated.has(resolved)) {
|
|
285
|
+
try {
|
|
286
|
+
const impStat = statSync(resolved);
|
|
287
|
+
allRelated.set(resolved, {
|
|
288
|
+
path: resolved,
|
|
289
|
+
relativePath: relative(projectRoot, resolved),
|
|
290
|
+
reason: 'imported module',
|
|
291
|
+
priority: 8,
|
|
292
|
+
size: impStat.size,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
catch { }
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Find related by naming
|
|
299
|
+
const namedRelated = findRelatedByNaming(targetPath, projectRoot);
|
|
300
|
+
for (const rel of namedRelated) {
|
|
301
|
+
if (!allRelated.has(rel.path)) {
|
|
302
|
+
allRelated.set(rel.path, rel);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
catch { }
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Find type definitions
|
|
310
|
+
const typeDefs = findTypeDefinitions(projectRoot, []);
|
|
311
|
+
for (const td of typeDefs) {
|
|
312
|
+
if (!allRelated.has(td.path)) {
|
|
313
|
+
allRelated.set(td.path, td);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Add config files (lower priority)
|
|
317
|
+
const configs = findConfigFiles(projectRoot);
|
|
318
|
+
for (const cfg of configs) {
|
|
319
|
+
if (!allRelated.has(cfg.path)) {
|
|
320
|
+
allRelated.set(cfg.path, cfg);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// If task mentions specific files, try to find them
|
|
324
|
+
if (taskDescription) {
|
|
325
|
+
const mentionedFiles = extractMentionedFiles(taskDescription, projectRoot);
|
|
326
|
+
for (const mf of mentionedFiles) {
|
|
327
|
+
if (!allRelated.has(mf.path)) {
|
|
328
|
+
allRelated.set(mf.path, mf);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// Sort by priority and limit
|
|
333
|
+
let files = Array.from(allRelated.values())
|
|
334
|
+
.sort((a, b) => b.priority - a.priority)
|
|
335
|
+
.slice(0, MAX_FILES);
|
|
336
|
+
// Load content for files that don't have it
|
|
337
|
+
let totalSize = 0;
|
|
338
|
+
let truncated = false;
|
|
339
|
+
for (const file of files) {
|
|
340
|
+
if (!file.content && totalSize < MAX_CONTEXT_SIZE) {
|
|
341
|
+
try {
|
|
342
|
+
const content = readFileSync(file.path, 'utf-8');
|
|
343
|
+
if (totalSize + content.length <= MAX_CONTEXT_SIZE) {
|
|
344
|
+
file.content = content;
|
|
345
|
+
totalSize += content.length;
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
// Truncate this file
|
|
349
|
+
const remaining = MAX_CONTEXT_SIZE - totalSize;
|
|
350
|
+
file.content = content.slice(0, remaining) + '\n... (truncated)';
|
|
351
|
+
totalSize = MAX_CONTEXT_SIZE;
|
|
352
|
+
truncated = true;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
catch { }
|
|
356
|
+
}
|
|
357
|
+
else if (file.content) {
|
|
358
|
+
totalSize += file.content.length;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// Remove files without content if we're at limit
|
|
362
|
+
if (truncated) {
|
|
363
|
+
files = files.filter(f => f.content);
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
files,
|
|
367
|
+
totalSize,
|
|
368
|
+
truncated,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Extract file paths mentioned in task description
|
|
373
|
+
*/
|
|
374
|
+
function extractMentionedFiles(task, projectRoot) {
|
|
375
|
+
const related = [];
|
|
376
|
+
// Match file paths like src/utils/helper.ts or ./config.json
|
|
377
|
+
const pathPattern = /(?:^|[\s'"`])([.\w/-]+\.\w{1,10})(?:[\s'"`]|$)/g;
|
|
378
|
+
const matches = task.matchAll(pathPattern);
|
|
379
|
+
for (const match of matches) {
|
|
380
|
+
const filePath = match[1];
|
|
381
|
+
const fullPath = join(projectRoot, filePath);
|
|
382
|
+
if (existsSync(fullPath)) {
|
|
383
|
+
try {
|
|
384
|
+
const stat = statSync(fullPath);
|
|
385
|
+
if (stat.isFile()) {
|
|
386
|
+
related.push({
|
|
387
|
+
path: fullPath,
|
|
388
|
+
relativePath: filePath,
|
|
389
|
+
reason: 'mentioned in task',
|
|
390
|
+
priority: 9,
|
|
391
|
+
size: stat.size,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
catch { }
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return related;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Format smart context for system prompt
|
|
402
|
+
*/
|
|
403
|
+
export function formatSmartContext(context) {
|
|
404
|
+
if (context.files.length === 0) {
|
|
405
|
+
return '';
|
|
406
|
+
}
|
|
407
|
+
const lines = ['## Related Files (Smart Context)', ''];
|
|
408
|
+
for (const file of context.files) {
|
|
409
|
+
if (file.content) {
|
|
410
|
+
lines.push(`### ${file.relativePath}`);
|
|
411
|
+
lines.push(`> Reason: ${file.reason}`);
|
|
412
|
+
lines.push('```');
|
|
413
|
+
lines.push(file.content);
|
|
414
|
+
lines.push('```');
|
|
415
|
+
lines.push('');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (context.truncated) {
|
|
419
|
+
lines.push('> Note: Some files were truncated due to size limits.');
|
|
420
|
+
}
|
|
421
|
+
return lines.join('\n');
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Extract target file from task description
|
|
425
|
+
*/
|
|
426
|
+
export function extractTargetFile(task) {
|
|
427
|
+
// Common patterns for target files
|
|
428
|
+
const patterns = [
|
|
429
|
+
/(?:edit|modify|update|change|fix)\s+(?:the\s+)?(?:file\s+)?['"`]?([.\w/-]+\.\w{1,10})['"`]?/i,
|
|
430
|
+
/(?:in|to)\s+(?:the\s+)?(?:file\s+)?['"`]?([.\w/-]+\.\w{1,10})['"`]?/i,
|
|
431
|
+
/['"`]([.\w/-]+\.\w{1,10})['"`]/,
|
|
432
|
+
/(?:^|\s)([.\w/-]+\.\w{1,10})(?:\s|$)/,
|
|
433
|
+
];
|
|
434
|
+
for (const pattern of patterns) {
|
|
435
|
+
const match = task.match(pattern);
|
|
436
|
+
if (match) {
|
|
437
|
+
return match[1];
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent tools - definitions and execution
|
|
3
|
+
*/
|
|
4
|
+
export interface OpenAITool {
|
|
5
|
+
type: 'function';
|
|
6
|
+
function: {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object';
|
|
11
|
+
properties: Record<string, {
|
|
12
|
+
type: string;
|
|
13
|
+
description: string;
|
|
14
|
+
items?: {
|
|
15
|
+
type: string;
|
|
16
|
+
};
|
|
17
|
+
}>;
|
|
18
|
+
required: string[];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface AnthropicTool {
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
input_schema: {
|
|
26
|
+
type: 'object';
|
|
27
|
+
properties: Record<string, {
|
|
28
|
+
type: string;
|
|
29
|
+
description: string;
|
|
30
|
+
items?: {
|
|
31
|
+
type: string;
|
|
32
|
+
};
|
|
33
|
+
}>;
|
|
34
|
+
required: string[];
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export interface ToolCall {
|
|
38
|
+
tool: string;
|
|
39
|
+
parameters: Record<string, unknown>;
|
|
40
|
+
id?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ToolResult {
|
|
43
|
+
success: boolean;
|
|
44
|
+
output: string;
|
|
45
|
+
error?: string;
|
|
46
|
+
tool: string;
|
|
47
|
+
parameters: Record<string, unknown>;
|
|
48
|
+
}
|
|
49
|
+
export interface ActionLog {
|
|
50
|
+
type: 'read' | 'write' | 'edit' | 'delete' | 'command' | 'search' | 'list' | 'mkdir' | 'fetch';
|
|
51
|
+
target: string;
|
|
52
|
+
result: 'success' | 'error';
|
|
53
|
+
details?: string;
|
|
54
|
+
timestamp: number;
|
|
55
|
+
}
|
|
56
|
+
export declare const AGENT_TOOLS: {
|
|
57
|
+
read_file: {
|
|
58
|
+
name: string;
|
|
59
|
+
description: string;
|
|
60
|
+
parameters: {
|
|
61
|
+
path: {
|
|
62
|
+
type: string;
|
|
63
|
+
description: string;
|
|
64
|
+
required: boolean;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
write_file: {
|
|
69
|
+
name: string;
|
|
70
|
+
description: string;
|
|
71
|
+
parameters: {
|
|
72
|
+
path: {
|
|
73
|
+
type: string;
|
|
74
|
+
description: string;
|
|
75
|
+
required: boolean;
|
|
76
|
+
};
|
|
77
|
+
content: {
|
|
78
|
+
type: string;
|
|
79
|
+
description: string;
|
|
80
|
+
required: boolean;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
edit_file: {
|
|
85
|
+
name: string;
|
|
86
|
+
description: string;
|
|
87
|
+
parameters: {
|
|
88
|
+
path: {
|
|
89
|
+
type: string;
|
|
90
|
+
description: string;
|
|
91
|
+
required: boolean;
|
|
92
|
+
};
|
|
93
|
+
old_text: {
|
|
94
|
+
type: string;
|
|
95
|
+
description: string;
|
|
96
|
+
required: boolean;
|
|
97
|
+
};
|
|
98
|
+
new_text: {
|
|
99
|
+
type: string;
|
|
100
|
+
description: string;
|
|
101
|
+
required: boolean;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
delete_file: {
|
|
106
|
+
name: string;
|
|
107
|
+
description: string;
|
|
108
|
+
parameters: {
|
|
109
|
+
path: {
|
|
110
|
+
type: string;
|
|
111
|
+
description: string;
|
|
112
|
+
required: boolean;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
list_files: {
|
|
117
|
+
name: string;
|
|
118
|
+
description: string;
|
|
119
|
+
parameters: {
|
|
120
|
+
path: {
|
|
121
|
+
type: string;
|
|
122
|
+
description: string;
|
|
123
|
+
required: boolean;
|
|
124
|
+
};
|
|
125
|
+
recursive: {
|
|
126
|
+
type: string;
|
|
127
|
+
description: string;
|
|
128
|
+
required: boolean;
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
create_directory: {
|
|
133
|
+
name: string;
|
|
134
|
+
description: string;
|
|
135
|
+
parameters: {
|
|
136
|
+
path: {
|
|
137
|
+
type: string;
|
|
138
|
+
description: string;
|
|
139
|
+
required: boolean;
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
execute_command: {
|
|
144
|
+
name: string;
|
|
145
|
+
description: string;
|
|
146
|
+
parameters: {
|
|
147
|
+
command: {
|
|
148
|
+
type: string;
|
|
149
|
+
description: string;
|
|
150
|
+
required: boolean;
|
|
151
|
+
};
|
|
152
|
+
args: {
|
|
153
|
+
type: string;
|
|
154
|
+
description: string;
|
|
155
|
+
required: boolean;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
search_code: {
|
|
160
|
+
name: string;
|
|
161
|
+
description: string;
|
|
162
|
+
parameters: {
|
|
163
|
+
pattern: {
|
|
164
|
+
type: string;
|
|
165
|
+
description: string;
|
|
166
|
+
required: boolean;
|
|
167
|
+
};
|
|
168
|
+
path: {
|
|
169
|
+
type: string;
|
|
170
|
+
description: string;
|
|
171
|
+
required: boolean;
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
fetch_url: {
|
|
176
|
+
name: string;
|
|
177
|
+
description: string;
|
|
178
|
+
parameters: {
|
|
179
|
+
url: {
|
|
180
|
+
type: string;
|
|
181
|
+
description: string;
|
|
182
|
+
required: boolean;
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Format tool definitions for system prompt (text-based fallback)
|
|
189
|
+
*/
|
|
190
|
+
export declare function formatToolDefinitions(): string;
|
|
191
|
+
/**
|
|
192
|
+
* Get tools in OpenAI Function Calling format
|
|
193
|
+
*/
|
|
194
|
+
export declare function getOpenAITools(): OpenAITool[];
|
|
195
|
+
/**
|
|
196
|
+
* Get tools in Anthropic Tool Use format
|
|
197
|
+
*/
|
|
198
|
+
export declare function getAnthropicTools(): AnthropicTool[];
|
|
199
|
+
/**
|
|
200
|
+
* Parse tool calls from OpenAI response
|
|
201
|
+
*/
|
|
202
|
+
export declare function parseOpenAIToolCalls(toolCalls: any[]): ToolCall[];
|
|
203
|
+
/**
|
|
204
|
+
* Parse tool calls from Anthropic response
|
|
205
|
+
*/
|
|
206
|
+
export declare function parseAnthropicToolCalls(content: any[]): ToolCall[];
|
|
207
|
+
/**
|
|
208
|
+
* Parse tool calls from LLM response
|
|
209
|
+
* Supports multiple formats:
|
|
210
|
+
* - <tool_call>{"tool": "name", "parameters": {...}}</tool_call>
|
|
211
|
+
* - <toolcall>{"tool": "name", "parameters": {...}}</toolcall>
|
|
212
|
+
* - <toolcall>toolname{"parameters": {...}}</toolcall>
|
|
213
|
+
* - ```tool\n{"tool": "name", "parameters": {...}}\n```
|
|
214
|
+
* - Direct JSON blocks with tool property
|
|
215
|
+
*/
|
|
216
|
+
export declare function parseToolCalls(response: string): ToolCall[];
|
|
217
|
+
/**
|
|
218
|
+
* Execute a tool call
|
|
219
|
+
*/
|
|
220
|
+
export declare function executeTool(toolCall: ToolCall, projectRoot: string): ToolResult;
|
|
221
|
+
/**
|
|
222
|
+
* Create action log from tool result
|
|
223
|
+
*/
|
|
224
|
+
export declare function createActionLog(toolCall: ToolCall, result: ToolResult): ActionLog;
|