opencode-magi 0.0.0-dev-20260522144259 → 0.0.0-dev-20260522144424
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/github/commands.js +62 -0
- package/dist/orchestrator/merge.js +18 -4
- package/dist/orchestrator/review.js +39 -2
- package/package.json +1 -1
package/dist/github/commands.js
CHANGED
|
@@ -20,6 +20,68 @@ function errorText(error) {
|
|
|
20
20
|
.filter((item) => typeof item === "string")
|
|
21
21
|
.join("\n");
|
|
22
22
|
}
|
|
23
|
+
async function localCommitExists(exec, worktreePath, sha) {
|
|
24
|
+
try {
|
|
25
|
+
await exec(`git cat-file -e ${shellQuote(`${sha}^{commit}`)}`, {
|
|
26
|
+
cwd: worktreePath,
|
|
27
|
+
});
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function pullRequestCommitSource(input) {
|
|
35
|
+
if (input.source === "base") {
|
|
36
|
+
return {
|
|
37
|
+
owner: input.repository.github.owner,
|
|
38
|
+
refName: input.meta.baseRefName,
|
|
39
|
+
repo: input.repository.github.repo,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
owner: input.meta.headRepositoryOwner?.login ?? input.repository.github.owner,
|
|
44
|
+
refName: input.meta.headRefName,
|
|
45
|
+
repo: input.meta.headRepository?.name ?? input.repository.github.repo,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function fetchPullRequestCommitSource(input) {
|
|
49
|
+
const commitSource = pullRequestCommitSource(input);
|
|
50
|
+
try {
|
|
51
|
+
await input.exec(`git fetch --no-tags ${shellQuote(repositoryGitUrl(input.repository, commitSource.owner, commitSource.repo))} ${shellQuote(`refs/heads/${commitSource.refName}`)}`, { cwd: input.worktreePath });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Could not fetch ${input.source} ref ${commitSource.refName} for #${input.meta.number}: ${errorText(error)}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export async function ensurePullRequestCommits(input) {
|
|
58
|
+
const missing = [];
|
|
59
|
+
for (const commit of input.commits) {
|
|
60
|
+
if (!(await localCommitExists(input.exec, input.worktreePath, commit.sha))) {
|
|
61
|
+
missing.push(commit);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const source of new Set(missing.map((commit) => commit.source))) {
|
|
65
|
+
await fetchPullRequestCommitSource({
|
|
66
|
+
exec: input.exec,
|
|
67
|
+
meta: input.meta,
|
|
68
|
+
repository: input.repository,
|
|
69
|
+
source,
|
|
70
|
+
worktreePath: input.worktreePath,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
for (const commit of missing) {
|
|
74
|
+
if (await localCommitExists(input.exec, input.worktreePath, commit.sha)) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const source = pullRequestCommitSource({
|
|
78
|
+
meta: input.meta,
|
|
79
|
+
repository: input.repository,
|
|
80
|
+
source: commit.source,
|
|
81
|
+
});
|
|
82
|
+
throw new Error(`${commit.label} commit ${commit.sha} is unavailable after fetching ${commit.source} ref ${source.refName}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
23
85
|
function isCheckoutConfigLockError(error) {
|
|
24
86
|
const text = errorText(error);
|
|
25
87
|
return (/could not lock config file/i.test(text) ||
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { prRunOutputDir } from "../config/output";
|
|
4
|
-
import { closePullRequest, configureGitIdentity, fetchMergeQueueRequirement, fetchPullRequest, fetchUnresolvedThreads, mergePullRequest, postApproval, postChangesRequested, postCloseComment, postReply, pushHead, removeWorktree, resolveThread,
|
|
4
|
+
import { closePullRequest, configureGitIdentity, fetchMergeQueueRequirement, fetchPullRequest, fetchUnresolvedThreads, mergePullRequest, postApproval, postChangesRequested, postCloseComment, postReply, pushHead, removeWorktree, resolveThread, waitForMergeQueue, } from "../github/commands";
|
|
5
5
|
import { composeEditPrompt, composeRereviewCloseReconsiderationPrompt, composeRereviewPrompt, } from "../prompts/compose";
|
|
6
6
|
import { parseEditOutput, parseRereviewCloseReconsiderationOutput, parseRereviewOutput, } from "../prompts/output";
|
|
7
7
|
import { throwIfAborted, withAbortSignal } from "./abort";
|
|
8
8
|
import { waitForChecksWithClassification } from "./ci";
|
|
9
|
-
import {
|
|
9
|
+
import { validateInlineCommentTargets, } from "./inline-comments";
|
|
10
10
|
import { closeMinorityReviewers, mergeVerdictForPolicy } from "./majority";
|
|
11
11
|
import { runModelWithRepair } from "./model";
|
|
12
12
|
import { mapPool } from "./pool";
|
|
13
13
|
import { formatMergeReport } from "./report";
|
|
14
|
-
import { runReview } from "./review";
|
|
14
|
+
import { inlineCommentTargetsForDiff, runReview, } from "./review";
|
|
15
15
|
import { checkSafetyGate, hasSafetyGate } from "./safety";
|
|
16
16
|
function outputDir(input) {
|
|
17
17
|
return prRunOutputDir({
|
|
@@ -196,7 +196,21 @@ async function runRereview(input, worktreePath, previousHeadSha, cycle, sessionI
|
|
|
196
196
|
throwIfAborted(input.signal);
|
|
197
197
|
const meta = await fetchPullRequest(input.exec, input.repository, input.pr);
|
|
198
198
|
const headSha = options.dryRunHeadSha ?? meta.headRefOid;
|
|
199
|
-
const inlineCommentTargets =
|
|
199
|
+
const inlineCommentTargets = await inlineCommentTargetsForDiff({
|
|
200
|
+
ensure: options.dryRunHeadSha
|
|
201
|
+
? undefined
|
|
202
|
+
: {
|
|
203
|
+
fromSource: "base",
|
|
204
|
+
meta,
|
|
205
|
+
repository: input.repository,
|
|
206
|
+
toSource: "head",
|
|
207
|
+
},
|
|
208
|
+
exec: input.exec,
|
|
209
|
+
fromSha: meta.baseRefOid,
|
|
210
|
+
range: "direct",
|
|
211
|
+
toSha: headSha,
|
|
212
|
+
worktreePath,
|
|
213
|
+
});
|
|
200
214
|
const artifactDir = outputDir(input);
|
|
201
215
|
let entries = await mapPool(input.repository.agents.reviewers, input.repository.concurrency.reviewers, async (reviewer) => {
|
|
202
216
|
throwIfAborted(input.signal);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { createWorktree, fetchPullRequest, fetchPullRequestCommits, fetchPullRequestReviews, fetchUnresolvedThreads, closePullRequest, mergePullRequest, postApproval, postChangesRequested, postCloseComment, postReply, removeWorktree, resolveThread, shellQuote, } from "../github/commands";
|
|
3
|
+
import { createWorktree, fetchPullRequest, fetchPullRequestCommits, fetchPullRequestReviews, fetchUnresolvedThreads, closePullRequest, mergePullRequest, ensurePullRequestCommits, postApproval, postChangesRequested, postCloseComment, postReply, removeWorktree, resolveThread, shellQuote, } from "../github/commands";
|
|
4
4
|
import { composeFindingValidationPrompt, composeCloseReconsiderationPrompt, composeRereviewPrompt, composeReviewPrompt, } from "../prompts/compose";
|
|
5
5
|
import { prRunOutputDir } from "../config/output";
|
|
6
6
|
import { prRunWorktreeDir } from "../config/worktree";
|
|
@@ -136,7 +136,32 @@ function parseRereviewOutputWithInlineTargets(text, targets) {
|
|
|
136
136
|
return output;
|
|
137
137
|
}
|
|
138
138
|
export async function inlineCommentTargetsForDiff(input) {
|
|
139
|
-
|
|
139
|
+
if (input.ensure) {
|
|
140
|
+
await ensurePullRequestCommits({
|
|
141
|
+
commits: [
|
|
142
|
+
{
|
|
143
|
+
label: "base",
|
|
144
|
+
sha: input.fromSha,
|
|
145
|
+
source: input.ensure.fromSource,
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
label: "head",
|
|
149
|
+
sha: input.toSha,
|
|
150
|
+
source: input.ensure.toSource,
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
exec: input.exec,
|
|
154
|
+
meta: input.ensure.meta,
|
|
155
|
+
repository: input.ensure.repository,
|
|
156
|
+
worktreePath: input.worktreePath,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
const diffRange = input.range === "direct"
|
|
160
|
+
? `${shellQuote(input.fromSha)} ${shellQuote(input.toSha)}`
|
|
161
|
+
: `${shellQuote(input.fromSha)}...${shellQuote(input.toSha)}`;
|
|
162
|
+
return parseRightSideDiffTargets(await input.exec(`git diff --no-ext-diff --unified=3 ${diffRange}`, {
|
|
163
|
+
cwd: input.worktreePath,
|
|
164
|
+
}));
|
|
140
165
|
}
|
|
141
166
|
function parsePostedFindingLocation(location) {
|
|
142
167
|
const range = /^(.*):(\d+)-(\d+)$/.exec(location);
|
|
@@ -645,6 +670,12 @@ export async function runReview(input) {
|
|
|
645
670
|
return [{ assignment, reviewer }];
|
|
646
671
|
});
|
|
647
672
|
const initialInlineCommentTargets = await inlineCommentTargetsForDiff({
|
|
673
|
+
ensure: {
|
|
674
|
+
fromSource: "base",
|
|
675
|
+
meta,
|
|
676
|
+
repository: input.repository,
|
|
677
|
+
toSource: "head",
|
|
678
|
+
},
|
|
648
679
|
exec,
|
|
649
680
|
fromSha: meta.baseRefOid,
|
|
650
681
|
toSha: meta.headRefOid,
|
|
@@ -670,6 +701,12 @@ export async function runReview(input) {
|
|
|
670
701
|
if (!previous.commit?.oid)
|
|
671
702
|
throw new Error(`Missing previous review commit for ${reviewer.account}`);
|
|
672
703
|
const inlineCommentTargets = await inlineCommentTargetsForDiff({
|
|
704
|
+
ensure: {
|
|
705
|
+
fromSource: "head",
|
|
706
|
+
meta,
|
|
707
|
+
repository: input.repository,
|
|
708
|
+
toSource: "head",
|
|
709
|
+
},
|
|
673
710
|
exec,
|
|
674
711
|
fromSha: previous.commit.oid,
|
|
675
712
|
toSha: meta.headRefOid,
|
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-20260522144424",
|
|
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>",
|