codex-orchestrator 0.1.41 → 0.1.43
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/CHANGELOG.md +23 -0
- package/dist/src/cli.js +66 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/github/gh-issue-adapter.d.ts +2 -0
- package/dist/src/github/gh-issue-adapter.d.ts.map +1 -1
- package/dist/src/github/gh-issue-adapter.js +7 -1
- package/dist/src/github/gh-issue-adapter.js.map +1 -1
- package/dist/src/github/issues.d.ts +3 -0
- package/dist/src/github/issues.d.ts.map +1 -1
- package/dist/src/github/issues.js +7 -1
- package/dist/src/github/issues.js.map +1 -1
- package/dist/src/runner/acceptance-proof-loop.d.ts +122 -0
- package/dist/src/runner/acceptance-proof-loop.d.ts.map +1 -0
- package/dist/src/runner/acceptance-proof-loop.js +426 -0
- package/dist/src/runner/acceptance-proof-loop.js.map +1 -0
- package/dist/src/runner/acceptance-proof-runner.d.ts +3 -20
- package/dist/src/runner/acceptance-proof-runner.d.ts.map +1 -1
- package/dist/src/runner/acceptance-proof-runner.js +28 -104
- package/dist/src/runner/acceptance-proof-runner.js.map +1 -1
- package/dist/src/runner/acceptance-proof.d.ts +8 -0
- package/dist/src/runner/acceptance-proof.d.ts.map +1 -1
- package/dist/src/runner/acceptance-proof.js +116 -40
- package/dist/src/runner/acceptance-proof.js.map +1 -1
- package/dist/src/runner/agent-attempt.d.ts +105 -0
- package/dist/src/runner/agent-attempt.d.ts.map +1 -0
- package/dist/src/runner/agent-attempt.js +235 -0
- package/dist/src/runner/agent-attempt.js.map +1 -0
- package/dist/src/runner/daemon-command.d.ts +1 -1
- package/dist/src/runner/daemon-command.d.ts.map +1 -1
- package/dist/src/runner/daemon-command.js +24 -0
- package/dist/src/runner/daemon-command.js.map +1 -1
- package/dist/src/runner/durable-run-summary.js +10 -1
- package/dist/src/runner/durable-run-summary.js.map +1 -1
- package/dist/src/runner/local-execution-session.d.ts.map +1 -1
- package/dist/src/runner/local-execution-session.js +98 -126
- package/dist/src/runner/local-execution-session.js.map +1 -1
- package/dist/src/runner/plan-auto-command.d.ts.map +1 -1
- package/dist/src/runner/plan-auto-command.js +181 -295
- package/dist/src/runner/plan-auto-command.js.map +1 -1
- package/dist/src/runner/review-gate-policy.d.ts +3 -11
- package/dist/src/runner/review-gate-policy.d.ts.map +1 -1
- package/dist/src/runner/review-gate-policy.js +6 -178
- package/dist/src/runner/review-gate-policy.js.map +1 -1
- package/dist/src/runner/rework-policy.d.ts +1 -1
- package/dist/src/runner/rework-policy.d.ts.map +1 -1
- package/dist/src/runner/rework-policy.js +6 -1
- package/dist/src/runner/rework-policy.js.map +1 -1
- package/dist/src/runner/runner-handoff-decision.d.ts.map +1 -1
- package/dist/src/runner/runner-handoff-decision.js +22 -4
- package/dist/src/runner/runner-handoff-decision.js.map +1 -1
- package/dist/src/runner/scoped-auto-command.d.ts.map +1 -1
- package/dist/src/runner/scoped-auto-command.js +104 -221
- package/dist/src/runner/scoped-auto-command.js.map +1 -1
- package/dist/src/runner/terminal-outcome.d.ts +58 -0
- package/dist/src/runner/terminal-outcome.d.ts.map +1 -0
- package/dist/src/runner/terminal-outcome.js +73 -0
- package/dist/src/runner/terminal-outcome.js.map +1 -0
- package/dist/src/runner/visual-proof-runner.d.ts +2 -0
- package/dist/src/runner/visual-proof-runner.d.ts.map +1 -1
- package/dist/src/runner/visual-proof-runner.js +30 -8
- package/dist/src/runner/visual-proof-runner.js.map +1 -1
- package/docs/deep-dive.md +13 -0
- package/package.json +1 -1
|
@@ -6,7 +6,6 @@ import { resolveBaseBranch } from '../git/base-branch.js';
|
|
|
6
6
|
import { GitMergeConflictError, GitWorktreeManager, renderBranchTemplate } from '../git/worktree.js';
|
|
7
7
|
import { GhCliIssueAdapter } from '../github/gh-issue-adapter.js';
|
|
8
8
|
import { GhCliPullRequestAdapter } from '../github/gh-pull-request-adapter.js';
|
|
9
|
-
import { verifyPullRequestRefs } from '../github/pull-requests.js';
|
|
10
9
|
import { defaultShellCommandExecutor } from '../process/command.js';
|
|
11
10
|
import { formatSessionTimestamp, readRunnerConfig, runConfiguredChecks, } from './command-utils.js';
|
|
12
11
|
import { buildChildBlockedReport, buildChildReviewReport, buildIssueTreePullRequestBody, buildIssueTreeReviewReport, buildParentBlockedReport, } from './handoff-evidence.js';
|
|
@@ -16,16 +15,16 @@ import { writeContextSnapshot } from './context-snapshot.js';
|
|
|
16
15
|
import { readPlanAutoCompletionReport, } from './completion-report.js';
|
|
17
16
|
import { claimIssue, discoverIssueWork } from './issue-state-machine.js';
|
|
18
17
|
import { collectExecutableChildBatches, persistAutonomousChildNode, readAutonomousChildNodes, topologicalPlanNodes, } from './issue-tree.js';
|
|
19
|
-
import { runImplementationPublishabilityCheck } from './local-execution-session.js';
|
|
20
18
|
import { RunnerLifecycleEventStore } from './lifecycle-events.js';
|
|
21
19
|
import { RunnerStateStore } from './local-state.js';
|
|
22
20
|
import { classifyPlanAutoBlockedChildRecovery, classifyPlanAutoCompletedChildRecovery, classifyPlanAutoParentRecovery, } from './plan-auto-recovery.js';
|
|
23
21
|
import { buildIssueTreeChildPrompt, buildPlanAutoPrompt, sessionPromptPath, sessionReportPath, writeDurablePrompt, } from './prompt.js';
|
|
24
|
-
import {
|
|
22
|
+
import { runAgentAttemptLoop } from './agent-attempt.js';
|
|
25
23
|
import { evaluateParentRiskRoutingGate } from './review-gates.js';
|
|
26
24
|
import { buildBlockedHandoffEvidence, buildPromotionAsBlockedHandoffEvidence, buildReviewReadyHandoffEvidence, } from './runner-handoff-decision.js';
|
|
27
25
|
import { sessionLogPath } from './run-log.js';
|
|
28
26
|
import { cleanupSessionCodexHome, sessionCodexHomePath } from './session-home.js';
|
|
27
|
+
import { finishBlockedTerminalOutcome, finishReviewReadyCommentTerminalOutcome, finishReviewReadyTerminalOutcome, } from './terminal-outcome.js';
|
|
29
28
|
class ChildExecutionBlockedError extends Error {
|
|
30
29
|
durableRunSummary;
|
|
31
30
|
freshContextReview;
|
|
@@ -375,37 +374,44 @@ export async function runPlanAutoCommand(options) {
|
|
|
375
374
|
...failedFinalValidation.map((line) => `${line.command}: ${line.status} - ${line.summary}`),
|
|
376
375
|
], childIssues);
|
|
377
376
|
}
|
|
378
|
-
await
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
377
|
+
const handoff = await finishReviewReadyTerminalOutcome({
|
|
378
|
+
issueNumber: options.issueNumber,
|
|
379
|
+
config,
|
|
380
|
+
branchName,
|
|
381
|
+
baseBranch: resolvedBase.prBaseBranch,
|
|
382
|
+
worktreePath,
|
|
383
|
+
git,
|
|
384
|
+
pullRequestAdapter,
|
|
385
|
+
issueAdapter,
|
|
386
|
+
pullRequest: {
|
|
387
|
+
title: renderParentTemplate(config.pullRequests.issueTreeTitle, options.issueNumber),
|
|
388
|
+
body: buildIssueTreePullRequestBody({
|
|
389
|
+
parentIssueNumber: options.issueNumber,
|
|
390
|
+
childIssues,
|
|
391
|
+
childResults: executionResults,
|
|
392
|
+
finalValidation,
|
|
393
|
+
sizeRisk: report.sizeRisk,
|
|
394
|
+
parentReviewHandoff: report.parentReviewHandoff,
|
|
395
|
+
riskRoutingWarnings,
|
|
396
|
+
}),
|
|
397
|
+
},
|
|
398
|
+
findExistingPullRequest: false,
|
|
399
|
+
reportComment: (verifiedPullRequest) => buildIssueTreeReviewReport({
|
|
382
400
|
parentIssueNumber: options.issueNumber,
|
|
383
|
-
|
|
401
|
+
pullRequest: verifiedPullRequest,
|
|
402
|
+
batches: batches.batches,
|
|
384
403
|
childResults: executionResults,
|
|
385
404
|
finalValidation,
|
|
386
405
|
sizeRisk: report.sizeRisk,
|
|
387
406
|
parentReviewHandoff: report.parentReviewHandoff,
|
|
388
407
|
riskRoutingWarnings,
|
|
389
408
|
}),
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
parentIssueNumber: options.issueNumber,
|
|
396
|
-
pullRequest,
|
|
397
|
-
batches: batches.batches,
|
|
398
|
-
childResults: executionResults,
|
|
399
|
-
finalValidation,
|
|
400
|
-
sizeRisk: report.sizeRisk,
|
|
401
|
-
parentReviewHandoff: report.parentReviewHandoff,
|
|
402
|
-
riskRoutingWarnings,
|
|
409
|
+
onPullRequestReady: (verifiedPullRequest) => {
|
|
410
|
+
pullRequest = verifiedPullRequest;
|
|
411
|
+
},
|
|
412
|
+
beforeIssueMutation: () => markCompletedChildrenReviewReady(issueAdapter, config, store, options.issueNumber, executionResults),
|
|
413
|
+
afterComment: () => store.removeRun(options.issueNumber),
|
|
403
414
|
});
|
|
404
|
-
await markCompletedChildrenReviewReady(issueAdapter, config, store, options.issueNumber, executionResults);
|
|
405
|
-
await issueAdapter.removeLabels(options.issueNumber, [config.github.labels.running.name]);
|
|
406
|
-
await issueAdapter.addLabels(options.issueNumber, [config.github.labels.review.name]);
|
|
407
|
-
await issueAdapter.postComment(options.issueNumber, reportComment);
|
|
408
|
-
await store.removeRun(options.issueNumber);
|
|
409
415
|
await safeAppendEvent(events, {
|
|
410
416
|
issueNumber: options.issueNumber,
|
|
411
417
|
mode: 'plan-parent',
|
|
@@ -415,14 +421,14 @@ export async function runPlanAutoCommand(options) {
|
|
|
415
421
|
summary: 'Issue-tree execution completed draft PR handoff.',
|
|
416
422
|
artifacts: [
|
|
417
423
|
...sessionArtifacts(promptPath, reportPath, logPath, parentSnapshotPath),
|
|
418
|
-
{ kind: 'pr', url: pullRequest.url, description: 'Draft pull request' },
|
|
424
|
+
{ kind: 'pr', url: handoff.pullRequest.url, description: 'Draft pull request' },
|
|
419
425
|
],
|
|
420
426
|
});
|
|
421
427
|
return {
|
|
422
428
|
...buildBase(),
|
|
423
429
|
status: 'review-ready',
|
|
424
|
-
pullRequest,
|
|
425
|
-
reportComment,
|
|
430
|
+
pullRequest: handoff.pullRequest,
|
|
431
|
+
reportComment: handoff.reportComment,
|
|
426
432
|
riskRoutingWarnings,
|
|
427
433
|
};
|
|
428
434
|
}
|
|
@@ -479,7 +485,6 @@ async function executeChild(input) {
|
|
|
479
485
|
const childIssueNumber = input.child.issue.number;
|
|
480
486
|
const branchName = `codex/tree-${input.parentIssue.number}-issue-${childIssueNumber}`;
|
|
481
487
|
const worktreePath = join(input.targetRoot, input.config.runner.workspaceRoot, `tree-${input.parentIssue.number}-issue-${childIssueNumber}`);
|
|
482
|
-
const store = new RunnerStateStore(input.targetRoot, input.config);
|
|
483
488
|
let sessionId = '';
|
|
484
489
|
let promptPath = '';
|
|
485
490
|
let reportPath = '';
|
|
@@ -506,204 +511,69 @@ async function executeChild(input) {
|
|
|
506
511
|
await input.issueAdapter.addLabels(childIssueNumber, [input.config.github.labels.running.name]);
|
|
507
512
|
await input.issueAdapter.postComment(childIssueNumber, `codex-orchestrator: claimed #${childIssueNumber} for tree-child autonomous work under #${input.parentIssue.number} at ${input.now.toISOString()}.`);
|
|
508
513
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
});
|
|
529
|
-
logPath = sessionLogPath({
|
|
530
|
-
targetRoot: input.targetRoot,
|
|
531
|
-
config: input.config,
|
|
532
|
-
issueNumber: childIssueNumber,
|
|
533
|
-
sessionId,
|
|
534
|
-
});
|
|
535
|
-
const isolatedHomePath = sessionCodexHomePath({ targetRoot: input.targetRoot, sessionId });
|
|
536
|
-
await mkdir(dirname(reportPath), { recursive: true });
|
|
537
|
-
await mkdir(isolatedHomePath, { recursive: true });
|
|
538
|
-
const promptText = buildIssueTreeChildPrompt({
|
|
539
|
-
parentIssue: input.parentIssue,
|
|
540
|
-
childIssue: input.child.issue,
|
|
541
|
-
config: input.config,
|
|
542
|
-
workflowPromptText: input.issueTreeWorkflowPrompt,
|
|
543
|
-
childMetadata: input.child.metadata,
|
|
544
|
-
dependencyIssues: input.dependencyIssues,
|
|
545
|
-
promptPath,
|
|
546
|
-
reportPath,
|
|
547
|
-
branchName,
|
|
548
|
-
worktreePath,
|
|
549
|
-
});
|
|
550
|
-
const attemptPromptText = rework
|
|
551
|
-
? `${promptText}\n\n## Rework Request\nThis is an automatic rework attempt (#${rework.attempt}). Continue from the current worktree state; do not start over.\nThe previous attempt was blocked for these reasons:\n${rework.blockedReasons.map((reason) => `- ${reason}`).join('\n')}\n${rework.disableOptionalFigmaMcp ? 'Optional Figma MCP failed in the previous attempt. Continue without optional Figma MCP access unless the issue explicitly requires Figma.\n' : ''}Address the blockers, then produce a fresh completion report JSON for the runner.`
|
|
552
|
-
: promptText;
|
|
553
|
-
await writeDurablePrompt({
|
|
554
|
-
targetRoot: input.targetRoot,
|
|
555
|
-
config: input.config,
|
|
556
|
-
issueNumber: childIssueNumber,
|
|
557
|
-
sessionId,
|
|
558
|
-
promptText: attemptPromptText,
|
|
559
|
-
});
|
|
560
|
-
const snapshot = await writeContextSnapshot({
|
|
561
|
-
targetRoot: input.targetRoot,
|
|
562
|
-
config: input.config,
|
|
563
|
-
issue: input.child.issue,
|
|
564
|
-
mode: 'tree-child',
|
|
565
|
-
phase: 'tree-child',
|
|
566
|
-
decision: rework
|
|
567
|
-
? `tree-child rework attempt #${rework.attempt} under parent #${input.parentIssue.number}`
|
|
568
|
-
: `child issue execution under parent #${input.parentIssue.number}`,
|
|
569
|
-
sessionId,
|
|
570
|
-
worktreePath,
|
|
571
|
-
promptPath,
|
|
572
|
-
reportPath,
|
|
573
|
-
logPath,
|
|
574
|
-
branchName,
|
|
575
|
-
baseBranch: input.parentBranchName,
|
|
576
|
-
parentIssueNumber: input.parentIssue.number,
|
|
577
|
-
blockedBy: [],
|
|
578
|
-
createdAt: attemptNow,
|
|
579
|
-
});
|
|
580
|
-
snapshotPath = snapshot.path;
|
|
581
|
-
await store.upsertRun({
|
|
582
|
-
issueNumber: childIssueNumber,
|
|
583
|
-
parentIssueNumber: input.parentIssue.number,
|
|
584
|
-
mode: 'tree-child',
|
|
585
|
-
workspacePath: worktreePath,
|
|
586
|
-
sessionId,
|
|
587
|
-
branchName,
|
|
588
|
-
promptPath,
|
|
589
|
-
reportPath,
|
|
590
|
-
logPath,
|
|
591
|
-
retryCount: attempt,
|
|
592
|
-
createdAt: input.now.toISOString(),
|
|
593
|
-
updatedAt: attemptNow.toISOString(),
|
|
594
|
-
attemptStartedAt: attemptNow.toISOString(),
|
|
595
|
-
snapshotPath,
|
|
596
|
-
});
|
|
597
|
-
await safeAppendEvent(input.events, {
|
|
598
|
-
timestamp: attemptNow,
|
|
599
|
-
issueNumber: childIssueNumber,
|
|
600
|
-
parentIssueNumber: input.parentIssue.number,
|
|
601
|
-
mode: 'tree-child',
|
|
602
|
-
sessionId,
|
|
603
|
-
phase: 'tree-child',
|
|
604
|
-
status: 'started',
|
|
605
|
-
summary: rework ? `Starting tree-child rework attempt #${rework.attempt}.` : 'Starting tree-child Codex session.',
|
|
606
|
-
artifacts: sessionArtifacts(promptPath, reportPath, logPath, snapshotPath),
|
|
607
|
-
});
|
|
608
|
-
const beforeHead = await input.git.getHead(worktreePath);
|
|
609
|
-
let codexResult;
|
|
610
|
-
try {
|
|
611
|
-
codexResult = await input.codexAdapter.run({
|
|
612
|
-
targetRoot: input.targetRoot,
|
|
514
|
+
const attemptLoop = await runAgentAttemptLoop({
|
|
515
|
+
targetRoot: input.targetRoot,
|
|
516
|
+
config: input.config,
|
|
517
|
+
issue: input.child.issue,
|
|
518
|
+
issueNumber: childIssueNumber,
|
|
519
|
+
parentIssueNumber: input.parentIssue.number,
|
|
520
|
+
mode: 'tree-child',
|
|
521
|
+
phase: 'tree-child',
|
|
522
|
+
branchName,
|
|
523
|
+
worktreePath,
|
|
524
|
+
baseBranch: input.parentBranchName,
|
|
525
|
+
createdAt: input.now,
|
|
526
|
+
firstAttempt: input.recovery ? input.recovery.rework.attempt : 0,
|
|
527
|
+
initialRework: input.recovery?.rework,
|
|
528
|
+
buildSessionId: ({ attempt, attemptNow }) => `tree-${input.parentIssue.number}-issue-${childIssueNumber}-${formatSessionTimestamp(attemptNow)}${attempt === 0 ? '' : `-attempt-${attempt}`}`,
|
|
529
|
+
buildPrompt: ({ promptPath: attemptPromptPath, reportPath: attemptReportPath, rework }) => {
|
|
530
|
+
const promptText = buildIssueTreeChildPrompt({
|
|
531
|
+
parentIssue: input.parentIssue,
|
|
532
|
+
childIssue: input.child.issue,
|
|
613
533
|
config: input.config,
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
issueNumber: childIssueNumber,
|
|
620
|
-
sessionId,
|
|
534
|
+
workflowPromptText: input.issueTreeWorkflowPrompt,
|
|
535
|
+
childMetadata: input.child.metadata,
|
|
536
|
+
dependencyIssues: input.dependencyIssues,
|
|
537
|
+
promptPath: attemptPromptPath,
|
|
538
|
+
reportPath: attemptReportPath,
|
|
621
539
|
branchName,
|
|
622
|
-
|
|
623
|
-
logPath,
|
|
624
|
-
disableOptionalFigmaMcp: rework?.disableOptionalFigmaMcp,
|
|
540
|
+
worktreePath,
|
|
625
541
|
});
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
542
|
+
return rework
|
|
543
|
+
? `${promptText}\n\n## Rework Request\nThis is an automatic rework attempt (#${rework.attempt}). Continue from the current worktree state; do not start over.\nThe previous attempt was blocked for these reasons:\n${rework.blockedReasons.map((reason) => `- ${reason}`).join('\n')}\n${rework.disableOptionalFigmaMcp ? 'Optional Figma MCP failed in the previous attempt. Continue without optional Figma MCP access unless the issue explicitly requires Figma.\n' : ''}Address the blockers, then produce a fresh completion report JSON for the runner.`
|
|
544
|
+
: promptText;
|
|
545
|
+
},
|
|
546
|
+
buildSnapshotDecision: ({ rework }) => rework
|
|
547
|
+
? `tree-child rework attempt #${rework.attempt} under parent #${input.parentIssue.number}`
|
|
548
|
+
: `child issue execution under parent #${input.parentIssue.number}`,
|
|
549
|
+
startedSummary: ({ rework }) => rework ? `Starting tree-child rework attempt #${rework.attempt}.` : 'Starting tree-child Codex session.',
|
|
550
|
+
reworkScheduledSummary: ({ nextAttempt }) => `Runner scheduled tree-child rework attempt #${nextAttempt}.`,
|
|
551
|
+
missingPublishabilityMessage: 'Runner internal error: missing child publishability result',
|
|
552
|
+
codexAdapter: input.codexAdapter,
|
|
553
|
+
git: input.git,
|
|
554
|
+
shellExecutor: input.shellExecutor,
|
|
555
|
+
commitMessage: `Codex: implement issue #${childIssueNumber} for parent #${input.parentIssue.number}`,
|
|
556
|
+
events: input.events,
|
|
557
|
+
acceptanceProof: {
|
|
634
558
|
targetRoot: input.targetRoot,
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
sessionId,
|
|
654
|
-
event,
|
|
655
|
-
}),
|
|
656
|
-
},
|
|
657
|
-
});
|
|
658
|
-
if (publishability.status === 'blocked') {
|
|
659
|
-
const reworkDecision = decideImplementationRework({
|
|
660
|
-
reasons: publishability.reasons,
|
|
661
|
-
config: input.config,
|
|
662
|
-
attempt,
|
|
663
|
-
});
|
|
664
|
-
reworkAttempts.push({
|
|
665
|
-
attempt,
|
|
666
|
-
maxAttempts: 'maxAttempts' in reworkDecision ? reworkDecision.maxAttempts : undefined,
|
|
667
|
-
decisionKind: reworkDecision.kind,
|
|
668
|
-
reasons: publishability.reasons,
|
|
669
|
-
promptPath,
|
|
670
|
-
reportPath,
|
|
671
|
-
logPath,
|
|
672
|
-
snapshotPath,
|
|
673
|
-
});
|
|
674
|
-
if (reworkDecision.kind === 'retry') {
|
|
675
|
-
rework = reworkDecision.rework;
|
|
676
|
-
await safeAppendEvent(input.events, {
|
|
677
|
-
timestamp: attemptNow,
|
|
678
|
-
issueNumber: childIssueNumber,
|
|
679
|
-
parentIssueNumber: input.parentIssue.number,
|
|
680
|
-
mode: 'tree-child',
|
|
681
|
-
sessionId,
|
|
682
|
-
phase: 'tree-child',
|
|
683
|
-
status: 'needs-rework',
|
|
684
|
-
summary: `Runner scheduled tree-child rework attempt #${reworkDecision.nextAttempt}.`,
|
|
685
|
-
artifacts: sessionArtifacts(promptPath, reportPath, logPath, snapshotPath),
|
|
686
|
-
});
|
|
687
|
-
await mkdir(isolatedHomePath, { recursive: true });
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
await safeAppendEvent(input.events, {
|
|
691
|
-
timestamp: attemptNow,
|
|
692
|
-
issueNumber: childIssueNumber,
|
|
693
|
-
parentIssueNumber: input.parentIssue.number,
|
|
694
|
-
mode: 'tree-child',
|
|
695
|
-
sessionId,
|
|
696
|
-
phase: 'tree-child',
|
|
697
|
-
status: 'blocked',
|
|
698
|
-
summary: `Runner rework decision: ${reworkDecision.kind}.`,
|
|
699
|
-
artifacts: sessionArtifacts(promptPath, reportPath, logPath, snapshotPath),
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
break;
|
|
703
|
-
}
|
|
704
|
-
if (!publishability) {
|
|
705
|
-
throw new Error('Runner internal error: missing child publishability result');
|
|
706
|
-
}
|
|
559
|
+
workflowPromptText: input.acceptanceProofWorkflowPrompt,
|
|
560
|
+
codexAdapter: input.codexAdapter,
|
|
561
|
+
},
|
|
562
|
+
onAcceptanceProofAttemptEvent: ({ sessionId: attemptSessionId, event }) => appendAcceptanceProofEvent({
|
|
563
|
+
events: input.events,
|
|
564
|
+
issueNumber: childIssueNumber,
|
|
565
|
+
parentIssueNumber: input.parentIssue.number,
|
|
566
|
+
sessionId: attemptSessionId,
|
|
567
|
+
event,
|
|
568
|
+
}),
|
|
569
|
+
});
|
|
570
|
+
const publishability = attemptLoop.publishability;
|
|
571
|
+
sessionId = attemptLoop.sessionId;
|
|
572
|
+
promptPath = attemptLoop.promptPath;
|
|
573
|
+
reportPath = attemptLoop.reportPath;
|
|
574
|
+
logPath = attemptLoop.logPath;
|
|
575
|
+
snapshotPath = attemptLoop.snapshotPath;
|
|
576
|
+
const reworkAttempts = attemptLoop.reworkAttempts;
|
|
707
577
|
if (publishability.status === 'promotion-requested') {
|
|
708
578
|
const promotion = publishability.report.promotion;
|
|
709
579
|
const evidence = buildPromotionAsBlockedHandoffEvidence({
|
|
@@ -842,31 +712,37 @@ async function blockFailedBatch(issueAdapter, config, parentIssueNumber, failure
|
|
|
842
712
|
if (!failure.child) {
|
|
843
713
|
continue;
|
|
844
714
|
}
|
|
845
|
-
await
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
715
|
+
await finishBlockedTerminalOutcome({
|
|
716
|
+
issueNumber: failure.child.issue.number,
|
|
717
|
+
config,
|
|
718
|
+
issueAdapter,
|
|
719
|
+
reportComment: buildChildBlockedReport({
|
|
720
|
+
parentIssueNumber,
|
|
721
|
+
childIssueNumber: failure.child.issue.number,
|
|
722
|
+
reasons: [failure.message],
|
|
723
|
+
details: ['Worktree preserved for maintainer inspection.'],
|
|
724
|
+
freshContextReview: failure.freshContextReview,
|
|
725
|
+
durableRunSummary: failure.durableRunSummary,
|
|
726
|
+
reworkAttempts: failure.reworkAttempts,
|
|
727
|
+
acceptanceProof: failure.acceptanceProof,
|
|
728
|
+
}),
|
|
729
|
+
});
|
|
857
730
|
}
|
|
858
731
|
for (const result of successfulUnmerged) {
|
|
859
|
-
await
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
732
|
+
await finishBlockedTerminalOutcome({
|
|
733
|
+
issueNumber: result.child.issue.number,
|
|
734
|
+
config,
|
|
735
|
+
issueAdapter,
|
|
736
|
+
reportComment: buildChildBlockedReport({
|
|
737
|
+
parentIssueNumber,
|
|
738
|
+
childIssueNumber: result.child.issue.number,
|
|
739
|
+
reasons: ['A sibling child failed before the batch merge; this child branch was not merged.'],
|
|
740
|
+
branchName: result.branchName,
|
|
741
|
+
worktreePath: result.worktreePath,
|
|
742
|
+
durableRunSummary: result.durableRunSummary,
|
|
743
|
+
acceptanceProof: result.acceptanceProof,
|
|
744
|
+
}),
|
|
745
|
+
});
|
|
870
746
|
}
|
|
871
747
|
}
|
|
872
748
|
async function handleMergeConflict(git, issueAdapter, config, parentIssueNumber, error, childResult, batchResults) {
|
|
@@ -878,30 +754,33 @@ async function handleMergeConflict(git, issueAdapter, config, parentIssueNumber,
|
|
|
878
754
|
abortMessage = abortError instanceof Error ? abortError.message : 'merge abort failed';
|
|
879
755
|
}
|
|
880
756
|
for (const result of batchResults) {
|
|
881
|
-
await
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
result.child.issue.number
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
757
|
+
await finishBlockedTerminalOutcome({
|
|
758
|
+
issueNumber: result.child.issue.number,
|
|
759
|
+
config,
|
|
760
|
+
issueAdapter,
|
|
761
|
+
reportComment: buildChildBlockedReport({
|
|
762
|
+
parentIssueNumber,
|
|
763
|
+
childIssueNumber: result.child.issue.number,
|
|
764
|
+
reasons: [
|
|
765
|
+
result.child.issue.number === childResult.child.issue.number
|
|
766
|
+
? `Merge conflict from branch ${childResult.branchName}`
|
|
767
|
+
: `A sibling merge conflict stopped the batch before publication: ${childResult.branchName}`,
|
|
768
|
+
],
|
|
769
|
+
details: [
|
|
770
|
+
`- Parent worktree: ${error.worktreePath}`,
|
|
771
|
+
`- Child worktree: ${result.worktreePath}`,
|
|
772
|
+
`- Child branch preserved: ${result.branchName}`,
|
|
773
|
+
abortMessage ? `- Merge abort also failed: ${abortMessage}` : '- Merge abort completed.',
|
|
774
|
+
],
|
|
775
|
+
batchChildren: batchResults.map((batchResult) => ({
|
|
776
|
+
issueNumber: batchResult.child.issue.number,
|
|
777
|
+
branchName: batchResult.branchName,
|
|
778
|
+
})),
|
|
779
|
+
gitOutput: error.stderr || error.stdout || 'no git output',
|
|
780
|
+
durableRunSummary: result.durableRunSummary,
|
|
781
|
+
acceptanceProof: result.acceptanceProof,
|
|
782
|
+
}),
|
|
783
|
+
});
|
|
905
784
|
}
|
|
906
785
|
}
|
|
907
786
|
async function markCompletedChildrenReviewReady(issueAdapter, config, store, parentIssueNumber, childResults) {
|
|
@@ -910,10 +789,13 @@ async function markCompletedChildrenReviewReady(issueAdapter, config, store, par
|
|
|
910
789
|
await store.removeRun(childResult.child.issue.number);
|
|
911
790
|
continue;
|
|
912
791
|
}
|
|
913
|
-
await
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
792
|
+
await finishReviewReadyCommentTerminalOutcome({
|
|
793
|
+
issueNumber: childResult.child.issue.number,
|
|
794
|
+
config,
|
|
795
|
+
issueAdapter,
|
|
796
|
+
reportComment: buildChildReviewReport({ parentIssueNumber, result: childResult }),
|
|
797
|
+
afterTerminalMutation: () => store.removeRun(childResult.child.issue.number),
|
|
798
|
+
});
|
|
917
799
|
}
|
|
918
800
|
}
|
|
919
801
|
async function blockCompletedChildren(issueAdapter, config, store, parentIssueNumber, childResults, reason, parentWorktreePath) {
|
|
@@ -921,20 +803,23 @@ async function blockCompletedChildren(issueAdapter, config, store, parentIssueNu
|
|
|
921
803
|
if (result.recovered) {
|
|
922
804
|
continue;
|
|
923
805
|
}
|
|
924
|
-
await
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
806
|
+
await finishBlockedTerminalOutcome({
|
|
807
|
+
issueNumber: result.child.issue.number,
|
|
808
|
+
config,
|
|
809
|
+
issueAdapter,
|
|
810
|
+
reportComment: buildChildBlockedReport({
|
|
811
|
+
parentIssueNumber,
|
|
812
|
+
childIssueNumber: result.child.issue.number,
|
|
813
|
+
reasons: [reason],
|
|
814
|
+
details: [
|
|
815
|
+
`- Merged child branch was not published: ${result.branchName}`,
|
|
816
|
+
`- Parent worktree preserved: ${parentWorktreePath}`,
|
|
817
|
+
],
|
|
818
|
+
durableRunSummary: result.durableRunSummary,
|
|
819
|
+
acceptanceProof: result.acceptanceProof,
|
|
820
|
+
}),
|
|
821
|
+
afterTerminalMutation: () => store.removeRun(result.child.issue.number),
|
|
822
|
+
});
|
|
938
823
|
}
|
|
939
824
|
}
|
|
940
825
|
async function finishPlanBlocked(issueAdapter, config, events, result, reasons, mutatedChildren, commentMarker) {
|
|
@@ -945,12 +830,13 @@ async function finishPlanBlocked(issueAdapter, config, events, result, reasons,
|
|
|
945
830
|
mutatedChildren,
|
|
946
831
|
});
|
|
947
832
|
const reportComment = commentMarker ? `<!-- codex-orchestrator:${commentMarker} -->\n${reportBody}` : reportBody;
|
|
948
|
-
await
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
833
|
+
await finishBlockedTerminalOutcome({
|
|
834
|
+
issueNumber: result.parentIssueNumber,
|
|
835
|
+
config,
|
|
836
|
+
issueAdapter,
|
|
837
|
+
reportComment,
|
|
838
|
+
skipCommentIfIncludes: commentMarker,
|
|
839
|
+
});
|
|
954
840
|
await safeAppendEvent(events, {
|
|
955
841
|
issueNumber: result.parentIssueNumber,
|
|
956
842
|
mode: 'plan-parent',
|