kodevu 0.1.33 → 0.1.36
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/package.json +1 -1
- package/src/config.js +3 -2
- package/src/git-client.js +19 -0
- package/src/review-runner.js +5 -4
- package/src/vcs-client.js +16 -2
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -214,6 +214,7 @@ export async function resolveConfig(cliArgs = {}) {
|
|
|
214
214
|
config.target = process.cwd();
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
config.baseDir = process.cwd();
|
|
217
218
|
config.debug = Boolean(cliArgs.debug);
|
|
218
219
|
config.reviewer = String(config.reviewer || "auto").toLowerCase();
|
|
219
220
|
config.lang = String(config.lang || "auto").toLowerCase();
|
|
@@ -265,8 +266,8 @@ Options:
|
|
|
265
266
|
--reviewer, -r Reviewer (codex | gemini | copilot | auto, default: auto)
|
|
266
267
|
--prompt, -p Additional instructions or @file.txt to read from file
|
|
267
268
|
--lang, -l Output language (e.g. zh, en, auto)
|
|
268
|
-
--rev, -v Review
|
|
269
|
-
--last, -n Review the latest N revisions (default: 1)
|
|
269
|
+
--rev, -v Review specific revision(s), hashes, branches or ranges (comma-separated)
|
|
270
|
+
--last, -n Review the latest N revisions (ignored if --rev is provided) (default: 1)
|
|
270
271
|
--output, -o Output directory (default: ~/.kodevu)
|
|
271
272
|
--format, -f Output formats (markdown, json, comma-separated)
|
|
272
273
|
--debug, -d Print extra debug information
|
package/src/git-client.js
CHANGED
|
@@ -105,6 +105,25 @@ export async function isValidCheckpoint(config, targetInfo, checkpointCommit, la
|
|
|
105
105
|
return ancestorResult.code === 0;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
export async function resolveCommits(config, targetInfo, revSpec) {
|
|
109
|
+
const result = await runGit(
|
|
110
|
+
config,
|
|
111
|
+
["rev-list", revSpec],
|
|
112
|
+
{ cwd: targetInfo.repoRootPath, trim: true, allowFailure: true }
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (result.code !== 0) {
|
|
116
|
+
// Attempt fallback to a single hash resolution if rev-list fails (e.g. for non-standard specs)
|
|
117
|
+
const single = await runGit(config, ["rev-parse", revSpec], {
|
|
118
|
+
cwd: targetInfo.repoRootPath, trim: true, allowFailure: true
|
|
119
|
+
});
|
|
120
|
+
if (single.code === 0) return [single.stdout.trim()];
|
|
121
|
+
throw new Error(`Failed to resolve Git revision: ${revSpec}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return splitLines(result.stdout);
|
|
125
|
+
}
|
|
126
|
+
|
|
108
127
|
export async function getPendingCommits(config, targetInfo, startExclusive, endInclusive, limit) {
|
|
109
128
|
const args = ["rev-list", "--reverse"];
|
|
110
129
|
|
package/src/review-runner.js
CHANGED
|
@@ -20,6 +20,7 @@ async function reviewChange(config, backend, targetInfo, changeId, progress) {
|
|
|
20
20
|
logger.info(`Starting review for ${backend.changeName} ${displayId}`);
|
|
21
21
|
progress?.update(0.05, "loading change details");
|
|
22
22
|
const details = await backend.getChangeDetails(config, targetInfo, changeId);
|
|
23
|
+
const resolvedChangeId = details.id;
|
|
23
24
|
|
|
24
25
|
if (details.changedPaths.length === 0) {
|
|
25
26
|
progress?.update(0.7, "writing skipped report");
|
|
@@ -29,7 +30,7 @@ async function reviewChange(config, backend, targetInfo, changeId, progress) {
|
|
|
29
30
|
"No file changes were captured for this change under the configured target."
|
|
30
31
|
].join("\n");
|
|
31
32
|
|
|
32
|
-
const markdownReportFile = path.join(config.outputDir, backend.getReportFileName(
|
|
33
|
+
const markdownReportFile = path.join(config.outputDir, backend.getReportFileName(resolvedChangeId));
|
|
33
34
|
const jsonReportFile = markdownReportFile.replace(/\.md$/i, ".json");
|
|
34
35
|
|
|
35
36
|
if (shouldWriteFormat(config, "markdown")) {
|
|
@@ -55,7 +56,7 @@ async function reviewChange(config, backend, targetInfo, changeId, progress) {
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
progress?.update(0.2, "loading diff");
|
|
58
|
-
const diffText = await backend.getChangeDiff(config, targetInfo,
|
|
59
|
+
const diffText = await backend.getChangeDiff(config, targetInfo, resolvedChangeId);
|
|
59
60
|
const reviewersToTry = [config.reviewer, ...(config.fallbackReviewers || [])];
|
|
60
61
|
|
|
61
62
|
let reviewer;
|
|
@@ -99,7 +100,7 @@ async function reviewChange(config, backend, targetInfo, changeId, progress) {
|
|
|
99
100
|
progress?.update(0.82, "writing report");
|
|
100
101
|
logger.debug(`Token usage: input=${tokenUsage.inputTokens} output=${tokenUsage.outputTokens} total=${tokenUsage.totalTokens} source=${tokenUsage.source}`);
|
|
101
102
|
const report = buildReport(currentReviewerConfig, backend, targetInfo, details, diffPayloads, reviewer, reviewerResult, tokenUsage);
|
|
102
|
-
const outputFile = path.join(config.outputDir, backend.getReportFileName(
|
|
103
|
+
const outputFile = path.join(config.outputDir, backend.getReportFileName(resolvedChangeId));
|
|
103
104
|
const jsonOutputFile = outputFile.replace(/\.md$/i, ".json");
|
|
104
105
|
|
|
105
106
|
if (shouldWriteFormat(config, "markdown")) {
|
|
@@ -156,7 +157,7 @@ export async function runReviewCycle(config) {
|
|
|
156
157
|
let changeIdsToReview = [];
|
|
157
158
|
|
|
158
159
|
if (config.rev) {
|
|
159
|
-
changeIdsToReview =
|
|
160
|
+
changeIdsToReview = await backend.resolveChangeIds(config, targetInfo, config.rev);
|
|
160
161
|
} else {
|
|
161
162
|
changeIdsToReview = await backend.getLatestChangeIds(config, targetInfo, config.last || 1);
|
|
162
163
|
}
|
package/src/vcs-client.js
CHANGED
|
@@ -36,6 +36,10 @@ function createSvnBackend() {
|
|
|
36
36
|
return `${datePrefix}-svn-r${revision}.md`;
|
|
37
37
|
},
|
|
38
38
|
|
|
39
|
+
async resolveChangeIds(config, targetInfo, revString) {
|
|
40
|
+
if (!revString) return [];
|
|
41
|
+
return String(revString).split(',').map(s => s.trim()).filter(Boolean);
|
|
42
|
+
},
|
|
39
43
|
async getTargetInfo(config) {
|
|
40
44
|
return await svnClient.getTargetInfo(config);
|
|
41
45
|
},
|
|
@@ -83,6 +87,16 @@ function createGitBackend() {
|
|
|
83
87
|
return `${datePrefix}-git-${commitHash.slice(0, 12)}.md`;
|
|
84
88
|
},
|
|
85
89
|
|
|
90
|
+
async resolveChangeIds(config, targetInfo, revString) {
|
|
91
|
+
if (!revString) return [];
|
|
92
|
+
const specs = String(revString).split(',').map(s => s.trim()).filter(Boolean);
|
|
93
|
+
const allHashes = [];
|
|
94
|
+
for (const spec of specs) {
|
|
95
|
+
const hashes = await gitClient.resolveCommits(config, targetInfo, spec);
|
|
96
|
+
allHashes.push(...hashes);
|
|
97
|
+
}
|
|
98
|
+
return [...new Set(allHashes)];
|
|
99
|
+
},
|
|
86
100
|
async getTargetInfo(config) {
|
|
87
101
|
return await gitClient.getTargetInfo(config);
|
|
88
102
|
},
|
|
@@ -99,8 +113,8 @@ function createGitBackend() {
|
|
|
99
113
|
const details = await gitClient.getCommitDetails(config, targetInfo, commitHash);
|
|
100
114
|
|
|
101
115
|
return {
|
|
102
|
-
id: commitHash,
|
|
103
|
-
displayId: commitHash.slice(0, 12),
|
|
116
|
+
id: details.commitHash,
|
|
117
|
+
displayId: details.commitHash.slice(0, 12),
|
|
104
118
|
author: details.author,
|
|
105
119
|
date: details.date,
|
|
106
120
|
message: details.message,
|