@contextrail/code-review-agent 0.1.1 → 0.1.2-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/help.d.ts +2 -0
- package/dist/cli/help.js +48 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/parser.d.ts +3 -0
- package/dist/cli/parser.js +144 -0
- package/dist/cli/types.d.ts +17 -0
- package/dist/cli/types.js +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +16 -0
- package/dist/errors/error-utils.d.ts +2 -0
- package/dist/errors/error-utils.js +37 -0
- package/dist/index.js +40 -578
- package/dist/lifecycle.d.ts +4 -0
- package/dist/lifecycle.js +52 -0
- package/dist/output/summary-logger.d.ts +3 -0
- package/dist/output/summary-logger.js +81 -0
- package/dist/pipeline.d.ts +25 -0
- package/dist/pipeline.js +267 -0
- package/dist/review-inputs/filtering.d.ts +14 -0
- package/dist/review-inputs/filtering.js +97 -8
- package/dist/review-inputs/index.js +59 -13
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { access, mkdir, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { gitDiffProvider } from './git-diff-provider.js';
|
|
4
|
-
import {
|
|
4
|
+
import { DEFAULT_EXCLUDE_PATTERNS } from '../config/defaults.js';
|
|
5
|
+
import { filterDiffInputs, filterFiles, parseGitignoreContent } from './filtering.js';
|
|
5
6
|
export { triagePr } from './triage.js';
|
|
6
7
|
export const isDiffInputs = (inputs) => inputs.mode === 'diff';
|
|
7
8
|
export const isFileListInputs = (inputs) => inputs.mode === 'file-list';
|
|
@@ -45,6 +46,43 @@ const validateFileList = async (files, basePath) => {
|
|
|
45
46
|
const normalizeFiles = (files) => {
|
|
46
47
|
return files.map((file) => file.trim()).filter(Boolean);
|
|
47
48
|
};
|
|
49
|
+
const mergeFilteringWithRootGitignore = async (filtering, repoRoot) => {
|
|
50
|
+
if (!repoRoot) {
|
|
51
|
+
return filtering;
|
|
52
|
+
}
|
|
53
|
+
const gitignorePath = path.join(repoRoot, '.gitignore');
|
|
54
|
+
try {
|
|
55
|
+
const gitignoreContents = await readFile(gitignorePath, 'utf-8');
|
|
56
|
+
if (typeof gitignoreContents !== 'string' || gitignoreContents.length === 0) {
|
|
57
|
+
return filtering;
|
|
58
|
+
}
|
|
59
|
+
const parsed = parseGitignoreContent(gitignoreContents);
|
|
60
|
+
if (parsed.excludePatterns.length === 0 && parsed.includePatterns.length === 0) {
|
|
61
|
+
return filtering;
|
|
62
|
+
}
|
|
63
|
+
const excludePatterns = filtering?.excludePatterns
|
|
64
|
+
? [...filtering.excludePatterns, ...parsed.excludePatterns]
|
|
65
|
+
: [...DEFAULT_EXCLUDE_PATTERNS, ...parsed.excludePatterns];
|
|
66
|
+
const includePatterns = [...(filtering?.includePatterns ?? []), ...parsed.includePatterns];
|
|
67
|
+
return {
|
|
68
|
+
...filtering,
|
|
69
|
+
excludePatterns,
|
|
70
|
+
includePatterns,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75
|
+
const code = typeof error === 'object' && error !== null && 'code' in error
|
|
76
|
+
? String(error.code)
|
|
77
|
+
: undefined;
|
|
78
|
+
const isMissingFileMessage = message.toLowerCase().includes('no such file') || message.toLowerCase().includes('file not found');
|
|
79
|
+
// Missing .gitignore is expected in many repos; keep defaults without failing.
|
|
80
|
+
if (code === 'ENOENT' || isMissingFileMessage) {
|
|
81
|
+
return filtering;
|
|
82
|
+
}
|
|
83
|
+
throw new Error(`Failed to read root .gitignore at "${gitignorePath}": ${message}`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
48
86
|
export const buildReviewInputs = async (options, deps) => {
|
|
49
87
|
if (options.mode === 'diff') {
|
|
50
88
|
const diffProvider = deps?.diffProvider ?? gitDiffProvider;
|
|
@@ -53,8 +91,9 @@ export const buildReviewInputs = async (options, deps) => {
|
|
|
53
91
|
from: options.from,
|
|
54
92
|
to: options.to,
|
|
55
93
|
});
|
|
94
|
+
const mergedFiltering = await mergeFilteringWithRootGitignore(options.filtering, options.repoPath);
|
|
56
95
|
const normalizedFiles = normalizeFiles(result.files);
|
|
57
|
-
const { files, diffs } = filterDiffInputs(normalizedFiles, result.diffs,
|
|
96
|
+
const { files, diffs } = filterDiffInputs(normalizedFiles, result.diffs, mergedFiltering);
|
|
58
97
|
if (files.length === 0) {
|
|
59
98
|
throw new Error('Diff mode produced no files to review after filtering.');
|
|
60
99
|
}
|
|
@@ -76,8 +115,9 @@ export const buildReviewInputs = async (options, deps) => {
|
|
|
76
115
|
}
|
|
77
116
|
return inputs;
|
|
78
117
|
}
|
|
118
|
+
const mergedFiltering = await mergeFilteringWithRootGitignore(options.filtering, options.basePath);
|
|
79
119
|
const normalizedFiles = normalizeFiles(options.files);
|
|
80
|
-
const files = filterFiles(normalizedFiles,
|
|
120
|
+
const files = filterFiles(normalizedFiles, mergedFiltering);
|
|
81
121
|
if (files.length === 0) {
|
|
82
122
|
throw new Error('File list produced no files to review after filtering.');
|
|
83
123
|
}
|
|
@@ -108,15 +148,21 @@ export const buildReviewInputs = async (options, deps) => {
|
|
|
108
148
|
return inputs;
|
|
109
149
|
};
|
|
110
150
|
export const persistReviewInputs = async (inputs, outputDir) => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
151
|
+
try {
|
|
152
|
+
await mkdir(outputDir, { recursive: true });
|
|
153
|
+
const filesPayload = JSON.stringify({ mode: inputs.mode, files: inputs.files }, null, 2);
|
|
154
|
+
await writeFile(path.join(outputDir, 'files.json'), filesPayload);
|
|
155
|
+
if (inputs.mode !== 'diff') {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
for (const [filePath, diff] of Object.entries(inputs.diffs)) {
|
|
159
|
+
const diffPath = path.join(outputDir, 'diff', `${filePath}.diff`);
|
|
160
|
+
await mkdir(path.dirname(diffPath), { recursive: true });
|
|
161
|
+
await writeFile(diffPath, diff);
|
|
162
|
+
}
|
|
116
163
|
}
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
await writeFile(diffPath, diff);
|
|
164
|
+
catch (error) {
|
|
165
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
166
|
+
throw new Error(`Failed to persist review inputs to "${outputDir}": ${message}`);
|
|
121
167
|
}
|
|
122
168
|
};
|