opencode-magi 0.10.0 → 0.11.0
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/README.ja.md +254 -0
- package/README.md +31 -26
- package/dist/commands.js +11 -9
- package/dist/config/index.js +2 -0
- package/dist/config/resolve.js +120 -246
- package/dist/config/validate.js +103 -1110
- package/dist/constant.js +135 -0
- package/dist/graphql/index.generated.js +125 -0
- package/dist/graphql/index.js +49 -0
- package/dist/index.js +12 -800
- package/dist/magi.js +357 -0
- package/dist/permissions/common.json +22 -22
- package/dist/permissions/editor.json +12 -12
- package/dist/prompts/index.js +98 -0
- package/dist/prompts/merge/ci-classification/output-contract.md +22 -0
- package/dist/prompts/merge/ci-classification/task.md +10 -0
- package/dist/prompts/merge/ci-classification/validate.json +20 -0
- package/dist/prompts/merge/conflict/output-contract.md +12 -0
- package/dist/prompts/merge/conflict/task.md +9 -0
- package/dist/prompts/merge/conflict/validate.json +4 -0
- package/dist/prompts/merge/edit/output-contract.md +26 -0
- package/dist/prompts/merge/edit/task.md +10 -0
- package/dist/prompts/merge/edit/validate.json +60 -0
- package/dist/prompts/review/ci-classification/output-contract.md +21 -0
- package/dist/prompts/review/ci-classification/task.md +7 -0
- package/dist/prompts/review/ci-classification/validate.json +20 -0
- package/dist/prompts/review/close-reconsideration/output-contract.md +21 -0
- package/dist/prompts/review/close-reconsideration/task.md +6 -0
- package/dist/prompts/review/close-reconsideration/validate.json +44 -0
- package/dist/prompts/review/comment/output-contract.md +11 -0
- package/dist/prompts/review/comment/task.md +3 -0
- package/dist/prompts/review/comment/validate.json +8 -0
- package/dist/prompts/review/finding-validation/output-contract.md +25 -0
- package/dist/prompts/{templates/review/finding-validation.md → review/finding-validation/task.md} +2 -3
- package/dist/prompts/review/finding-validation/validate.json +21 -0
- package/dist/prompts/review/rereview/output-contract.md +30 -0
- package/dist/prompts/{templates/review/rereview.md → review/rereview/task.md} +8 -11
- package/dist/prompts/review/rereview/validate.json +87 -0
- package/dist/prompts/review/review/output-contract.md +25 -0
- package/dist/prompts/{templates/review/review.md → review/review/task.md} +2 -5
- package/dist/prompts/review/review/validate.json +54 -0
- package/dist/prompts/triage/acceptance/output-contract.md +16 -0
- package/dist/prompts/triage/acceptance/validate.json +23 -0
- package/dist/prompts/triage/category/output-contract.md +16 -0
- package/dist/prompts/triage/category/validate.json +23 -0
- package/dist/prompts/triage/comment-classification/output-contract.md +15 -0
- package/dist/prompts/triage/comment-classification/validate.json +28 -0
- package/dist/prompts/triage/create/output-contract.md +28 -0
- package/dist/prompts/triage/create/validate.json +73 -0
- package/dist/prompts/triage/deplicate/output-contract.md +16 -0
- package/dist/prompts/triage/deplicate/validate.json +20 -0
- package/dist/prompts/triage/existing/output-contract.md +16 -0
- package/dist/prompts/triage/existing/validate.json +13 -0
- package/dist/prompts/triage/reconsider/output-contract.md +16 -0
- package/dist/prompts/triage/reconsider/validate.json +23 -0
- package/dist/prompts/triage/signal/output-contract.md +19 -0
- package/dist/prompts/triage/signal/validate.json +18 -0
- package/dist/tools/clear/index.js +21 -0
- package/dist/tools/index.js +12 -0
- package/dist/tools/merge/action.js +47 -0
- package/dist/tools/merge/context.js +118 -0
- package/dist/tools/merge/editor.js +264 -0
- package/dist/tools/merge/index.js +151 -0
- package/dist/tools/merge/index.type.js +1 -0
- package/dist/tools/merge/merge.js +42 -0
- package/dist/tools/merge/report.js +73 -0
- package/dist/tools/review/action.js +429 -0
- package/dist/tools/review/check.js +295 -0
- package/dist/tools/review/context.js +258 -0
- package/dist/tools/review/index.js +104 -0
- package/dist/tools/review/index.type.js +1 -0
- package/dist/tools/review/report.js +143 -0
- package/dist/tools/review/review.js +145 -0
- package/dist/tools/review/reviewer.js +409 -0
- package/dist/tools/triage/index.js +16 -0
- package/dist/tools/validate/index.js +28 -0
- package/dist/utils/array.js +6 -0
- package/dist/utils/assertion.js +38 -0
- package/dist/utils/exec.js +14 -0
- package/dist/utils/fs.js +24 -0
- package/dist/utils/function.js +37 -0
- package/dist/utils/github.js +63 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.type.js +1 -0
- package/dist/utils/object.js +21 -0
- package/dist/utils/opencode.js +25 -0
- package/dist/utils/string.js +38 -0
- package/dist/utils/worker.js +30 -0
- package/package.json +20 -8
- package/schema.json +6 -4
- package/dist/config/load.js +0 -62
- package/dist/config/output.js +0 -25
- package/dist/config/worktree.js +0 -25
- package/dist/github/commands.js +0 -905
- package/dist/github/retry.js +0 -44
- package/dist/orchestrator/abort.js +0 -9
- package/dist/orchestrator/ci.js +0 -579
- package/dist/orchestrator/findings.js +0 -88
- package/dist/orchestrator/inline-comments.js +0 -73
- package/dist/orchestrator/majority.js +0 -62
- package/dist/orchestrator/merge.js +0 -1260
- package/dist/orchestrator/model.js +0 -216
- package/dist/orchestrator/pool.js +0 -15
- package/dist/orchestrator/report.js +0 -175
- package/dist/orchestrator/review-context.js +0 -342
- package/dist/orchestrator/review.js +0 -1480
- package/dist/orchestrator/run-manager.js +0 -2132
- package/dist/orchestrator/safety.js +0 -44
- package/dist/orchestrator/triage.js +0 -1370
- package/dist/prompts/compose.js +0 -473
- package/dist/prompts/contracts.js +0 -300
- package/dist/prompts/output.js +0 -401
- package/dist/prompts/templates/merge/ci-classification.md +0 -16
- package/dist/prompts/templates/merge/conflict.md +0 -10
- package/dist/prompts/templates/merge/edit.md +0 -15
- package/dist/prompts/templates/review/ci-classification.md +0 -9
- package/dist/prompts/templates/review/close-reconsideration.md +0 -6
- /package/dist/{types.js → config/index.type.js} +0 -0
- /package/dist/prompts/{templates/triage/acceptance.md → triage/acceptance/task.md} +0 -0
- /package/dist/prompts/{templates/triage/category.md → triage/category/task.md} +0 -0
- /package/dist/prompts/{templates/triage/comment-classification.md → triage/comment-classification/task.md} +0 -0
- /package/dist/prompts/{templates/triage/create.md → triage/create/task.md} +0 -0
- /package/dist/prompts/{templates/triage/duplicate.md → triage/deplicate/task.md} +0 -0
- /package/dist/prompts/{templates/triage/existing-pr.md → triage/existing/task.md} +0 -0
- /package/dist/prompts/{templates/triage/reconsider.md → triage/reconsider/task.md} +0 -0
- /package/dist/prompts/{templates/triage/signal.md → triage/signal/task.md} +0 -0
|
@@ -1,88 +0,0 @@
|
|
|
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
|
-
}
|
|
13
|
-
export function reviewFindingTargets(outputs) {
|
|
14
|
-
return Object.entries(outputs).flatMap(([reviewer, output]) => {
|
|
15
|
-
if (output.verdict !== "CHANGES_REQUESTED")
|
|
16
|
-
return [];
|
|
17
|
-
return validationFindings(output).map((finding, findingIndex) => ({
|
|
18
|
-
finding,
|
|
19
|
-
findingIndex,
|
|
20
|
-
reviewer,
|
|
21
|
-
}));
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
export function validateFindingVotes(input) {
|
|
25
|
-
const expected = input.targets.filter((target) => target.reviewer !== input.validator);
|
|
26
|
-
const expectedKeys = new Set(expected.map((target) => `${target.reviewer}:${target.findingIndex}`));
|
|
27
|
-
const seen = new Set();
|
|
28
|
-
for (const vote of input.output.votes) {
|
|
29
|
-
if (vote.reviewer === input.validator) {
|
|
30
|
-
throw new Error(`${input.validator} must not vote on its own findings`);
|
|
31
|
-
}
|
|
32
|
-
const key = `${vote.reviewer}:${vote.findingIndex}`;
|
|
33
|
-
if (!expectedKeys.has(key))
|
|
34
|
-
throw new Error(`unexpected finding vote: ${key}`);
|
|
35
|
-
if (seen.has(key))
|
|
36
|
-
throw new Error(`duplicate finding vote: ${key}`);
|
|
37
|
-
seen.add(key);
|
|
38
|
-
}
|
|
39
|
-
for (const target of expected) {
|
|
40
|
-
const key = `${target.reviewer}:${target.findingIndex}`;
|
|
41
|
-
if (!seen.has(key))
|
|
42
|
-
throw new Error(`missing finding vote: ${key}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
export function applyFindingValidation(input) {
|
|
46
|
-
const threshold = majorityThreshold(input.reviewerKeys.length);
|
|
47
|
-
const kept = [];
|
|
48
|
-
const discarded = [];
|
|
49
|
-
const next = {};
|
|
50
|
-
for (const [reviewer, output] of Object.entries(input.outputs)) {
|
|
51
|
-
if (output.verdict !== "CHANGES_REQUESTED") {
|
|
52
|
-
next[reviewer] = output;
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const keptIndexes = new Set();
|
|
56
|
-
const findings = validationFindings(output);
|
|
57
|
-
findings.forEach((finding, findingIndex) => {
|
|
58
|
-
let agrees = 1;
|
|
59
|
-
for (const validator of input.reviewerKeys) {
|
|
60
|
-
if (validator === reviewer)
|
|
61
|
-
continue;
|
|
62
|
-
const vote = input.validations[validator]?.votes.find((item) => item.reviewer === reviewer && item.findingIndex === findingIndex);
|
|
63
|
-
if (vote?.vote === "AGREE")
|
|
64
|
-
agrees += 1;
|
|
65
|
-
}
|
|
66
|
-
const target = { finding, findingIndex, reviewer };
|
|
67
|
-
if (agrees >= threshold) {
|
|
68
|
-
kept.push(target);
|
|
69
|
-
keptIndexes.add(findingIndex);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
discarded.push(target);
|
|
73
|
-
});
|
|
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" };
|
|
86
|
-
}
|
|
87
|
-
return { outputs: next, summary: { discarded, kept } };
|
|
88
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
function parseDiffPath(value) {
|
|
2
|
-
if (value === "/dev/null")
|
|
3
|
-
return undefined;
|
|
4
|
-
let path = value;
|
|
5
|
-
if (path.startsWith('"') && path.endsWith('"')) {
|
|
6
|
-
try {
|
|
7
|
-
path = JSON.parse(path);
|
|
8
|
-
}
|
|
9
|
-
catch {
|
|
10
|
-
path = path.slice(1, -1);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return path.startsWith("b/") ? path.slice(2) : path;
|
|
14
|
-
}
|
|
15
|
-
function addTargetLine(targets, path, line) {
|
|
16
|
-
const lines = targets.get(path) ?? new Set();
|
|
17
|
-
lines.add(line);
|
|
18
|
-
targets.set(path, lines);
|
|
19
|
-
}
|
|
20
|
-
export function parseRightSideDiffTargets(diff) {
|
|
21
|
-
const targets = new Map();
|
|
22
|
-
let currentPath;
|
|
23
|
-
let rightLine;
|
|
24
|
-
for (const line of diff.split("\n")) {
|
|
25
|
-
if (line.startsWith("+++ ")) {
|
|
26
|
-
currentPath = parseDiffPath(line.slice(4));
|
|
27
|
-
rightLine = undefined;
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
if (line.startsWith("@@ ")) {
|
|
31
|
-
const match = line.match(/\+(\d+)(?:,\d+)?/);
|
|
32
|
-
rightLine = match ? Number(match[1]) : undefined;
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
if (!currentPath || rightLine == null)
|
|
36
|
-
continue;
|
|
37
|
-
if (line.startsWith("+") || line.startsWith(" ")) {
|
|
38
|
-
addTargetLine(targets, currentPath, rightLine);
|
|
39
|
-
rightLine += 1;
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (line.startsWith("-"))
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
return targets;
|
|
46
|
-
}
|
|
47
|
-
function assertPositiveInteger(value, name) {
|
|
48
|
-
if (!Number.isInteger(value) || value < 1) {
|
|
49
|
-
throw new Error(`${name} must be a positive integer`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
export function validateInlineCommentTargets(findings, targets, label = "findings") {
|
|
53
|
-
for (const [index, finding] of findings.entries()) {
|
|
54
|
-
const name = `${label}[${index}]`;
|
|
55
|
-
assertPositiveInteger(finding.line, `${name}.line`);
|
|
56
|
-
if (finding.startLine != null) {
|
|
57
|
-
assertPositiveInteger(finding.startLine, `${name}.startLine`);
|
|
58
|
-
if (finding.startLine > finding.line) {
|
|
59
|
-
throw new Error(`${name}.startLine must be before or equal to line`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
const lines = targets.get(finding.path);
|
|
63
|
-
if (!lines) {
|
|
64
|
-
throw new Error(`${name} targets ${finding.path}:${finding.line}, but path is not in the PR diff`);
|
|
65
|
-
}
|
|
66
|
-
const startLine = finding.startLine ?? finding.line;
|
|
67
|
-
for (let line = startLine; line <= finding.line; line += 1) {
|
|
68
|
-
if (!lines.has(line)) {
|
|
69
|
-
throw new Error(`${name} targets ${finding.path}:${line}, but line is not in a right-side PR diff hunk`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
const VERDICTS = ["MERGE", "CHANGES_REQUESTED", "CLOSE"];
|
|
2
|
-
export function majorityThreshold(total) {
|
|
3
|
-
return Math.floor(total / 2) + 1;
|
|
4
|
-
}
|
|
5
|
-
export function aggregateStringMajority(results, votes) {
|
|
6
|
-
if (results.length < 3 || results.length % 2 === 0) {
|
|
7
|
-
throw new Error("majority requires an odd number of at least 3 results");
|
|
8
|
-
}
|
|
9
|
-
const counts = Object.fromEntries(votes.map((vote) => [vote, 0]));
|
|
10
|
-
const voters = Object.fromEntries(votes.map((vote) => [vote, []]));
|
|
11
|
-
for (const result of results) {
|
|
12
|
-
counts[result.vote] += 1;
|
|
13
|
-
voters[result.vote].push(result.voter);
|
|
14
|
-
}
|
|
15
|
-
const threshold = majorityThreshold(results.length);
|
|
16
|
-
const vote = votes.find((item) => counts[item] >= threshold);
|
|
17
|
-
return { counts, threshold, vote, voters };
|
|
18
|
-
}
|
|
19
|
-
export function aggregateMajority(results) {
|
|
20
|
-
if (results.length < 3 || results.length % 2 === 0) {
|
|
21
|
-
throw new Error("majority requires an odd number of at least 3 reviewer results");
|
|
22
|
-
}
|
|
23
|
-
const counts = {
|
|
24
|
-
CHANGES_REQUESTED: 0,
|
|
25
|
-
CLOSE: 0,
|
|
26
|
-
MERGE: 0,
|
|
27
|
-
};
|
|
28
|
-
const reviewers = {
|
|
29
|
-
CHANGES_REQUESTED: [],
|
|
30
|
-
CLOSE: [],
|
|
31
|
-
MERGE: [],
|
|
32
|
-
};
|
|
33
|
-
for (const result of results) {
|
|
34
|
-
counts[result.verdict] += 1;
|
|
35
|
-
reviewers[result.verdict].push(result.reviewer);
|
|
36
|
-
}
|
|
37
|
-
const threshold = majorityThreshold(results.length);
|
|
38
|
-
const verdict = VERDICTS.find((item) => counts[item] >= threshold);
|
|
39
|
-
if (!verdict)
|
|
40
|
-
throw new Error("no majority verdict");
|
|
41
|
-
return { counts, reviewers, threshold, verdict };
|
|
42
|
-
}
|
|
43
|
-
export function reviewOutputsToVerdicts(outputs) {
|
|
44
|
-
return Object.entries(outputs).map(([reviewer, output]) => ({
|
|
45
|
-
reviewer,
|
|
46
|
-
verdict: output.verdict,
|
|
47
|
-
}));
|
|
48
|
-
}
|
|
49
|
-
export function mergeVerdictForPolicy(results, policy) {
|
|
50
|
-
const majority = aggregateMajority(results);
|
|
51
|
-
if (majority.verdict === "CLOSE")
|
|
52
|
-
return "CLOSE";
|
|
53
|
-
if (policy === "majority")
|
|
54
|
-
return majority.verdict;
|
|
55
|
-
return majority.counts.MERGE === results.length
|
|
56
|
-
? "MERGE"
|
|
57
|
-
: "CHANGES_REQUESTED";
|
|
58
|
-
}
|
|
59
|
-
export function closeMinorityReviewers(results) {
|
|
60
|
-
const majority = aggregateMajority(results);
|
|
61
|
-
return majority.verdict === "CLOSE" ? [] : majority.reviewers.CLOSE;
|
|
62
|
-
}
|