opencode-magi 0.0.0-dev-20260630082136 → 0.0.0-dev-20260630082946
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/magi.js
CHANGED
|
@@ -6,7 +6,7 @@ import { dirname, isAbsolute, join, relative } from "node:path";
|
|
|
6
6
|
import { Octokit } from "octokit";
|
|
7
7
|
import { getConfig, resolvePermissions, validateConfig } from "@/config";
|
|
8
8
|
import { graphql } from "@/graphql";
|
|
9
|
-
import { command, createExec, filterEmpty, isArray, isObject, merge, quote, } from "@/utils";
|
|
9
|
+
import { command, createExec, filterEmpty, isArray, isNumber, isObject, merge, quote, } from "@/utils";
|
|
10
10
|
const active = new Set(["preparing", "running"]);
|
|
11
11
|
const backgrounds = new Map();
|
|
12
12
|
export class MagiError extends Error {
|
|
@@ -195,6 +195,16 @@ export class Magi {
|
|
|
195
195
|
await mkdir(state.output, { recursive: true });
|
|
196
196
|
await writeFile(join(state.output, "state.json"), `${JSON.stringify(state, null, 2)}\n`);
|
|
197
197
|
}
|
|
198
|
+
async createAgentFile(output, phase, id, content, attempt = 1, cycle) {
|
|
199
|
+
const segments = [output, "agents", phase, id];
|
|
200
|
+
if (isNumber(cycle))
|
|
201
|
+
segments.push(cycle.toString());
|
|
202
|
+
if (isNumber(attempt))
|
|
203
|
+
segments.push(attempt.toString());
|
|
204
|
+
const path = segments.join("/") + ".md";
|
|
205
|
+
await mkdir(dirname(path), { recursive: true });
|
|
206
|
+
await writeFile(path, content);
|
|
207
|
+
}
|
|
198
208
|
async updateState(dir, next) {
|
|
199
209
|
next.updatedAt = new Date().toISOString();
|
|
200
210
|
const prev = await this.getState(dir);
|
|
@@ -14,6 +14,7 @@ export async function edit() {
|
|
|
14
14
|
: unresolvedThreads;
|
|
15
15
|
if (!threads.length)
|
|
16
16
|
throw new MagiError("blocked", "No editable review threads found.");
|
|
17
|
+
const cycle = (this.state.editor.outputs?.length ?? 0) + 1;
|
|
17
18
|
const prompt = await Prompt.init(this.magi, this.config, "merge/edit");
|
|
18
19
|
const taskMessage = await prompt.create(this.config.merge.prompts?.edit, [
|
|
19
20
|
"output_contract",
|
|
@@ -27,6 +28,7 @@ export async function edit() {
|
|
|
27
28
|
const repairMessage = await prompt.repair();
|
|
28
29
|
const output = await retry(async (count) => {
|
|
29
30
|
const raw = await this.magi.promptSession(this.state.editor.sessionId, count === 1 ? taskMessage : repairMessage);
|
|
31
|
+
await this.createAgentFile("edit", "editor", raw, count, cycle);
|
|
30
32
|
const parsed = prompt.parse(raw);
|
|
31
33
|
if (!prompt.validate(parsed))
|
|
32
34
|
throw new Error("Invalid output for editor.");
|
|
@@ -105,6 +107,7 @@ export async function resolveConflict() {
|
|
|
105
107
|
const conflictedFiles = await getConflictedFiles.call(this);
|
|
106
108
|
if (!conflictedFiles.length)
|
|
107
109
|
throw new MagiError("blocked", "No merge conflicts found in worktree.");
|
|
110
|
+
const cycle = (this.state.editor.outputs?.length ?? 0) + 1;
|
|
108
111
|
const prompt = await Prompt.init(this.magi, this.config, "merge/conflict");
|
|
109
112
|
const taskMessage = await prompt.create(undefined, [
|
|
110
113
|
"output_contract",
|
|
@@ -118,6 +121,7 @@ export async function resolveConflict() {
|
|
|
118
121
|
const repairMessage = await prompt.repair();
|
|
119
122
|
const output = await retry(async (count) => {
|
|
120
123
|
const raw = await this.magi.promptSession(this.state.editor.sessionId, count === 1 ? taskMessage : repairMessage);
|
|
124
|
+
await this.createAgentFile("conflict", "editor", raw, count, cycle);
|
|
121
125
|
const parsed = prompt.parse(raw);
|
|
122
126
|
if (!prompt.validate(parsed))
|
|
123
127
|
throw new Error("Invalid output for conflict editor.");
|
|
@@ -83,6 +83,7 @@ export async function postReviews() {
|
|
|
83
83
|
const repairMessage = await prompt.repair();
|
|
84
84
|
const output = await retry(async (count) => {
|
|
85
85
|
const raw = await this.magi.promptSession(this.state.operator.sessionId, count === 1 ? taskMessage : repairMessage);
|
|
86
|
+
await this.createAgentFile("comment", "operator", raw, count);
|
|
86
87
|
const parsed = prompt.parse(raw);
|
|
87
88
|
if (!prompt.validate(parsed))
|
|
88
89
|
throw new Error("Invalid output for operator.");
|
|
@@ -118,6 +118,7 @@ export async function classifyChecks() {
|
|
|
118
118
|
await this.notify(`Classifying CI checks for ${this.getLink()} with reviewer ${id}.`);
|
|
119
119
|
const output = await retry(async (count) => {
|
|
120
120
|
const raw = await this.magi.promptSession(sessionId, count === 1 ? taskMessage : repairMessage);
|
|
121
|
+
await this.createAgentFile("ci-classification", id, raw, count);
|
|
121
122
|
const parsed = prompt.parse(raw);
|
|
122
123
|
if (!prompt.validate(parsed))
|
|
123
124
|
throw new Error(`Invalid output for reviewer ${id}.`);
|
|
@@ -246,7 +247,10 @@ export async function getMetadata() {
|
|
|
246
247
|
repo: this.config.github.repo,
|
|
247
248
|
}),
|
|
248
249
|
]);
|
|
249
|
-
return {
|
|
250
|
+
return {
|
|
251
|
+
files: files.map(({ filename }) => filename),
|
|
252
|
+
metadata: data,
|
|
253
|
+
};
|
|
250
254
|
}
|
|
251
255
|
async function getChecks() {
|
|
252
256
|
const fields = "name,state,bucket,link,workflow";
|
|
@@ -76,6 +76,9 @@ export class Review {
|
|
|
76
76
|
getLink() {
|
|
77
77
|
return `[#${this.state.pr.number}](${this.state.pr.url})`;
|
|
78
78
|
}
|
|
79
|
+
async createAgentFile(phase, id, content, attempt, cycle) {
|
|
80
|
+
await this.magi.createAgentFile(this.state.output, phase, id, content, attempt, cycle);
|
|
81
|
+
}
|
|
79
82
|
async createSessions() {
|
|
80
83
|
this.context.abort.throwIfAborted();
|
|
81
84
|
if (!this.state.reviewers)
|
|
@@ -32,6 +32,7 @@ export async function review() {
|
|
|
32
32
|
throw new MagiError("blocked", `Missing previous review commit for reviewer ${id}.`);
|
|
33
33
|
const rereview = status !== "initial";
|
|
34
34
|
const label = rereview ? "rereview" : "review";
|
|
35
|
+
const cycle = (outputs?.length ?? 0) + 1;
|
|
35
36
|
await this.notify(`Running ${label} for ${this.getLink()} with reviewer ${id}.`);
|
|
36
37
|
const sha = rereview
|
|
37
38
|
? (review?.commit_id ?? this.state.pr.metadata.base.sha)
|
|
@@ -98,6 +99,7 @@ export async function review() {
|
|
|
98
99
|
const repairMessage = await prompt.repair();
|
|
99
100
|
const output = await retry(async (count) => {
|
|
100
101
|
const raw = await this.magi.promptSession(sessionId, count === 1 ? taskMessage : repairMessage);
|
|
102
|
+
await this.createAgentFile(rereview ? "rereview" : "review", id, raw, count, cycle);
|
|
101
103
|
const parsed = prompt.parse(raw);
|
|
102
104
|
if (!prompt.validate(parsed))
|
|
103
105
|
throw new Error(`Invalid output for reviewer ${id}.`);
|
|
@@ -174,6 +176,7 @@ export async function reconsiderClose() {
|
|
|
174
176
|
throw new MagiError("blocked", `No session ID found for reviewer ${id}.`);
|
|
175
177
|
if (status === "rereview" && !review?.commit_id)
|
|
176
178
|
throw new MagiError("blocked", `Missing previous review commit for reviewer ${id}.`);
|
|
179
|
+
const cycle = (outputs?.length ?? 0) + 1;
|
|
177
180
|
const sha = status === "initial"
|
|
178
181
|
? this.state.pr.metadata.base.sha
|
|
179
182
|
: (review?.commit_id ?? this.state.pr.metadata.base.sha);
|
|
@@ -187,6 +190,7 @@ export async function reconsiderClose() {
|
|
|
187
190
|
await this.notify(`Reconsidering close verdict for ${this.getLink()} with reviewer ${id}.`);
|
|
188
191
|
const output = await retry(async (count) => {
|
|
189
192
|
const raw = await this.magi.promptSession(sessionId, count === 1 ? taskMessage : repairMessage);
|
|
193
|
+
await this.createAgentFile("close-reconsideration", id, raw, count, cycle);
|
|
190
194
|
const parsed = prompt.parse(raw);
|
|
191
195
|
if (!prompt.validate(parsed))
|
|
192
196
|
throw new Error(`Invalid close reconsideration output for reviewer ${id}.`);
|
|
@@ -254,6 +258,7 @@ async function collectAcceptedFindings(findings) {
|
|
|
254
258
|
const repairMessage = await prompt.repair();
|
|
255
259
|
const output = await retry(async (count) => {
|
|
256
260
|
const raw = await this.magi.promptSession(sessionId, count === 1 ? taskMessage : repairMessage);
|
|
261
|
+
await this.createAgentFile("finding-validation", id, raw, count);
|
|
257
262
|
const parsed = prompt.parse(raw);
|
|
258
263
|
if (!prompt.validate(parsed))
|
|
259
264
|
throw new Error(`Invalid finding validation output for reviewer ${id}.`);
|
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-20260630082946",
|
|
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>",
|