opencode-magi 0.0.0-dev-20260525165911 → 0.0.0-dev-20260525205150

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.
@@ -113,9 +113,7 @@ export function resolveAgents(config) {
113
113
  const agents = config.agents ?? {};
114
114
  const editor = config.merge?.editor;
115
115
  const creator = config.triage?.creator;
116
- const singleReviewAccount = config.review && config.review.mode !== "multi"
117
- ? config.review.account
118
- : undefined;
116
+ const singleReviewAccount = config.review && config.mode !== "multi" ? config.account : undefined;
119
117
  return {
120
118
  editor: editor
121
119
  ? {
@@ -188,6 +186,8 @@ export function resolveRepository(config) {
188
186
  repo: config.github.repo,
189
187
  },
190
188
  language: config.language,
189
+ account: config.account,
190
+ mode: config.mode ?? "single",
191
191
  merge: {
192
192
  approvalPolicy: config.review?.merge?.approvalPolicy ?? "majority",
193
193
  method: config.review?.merge?.method ?? "squash",
@@ -208,10 +208,6 @@ export function resolveRepository(config) {
208
208
  review: config.review?.prompts?.review,
209
209
  reviewGuidelines: config.review?.prompts?.reviewGuidelines,
210
210
  },
211
- review: {
212
- account: config.review?.account,
213
- mode: config.review?.mode ?? "single",
214
- },
215
211
  reviewAutomation: {
216
212
  close: config.review?.automation?.close ?? false,
217
213
  merge: config.review?.automation?.merge ?? true,
@@ -13,11 +13,13 @@ const TRIAGE_CATEGORY_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
13
13
  const RESERVED_TRIAGE_CATEGORY_IDS = new Set(["ASK", "none"]);
14
14
  const CONFIG_KEYS = new Set([
15
15
  "$schema",
16
+ "account",
16
17
  "agents",
17
18
  "clear",
18
19
  "github",
19
20
  "language",
20
21
  "merge",
22
+ "mode",
21
23
  "output",
22
24
  "review",
23
25
  "triage",
@@ -54,12 +56,10 @@ const TRIAGE_CREATOR_KEYS = new Set([
54
56
  const AUTHOR_KEYS = new Set(["email", "name"]);
55
57
  const GITHUB_KEYS = new Set(["apiRetryAttempts", "host", "owner", "repo"]);
56
58
  const REVIEW_KEYS = new Set([
57
- "account",
58
59
  "automation",
59
60
  "checks",
60
61
  "concurrency",
61
62
  "merge",
62
- "mode",
63
63
  "output",
64
64
  "prompts",
65
65
  "reviewers",
@@ -469,16 +469,15 @@ function validateResolvedReviewers(reviewers, path, errors, mode = "single") {
469
469
  }
470
470
  }
471
471
  function reviewMode(config) {
472
- return config.review?.mode === "multi" ? "multi" : "single";
472
+ return config.mode === "multi" ? "multi" : "single";
473
473
  }
474
474
  function validateReviewIdentity(config, errors) {
475
- const mode = config.review?.mode;
475
+ const mode = config.mode;
476
476
  if (mode != null && mode !== "multi" && mode !== "single") {
477
- errors.push("review.mode must be multi or single");
477
+ errors.push("mode must be multi or single");
478
478
  }
479
- validateString(config.review?.account, "review.account", errors);
480
- if ((mode == null || mode === "single") && !config.review?.account) {
481
- errors.push("review.account is required when review.mode is single");
479
+ if ((mode == null || mode === "single") && !config.account) {
480
+ errors.push("account is required when mode is single");
482
481
  }
483
482
  }
484
483
  function validateResolvedTriageAgents(agents, path, errors) {
@@ -924,8 +923,8 @@ async function validateAuth(config, exec, errors) {
924
923
  const accounts = new Set();
925
924
  const agents = resolveAgents(config);
926
925
  if (reviewMode(config) === "single") {
927
- if (config.review?.account)
928
- accounts.add(config.review.account);
926
+ if (config.account)
927
+ accounts.add(config.account);
929
928
  }
930
929
  else {
931
930
  for (const reviewer of agents.reviewers)
@@ -978,8 +977,8 @@ async function validateRepositoryPermissions(config, exec, errors, warnings) {
978
977
  return;
979
978
  const agents = resolveAgents(config);
980
979
  const reviewAccounts = reviewMode(config) === "single"
981
- ? config.review?.account
982
- ? [config.review.account]
980
+ ? config.account
981
+ ? [config.account]
983
982
  : []
984
983
  : agents.reviewers.map((reviewer) => reviewer.account);
985
984
  await Promise.all(reviewAccounts.map(async (account) => {
@@ -1040,6 +1039,7 @@ export async function validateConfig(config, options = {}) {
1040
1039
  validateJsonSchema(config, errors);
1041
1040
  validateKnownKeys(config, "config", CONFIG_KEYS, errors);
1042
1041
  validateString(config.$schema, "$schema", errors);
1042
+ validateString(config.account, "account", errors);
1043
1043
  validateString(config.language, "language", errors);
1044
1044
  if (config.agents != null && !isPlainObject(config.agents)) {
1045
1045
  errors.push("agents must be an object");
@@ -213,7 +213,7 @@ async function runRereview(input, worktreePath, previousHeadSha, cycle, sessionI
213
213
  worktreePath,
214
214
  });
215
215
  const artifactDir = outputDir(input);
216
- const singleReviewMode = input.repository.review?.mode !== "multi";
216
+ const singleReviewMode = input.repository.mode !== "multi";
217
217
  const reviewerKeys = input.repository.agents.reviewers.map((reviewer) => reviewer.key);
218
218
  const singleModeThreads = singleReviewMode
219
219
  ? assignThreadsByReviewFindingMarker({
@@ -221,7 +221,7 @@ async function runRereview(input, worktreePath, previousHeadSha, cycle, sessionI
221
221
  pr: input.pr,
222
222
  reviewerKeys,
223
223
  threads: options.dryRunThreads == null
224
- ? await fetchUnresolvedThreads(input.exec, input.repository, input.pr, input.repository.review?.account ?? "")
224
+ ? await fetchUnresolvedThreads(input.exec, input.repository, input.pr, input.repository.account ?? "")
225
225
  : Object.values(options.dryRunThreads).flat(),
226
226
  })
227
227
  : undefined;
@@ -412,7 +412,7 @@ async function runRereview(input, worktreePath, previousHeadSha, cycle, sessionI
412
412
  ? { consensus: `dry-run:would-post-single-review:${verdict}` }
413
413
  : {
414
414
  consensus: await (async () => {
415
- const account = input.repository.review?.account ?? "";
415
+ const account = input.repository.account ?? "";
416
416
  await Promise.all(entries.flatMap((entry) => entry.output.resolve.map((item) => resolveThread(input.exec, input.repository, account, item.threadId))));
417
417
  await Promise.all(entries.flatMap((entry) => entry.output.followUps.map((item) => postReply(input.exec, input.repository, input.pr, account, item.commentId, [
418
418
  `**Reviewer:** ${entry.reviewer}`,
@@ -16,12 +16,14 @@ import { formatReviewReport } from "./report";
16
16
  import { buildReviewContextSnapshot, renderReviewContext, } from "./review-context";
17
17
  import { checkSafetyGate, hasSafetyGate } from "./safety";
18
18
  function resolvedReviewMode(repository) {
19
- return repository.review?.mode === "multi" ? "multi" : "single";
19
+ return repository.mode === "multi" ? "multi" : "single";
20
20
  }
21
21
  export function reviewPostingAccount(repository, reviewer) {
22
- return resolvedReviewMode(repository) === "single"
23
- ? (repository.review?.account ?? reviewer.account)
24
- : reviewer.account;
22
+ if (resolvedReviewMode(repository) !== "single")
23
+ return reviewer.account;
24
+ if (repository.account)
25
+ return repository.account;
26
+ throw new Error("account is required for single review mode");
25
27
  }
26
28
  function reviewAssignmentKey(repository, reviewer) {
27
29
  return resolvedReviewMode(repository) === "single"
@@ -579,9 +581,9 @@ function singleFindingBody(input) {
579
581
  ].join("\n");
580
582
  }
581
583
  export async function postSingleConsensusReview(input) {
582
- const account = input.repository.review?.account;
584
+ const account = input.repository.account;
583
585
  if (!account)
584
- throw new Error("review.account is required for single review mode");
586
+ throw new Error("account is required for single review mode");
585
587
  const body = singleReviewBody(input);
586
588
  if (input.verdict === "MERGE") {
587
589
  return postApproval(input.exec, input.repository, input.pr, account, body);
@@ -927,7 +929,7 @@ export async function runReview(input) {
927
929
  const reviewerAccounts = input.repository.agents.reviewers.map((reviewer) => reviewer.account);
928
930
  const preliminaryMode = singleReviewMode
929
931
  ? resolveSingleAccountReviewMode({
930
- account: input.repository.review?.account ?? "",
932
+ account: input.repository.account ?? "",
931
933
  current: freshnessTarget,
932
934
  pr: input.pr,
933
935
  reviewerKeys,
@@ -942,7 +944,7 @@ export async function runReview(input) {
942
944
  return (preliminaryMode.assignments.get(reviewAssignmentKey(input.repository, reviewer))?.type === "skip");
943
945
  });
944
946
  if (singleReviewMode) {
945
- const account = input.repository.review?.account ?? "";
947
+ const account = input.repository.account ?? "";
946
948
  const threads = await fetchUnresolvedThreads(exec, input.repository, input.pr, account);
947
949
  const assigned = assignThreadsByReviewFindingMarker({
948
950
  fallbackReviewerKeys: reviewerKeys,
@@ -973,7 +975,7 @@ export async function runReview(input) {
973
975
  const mode = singleReviewMode
974
976
  ? pendingThreadReplyReviewers.size
975
977
  ? resolveSingleAccountReviewMode({
976
- account: input.repository.review?.account ?? "",
978
+ account: input.repository.account ?? "",
977
979
  current: freshnessTarget,
978
980
  pendingReviewers: pendingThreadReplyReviewers,
979
981
  pr: input.pr,
@@ -1368,7 +1370,7 @@ export async function runReview(input) {
1368
1370
  consensus: input.dryRun
1369
1371
  ? `dry-run:would-post-single-review:${verdict}`
1370
1372
  : await (async () => {
1371
- const account = input.repository.review?.account ?? "";
1373
+ const account = input.repository.account ?? "";
1372
1374
  await Promise.all(Object.values(activeOutputs).flatMap((output) => {
1373
1375
  if (!("resolve" in output))
1374
1376
  return [];
@@ -1414,7 +1416,7 @@ export async function runReview(input) {
1414
1416
  ]))),
1415
1417
  };
1416
1418
  const automationAccount = singleReviewMode
1417
- ? input.repository.review?.account
1419
+ ? input.repository.account
1418
1420
  : input.repository.agents.reviewers[0]?.account;
1419
1421
  const enableReviewAutomation = input.enableReviewAutomation ?? true;
1420
1422
  if (enableReviewAutomation &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-magi",
3
- "version": "0.0.0-dev-20260525165911",
3
+ "version": "0.0.0-dev-20260525205150",
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
@@ -5,6 +5,7 @@
5
5
  "additionalProperties": false,
6
6
  "properties": {
7
7
  "$schema": { "type": "string" },
8
+ "account": { "type": "string", "minLength": 1 },
8
9
  "agents": {
9
10
  "type": "object",
10
11
  "additionalProperties": false,
@@ -44,6 +45,7 @@
44
45
  },
45
46
  "language": { "type": "string" },
46
47
  "merge": { "$ref": "#/$defs/merge" },
48
+ "mode": { "enum": ["multi", "single"], "default": "single" },
47
49
  "output": {
48
50
  "type": "object",
49
51
  "additionalProperties": false,
@@ -366,8 +368,6 @@
366
368
  "type": "object",
367
369
  "additionalProperties": false,
368
370
  "properties": {
369
- "mode": { "enum": ["multi", "single"], "default": "single" },
370
- "account": { "type": "string", "minLength": 1 },
371
371
  "reviewers": {
372
372
  "type": "array",
373
373
  "minItems": 3,