opencode-magi 0.10.0 → 0.12.0
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.ja.md +254 -0
- package/README.md +31 -26
- package/dist/commands.js +11 -9
- package/dist/config/index.js +2 -0
- package/dist/config/resolve.js +120 -246
- package/dist/config/validate.js +98 -1110
- package/dist/constant.js +131 -0
- package/dist/graphql/index.generated.js +125 -0
- package/dist/graphql/index.js +49 -0
- package/dist/index.js +12 -800
- package/dist/magi.js +357 -0
- package/dist/permissions/common.json +22 -22
- package/dist/permissions/editor.json +12 -12
- package/dist/prompts/index.js +98 -0
- package/dist/prompts/merge/ci-classification/output-contract.md +22 -0
- package/dist/prompts/merge/ci-classification/task.md +10 -0
- package/dist/prompts/merge/ci-classification/validate.json +20 -0
- package/dist/prompts/merge/conflict/output-contract.md +12 -0
- package/dist/prompts/merge/conflict/task.md +9 -0
- package/dist/prompts/merge/conflict/validate.json +4 -0
- package/dist/prompts/merge/edit/output-contract.md +26 -0
- package/dist/prompts/merge/edit/task.md +10 -0
- package/dist/prompts/merge/edit/validate.json +60 -0
- package/dist/prompts/review/ci-classification/output-contract.md +21 -0
- package/dist/prompts/review/ci-classification/task.md +7 -0
- package/dist/prompts/review/ci-classification/validate.json +20 -0
- package/dist/prompts/review/close-reconsideration/output-contract.md +21 -0
- package/dist/prompts/review/close-reconsideration/task.md +6 -0
- package/dist/prompts/review/close-reconsideration/validate.json +44 -0
- package/dist/prompts/review/comment/output-contract.md +11 -0
- package/dist/prompts/review/comment/task.md +3 -0
- package/dist/prompts/review/comment/validate.json +8 -0
- package/dist/prompts/review/finding-validation/output-contract.md +25 -0
- package/dist/prompts/{templates/review/finding-validation.md → review/finding-validation/task.md} +2 -3
- package/dist/prompts/review/finding-validation/validate.json +21 -0
- package/dist/prompts/review/rereview/output-contract.md +30 -0
- package/dist/prompts/{templates/review/rereview.md → review/rereview/task.md} +8 -11
- package/dist/prompts/review/rereview/validate.json +87 -0
- package/dist/prompts/review/review/output-contract.md +25 -0
- package/dist/prompts/{templates/review/review.md → review/review/task.md} +2 -5
- package/dist/prompts/review/review/validate.json +54 -0
- package/dist/prompts/triage/acceptance/output-contract.md +16 -0
- package/dist/prompts/triage/acceptance/validate.json +23 -0
- package/dist/prompts/triage/category/output-contract.md +16 -0
- package/dist/prompts/triage/category/validate.json +23 -0
- package/dist/prompts/triage/comment-classification/output-contract.md +15 -0
- package/dist/prompts/triage/comment-classification/validate.json +28 -0
- package/dist/prompts/triage/create/output-contract.md +28 -0
- package/dist/prompts/triage/create/validate.json +73 -0
- package/dist/prompts/triage/deplicate/output-contract.md +16 -0
- package/dist/prompts/triage/deplicate/validate.json +20 -0
- package/dist/prompts/triage/existing/output-contract.md +16 -0
- package/dist/prompts/triage/existing/validate.json +13 -0
- package/dist/prompts/triage/reconsider/output-contract.md +16 -0
- package/dist/prompts/triage/reconsider/validate.json +23 -0
- package/dist/prompts/triage/signal/output-contract.md +19 -0
- package/dist/prompts/triage/signal/validate.json +18 -0
- package/dist/tools/clear/index.js +21 -0
- package/dist/tools/index.js +12 -0
- package/dist/tools/merge/action.js +47 -0
- package/dist/tools/merge/context.js +116 -0
- package/dist/tools/merge/editor.js +256 -0
- package/dist/tools/merge/index.js +151 -0
- package/dist/tools/merge/index.type.js +1 -0
- package/dist/tools/merge/merge.js +42 -0
- package/dist/tools/merge/report.js +73 -0
- package/dist/tools/review/action.js +459 -0
- package/dist/tools/review/check.js +335 -0
- package/dist/tools/review/context.js +254 -0
- package/dist/tools/review/index.js +104 -0
- package/dist/tools/review/index.type.js +1 -0
- package/dist/tools/review/report.js +143 -0
- package/dist/tools/review/review.js +146 -0
- package/dist/tools/review/reviewer.js +409 -0
- package/dist/tools/triage/index.js +16 -0
- package/dist/tools/validate/index.js +28 -0
- package/dist/utils/array.js +6 -0
- package/dist/utils/assertion.js +38 -0
- package/dist/utils/exec.js +14 -0
- package/dist/utils/fs.js +24 -0
- package/dist/utils/function.js +46 -0
- package/dist/utils/github.js +63 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.type.js +1 -0
- package/dist/utils/object.js +21 -0
- package/dist/utils/opencode.js +25 -0
- package/dist/utils/string.js +38 -0
- package/dist/utils/worker.js +30 -0
- package/package.json +36 -23
- package/schema.json +116 -20
- package/dist/config/load.js +0 -62
- package/dist/config/output.js +0 -25
- package/dist/config/worktree.js +0 -25
- package/dist/github/commands.js +0 -905
- package/dist/github/retry.js +0 -44
- package/dist/orchestrator/abort.js +0 -9
- package/dist/orchestrator/ci.js +0 -579
- package/dist/orchestrator/findings.js +0 -88
- package/dist/orchestrator/inline-comments.js +0 -73
- package/dist/orchestrator/majority.js +0 -62
- package/dist/orchestrator/merge.js +0 -1260
- package/dist/orchestrator/model.js +0 -216
- package/dist/orchestrator/pool.js +0 -15
- package/dist/orchestrator/report.js +0 -175
- package/dist/orchestrator/review-context.js +0 -342
- package/dist/orchestrator/review.js +0 -1480
- package/dist/orchestrator/run-manager.js +0 -2132
- package/dist/orchestrator/safety.js +0 -44
- package/dist/orchestrator/triage.js +0 -1370
- package/dist/prompts/compose.js +0 -473
- package/dist/prompts/contracts.js +0 -300
- package/dist/prompts/output.js +0 -401
- package/dist/prompts/templates/merge/ci-classification.md +0 -16
- package/dist/prompts/templates/merge/conflict.md +0 -10
- package/dist/prompts/templates/merge/edit.md +0 -15
- package/dist/prompts/templates/review/ci-classification.md +0 -9
- package/dist/prompts/templates/review/close-reconsideration.md +0 -6
- /package/dist/{types.js → config/index.type.js} +0 -0
- /package/dist/prompts/{templates/triage/acceptance.md → triage/acceptance/task.md} +0 -0
- /package/dist/prompts/{templates/triage/category.md → triage/category/task.md} +0 -0
- /package/dist/prompts/{templates/triage/comment-classification.md → triage/comment-classification/task.md} +0 -0
- /package/dist/prompts/{templates/triage/create.md → triage/create/task.md} +0 -0
- /package/dist/prompts/{templates/triage/duplicate.md → triage/deplicate/task.md} +0 -0
- /package/dist/prompts/{templates/triage/existing-pr.md → triage/existing/task.md} +0 -0
- /package/dist/prompts/{templates/triage/reconsider.md → triage/reconsider/task.md} +0 -0
- /package/dist/prompts/{templates/triage/signal.md → triage/signal/task.md} +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { isObject } from "./assertion";
|
|
2
|
+
export function merge(base, override) {
|
|
3
|
+
const merged = { ...base };
|
|
4
|
+
for (const [key, value] of Object.entries(override)) {
|
|
5
|
+
const existing = merged[key];
|
|
6
|
+
merged[key] =
|
|
7
|
+
isObject(existing) && isObject(value) ? merge(existing, value) : value;
|
|
8
|
+
}
|
|
9
|
+
return merged;
|
|
10
|
+
}
|
|
11
|
+
export function filterObject(obj, func) {
|
|
12
|
+
const result = {};
|
|
13
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
14
|
+
if (func(key, value, obj))
|
|
15
|
+
result[key] = value;
|
|
16
|
+
});
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
export function omitNullish(obj) {
|
|
20
|
+
return filterObject(obj, (_, val) => val != null);
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isArray } from "./assertion";
|
|
2
|
+
import { createExec } from "./exec";
|
|
3
|
+
export async function getModels(input) {
|
|
4
|
+
const providers = await input.client.config
|
|
5
|
+
.providers({ directory: input.directory })
|
|
6
|
+
.catch(() => input.client.provider.list({ directory: input.directory }));
|
|
7
|
+
const data = "data" in providers ? providers.data : undefined;
|
|
8
|
+
const all = data && "providers" in data ? data.providers : data?.all;
|
|
9
|
+
const models = isArray(all)
|
|
10
|
+
? all.flatMap((provider) => {
|
|
11
|
+
const models = Object.keys(provider.models);
|
|
12
|
+
return provider.id ? models.map((id) => `${provider.id}/${id}`) : models;
|
|
13
|
+
})
|
|
14
|
+
: [];
|
|
15
|
+
if (models.length)
|
|
16
|
+
return models;
|
|
17
|
+
else
|
|
18
|
+
try {
|
|
19
|
+
const output = await createExec(input.directory)("opencode models");
|
|
20
|
+
return output.split("\n").filter((model) => model.includes("/"));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { filterEmpty } from "./array";
|
|
2
|
+
export function quote(value) {
|
|
3
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
4
|
+
}
|
|
5
|
+
export function split(value) {
|
|
6
|
+
return filterEmpty(value.split(/[\s,]+/));
|
|
7
|
+
}
|
|
8
|
+
export function toTitleCase(value) {
|
|
9
|
+
return value
|
|
10
|
+
.replace(/([A-Z])/g, " $1")
|
|
11
|
+
.replace(/[_-](.)/g, (_, val) => ` ${val.toUpperCase()}`)
|
|
12
|
+
.replace(/^./, (str) => str.toUpperCase())
|
|
13
|
+
.trim();
|
|
14
|
+
}
|
|
15
|
+
export function command(...values) {
|
|
16
|
+
return filterEmpty(values).join(" ");
|
|
17
|
+
}
|
|
18
|
+
export const marker = {
|
|
19
|
+
parse(body) {
|
|
20
|
+
const matchAll = body.matchAll(/<!--\s*opencode-magi\s+([^>]*)-->/g);
|
|
21
|
+
return [...matchAll].map((match) => Object.fromEntries(match[1]
|
|
22
|
+
?.trim()
|
|
23
|
+
.split(/\s+/)
|
|
24
|
+
.flatMap((part) => {
|
|
25
|
+
const [key, ...rest] = part.split("=");
|
|
26
|
+
if (!key || !rest.length)
|
|
27
|
+
return [];
|
|
28
|
+
return [[key, rest.join("=")]];
|
|
29
|
+
}) ?? []));
|
|
30
|
+
},
|
|
31
|
+
stringify(...values) {
|
|
32
|
+
return values
|
|
33
|
+
.map((value) => `<!-- opencode-magi ${Object.entries(value)
|
|
34
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
35
|
+
.join(" ")} -->`)
|
|
36
|
+
.join("\n");
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class Worker {
|
|
2
|
+
active = 0;
|
|
3
|
+
tasks = [];
|
|
4
|
+
limit;
|
|
5
|
+
constructor(limit) {
|
|
6
|
+
this.limit = Math.max(1, Math.floor(limit));
|
|
7
|
+
}
|
|
8
|
+
async run(run) {
|
|
9
|
+
const task = new Promise((resolve, reject) => {
|
|
10
|
+
this.tasks.push({ reject, resolve, run });
|
|
11
|
+
});
|
|
12
|
+
this.drain();
|
|
13
|
+
return task;
|
|
14
|
+
}
|
|
15
|
+
drain() {
|
|
16
|
+
while (this.active < this.limit) {
|
|
17
|
+
const task = this.tasks.shift();
|
|
18
|
+
if (!task)
|
|
19
|
+
return;
|
|
20
|
+
this.active += 1;
|
|
21
|
+
void task
|
|
22
|
+
.run()
|
|
23
|
+
.then(task.resolve, task.reject)
|
|
24
|
+
.finally(() => {
|
|
25
|
+
this.active -= 1;
|
|
26
|
+
this.drain();
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-magi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
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>",
|
|
@@ -28,42 +28,55 @@
|
|
|
28
28
|
"schema.json"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@opencode-ai/plugin": "^1.
|
|
31
|
+
"@opencode-ai/plugin": "^1.18.4",
|
|
32
|
+
"@opencode-ai/sdk": "^1.18.4",
|
|
32
33
|
"ajv": "^8.20.0",
|
|
33
|
-
"
|
|
34
|
-
"
|
|
34
|
+
"graphql": "^17.0.2",
|
|
35
|
+
"graphql-tag": "^2.12.7",
|
|
36
|
+
"octokit": "^5.0.5",
|
|
37
|
+
"picomatch": "^4.0.5",
|
|
38
|
+
"valibot": "^1.4.2"
|
|
35
39
|
},
|
|
36
40
|
"devDependencies": {
|
|
37
41
|
"@changesets/changelog-github": "^0.7.0",
|
|
38
|
-
"@changesets/cli": "^2.
|
|
39
|
-
"@commitlint/cli": "^21.
|
|
40
|
-
"@commitlint/config-conventional": "^21.0
|
|
41
|
-
"@
|
|
42
|
+
"@changesets/cli": "^2.31.1",
|
|
43
|
+
"@commitlint/cli": "^21.2.1",
|
|
44
|
+
"@commitlint/config-conventional": "^21.2.0",
|
|
45
|
+
"@graphql-codegen/cli": "^7.2.0",
|
|
46
|
+
"@graphql-codegen/typescript-generic-sdk": "^5.0.1",
|
|
47
|
+
"@graphql-codegen/typescript-operations": "^6.1.1",
|
|
48
|
+
"@limegrass/eslint-plugin-import-alias": "^1.6.1",
|
|
49
|
+
"@octokit/graphql-schema": "^15.26.1",
|
|
50
|
+
"@octokit/plugin-throttling": "^11.0.3",
|
|
51
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
52
|
+
"@types/node": "^26.1.1",
|
|
42
53
|
"@types/picomatch": "^4.0.3",
|
|
43
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
44
|
-
"@vitest/coverage-v8": "^4.1.
|
|
45
|
-
"@vitest/ui": "^4.1.
|
|
46
|
-
"eslint-plugin-perfectionist": "^5.
|
|
54
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
55
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
56
|
+
"@vitest/ui": "^4.1.10",
|
|
57
|
+
"eslint-plugin-perfectionist": "^5.10.0",
|
|
47
58
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
48
|
-
"lefthook": "^2.1.
|
|
49
|
-
"oxfmt": "^0.
|
|
50
|
-
"oxlint": "^1.
|
|
51
|
-
"oxlint-tsgolint": "^0.
|
|
59
|
+
"lefthook": "^2.1.10",
|
|
60
|
+
"oxfmt": "^0.60.0",
|
|
61
|
+
"oxlint": "^1.75.0",
|
|
62
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
52
63
|
"rimraf": "^6.1.3",
|
|
53
|
-
"vitest": "^4.1.
|
|
64
|
+
"vitest": "^4.1.10"
|
|
54
65
|
},
|
|
55
66
|
"scripts": {
|
|
56
|
-
"prebuild": "node scripts/copy-data.ts",
|
|
57
|
-
"build": "tsgo -p tsconfig.build.json",
|
|
58
67
|
"clean": "rimraf node_modules dist coverage",
|
|
68
|
+
"postbuild": "node scripts/copy-data.ts",
|
|
69
|
+
"build": "tsgo -p tsconfig.build.json",
|
|
70
|
+
"graphql:codegen": "graphql-codegen --config codegen.json",
|
|
59
71
|
"format:check": "oxfmt --check .",
|
|
60
72
|
"format:write": "oxfmt --write .",
|
|
61
73
|
"lint:check": "oxlint . --max-warnings=0",
|
|
62
74
|
"lint:fix": "oxlint . --max-warnings=0 --fix",
|
|
63
|
-
"
|
|
64
|
-
"test": "vitest run",
|
|
65
|
-
"test:
|
|
66
|
-
"
|
|
75
|
+
"type:check": "tsgo --noEmit",
|
|
76
|
+
"test": "vitest run --passWithNoTests",
|
|
77
|
+
"test:coverage": "vitest run --coverage --coverage.reporter=html && open coverage/index.html",
|
|
78
|
+
"test:dev": "vitest --watch --ui --passWithNoTests",
|
|
79
|
+
"quality": "pnpm format:check && pnpm lint:check && pnpm type:check && pnpm test",
|
|
67
80
|
"release": "changeset publish",
|
|
68
81
|
"release:dev": "changeset version --snapshot dev && changeset publish --tag dev"
|
|
69
82
|
}
|
package/schema.json
CHANGED
|
@@ -33,14 +33,15 @@
|
|
|
33
33
|
"additionalProperties": false,
|
|
34
34
|
"properties": {
|
|
35
35
|
"host": { "type": "string", "default": "github.com" },
|
|
36
|
-
"
|
|
36
|
+
"retryApiAttempts": {
|
|
37
37
|
"type": "integer",
|
|
38
38
|
"minimum": 0,
|
|
39
39
|
"default": 3,
|
|
40
40
|
"description": "Number of retry attempts for GitHub CLI API calls that fail with rate limit errors."
|
|
41
41
|
},
|
|
42
42
|
"owner": { "type": "string", "minLength": 1 },
|
|
43
|
-
"repo": { "type": "string", "minLength": 1 }
|
|
43
|
+
"repo": { "type": "string", "minLength": 1 },
|
|
44
|
+
"url": { "type": "string" }
|
|
44
45
|
}
|
|
45
46
|
},
|
|
46
47
|
"language": { "type": "string" },
|
|
@@ -170,24 +171,128 @@
|
|
|
170
171
|
"additionalProperties": false,
|
|
171
172
|
"properties": {
|
|
172
173
|
"id": { "type": "string", "minLength": 1 },
|
|
173
|
-
"
|
|
174
|
+
"variant": { "type": "string" }
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"safetyFilter": {
|
|
178
|
+
"type": "object",
|
|
179
|
+
"additionalProperties": false,
|
|
180
|
+
"minProperties": 1,
|
|
181
|
+
"properties": {
|
|
182
|
+
"exclude": { "type": "array", "items": { "type": "string" } },
|
|
183
|
+
"include": { "type": "array", "items": { "type": "string" } }
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"safetyBranchFilter": {
|
|
187
|
+
"type": "object",
|
|
188
|
+
"additionalProperties": false,
|
|
189
|
+
"minProperties": 1,
|
|
190
|
+
"properties": {
|
|
191
|
+
"base": { "$ref": "#/$defs/safetyFilter" },
|
|
192
|
+
"head": { "$ref": "#/$defs/safetyFilter" }
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"safety": {
|
|
196
|
+
"type": "object",
|
|
197
|
+
"additionalProperties": false,
|
|
198
|
+
"properties": {
|
|
199
|
+
"authors": { "$ref": "#/$defs/safetyFilter" },
|
|
200
|
+
"branches": { "$ref": "#/$defs/safetyBranchFilter" },
|
|
201
|
+
"labels": { "$ref": "#/$defs/safetyFilter" },
|
|
202
|
+
"maxChangedFiles": { "type": "integer", "minimum": 0 },
|
|
203
|
+
"paths": { "$ref": "#/$defs/safetyFilter" }
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"conditions": {
|
|
207
|
+
"oneOf": [
|
|
208
|
+
{ "type": "boolean" },
|
|
209
|
+
{
|
|
210
|
+
"type": "array",
|
|
211
|
+
"items": {
|
|
212
|
+
"type": "array",
|
|
213
|
+
"minItems": 2,
|
|
214
|
+
"maxItems": 2,
|
|
215
|
+
"prefixItems": [{ "type": "boolean" }, { "$ref": "#/$defs/safety" }]
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
"automationSafety": {
|
|
221
|
+
"type": "object",
|
|
222
|
+
"additionalProperties": false,
|
|
223
|
+
"properties": {
|
|
224
|
+
"authors": { "$ref": "#/$defs/safetyFilter" },
|
|
225
|
+
"branches": { "$ref": "#/$defs/safetyBranchFilter" },
|
|
226
|
+
"labels": { "$ref": "#/$defs/safetyFilter" },
|
|
227
|
+
"paths": { "$ref": "#/$defs/safetyFilter" }
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
"automationConditions": {
|
|
231
|
+
"oneOf": [
|
|
232
|
+
{ "type": "boolean" },
|
|
233
|
+
{
|
|
234
|
+
"type": "array",
|
|
235
|
+
"items": {
|
|
236
|
+
"type": "array",
|
|
237
|
+
"minItems": 2,
|
|
238
|
+
"maxItems": 2,
|
|
239
|
+
"prefixItems": [
|
|
240
|
+
{ "type": "boolean" },
|
|
241
|
+
{ "$ref": "#/$defs/automationSafety" }
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
},
|
|
247
|
+
"mergeAutomationConditions": {
|
|
248
|
+
"oneOf": [
|
|
249
|
+
{ "type": "boolean" },
|
|
250
|
+
{
|
|
251
|
+
"type": "array",
|
|
252
|
+
"items": {
|
|
253
|
+
"type": "array",
|
|
254
|
+
"minItems": 2,
|
|
255
|
+
"maxItems": 2,
|
|
256
|
+
"prefixItems": [
|
|
257
|
+
{ "type": "boolean" },
|
|
258
|
+
{ "$ref": "#/$defs/mergeAutomationSafety" }
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
"mergeAutomationSafety": {
|
|
265
|
+
"type": "object",
|
|
266
|
+
"additionalProperties": false,
|
|
267
|
+
"properties": {
|
|
268
|
+
"authors": { "$ref": "#/$defs/safetyFilter" },
|
|
269
|
+
"branches": { "$ref": "#/$defs/safetyBranchFilter" },
|
|
270
|
+
"edited": { "type": "boolean" },
|
|
271
|
+
"labels": { "$ref": "#/$defs/safetyFilter" },
|
|
272
|
+
"paths": { "$ref": "#/$defs/safetyFilter" }
|
|
174
273
|
}
|
|
175
274
|
},
|
|
176
275
|
"automation": {
|
|
177
276
|
"type": "object",
|
|
178
277
|
"additionalProperties": false,
|
|
179
278
|
"properties": {
|
|
180
|
-
"merge": { "
|
|
181
|
-
"close": { "
|
|
279
|
+
"merge": { "$ref": "#/$defs/automationConditions", "default": true },
|
|
280
|
+
"close": { "$ref": "#/$defs/automationConditions", "default": false }
|
|
182
281
|
}
|
|
183
282
|
},
|
|
184
283
|
"mergeAutomation": {
|
|
185
284
|
"type": "object",
|
|
186
285
|
"additionalProperties": false,
|
|
187
286
|
"properties": {
|
|
188
|
-
"merge": {
|
|
189
|
-
|
|
190
|
-
|
|
287
|
+
"merge": {
|
|
288
|
+
"$ref": "#/$defs/mergeAutomationConditions",
|
|
289
|
+
"default": true
|
|
290
|
+
},
|
|
291
|
+
"close": {
|
|
292
|
+
"$ref": "#/$defs/mergeAutomationConditions",
|
|
293
|
+
"default": false
|
|
294
|
+
},
|
|
295
|
+
"conflict": { "$ref": "#/$defs/automationConditions", "default": false }
|
|
191
296
|
}
|
|
192
297
|
},
|
|
193
298
|
"reviewChecks": {
|
|
@@ -221,16 +326,6 @@
|
|
|
221
326
|
"runs": { "type": "integer", "minimum": 1, "default": 3 }
|
|
222
327
|
}
|
|
223
328
|
},
|
|
224
|
-
"safety": {
|
|
225
|
-
"type": "object",
|
|
226
|
-
"additionalProperties": false,
|
|
227
|
-
"properties": {
|
|
228
|
-
"allowAuthors": { "type": "array", "items": { "type": "string" } },
|
|
229
|
-
"blockedPaths": { "type": "array", "items": { "type": "string" } },
|
|
230
|
-
"maxChangedFiles": { "type": "integer", "minimum": 0 },
|
|
231
|
-
"requiredLabels": { "type": "array", "items": { "type": "string" } }
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
329
|
"reviewPrompts": {
|
|
235
330
|
"type": "object",
|
|
236
331
|
"additionalProperties": false,
|
|
@@ -375,10 +470,11 @@
|
|
|
375
470
|
},
|
|
376
471
|
"prompts": { "$ref": "#/$defs/reviewPrompts" },
|
|
377
472
|
"checks": { "$ref": "#/$defs/reviewChecks" },
|
|
378
|
-
"safety": { "$ref": "#/$defs/
|
|
473
|
+
"safety": { "$ref": "#/$defs/conditions" },
|
|
379
474
|
"automation": { "$ref": "#/$defs/automation" },
|
|
380
475
|
"concurrency": { "$ref": "#/$defs/concurrency" },
|
|
381
476
|
"merge": { "$ref": "#/$defs/reviewMerge" },
|
|
477
|
+
"operator": { "type": "string", "minLength": 1 },
|
|
382
478
|
"output": { "type": "string" },
|
|
383
479
|
"worktree": { "type": "string" }
|
|
384
480
|
}
|
|
@@ -421,7 +517,7 @@
|
|
|
421
517
|
"safety": { "$ref": "#/$defs/triageSafety" },
|
|
422
518
|
"concurrency": { "$ref": "#/$defs/triageConcurrency" },
|
|
423
519
|
"prompts": { "$ref": "#/$defs/triagePrompts" },
|
|
424
|
-
"
|
|
520
|
+
"operator": { "type": "string", "minLength": 1 },
|
|
425
521
|
"output": { "type": "string" },
|
|
426
522
|
"worktree": { "type": "string" }
|
|
427
523
|
}
|
package/dist/config/load.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { isAbsolute, join } from "node:path";
|
|
4
|
-
const GLOBAL_CONFIG = join(homedir(), ".config", "opencode", "magi.json");
|
|
5
|
-
const PROJECT_CONFIG = join(".opencode", "magi.json");
|
|
6
|
-
function isPlainObject(value) {
|
|
7
|
-
return (!!value &&
|
|
8
|
-
typeof value === "object" &&
|
|
9
|
-
!Array.isArray(value) &&
|
|
10
|
-
Object.getPrototypeOf(value) === Object.prototype);
|
|
11
|
-
}
|
|
12
|
-
export function mergeMagiConfig(base, override) {
|
|
13
|
-
const merged = { ...base };
|
|
14
|
-
for (const [key, value] of Object.entries(override)) {
|
|
15
|
-
const existing = merged[key];
|
|
16
|
-
merged[key] =
|
|
17
|
-
isPlainObject(existing) && isPlainObject(value)
|
|
18
|
-
? mergeMagiConfig(existing, value)
|
|
19
|
-
: value;
|
|
20
|
-
}
|
|
21
|
-
return merged;
|
|
22
|
-
}
|
|
23
|
-
async function readConfig(path) {
|
|
24
|
-
try {
|
|
25
|
-
return JSON.parse(await readFile(path, "utf8"));
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
const code = error.code;
|
|
29
|
-
if (code === "ENOENT")
|
|
30
|
-
return null;
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
export async function loadConfig(directory, configPath) {
|
|
35
|
-
if (configPath) {
|
|
36
|
-
const path = isAbsolute(configPath)
|
|
37
|
-
? configPath
|
|
38
|
-
: join(directory, configPath);
|
|
39
|
-
const config = await readConfig(path);
|
|
40
|
-
if (!config)
|
|
41
|
-
throw new Error(`Magi config not found: ${path}`);
|
|
42
|
-
return { config: config, path };
|
|
43
|
-
}
|
|
44
|
-
const projectPath = join(directory, PROJECT_CONFIG);
|
|
45
|
-
const configs = await Promise.all([
|
|
46
|
-
readConfig(GLOBAL_CONFIG),
|
|
47
|
-
readConfig(projectPath),
|
|
48
|
-
]);
|
|
49
|
-
const loaded = configs
|
|
50
|
-
.map((config, index) => ({
|
|
51
|
-
config,
|
|
52
|
-
path: index === 0 ? GLOBAL_CONFIG : projectPath,
|
|
53
|
-
}))
|
|
54
|
-
.filter((item) => Boolean(item.config));
|
|
55
|
-
if (!loaded.length)
|
|
56
|
-
throw new Error(`Magi config not found. Tried: ${GLOBAL_CONFIG}, ${projectPath}`);
|
|
57
|
-
const config = loaded.reduce((merged, item) => mergeMagiConfig(merged, item.config), {});
|
|
58
|
-
return {
|
|
59
|
-
config: config,
|
|
60
|
-
path: loaded.map((item) => item.path).join(", "),
|
|
61
|
-
};
|
|
62
|
-
}
|
package/dist/config/output.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { isAbsolute, join } from "node:path";
|
|
2
|
-
const DEFAULT_OUTPUT_DIRS = {
|
|
3
|
-
issue: ".magi/runs/issue",
|
|
4
|
-
pr: ".magi/runs/pr",
|
|
5
|
-
};
|
|
6
|
-
function resolvePath(directory, path) {
|
|
7
|
-
return isAbsolute(path) ? path : join(directory, path);
|
|
8
|
-
}
|
|
9
|
-
export function outputBaseDir(directory, config, kind) {
|
|
10
|
-
return resolvePath(directory, kind === "issue"
|
|
11
|
-
? (config.triage?.output ?? DEFAULT_OUTPUT_DIRS[kind])
|
|
12
|
-
: (config.review?.output ?? DEFAULT_OUTPUT_DIRS[kind]));
|
|
13
|
-
}
|
|
14
|
-
export function outputBaseDirs(directory, config) {
|
|
15
|
-
return [
|
|
16
|
-
outputBaseDir(directory, config, "pr"),
|
|
17
|
-
outputBaseDir(directory, config, "issue"),
|
|
18
|
-
];
|
|
19
|
-
}
|
|
20
|
-
export function prRunOutputDir(input) {
|
|
21
|
-
return join(outputBaseDir(input.directory, input.config, "pr"), String(input.pr), ...(input.runId ? [input.runId] : []));
|
|
22
|
-
}
|
|
23
|
-
export function issueRunOutputDir(input) {
|
|
24
|
-
return join(outputBaseDir(input.directory, input.config, "issue"), String(input.issue), ...(input.runId ? [input.runId] : []));
|
|
25
|
-
}
|
package/dist/config/worktree.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { isAbsolute, join } from "node:path";
|
|
2
|
-
const DEFAULT_WORKTREE_DIRS = {
|
|
3
|
-
issue: ".magi/worktrees/issue",
|
|
4
|
-
pr: ".magi/worktrees/pr",
|
|
5
|
-
};
|
|
6
|
-
function resolvePath(directory, path) {
|
|
7
|
-
return isAbsolute(path) ? path : join(directory, path);
|
|
8
|
-
}
|
|
9
|
-
export function worktreeBaseDir(directory, config, kind) {
|
|
10
|
-
return resolvePath(directory, kind === "issue"
|
|
11
|
-
? (config.triage?.worktree ?? DEFAULT_WORKTREE_DIRS[kind])
|
|
12
|
-
: (config.review?.worktree ?? DEFAULT_WORKTREE_DIRS[kind]));
|
|
13
|
-
}
|
|
14
|
-
export function worktreeBaseDirs(directory, config = {}) {
|
|
15
|
-
return [
|
|
16
|
-
worktreeBaseDir(directory, config, "pr"),
|
|
17
|
-
worktreeBaseDir(directory, config, "issue"),
|
|
18
|
-
];
|
|
19
|
-
}
|
|
20
|
-
export function prRunWorktreeDir(input) {
|
|
21
|
-
return join(worktreeBaseDir(input.directory, input.config, "pr"), String(input.pr), input.runId);
|
|
22
|
-
}
|
|
23
|
-
export function issueRunWorktreeDir(input) {
|
|
24
|
-
return join(worktreeBaseDir(input.directory, input.config, "issue"), String(input.issue), input.runId);
|
|
25
|
-
}
|