opencode-magi 0.0.0-dev-20260525025216 → 0.0.0-dev-20260525030452
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.md +5 -5
- package/dist/config/resolve.js +2 -2
- package/dist/config/validate.js +26 -26
- package/dist/index.js +2 -2
- package/dist/orchestrator/run-manager.js +4 -4
- package/dist/orchestrator/triage.js +5 -5
- package/package.json +1 -1
- package/schema.json +2 -2
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ Add the following content to the configuration file.
|
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
"review": {
|
|
81
|
-
"
|
|
81
|
+
"reviewers": [
|
|
82
82
|
{ "ref": "account-1" },
|
|
83
83
|
{ "ref": "account-2" },
|
|
84
84
|
{ "ref": "account-3" }
|
|
@@ -87,7 +87,7 @@ Add the following content to the configuration file.
|
|
|
87
87
|
}
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
After refs are expanded, `review.
|
|
90
|
+
After `refs` are expanded, `review.reviewers[].account` is the GitHub account used to post reviews and approvals. Must be authenticated with `gh auth token --user <account>` and must be unique.
|
|
91
91
|
|
|
92
92
|
#### Set project config
|
|
93
93
|
|
|
@@ -133,7 +133,7 @@ Add the following content to the configuration file.
|
|
|
133
133
|
}
|
|
134
134
|
},
|
|
135
135
|
"review": {
|
|
136
|
-
"
|
|
136
|
+
"reviewers": [
|
|
137
137
|
{ "ref": "account-1" },
|
|
138
138
|
{ "ref": "account-2" },
|
|
139
139
|
{ "ref": "account-3" }
|
|
@@ -143,7 +143,7 @@ Add the following content to the configuration file.
|
|
|
143
143
|
"editor": { "ref": "account-4" }
|
|
144
144
|
},
|
|
145
145
|
"triage": {
|
|
146
|
-
"
|
|
146
|
+
"voters": [
|
|
147
147
|
{ "ref": "account-1" },
|
|
148
148
|
{ "ref": "account-2" },
|
|
149
149
|
{ "ref": "account-3" }
|
|
@@ -168,7 +168,7 @@ Entries with `ref` are expanded from `agents.refs`. Fields set alongside `ref` o
|
|
|
168
168
|
}
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
After refs are expanded, `review.
|
|
171
|
+
After `refs` are expanded, `review.reviewers[].account` is the GitHub account used to post reviews and approvals. Must be authenticated with `gh auth token --user <account>` and must be unique. `merge.editor.account` is used by `/magi:merge` to push fixes, close PRs, and merge PRs.
|
|
172
172
|
|
|
173
173
|
#### Validate config
|
|
174
174
|
|
package/dist/config/resolve.js
CHANGED
|
@@ -96,14 +96,14 @@ export function resolveAgents(config) {
|
|
|
96
96
|
permission: resolveEditorPermission(agents, editor),
|
|
97
97
|
}
|
|
98
98
|
: undefined,
|
|
99
|
-
reviewers: (config.review?.
|
|
99
|
+
reviewers: (config.review?.reviewers ?? []).map((reviewer, index) => ({
|
|
100
100
|
...reviewer,
|
|
101
101
|
key: reviewerKey(reviewer, index),
|
|
102
102
|
index,
|
|
103
103
|
model: normalizedModel(reviewer.model),
|
|
104
104
|
permission: resolveReviewerPermission(agents, reviewer),
|
|
105
105
|
})),
|
|
106
|
-
triage: (config.triage?.
|
|
106
|
+
triage: (config.triage?.voters ?? []).map((agent, index) => ({
|
|
107
107
|
...agent,
|
|
108
108
|
key: triageAgentKey(agent, index),
|
|
109
109
|
index,
|
package/dist/config/validate.js
CHANGED
|
@@ -54,13 +54,13 @@ const TRIAGE_CREATOR_KEYS = new Set([
|
|
|
54
54
|
const AUTHOR_KEYS = new Set(["email", "name"]);
|
|
55
55
|
const GITHUB_KEYS = new Set(["apiRetryAttempts", "host", "owner", "repo"]);
|
|
56
56
|
const REVIEW_KEYS = new Set([
|
|
57
|
-
"agents",
|
|
58
57
|
"automation",
|
|
59
58
|
"checks",
|
|
60
59
|
"concurrency",
|
|
61
60
|
"merge",
|
|
62
61
|
"output",
|
|
63
62
|
"prompts",
|
|
63
|
+
"reviewers",
|
|
64
64
|
"safety",
|
|
65
65
|
"worktree",
|
|
66
66
|
]);
|
|
@@ -72,7 +72,6 @@ const MERGE_KEYS = new Set([
|
|
|
72
72
|
"prompts",
|
|
73
73
|
]);
|
|
74
74
|
const TRIAGE_KEYS = new Set([
|
|
75
|
-
"agents",
|
|
76
75
|
"automation",
|
|
77
76
|
"categories",
|
|
78
77
|
"concurrency",
|
|
@@ -81,6 +80,7 @@ const TRIAGE_KEYS = new Set([
|
|
|
81
80
|
"prompts",
|
|
82
81
|
"reporter",
|
|
83
82
|
"safety",
|
|
83
|
+
"voters",
|
|
84
84
|
"worktree",
|
|
85
85
|
]);
|
|
86
86
|
const REVIEW_MERGE_KEYS = new Set([
|
|
@@ -187,14 +187,14 @@ function expandAgentRefs(config, errors) {
|
|
|
187
187
|
const refsValue = isPlainObject(agents) ? agents.refs : undefined;
|
|
188
188
|
const refsInvalid = refsValue != null && !isPlainObject(refsValue);
|
|
189
189
|
const refs = isPlainObject(refsValue) ? refsValue : undefined;
|
|
190
|
-
if (Array.isArray(magiConfig.review?.
|
|
191
|
-
magiConfig.review.
|
|
190
|
+
if (Array.isArray(magiConfig.review?.reviewers)) {
|
|
191
|
+
magiConfig.review.reviewers = magiConfig.review.reviewers.map((agent, index) => expandAgentRefUse(agent, `review.reviewers[${index}]`, refs, refsInvalid, errors));
|
|
192
192
|
}
|
|
193
193
|
if (isPlainObject(magiConfig.merge?.editor)) {
|
|
194
194
|
magiConfig.merge.editor = expandAgentRefUse(magiConfig.merge.editor, "merge.editor", refs, refsInvalid, errors);
|
|
195
195
|
}
|
|
196
|
-
if (Array.isArray(magiConfig.triage?.
|
|
197
|
-
magiConfig.triage.
|
|
196
|
+
if (Array.isArray(magiConfig.triage?.voters)) {
|
|
197
|
+
magiConfig.triage.voters = magiConfig.triage.voters.map((agent, index) => expandAgentRefUse(agent, `triage.voters[${index}]`, refs, refsInvalid, errors));
|
|
198
198
|
}
|
|
199
199
|
if (isPlainObject(magiConfig.triage?.creator)) {
|
|
200
200
|
magiConfig.triage.creator = expandAgentRefUse(magiConfig.triage.creator, "triage.creator", refs, refsInvalid, errors);
|
|
@@ -387,18 +387,18 @@ function validateReviewerList(reviewers, path, errors, catalog) {
|
|
|
387
387
|
}
|
|
388
388
|
});
|
|
389
389
|
}
|
|
390
|
-
function validateTriageAgentList(
|
|
391
|
-
if (
|
|
390
|
+
function validateTriageAgentList(voters, path, errors, catalog) {
|
|
391
|
+
if (voters == null)
|
|
392
392
|
return;
|
|
393
|
-
if (!Array.isArray(
|
|
393
|
+
if (!Array.isArray(voters)) {
|
|
394
394
|
errors.push(`${path} must be an array`);
|
|
395
395
|
return;
|
|
396
396
|
}
|
|
397
|
-
if (
|
|
398
|
-
errors.push(`${path} must contain at least 3
|
|
399
|
-
if (
|
|
400
|
-
errors.push(`${path} must contain an odd number of
|
|
401
|
-
|
|
397
|
+
if (voters.length < 3)
|
|
398
|
+
errors.push(`${path} must contain at least 3 voters`);
|
|
399
|
+
if (voters.length % 2 === 0)
|
|
400
|
+
errors.push(`${path} must contain an odd number of voters`);
|
|
401
|
+
voters.forEach((agent, index) => {
|
|
402
402
|
if (!agent || typeof agent !== "object") {
|
|
403
403
|
errors.push(`${path}[${index}] must be an object`);
|
|
404
404
|
return;
|
|
@@ -722,11 +722,11 @@ function validateTriage(config, errors, options) {
|
|
|
722
722
|
const creator = triage.creator;
|
|
723
723
|
const reporter = typeof triage.reporter === "string" ? triage.reporter : undefined;
|
|
724
724
|
const safety = triage.safety;
|
|
725
|
-
if (!triage.
|
|
726
|
-
errors.push("triage.
|
|
727
|
-
validateTriageAgentList(triage.
|
|
728
|
-
if (Array.isArray(triage.
|
|
729
|
-
const resolvedTriageAgents = triage.
|
|
725
|
+
if (!triage.voters)
|
|
726
|
+
errors.push("triage.voters is required");
|
|
727
|
+
validateTriageAgentList(triage.voters, "triage.voters", errors, options.modelCatalog);
|
|
728
|
+
if (Array.isArray(triage.voters)) {
|
|
729
|
+
const resolvedTriageAgents = triage.voters.map((agent, index) => ({
|
|
730
730
|
account: agent && typeof agent === "object" && typeof agent.account === "string"
|
|
731
731
|
? agent.account
|
|
732
732
|
: "",
|
|
@@ -735,7 +735,7 @@ function validateTriage(config, errors, options) {
|
|
|
735
735
|
validateResolvedTriageAgents(resolvedTriageAgents, "triage.resolvedAgents", errors);
|
|
736
736
|
if (reporter != null &&
|
|
737
737
|
!resolvedTriageAgents.some((agent) => agent.key === reporter)) {
|
|
738
|
-
errors.push(`triage.reporter must match a triage
|
|
738
|
+
errors.push(`triage.reporter must match a triage voter key: ${reporter}`);
|
|
739
739
|
}
|
|
740
740
|
}
|
|
741
741
|
validateString(triage.reporter, "triage.reporter", errors);
|
|
@@ -926,11 +926,11 @@ export async function validateConfig(config, options = {}) {
|
|
|
926
926
|
else {
|
|
927
927
|
validateKnownKeys(config.review, "review", REVIEW_KEYS, errors);
|
|
928
928
|
}
|
|
929
|
-
if (!config.review.
|
|
930
|
-
errors.push("review.
|
|
931
|
-
validateReviewerList(config.review.
|
|
932
|
-
if (Array.isArray(config.review.
|
|
933
|
-
validateResolvedReviewers(config.review.
|
|
929
|
+
if (!config.review.reviewers)
|
|
930
|
+
errors.push("review.reviewers is required");
|
|
931
|
+
validateReviewerList(config.review.reviewers, "review.reviewers", errors, options.modelCatalog);
|
|
932
|
+
if (Array.isArray(config.review.reviewers)) {
|
|
933
|
+
validateResolvedReviewers(config.review.reviewers.map((reviewer, index) => ({
|
|
934
934
|
account: reviewer &&
|
|
935
935
|
typeof reviewer === "object" &&
|
|
936
936
|
typeof reviewer.account === "string"
|
|
@@ -939,7 +939,7 @@ export async function validateConfig(config, options = {}) {
|
|
|
939
939
|
key: reviewer && typeof reviewer === "object"
|
|
940
940
|
? reviewerKey(reviewer, index)
|
|
941
941
|
: "",
|
|
942
|
-
})), "review.
|
|
942
|
+
})), "review.resolvedReviewers", errors);
|
|
943
943
|
}
|
|
944
944
|
}
|
|
945
945
|
if (options.requireTriage && !config.triage) {
|
package/dist/index.js
CHANGED
|
@@ -381,7 +381,7 @@ export async function validateMagiConfigFiles(directory, options = {}) {
|
|
|
381
381
|
? withGitHubApiRetry(options.exec, mergedConfig.github?.apiRetryAttempts ?? 3)
|
|
382
382
|
: undefined,
|
|
383
383
|
modelCatalog: options.modelCatalog,
|
|
384
|
-
requireGithub: hasProjectConfig && Boolean(mergedConfig.review?.
|
|
384
|
+
requireGithub: hasProjectConfig && Boolean(mergedConfig.review?.reviewers),
|
|
385
385
|
requireModelCatalog: true,
|
|
386
386
|
requireWorktreeConfig: true,
|
|
387
387
|
});
|
|
@@ -547,7 +547,7 @@ export const MagiPlugin = async ({ client, directory }) => {
|
|
|
547
547
|
},
|
|
548
548
|
}),
|
|
549
549
|
magi_triage: tool({
|
|
550
|
-
description: "Triage one or more GitHub issues with configured Magi triage
|
|
550
|
+
description: "Triage one or more GitHub issues with configured Magi triage voters.",
|
|
551
551
|
args: {
|
|
552
552
|
issues: tool.schema.string(),
|
|
553
553
|
dryRun: tool.schema.boolean().optional(),
|
|
@@ -1616,16 +1616,16 @@ export class MagiRunManager {
|
|
|
1616
1616
|
}));
|
|
1617
1617
|
}
|
|
1618
1618
|
if (progress.type === "triage_agent_started") {
|
|
1619
|
-
await this.notify(state, `**Triage
|
|
1619
|
+
await this.notify(state, `**Triage voter ${progress.voter}** started ${progress.phase} for ${issue}.`);
|
|
1620
1620
|
}
|
|
1621
1621
|
if (progress.type === "triage_agent_repair") {
|
|
1622
|
-
await this.notify(state, `**Triage
|
|
1622
|
+
await this.notify(state, `**Triage voter ${progress.voter}** started JSON regeneration for ${issue}.`);
|
|
1623
1623
|
}
|
|
1624
1624
|
if (progress.type === "triage_agent_completed") {
|
|
1625
|
-
await this.notify(state, `**Triage
|
|
1625
|
+
await this.notify(state, `**Triage voter ${progress.voter}** completed ${progress.phase} for ${issue}: ${progress.vote}.`);
|
|
1626
1626
|
}
|
|
1627
1627
|
if (progress.type === "triage_agent_failed") {
|
|
1628
|
-
await this.notify(state, `**Triage
|
|
1628
|
+
await this.notify(state, `**Triage voter ${progress.voter}** failed ${progress.phase} for ${issue}: ${redactSecrets(progress.error)}`);
|
|
1629
1629
|
}
|
|
1630
1630
|
if (progress.type === "comment_posting") {
|
|
1631
1631
|
await this.notify(state, `Posting triage comment for ${issue}.`);
|
|
@@ -217,7 +217,7 @@ export function chooseDuplicateOutput(input) {
|
|
|
217
217
|
async function runDuplicateVote(input) {
|
|
218
218
|
const agents = input.input.repository.agents.triage;
|
|
219
219
|
if (!agents?.length)
|
|
220
|
-
throw new Error("triage.
|
|
220
|
+
throw new Error("triage.voters is required");
|
|
221
221
|
await emitProgress(input.input, { phase: "duplicate", type: "phase" });
|
|
222
222
|
const outputs = await Promise.all(agents.map((agent) => runVote({
|
|
223
223
|
agent,
|
|
@@ -259,7 +259,7 @@ async function runDuplicateVote(input) {
|
|
|
259
259
|
async function runPhaseVote(input) {
|
|
260
260
|
const agents = input.input.repository.agents.triage;
|
|
261
261
|
if (!agents?.length)
|
|
262
|
-
throw new Error("triage.
|
|
262
|
+
throw new Error("triage.voters is required");
|
|
263
263
|
await emitProgress(input.input, { phase: input.phase, type: "phase" });
|
|
264
264
|
const promptTexts = await Promise.all(agents.map((agent) => input.prompt({
|
|
265
265
|
context: input.context,
|
|
@@ -525,7 +525,7 @@ async function runReconsiderationVote(input) {
|
|
|
525
525
|
function triageReporter(repository, issue) {
|
|
526
526
|
const agents = repository.agents.triage ?? [];
|
|
527
527
|
if (!agents.length)
|
|
528
|
-
throw new Error("triage.
|
|
528
|
+
throw new Error("triage.voters is required");
|
|
529
529
|
const configured = repository.triage?.reporter;
|
|
530
530
|
const reporter = configured
|
|
531
531
|
? agents.find((agent) => agent.key === configured)
|
|
@@ -563,7 +563,7 @@ function decisionCommentFallback(input) {
|
|
|
563
563
|
function agentForKey(repository, key) {
|
|
564
564
|
const agent = repository.agents.triage?.find((item) => item.key === key);
|
|
565
565
|
if (!agent)
|
|
566
|
-
throw new Error(`Unknown triage
|
|
566
|
+
throw new Error(`Unknown triage voter: ${key}`);
|
|
567
567
|
return agent;
|
|
568
568
|
}
|
|
569
569
|
function askOutputs(outputs) {
|
|
@@ -905,7 +905,7 @@ export async function runTriage(input) {
|
|
|
905
905
|
throw new Error("triage configuration is required");
|
|
906
906
|
const agents = input.repository.agents.triage;
|
|
907
907
|
if (!agents?.length)
|
|
908
|
-
throw new Error("triage.
|
|
908
|
+
throw new Error("triage.voters is required");
|
|
909
909
|
const runId = input.runId ?? `run-${Date.now().toString(36)}`;
|
|
910
910
|
const outputDir = issueRunOutputDir({
|
|
911
911
|
config: input.config,
|
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-20260525030452",
|
|
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>",
|
package/schema.json
CHANGED
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
"type": "object",
|
|
317
317
|
"additionalProperties": false,
|
|
318
318
|
"properties": {
|
|
319
|
-
"
|
|
319
|
+
"reviewers": {
|
|
320
320
|
"type": "array",
|
|
321
321
|
"minItems": 3,
|
|
322
322
|
"items": { "$ref": "#/$defs/reviewer" }
|
|
@@ -351,7 +351,7 @@
|
|
|
351
351
|
"type": "object",
|
|
352
352
|
"additionalProperties": false,
|
|
353
353
|
"properties": {
|
|
354
|
-
"
|
|
354
|
+
"voters": {
|
|
355
355
|
"type": "array",
|
|
356
356
|
"minItems": 3,
|
|
357
357
|
"items": { "$ref": "#/$defs/triageAgent" }
|