@claudexor/orchestrator 6.0.0 → 6.1.2
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/attemptUsageCost.d.ts +2 -2
- package/dist/attemptUsageCost.d.ts.map +1 -1
- package/dist/attemptUsageCost.js +3 -3
- package/dist/attemptUsageCost.js.map +1 -1
- package/dist/candidateOutputs.d.ts +3 -2
- package/dist/candidateOutputs.d.ts.map +1 -1
- package/dist/candidateOutputs.js +5 -4
- package/dist/candidateOutputs.js.map +1 -1
- package/dist/candidateReview.js +3 -3
- package/dist/candidateReview.js.map +1 -1
- package/dist/candidateTerminals.js +3 -3
- package/dist/candidateTerminals.js.map +1 -1
- package/dist/candidateWorkProduct.js +2 -2
- package/dist/candidateWorkProduct.js.map +1 -1
- package/dist/continuation-custody.d.ts +15 -3
- package/dist/continuation-custody.d.ts.map +1 -1
- package/dist/continuation-custody.js +42 -14
- package/dist/continuation-custody.js.map +1 -1
- package/dist/continue-from.d.ts.map +1 -1
- package/dist/continue-from.js +6 -3
- package/dist/continue-from.js.map +1 -1
- package/dist/deepScanReducer.d.ts +1 -1
- package/dist/deepScanReducer.d.ts.map +1 -1
- package/dist/deepScanReducer.js +7 -5
- package/dist/deepScanReducer.js.map +1 -1
- package/dist/delegationFailure.js +1 -1
- package/dist/delegationFailure.js.map +1 -1
- package/dist/directoryCandidate.js +4 -4
- package/dist/directoryCandidate.js.map +1 -1
- package/dist/git-precondition.d.ts +0 -2
- package/dist/git-precondition.d.ts.map +1 -1
- package/dist/git-precondition.js +2 -21
- package/dist/git-precondition.js.map +1 -1
- package/dist/inrun-continuity.d.ts.map +1 -1
- package/dist/inrun-continuity.js +5 -6
- package/dist/inrun-continuity.js.map +1 -1
- package/dist/interaction.d.ts +4 -3
- package/dist/interaction.d.ts.map +1 -1
- package/dist/interaction.js +10 -6
- package/dist/interaction.js.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +65 -72
- package/dist/orchestrator.js.map +1 -1
- package/dist/planRun.d.ts +1 -1
- package/dist/planRun.d.ts.map +1 -1
- package/dist/planRun.js +5 -5
- package/dist/planRun.js.map +1 -1
- package/dist/plannerAttempt.d.ts.map +1 -1
- package/dist/plannerAttempt.js +6 -5
- package/dist/plannerAttempt.js.map +1 -1
- package/dist/retainedOutput.d.ts.map +1 -1
- package/dist/retainedOutput.js +4 -3
- package/dist/retainedOutput.js.map +1 -1
- package/dist/reviewerPanel.js +2 -2
- package/dist/reviewerPanel.js.map +1 -1
- package/dist/routeContext.d.ts +1 -1
- package/dist/routeContext.d.ts.map +1 -1
- package/dist/runEventLog.d.ts +11 -7
- package/dist/runEventLog.d.ts.map +1 -1
- package/dist/runEventLog.js +17 -13
- package/dist/runEventLog.js.map +1 -1
- package/dist/runScope.d.ts +3 -2
- package/dist/runScope.d.ts.map +1 -1
- package/dist/runScope.js +5 -4
- package/dist/runScope.js.map +1 -1
- package/dist/runSupport.d.ts +18 -1
- package/dist/runSupport.d.ts.map +1 -1
- package/dist/runSupport.js +16 -1
- package/dist/runSupport.js.map +1 -1
- package/dist/runTerminalHelpers.d.ts +14 -0
- package/dist/runTerminalHelpers.d.ts.map +1 -1
- package/dist/runTerminalHelpers.js +54 -1
- package/dist/runTerminalHelpers.js.map +1 -1
- package/dist/runTerminalResults.d.ts +5 -1
- package/dist/runTerminalResults.d.ts.map +1 -1
- package/dist/runTerminalResults.js +37 -4
- package/dist/runTerminalResults.js.map +1 -1
- package/dist/runTerminals.d.ts.map +1 -1
- package/dist/runTerminals.js +140 -138
- package/dist/runTerminals.js.map +1 -1
- package/dist/secretDiff.d.ts +4 -3
- package/dist/secretDiff.d.ts.map +1 -1
- package/dist/secretDiff.js +4 -3
- package/dist/secretDiff.js.map +1 -1
- package/package.json +17 -17
package/dist/orchestrator.js
CHANGED
|
@@ -51,10 +51,10 @@ import { budgetFailureRecord, classifyBudgetFailure } from "./budgetFailure.js";
|
|
|
51
51
|
import { finalizeStructuredOutput } from "./structuredOutput.js";
|
|
52
52
|
import { prepareRunAdmission } from "./runAdmission.js";
|
|
53
53
|
import { dropDeltaPastBudget, emitPlanProgress, emitTransientExhausted, observeUsageSpend, recordAdapterThrow, } from "./laneStreamEvents.js";
|
|
54
|
-
import { promptWithEngineConstraints, sleep, harnessEventPayload, safeErrorMessage, renderSummary, observeBudgetSignals, rotateOnStall, recordCleanAttemptMetrics, envInheritance, transientRetryPolicy, reviewerTimeoutMs, harnessInactivityTimeoutMs, observeAuthSwitch, emitPoolDegraded, deliveryRefusalFailure, winnerNeedsHuman, writeRaceDeliveryDecision, } from "./runSupport.js";
|
|
54
|
+
import { promptWithEngineConstraints, sleep, harnessEventPayload, safeErrorMessage, renderSummary, observeBudgetSignals, rotateOnStall, recordCleanAttemptMetrics, envInheritance, transientRetryPolicy, reviewerTimeoutMs, harnessInactivityTimeoutMs, laneSuspension, observeAuthSwitch, emitPoolDegraded, deliveryRefusalFailure, winnerNeedsHuman, writeRaceDeliveryDecision, } from "./runSupport.js";
|
|
55
55
|
import { candidateStatusInRouteContext, resolveReadOnlyRouteContext, } from "./routeContext.js";
|
|
56
56
|
import { resolveAutoReviewerPanel, resolveExplicitReviewerPanel } from "./reviewerPanel.js";
|
|
57
|
-
import {
|
|
57
|
+
import { ensureWriteModeGitBoundary } from "./git-precondition.js";
|
|
58
58
|
import { buildContinuation } from "./continuity.js";
|
|
59
59
|
import { resolveContinuitySummary, threadContinuityRequest } from "./continuity-facts.js";
|
|
60
60
|
import { runDiffReview } from "./diffReview.js";
|
|
@@ -84,7 +84,7 @@ import { ReadinessLedger, evaluateConvergence, failureSignature, gatesPassed, re
|
|
|
84
84
|
import { arbitrate } from "@claudexor/arbitration";
|
|
85
85
|
import { buildSynthesisPlan, decideSynthesis } from "@claudexor/synthesis";
|
|
86
86
|
import { billingKnowledgeForAuthRoute, attemptUsageCostSettlement, BudgetLedger, isBudgetTerminal, explainRanking, loadHarnessMetrics, promptFingerprint, rankHarnesses, } from "@claudexor/budget";
|
|
87
|
-
import { hashJson, newId, noProjectRepoRoot, redactSecrets, safeInvoke, userConfigDir, } from "@claudexor/util";
|
|
87
|
+
import { hashJson, measureSync, newId, noProjectRepoRoot, pacedByAppends, redactSecrets, safeInvoke, userConfigDir, } from "@claudexor/util";
|
|
88
88
|
const LABELS = "ABCDEFGHIJ".split("");
|
|
89
89
|
const NO_PROJECT_ROOT = noProjectRepoRoot();
|
|
90
90
|
export class Orchestrator {
|
|
@@ -231,14 +231,14 @@ export class Orchestrator {
|
|
|
231
231
|
}
|
|
232
232
|
catch (err) {
|
|
233
233
|
const message = safeErrorMessage(err);
|
|
234
|
-
store.
|
|
234
|
+
await store.writeTextAsync(join(paths.contextDir, "context_error.md"), `# Reviewer Panel Error\n\n${message}\n`);
|
|
235
235
|
writeFailure(store, paths, {
|
|
236
236
|
phase: "review_preflight",
|
|
237
237
|
category: "harness_unavailable",
|
|
238
238
|
safeMessage: message,
|
|
239
239
|
runDir: paths.root,
|
|
240
240
|
});
|
|
241
|
-
store.
|
|
241
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: failed\n- Phase: review preflight\n\n${message}\n`);
|
|
242
242
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
243
243
|
log.emit("run.failed", {
|
|
244
244
|
lifecycle: "failed",
|
|
@@ -971,7 +971,7 @@ export class Orchestrator {
|
|
|
971
971
|
include: projectCtx.include,
|
|
972
972
|
exclude: projectCtx.exclude,
|
|
973
973
|
});
|
|
974
|
-
store.
|
|
974
|
+
await store.writeYamlAsync(join(paths.contextDir, "context_pack.yaml"), pack);
|
|
975
975
|
log.emit("context.pack.created", {
|
|
976
976
|
hash: pack.hash,
|
|
977
977
|
files: pack.atlas.length,
|
|
@@ -1188,7 +1188,7 @@ export class Orchestrator {
|
|
|
1188
1188
|
if (!result.packetMarkdown)
|
|
1189
1189
|
return { pointerLine: null };
|
|
1190
1190
|
const briefPath = join(paths.contextDir, "THREAD.md");
|
|
1191
|
-
store.
|
|
1191
|
+
await store.writeTextAsync(briefPath, result.packetMarkdown);
|
|
1192
1192
|
return {
|
|
1193
1193
|
pointerLine: threadContextPointer(briefPath),
|
|
1194
1194
|
};
|
|
@@ -1419,6 +1419,7 @@ export class Orchestrator {
|
|
|
1419
1419
|
const rateLimitStart = telemetry.rateLimits.length;
|
|
1420
1420
|
rawLane.beginTry();
|
|
1421
1421
|
try {
|
|
1422
|
+
const pacing = { waiting: false, version: 0 };
|
|
1422
1423
|
const watched = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec, dispatch), {
|
|
1423
1424
|
timeoutMs: inactivityMs,
|
|
1424
1425
|
countsAsProgress: countsAsAgentProgress,
|
|
@@ -1428,12 +1429,11 @@ export class Orchestrator {
|
|
|
1428
1429
|
},
|
|
1429
1430
|
// Waiting on the USER is legitimate silence. The interaction policy
|
|
1430
1431
|
// either enforces a finite deadline or waits until answer/cancel/
|
|
1431
|
-
// terminal/restart when the timeout is disabled.
|
|
1432
|
-
|
|
1433
|
-
suspensionVersion: () => interaction?.suspensionVersion?.() ?? 0,
|
|
1432
|
+
// terminal/restart when the timeout is disabled. So is the journal wait.
|
|
1433
|
+
...laneSuspension(pacing, interaction),
|
|
1434
1434
|
stopSignal: signal, // after Stop: drained events are recorded, never used
|
|
1435
1435
|
});
|
|
1436
|
-
for await (const ev of watched) {
|
|
1436
|
+
for await (const ev of pacedByAppends(watched, [paths.eventsPath], pacing)) {
|
|
1437
1437
|
// After Stop: stored evidence only, but file paths are still collected for the capture.
|
|
1438
1438
|
const stopped = signal?.aborted === true;
|
|
1439
1439
|
if (!stopped)
|
|
@@ -1708,7 +1708,7 @@ export class Orchestrator {
|
|
|
1708
1708
|
aborted: signal?.aborted === true,
|
|
1709
1709
|
authMode: telemetry.authMode,
|
|
1710
1710
|
});
|
|
1711
|
-
const { produced: producedFiles, omitted: producedOmitted } = AC.withAttemptFailureCost(() => writeCandidateAttemptArtifacts({
|
|
1711
|
+
const { produced: producedFiles, omitted: producedOmitted } = await AC.withAttemptFailureCost(() => writeCandidateAttemptArtifacts({
|
|
1712
1712
|
store,
|
|
1713
1713
|
attemptDir,
|
|
1714
1714
|
worktreePath: envelope.worktree_path,
|
|
@@ -1838,7 +1838,7 @@ export class Orchestrator {
|
|
|
1838
1838
|
const mutatingRun = isMutatingAccess(contract.access.effective_profile);
|
|
1839
1839
|
const planBrief = verifiedPlanBrief(input);
|
|
1840
1840
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
1841
|
-
const { store, paths, log, ledger, runContext } = beginAnnouncedRun({
|
|
1841
|
+
const { store, paths, log, ledger, runContext } = await beginAnnouncedRun({
|
|
1842
1842
|
input,
|
|
1843
1843
|
contract,
|
|
1844
1844
|
quotaSnapshots,
|
|
@@ -1860,7 +1860,7 @@ export class Orchestrator {
|
|
|
1860
1860
|
const projectRoot = input.repoRoot;
|
|
1861
1861
|
const wsm = new WorkspaceManager(execRoot, { projectRoot, runtimeRoot: runRuntimeRoot(input) });
|
|
1862
1862
|
const anchors = secretDiff.revertAnchors(execRoot, projectRoot);
|
|
1863
|
-
store.
|
|
1863
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
1864
1864
|
log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
|
|
1865
1865
|
// Write modes need a git boundary for worktree isolation and honest diffs.
|
|
1866
1866
|
// A non-git project folder is initialized automatically (baseline commit),
|
|
@@ -1884,11 +1884,6 @@ export class Orchestrator {
|
|
|
1884
1884
|
};
|
|
1885
1885
|
}
|
|
1886
1886
|
}
|
|
1887
|
-
// Same run-prep stage as the git boundary: if the PROJECT root uses AGENTS.md
|
|
1888
|
-
// with no CLAUDE.md, bridge it so a Claude Code candidate reads it (INV-113).
|
|
1889
|
-
if (mutatingRun && input.workspaceKind !== "directory") {
|
|
1890
|
-
ensureClaudeBridgeForRun(input.repoRoot, input.inPlace === true, log);
|
|
1891
|
-
}
|
|
1892
1887
|
// Pre-turn snapshot of the live tree for in-place runs: the revert restore
|
|
1893
1888
|
// target (server-owned revertInPlace). A snapshot failure must never fail the
|
|
1894
1889
|
// run — revert is simply unavailable then.
|
|
@@ -2213,7 +2208,7 @@ export class Orchestrator {
|
|
|
2213
2208
|
error: message,
|
|
2214
2209
|
phase: infraPhase,
|
|
2215
2210
|
});
|
|
2216
|
-
store.
|
|
2211
|
+
await store.writeYamlAsync(join(paths.attemptsDir, slot.attemptId, "attempt.yaml"), AC.attemptFailureRecord(slot.attemptId, adapter.id, failureCost, infraPhase, message, applied));
|
|
2217
2212
|
runsBySlot[slotIdx] = {
|
|
2218
2213
|
attemptId: slot.attemptId,
|
|
2219
2214
|
harnessId: adapter.id,
|
|
@@ -2410,7 +2405,7 @@ export class Orchestrator {
|
|
|
2410
2405
|
sources: evidences.map((evidence) => evidence.attemptId),
|
|
2411
2406
|
};
|
|
2412
2407
|
try {
|
|
2413
|
-
store.
|
|
2408
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "synthesis.yaml"), synth);
|
|
2414
2409
|
log.emit("synthesis.started", { synthesize: synth.synthesize, reason: synth.reason });
|
|
2415
2410
|
if (synth.synthesize && !budgetStopped) {
|
|
2416
2411
|
const synthRouted = adapters[0];
|
|
@@ -2583,7 +2578,7 @@ export class Orchestrator {
|
|
|
2583
2578
|
facts = { ...facts, checks: "failed", reason: "checks_failed" };
|
|
2584
2579
|
}
|
|
2585
2580
|
const needsDec = facts.review === "blocked" || facts.checks === "failed";
|
|
2586
|
-
store.
|
|
2581
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "decision.yaml"), {
|
|
2587
2582
|
...result.decision,
|
|
2588
2583
|
...(needsDec
|
|
2589
2584
|
? blockedDecisionOverride(result.decision.evidence_facts, facts, finalVerify)
|
|
@@ -2591,7 +2586,7 @@ export class Orchestrator {
|
|
|
2591
2586
|
review_verified: actualReviewVerified,
|
|
2592
2587
|
final_verify: finalVerify,
|
|
2593
2588
|
});
|
|
2594
|
-
store.
|
|
2589
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "pairwise.yaml"), result.pairwise);
|
|
2595
2590
|
const decisionPath = join(paths.arbitrationDir, "decision.yaml");
|
|
2596
2591
|
// Every attempt's failed tries by the FINAL outcome (delivery below can
|
|
2597
2592
|
// still fail the checks); a review or check block is not an account failure.
|
|
@@ -2606,7 +2601,7 @@ export class Orchestrator {
|
|
|
2606
2601
|
}
|
|
2607
2602
|
const winnerAnswer = winnerRun.answerText ?? "";
|
|
2608
2603
|
if (winnerAnswer.length > 0) {
|
|
2609
|
-
store.
|
|
2604
|
+
await store.writeTextAsync(join(paths.finalDir, "answer.md"), winnerAnswer + "\n");
|
|
2610
2605
|
}
|
|
2611
2606
|
if (contract.output_schema) {
|
|
2612
2607
|
finalizeStructuredOutput({
|
|
@@ -2628,7 +2623,7 @@ export class Orchestrator {
|
|
|
2628
2623
|
const delivered = await verifyAndDeliverFiles(execRoot, winnerRun.files, {}, gateSpecsFromContract(contract, input.runScopeMarker), (freshVerify) => finalVerifyBlocks(freshVerify)
|
|
2629
2624
|
? (freshVerify.reason ?? "final verify failed before directory race adoption")
|
|
2630
2625
|
: null, log);
|
|
2631
|
-
store.
|
|
2626
|
+
await store.writeYamlAsync(join(paths.finalDir, "delivery_receipt.yaml"), delivered);
|
|
2632
2627
|
directoryDeliveryReceipt = true;
|
|
2633
2628
|
directoryDelivery = delivered;
|
|
2634
2629
|
finalVerify = delivered.finalVerify;
|
|
@@ -2660,7 +2655,7 @@ export class Orchestrator {
|
|
|
2660
2655
|
});
|
|
2661
2656
|
}
|
|
2662
2657
|
else if (mutatingRun) {
|
|
2663
|
-
const savedPatch = secretDiff.persistFinalPatch(store, paths.finalDir, winnerRun);
|
|
2658
|
+
const savedPatch = await secretDiff.persistFinalPatch(store, paths.finalDir, winnerRun);
|
|
2664
2659
|
const patchSha256 = savedPatch.patchSha256;
|
|
2665
2660
|
const wstats = secretDiff.resultDiffStats(winnerRun);
|
|
2666
2661
|
const hasDiff = secretDiff.hasCandidateChanges(winnerRun);
|
|
@@ -2695,7 +2690,7 @@ export class Orchestrator {
|
|
|
2695
2690
|
: null;
|
|
2696
2691
|
}, log);
|
|
2697
2692
|
raceDeliveryReceipt = applied;
|
|
2698
|
-
store.
|
|
2693
|
+
await store.writeYamlAsync(join(paths.finalDir, "delivery_receipt.yaml"), applied);
|
|
2699
2694
|
finalVerify = applied.finalVerify;
|
|
2700
2695
|
if (applied.applied) {
|
|
2701
2696
|
adopted = true;
|
|
@@ -2741,7 +2736,7 @@ export class Orchestrator {
|
|
|
2741
2736
|
revertAnchorId = await anchors.turn(preTurnSha, postTurnSha);
|
|
2742
2737
|
}
|
|
2743
2738
|
const capturedNoGitChange = capturedNoGitChangeValue(winnerRun);
|
|
2744
|
-
store.
|
|
2739
|
+
await store.writeYamlAsync(join(paths.finalDir, "work_product.yaml"), {
|
|
2745
2740
|
id: newId("wp"),
|
|
2746
2741
|
kind: input.create === true ? "new_repo" : "patch",
|
|
2747
2742
|
source_task_id: taskId,
|
|
@@ -2776,7 +2771,7 @@ export class Orchestrator {
|
|
|
2776
2771
|
},
|
|
2777
2772
|
});
|
|
2778
2773
|
}
|
|
2779
|
-
store.
|
|
2774
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), withPoolAttempts(renderSummary(runId, mode, { ...result.decision, facts }, evidences, synth.reason, actualReviewVerified, delegateFailure.raceSummaryDisclosure(winnerRun, runs)), racePool()));
|
|
2780
2775
|
// summary.md is a DIAGNOSTIC artifact only (V8/PLAN addendum 2): it no
|
|
2781
2776
|
// longer carries primary-output authority. A clean applyable success or a
|
|
2782
2777
|
// winner answer still marks it ready for legacy INV-116 ordering; any
|
|
@@ -2888,7 +2883,7 @@ export class Orchestrator {
|
|
|
2888
2883
|
...(decisionBlock ? {} : erroredWinnerFailure(winnerRun, keptSources)),
|
|
2889
2884
|
});
|
|
2890
2885
|
if (!winnerRun) {
|
|
2891
|
-
store.
|
|
2886
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Phase: arbitration\n\n${withPoolAttempts(result.decision.why_winner, pool)}\n`);
|
|
2892
2887
|
log.emit("output.ready", {
|
|
2893
2888
|
kind: "summary",
|
|
2894
2889
|
path: "final/summary.md",
|
|
@@ -2954,9 +2949,10 @@ export class Orchestrator {
|
|
|
2954
2949
|
writeRunTelemetry(store, paths, contract, runId, taskId, mode, attempts, finalAttemptId, deepScanSynthesis) {
|
|
2955
2950
|
// QA-034: attach the routing rationale recorded at pool ordering (if this
|
|
2956
2951
|
// run computed one), then clear it — telemetry is written once at terminal.
|
|
2952
|
+
// It stays synchronous (several callers are synchronous callbacks), labeled (#688).
|
|
2957
2953
|
const routingRationale = this.routingRationaleByRun.get(runId) ?? null;
|
|
2958
2954
|
this.routingRationaleByRun.delete(runId);
|
|
2959
|
-
writeRunTelemetryArtifact({
|
|
2955
|
+
measureSync("run.telemetry_write", () => writeRunTelemetryArtifact({
|
|
2960
2956
|
store,
|
|
2961
2957
|
finalDir: paths.finalDir,
|
|
2962
2958
|
contract,
|
|
@@ -2968,7 +2964,7 @@ export class Orchestrator {
|
|
|
2968
2964
|
routingRationale,
|
|
2969
2965
|
deepScanSynthesis: deepScanSynthesis ?? null,
|
|
2970
2966
|
resolveAuthPreference: (harnessId) => this.authPreferenceForHarness(contract.repo.root, harnessId, contract.auth_preference),
|
|
2971
|
-
});
|
|
2967
|
+
}));
|
|
2972
2968
|
}
|
|
2973
2969
|
/**
|
|
2974
2970
|
* SINGLE funnel for every reviewer-panel invocation: run it inside a per-review
|
|
@@ -3022,7 +3018,7 @@ export class Orchestrator {
|
|
|
3022
3018
|
const contract = this.buildContract(input, taskId, mode);
|
|
3023
3019
|
const planBrief = verifiedPlanBrief(input);
|
|
3024
3020
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
3025
|
-
const { store, paths, log, ledger, runContext } = beginAnnouncedRun({
|
|
3021
|
+
const { store, paths, log, ledger, runContext } = await beginAnnouncedRun({
|
|
3026
3022
|
input,
|
|
3027
3023
|
contract,
|
|
3028
3024
|
quotaSnapshots,
|
|
@@ -3047,7 +3043,7 @@ export class Orchestrator {
|
|
|
3047
3043
|
});
|
|
3048
3044
|
const anchors = secretDiff.revertAnchors(execRoot, input.repoRoot);
|
|
3049
3045
|
const readiness = new ReadinessLedger();
|
|
3050
|
-
store.
|
|
3046
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
3051
3047
|
// Legacy Git envelopes need their boundary; explicit directory execution
|
|
3052
3048
|
// keeps the requested strategy without initializing the selected folder.
|
|
3053
3049
|
if (!input.inPlace && input.workspaceKind !== "directory") {
|
|
@@ -3066,11 +3062,6 @@ export class Orchestrator {
|
|
|
3066
3062
|
candidates: [],
|
|
3067
3063
|
};
|
|
3068
3064
|
}
|
|
3069
|
-
// Same run-prep stage as the git boundary (and the same `!inPlace`
|
|
3070
|
-
// exclusion — we are inside that branch, so inPlace is false here): bridge
|
|
3071
|
-
// an AGENTS.md-only PROJECT root so a Claude Code convergence attempt reads
|
|
3072
|
-
// it (INV-113).
|
|
3073
|
-
ensureClaudeBridgeForRun(input.repoRoot, false, log);
|
|
3074
3065
|
}
|
|
3075
3066
|
const reviewDir = join(paths.root, "review-evidence");
|
|
3076
3067
|
if (contract.review_requested !== false)
|
|
@@ -3118,7 +3109,7 @@ export class Orchestrator {
|
|
|
3118
3109
|
if (contract.convergence.require_final_cross_family_clean_review && !reviewVerified) {
|
|
3119
3110
|
const message = `convergence requires a cross-family clean review (>=2 healthy reviewer provider families); found ${new Set(reviewers.map((r) => r.providerFamily)).size}. ` +
|
|
3120
3111
|
"Configure reviewers from a second provider family and check `claudexor doctor` for reviewer readiness.";
|
|
3121
|
-
store.
|
|
3112
|
+
await store.writeTextAsync(join(paths.contextDir, "context_error.md"), `# Convergence Preflight Error\n\n${message}\n`);
|
|
3122
3113
|
writeFailure(store, paths, {
|
|
3123
3114
|
phase: "review",
|
|
3124
3115
|
category: "policy",
|
|
@@ -3129,7 +3120,7 @@ export class Orchestrator {
|
|
|
3129
3120
|
"Check harness doctor for reviewer readiness",
|
|
3130
3121
|
],
|
|
3131
3122
|
});
|
|
3132
|
-
store.
|
|
3123
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${mode})\n\n- Lifecycle: failed\n- Phase: review preflight\n\n${message}\n`);
|
|
3133
3124
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
3134
3125
|
log.emit("run.failed", {
|
|
3135
3126
|
lifecycle: "failed",
|
|
@@ -3294,7 +3285,7 @@ export class Orchestrator {
|
|
|
3294
3285
|
status: "failed",
|
|
3295
3286
|
error: message,
|
|
3296
3287
|
});
|
|
3297
|
-
store.
|
|
3288
|
+
await store.writeYamlAsync(join(paths.attemptsDir, attemptId, "attempt.yaml"), AC.attemptFailureRecord(attemptId, adapter.id, failureCost, "harness", message, applied));
|
|
3298
3289
|
run = {
|
|
3299
3290
|
applied,
|
|
3300
3291
|
attemptId,
|
|
@@ -3550,7 +3541,7 @@ export class Orchestrator {
|
|
|
3550
3541
|
toCandidateEvidence(lastRun, contract, lastFindings, lastFinalReviewClean, actualReviewVerified),
|
|
3551
3542
|
], { ...arbitrationBudgetOptions(ledger), reviewRequested: contract.review_requested });
|
|
3552
3543
|
decision = arb.decision;
|
|
3553
|
-
store.
|
|
3544
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "decision.yaml"), decision);
|
|
3554
3545
|
// A converged run adopts the arbitration axes (checks/review); an
|
|
3555
3546
|
// otherwise not-converged loop that nonetheless produced an applyable
|
|
3556
3547
|
// decision adopts it too.
|
|
@@ -3626,7 +3617,7 @@ export class Orchestrator {
|
|
|
3626
3617
|
: { facts }),
|
|
3627
3618
|
final_verify: convFinalVerify,
|
|
3628
3619
|
};
|
|
3629
|
-
store.
|
|
3620
|
+
await store.writeYamlAsync(join(paths.arbitrationDir, "decision.yaml"), decision);
|
|
3630
3621
|
}
|
|
3631
3622
|
this.writeRunTelemetry(store, paths, contract, runId, taskId, mode, attemptTelemetries, lastRun?.attemptId ?? null);
|
|
3632
3623
|
// Deliver the converged/last work to final/ so `apply` and `inspect` can
|
|
@@ -3648,7 +3639,7 @@ export class Orchestrator {
|
|
|
3648
3639
|
});
|
|
3649
3640
|
}
|
|
3650
3641
|
else {
|
|
3651
|
-
const savedPatch = secretDiff.persistFinalPatch(store, paths.finalDir, lastRun);
|
|
3642
|
+
const savedPatch = await secretDiff.persistFinalPatch(store, paths.finalDir, lastRun);
|
|
3652
3643
|
const patchSha256 = savedPatch.patchSha256;
|
|
3653
3644
|
// Honest apply-state (parity with runRace single-candidate in-place): a
|
|
3654
3645
|
// convergence run with inPlace mutated the live tree directly across its
|
|
@@ -3662,7 +3653,7 @@ export class Orchestrator {
|
|
|
3662
3653
|
: "not_applied";
|
|
3663
3654
|
const revertAnchorId = convAdopted === true ? await anchors.turn(preTurnSha, lastPostTurnSha) : null;
|
|
3664
3655
|
const capturedNoGitChange = capturedNoGitChangeValue(lastRun);
|
|
3665
|
-
store.
|
|
3656
|
+
await store.writeYamlAsync(join(paths.finalDir, "work_product.yaml"), {
|
|
3666
3657
|
id: newId("wp"),
|
|
3667
3658
|
kind: "patch",
|
|
3668
3659
|
source_task_id: taskId,
|
|
@@ -3688,10 +3679,10 @@ export class Orchestrator {
|
|
|
3688
3679
|
}
|
|
3689
3680
|
// The exact answer is kept for every convergence result, patch or files.
|
|
3690
3681
|
if (lastRun.answerText) {
|
|
3691
|
-
store.
|
|
3682
|
+
await store.writeTextAsync(join(paths.finalDir, "answer.md"), lastRun.answerText);
|
|
3692
3683
|
log.emit("output.ready", { kind: "answer", path: "final/answer.md" });
|
|
3693
3684
|
}
|
|
3694
|
-
store.
|
|
3685
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `${withPoolAttempts(`# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Attempts: ${attempt}\n- Winner: ${lastRun.attemptId}\n- Review verified (cross-family): ${actualReviewVerified}\n- Apply recommendation: ${decision?.apply_recommendation ?? "inspect"}${stuckNoProgressReason ? `\n- No-progress reason: ${stuckNoProgressReason}` : ""}${convCause ? `\n- Failure: ${convCause}` : ""}${secretDiff.resultSummaryDisclosure(lastRun)}`, convPool)}\n`);
|
|
3695
3686
|
// Lifecycle invariant (all modes): output.ready precedes the terminal
|
|
3696
3687
|
// event so a client that applied the terminal event has the output.
|
|
3697
3688
|
log.emit("output.ready", {
|
|
@@ -3774,7 +3765,7 @@ export class Orchestrator {
|
|
|
3774
3765
|
// ARCHITECTURE event contract guarantees output.ready precedes the
|
|
3775
3766
|
// terminal in every mode.
|
|
3776
3767
|
if (!lastRun || (interrupted && input.inPlace !== true && !lastRun.files)) {
|
|
3777
|
-
store.
|
|
3768
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `${withPoolAttempts(`# Run ${runId} (${mode})\n\n- Lifecycle: ${facts.lifecycle}${facts.reason ? ` (${facts.reason})` : ""}\n- Attempts: ${attempt}`, convPool)}\n`);
|
|
3778
3769
|
log.emit("output.ready", {
|
|
3779
3770
|
kind: "summary",
|
|
3780
3771
|
path: "final/summary.md",
|
|
@@ -3918,7 +3909,7 @@ export class Orchestrator {
|
|
|
3918
3909
|
// contract validation runs BEFORE the run is announced (see runRace).
|
|
3919
3910
|
const contract = this.buildContract(input, taskId, "plan");
|
|
3920
3911
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
3921
|
-
const { store, paths, log, ledger } = beginAnnouncedRun({
|
|
3912
|
+
const { store, paths, log, ledger } = await beginAnnouncedRun({
|
|
3922
3913
|
input,
|
|
3923
3914
|
contract,
|
|
3924
3915
|
quotaSnapshots,
|
|
@@ -3930,7 +3921,7 @@ export class Orchestrator {
|
|
|
3930
3921
|
phase: "plan",
|
|
3931
3922
|
prompt: input.prompt,
|
|
3932
3923
|
}, announce);
|
|
3933
|
-
store.
|
|
3924
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
3934
3925
|
log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
|
|
3935
3926
|
// W3.3: ONE resolved read-only context — the routing point-probe and every
|
|
3936
3927
|
// planner spawn consume the SAME scoped env (see routeContext.ts).
|
|
@@ -3946,7 +3937,7 @@ export class Orchestrator {
|
|
|
3946
3937
|
adapters = await this.resolveCandidateAdapters({ ...input, n: undefined }, "plan", ledger, log, roHome, runId);
|
|
3947
3938
|
}
|
|
3948
3939
|
catch (err) {
|
|
3949
|
-
roHome.dispose();
|
|
3940
|
+
await roHome.dispose();
|
|
3950
3941
|
const message = safeErrorMessage(err);
|
|
3951
3942
|
writeRoutingFailureTerminal(store, paths, log, {
|
|
3952
3943
|
runId,
|
|
@@ -3973,16 +3964,16 @@ export class Orchestrator {
|
|
|
3973
3964
|
contextSection = await this.lazyContextSection(input, contract, store, paths, log);
|
|
3974
3965
|
}
|
|
3975
3966
|
catch (err) {
|
|
3976
|
-
roHome.dispose();
|
|
3967
|
+
await roHome.dispose();
|
|
3977
3968
|
const message = safeErrorMessage(err);
|
|
3978
|
-
store.
|
|
3969
|
+
await store.writeTextAsync(join(paths.contextDir, "context_error.md"), `# Context Error\n\n${message}\n`);
|
|
3979
3970
|
writeFailure(store, paths, {
|
|
3980
3971
|
phase: "context",
|
|
3981
3972
|
category: "project",
|
|
3982
3973
|
safeMessage: message,
|
|
3983
3974
|
runDir: paths.root,
|
|
3984
3975
|
});
|
|
3985
|
-
store.
|
|
3976
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (plan)\n\n- Lifecycle: failed\n- Phase: context\n\n${message}\n`);
|
|
3986
3977
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
3987
3978
|
log.emit("run.failed", {
|
|
3988
3979
|
lifecycle: "failed",
|
|
@@ -4095,7 +4086,7 @@ export class Orchestrator {
|
|
|
4095
4086
|
const text = outcome.text ?? "(no output)";
|
|
4096
4087
|
plans.push({ id: outcome.harnessId, text });
|
|
4097
4088
|
// The planner's own saved copy keeps its exact text (INV-146).
|
|
4098
|
-
store.
|
|
4089
|
+
await store.writeTextAsync(join(paths.root, "plans", `${outcome.harnessId}.md`), text + "\n");
|
|
4099
4090
|
// Solo planning (D31): the FIRST successful planner is the plan; later
|
|
4100
4091
|
// pool members are a sequential fallback chain (ask parity), not
|
|
4101
4092
|
// parallel co-authors. Council re-enables the multi-draft round.
|
|
@@ -4112,7 +4103,7 @@ export class Orchestrator {
|
|
|
4112
4103
|
}
|
|
4113
4104
|
finally {
|
|
4114
4105
|
// Planners done (or threw) — reclaim scoped scratch/API-route state.
|
|
4115
|
-
roHome.dispose();
|
|
4106
|
+
await roHome.dispose();
|
|
4116
4107
|
}
|
|
4117
4108
|
if (input.signal?.aborted) {
|
|
4118
4109
|
return cancelledResult(log, runId, taskId, "plan", paths.root, planAttempts.map((p) => ({
|
|
@@ -4282,7 +4273,7 @@ export class Orchestrator {
|
|
|
4282
4273
|
// recorded user intent is the CALLER's goal.
|
|
4283
4274
|
const contract = this.buildContract({ ...input, prompt: opts.contractIntent ?? prompt }, taskId, opts.mode);
|
|
4284
4275
|
const quotaSnapshots = this.quotaSnapshotPreflight();
|
|
4285
|
-
const { store, paths, log, ledger, runContext } = beginAnnouncedRun({
|
|
4276
|
+
const { store, paths, log, ledger, runContext } = await beginAnnouncedRun({
|
|
4286
4277
|
input,
|
|
4287
4278
|
contract,
|
|
4288
4279
|
quotaSnapshots,
|
|
@@ -4294,7 +4285,7 @@ export class Orchestrator {
|
|
|
4294
4285
|
phase: "report",
|
|
4295
4286
|
prompt,
|
|
4296
4287
|
}, announce);
|
|
4297
|
-
store.
|
|
4288
|
+
await store.writeYamlAsync(join(paths.contextDir, "task.yaml"), contract);
|
|
4298
4289
|
log.emit("task.contract.created", { task_contract_hash: hashJson(contract) });
|
|
4299
4290
|
// The ask/deep-scan report stays bare (its scouts read the tree themselves);
|
|
4300
4291
|
// no lazy ContextPack section is attached here.
|
|
@@ -4321,7 +4312,7 @@ export class Orchestrator {
|
|
|
4321
4312
|
}));
|
|
4322
4313
|
}
|
|
4323
4314
|
catch (err) {
|
|
4324
|
-
roHome.dispose();
|
|
4315
|
+
await roHome.dispose();
|
|
4325
4316
|
const message = safeErrorMessage(err);
|
|
4326
4317
|
writeRoutingFailureTerminal(store, paths, log, {
|
|
4327
4318
|
runId,
|
|
@@ -4549,7 +4540,7 @@ export class Orchestrator {
|
|
|
4549
4540
|
});
|
|
4550
4541
|
attemptTelemetries.push({ attemptId, harnessId: adapter.id, telemetry });
|
|
4551
4542
|
if (opts.deepScan) {
|
|
4552
|
-
store.
|
|
4543
|
+
await store.writeTextAsync(join(paths.findingsDir, `${attemptId}-error.md`), `# Explorer ${attemptId} failed\n\n${message}\n`);
|
|
4553
4544
|
}
|
|
4554
4545
|
return { status: "launched" };
|
|
4555
4546
|
}
|
|
@@ -4618,6 +4609,7 @@ export class Orchestrator {
|
|
|
4618
4609
|
...(knobs.ignored.length > 0 ? { ignored_settings: knobs.ignored } : {}),
|
|
4619
4610
|
});
|
|
4620
4611
|
try {
|
|
4612
|
+
const pacing = { waiting: false, version: 0 };
|
|
4621
4613
|
const watchedReport = withInactivityWatchdog(runModelGovernedRoute(routed, runSpec), {
|
|
4622
4614
|
timeoutMs: harnessInactivityTimeoutMs(this.config(input.repoRoot)),
|
|
4623
4615
|
countsAsProgress: countsAsAgentProgress,
|
|
@@ -4625,11 +4617,12 @@ export class Orchestrator {
|
|
|
4625
4617
|
tryAbort.abort();
|
|
4626
4618
|
void adapter.cancel?.(activeSessionId)?.catch(() => { });
|
|
4627
4619
|
},
|
|
4628
|
-
|
|
4629
|
-
suspensionVersion: () => reportInteraction?.suspensionVersion?.() ?? 0,
|
|
4620
|
+
...laneSuspension(pacing, reportInteraction),
|
|
4630
4621
|
stopSignal: input.signal, // after Stop: drained events are recorded, never used
|
|
4631
4622
|
});
|
|
4632
|
-
|
|
4623
|
+
const files = [paths.eventsPath, attemptEventsPath];
|
|
4624
|
+
const read = pacedByAppends(watchedReport, files, pacing);
|
|
4625
|
+
for await (const ev of read) {
|
|
4633
4626
|
// A read after Stop is stored evidence only; a callback may itself press Stop.
|
|
4634
4627
|
const shown = !input.signal?.aborted && ev.payload?.["buffered"] !== true;
|
|
4635
4628
|
if (shown)
|
|
@@ -4814,7 +4807,7 @@ export class Orchestrator {
|
|
|
4814
4807
|
});
|
|
4815
4808
|
launched.delete(tried);
|
|
4816
4809
|
if (opts.deepScan) {
|
|
4817
|
-
store.
|
|
4810
|
+
await store.writeTextAsync(join(paths.findingsDir, `${attemptId}-error.md`), `# Explorer ${attemptId} failed\n\n${harnessError}\n`);
|
|
4818
4811
|
}
|
|
4819
4812
|
return { status: "launched" };
|
|
4820
4813
|
}
|
|
@@ -4846,7 +4839,7 @@ export class Orchestrator {
|
|
|
4846
4839
|
const scoutTag = scoutInterrupted
|
|
4847
4840
|
? ` interrupted (${interruptionDetail(roFinalized.reason)})`
|
|
4848
4841
|
: ` (${adapter.id})`;
|
|
4849
|
-
store.
|
|
4842
|
+
await store.writeTextAsync(join(paths.findingsDir, `${attemptId}${scoutInterrupted ? "-interrupted" : ""}.md`), `# Explorer ${attemptId}${scoutTag}\n\n${report || "(no output)"}${warningNote}\n`);
|
|
4850
4843
|
}
|
|
4851
4844
|
return { status: "launched" };
|
|
4852
4845
|
};
|
|
@@ -4991,7 +4984,7 @@ export class Orchestrator {
|
|
|
4991
4984
|
finally {
|
|
4992
4985
|
// All read-only attempts done (or threw) — reclaim scoped scratch and
|
|
4993
4986
|
// injected API-route state. Vendor-owned native credentials were not copied.
|
|
4994
|
-
roHome.dispose();
|
|
4987
|
+
await roHome.dispose();
|
|
4995
4988
|
}
|
|
4996
4989
|
const candidateSummaries = attempts.map((a) => ({
|
|
4997
4990
|
attemptId: a.attemptId,
|
|
@@ -5047,7 +5040,7 @@ export class Orchestrator {
|
|
|
5047
5040
|
: reducedReport !== null
|
|
5048
5041
|
? reducedReport
|
|
5049
5042
|
: rawScoutBundle({ succeeded, unsuccessful, status: deepScanSynthesis });
|
|
5050
|
-
store.
|
|
5043
|
+
await store.writeTextAsync(join(paths.finalDir, opts.artifactName), `# ${opts.title}\n\n${report}\n`);
|
|
5051
5044
|
// ask is the only read-only strategy that can carry a structured-output
|
|
5052
5045
|
// contract (the boundary refuses the rest); validate the FINAL aggregate
|
|
5053
5046
|
// (the reduced synthesis, or the honest bundle for a degraded scan) — never
|
|
@@ -5068,7 +5061,7 @@ export class Orchestrator {
|
|
|
5068
5061
|
path: `final/${opts.artifactName}`,
|
|
5069
5062
|
});
|
|
5070
5063
|
if (opts.deepScan) {
|
|
5071
|
-
store.
|
|
5064
|
+
await store.writeYamlAsync(join(paths.finalDir, "explore-findings.yaml"), {
|
|
5072
5065
|
mode: "explore",
|
|
5073
5066
|
width,
|
|
5074
5067
|
attempts: attempts.map((a) => ({
|
|
@@ -5087,7 +5080,7 @@ export class Orchestrator {
|
|
|
5087
5080
|
})),
|
|
5088
5081
|
read_only: true,
|
|
5089
5082
|
});
|
|
5090
|
-
store.
|
|
5083
|
+
await store.writeTextAsync(join(paths.finalDir, "omissions.md"), `# Omissions\n\n${unsuccessful.map((a) => `- ${a.attemptId} / ${a.harnessId} (${a.status}): ${a.error}`).join("\n") || "- None recorded by the runner. Synthesis claims still require evidence checks."}\n`);
|
|
5091
5084
|
}
|
|
5092
5085
|
let terminalFacts = makeOutcomeFacts("succeeded");
|
|
5093
5086
|
const reportBudgetTerminal = ledger.terminal();
|
|
@@ -5116,13 +5109,13 @@ export class Orchestrator {
|
|
|
5116
5109
|
.join(", ");
|
|
5117
5110
|
// A delivered report that still ends unsuccessfully or blocked keeps it and names every failed try.
|
|
5118
5111
|
const reportPool = terminalPoolAttempts(terminalFacts, attempts);
|
|
5119
|
-
store.
|
|
5112
|
+
await store.writeTextAsync(join(paths.finalDir, "summary.md"), `# Run ${runId} (${opts.mode})\n\n- Harnesses: ${harnessLabel}\n- Lifecycle: ${terminalFacts.lifecycle}${terminalFacts.reason ? ` (${terminalFacts.reason})` : ""}\n\n${withPoolAttempts(report, reportPool)}\n`);
|
|
5120
5113
|
const reportProducerAttemptId = opts.deepScan &&
|
|
5121
5114
|
deepScanSynthesis?.status === "succeeded" &&
|
|
5122
5115
|
deepScanSynthesis.reducer_attempt_id
|
|
5123
5116
|
? deepScanSynthesis.reducer_attempt_id
|
|
5124
5117
|
: (succeeded[0]?.attemptId ?? "a01");
|
|
5125
|
-
store.
|
|
5118
|
+
await store.writeYamlAsync(join(paths.finalDir, "work_product.yaml"), {
|
|
5126
5119
|
id: newId("wp"),
|
|
5127
5120
|
kind: "report",
|
|
5128
5121
|
source_task_id: taskId,
|