opencode-magi 0.5.0 → 0.6.1

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,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { isAbsolute, join } from "node:path";
4
- import { ciClassificationAfterEditOutputContract, ciClassificationOutputContract, closeReconsiderationOutputContract, editOutputContract, findingValidationOutputContract, rereviewCloseReconsiderationOutputContract, rereviewOutputContract, reviewOutputContract, triageActionOutputContract, triageCommentClassificationOutputContract, triageCreatePrOutputContract, triageDuplicateOutputContract, triageVoteOutputContract, } from "./contracts";
4
+ import { ciClassificationAfterEditOutputContract, ciClassificationOutputContract, closeReconsiderationOutputContract, editOutputContract, findingValidationOutputContract, rereviewCloseReconsiderationOutputContract, rereviewOutputContract, reviewOutputContract, triageCommentClassificationOutputContract, triageCreatePrOutputContract, triageDuplicateOutputContract, triageVoteOutputContract, } from "./contracts";
5
5
  async function readOptionalPrompt(directory, path, values = {}) {
6
6
  if (!path)
7
7
  return "";
@@ -333,52 +333,12 @@ async function composeTriageVotePrompt(input) {
333
333
  return [
334
334
  task,
335
335
  languageBlock(input.repository.language),
336
- personaBlock(input.reviewer.persona),
336
+ personaBlock(input.voter.persona),
337
337
  input.outputContract,
338
338
  ]
339
339
  .filter(Boolean)
340
340
  .join("\n\n");
341
341
  }
342
- export async function composeTriageActionPrompt(input) {
343
- return composeTriageVotePrompt({
344
- ...input,
345
- builtin: "action",
346
- customPath: input.repository.triage?.prompts.action,
347
- outputContract: triageActionOutputContract,
348
- });
349
- }
350
- export async function composeTriageCommentPrompt(input) {
351
- const values = triageValues(input);
352
- const task = await taskBlock({
353
- builtin: "triage/comment",
354
- customPath: input.repository.triage?.prompts.comment,
355
- directory: input.directory,
356
- values,
357
- });
358
- return [
359
- task,
360
- languageBlock(input.repository.language),
361
- `<context>\n${input.context}\n</context>`,
362
- ]
363
- .filter(Boolean)
364
- .join("\n\n");
365
- }
366
- export async function composeTriageQuestionPrompt(input) {
367
- const values = triageValues(input);
368
- const task = await taskBlock({
369
- builtin: "triage/question",
370
- customPath: input.repository.triage?.prompts.question,
371
- directory: input.directory,
372
- values,
373
- });
374
- return [
375
- task,
376
- languageBlock(input.repository.language),
377
- `<context>\n${input.context}\n</context>`,
378
- ]
379
- .filter(Boolean)
380
- .join("\n\n");
381
- }
382
342
  export async function composeTriageCreatePrPrompt(input) {
383
343
  const values = triageValues(input);
384
344
  const task = await taskBlock({
@@ -217,8 +217,13 @@ Return exactly one JSON object and nothing else. Do not wrap it in markdown.
217
217
  The object must match this shape:
218
218
  {
219
219
  "vote": ${votes},
220
- "reason": "Short rationale."
220
+ "reason": "Short rationale.",
221
+ "body": "Required only when vote is ASK. Public issue comment body asking for the missing information."
221
222
  }
223
+
224
+ Rules:
225
+ - body is required when vote is ASK and must be written for the issue author.
226
+ - Omit body when vote is not ASK.
222
227
  </output_contract>`.trim();
223
228
  }
224
229
  export const triageDuplicateOutputContract = `
@@ -251,24 +256,6 @@ The object must match this shape:
251
256
  ]
252
257
  }
253
258
  </output_contract>`.trim();
254
- export const triageActionOutputContract = `
255
- <output_contract>
256
- Return exactly one JSON object and nothing else. Do not wrap it in markdown.
257
-
258
- The object must match this shape:
259
- {
260
- "action": "ASK" | "COMMENT" | "CLOSE" | "PR" | "CLEAR_ONLY",
261
- "reason": "Short rationale."
262
- }
263
-
264
- Rules:
265
- - Choose only an action listed as allowed in the task context.
266
- - ASK means post an author-mentioned question and do not close, create a PR, or clear labels.
267
- - COMMENT means post a decision comment only.
268
- - CLOSE means post a decision comment and close the issue.
269
- - PR means post a decision comment and create an implementation PR.
270
- - CLEAR_ONLY means clear labels without posting a comment.
271
- </output_contract>`.trim();
272
259
  const outputContractsBySchemaName = {
273
260
  "CI classification": ciClassificationOutputContract,
274
261
  "close reconsideration": closeReconsiderationOutputContract,
@@ -277,7 +264,6 @@ const outputContractsBySchemaName = {
277
264
  rereview: rereviewOutputContract,
278
265
  "rereview close reconsideration": rereviewCloseReconsiderationOutputContract,
279
266
  review: reviewOutputContract,
280
- "triage action": triageActionOutputContract,
281
267
  "triage acceptance": triageVoteOutputContract('"YES" | "NO" | "ASK"'),
282
268
  "triage category": triageVoteOutputContract('"ASK" or one of the configured category IDs'),
283
269
  "triage create PR": triageCreatePrOutputContract,
@@ -92,9 +92,14 @@ function parseTriageVote(text, votes) {
92
92
  const data = extractJson(text);
93
93
  if (!data || typeof data !== "object")
94
94
  throw new Error("triage vote output must be an object");
95
+ const vote = requireOneOf(data.vote, "vote", votes);
96
+ const body = data.body == null ? undefined : requireString(data.body, "body");
97
+ if (vote === "ASK" && !body?.trim())
98
+ throw new Error("ASK requires body");
95
99
  return {
100
+ body,
96
101
  reason: requireString(data.reason, "reason"),
97
- vote: requireOneOf(data.vote, "vote", votes),
102
+ vote,
98
103
  };
99
104
  }
100
105
  export function parseTriageExistingPrOutput(text) {
@@ -149,21 +154,6 @@ export function parseTriageCommentClassificationOutput(text) {
149
154
  }),
150
155
  };
151
156
  }
152
- export function parseTriageActionOutput(text) {
153
- const data = extractJson(text);
154
- if (!data || typeof data !== "object")
155
- throw new Error("triage action output must be an object");
156
- return {
157
- action: requireOneOf(data.action, "action", [
158
- "ASK",
159
- "CLEAR_ONLY",
160
- "CLOSE",
161
- "COMMENT",
162
- "PR",
163
- ]),
164
- reason: requireString(data.reason, "reason"),
165
- };
166
- }
167
157
  export function parseReviewOutput(text) {
168
158
  const data = extractJson(text);
169
159
  if (!data || typeof data !== "object")
@@ -1,6 +1,6 @@
1
1
  Decide whether an existing related pull request already handles issue #{issue} in {owner}/{repo}.
2
2
 
3
- Use only the provided context. Return HANDLE only when the PR clearly addresses the issue.
3
+ Use only the provided context. Return RELATED_PR_HANDLES_ISSUE only when the PR clearly addresses the issue. Otherwise return RELATED_PR_DOES_NOT_HANDLE_ISSUE.
4
4
 
5
5
  <context>
6
6
  {context}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-magi",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
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
@@ -116,12 +116,13 @@
116
116
  "triageAgent": {
117
117
  "type": "object",
118
118
  "if": { "not": { "required": ["ref"] } },
119
- "then": { "required": ["model"] },
119
+ "then": { "required": ["model", "account"] },
120
120
  "additionalProperties": false,
121
121
  "properties": {
122
122
  "ref": { "type": "string", "minLength": 1 },
123
123
  "id": { "type": "string", "pattern": "^[A-Za-z0-9_-]+$" },
124
124
  "model": { "type": "string", "minLength": 1 },
125
+ "account": { "type": "string", "minLength": 1 },
125
126
  "options": { "type": "object", "additionalProperties": true },
126
127
  "permissions": { "$ref": "#/$defs/permissions" },
127
128
  "persona": { "type": "string" }
@@ -228,9 +229,6 @@
228
229
  "duplicate": { "type": "string" },
229
230
  "category": { "type": "string" },
230
231
  "acceptance": { "type": "string" },
231
- "action": { "type": "string" },
232
- "question": { "type": "string" },
233
- "comment": { "type": "string" },
234
232
  "commentClassification": { "type": "string" },
235
233
  "reconsider": { "type": "string" },
236
234
  "create": { "type": "string" },
@@ -334,7 +332,6 @@
334
332
  "type": "object",
335
333
  "additionalProperties": false,
336
334
  "properties": {
337
- "account": { "type": "string", "minLength": 1 },
338
335
  "agents": {
339
336
  "type": "array",
340
337
  "minItems": 3,
@@ -349,6 +346,7 @@
349
346
  "safety": { "$ref": "#/$defs/triageSafety" },
350
347
  "concurrency": { "$ref": "#/$defs/triageConcurrency" },
351
348
  "prompts": { "$ref": "#/$defs/triagePrompts" },
349
+ "reporter": { "type": "string", "minLength": 1 },
352
350
  "output": { "type": "string" },
353
351
  "worktree": { "type": "string" }
354
352
  }
@@ -1,5 +0,0 @@
1
- Decide the next action for issue #{issue} in {owner}/{repo} from the provided triage result and allowed actions.
2
-
3
- <context>
4
- {context}
5
- </context>
@@ -1,5 +0,0 @@
1
- Compose one concise final triage comment for issue #{issue} in {owner}/{repo}. Mention @{author}. Do not include markdown fences.
2
-
3
- <context>
4
- {context}
5
- </context>
@@ -1,5 +0,0 @@
1
- Compose concrete, actionable questions for issue #{issue} in {owner}/{repo}. Mention @{author}. Do not include markdown fences.
2
-
3
- <context>
4
- {context}
5
- </context>