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 { files: files.map(({ filename }) => filename), metadata: data };
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-20260630082136",
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>",