opencode-magi 0.0.0-dev-20260522141924 → 0.0.0-dev-20260522142016

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.
@@ -17,3 +17,9 @@ export function worktreeBaseDirs(directory, config = {}) {
17
17
  worktreeBaseDir(directory, config, "issue"),
18
18
  ];
19
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
+ }
@@ -446,9 +446,8 @@ export async function fetchMergeQueueRequirement(exec, repository, branch) {
446
446
  const rules = JSON.parse(raw);
447
447
  return rules.some((rule) => rule.type === "merge_queue");
448
448
  }
449
- export async function createWorktree(exec, repository, pr, root) {
450
- const worktreePath = join(root, `pr-${pr}`);
451
- const lockKey = `${repoSpecifier(repository)}:${root}`;
449
+ export async function createWorktree(exec, repository, pr, worktreePath) {
450
+ const lockKey = `${repoSpecifier(repository)}:${dirname(dirname(worktreePath))}`;
452
451
  return withWorktreeCreateLock(lockKey, async () => {
453
452
  let worktreeAdded = false;
454
453
  try {
@@ -3,7 +3,7 @@ import { join } from "node:path";
3
3
  import { createWorktree, fetchPullRequest, fetchPullRequestCommits, fetchPullRequestReviews, fetchUnresolvedThreads, closePullRequest, mergePullRequest, postApproval, postChangesRequested, postCloseComment, postReply, removeWorktree, resolveThread, shellQuote, } from "../github/commands";
4
4
  import { composeFindingValidationPrompt, composeCloseReconsiderationPrompt, composeRereviewPrompt, composeReviewPrompt, } from "../prompts/compose";
5
5
  import { prRunOutputDir } from "../config/output";
6
- import { worktreeBaseDir } from "../config/worktree";
6
+ import { prRunWorktreeDir } from "../config/worktree";
7
7
  import { parseCloseReconsiderationOutput, parseFindingValidationOutput, parseRereviewOutput, parseReviewOutput, } from "../prompts/output";
8
8
  import { throwIfAborted, withAbortSignal } from "./abort";
9
9
  import { waitForChecksWithClassification } from "./ci";
@@ -552,11 +552,13 @@ export async function runReview(input) {
552
552
  : preliminaryMode;
553
553
  if (mode.type === "already_reviewed" && !input.allowAlreadyReviewed)
554
554
  throw new Error("PR has already been reviewed by all configured accounts");
555
- const outputDir = join(prRunOutputDir({
555
+ const runId = input.runId ?? `run-${Date.now().toString(36)}`;
556
+ const outputDir = prRunOutputDir({
556
557
  config: input.config,
557
558
  directory: input.directory,
558
559
  pr: input.pr,
559
- }), ...(input.runId ? [input.runId] : []));
560
+ runId,
561
+ });
560
562
  await mkdir(outputDir, { recursive: true });
561
563
  await input.onProgress?.({ phase: "fetching review context", type: "phase" });
562
564
  const reviewContextSnapshot = await buildReviewContextSnapshot({
@@ -621,10 +623,14 @@ export async function runReview(input) {
621
623
  checkResult.report.scopeInside.length)) {
622
624
  await input.onProgress?.({ report: checkResult.report, type: "ci_report" });
623
625
  }
624
- const worktreeRoot = worktreeBaseDir(input.directory, input.config, "pr");
626
+ const worktreePath = prRunWorktreeDir({
627
+ config: input.config,
628
+ directory: input.directory,
629
+ pr: input.pr,
630
+ runId,
631
+ });
625
632
  await input.onProgress?.({ phase: "creating worktree", type: "phase" });
626
- const worktree = await createWorktree(exec, input.repository, input.pr, worktreeRoot);
627
- const worktreePath = worktree.path;
633
+ const worktree = await createWorktree(exec, input.repository, input.pr, worktreePath);
628
634
  await input.onProgress?.({
629
635
  branch: worktree.branch,
630
636
  type: "worktree_created",
@@ -1463,6 +1463,18 @@ export class MagiRunManager {
1463
1463
  state.worktreePath = progress.worktreePath;
1464
1464
  state.worktreeBranch = progress.branch;
1465
1465
  }
1466
+ if (progress.type === "triage_session") {
1467
+ if (progress.options)
1468
+ this.input.setSessionOptions?.(progress.sessionId, progress.options);
1469
+ state.sessionIds = {
1470
+ ...state.sessionIds,
1471
+ [progress.key]: progress.sessionId,
1472
+ };
1473
+ this.sessionToRun.set(progress.sessionId, {
1474
+ agent: progress.agent,
1475
+ runId,
1476
+ });
1477
+ }
1466
1478
  if (progress.type === "triage_agent_started") {
1467
1479
  const reviewer = state.reviewers[progress.reviewer];
1468
1480
  if (reviewer)
@@ -1,7 +1,7 @@
1
1
  import { mkdir, writeFile } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
  import { issueRunOutputDir } from "../config/output";
4
- import { worktreeBaseDir } from "../config/worktree";
4
+ import { issueRunWorktreeDir } from "../config/worktree";
5
5
  import { assignIssue, closeIssue, closePullRequest, configureGitIdentity, createPullRequest, fetchIssue, fetchIssueComments, fetchRelatedPullRequests, postIssueComment, pushHead, removeIssueLabels, removeWorktree, searchDuplicateIssues, shellQuote, updateIssueComment, } from "../github/commands";
6
6
  import { composeTriageAcceptancePrompt, composeTriageCategoryPrompt, composeTriageCommentClassificationPrompt, composeTriageCreatePrPrompt, composeTriageDuplicatePrompt, composeTriageExistingPrPrompt, composeTriageReconsiderPrompt, } from "../prompts/compose";
7
7
  import { parseTriageBinaryOutput, parseTriageCategoryOutput, parseTriageCommentClassificationOutput, parseTriageCreatePrOutput, parseTriageDuplicateOutput, parseTriageExistingPrOutput, } from "../prompts/output";
@@ -457,9 +457,7 @@ function previousAutomationPlan(input) {
457
457
  };
458
458
  }
459
459
  async function classifyMentionReplies(input) {
460
- const agent = input.input.repository.agents.triage?.[0];
461
- if (!agent)
462
- throw new Error("triage.agents is required");
460
+ const agent = triageReporter(input.input.repository, input.input.issue);
463
461
  const prompt = await composeTriageCommentClassificationPrompt({
464
462
  context: JSON.stringify({ context: input.context, mentionReplies: input.replies }, null, 2),
465
463
  directory: input.input.directory,
@@ -470,6 +468,17 @@ async function classifyMentionReplies(input) {
470
468
  const result = await runModelWithRepair({
471
469
  client: input.input.client,
472
470
  model: agent.model,
471
+ onProgress: async (progress) => {
472
+ if (progress.type !== "session_created")
473
+ return;
474
+ await emitProgress(input.input, {
475
+ agent: agent.key,
476
+ key: `triage:comment-classification:${agent.key}:${progress.sessionId}`,
477
+ options: progress.options,
478
+ sessionId: progress.sessionId,
479
+ type: "triage_session",
480
+ });
481
+ },
473
482
  options: agent.options,
474
483
  parentSessionId: input.input.parentSessionId,
475
484
  parse: parseTriageCommentClassificationOutput,
@@ -478,7 +487,7 @@ async function classifyMentionReplies(input) {
478
487
  repairAttempts: 3,
479
488
  schemaName: "triage comment classification",
480
489
  signal: input.input.signal,
481
- title: `Magi triage comment classification #${input.input.issue}`,
490
+ title: `Magi triage comment classification #${input.input.issue} (${agent.key})`,
482
491
  });
483
492
  await writeJson(join(input.outputDir, "comment-classification.json"), result.value);
484
493
  return result.value;
@@ -698,6 +707,7 @@ async function finishWithResult(input) {
698
707
  input: input.input,
699
708
  issue: input.issue,
700
709
  outputDir: input.outputDir,
710
+ runId: input.runId,
701
711
  });
702
712
  if (prUrl) {
703
713
  await writeJson(join(input.outputDir, "pr.json"), { url: prUrl });
@@ -766,7 +776,12 @@ async function createImplementationPr(input) {
766
776
  try {
767
777
  await assignIssue(input.input.exec, input.input.repository, input.issue.number, creator.account);
768
778
  const branch = `magi/issue-${input.issue.number}-${Date.now().toString(36)}`;
769
- const worktreePath = join(worktreeBaseDir(input.input.directory, input.input.config, "issue"), `issue-${input.issue.number}`);
779
+ const worktreePath = issueRunWorktreeDir({
780
+ config: input.input.config,
781
+ directory: input.input.directory,
782
+ issue: input.issue.number,
783
+ runId: input.runId,
784
+ });
770
785
  await mkdir(dirname(worktreePath), { recursive: true });
771
786
  await input.input.exec(`git worktree add -b ${shellQuote(branch)} ${shellQuote(worktreePath)}`);
772
787
  await emitProgress(input.input, {
@@ -914,6 +929,7 @@ export async function runTriage(input) {
914
929
  processed,
915
930
  relationship,
916
931
  result,
932
+ runId,
917
933
  });
918
934
  }
919
935
  const report = `Magi triage skipped #${issue.number} because no eligible mention replies were found for reconsideration.`;
@@ -1032,6 +1048,7 @@ export async function runTriage(input) {
1032
1048
  processed,
1033
1049
  relationship,
1034
1050
  result: relatedPrDecision,
1051
+ runId,
1035
1052
  });
1036
1053
  }
1037
1054
  return finishWithResult({
@@ -1042,6 +1059,7 @@ export async function runTriage(input) {
1042
1059
  processed,
1043
1060
  relationship,
1044
1061
  result: { category: null, disposition: "clear_only" },
1062
+ runId,
1045
1063
  });
1046
1064
  }
1047
1065
  }
@@ -1139,5 +1157,6 @@ export async function runTriage(input) {
1139
1157
  category: null,
1140
1158
  disposition: "ask",
1141
1159
  },
1160
+ runId,
1142
1161
  });
1143
1162
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-magi",
3
- "version": "0.0.0-dev-20260522141924",
3
+ "version": "0.0.0-dev-20260522142016",
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>",