@motivation-labs/crosscheck 0.10.3 → 0.10.4-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/codex.test.js +35 -1
- package/dist/__tests__/codex.test.js.map +1 -1
- package/dist/__tests__/fix.test.d.ts +2 -0
- package/dist/__tests__/fix.test.d.ts.map +1 -0
- package/dist/__tests__/fix.test.js +126 -0
- package/dist/__tests__/fix.test.js.map +1 -0
- package/dist/reviewers/codex.d.ts.map +1 -1
- package/dist/reviewers/codex.js +21 -2
- package/dist/reviewers/codex.js.map +1 -1
- package/dist/reviewers/fix.d.ts +1 -0
- package/dist/reviewers/fix.d.ts.map +1 -1
- package/dist/reviewers/fix.js +112 -14
- package/dist/reviewers/fix.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, writeFileSync, readFileSync, existsSync, rmSync, mkdirSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
2
5
|
import { inferVerdictFromCodexOutput } from '../reviewers/codex.js';
|
|
3
6
|
const CODEX_FOOTER = '\n\n---\n_Reviewed with [OpenAI Codex](https://openai.com/codex)_';
|
|
4
7
|
describe('inferVerdictFromCodexOutput', () => {
|
|
@@ -39,6 +42,10 @@ describe('inferVerdictFromCodexOutput', () => {
|
|
|
39
42
|
expect(inferVerdictFromCodexOutput('[p1] issue')).toBe('BLOCK');
|
|
40
43
|
expect(inferVerdictFromCodexOutput('[P2] issue')).toBe('NEEDS WORK');
|
|
41
44
|
});
|
|
45
|
+
it('is case-insensitive for [p0]/[p1]/[p2]/[p3]', () => {
|
|
46
|
+
expect(inferVerdictFromCodexOutput('[p1] issue')).toBe('BLOCK');
|
|
47
|
+
expect(inferVerdictFromCodexOutput('[P2] issue')).toBe('NEEDS WORK');
|
|
48
|
+
});
|
|
42
49
|
it('infers correctly from real Codex output shape (motivation-form PR #90)', () => {
|
|
43
50
|
const realOutput = `The added guidance contains copy-paste survey templates that default to form mode.
|
|
44
51
|
|
|
@@ -55,4 +62,31 @@ _Reviewed with [OpenAI Codex](https://openai.com/codex)_`;
|
|
|
55
62
|
expect(inferVerdictFromCodexOutput(realOutput)).toBe('NEEDS WORK');
|
|
56
63
|
});
|
|
57
64
|
});
|
|
65
|
+
describe('.codex/instructions cleanup after review', () => {
|
|
66
|
+
let repoDir;
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
repoDir = mkdtempSync(join(tmpdir(), 'crosscheck-test-'));
|
|
69
|
+
mkdirSync(join(repoDir, '.codex'), { recursive: true });
|
|
70
|
+
});
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
rmSync(repoDir, { force: true, recursive: true });
|
|
73
|
+
});
|
|
74
|
+
it('deletes .codex/instructions when it did not exist before the review', () => {
|
|
75
|
+
const instructionsPath = join(repoDir, '.codex', 'instructions');
|
|
76
|
+
// Simulate what runCodexReview does: write the file
|
|
77
|
+
writeFileSync(instructionsPath, 'crosscheck review instructions');
|
|
78
|
+
// Simulate cleanup (originalInstructions was undefined)
|
|
79
|
+
rmSync(instructionsPath, { force: true });
|
|
80
|
+
expect(existsSync(instructionsPath)).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
it('restores original .codex/instructions content after review', () => {
|
|
83
|
+
const instructionsPath = join(repoDir, '.codex', 'instructions');
|
|
84
|
+
const original = 'user-defined codex instructions';
|
|
85
|
+
writeFileSync(instructionsPath, original);
|
|
86
|
+
// Simulate: crosscheck overwrites, then restores
|
|
87
|
+
writeFileSync(instructionsPath, 'crosscheck review instructions');
|
|
88
|
+
writeFileSync(instructionsPath, original);
|
|
89
|
+
expect(readFileSync(instructionsPath, 'utf8')).toBe(original);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
58
92
|
//# sourceMappingURL=codex.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.test.js","sourceRoot":"","sources":["../../src/__tests__/codex.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"codex.test.js","sourceRoot":"","sources":["../../src/__tests__/codex.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fix.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'fs';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { applyEdit } from '../reviewers/fix.js';
|
|
6
|
+
describe('applyEdit', () => {
|
|
7
|
+
it('replaces exact match at start of file', () => {
|
|
8
|
+
const content = 'function foo() {\n return 1\n}\n';
|
|
9
|
+
const result = applyEdit(content, 'return 1', 'return 2');
|
|
10
|
+
expect(result).toBe('function foo() {\n return 2\n}\n');
|
|
11
|
+
});
|
|
12
|
+
it('returns null when old text is not found', () => {
|
|
13
|
+
const content = 'function foo() {\n return 1\n}\n';
|
|
14
|
+
expect(applyEdit(content, 'return 99', 'return 2')).toBeNull();
|
|
15
|
+
});
|
|
16
|
+
it('returns null when old text is ambiguous (appears more than once)', () => {
|
|
17
|
+
const content = 'a\na\na\n';
|
|
18
|
+
expect(applyEdit(content, 'a', 'b')).toBeNull();
|
|
19
|
+
});
|
|
20
|
+
it('handles multi-line old text', () => {
|
|
21
|
+
const content = 'line1\nline2\nline3\nline4\n';
|
|
22
|
+
const result = applyEdit(content, 'line2\nline3', 'replaced');
|
|
23
|
+
expect(result).toBe('line1\nreplaced\nline4\n');
|
|
24
|
+
});
|
|
25
|
+
it('can replace with empty string (deletion)', () => {
|
|
26
|
+
const content = 'before\ndelete me\nafter\n';
|
|
27
|
+
const result = applyEdit(content, 'delete me\n', '');
|
|
28
|
+
expect(result).toBe('before\nafter\n');
|
|
29
|
+
});
|
|
30
|
+
it('returns null on empty old text (ambiguous — matches everywhere)', () => {
|
|
31
|
+
// '' satisfies indexOf !== lastIndexOf, so the ambiguity guard rejects it.
|
|
32
|
+
// Callers handle new-file creation separately before invoking applyEdit.
|
|
33
|
+
expect(applyEdit('content', '', 'new')).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe('fix step <edit> block parsing', () => {
|
|
37
|
+
let tmpDir;
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'crosscheck-fix-test-'));
|
|
40
|
+
});
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
rmSync(tmpDir, { force: true, recursive: true });
|
|
43
|
+
});
|
|
44
|
+
it('size guard: rejects <file> block when new content < 60% of original', async () => {
|
|
45
|
+
// Write a "large" original file (10 lines)
|
|
46
|
+
const filePath = join(tmpDir, 'src', 'large.ts');
|
|
47
|
+
const { mkdirSync } = await import('fs');
|
|
48
|
+
mkdirSync(join(tmpDir, 'src'), { recursive: true });
|
|
49
|
+
const original = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join('\n') + '\n';
|
|
50
|
+
writeFileSync(filePath, original);
|
|
51
|
+
// Simulate Claude outputting only 3 lines for a 10-line file (30% — below 60% threshold)
|
|
52
|
+
const truncated = 'line1\nline2\nline3\n';
|
|
53
|
+
// Directly test the guard logic: if newLines / origLines < 0.6, skip
|
|
54
|
+
const origLines = original.split('\n').length;
|
|
55
|
+
const newLines = truncated.split('\n').length;
|
|
56
|
+
expect(newLines / origLines).toBeLessThan(0.6);
|
|
57
|
+
// Confirm original is unchanged (guard would have skipped the write)
|
|
58
|
+
expect(readFileSync(filePath, 'utf8')).toBe(original);
|
|
59
|
+
});
|
|
60
|
+
it('size guard: accepts <file> block when new content >= 60% of original', () => {
|
|
61
|
+
const original = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join('\n') + '\n';
|
|
62
|
+
const replacement = Array.from({ length: 7 }, (_, i) => `replaced${i + 1}`).join('\n') + '\n';
|
|
63
|
+
const origLines = original.split('\n').length;
|
|
64
|
+
const newLines = replacement.split('\n').length;
|
|
65
|
+
expect(newLines / origLines).toBeGreaterThanOrEqual(0.6);
|
|
66
|
+
});
|
|
67
|
+
it('applyEdit composes correctly for multiple edits to same file', () => {
|
|
68
|
+
const content = 'a: 1\nb: 2\nc: 3\n';
|
|
69
|
+
const after1 = applyEdit(content, 'a: 1', 'a: 10');
|
|
70
|
+
expect(after1).not.toBeNull();
|
|
71
|
+
const after2 = applyEdit(after1, 'b: 2', 'b: 20');
|
|
72
|
+
expect(after2).not.toBeNull();
|
|
73
|
+
expect(after2).toBe('a: 10\nb: 20\nc: 3\n');
|
|
74
|
+
});
|
|
75
|
+
it('failed <old> match does not count as applied or write the unchanged file', () => {
|
|
76
|
+
// Regression for: file added to fileEdits during read step, then applyEdit returns null,
|
|
77
|
+
// but write loop still writes it and increments appliedCount.
|
|
78
|
+
const filePath = join(tmpDir, 'src.ts');
|
|
79
|
+
const original = 'export function foo() {\n return 1\n}\n';
|
|
80
|
+
writeFileSync(filePath, original);
|
|
81
|
+
// applyEdit with a non-matching old text returns null — file must not be touched
|
|
82
|
+
const result = applyEdit(original, 'does not exist in file', 'anything');
|
|
83
|
+
expect(result).toBeNull();
|
|
84
|
+
// File must be untouched on disk
|
|
85
|
+
expect(readFileSync(filePath, 'utf8')).toBe(original);
|
|
86
|
+
});
|
|
87
|
+
it('applyEdit: empty old text returns null (ambiguity guard catches it)', () => {
|
|
88
|
+
// Empty string satisfies indexOf('') !== lastIndexOf(''), so applyEdit rejects it.
|
|
89
|
+
// runFixStep handles new-file creation (empty <old> on missing file) before calling applyEdit.
|
|
90
|
+
expect(applyEdit('existing content', '', 'prepended ')).toBeNull();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('fix step new-file and empty-old guard', () => {
|
|
94
|
+
let tmpDir;
|
|
95
|
+
beforeEach(() => {
|
|
96
|
+
tmpDir = mkdtempSync(join(tmpdir(), 'crosscheck-fix-test-'));
|
|
97
|
+
});
|
|
98
|
+
afterEach(() => {
|
|
99
|
+
rmSync(tmpDir, { force: true, recursive: true });
|
|
100
|
+
});
|
|
101
|
+
it('empty <old> on existing file is rejected — does not prepend new text', () => {
|
|
102
|
+
const { mkdirSync: mkdir } = require('fs');
|
|
103
|
+
mkdir(join(tmpDir, 'src'), { recursive: true });
|
|
104
|
+
const filePath = join(tmpDir, 'src', 'util.ts');
|
|
105
|
+
const original = 'export const x = 1\n';
|
|
106
|
+
writeFileSync(filePath, original);
|
|
107
|
+
// applyEdit('export const x = 1\n', '', 'prepended\n') would prepend if not guarded.
|
|
108
|
+
// The guard in runFixStep must block this — original must be unchanged.
|
|
109
|
+
// We verify the guard logic directly: empty oldText on existing file => skip.
|
|
110
|
+
const oldText = '';
|
|
111
|
+
const fileExists = true; // file was readable
|
|
112
|
+
const wouldBeGuarded = fileExists && oldText === '';
|
|
113
|
+
expect(wouldBeGuarded).toBe(true);
|
|
114
|
+
expect(readFileSync(filePath, 'utf8')).toBe(original);
|
|
115
|
+
});
|
|
116
|
+
it('empty <old> on non-existent file writes <new> as new file content', () => {
|
|
117
|
+
const { mkdirSync: mkdir } = require('fs');
|
|
118
|
+
mkdir(join(tmpDir, 'src'), { recursive: true });
|
|
119
|
+
const newFilePath = join(tmpDir, 'src', 'new-module.ts');
|
|
120
|
+
// File does not exist — simulate the new-file path: write newText directly
|
|
121
|
+
const newContent = 'export const added = true\n';
|
|
122
|
+
writeFileSync(newFilePath, newContent); // as runFixStep would do for empty <old>
|
|
123
|
+
expect(readFileSync(newFilePath, 'utf8')).toBe(newContent);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=fix.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.test.js","sourceRoot":"","sources":["../../src/__tests__/fix.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/reviewers/codex.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAK/C,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIhE;AA8BD,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,iBAAiB,EACzB,gBAAgB,CAAC,EAAE,MAAM,EACzB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC5B,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/reviewers/codex.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAK/C,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIhE;AA8BD,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,iBAAiB,EACzB,gBAAgB,CAAC,EAAE,MAAM,EACzB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC5B,OAAO,CAAC,YAAY,CAAC,CA4EvB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ/E"}
|
package/dist/reviewers/codex.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execa } from 'execa';
|
|
2
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'fs';
|
|
2
|
+
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from 'fs';
|
|
3
3
|
import { tmpdir } from 'os';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import { DEFAULT_REVIEW_INSTRUCTIONS } from '../lib/workflow.js';
|
|
@@ -51,8 +51,16 @@ export async function runCodexReview(repoDir, baseBranch, prTitle, quality, vend
|
|
|
51
51
|
const customNote = quality.custom_prompt ?? '';
|
|
52
52
|
const behaviorInstructions = stepInstructions ?? DEFAULT_REVIEW_INSTRUCTIONS;
|
|
53
53
|
const instructionsNote = [focusNote, customNote, behaviorInstructions].filter(Boolean).join('\n\n');
|
|
54
|
+
const instructionsPath = `${repoDir}/.codex/instructions`;
|
|
55
|
+
// Save original content so we can restore it after the review — prevents the
|
|
56
|
+
// fix step's git add -A from committing crosscheck's instructions as a PR change.
|
|
57
|
+
let originalInstructions;
|
|
58
|
+
try {
|
|
59
|
+
originalInstructions = readFileSync(instructionsPath, 'utf8');
|
|
60
|
+
}
|
|
61
|
+
catch { /* didn't exist */ }
|
|
54
62
|
mkdirSync(`${repoDir}/.codex`, { recursive: true });
|
|
55
|
-
writeFileSync(
|
|
63
|
+
writeFileSync(instructionsPath, instructionsNote);
|
|
56
64
|
try {
|
|
57
65
|
const modelArgs = model ? ['-c', `model="${model}"`] : [];
|
|
58
66
|
onLog?.(` running: codex review --base ${baseBranch}${model ? ` -c model="${model}"` : ''}`);
|
|
@@ -91,6 +99,17 @@ export async function runCodexReview(repoDir, baseBranch, prTitle, quality, vend
|
|
|
91
99
|
throw thrown;
|
|
92
100
|
}
|
|
93
101
|
finally {
|
|
102
|
+
// Restore .codex/instructions to its pre-review state so the fix step's
|
|
103
|
+
// git add -A doesn't commit crosscheck's instructions as a PR file change.
|
|
104
|
+
try {
|
|
105
|
+
if (originalInstructions !== undefined) {
|
|
106
|
+
writeFileSync(instructionsPath, originalInstructions);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
rmSync(instructionsPath, { force: true });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch { /* ignore */ }
|
|
94
113
|
try {
|
|
95
114
|
rmSync(tmpFile, { force: true, recursive: true });
|
|
96
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/reviewers/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/reviewers/codex.ts"],"names":[],"mappings":"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"}
|
package/dist/reviewers/fix.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Config } from '../config/schema.js';
|
|
2
|
+
export declare function applyEdit(fileContent: string, oldText: string, newText: string): string | null;
|
|
2
3
|
export declare function runFixStep(tmpDir: string, baseRef: string, prTitle: string, reviewComment: string, instructions: string, config: Config): Promise<{
|
|
3
4
|
appliedCount: number;
|
|
4
5
|
tokensUsed?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../../src/reviewers/fix.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../../src/reviewers/fix.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AA4DjD,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO9F;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgIxD"}
|
package/dist/reviewers/fix.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
|
-
import { writeFileSync } from 'fs';
|
|
2
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { execa } from 'execa';
|
|
5
|
+
// Minimum ratio of new lines to original lines before we reject a full-file write.
|
|
6
|
+
// Guards against Claude silently truncating large files.
|
|
7
|
+
const MIN_SIZE_RATIO = 0.6;
|
|
5
8
|
const PROMPT_TEMPLATE = `You opened a pull request that received the following code review.
|
|
6
9
|
|
|
7
10
|
PR title: {PR_TITLE}
|
|
@@ -24,13 +27,41 @@ Please address the issues raised in the review. Rules:
|
|
|
24
27
|
- If a comment requires deeper understanding of business logic, skip it
|
|
25
28
|
- If the review has no actionable code changes, output exactly: NO_CHANGES
|
|
26
29
|
|
|
27
|
-
For each file you need to change, output the
|
|
30
|
+
For each file you need to change, output ONLY the edited sections using this format:
|
|
28
31
|
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
<edit path="relative/path/to/file.ext">
|
|
33
|
+
<old>
|
|
34
|
+
exact lines from the file that need to be replaced (copy verbatim — must match exactly)
|
|
35
|
+
</old>
|
|
36
|
+
<new>
|
|
37
|
+
replacement lines
|
|
38
|
+
</new>
|
|
39
|
+
</edit>
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
Rules for <edit> blocks:
|
|
42
|
+
- <old> must match the file content EXACTLY (whitespace, indentation, line endings)
|
|
43
|
+
- Include enough surrounding context lines (2–3) so the match is unambiguous
|
|
44
|
+
- One <edit> block per contiguous change; multiple blocks per file are fine
|
|
45
|
+
- Never output the entire file — only the sections that change
|
|
46
|
+
- If a file needs a new section appended, use an <old> that matches the last few lines before the insertion point
|
|
47
|
+
- To create a brand-new file, leave <old> empty and put the complete file content in <new>
|
|
48
|
+
|
|
49
|
+
Output ONLY <edit> blocks or NO_CHANGES. No other text.`;
|
|
50
|
+
function isSafePath(filePath) {
|
|
51
|
+
return !filePath.includes('..') && !filePath.startsWith('/');
|
|
52
|
+
}
|
|
53
|
+
// Apply a single edit: find <old> in fileContent and replace with <new>.
|
|
54
|
+
// Returns null if the old text is not found or appears more than once (ambiguous).
|
|
55
|
+
export function applyEdit(fileContent, oldText, newText) {
|
|
56
|
+
const idx = fileContent.indexOf(oldText);
|
|
57
|
+
if (idx === -1)
|
|
58
|
+
return null;
|
|
59
|
+
// Reject ambiguous matches — if the snippet appears more than once, indexOf and
|
|
60
|
+
// lastIndexOf disagree, so we can't know which occurrence Claude intended to edit.
|
|
61
|
+
if (fileContent.lastIndexOf(oldText) !== idx)
|
|
62
|
+
return null;
|
|
63
|
+
return fileContent.slice(0, idx) + newText + fileContent.slice(idx + oldText.length);
|
|
64
|
+
}
|
|
34
65
|
export async function runFixStep(tmpDir, baseRef, prTitle, reviewComment, instructions, config) {
|
|
35
66
|
let diff = '';
|
|
36
67
|
try {
|
|
@@ -76,22 +107,89 @@ export async function runFixStep(tmpDir, baseRef, prTitle, reviewComment, instru
|
|
|
76
107
|
}
|
|
77
108
|
if (!output || output === 'NO_CHANGES')
|
|
78
109
|
return { appliedCount: 0, tokensUsed };
|
|
79
|
-
// Parse <file path="...">content</file> blocks
|
|
80
|
-
const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/g;
|
|
81
|
-
let match;
|
|
82
110
|
let appliedCount = 0;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
111
|
+
// Primary: apply <edit path="..."><old>...</old><new>...</new></edit> blocks.
|
|
112
|
+
// This format only outputs changed sections — structurally prevents truncation.
|
|
113
|
+
const editRegex = /<edit path="([^"]+)">([\s\S]*?)<\/edit>/g;
|
|
114
|
+
const fileEdits = new Map(); // files with ≥1 successful edit
|
|
115
|
+
const fileCache = new Map(); // raw disk reads; never written directly
|
|
116
|
+
let match;
|
|
117
|
+
while ((match = editRegex.exec(output)) !== null) {
|
|
118
|
+
const [, filePath, body] = match;
|
|
119
|
+
if (!isSafePath(filePath))
|
|
120
|
+
continue;
|
|
121
|
+
const oldMatch = body.match(/<old>([\s\S]*?)<\/old>/);
|
|
122
|
+
const newMatch = body.match(/<new>([\s\S]*?)<\/new>/);
|
|
123
|
+
if (!oldMatch || !newMatch)
|
|
87
124
|
continue;
|
|
125
|
+
// Strip exactly one leading/trailing newline added by the XML-style tags
|
|
126
|
+
const oldText = oldMatch[1].replace(/^\n/, '').replace(/\n$/, '');
|
|
127
|
+
const newText = newMatch[1].replace(/^\n/, '').replace(/\n$/, '');
|
|
128
|
+
const absPath = join(tmpDir, filePath);
|
|
129
|
+
// fileCache holds disk reads; fileEdits holds files that have at least one
|
|
130
|
+
// successful edit applied. Keeping them separate prevents a failed <old> match
|
|
131
|
+
// from adding the unchanged file to fileEdits and inflating appliedCount.
|
|
132
|
+
let current = fileEdits.get(filePath) ?? fileCache.get(filePath);
|
|
133
|
+
const alreadyKnown = current !== undefined;
|
|
134
|
+
if (!alreadyKnown) {
|
|
135
|
+
try {
|
|
136
|
+
current = readFileSync(absPath, 'utf8');
|
|
137
|
+
fileCache.set(filePath, current);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// File doesn't exist on disk — allow new-file creation only when <old> is empty.
|
|
141
|
+
// Any non-empty <old> is meaningless against a non-existent file.
|
|
142
|
+
if (oldText !== '')
|
|
143
|
+
continue;
|
|
144
|
+
fileEdits.set(filePath, newText);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Guard: empty <old> on an existing file is ambiguous — indexOf('') = 0 would
|
|
149
|
+
// silently prepend <new> at the top of the file instead of anchoring to content.
|
|
150
|
+
if (oldText === '')
|
|
151
|
+
continue;
|
|
152
|
+
const updated = applyEdit(current, oldText, newText);
|
|
153
|
+
if (updated === null)
|
|
154
|
+
continue; // <old> not found — skip this edit safely
|
|
155
|
+
fileEdits.set(filePath, updated);
|
|
156
|
+
}
|
|
157
|
+
for (const [filePath, content] of fileEdits) {
|
|
88
158
|
const absPath = join(tmpDir, filePath);
|
|
89
159
|
try {
|
|
90
|
-
writeFileSync(absPath,
|
|
160
|
+
writeFileSync(absPath, content);
|
|
91
161
|
appliedCount++;
|
|
92
162
|
}
|
|
93
163
|
catch { /* skip unwritable paths */ }
|
|
94
164
|
}
|
|
165
|
+
// Fallback: <file path="...">complete content</file> blocks, with size guard.
|
|
166
|
+
// These are only accepted when the new content is >= MIN_SIZE_RATIO of the original,
|
|
167
|
+
// preventing silent truncation of large files.
|
|
168
|
+
if (appliedCount === 0) {
|
|
169
|
+
const fileRegex = /<file path="([^"]+)">([\s\S]*?)<\/file>/g;
|
|
170
|
+
while ((match = fileRegex.exec(output)) !== null) {
|
|
171
|
+
const [, filePath, rawContent] = match;
|
|
172
|
+
if (!isSafePath(filePath))
|
|
173
|
+
continue;
|
|
174
|
+
const absPath = join(tmpDir, filePath);
|
|
175
|
+
const newContent = rawContent.replace(/^\n/, '');
|
|
176
|
+
try {
|
|
177
|
+
let originalLineCount = 0;
|
|
178
|
+
try {
|
|
179
|
+
originalLineCount = readFileSync(absPath, 'utf8').split('\n').length;
|
|
180
|
+
}
|
|
181
|
+
catch { /* new file — no size guard needed */ }
|
|
182
|
+
if (originalLineCount > 0) {
|
|
183
|
+
const newLineCount = newContent.split('\n').length;
|
|
184
|
+
if (newLineCount < originalLineCount * MIN_SIZE_RATIO)
|
|
185
|
+
continue; // reject — likely truncated
|
|
186
|
+
}
|
|
187
|
+
writeFileSync(absPath, newContent);
|
|
188
|
+
appliedCount++;
|
|
189
|
+
}
|
|
190
|
+
catch { /* skip unwritable paths */ }
|
|
191
|
+
}
|
|
192
|
+
}
|
|
95
193
|
return { appliedCount, tokensUsed };
|
|
96
194
|
}
|
|
97
195
|
//# sourceMappingURL=fix.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix.js","sourceRoot":"","sources":["../../src/reviewers/fix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"fix.js","sourceRoot":"","sources":["../../src/reviewers/fix.ts"],"names":[],"mappings":"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"}
|