opencode-magi 0.0.0-dev-20260522105233 → 0.0.0-dev-20260522105602
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.
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { majorityThreshold } from "./majority";
|
|
2
|
+
function validationFindings(output) {
|
|
3
|
+
if ("findings" in output)
|
|
4
|
+
return output.findings;
|
|
5
|
+
return output.newFindings.map((finding) => ({
|
|
6
|
+
fix: "Please address this before merging.",
|
|
7
|
+
issue: finding.body,
|
|
8
|
+
line: finding.line,
|
|
9
|
+
path: finding.path,
|
|
10
|
+
startLine: finding.startLine,
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
2
13
|
export function reviewFindingTargets(outputs) {
|
|
3
14
|
return Object.entries(outputs).flatMap(([reviewer, output]) => {
|
|
4
15
|
if (output.verdict !== "CHANGES_REQUESTED")
|
|
5
16
|
return [];
|
|
6
|
-
return output.
|
|
17
|
+
return validationFindings(output).map((finding, findingIndex) => ({
|
|
7
18
|
finding,
|
|
8
19
|
findingIndex,
|
|
9
20
|
reviewer,
|
|
@@ -41,7 +52,9 @@ export function applyFindingValidation(input) {
|
|
|
41
52
|
next[reviewer] = output;
|
|
42
53
|
continue;
|
|
43
54
|
}
|
|
44
|
-
const
|
|
55
|
+
const keptIndexes = new Set();
|
|
56
|
+
const findings = validationFindings(output);
|
|
57
|
+
findings.forEach((finding, findingIndex) => {
|
|
45
58
|
let agrees = 1;
|
|
46
59
|
for (const validator of input.reviewerKeys) {
|
|
47
60
|
if (validator === reviewer)
|
|
@@ -53,14 +66,23 @@ export function applyFindingValidation(input) {
|
|
|
53
66
|
const target = { finding, findingIndex, reviewer };
|
|
54
67
|
if (agrees >= threshold) {
|
|
55
68
|
kept.push(target);
|
|
56
|
-
|
|
69
|
+
keptIndexes.add(findingIndex);
|
|
70
|
+
return;
|
|
57
71
|
}
|
|
58
72
|
discarded.push(target);
|
|
59
|
-
return false;
|
|
60
73
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
if ("findings" in output) {
|
|
75
|
+
const keptFindings = output.findings.filter((_finding, index) => keptIndexes.has(index));
|
|
76
|
+
next[reviewer] = keptFindings.length
|
|
77
|
+
? { ...output, findings: keptFindings }
|
|
78
|
+
: { findings: [], verdict: "MERGE" };
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const newFindings = output.newFindings.filter((_finding, index) => keptIndexes.has(index));
|
|
82
|
+
next[reviewer] =
|
|
83
|
+
newFindings.length || output.followUps.length
|
|
84
|
+
? { ...output, newFindings }
|
|
85
|
+
: { ...output, newFindings, verdict: "MERGE" };
|
|
64
86
|
}
|
|
65
87
|
return { outputs: next, summary: { discarded, kept } };
|
|
66
88
|
}
|
|
@@ -135,6 +135,9 @@ function parseRereviewOutputWithInlineTargets(text, targets) {
|
|
|
135
135
|
validateInlineCommentTargets(output.newFindings, targets, "newFindings");
|
|
136
136
|
return output;
|
|
137
137
|
}
|
|
138
|
+
export async function inlineCommentTargetsForDiff(input) {
|
|
139
|
+
return parseRightSideDiffTargets(await input.exec(`git diff --no-ext-diff --unified=3 ${shellQuote(input.fromSha)}...${shellQuote(input.toSha)}`, { cwd: input.worktreePath }));
|
|
140
|
+
}
|
|
138
141
|
function parsePostedFindingLocation(location) {
|
|
139
142
|
const range = /^(.*):(\d+)-(\d+)$/.exec(location);
|
|
140
143
|
if (range) {
|
|
@@ -262,8 +265,8 @@ function isReviewOutput(output) {
|
|
|
262
265
|
return "findings" in output;
|
|
263
266
|
}
|
|
264
267
|
async function runFindingValidation(input) {
|
|
265
|
-
const
|
|
266
|
-
const targets = reviewFindingTargets(
|
|
268
|
+
const outputs = Object.fromEntries(input.entries.map((entry) => [entry.key, entry.value]));
|
|
269
|
+
const targets = reviewFindingTargets(outputs);
|
|
267
270
|
if (!targets.length) {
|
|
268
271
|
return {
|
|
269
272
|
outputs: Object.fromEntries(input.entries.map((entry) => [entry.key, entry.value])),
|
|
@@ -348,7 +351,7 @@ async function runFindingValidation(input) {
|
|
|
348
351
|
return [reviewer.key, result.value];
|
|
349
352
|
}, { signal: input.reviewInput.signal }));
|
|
350
353
|
const filtered = applyFindingValidation({
|
|
351
|
-
outputs
|
|
354
|
+
outputs,
|
|
352
355
|
reviewerKeys: input.reviewInput.repository.agents.reviewers.map((reviewer) => reviewer.key),
|
|
353
356
|
validations,
|
|
354
357
|
});
|
|
@@ -356,7 +359,7 @@ async function runFindingValidation(input) {
|
|
|
356
359
|
await input.reviewInput.onProgress?.({
|
|
357
360
|
discarded: filtered.summary.discarded.length,
|
|
358
361
|
kept: filtered.summary.kept.length,
|
|
359
|
-
reviewersChangedToMerge: Object.entries(
|
|
362
|
+
reviewersChangedToMerge: Object.entries(outputs)
|
|
360
363
|
.filter(([reviewer, output]) => {
|
|
361
364
|
return (output.verdict === "CHANGES_REQUESTED" &&
|
|
362
365
|
filtered.outputs[reviewer]?.verdict === "MERGE");
|
|
@@ -439,7 +442,7 @@ async function runCloseReconsideration(input) {
|
|
|
439
442
|
parentSessionId: input.reviewInput.parentSessionId,
|
|
440
443
|
parse: (text) => {
|
|
441
444
|
const output = parseCloseReconsiderationOutput(text);
|
|
442
|
-
validateInlineCommentTargets(output.findings,
|
|
445
|
+
validateInlineCommentTargets(output.findings, entry.inlineCommentTargets);
|
|
443
446
|
return output;
|
|
444
447
|
},
|
|
445
448
|
permission: reviewer.permission,
|
|
@@ -468,6 +471,7 @@ async function runCloseReconsideration(input) {
|
|
|
468
471
|
});
|
|
469
472
|
input.sessionIds[reviewer.key] = result.sessionId;
|
|
470
473
|
return {
|
|
474
|
+
inlineCommentTargets: entry.inlineCommentTargets,
|
|
471
475
|
key: entry.key,
|
|
472
476
|
raw: result.raw,
|
|
473
477
|
sessionId: result.sessionId,
|
|
@@ -634,7 +638,12 @@ export async function runReview(input) {
|
|
|
634
638
|
return [];
|
|
635
639
|
return [{ assignment, reviewer }];
|
|
636
640
|
});
|
|
637
|
-
const
|
|
641
|
+
const initialInlineCommentTargets = await inlineCommentTargetsForDiff({
|
|
642
|
+
exec,
|
|
643
|
+
fromSha: meta.baseRefOid,
|
|
644
|
+
toSha: meta.headRefOid,
|
|
645
|
+
worktreePath,
|
|
646
|
+
});
|
|
638
647
|
for (const reviewer of input.repository.agents.reviewers) {
|
|
639
648
|
const assignment = mode.assignments.get(reviewer.account);
|
|
640
649
|
if (assignment?.type !== "skip")
|
|
@@ -654,6 +663,12 @@ export async function runReview(input) {
|
|
|
654
663
|
const previous = assignment.review;
|
|
655
664
|
if (!previous.commit?.oid)
|
|
656
665
|
throw new Error(`Missing previous review commit for ${reviewer.account}`);
|
|
666
|
+
const inlineCommentTargets = await inlineCommentTargetsForDiff({
|
|
667
|
+
exec,
|
|
668
|
+
fromSha: previous.commit.oid,
|
|
669
|
+
toSha: meta.headRefOid,
|
|
670
|
+
worktreePath,
|
|
671
|
+
});
|
|
657
672
|
const unresolved = unresolvedThreadsByAccount.get(reviewer.account) ??
|
|
658
673
|
(await fetchUnresolvedThreads(exec, input.repository, input.pr, reviewer.account));
|
|
659
674
|
const prompt = await composeRereviewPrompt({
|
|
@@ -720,6 +735,7 @@ export async function runReview(input) {
|
|
|
720
735
|
verdict: result.value.verdict,
|
|
721
736
|
});
|
|
722
737
|
return {
|
|
738
|
+
inlineCommentTargets,
|
|
723
739
|
key: reviewer.key,
|
|
724
740
|
raw: result.raw,
|
|
725
741
|
sessionId: result.sessionId,
|
|
@@ -768,7 +784,7 @@ export async function runReview(input) {
|
|
|
768
784
|
},
|
|
769
785
|
options: reviewer.options,
|
|
770
786
|
parentSessionId: input.parentSessionId,
|
|
771
|
-
parse: (text) => parseReviewOutputWithInlineTargets(text,
|
|
787
|
+
parse: (text) => parseReviewOutputWithInlineTargets(text, initialInlineCommentTargets),
|
|
772
788
|
permission: reviewer.permission,
|
|
773
789
|
prompt,
|
|
774
790
|
repairAttempts: input.config.output?.repairAttempts ?? 3,
|
|
@@ -787,6 +803,7 @@ export async function runReview(input) {
|
|
|
787
803
|
verdict: result.value.verdict,
|
|
788
804
|
});
|
|
789
805
|
return {
|
|
806
|
+
inlineCommentTargets: initialInlineCommentTargets,
|
|
790
807
|
key: reviewer.key,
|
|
791
808
|
raw: result.raw,
|
|
792
809
|
sessionId: result.sessionId,
|
|
@@ -820,6 +837,7 @@ export async function runReview(input) {
|
|
|
820
837
|
return [
|
|
821
838
|
{
|
|
822
839
|
key: reviewer.key,
|
|
840
|
+
inlineCommentTargets: initialInlineCommentTargets,
|
|
823
841
|
raw: assignment.review.body ?? "",
|
|
824
842
|
sessionId: "",
|
|
825
843
|
value: reviewOutputFromState(assignment.review),
|
|
@@ -828,7 +846,6 @@ export async function runReview(input) {
|
|
|
828
846
|
});
|
|
829
847
|
entries = await runCloseReconsideration({
|
|
830
848
|
entries: [...entries, ...skippedCloseEntries],
|
|
831
|
-
inlineCommentTargets,
|
|
832
849
|
meta,
|
|
833
850
|
outputDir,
|
|
834
851
|
reviewContext,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-magi",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-20260522105602",
|
|
4
4
|
"description": "Multi-agent PR review and merge orchestration plugin for OpenCode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Hirotomo Yamada <hirotomo.yamada@avap.co.jp>",
|