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.findings.map((finding, findingIndex) => ({
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 findings = output.findings.filter((finding, findingIndex) => {
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
- return true;
69
+ keptIndexes.add(findingIndex);
70
+ return;
57
71
  }
58
72
  discarded.push(target);
59
- return false;
60
73
  });
61
- next[reviewer] = findings.length
62
- ? { ...output, findings }
63
- : { findings: [], verdict: "MERGE" };
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 reviewOutputs = Object.fromEntries(input.entries.flatMap((entry) => isReviewOutput(entry.value) ? [[entry.key, entry.value]] : []));
266
- const targets = reviewFindingTargets(reviewOutputs);
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: reviewOutputs,
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(reviewOutputs)
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, input.inlineCommentTargets);
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 inlineCommentTargets = parseRightSideDiffTargets(await exec(`git diff --no-ext-diff --unified=3 ${shellQuote(meta.baseRefOid)} ${shellQuote(meta.headRefOid)}`, { cwd: worktreePath }));
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, inlineCommentTargets),
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-20260522105233",
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>",