opencode-magi 0.0.0-dev-20260720080129 → 0.0.0-dev-20260720123050

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,6 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { CONFIG_PATH, DEFAULT_CONFIG } from "@/constant";
4
+ import editPermissions from "@/permissions/editor.json" with { type: "json" };
4
5
  import { filterEmpty, getModels, isArray, isObject, isString, merge, } from "@/utils";
5
6
  export function resolvePermissions(permissions) {
6
7
  if (!permissions)
@@ -83,6 +84,8 @@ export async function getConfig(input) {
83
84
  readConfig(projectPath),
84
85
  ]);
85
86
  const results = filterEmpty(data);
87
+ if (!models.length)
88
+ throw new Error("No OpenCode models found.");
86
89
  if (!results.length)
87
90
  throw new Error(`No Magi config found. Expected ${CONFIG_PATH.GLOBAL} or ${projectPath}.`);
88
91
  const config = results.reduce((prev, current) => merge(prev, current), DEFAULT_CONFIG);
@@ -96,8 +99,14 @@ export async function getConfig(input) {
96
99
  model: resolveModel(models, model),
97
100
  };
98
101
  });
99
- config.merge.editor = mergeAgent(config, config.merge.editor);
100
- config.merge.editor.model = resolveModel(models, config.merge.editor.model);
102
+ if (config.merge.editor) {
103
+ if (config.merge.editor.permissions)
104
+ config.merge.editor.permissions = mergePermissions(editPermissions, config.merge.editor.permissions);
105
+ else
106
+ config.merge.editor.permissions = editPermissions;
107
+ config.merge.editor = mergeAgent(config, config.merge.editor);
108
+ config.merge.editor.model = resolveModel(models, config.merge.editor.model);
109
+ }
101
110
  if (config.triage.voters)
102
111
  config.triage.voters = config.triage.voters.map((agent, index) => {
103
112
  const { id, model, ...rest } = mergeAgent(config, agent);
@@ -107,7 +116,13 @@ export async function getConfig(input) {
107
116
  model: resolveModel(models, model),
108
117
  };
109
118
  });
110
- config.triage.creator = mergeAgent(config, config.triage.creator);
111
- config.triage.creator.model = resolveModel(models, config.triage.creator.model);
119
+ if (config.triage.creator) {
120
+ if (config.triage.creator.permissions)
121
+ config.triage.creator.permissions = mergePermissions(editPermissions, config.triage.creator.permissions);
122
+ else
123
+ config.triage.creator.permissions = editPermissions;
124
+ config.triage.creator = mergeAgent(config, config.triage.creator);
125
+ config.triage.creator.model = resolveModel(models, config.triage.creator.model);
126
+ }
112
127
  return config;
113
128
  }
@@ -12,28 +12,32 @@ function schemaErrors(config) {
12
12
  return (validateSchema.errors ?? []).map((e) => `schema ${e.instancePath || "config"}: ${e.message ?? "invalid value"}`);
13
13
  }
14
14
  function requiredErrors(config, { creator = false, editor = false, github = true, reviewers = false, voters = false, } = {}) {
15
+ creator ||= !!config.triage.creator;
16
+ editor ||= !!config.merge.editor;
17
+ reviewers ||= !!config.review.reviewers;
18
+ voters ||= !!config.triage.voters;
15
19
  const errors = [
16
20
  required(github, config.github.owner, "github.owner"),
17
21
  required(github, config.github.repo, "github.repo"),
18
22
  required(reviewers, config.review.reviewers, "review.reviewers"),
19
- ...(config.review.reviewers ?? []).map((reviewer, index) => required(reviewers, reviewer.model, `review.reviewers[${index}].model`)),
23
+ ...(config.review.reviewers ?? []).map((reviewer, index) => required(reviewers || !!reviewer, reviewer.model, `review.reviewers[${index}].model`)),
20
24
  required(editor, config.merge.editor, "merge.editor"),
21
- required(editor, config.merge.editor.model, "merge.editor.model"),
22
- required(editor, config.merge.editor.author, "merge.editor.author"),
25
+ required(editor, config.merge.editor?.model, "merge.editor.model"),
26
+ required(editor, config.merge.editor?.author, "merge.editor.author"),
23
27
  required(voters, config.triage.voters, "triage.voters"),
24
- ...(config.triage.voters ?? []).map((voter, index) => required(voters, voter.model, `triage.voters[${index}].model`)),
28
+ ...(config.triage.voters ?? []).map((voter, index) => required(voters || !!voter, voter.model, `triage.voters[${index}].model`)),
25
29
  required(creator, config.triage.creator, "triage.creator"),
26
- required(creator, config.triage.creator.model, "triage.creator.model"),
27
- required(creator, config.triage.creator.author, "triage.creator.author"),
30
+ required(creator, config.triage.creator?.model, "triage.creator.model"),
31
+ required(creator, config.triage.creator?.author, "triage.creator.author"),
28
32
  ];
29
33
  if (config.mode === "single") {
30
34
  errors.push(required(true, config.account, "account"));
31
35
  }
32
36
  else {
33
37
  errors.push(...(config.review.reviewers ?? []).map((reviewer, index) => required(reviewers, reviewer.account, `review.reviewers[${index}].account`)));
34
- errors.push(required(editor, config.merge.editor.account, "merge.editor.account"));
38
+ errors.push(required(editor, config.merge.editor?.account, "merge.editor.account"));
35
39
  errors.push(...(config.triage.voters ?? []).map((voter, index) => required(voters, voter.account, `triage.voters[${index}].account`)));
36
- errors.push(required(creator, config.triage.creator.account, "triage.creator.account"));
40
+ errors.push(required(creator, config.triage.creator?.account, "triage.creator.account"));
37
41
  }
38
42
  return filterEmpty(errors);
39
43
  }
@@ -85,17 +89,19 @@ async function authErrors(config, exec) {
85
89
  }
86
90
  else {
87
91
  const accounts = {
88
- ...Object.fromEntries(config.review.reviewers.map(({ account }, index) => [
92
+ ...Object.fromEntries(config.review.reviewers?.map(({ account }, index) => [
89
93
  account,
90
94
  `review.reviewers[${index}]`,
91
- ])),
92
- [config.merge.editor.account]: "merge.editor",
93
- ...Object.fromEntries(config.triage.voters.map(({ account }, index) => [
95
+ ]) ?? []),
96
+ ...Object.fromEntries(config.triage.voters?.map(({ account }, index) => [
94
97
  account,
95
98
  `triage.voters[${index}]`,
96
- ])),
97
- [config.triage.creator.account]: "triage.creator",
99
+ ]) ?? []),
98
100
  };
101
+ if (config.merge.editor)
102
+ accounts[config.merge.editor.account] = "merge.editor";
103
+ if (config.triage.creator)
104
+ accounts[config.triage.creator.account] = "triage.creator";
99
105
  return filterEmpty([
100
106
  ...duplicateErrors(Object.keys(accounts), (value) => `${accounts[value]} has duplicate account: ${value}`),
101
107
  ...(await Promise.all(Object.keys(accounts).map((account) => authError(config, exec, account)))),
package/dist/constant.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
3
  import commonPermissions from "./permissions/common.json" with { type: "json" };
4
- import editPermissions from "./permissions/editor.json" with { type: "json" };
5
4
  export const CONFIG_PATH = {
6
5
  GLOBAL: join(homedir(), ".config", "opencode", "magi.json"),
7
6
  PROJECT: join(".opencode", "magi.json"),
@@ -33,9 +32,6 @@ export const DEFAULT_CONFIG = {
33
32
  checks: {
34
33
  wait: true,
35
34
  },
36
- editor: {
37
- permissions: editPermissions,
38
- },
39
35
  maxThreadResolutionCycles: 5,
40
36
  },
41
37
  mode: "single",
@@ -126,9 +122,6 @@ export const DEFAULT_CONFIG = {
126
122
  concurrency: {
127
123
  runs: 3,
128
124
  },
129
- creator: {
130
- permissions: editPermissions,
131
- },
132
125
  output: ".magi/runs/issue",
133
126
  safety: {
134
127
  allowAuthors: [],
@@ -193,7 +193,7 @@ async function push() {
193
193
  GIT_CONFIG_KEY_0: "credential.helper",
194
194
  GIT_CONFIG_KEY_1: "credential.helper",
195
195
  GIT_CONFIG_VALUE_0: "",
196
- GIT_CONFIG_VALUE_1: "!f() { echo username=x-access-token; echo password=$GIT_PASSWORD; }; f",
196
+ GIT_CONFIG_VALUE_1: "!f() { echo username=git; echo password=$GIT_PASSWORD; }; f",
197
197
  GIT_PASSWORD: token,
198
198
  GIT_TERMINAL_PROMPT: "0",
199
199
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-magi",
3
- "version": "0.0.0-dev-20260720080129",
3
+ "version": "0.0.0-dev-20260720123050",
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>",