koneck 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +222 -0
- package/dist/chat.js.map +1 -1
- package/dist/code-graph.d.ts +1 -0
- package/dist/code-graph.d.ts.map +1 -1
- package/dist/code-graph.js +94 -56
- package/dist/code-graph.js.map +1 -1
- package/dist/debugger.d.ts +4 -0
- package/dist/debugger.d.ts.map +1 -0
- package/dist/debugger.js +104 -0
- package/dist/debugger.js.map +1 -0
- package/dist/diff-review.d.ts +13 -0
- package/dist/diff-review.d.ts.map +1 -0
- package/dist/diff-review.js +115 -0
- package/dist/diff-review.js.map +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +63 -3
- package/dist/engine.js.map +1 -1
- package/dist/explain.d.ts +5 -0
- package/dist/explain.d.ts.map +1 -0
- package/dist/explain.js +58 -0
- package/dist/explain.js.map +1 -0
- package/dist/index.js +159 -0
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +7 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +89 -2
- package/dist/memory.js.map +1 -1
- package/dist/plugin-packs.d.ts +14 -0
- package/dist/plugin-packs.d.ts.map +1 -0
- package/dist/plugin-packs.js +136 -0
- package/dist/plugin-packs.js.map +1 -0
- package/dist/refactor.d.ts +10 -0
- package/dist/refactor.d.ts.map +1 -0
- package/dist/refactor.js +182 -0
- package/dist/refactor.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +209 -0
- package/dist/server.js.map +1 -0
- package/dist/test-gen.d.ts +3 -0
- package/dist/test-gen.d.ts.map +1 -0
- package/dist/test-gen.js +136 -0
- package/dist/test-gen.js.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/code-graph.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
2
|
-
import { existsSync } from 'fs';
|
|
1
|
+
import { readFile, writeFile, mkdir, stat } from 'fs/promises';
|
|
2
|
+
import { existsSync, watch } from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { Project, SyntaxKind } from 'ts-morph';
|
|
5
5
|
import ora from 'ora';
|
|
@@ -18,8 +18,40 @@ async function loadGraph(cwd) {
|
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
function indexSourceFile(sf, cwd) {
|
|
22
|
+
const file = path.relative(cwd, sf.getFilePath());
|
|
23
|
+
const symbols = [];
|
|
24
|
+
for (const fn of sf.getFunctions()) {
|
|
25
|
+
const name = fn.getName() ?? '<anonymous>';
|
|
26
|
+
const calls = new Set();
|
|
27
|
+
fn.getDescendantsOfKind(SyntaxKind.CallExpression).forEach(ce => {
|
|
28
|
+
const leaf = ce.getExpression().getText().split('.').pop()?.trim();
|
|
29
|
+
if (leaf)
|
|
30
|
+
calls.add(leaf);
|
|
31
|
+
});
|
|
32
|
+
symbols.push({ name, kind: 'function', file, line: fn.getStartLineNumber(), exported: fn.isExported(), calls: [...calls] });
|
|
33
|
+
}
|
|
34
|
+
for (const cls of sf.getClasses()) {
|
|
35
|
+
symbols.push({ name: cls.getName() ?? '<anonymous>', kind: 'class', file, line: cls.getStartLineNumber(), exported: cls.isExported() });
|
|
36
|
+
}
|
|
37
|
+
for (const iface of sf.getInterfaces()) {
|
|
38
|
+
symbols.push({ name: iface.getName(), kind: 'interface', file, line: iface.getStartLineNumber(), exported: iface.isExported() });
|
|
39
|
+
}
|
|
40
|
+
for (const ta of sf.getTypeAliases()) {
|
|
41
|
+
symbols.push({ name: ta.getName(), kind: 'type', file, line: ta.getStartLineNumber(), exported: ta.isExported() });
|
|
42
|
+
}
|
|
43
|
+
for (const vd of sf.getVariableDeclarations()) {
|
|
44
|
+
if (vd.getVariableStatement()?.isExported()) {
|
|
45
|
+
symbols.push({ name: vd.getName(), kind: 'variable', file, line: vd.getStartLineNumber(), exported: true });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return symbols;
|
|
49
|
+
}
|
|
21
50
|
export async function buildCodeGraph(cwd) {
|
|
22
51
|
const spinner = ora('Building code graph…').start();
|
|
52
|
+
const existing = await loadGraph(cwd);
|
|
53
|
+
const prevMtimes = existing?.fileMtimes ?? {};
|
|
54
|
+
const prevSymbols = existing?.symbols ?? [];
|
|
23
55
|
const project = new Project({
|
|
24
56
|
skipAddingFilesFromTsConfig: true,
|
|
25
57
|
compilerOptions: { skipLibCheck: true, noEmit: true },
|
|
@@ -31,72 +63,80 @@ export async function buildCodeGraph(cwd) {
|
|
|
31
63
|
`!${cwd}/.koneck/**`,
|
|
32
64
|
]);
|
|
33
65
|
const sourceFiles = project.getSourceFiles();
|
|
34
|
-
const
|
|
35
|
-
const
|
|
66
|
+
const currentFiles = new Set();
|
|
67
|
+
const newMtimes = { ...prevMtimes };
|
|
68
|
+
const toIndex = [];
|
|
69
|
+
let unchanged = 0;
|
|
36
70
|
for (const sf of sourceFiles) {
|
|
37
|
-
const
|
|
38
|
-
|
|
71
|
+
const rel = path.relative(cwd, sf.getFilePath());
|
|
72
|
+
currentFiles.add(rel);
|
|
73
|
+
let mtime = 0;
|
|
39
74
|
try {
|
|
40
|
-
|
|
41
|
-
for (const fn of sf.getFunctions()) {
|
|
42
|
-
const name = fn.getName() ?? '<anonymous>';
|
|
43
|
-
const callees = new Set();
|
|
44
|
-
fn.getDescendantsOfKind(SyntaxKind.CallExpression).forEach(ce => {
|
|
45
|
-
const leaf = ce.getExpression().getText().split('.').pop()?.trim();
|
|
46
|
-
if (leaf)
|
|
47
|
-
callees.add(leaf);
|
|
48
|
-
});
|
|
49
|
-
callMap.set(name, callees);
|
|
50
|
-
symbols.push({
|
|
51
|
-
name, kind: 'function', file,
|
|
52
|
-
line: fn.getStartLineNumber(),
|
|
53
|
-
exported: fn.isExported(),
|
|
54
|
-
calls: [...callees],
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
// Classes
|
|
58
|
-
for (const cls of sf.getClasses()) {
|
|
59
|
-
const name = cls.getName() ?? '<anonymous>';
|
|
60
|
-
symbols.push({ name, kind: 'class', file, line: cls.getStartLineNumber(), exported: cls.isExported() });
|
|
61
|
-
}
|
|
62
|
-
// Interfaces
|
|
63
|
-
for (const iface of sf.getInterfaces()) {
|
|
64
|
-
symbols.push({ name: iface.getName(), kind: 'interface', file, line: iface.getStartLineNumber(), exported: iface.isExported() });
|
|
65
|
-
}
|
|
66
|
-
// Type aliases
|
|
67
|
-
for (const ta of sf.getTypeAliases()) {
|
|
68
|
-
symbols.push({ name: ta.getName(), kind: 'type', file, line: ta.getStartLineNumber(), exported: ta.isExported() });
|
|
69
|
-
}
|
|
70
|
-
// Exported variable declarations
|
|
71
|
-
for (const vd of sf.getVariableDeclarations()) {
|
|
72
|
-
const stmt = vd.getVariableStatement();
|
|
73
|
-
if (stmt?.isExported()) {
|
|
74
|
-
symbols.push({ name: vd.getName(), kind: 'variable', file, line: vd.getStartLineNumber(), exported: true });
|
|
75
|
-
}
|
|
76
|
-
}
|
|
75
|
+
mtime = (await stat(sf.getFilePath())).mtimeMs;
|
|
77
76
|
}
|
|
78
|
-
catch {
|
|
79
|
-
|
|
77
|
+
catch { /* skip */ }
|
|
78
|
+
if (prevMtimes[rel] === mtime && mtime !== 0) {
|
|
79
|
+
unchanged++;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
toIndex.push(sf);
|
|
83
|
+
newMtimes[rel] = mtime;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Drop deleted files from mtime map
|
|
87
|
+
for (const rel of Object.keys(newMtimes)) {
|
|
88
|
+
if (!currentFiles.has(rel))
|
|
89
|
+
delete newMtimes[rel];
|
|
90
|
+
}
|
|
91
|
+
// Keep symbols from unchanged files; drop deleted and stale
|
|
92
|
+
const changedFiles = new Set(toIndex.map(sf => path.relative(cwd, sf.getFilePath())));
|
|
93
|
+
const kept = prevSymbols.filter(s => currentFiles.has(s.file) && !changedFiles.has(s.file));
|
|
94
|
+
const fresh = [];
|
|
95
|
+
for (const sf of toIndex) {
|
|
96
|
+
const rel = path.relative(cwd, sf.getFilePath());
|
|
97
|
+
spinner.text = `Indexing ${rel}`;
|
|
98
|
+
try {
|
|
99
|
+
fresh.push(...indexSourceFile(sf, cwd));
|
|
80
100
|
}
|
|
101
|
+
catch { /* skip unparseable */ }
|
|
81
102
|
}
|
|
82
|
-
|
|
103
|
+
const symbols = [...kept, ...fresh];
|
|
104
|
+
// Rebuild calledBy from all symbols' calls arrays (covers both kept and fresh)
|
|
83
105
|
const calledByMap = new Map();
|
|
84
|
-
for (const
|
|
85
|
-
for (const callee of
|
|
106
|
+
for (const sym of symbols) {
|
|
107
|
+
for (const callee of sym.calls ?? []) {
|
|
86
108
|
if (!calledByMap.has(callee))
|
|
87
109
|
calledByMap.set(callee, new Set());
|
|
88
|
-
calledByMap.get(callee).add(
|
|
110
|
+
calledByMap.get(callee).add(sym.name);
|
|
89
111
|
}
|
|
90
112
|
}
|
|
91
113
|
for (const sym of symbols) {
|
|
92
114
|
const cb = calledByMap.get(sym.name);
|
|
93
|
-
|
|
94
|
-
sym.calledBy = [...cb];
|
|
115
|
+
sym.calledBy = cb?.size ? [...cb] : undefined;
|
|
95
116
|
}
|
|
96
|
-
const data = { builtAt: new Date().toISOString(), cwd, symbols };
|
|
117
|
+
const data = { builtAt: new Date().toISOString(), cwd, symbols, fileMtimes: newMtimes };
|
|
97
118
|
await mkdir(path.join(cwd, '.koneck'), { recursive: true });
|
|
98
119
|
await writeFile(graphPath(cwd), JSON.stringify(data, null, 2));
|
|
99
|
-
spinner.succeed(
|
|
120
|
+
spinner.succeed(`↺ incremental: ${toIndex.length} new/changed, ${unchanged} unchanged — ${symbols.length} symbols`);
|
|
121
|
+
}
|
|
122
|
+
export async function watchAndIndex(cwd) {
|
|
123
|
+
const watchDir = existsSync(path.join(cwd, 'src')) ? path.join(cwd, 'src') : cwd;
|
|
124
|
+
await buildCodeGraph(cwd);
|
|
125
|
+
let debounce = null;
|
|
126
|
+
const watcher = watch(watchDir, { recursive: true }, (_, filename) => {
|
|
127
|
+
if (!filename?.endsWith('.ts'))
|
|
128
|
+
return;
|
|
129
|
+
if (debounce)
|
|
130
|
+
clearTimeout(debounce);
|
|
131
|
+
debounce = setTimeout(async () => {
|
|
132
|
+
console.log(`↺ Re-indexed: ${filename}`);
|
|
133
|
+
await buildCodeGraph(cwd);
|
|
134
|
+
}, 1500);
|
|
135
|
+
});
|
|
136
|
+
return new Promise(() => {
|
|
137
|
+
process.on('SIGINT', () => { watcher.close(); process.exit(0); });
|
|
138
|
+
process.on('SIGTERM', () => { watcher.close(); process.exit(0); });
|
|
139
|
+
});
|
|
100
140
|
}
|
|
101
141
|
export async function findUsages(symbolName, cwd) {
|
|
102
142
|
let graph = await loadGraph(cwd);
|
|
@@ -153,9 +193,7 @@ export async function getCallGraph(cwd) {
|
|
|
153
193
|
.map(s => ({ s, score: (s.calls?.length ?? 0) + (s.calledBy?.length ?? 0) }))
|
|
154
194
|
.sort((a, b) => b.score - a.score)
|
|
155
195
|
.slice(0, 20);
|
|
156
|
-
return top
|
|
157
|
-
.map(({ s }) => `${s.name} → [${(s.calls ?? []).join(', ')}]`)
|
|
158
|
-
.join('\n');
|
|
196
|
+
return top.map(({ s }) => `${s.name} → [${(s.calls ?? []).join(', ')}]`).join('\n');
|
|
159
197
|
}
|
|
160
198
|
export async function queryGraph(query, cwd) {
|
|
161
199
|
const graph = await loadGraph(cwd);
|
package/dist/code-graph.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-graph.js","sourceRoot":"","sources":["../src/code-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"code-graph.js","sourceRoot":"","sources":["../src/code-graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AgentConfig } from './types.js';
|
|
2
|
+
export declare function runDebugger(config: AgentConfig, startCommand?: string): Promise<void>;
|
|
3
|
+
export declare function analyzeError(errorOutput: string, config: AgentConfig): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=debugger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debugger.d.ts","sourceRoot":"","sources":["../src/debugger.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAwE9C,wBAAsB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B3F;AAED,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAa1F"}
|
package/dist/debugger.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import readline from 'readline';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { execa } from 'execa';
|
|
6
|
+
import { runAgent } from './engine.js';
|
|
7
|
+
import { detectProject } from './project.js';
|
|
8
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
9
|
+
async function findStartCommand(cwd) {
|
|
10
|
+
try {
|
|
11
|
+
const raw = await fs.readFile(path.join(cwd, 'package.json'), 'utf8');
|
|
12
|
+
const pkg = JSON.parse(raw);
|
|
13
|
+
const scripts = pkg.scripts ?? {};
|
|
14
|
+
for (const key of ['start', 'dev', 'serve']) {
|
|
15
|
+
if (scripts[key])
|
|
16
|
+
return `npm run ${key}`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// no package.json or parse error — fall through to prompt
|
|
21
|
+
}
|
|
22
|
+
// Also check project info for a run command
|
|
23
|
+
const info = await detectProject(cwd);
|
|
24
|
+
if (info.runCommand)
|
|
25
|
+
return info.runCommand;
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
28
|
+
rl.question('What command runs your app? ', (answer) => {
|
|
29
|
+
rl.close();
|
|
30
|
+
resolve(answer.trim());
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function extractStackTrace(output) {
|
|
35
|
+
const lines = output.split('\n');
|
|
36
|
+
const matched = [];
|
|
37
|
+
lines.forEach((line, i) => {
|
|
38
|
+
if (/^\s+at /.test(line) ||
|
|
39
|
+
/\b(Error|TypeError|ReferenceError|SyntaxError|Exception):/i.test(line) ||
|
|
40
|
+
/File ".+?"/.test(line) ||
|
|
41
|
+
/\.(ts|js):\d+/.test(line)) {
|
|
42
|
+
matched.push(i);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
if (matched.length === 0)
|
|
46
|
+
return output.slice(0, 2000);
|
|
47
|
+
const first = Math.max(0, matched[0] - 5);
|
|
48
|
+
const last = Math.min(lines.length - 1, matched[matched.length - 1] + 5);
|
|
49
|
+
return lines.slice(first, Math.min(last + 1, first + 50)).join('\n');
|
|
50
|
+
}
|
|
51
|
+
function buildDebugTask(command, crashOutput, stackTrace) {
|
|
52
|
+
return `The application crashed. Analyze the error and fix it.
|
|
53
|
+
|
|
54
|
+
Command run: ${command}
|
|
55
|
+
|
|
56
|
+
Crash output:
|
|
57
|
+
${crashOutput.slice(0, 3000)}
|
|
58
|
+
|
|
59
|
+
Stack trace (extracted):
|
|
60
|
+
${stackTrace}
|
|
61
|
+
|
|
62
|
+
Steps:
|
|
63
|
+
1. Read the source files mentioned in the stack trace
|
|
64
|
+
2. Identify the root cause
|
|
65
|
+
3. Apply a fix
|
|
66
|
+
4. Run the app again to verify it works`;
|
|
67
|
+
}
|
|
68
|
+
// ─── Exports ─────────────────────────────────────────────────────────────────
|
|
69
|
+
export async function runDebugger(config, startCommand) {
|
|
70
|
+
const command = startCommand ?? (await findStartCommand(config.cwd));
|
|
71
|
+
console.log(chalk.bold.cyan('\n━━━ AI Debugger ━━━━━━━━━━━━━━━━━━━━━━━'));
|
|
72
|
+
console.log(chalk.white(`Command: ${command}`));
|
|
73
|
+
const [bin, ...args] = command.split(' ');
|
|
74
|
+
const result = await execa(bin, args, {
|
|
75
|
+
all: true,
|
|
76
|
+
reject: false,
|
|
77
|
+
timeout: 30_000,
|
|
78
|
+
cwd: config.cwd,
|
|
79
|
+
});
|
|
80
|
+
if (result.exitCode === 0) {
|
|
81
|
+
console.log(chalk.green('App ran successfully — no crash detected.'));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const output = result.all ?? '';
|
|
85
|
+
console.log(chalk.red(`Exit code: ${result.exitCode}`));
|
|
86
|
+
console.log(chalk.yellow('Analyzing crash...\n'));
|
|
87
|
+
const stackTrace = extractStackTrace(output);
|
|
88
|
+
const debugTask = buildDebugTask(command, output, stackTrace);
|
|
89
|
+
await runAgent(debugTask, { ...config, maxTurns: 20 });
|
|
90
|
+
}
|
|
91
|
+
export async function analyzeError(errorOutput, config) {
|
|
92
|
+
const task = `The user has pasted an error message. Diagnose the root cause and apply a fix.
|
|
93
|
+
|
|
94
|
+
Error output:
|
|
95
|
+
${errorOutput}
|
|
96
|
+
|
|
97
|
+
Steps:
|
|
98
|
+
1. Read any source files referenced in the error
|
|
99
|
+
2. Identify the root cause
|
|
100
|
+
3. Apply a fix
|
|
101
|
+
4. If possible, run the app to verify it works`;
|
|
102
|
+
await runAgent(task, { ...config, maxTurns: 20 });
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=debugger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debugger.js","sourceRoot":"","sources":["../src/debugger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface FileChange {
|
|
2
|
+
path: string;
|
|
3
|
+
originalContent: string;
|
|
4
|
+
newContent: string;
|
|
5
|
+
}
|
|
6
|
+
export type ReviewDecision = 'accept' | 'reject' | 'accept-all' | 'reject-all';
|
|
7
|
+
export declare function reviewChanges(changes: FileChange[], cwd: string): Promise<{
|
|
8
|
+
accepted: FileChange[];
|
|
9
|
+
rejected: FileChange[];
|
|
10
|
+
}>;
|
|
11
|
+
export declare function captureFileSnapshot(paths: string[], cwd: string): Promise<Map<string, string>>;
|
|
12
|
+
export declare function diffSnapshot(before: Map<string, string>, cwd: string): Promise<FileChange[]>;
|
|
13
|
+
//# sourceMappingURL=diff-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-review.d.ts","sourceRoot":"","sources":["../src/diff-review.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,YAAY,CAAC;AA2B/E,wBAAsB,aAAa,CACjC,OAAO,EAAE,UAAU,EAAE,EACrB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC,CAyD7D;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CASpG;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,EAAE,CAAC,CAUvB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import readline from 'readline';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { createTwoFilesPatch } from 'diff';
|
|
7
|
+
import { execa } from 'execa';
|
|
8
|
+
function printDiff(change) {
|
|
9
|
+
const rel = path.relative(process.cwd(), change.path);
|
|
10
|
+
const patch = createTwoFilesPatch(rel, rel, change.originalContent, change.newContent, '', '');
|
|
11
|
+
let added = 0;
|
|
12
|
+
let removed = 0;
|
|
13
|
+
for (const line of patch.split('\n').slice(4)) {
|
|
14
|
+
if (line.startsWith('+')) {
|
|
15
|
+
process.stdout.write(chalk.green(line) + '\n');
|
|
16
|
+
added++;
|
|
17
|
+
}
|
|
18
|
+
else if (line.startsWith('-')) {
|
|
19
|
+
process.stdout.write(chalk.red(line) + '\n');
|
|
20
|
+
removed++;
|
|
21
|
+
}
|
|
22
|
+
else if (line.startsWith('@@'))
|
|
23
|
+
process.stdout.write(chalk.cyan(line) + '\n');
|
|
24
|
+
else
|
|
25
|
+
process.stdout.write(chalk.dim(line) + '\n');
|
|
26
|
+
}
|
|
27
|
+
return { added, removed };
|
|
28
|
+
}
|
|
29
|
+
function ask(prompt) {
|
|
30
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
31
|
+
return new Promise(resolve => rl.question(prompt, ans => { rl.close(); resolve(ans.trim().toLowerCase()); }));
|
|
32
|
+
}
|
|
33
|
+
async function openEditor(filePath) {
|
|
34
|
+
const editor = process.env.EDITOR ?? 'nano';
|
|
35
|
+
await execa(editor, [filePath], { stdio: 'inherit' });
|
|
36
|
+
}
|
|
37
|
+
export async function reviewChanges(changes, cwd) {
|
|
38
|
+
if (changes.length === 0) {
|
|
39
|
+
console.log('No changes to review.');
|
|
40
|
+
return { accepted: [], rejected: [] };
|
|
41
|
+
}
|
|
42
|
+
const accepted = [];
|
|
43
|
+
const rejected = [];
|
|
44
|
+
const total = changes.length;
|
|
45
|
+
for (let i = 0; i < changes.length; i++) {
|
|
46
|
+
const change = changes[i];
|
|
47
|
+
const rel = path.relative(cwd, change.path);
|
|
48
|
+
const header = `━━━ [${i + 1}/${total}] ${rel} `;
|
|
49
|
+
console.log(chalk.bold(header.padEnd(60, '━')));
|
|
50
|
+
const { added, removed } = printDiff(change);
|
|
51
|
+
console.log(chalk.green(`+${added} lines`) + ' ' + chalk.red(`-${removed} lines`));
|
|
52
|
+
let decision = null;
|
|
53
|
+
while (decision === null) {
|
|
54
|
+
const ans = await ask('Accept changes? [Y]es / [n]o / [a]ll / [x] reject all / [e]dit > ');
|
|
55
|
+
if (ans === '' || ans === 'y')
|
|
56
|
+
decision = 'accept';
|
|
57
|
+
else if (ans === 'n')
|
|
58
|
+
decision = 'reject';
|
|
59
|
+
else if (ans === 'a')
|
|
60
|
+
decision = 'accept-all';
|
|
61
|
+
else if (ans === 'x')
|
|
62
|
+
decision = 'reject-all';
|
|
63
|
+
else if (ans === 'e') {
|
|
64
|
+
await writeFile(change.path, change.newContent, 'utf8');
|
|
65
|
+
await openEditor(change.path);
|
|
66
|
+
change.newContent = await readFile(change.path, 'utf8');
|
|
67
|
+
console.log(chalk.bold(header.padEnd(60, '━')));
|
|
68
|
+
printDiff(change);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.log(chalk.yellow(' → y/enter=yes n=no a=accept-all x=reject-all e=edit'));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (decision === 'accept-all') {
|
|
75
|
+
accepted.push(change);
|
|
76
|
+
for (let j = i + 1; j < changes.length; j++)
|
|
77
|
+
accepted.push(changes[j]);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
if (decision === 'reject-all') {
|
|
81
|
+
rejected.push(change);
|
|
82
|
+
for (let j = i + 1; j < changes.length; j++)
|
|
83
|
+
rejected.push(changes[j]);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
(decision === 'accept' ? accepted : rejected).push(change);
|
|
87
|
+
}
|
|
88
|
+
await Promise.all([
|
|
89
|
+
...accepted.map(c => writeFile(c.path, c.newContent, 'utf8')),
|
|
90
|
+
...rejected.map(c => writeFile(c.path, c.originalContent, 'utf8')),
|
|
91
|
+
]);
|
|
92
|
+
console.log(chalk.bold(`\nReview complete: ${accepted.length} accepted, ${rejected.length} rejected.`));
|
|
93
|
+
return { accepted, rejected };
|
|
94
|
+
}
|
|
95
|
+
export async function captureFileSnapshot(paths, cwd) {
|
|
96
|
+
const snapshot = new Map();
|
|
97
|
+
await Promise.all(paths.map(async (p) => {
|
|
98
|
+
const abs = path.isAbsolute(p) ? p : path.resolve(cwd, p);
|
|
99
|
+
if (existsSync(abs))
|
|
100
|
+
snapshot.set(abs, await readFile(abs, 'utf8'));
|
|
101
|
+
}));
|
|
102
|
+
return snapshot;
|
|
103
|
+
}
|
|
104
|
+
export async function diffSnapshot(before, cwd) {
|
|
105
|
+
const changes = [];
|
|
106
|
+
await Promise.all([...before.entries()].map(async ([abs, originalContent]) => {
|
|
107
|
+
if (!existsSync(abs))
|
|
108
|
+
return;
|
|
109
|
+
const newContent = await readFile(abs, 'utf8');
|
|
110
|
+
if (newContent !== originalContent)
|
|
111
|
+
changes.push({ path: abs, originalContent, newContent });
|
|
112
|
+
}));
|
|
113
|
+
return changes;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=diff-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-review.js","sourceRoot":"","sources":["../src/diff-review.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAc5B,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,UAAU,CAAC;AAIlB,OAAO,KAAK,EACV,OAAO,EACP,WAAW,EAEX,UAAU,EAIX,MAAM,YAAY,CAAC;AAIpB,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAQvD;AAsMD,wBAAsB,YAAY,CAChC,QAAQ,EAAE,OAAO,EAAE,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,cAAc,EAAE,EAC5B,OAAO,EAAE,WAAW,EAAE,EACtB,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAC7C,UAAU,SAAI,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,OAAO,CAAC,CAsNlB;AAID,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChE;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,WAAW,EACnB,eAAe,CAAC,EAAE,OAAO,EAAE,GAC1B,OAAO,CAAC,YAAY,CAAC,CA6CvB;AAwBD,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,EACnB,eAAe,CAAC,EAAE,OAAO,EAAE,GAC1B,OAAO,CAAC,YAAY,CAAC,CAuGvB"}
|
package/dist/engine.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
2
|
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
3
5
|
import { execa } from 'execa';
|
|
4
6
|
import { TOOL_DEFINITIONS, dispatchTool } from './tools.js';
|
|
5
7
|
import { tui } from './tui.js';
|
|
@@ -14,6 +16,7 @@ import { loadPlugins, callPlugin } from './plugins.js';
|
|
|
14
16
|
import { loadMCPConfig, connectMCPServers, callMCPTool, } from './mcp.js';
|
|
15
17
|
import { gatherRecon } from './recon.js';
|
|
16
18
|
import { runSelfCritique, detectFileWrites } from './critique.js';
|
|
19
|
+
import { getPackSystemPrompt } from './plugin-packs.js';
|
|
17
20
|
// ─── Client ──────────────────────────────────────────────────────────────────
|
|
18
21
|
export function buildClient(config) {
|
|
19
22
|
const provider = resolveProvider(config.provider, config.baseURL);
|
|
@@ -410,13 +413,15 @@ export async function createAgentSession(config, initialMessages) {
|
|
|
410
413
|
const stats = { promptTokens: 0, completionTokens: 0, totalTokens: 0, turns: 0 };
|
|
411
414
|
const messages = initialMessages ? [...initialMessages] : [];
|
|
412
415
|
if (!initialMessages) {
|
|
413
|
-
const [ctx, memory, project, agentInstructions] = await Promise.all([
|
|
416
|
+
const [ctx, memory, project, agentInstructions, packPrompt] = await Promise.all([
|
|
414
417
|
discoverEnvironment(config.cwd),
|
|
415
418
|
loadMemory(config.cwd),
|
|
416
419
|
detectProject(config.cwd),
|
|
417
420
|
loadAgentInstructions(config.cwd),
|
|
421
|
+
getPackSystemPrompt(config.cwd).catch(() => ''),
|
|
418
422
|
]);
|
|
419
|
-
|
|
423
|
+
const basePrompt = buildSystemPrompt(ctx, memory, project, agentInstructions);
|
|
424
|
+
messages.push({ role: 'system', content: packPrompt ? basePrompt + '\n\n' + packPrompt : basePrompt });
|
|
420
425
|
}
|
|
421
426
|
// Load MCP and plugins only at top level (spawnDepth === 0)
|
|
422
427
|
const isTopLevel = (config.spawnDepth ?? 0) === 0;
|
|
@@ -439,6 +444,26 @@ export async function createAgentSession(config, initialMessages) {
|
|
|
439
444
|
send,
|
|
440
445
|
};
|
|
441
446
|
}
|
|
447
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
448
|
+
function extractChangedPaths(messages, cwd) {
|
|
449
|
+
const paths = new Set();
|
|
450
|
+
for (const m of messages) {
|
|
451
|
+
if (m.role === 'assistant' && m.tool_calls) {
|
|
452
|
+
for (const tc of m.tool_calls) {
|
|
453
|
+
if (['write_file', 'apply_diff', 'delete_file', 'move_file'].includes(tc.function.name)) {
|
|
454
|
+
try {
|
|
455
|
+
const a = JSON.parse(tc.function.arguments);
|
|
456
|
+
const p = (a['path'] ?? a['destination'] ?? '');
|
|
457
|
+
if (p)
|
|
458
|
+
paths.add(path.resolve(cwd, p));
|
|
459
|
+
}
|
|
460
|
+
catch { /* skip */ }
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return [...paths];
|
|
466
|
+
}
|
|
442
467
|
// ─── Single-task entry point ──────────────────────────────────────────────────
|
|
443
468
|
export async function runAgent(task, config, initialMessages) {
|
|
444
469
|
let effectiveCwd = config.cwd;
|
|
@@ -480,8 +505,8 @@ export async function runAgent(task, config, initialMessages) {
|
|
|
480
505
|
}
|
|
481
506
|
await session.send(enrichedTask);
|
|
482
507
|
// Self-critique: one review pass if files were changed
|
|
508
|
+
const hadWrites = detectFileWrites(session.messages);
|
|
483
509
|
if (!config.silent && !config.ci && (config.spawnDepth ?? 0) === 0) {
|
|
484
|
-
const hadWrites = detectFileWrites(session.messages);
|
|
485
510
|
await runSelfCritique(session.messages, effectiveConfig, effectiveCwd, session.stats, hadWrites);
|
|
486
511
|
}
|
|
487
512
|
const agentElapsed = Date.now() - agentStart;
|
|
@@ -494,6 +519,41 @@ export async function runAgent(task, config, initialMessages) {
|
|
|
494
519
|
}
|
|
495
520
|
tui.printStats(session.stats, config.provider, config.model, agentElapsed);
|
|
496
521
|
}
|
|
522
|
+
// Offer diff review if files were changed
|
|
523
|
+
if (!config.silent && !config.ci && hadWrites) {
|
|
524
|
+
const { default: readline } = await import('readline');
|
|
525
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
526
|
+
await new Promise(resolve => {
|
|
527
|
+
rl.question(chalk.dim('\n Review file changes? [y/N] '), async (ans) => {
|
|
528
|
+
rl.close();
|
|
529
|
+
if (ans.toLowerCase() === 'y') {
|
|
530
|
+
const { captureFileSnapshot, diffSnapshot, reviewChanges } = await import('./diff-review.js');
|
|
531
|
+
// Get changed files from tool call history
|
|
532
|
+
const changedPaths = extractChangedPaths(session.messages, effectiveCwd);
|
|
533
|
+
if (changedPaths.length) {
|
|
534
|
+
// We don't have the before-snapshot here, so just show current git diff
|
|
535
|
+
const { execa: ex } = await import('execa');
|
|
536
|
+
const result = await ex('git', ['diff', 'HEAD'], { cwd: effectiveCwd, all: true, reject: false });
|
|
537
|
+
if (result.all?.trim()) {
|
|
538
|
+
console.log('');
|
|
539
|
+
result.all.split('\n').forEach((line) => {
|
|
540
|
+
if (line.startsWith('+'))
|
|
541
|
+
process.stdout.write(chalk.green(' ' + line) + '\n');
|
|
542
|
+
else if (line.startsWith('-'))
|
|
543
|
+
process.stdout.write(chalk.red(' ' + line) + '\n');
|
|
544
|
+
else if (line.startsWith('@@'))
|
|
545
|
+
process.stdout.write(chalk.cyan(' ' + line) + '\n');
|
|
546
|
+
else
|
|
547
|
+
process.stdout.write(chalk.dim(' ' + line) + '\n');
|
|
548
|
+
});
|
|
549
|
+
console.log('');
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
resolve();
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
}
|
|
497
557
|
await saveSession(config.cwd, session.id, {
|
|
498
558
|
id: session.id,
|
|
499
559
|
task: task.slice(0, 120),
|