doomcode 0.1.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/agent/agent-manager.d.ts +57 -0
- package/dist/agent/agent-manager.d.ts.map +1 -0
- package/dist/agent/agent-manager.js +545 -0
- package/dist/agent/agent-manager.js.map +1 -0
- package/dist/agent/diff-extractor.d.ts +15 -0
- package/dist/agent/diff-extractor.d.ts.map +1 -0
- package/dist/agent/diff-extractor.js +124 -0
- package/dist/agent/diff-extractor.js.map +1 -0
- package/dist/agent/patch-tracker.d.ts +62 -0
- package/dist/agent/patch-tracker.d.ts.map +1 -0
- package/dist/agent/patch-tracker.js +258 -0
- package/dist/agent/patch-tracker.js.map +1 -0
- package/dist/agent/permission-detector.d.ts +10 -0
- package/dist/agent/permission-detector.d.ts.map +1 -0
- package/dist/agent/permission-detector.js +83 -0
- package/dist/agent/permission-detector.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +118 -0
- package/dist/index.js.map +1 -0
- package/dist/session.d.ts +54 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +367 -0
- package/dist/session.js.map +1 -0
- package/package.json +31 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff Extractor
|
|
3
|
+
*
|
|
4
|
+
* Extracts git diffs from agent output.
|
|
5
|
+
*/
|
|
6
|
+
import { parseDiff } from '@doomcode/diff-parser';
|
|
7
|
+
import { randomUUID } from 'crypto';
|
|
8
|
+
export class DiffExtractor {
|
|
9
|
+
diffBuffer = '';
|
|
10
|
+
inDiff = false;
|
|
11
|
+
extract(output) {
|
|
12
|
+
// Look for diff start markers
|
|
13
|
+
if (output.includes('diff --git') || output.includes('--- a/')) {
|
|
14
|
+
this.inDiff = true;
|
|
15
|
+
}
|
|
16
|
+
if (this.inDiff) {
|
|
17
|
+
this.diffBuffer += output;
|
|
18
|
+
// Check for end of diff (typically followed by non-diff content or end of output)
|
|
19
|
+
// This is a simplified heuristic - real implementation would need better detection
|
|
20
|
+
if (this.isEndOfDiff(output)) {
|
|
21
|
+
const diffText = this.diffBuffer;
|
|
22
|
+
this.diffBuffer = '';
|
|
23
|
+
this.inDiff = false;
|
|
24
|
+
try {
|
|
25
|
+
const parsed = parseDiff(diffText);
|
|
26
|
+
if (parsed.files.length > 0) {
|
|
27
|
+
const files = parsed.files.map((file) => ({
|
|
28
|
+
path: file.newPath,
|
|
29
|
+
diff: file.hunks.map((h) => h.header + '\n' + h.lines.map((l) => {
|
|
30
|
+
const prefix = l.type === 'addition' ? '+' : l.type === 'deletion' ? '-' : ' ';
|
|
31
|
+
return prefix + l.content;
|
|
32
|
+
}).join('\n')).join('\n'),
|
|
33
|
+
status: file.status,
|
|
34
|
+
oldPath: file.oldPath !== file.newPath ? file.oldPath : undefined,
|
|
35
|
+
additions: file.additions,
|
|
36
|
+
deletions: file.deletions,
|
|
37
|
+
}));
|
|
38
|
+
return {
|
|
39
|
+
type: 'diff_patch',
|
|
40
|
+
patchId: randomUUID(),
|
|
41
|
+
files,
|
|
42
|
+
summary: this.generateSummary(parsed.files),
|
|
43
|
+
estimatedRisk: this.estimateRisk(parsed.files),
|
|
44
|
+
totalAdditions: parsed.totalAdditions,
|
|
45
|
+
totalDeletions: parsed.totalDeletions,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Failed to parse diff
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
isEndOfDiff(output) {
|
|
58
|
+
// Heuristics for detecting end of diff:
|
|
59
|
+
// 1. Multiple empty lines
|
|
60
|
+
// 2. Non-diff content (prompt, message, etc.)
|
|
61
|
+
// 3. Common terminal prompts
|
|
62
|
+
const trimmed = output.trim();
|
|
63
|
+
// Check for common end patterns
|
|
64
|
+
if (trimmed.endsWith('$') || trimmed.endsWith('>') || trimmed.endsWith('#')) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
// Check for multiple newlines at end
|
|
68
|
+
if (output.endsWith('\n\n\n')) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
// Check for certain keywords that indicate end of diff
|
|
72
|
+
const endPatterns = [
|
|
73
|
+
/Do you want to apply/i,
|
|
74
|
+
/Apply these changes\?/i,
|
|
75
|
+
/\d+ files? changed/i,
|
|
76
|
+
/Successfully applied/i,
|
|
77
|
+
];
|
|
78
|
+
for (const pattern of endPatterns) {
|
|
79
|
+
if (pattern.test(output)) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
generateSummary(files) {
|
|
86
|
+
const added = files.filter((f) => f.status === 'added').length;
|
|
87
|
+
const modified = files.filter((f) => f.status === 'modified').length;
|
|
88
|
+
const deleted = files.filter((f) => f.status === 'deleted').length;
|
|
89
|
+
const parts = [];
|
|
90
|
+
if (added > 0)
|
|
91
|
+
parts.push(`${added} added`);
|
|
92
|
+
if (modified > 0)
|
|
93
|
+
parts.push(`${modified} modified`);
|
|
94
|
+
if (deleted > 0)
|
|
95
|
+
parts.push(`${deleted} deleted`);
|
|
96
|
+
return parts.join(', ') || 'No changes';
|
|
97
|
+
}
|
|
98
|
+
estimateRisk(files) {
|
|
99
|
+
// Simple risk estimation based on:
|
|
100
|
+
// 1. Number of files changed
|
|
101
|
+
// 2. Types of files changed
|
|
102
|
+
// 3. Amount of changes
|
|
103
|
+
const riskFactors = {
|
|
104
|
+
fileCount: files.length,
|
|
105
|
+
sensitiveFiles: files.filter((f) => /\.(env|config|secret|key|password|auth)/i.test(f.newPath) ||
|
|
106
|
+
/package\.json|tsconfig\.json|webpack|vite\.config/i.test(f.newPath)).length,
|
|
107
|
+
totalChanges: files.reduce((sum, f) => sum + f.additions + f.deletions, 0),
|
|
108
|
+
};
|
|
109
|
+
// High risk if touching sensitive files
|
|
110
|
+
if (riskFactors.sensitiveFiles > 0) {
|
|
111
|
+
return 'high';
|
|
112
|
+
}
|
|
113
|
+
// High risk if many files or large changes
|
|
114
|
+
if (riskFactors.fileCount > 10 || riskFactors.totalChanges > 500) {
|
|
115
|
+
return 'high';
|
|
116
|
+
}
|
|
117
|
+
// Medium risk if moderate changes
|
|
118
|
+
if (riskFactors.fileCount > 5 || riskFactors.totalChanges > 100) {
|
|
119
|
+
return 'medium';
|
|
120
|
+
}
|
|
121
|
+
return 'low';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=diff-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-extractor.js","sourceRoot":"","sources":["../../src/agent/diff-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch Tracker
|
|
3
|
+
*
|
|
4
|
+
* Tracks applied patches for deterministic undo functionality.
|
|
5
|
+
* Captures file state before/after patches and generates reverse diffs.
|
|
6
|
+
*/
|
|
7
|
+
import type { AppliedPatch, DiffPatchMessage, AgentId } from '@doomcode/protocol';
|
|
8
|
+
export interface UndoResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
revertedFiles: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare class PatchTracker {
|
|
14
|
+
private workingDirectory;
|
|
15
|
+
private appliedPatches;
|
|
16
|
+
private maxPatches;
|
|
17
|
+
constructor(workingDirectory: string);
|
|
18
|
+
/**
|
|
19
|
+
* Prepare for a patch by capturing the before-state of all affected files.
|
|
20
|
+
* Returns a patchId to be used when finalizing.
|
|
21
|
+
*/
|
|
22
|
+
prepareForPatch(diff: DiffPatchMessage, prompt: string, agentId: AgentId): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Finalize patch record after application by capturing after-state hashes.
|
|
25
|
+
*/
|
|
26
|
+
finalizePatch(patchId: string): Promise<AppliedPatch | null>;
|
|
27
|
+
/**
|
|
28
|
+
* Undo a specific patch by applying its reverse diff.
|
|
29
|
+
* Verifies file state before reverting to ensure determinism.
|
|
30
|
+
*/
|
|
31
|
+
undoPatch(patchId: string): Promise<UndoResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Get list of applied patches (for status queries).
|
|
34
|
+
*/
|
|
35
|
+
getAppliedPatches(): AppliedPatch[];
|
|
36
|
+
/**
|
|
37
|
+
* Get a specific patch by ID.
|
|
38
|
+
*/
|
|
39
|
+
getPatch(patchId: string): AppliedPatch | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Clear all patch history.
|
|
42
|
+
*/
|
|
43
|
+
clearHistory(): void;
|
|
44
|
+
/**
|
|
45
|
+
* Hash file content for state verification.
|
|
46
|
+
*/
|
|
47
|
+
private hashContent;
|
|
48
|
+
/**
|
|
49
|
+
* Generate a reverse diff by swapping + and - lines.
|
|
50
|
+
*/
|
|
51
|
+
private generateReverseDiff;
|
|
52
|
+
/**
|
|
53
|
+
* Apply a reverse diff using git apply.
|
|
54
|
+
*/
|
|
55
|
+
private applyReverseDiff;
|
|
56
|
+
/**
|
|
57
|
+
* Fallback: manually revert a file by parsing the reverse diff.
|
|
58
|
+
* This is a simplified implementation for basic cases.
|
|
59
|
+
*/
|
|
60
|
+
private manualRevert;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=patch-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch-tracker.d.ts","sourceRoot":"","sources":["../../src/agent/patch-tracker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EACV,YAAY,EAEZ,gBAAgB,EAChB,OAAO,EACR,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,UAAU,CAAM;gBAEZ,gBAAgB,EAAE,MAAM;IAIpC;;;OAGG;IACG,eAAe,CACnB,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC;IA0ClB;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAgBlE;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAqDrD;;OAEG;IACH,iBAAiB,IAAI,YAAY,EAAE;IAInC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAInD;;OAEG;IACH,YAAY,IAAI,IAAI;IAIpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAe3B;;OAEG;YACW,gBAAgB;IAiC9B;;;OAGG;IACH,OAAO,CAAC,YAAY;CAwDrB"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch Tracker
|
|
3
|
+
*
|
|
4
|
+
* Tracks applied patches for deterministic undo functionality.
|
|
5
|
+
* Captures file state before/after patches and generates reverse diffs.
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'crypto';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
import { randomUUID } from 'crypto';
|
|
12
|
+
export class PatchTracker {
|
|
13
|
+
workingDirectory;
|
|
14
|
+
appliedPatches = [];
|
|
15
|
+
maxPatches = 50;
|
|
16
|
+
constructor(workingDirectory) {
|
|
17
|
+
this.workingDirectory = workingDirectory;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Prepare for a patch by capturing the before-state of all affected files.
|
|
21
|
+
* Returns a patchId to be used when finalizing.
|
|
22
|
+
*/
|
|
23
|
+
async prepareForPatch(diff, prompt, agentId) {
|
|
24
|
+
const patchId = randomUUID();
|
|
25
|
+
const files = [];
|
|
26
|
+
for (const file of diff.files) {
|
|
27
|
+
const filePath = path.join(this.workingDirectory, file.path);
|
|
28
|
+
let beforeHash = '';
|
|
29
|
+
let beforeContent = '';
|
|
30
|
+
// Capture before state if file exists
|
|
31
|
+
if (fs.existsSync(filePath)) {
|
|
32
|
+
beforeContent = fs.readFileSync(filePath, 'utf8');
|
|
33
|
+
beforeHash = this.hashContent(beforeContent);
|
|
34
|
+
}
|
|
35
|
+
files.push({
|
|
36
|
+
path: file.path,
|
|
37
|
+
beforeHash,
|
|
38
|
+
afterHash: '', // Will be filled after apply
|
|
39
|
+
reverseDiff: this.generateReverseDiff(file.diff),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const patch = {
|
|
43
|
+
patchId,
|
|
44
|
+
timestamp: Date.now(),
|
|
45
|
+
files,
|
|
46
|
+
agentId,
|
|
47
|
+
prompt,
|
|
48
|
+
};
|
|
49
|
+
// Add to front of list (newest first)
|
|
50
|
+
this.appliedPatches.unshift(patch);
|
|
51
|
+
// Trim to max size
|
|
52
|
+
if (this.appliedPatches.length > this.maxPatches) {
|
|
53
|
+
this.appliedPatches = this.appliedPatches.slice(0, this.maxPatches);
|
|
54
|
+
}
|
|
55
|
+
return patchId;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Finalize patch record after application by capturing after-state hashes.
|
|
59
|
+
*/
|
|
60
|
+
async finalizePatch(patchId) {
|
|
61
|
+
const patch = this.appliedPatches.find((p) => p.patchId === patchId);
|
|
62
|
+
if (!patch)
|
|
63
|
+
return null;
|
|
64
|
+
// Update after hashes
|
|
65
|
+
for (const file of patch.files) {
|
|
66
|
+
const filePath = path.join(this.workingDirectory, file.path);
|
|
67
|
+
if (fs.existsSync(filePath)) {
|
|
68
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
69
|
+
file.afterHash = this.hashContent(content);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return patch;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Undo a specific patch by applying its reverse diff.
|
|
76
|
+
* Verifies file state before reverting to ensure determinism.
|
|
77
|
+
*/
|
|
78
|
+
async undoPatch(patchId) {
|
|
79
|
+
const patch = this.appliedPatches.find((p) => p.patchId === patchId);
|
|
80
|
+
if (!patch) {
|
|
81
|
+
return { success: false, error: 'Patch not found', revertedFiles: [] };
|
|
82
|
+
}
|
|
83
|
+
const revertedFiles = [];
|
|
84
|
+
try {
|
|
85
|
+
// Verify current state matches expected "after" state for all files
|
|
86
|
+
for (const file of patch.files) {
|
|
87
|
+
const filePath = path.join(this.workingDirectory, file.path);
|
|
88
|
+
if (fs.existsSync(filePath)) {
|
|
89
|
+
const currentHash = this.hashContent(fs.readFileSync(filePath, 'utf8'));
|
|
90
|
+
if (file.afterHash && currentHash !== file.afterHash) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
error: `File ${file.path} has been modified since patch was applied`,
|
|
94
|
+
revertedFiles,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (file.afterHash) {
|
|
99
|
+
// File was supposed to exist but doesn't
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
error: `File ${file.path} no longer exists`,
|
|
103
|
+
revertedFiles,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Apply reverse diffs in reverse order (last file first)
|
|
108
|
+
for (const file of [...patch.files].reverse()) {
|
|
109
|
+
if (file.reverseDiff) {
|
|
110
|
+
await this.applyReverseDiff(file.path, file.reverseDiff);
|
|
111
|
+
revertedFiles.push(file.path);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Remove from history
|
|
115
|
+
this.appliedPatches = this.appliedPatches.filter((p) => p.patchId !== patchId);
|
|
116
|
+
return { success: true, revertedFiles };
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
error: error instanceof Error ? error.message : 'Unknown error during undo',
|
|
122
|
+
revertedFiles,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get list of applied patches (for status queries).
|
|
128
|
+
*/
|
|
129
|
+
getAppliedPatches() {
|
|
130
|
+
return [...this.appliedPatches];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get a specific patch by ID.
|
|
134
|
+
*/
|
|
135
|
+
getPatch(patchId) {
|
|
136
|
+
return this.appliedPatches.find((p) => p.patchId === patchId);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Clear all patch history.
|
|
140
|
+
*/
|
|
141
|
+
clearHistory() {
|
|
142
|
+
this.appliedPatches = [];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Hash file content for state verification.
|
|
146
|
+
*/
|
|
147
|
+
hashContent(content) {
|
|
148
|
+
return createHash('sha256').update(content).digest('hex');
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Generate a reverse diff by swapping + and - lines.
|
|
152
|
+
*/
|
|
153
|
+
generateReverseDiff(diff) {
|
|
154
|
+
const lines = diff.split('\n');
|
|
155
|
+
return lines
|
|
156
|
+
.map((line) => {
|
|
157
|
+
// Swap + and - lines (but not header lines like +++ or ---)
|
|
158
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
159
|
+
return '-' + line.slice(1);
|
|
160
|
+
}
|
|
161
|
+
else if (line.startsWith('-') && !line.startsWith('---')) {
|
|
162
|
+
return '+' + line.slice(1);
|
|
163
|
+
}
|
|
164
|
+
return line;
|
|
165
|
+
})
|
|
166
|
+
.join('\n');
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Apply a reverse diff using git apply.
|
|
170
|
+
*/
|
|
171
|
+
async applyReverseDiff(filePath, reverseDiff) {
|
|
172
|
+
const tmpFile = path.join(require('os').tmpdir(), `doomcode-reverse-${Date.now()}-${randomUUID().slice(0, 8)}.patch`);
|
|
173
|
+
try {
|
|
174
|
+
// Write the reverse diff to a temp file
|
|
175
|
+
fs.writeFileSync(tmpFile, reverseDiff, 'utf8');
|
|
176
|
+
// Try to apply using git apply
|
|
177
|
+
try {
|
|
178
|
+
execSync(`git apply --check "${tmpFile}"`, {
|
|
179
|
+
cwd: this.workingDirectory,
|
|
180
|
+
stdio: 'pipe',
|
|
181
|
+
});
|
|
182
|
+
execSync(`git apply "${tmpFile}"`, {
|
|
183
|
+
cwd: this.workingDirectory,
|
|
184
|
+
stdio: 'pipe',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (gitError) {
|
|
188
|
+
// Git apply failed, try manual revert
|
|
189
|
+
console.warn(`git apply failed for ${filePath}, attempting manual revert`);
|
|
190
|
+
this.manualRevert(filePath, reverseDiff);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
// Clean up temp file
|
|
195
|
+
if (fs.existsSync(tmpFile)) {
|
|
196
|
+
fs.unlinkSync(tmpFile);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Fallback: manually revert a file by parsing the reverse diff.
|
|
202
|
+
* This is a simplified implementation for basic cases.
|
|
203
|
+
*/
|
|
204
|
+
manualRevert(filePath, reverseDiff) {
|
|
205
|
+
const fullPath = path.join(this.workingDirectory, filePath);
|
|
206
|
+
// For deleted files (reverse of add), just delete
|
|
207
|
+
if (reverseDiff.includes('new file mode')) {
|
|
208
|
+
if (fs.existsSync(fullPath)) {
|
|
209
|
+
fs.unlinkSync(fullPath);
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// For added files (reverse of delete), we'd need the original content
|
|
214
|
+
// This is a limitation - we should store original content for deleted files
|
|
215
|
+
if (reverseDiff.includes('deleted file mode')) {
|
|
216
|
+
console.warn(`Cannot restore deleted file ${filePath} - original content not preserved`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// For modified files, try line-by-line patch
|
|
220
|
+
// This is a simplified implementation
|
|
221
|
+
if (fs.existsSync(fullPath)) {
|
|
222
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
223
|
+
const lines = content.split('\n');
|
|
224
|
+
const diffLines = reverseDiff.split('\n');
|
|
225
|
+
// Parse diff hunks and apply changes
|
|
226
|
+
// Note: This is a basic implementation and may not handle all edge cases
|
|
227
|
+
let outputLines = [...lines];
|
|
228
|
+
let lineOffset = 0;
|
|
229
|
+
for (const diffLine of diffLines) {
|
|
230
|
+
if (diffLine.startsWith('@@')) {
|
|
231
|
+
// Parse hunk header: @@ -start,count +start,count @@
|
|
232
|
+
const match = diffLine.match(/@@ -(\d+),?\d* \+(\d+),?\d* @@/);
|
|
233
|
+
if (match) {
|
|
234
|
+
lineOffset = parseInt(match[2], 10) - 1;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else if (diffLine.startsWith('+') && !diffLine.startsWith('+++')) {
|
|
238
|
+
// Add line
|
|
239
|
+
const lineContent = diffLine.slice(1);
|
|
240
|
+
outputLines.splice(lineOffset, 0, lineContent);
|
|
241
|
+
lineOffset++;
|
|
242
|
+
}
|
|
243
|
+
else if (diffLine.startsWith('-') && !diffLine.startsWith('---')) {
|
|
244
|
+
// Remove line
|
|
245
|
+
if (outputLines[lineOffset] === diffLine.slice(1)) {
|
|
246
|
+
outputLines.splice(lineOffset, 1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else if (!diffLine.startsWith('\\')) {
|
|
250
|
+
// Context line
|
|
251
|
+
lineOffset++;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
fs.writeFileSync(fullPath, outputLines.join('\n'), 'utf8');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=patch-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch-tracker.js","sourceRoot":"","sources":["../../src/agent/patch-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects permission requests in agent output.
|
|
5
|
+
*/
|
|
6
|
+
import type { PermissionRequestMessage } from '@doomcode/protocol';
|
|
7
|
+
export declare class PermissionDetector {
|
|
8
|
+
detect(output: string): PermissionRequestMessage | null;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=permission-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-detector.d.ts","sourceRoot":"","sources":["../../src/agent/permission-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAoB,MAAM,oBAAoB,CAAC;AAqErF,qBAAa,kBAAkB;IAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI;CAoBxD"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects permission requests in agent output.
|
|
5
|
+
*/
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
7
|
+
const PATTERNS = [
|
|
8
|
+
// Claude Code file read permission
|
|
9
|
+
{
|
|
10
|
+
regex: /Do you want to read (.+)\? \[y\/n\]/i,
|
|
11
|
+
action: 'file_read',
|
|
12
|
+
extractDetails: (match) => ({
|
|
13
|
+
description: `Read file: ${match[1]}`,
|
|
14
|
+
details: { path: match[1] },
|
|
15
|
+
}),
|
|
16
|
+
},
|
|
17
|
+
// Claude Code file write permission
|
|
18
|
+
{
|
|
19
|
+
regex: /Do you want to write to (.+)\? \[y\/n\]/i,
|
|
20
|
+
action: 'file_write',
|
|
21
|
+
extractDetails: (match) => ({
|
|
22
|
+
description: `Write to file: ${match[1]}`,
|
|
23
|
+
details: { path: match[1] },
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
26
|
+
// Claude Code shell command permission
|
|
27
|
+
{
|
|
28
|
+
regex: /Do you want to run: (.+)\? \[y\/n\]/i,
|
|
29
|
+
action: 'shell_command',
|
|
30
|
+
extractDetails: (match) => ({
|
|
31
|
+
description: `Run command: ${match[1]}`,
|
|
32
|
+
details: { command: match[1] },
|
|
33
|
+
}),
|
|
34
|
+
},
|
|
35
|
+
// Generic permission request
|
|
36
|
+
{
|
|
37
|
+
regex: /Allow (.+?) access\? \(yes\/no\)/i,
|
|
38
|
+
action: 'other',
|
|
39
|
+
extractDetails: (match) => ({
|
|
40
|
+
description: match[1],
|
|
41
|
+
details: {},
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
// Permission required prompt
|
|
45
|
+
{
|
|
46
|
+
regex: /Permission required: (.+)/i,
|
|
47
|
+
action: 'other',
|
|
48
|
+
extractDetails: (match) => ({
|
|
49
|
+
description: match[1],
|
|
50
|
+
details: {},
|
|
51
|
+
}),
|
|
52
|
+
},
|
|
53
|
+
// Y/N confirmation (generic)
|
|
54
|
+
{
|
|
55
|
+
regex: /Do you want to (.*?)\? \[y\/n\]/i,
|
|
56
|
+
action: 'other',
|
|
57
|
+
extractDetails: (match) => ({
|
|
58
|
+
description: match[1],
|
|
59
|
+
details: {},
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
export class PermissionDetector {
|
|
64
|
+
detect(output) {
|
|
65
|
+
// Check against each pattern
|
|
66
|
+
for (const pattern of PATTERNS) {
|
|
67
|
+
const match = output.match(pattern.regex);
|
|
68
|
+
if (match) {
|
|
69
|
+
const { description, details } = pattern.extractDetails(match);
|
|
70
|
+
return {
|
|
71
|
+
type: 'permission_request',
|
|
72
|
+
requestId: randomUUID(),
|
|
73
|
+
action: pattern.action,
|
|
74
|
+
description,
|
|
75
|
+
details,
|
|
76
|
+
timeout: 60000, // 1 minute timeout
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=permission-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-detector.js","sourceRoot":"","sources":["../../src/agent/permission-detector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAWpC,MAAM,QAAQ,GAAuB;IACnC,mCAAmC;IACnC;QACE,KAAK,EAAE,sCAAsC;QAC7C,MAAM,EAAE,WAAW;QACnB,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC1B,WAAW,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,EAAE;YACrC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE;SAC5B,CAAC;KACH;IACD,oCAAoC;IACpC;QACE,KAAK,EAAE,0CAA0C;QACjD,MAAM,EAAE,YAAY;QACpB,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC1B,WAAW,EAAE,kBAAkB,KAAK,CAAC,CAAC,CAAC,EAAE;YACzC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE;SAC5B,CAAC;KACH;IACD,uCAAuC;IACvC;QACE,KAAK,EAAE,sCAAsC;QAC7C,MAAM,EAAE,eAAe;QACvB,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC1B,WAAW,EAAE,gBAAgB,KAAK,CAAC,CAAC,CAAC,EAAE;YACvC,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE;SAC/B,CAAC;KACH;IACD,6BAA6B;IAC7B;QACE,KAAK,EAAE,mCAAmC;QAC1C,MAAM,EAAE,OAAO;QACf,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC1B,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;YACrB,OAAO,EAAE,EAAE;SACZ,CAAC;KACH;IACD,6BAA6B;IAC7B;QACE,KAAK,EAAE,4BAA4B;QACnC,MAAM,EAAE,OAAO;QACf,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC1B,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;YACrB,OAAO,EAAE,EAAE;SACZ,CAAC;KACH;IACD,6BAA6B;IAC7B;QACE,KAAK,EAAE,kCAAkC;QACzC,MAAM,EAAE,OAAO;QACf,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC1B,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;YACrB,OAAO,EAAE,EAAE;SACZ,CAAC;KACH;CACF,CAAC;AAEF,MAAM,OAAO,kBAAkB;IAC7B,MAAM,CAAC,MAAc;QACnB,6BAA6B;QAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1C,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;gBAE/D,OAAO;oBACL,IAAI,EAAE,oBAAoB;oBAC1B,SAAS,EAAE,UAAU,EAAE;oBACvB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,WAAW;oBACX,OAAO;oBACP,OAAO,EAAE,KAAK,EAAE,mBAAmB;iBACpC,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
|