opencode-magi 0.0.0-dev-20260521013020 → 0.0.0-dev-20260521140727
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/config/validate.js +51 -0
- package/dist/github/commands.js +7 -1
- package/package.json +1 -1
- package/schema.json +37 -5
package/dist/config/validate.js
CHANGED
|
@@ -157,6 +157,56 @@ function ghHostOption(config) {
|
|
|
157
157
|
function isPlainObject(value) {
|
|
158
158
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
159
159
|
}
|
|
160
|
+
function expandAgentRefUse(value, path, refs, refsInvalid, errors) {
|
|
161
|
+
if (!isPlainObject(value) || !Object.hasOwn(value, "ref"))
|
|
162
|
+
return value;
|
|
163
|
+
const use = { ...value };
|
|
164
|
+
const ref = use.ref;
|
|
165
|
+
delete use.ref;
|
|
166
|
+
if (typeof ref !== "string") {
|
|
167
|
+
errors.push(`${path}.ref must be a string`);
|
|
168
|
+
return use;
|
|
169
|
+
}
|
|
170
|
+
if (refsInvalid) {
|
|
171
|
+
errors.push(`agents.refs must be an object to resolve ${path}.ref`);
|
|
172
|
+
return use;
|
|
173
|
+
}
|
|
174
|
+
const preset = refs?.[ref];
|
|
175
|
+
if (preset == null) {
|
|
176
|
+
errors.push(`${path}.ref references unknown agents.refs preset: ${ref}`);
|
|
177
|
+
return use;
|
|
178
|
+
}
|
|
179
|
+
if (!isPlainObject(preset)) {
|
|
180
|
+
errors.push(`agents.refs.${ref} must be an object when referenced by ${path}.ref`);
|
|
181
|
+
return use;
|
|
182
|
+
}
|
|
183
|
+
const presetFields = { ...preset };
|
|
184
|
+
delete presetFields.ref;
|
|
185
|
+
return { ...presetFields, ...use };
|
|
186
|
+
}
|
|
187
|
+
function expandAgentRefs(config, errors) {
|
|
188
|
+
if (!config || typeof config !== "object")
|
|
189
|
+
return;
|
|
190
|
+
const magiConfig = config;
|
|
191
|
+
const agents = magiConfig.agents;
|
|
192
|
+
const refsValue = isPlainObject(agents) ? agents.refs : undefined;
|
|
193
|
+
const refsInvalid = refsValue != null && !isPlainObject(refsValue);
|
|
194
|
+
const refs = isPlainObject(refsValue) ? refsValue : undefined;
|
|
195
|
+
if (Array.isArray(magiConfig.review?.agents)) {
|
|
196
|
+
magiConfig.review.agents = magiConfig.review.agents.map((agent, index) => expandAgentRefUse(agent, `review.agents[${index}]`, refs, refsInvalid, errors));
|
|
197
|
+
}
|
|
198
|
+
if (isPlainObject(magiConfig.merge?.editor)) {
|
|
199
|
+
magiConfig.merge.editor = expandAgentRefUse(magiConfig.merge.editor, "merge.editor", refs, refsInvalid, errors);
|
|
200
|
+
}
|
|
201
|
+
if (Array.isArray(magiConfig.triage?.agents)) {
|
|
202
|
+
magiConfig.triage.agents = magiConfig.triage.agents.map((agent, index) => expandAgentRefUse(agent, `triage.agents[${index}]`, refs, refsInvalid, errors));
|
|
203
|
+
}
|
|
204
|
+
if (isPlainObject(magiConfig.triage?.creator)) {
|
|
205
|
+
magiConfig.triage.creator = expandAgentRefUse(magiConfig.triage.creator, "triage.creator", refs, refsInvalid, errors);
|
|
206
|
+
}
|
|
207
|
+
if (isPlainObject(magiConfig.agents))
|
|
208
|
+
delete magiConfig.agents.refs;
|
|
209
|
+
}
|
|
160
210
|
function validateKnownKeys(value, path, keys, errors) {
|
|
161
211
|
if (!isPlainObject(value))
|
|
162
212
|
return;
|
|
@@ -792,6 +842,7 @@ export async function validateConfig(config, options = {}) {
|
|
|
792
842
|
const warnings = [];
|
|
793
843
|
if (!config || typeof config !== "object")
|
|
794
844
|
errors.push("config must be an object");
|
|
845
|
+
expandAgentRefs(config, errors);
|
|
795
846
|
if (config && typeof config === "object")
|
|
796
847
|
validateJsonSchema(config, errors);
|
|
797
848
|
validateKnownKeys(config, "config", CONFIG_KEYS, errors);
|
package/dist/github/commands.js
CHANGED
|
@@ -246,6 +246,12 @@ function duplicateReferences(text) {
|
|
|
246
246
|
refs.add(Number(match[1]));
|
|
247
247
|
return [...refs];
|
|
248
248
|
}
|
|
249
|
+
function issueTitleSearchQuery(title, fallback) {
|
|
250
|
+
return (title
|
|
251
|
+
.replaceAll(/[^\p{L}\p{N}_]+/gu, " ")
|
|
252
|
+
.replaceAll(/\s+/g, " ")
|
|
253
|
+
.trim() || fallback);
|
|
254
|
+
}
|
|
249
255
|
async function fetchIssueCandidate(exec, repository, number, whyCandidate) {
|
|
250
256
|
const raw = await exec(`gh issue view ${number} --repo ${shellQuote(repoSpecifier(repository))} --json number,title,url,state,body,createdAt`).catch(() => undefined);
|
|
251
257
|
if (!raw)
|
|
@@ -254,7 +260,7 @@ async function fetchIssueCandidate(exec, repository, number, whyCandidate) {
|
|
|
254
260
|
return { ...data, whyCandidate };
|
|
255
261
|
}
|
|
256
262
|
export async function searchDuplicateIssues(exec, repository, issue, limit = 5) {
|
|
257
|
-
const query = issue.title;
|
|
263
|
+
const query = issueTitleSearchQuery(issue.title, String(issue.number));
|
|
258
264
|
const explicitCandidates = await Promise.all(duplicateReferences(issue.body)
|
|
259
265
|
.filter((number) => number !== issue.number)
|
|
260
266
|
.map((number) => fetchIssueCandidate(exec, repository, number, "Issue body explicitly references a duplicate target.")));
|
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-20260521140727",
|
|
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
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
"type": "object",
|
|
10
10
|
"additionalProperties": false,
|
|
11
11
|
"properties": {
|
|
12
|
-
"permissions": { "$ref": "#/$defs/permissions" }
|
|
12
|
+
"permissions": { "$ref": "#/$defs/permissions" },
|
|
13
|
+
"refs": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"additionalProperties": { "$ref": "#/$defs/agentRef" }
|
|
16
|
+
}
|
|
13
17
|
}
|
|
14
18
|
},
|
|
15
19
|
"clear": {
|
|
@@ -51,11 +55,33 @@
|
|
|
51
55
|
"triage": { "$ref": "#/$defs/triage" }
|
|
52
56
|
},
|
|
53
57
|
"$defs": {
|
|
58
|
+
"agentRef": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"additionalProperties": false,
|
|
61
|
+
"properties": {
|
|
62
|
+
"id": { "type": "string", "pattern": "^[A-Za-z0-9_-]+$" },
|
|
63
|
+
"model": { "type": "string", "minLength": 1 },
|
|
64
|
+
"options": { "type": "object", "additionalProperties": true },
|
|
65
|
+
"account": { "type": "string", "minLength": 1 },
|
|
66
|
+
"author": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"properties": {
|
|
70
|
+
"name": { "type": "string", "minLength": 1 },
|
|
71
|
+
"email": { "type": "string", "minLength": 1 }
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"permissions": { "$ref": "#/$defs/permissions" },
|
|
75
|
+
"persona": { "type": "string" }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
54
78
|
"reviewer": {
|
|
55
79
|
"type": "object",
|
|
56
|
-
"
|
|
80
|
+
"if": { "not": { "required": ["ref"] } },
|
|
81
|
+
"then": { "required": ["model", "account"] },
|
|
57
82
|
"additionalProperties": false,
|
|
58
83
|
"properties": {
|
|
84
|
+
"ref": { "type": "string", "minLength": 1 },
|
|
59
85
|
"id": { "type": "string", "pattern": "^[A-Za-z0-9_-]+$" },
|
|
60
86
|
"model": { "type": "string", "minLength": 1 },
|
|
61
87
|
"options": { "type": "object", "additionalProperties": true },
|
|
@@ -66,9 +92,11 @@
|
|
|
66
92
|
},
|
|
67
93
|
"editor": {
|
|
68
94
|
"type": "object",
|
|
69
|
-
"
|
|
95
|
+
"if": { "not": { "required": ["ref"] } },
|
|
96
|
+
"then": { "required": ["model", "account", "author"] },
|
|
70
97
|
"additionalProperties": false,
|
|
71
98
|
"properties": {
|
|
99
|
+
"ref": { "type": "string", "minLength": 1 },
|
|
72
100
|
"model": { "type": "string", "minLength": 1 },
|
|
73
101
|
"options": { "type": "object", "additionalProperties": true },
|
|
74
102
|
"account": { "type": "string", "minLength": 1 },
|
|
@@ -87,9 +115,11 @@
|
|
|
87
115
|
},
|
|
88
116
|
"triageAgent": {
|
|
89
117
|
"type": "object",
|
|
90
|
-
"required": ["
|
|
118
|
+
"if": { "not": { "required": ["ref"] } },
|
|
119
|
+
"then": { "required": ["model"] },
|
|
91
120
|
"additionalProperties": false,
|
|
92
121
|
"properties": {
|
|
122
|
+
"ref": { "type": "string", "minLength": 1 },
|
|
93
123
|
"id": { "type": "string", "pattern": "^[A-Za-z0-9_-]+$" },
|
|
94
124
|
"model": { "type": "string", "minLength": 1 },
|
|
95
125
|
"options": { "type": "object", "additionalProperties": true },
|
|
@@ -99,9 +129,11 @@
|
|
|
99
129
|
},
|
|
100
130
|
"triageCreator": {
|
|
101
131
|
"type": "object",
|
|
102
|
-
"
|
|
132
|
+
"if": { "not": { "required": ["ref"] } },
|
|
133
|
+
"then": { "required": ["model", "author"] },
|
|
103
134
|
"additionalProperties": false,
|
|
104
135
|
"properties": {
|
|
136
|
+
"ref": { "type": "string", "minLength": 1 },
|
|
105
137
|
"account": { "type": "string", "minLength": 1 },
|
|
106
138
|
"model": { "type": "string", "minLength": 1 },
|
|
107
139
|
"options": { "type": "object", "additionalProperties": true },
|