@nathapp/nax 0.67.15 → 0.67.17
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/nax.js +157 -24
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -52720,6 +52720,65 @@ var init_context2 = __esm(() => {
|
|
|
52720
52720
|
});
|
|
52721
52721
|
|
|
52722
52722
|
// src/execution/story-orchestrator.ts
|
|
52723
|
+
async function refreshReviewInputForDispatch(opName, input) {
|
|
52724
|
+
if (opName !== "semantic-review" && opName !== "adversarial-review")
|
|
52725
|
+
return input;
|
|
52726
|
+
const i = input;
|
|
52727
|
+
const { _refresh } = i;
|
|
52728
|
+
if (!_refresh || !i.workdir)
|
|
52729
|
+
return input;
|
|
52730
|
+
try {
|
|
52731
|
+
if (opName === "semantic-review") {
|
|
52732
|
+
const { _refresh: _, ...semInput } = input;
|
|
52733
|
+
const fresh2 = await _storyOrchestratorDeps.prepareSemanticReviewInput({
|
|
52734
|
+
workdir: semInput.workdir,
|
|
52735
|
+
projectDir: _refresh.projectDir,
|
|
52736
|
+
storyId: _refresh.storyId,
|
|
52737
|
+
storyGitRef: _refresh.storyGitRef,
|
|
52738
|
+
config: _refresh.config,
|
|
52739
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
52740
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
52741
|
+
semanticConfig: semInput.semanticConfig
|
|
52742
|
+
});
|
|
52743
|
+
return {
|
|
52744
|
+
...semInput,
|
|
52745
|
+
stat: fresh2.stat,
|
|
52746
|
+
diff: fresh2.diff,
|
|
52747
|
+
excludePatterns: fresh2.excludePatterns,
|
|
52748
|
+
storyGitRef: fresh2.effectiveRef ?? semInput.storyGitRef
|
|
52749
|
+
};
|
|
52750
|
+
}
|
|
52751
|
+
const { _refresh: __, ...advInput } = input;
|
|
52752
|
+
const fresh = await _storyOrchestratorDeps.prepareAdversarialReviewInput({
|
|
52753
|
+
workdir: advInput.workdir,
|
|
52754
|
+
projectDir: _refresh.projectDir,
|
|
52755
|
+
storyId: _refresh.storyId,
|
|
52756
|
+
storyGitRef: _refresh.storyGitRef,
|
|
52757
|
+
config: _refresh.config,
|
|
52758
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
52759
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
52760
|
+
adversarialConfig: advInput.adversarialConfig
|
|
52761
|
+
});
|
|
52762
|
+
return {
|
|
52763
|
+
...advInput,
|
|
52764
|
+
stat: fresh.stat,
|
|
52765
|
+
diff: fresh.diff,
|
|
52766
|
+
testInventory: fresh.testInventory,
|
|
52767
|
+
excludePatterns: fresh.excludePatterns,
|
|
52768
|
+
testGlobs: fresh.testGlobs,
|
|
52769
|
+
refExcludePatterns: fresh.refExcludePatterns,
|
|
52770
|
+
storyGitRef: fresh.effectiveRef ?? advInput.storyGitRef
|
|
52771
|
+
};
|
|
52772
|
+
} catch (err) {
|
|
52773
|
+
getSafeLogger()?.warn("story-orchestrator", "review input refresh failed \u2014 dispatching with stale input", {
|
|
52774
|
+
storyId: _refresh.storyId,
|
|
52775
|
+
phase: opName,
|
|
52776
|
+
error: errorMessage(err)
|
|
52777
|
+
});
|
|
52778
|
+
const { _refresh: _stripped, ...fallback } = input;
|
|
52779
|
+
return fallback;
|
|
52780
|
+
}
|
|
52781
|
+
}
|
|
52723
52782
|
function formatPhaseResultMessage(opName, success2) {
|
|
52724
52783
|
if (opName === "greenfield-gate") {
|
|
52725
52784
|
return success2 ? "Greenfield-gate: pre-existing tests detected (not greenfield) \u2014 proceeding with normal TDD" : "Greenfield-gate: no pre-existing tests \u2014 greenfield run, pausing TDD test-writer";
|
|
@@ -52995,7 +53054,8 @@ async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = fa
|
|
|
52995
53054
|
const opName = slot.op.name;
|
|
52996
53055
|
const isTddPhase = isThreeSession && TDD_OP_NAMES.has(opName);
|
|
52997
53056
|
const beforeRef = isTddPhase ? await _storyOrchestratorDeps.captureGitRef(ctx.packageDir) : undefined;
|
|
52998
|
-
|
|
53057
|
+
let dispatchInput = isTddPhase && beforeRef ? { ...slot.input, beforeRef } : slot.input;
|
|
53058
|
+
dispatchInput = await refreshReviewInputForDispatch(opName, dispatchInput);
|
|
52999
53059
|
if (isTddPhase) {
|
|
53000
53060
|
logger?.info("tdd", `-> Session: ${opName}`, { storyId: ctx.storyId, role: opName });
|
|
53001
53061
|
} else if (isThreeSession && opName === "full-suite-gate") {
|
|
@@ -53106,7 +53166,15 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
|
|
|
53106
53166
|
await runPhase(ctx, phase.slot, phaseCosts, phaseOutputs);
|
|
53107
53167
|
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
53108
53168
|
continue;
|
|
53109
|
-
|
|
53169
|
+
const output = phaseOutputs[phase.slot.op.name];
|
|
53170
|
+
findings.push(...extractPhaseFindings(output));
|
|
53171
|
+
if (!phasePassed(phase.slot.op.name, output, ctx.storyId)) {
|
|
53172
|
+
getSafeLogger()?.warn("story-orchestrator", "Short-circuiting revalidation on phase failure", {
|
|
53173
|
+
storyId: ctx.storyId,
|
|
53174
|
+
phase: phase.slot.op.name
|
|
53175
|
+
});
|
|
53176
|
+
break;
|
|
53177
|
+
}
|
|
53110
53178
|
}
|
|
53111
53179
|
return rectification.postValidate ? await rectification.postValidate(findings, _validateCtx) : findings;
|
|
53112
53180
|
}
|
|
@@ -53137,14 +53205,7 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
|
|
|
53137
53205
|
storyId: ctx.storyId
|
|
53138
53206
|
});
|
|
53139
53207
|
}
|
|
53140
|
-
|
|
53141
|
-
"max-attempts-total",
|
|
53142
|
-
"max-attempts-per-strategy",
|
|
53143
|
-
"bail-when",
|
|
53144
|
-
"no-strategy",
|
|
53145
|
-
"agent-gave-up"
|
|
53146
|
-
]);
|
|
53147
|
-
if (exhaustedReasons.has(cycleResult.exitReason) && cycleResult.finalFindings.length > 0) {
|
|
53208
|
+
if (EXHAUSTED_EXIT_REASONS.has(cycleResult.exitReason) && cycleResult.finalFindings.length > 0) {
|
|
53148
53209
|
return { rectificationExhausted: true, unfixedFindings: cycleResult.finalFindings };
|
|
53149
53210
|
}
|
|
53150
53211
|
return {};
|
|
@@ -53191,6 +53252,50 @@ class ExecutionPlan {
|
|
|
53191
53252
|
}
|
|
53192
53253
|
}
|
|
53193
53254
|
const rectResult = await runRectification(this.ctx, this.state, phaseCosts, phaseOutputs);
|
|
53255
|
+
if (this.state.rectification && !rectResult.rectificationExhausted) {
|
|
53256
|
+
let resumeRectifyUsed = false;
|
|
53257
|
+
for (const phase of collectOrderedPhases(this.state)) {
|
|
53258
|
+
const name = phase.slot.op.name;
|
|
53259
|
+
if (name in phaseOutputs && phasePassed(name, phaseOutputs[name], this.ctx.storyId)) {
|
|
53260
|
+
continue;
|
|
53261
|
+
}
|
|
53262
|
+
try {
|
|
53263
|
+
await runPhase(this.ctx, phase.slot, phaseCosts, phaseOutputs, this.isThreeSession);
|
|
53264
|
+
} catch (error48) {
|
|
53265
|
+
logger?.error("story-orchestrator", "Phase threw unexpected error (post-rectification resume)", {
|
|
53266
|
+
storyId: this.ctx.storyId,
|
|
53267
|
+
phase: name,
|
|
53268
|
+
error: errorMessage(error48)
|
|
53269
|
+
});
|
|
53270
|
+
throw error48;
|
|
53271
|
+
}
|
|
53272
|
+
if (!phasePassed(name, phaseOutputs[name], this.ctx.storyId)) {
|
|
53273
|
+
if (!resumeRectifyUsed) {
|
|
53274
|
+
resumeRectifyUsed = true;
|
|
53275
|
+
logger?.info("story-orchestrator", "Phase failed in post-rectification resume \u2014 invoking second rectification pass", { storyId: this.ctx.storyId, phase: name, source: "post-rectification-resume" });
|
|
53276
|
+
const secondRect = await runRectification(this.ctx, this.state, phaseCosts, phaseOutputs);
|
|
53277
|
+
if (secondRect.rectificationExhausted) {
|
|
53278
|
+
logger?.warn("story-orchestrator", "Second rectification pass exhausted \u2014 terminal failure", {
|
|
53279
|
+
storyId: this.ctx.storyId,
|
|
53280
|
+
phase: name,
|
|
53281
|
+
source: "post-rectification-resume"
|
|
53282
|
+
});
|
|
53283
|
+
break;
|
|
53284
|
+
}
|
|
53285
|
+
if (phasePassed(name, phaseOutputs[name], this.ctx.storyId)) {
|
|
53286
|
+
continue;
|
|
53287
|
+
}
|
|
53288
|
+
}
|
|
53289
|
+
logger?.warn("story-orchestrator", "Terminal phase failure (post-rectification resume \u2014 bypasses rectification)", {
|
|
53290
|
+
storyId: this.ctx.storyId,
|
|
53291
|
+
phase: name,
|
|
53292
|
+
source: "post-rectification-resume",
|
|
53293
|
+
secondRectifyUsed: resumeRectifyUsed
|
|
53294
|
+
});
|
|
53295
|
+
break;
|
|
53296
|
+
}
|
|
53297
|
+
}
|
|
53298
|
+
}
|
|
53194
53299
|
const verifierName = this.state.verifier?.slot.op.name;
|
|
53195
53300
|
const gateName = this.state.fullSuiteGate?.slot.op.name;
|
|
53196
53301
|
const verifierPassedSsot = verifierName !== undefined && phaseExplicitlyPassed(phaseOutputs[verifierName]);
|
|
@@ -53290,19 +53395,29 @@ class StoryOrchestratorBuilder {
|
|
|
53290
53395
|
return new ExecutionPlan(ctx, { ...this.state }, opts.isThreeSession ?? false);
|
|
53291
53396
|
}
|
|
53292
53397
|
}
|
|
53293
|
-
var _storyOrchestratorDeps, TDD_OP_NAMES, STRICT_VERDICT_PHASE_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY, STRATEGY_TO_REVALIDATION_PHASES;
|
|
53398
|
+
var _storyOrchestratorDeps, EXHAUSTED_EXIT_REASONS, TDD_OP_NAMES, STRICT_VERDICT_PHASE_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY, STRATEGY_TO_REVALIDATION_PHASES;
|
|
53294
53399
|
var init_story_orchestrator = __esm(() => {
|
|
53295
53400
|
init_errors();
|
|
53296
53401
|
init_findings();
|
|
53297
53402
|
init_logger2();
|
|
53298
53403
|
init_operations();
|
|
53299
53404
|
init_call();
|
|
53405
|
+
init_prepare_inputs();
|
|
53300
53406
|
init_git();
|
|
53301
53407
|
_storyOrchestratorDeps = {
|
|
53302
53408
|
callOp,
|
|
53303
53409
|
runFixCycle,
|
|
53304
|
-
captureGitRef
|
|
53410
|
+
captureGitRef,
|
|
53411
|
+
prepareSemanticReviewInput,
|
|
53412
|
+
prepareAdversarialReviewInput
|
|
53305
53413
|
};
|
|
53414
|
+
EXHAUSTED_EXIT_REASONS = new Set([
|
|
53415
|
+
"max-attempts-total",
|
|
53416
|
+
"max-attempts-per-strategy",
|
|
53417
|
+
"bail-when",
|
|
53418
|
+
"no-strategy",
|
|
53419
|
+
"agent-gave-up"
|
|
53420
|
+
]);
|
|
53306
53421
|
TDD_OP_NAMES = new Set(["test-writer", "implementer", "verifier"]);
|
|
53307
53422
|
STRICT_VERDICT_PHASE_NAMES = new Set([
|
|
53308
53423
|
fullSuiteGateOp.name,
|
|
@@ -53601,8 +53716,6 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
53601
53716
|
resolvedTestPatterns,
|
|
53602
53717
|
semanticConfig: ctx.config.review.semantic
|
|
53603
53718
|
});
|
|
53604
|
-
if (prepared.skipReason)
|
|
53605
|
-
return;
|
|
53606
53719
|
return {
|
|
53607
53720
|
workdir: ctx.workdir,
|
|
53608
53721
|
story,
|
|
@@ -53614,7 +53727,15 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
53614
53727
|
excludePatterns: prepared.excludePatterns,
|
|
53615
53728
|
featureCtxBlock: buildFeatureCtxBlock(ctx, "reviewer-semantic"),
|
|
53616
53729
|
priorSemanticIterations: ctx.priorSemanticIterations,
|
|
53617
|
-
blockingThreshold: ctx.config.review.blockingThreshold
|
|
53730
|
+
blockingThreshold: ctx.config.review.blockingThreshold,
|
|
53731
|
+
_refresh: {
|
|
53732
|
+
projectDir: ctx.projectDir,
|
|
53733
|
+
storyId: story.id,
|
|
53734
|
+
storyGitRef: ctx.storyGitRef,
|
|
53735
|
+
config: ctx.config,
|
|
53736
|
+
naxIgnoreIndex: ctx.naxIgnoreIndex,
|
|
53737
|
+
resolvedTestPatterns
|
|
53738
|
+
}
|
|
53618
53739
|
};
|
|
53619
53740
|
})() : undefined;
|
|
53620
53741
|
const adversarialEnabled = ctx.config.review?.enabled === true && ctx.config.review.checks?.includes("adversarial") && !!ctx.config.review.adversarial;
|
|
@@ -53629,8 +53750,6 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
53629
53750
|
resolvedTestPatterns,
|
|
53630
53751
|
adversarialConfig: ctx.config.review.adversarial
|
|
53631
53752
|
});
|
|
53632
|
-
if (prepared.skipReason)
|
|
53633
|
-
return;
|
|
53634
53753
|
return {
|
|
53635
53754
|
workdir: ctx.workdir,
|
|
53636
53755
|
story,
|
|
@@ -53645,7 +53764,15 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
53645
53764
|
refExcludePatterns: prepared.refExcludePatterns,
|
|
53646
53765
|
featureCtxBlock: buildFeatureCtxBlock(ctx, "reviewer-adversarial"),
|
|
53647
53766
|
priorAdversarialIterations: ctx.priorAdversarialIterations,
|
|
53648
|
-
blockingThreshold: ctx.config.review.blockingThreshold
|
|
53767
|
+
blockingThreshold: ctx.config.review.blockingThreshold,
|
|
53768
|
+
_refresh: {
|
|
53769
|
+
projectDir: ctx.projectDir,
|
|
53770
|
+
storyId: story.id,
|
|
53771
|
+
storyGitRef: ctx.storyGitRef,
|
|
53772
|
+
config: ctx.config,
|
|
53773
|
+
naxIgnoreIndex: ctx.naxIgnoreIndex,
|
|
53774
|
+
resolvedTestPatterns
|
|
53775
|
+
}
|
|
53649
53776
|
};
|
|
53650
53777
|
})() : undefined;
|
|
53651
53778
|
const rectificationInput = ctx.config.execution?.rectification?.enabled === true ? {
|
|
@@ -53839,7 +53966,7 @@ function extractPauseReason(phaseOutputs) {
|
|
|
53839
53966
|
}
|
|
53840
53967
|
return;
|
|
53841
53968
|
}
|
|
53842
|
-
function deriveTddFailureCategory(phaseOutputs) {
|
|
53969
|
+
function deriveTddFailureCategory(phaseOutputs, unfixedFindings) {
|
|
53843
53970
|
const testWriterOutput = phaseOutputs[testWriterOp.name];
|
|
53844
53971
|
if (testWriterOutput?.success === false) {
|
|
53845
53972
|
return "session-failure";
|
|
@@ -53856,6 +53983,12 @@ function deriveTddFailureCategory(phaseOutputs) {
|
|
|
53856
53983
|
return "tests-failing";
|
|
53857
53984
|
}
|
|
53858
53985
|
const verifierPassed = verifierOutput?.success === true;
|
|
53986
|
+
if (!verifierPassed && unfixedFindings && unfixedFindings.length > 0) {
|
|
53987
|
+
const rectOutput = phaseOutputs.rectification;
|
|
53988
|
+
if (rectOutput?.exitReason && EXHAUSTED_EXIT_REASONS.has(rectOutput.exitReason) && unfixedFindings.some((f) => f.source === "test-runner")) {
|
|
53989
|
+
return "full-suite-gate-exhausted";
|
|
53990
|
+
}
|
|
53991
|
+
}
|
|
53859
53992
|
if (!verifierPassed) {
|
|
53860
53993
|
const gateOutput = phaseOutputs[fullSuiteGateOp.name];
|
|
53861
53994
|
if (gateOutput && (gateOutput.success === false || gateOutput.passed === false)) {
|
|
@@ -53888,7 +54021,6 @@ async function applyPostRunInspection(ctx, planResult, opts) {
|
|
|
53888
54021
|
...capturedTokenUsage ? { tokenUsage: capturedTokenUsage } : {}
|
|
53889
54022
|
};
|
|
53890
54023
|
ctx.agentResult = agentResult;
|
|
53891
|
-
ctx.agentSwapCount = 0;
|
|
53892
54024
|
const fullSuiteGateOutput = planResult.phaseOutputs[fullSuiteGateOp.name];
|
|
53893
54025
|
if (fullSuiteGateOutput?.passed) {
|
|
53894
54026
|
ctx.fullSuiteGatePassed = true;
|
|
@@ -53959,7 +54091,7 @@ async function applyPostRunInspection(ctx, planResult, opts) {
|
|
|
53959
54091
|
}
|
|
53960
54092
|
}
|
|
53961
54093
|
const pauseReason = extractPauseReason(planResult.phaseOutputs);
|
|
53962
|
-
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs) : undefined;
|
|
54094
|
+
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs, planResult.unfixedFindings) : undefined;
|
|
53963
54095
|
if (isTdd && !planResult.success && !failureCategory) {
|
|
53964
54096
|
const phaseSignals = {};
|
|
53965
54097
|
for (const [name, output] of Object.entries(planResult.phaseOutputs)) {
|
|
@@ -54178,6 +54310,7 @@ var init_post_run = __esm(() => {
|
|
|
54178
54310
|
init_scratch_writer();
|
|
54179
54311
|
init_rollback();
|
|
54180
54312
|
init_git();
|
|
54313
|
+
init_story_orchestrator();
|
|
54181
54314
|
_postRunDeps = {
|
|
54182
54315
|
detectMergeConflict,
|
|
54183
54316
|
checkMergeConflict,
|
|
@@ -57700,7 +57833,7 @@ var package_default;
|
|
|
57700
57833
|
var init_package = __esm(() => {
|
|
57701
57834
|
package_default = {
|
|
57702
57835
|
name: "@nathapp/nax",
|
|
57703
|
-
version: "0.67.
|
|
57836
|
+
version: "0.67.17",
|
|
57704
57837
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
57705
57838
|
type: "module",
|
|
57706
57839
|
bin: {
|
|
@@ -57795,8 +57928,8 @@ var init_version = __esm(() => {
|
|
|
57795
57928
|
NAX_VERSION = package_default.version;
|
|
57796
57929
|
NAX_COMMIT = (() => {
|
|
57797
57930
|
try {
|
|
57798
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
57799
|
-
return "
|
|
57931
|
+
if (/^[0-9a-f]{6,10}$/.test("74621ad5"))
|
|
57932
|
+
return "74621ad5";
|
|
57800
57933
|
} catch {}
|
|
57801
57934
|
try {
|
|
57802
57935
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|