@nathapp/nax 0.67.14 → 0.67.16

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.
Files changed (2) hide show
  1. package/dist/nax.js +158 -32
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -52720,6 +52720,71 @@ 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
+ }
52782
+ function formatPhaseResultMessage(opName, success2) {
52783
+ if (opName === "greenfield-gate") {
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";
52785
+ }
52786
+ return success2 ? `Phase passed: ${opName}` : `Phase failed: ${opName}`;
52787
+ }
52723
52788
  function isSlot(value) {
52724
52789
  return value !== null && typeof value === "object" && "op" in value && "input" in value && typeof value.op?.kind === "string";
52725
52790
  }
@@ -52832,19 +52897,18 @@ function collectRectificationPhases(state) {
52832
52897
  ].filter((phase) => phase !== undefined);
52833
52898
  }
52834
52899
  function phasesToRevalidate(strategiesRun, allPhases) {
52835
- const sourceFiltered = allPhases.filter((p) => p.kind !== "verifier");
52836
52900
  if (!strategiesRun || strategiesRun.length === 0)
52837
- return sourceFiltered;
52901
+ return allPhases;
52838
52902
  const unknown2 = strategiesRun.some((name) => STRATEGY_TO_REVALIDATION_PHASES[name] === undefined);
52839
52903
  if (unknown2)
52840
- return sourceFiltered;
52904
+ return allPhases;
52841
52905
  const needed = new Set;
52842
52906
  for (const name of strategiesRun) {
52843
52907
  for (const kind of STRATEGY_TO_REVALIDATION_PHASES[name] ?? []) {
52844
52908
  needed.add(kind);
52845
52909
  }
52846
52910
  }
52847
- return sourceFiltered.filter((p) => needed.has(p.kind));
52911
+ return allPhases.filter((p) => needed.has(p.kind));
52848
52912
  }
52849
52913
  function toReviewDecisionPayload(opName, output) {
52850
52914
  if (output === null || output === undefined || typeof output !== "object")
@@ -52928,10 +52992,11 @@ function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTdd
52928
52992
  data.findingsCount = findingsCount;
52929
52993
  if (status !== undefined)
52930
52994
  data.status = status;
52995
+ const message = formatPhaseResultMessage(opName, success2);
52931
52996
  if (success2) {
52932
- logger?.info("story-orchestrator", `Phase passed: ${opName}`, data);
52997
+ logger?.info("story-orchestrator", message, data);
52933
52998
  } else {
52934
- logger?.warn("story-orchestrator", `Phase failed: ${opName}`, data);
52999
+ logger?.warn("story-orchestrator", message, data);
52935
53000
  }
52936
53001
  }
52937
53002
  function logUnifiedReviewPhaseResult(storyId, opName, output) {
@@ -52989,7 +53054,8 @@ async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = fa
52989
53054
  const opName = slot.op.name;
52990
53055
  const isTddPhase = isThreeSession && TDD_OP_NAMES.has(opName);
52991
53056
  const beforeRef = isTddPhase ? await _storyOrchestratorDeps.captureGitRef(ctx.packageDir) : undefined;
52992
- const dispatchInput = isTddPhase && beforeRef ? { ...slot.input, beforeRef } : slot.input;
53057
+ let dispatchInput = isTddPhase && beforeRef ? { ...slot.input, beforeRef } : slot.input;
53058
+ dispatchInput = await refreshReviewInputForDispatch(opName, dispatchInput);
52993
53059
  if (isTddPhase) {
52994
53060
  logger?.info("tdd", `-> Session: ${opName}`, { storyId: ctx.storyId, role: opName });
52995
53061
  } else if (isThreeSession && opName === "full-suite-gate") {
@@ -53100,13 +53166,26 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
53100
53166
  await runPhase(ctx, phase.slot, phaseCosts, phaseOutputs);
53101
53167
  if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
53102
53168
  continue;
53103
- findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
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
+ }
53104
53178
  }
53105
53179
  return rectification.postValidate ? await rectification.postValidate(findings, _validateCtx) : findings;
53106
53180
  }
53107
53181
  };
53108
53182
  const cycleResult = await _storyOrchestratorDeps.runFixCycle(cycle, ctx, "story-orchestrator-rectification", { callOp: wrappedCallOp });
53109
- phaseOutputs.rectification = { iterationCount: cycleResult.iterations.length };
53183
+ phaseOutputs.rectification = {
53184
+ success: cycleResult.exitReason === "resolved",
53185
+ iterationCount: cycleResult.iterations.length,
53186
+ exitReason: cycleResult.exitReason,
53187
+ finalFindingsCount: cycleResult.finalFindings.length
53188
+ };
53110
53189
  const rectLogger = getSafeLogger();
53111
53190
  const rectSummary = {
53112
53191
  storyId: ctx.storyId,
@@ -53160,13 +53239,6 @@ class ExecutionPlan {
53160
53239
  const phaseOutputs = {};
53161
53240
  const startedAt = Date.now();
53162
53241
  const logger = getSafeLogger();
53163
- const verifierPresent = this.state.verifier !== undefined;
53164
- const rectificationExempt = this.state.rectification ? [
53165
- ...this.state.fullSuiteGate ? [this.state.fullSuiteGate.slot.op.name] : [],
53166
- ...this.state.verifier ? [this.state.verifier.slot.op.name] : []
53167
- ] : [];
53168
- const verifierExempt = verifierPresent && this.state.fullSuiteGate ? [this.state.fullSuiteGate.slot.op.name] : [];
53169
- const shortCircuitExempt = new Set([...rectificationExempt, ...verifierExempt]);
53170
53242
  for (const phase of collectOrderedPhases(this.state)) {
53171
53243
  try {
53172
53244
  await runPhase(this.ctx, phase.slot, phaseCosts, phaseOutputs, this.isThreeSession);
@@ -53179,16 +53251,40 @@ class ExecutionPlan {
53179
53251
  throw error48;
53180
53252
  }
53181
53253
  if (!phasePassed(phase.slot.op.name, phaseOutputs[phase.slot.op.name], this.ctx.storyId)) {
53182
- if (!shortCircuitExempt.has(phase.slot.op.name)) {
53183
- logger?.warn("story-orchestrator", "Short-circuiting on phase failure", {
53254
+ logger?.warn("story-orchestrator", "Short-circuiting on phase failure", {
53255
+ storyId: this.ctx.storyId,
53256
+ phase: phase.slot.op.name
53257
+ });
53258
+ break;
53259
+ }
53260
+ }
53261
+ const rectResult = await runRectification(this.ctx, this.state, phaseCosts, phaseOutputs);
53262
+ if (this.state.rectification && !rectResult.rectificationExhausted) {
53263
+ for (const phase of collectOrderedPhases(this.state)) {
53264
+ const name = phase.slot.op.name;
53265
+ if (name in phaseOutputs && phasePassed(name, phaseOutputs[name], this.ctx.storyId)) {
53266
+ continue;
53267
+ }
53268
+ try {
53269
+ await runPhase(this.ctx, phase.slot, phaseCosts, phaseOutputs, this.isThreeSession);
53270
+ } catch (error48) {
53271
+ logger?.error("story-orchestrator", "Phase threw unexpected error (post-rectification resume)", {
53184
53272
  storyId: this.ctx.storyId,
53185
- phase: phase.slot.op.name
53273
+ phase: name,
53274
+ error: errorMessage(error48)
53275
+ });
53276
+ throw error48;
53277
+ }
53278
+ if (!phasePassed(name, phaseOutputs[name], this.ctx.storyId)) {
53279
+ logger?.warn("story-orchestrator", "Terminal phase failure (post-rectification resume \u2014 bypasses rectification)", {
53280
+ storyId: this.ctx.storyId,
53281
+ phase: name,
53282
+ source: "post-rectification-resume"
53186
53283
  });
53187
53284
  break;
53188
53285
  }
53189
53286
  }
53190
53287
  }
53191
- const rectResult = await runRectification(this.ctx, this.state, phaseCosts, phaseOutputs);
53192
53288
  const verifierName = this.state.verifier?.slot.op.name;
53193
53289
  const gateName = this.state.fullSuiteGate?.slot.op.name;
53194
53290
  const verifierPassedSsot = verifierName !== undefined && phaseExplicitlyPassed(phaseOutputs[verifierName]);
@@ -53295,11 +53391,14 @@ var init_story_orchestrator = __esm(() => {
53295
53391
  init_logger2();
53296
53392
  init_operations();
53297
53393
  init_call();
53394
+ init_prepare_inputs();
53298
53395
  init_git();
53299
53396
  _storyOrchestratorDeps = {
53300
53397
  callOp,
53301
53398
  runFixCycle,
53302
- captureGitRef
53399
+ captureGitRef,
53400
+ prepareSemanticReviewInput,
53401
+ prepareAdversarialReviewInput
53303
53402
  };
53304
53403
  TDD_OP_NAMES = new Set(["test-writer", "implementer", "verifier"]);
53305
53404
  STRICT_VERDICT_PHASE_NAMES = new Set([
@@ -53340,12 +53439,27 @@ var init_story_orchestrator = __esm(() => {
53340
53439
  "lint-check",
53341
53440
  "typecheck-check",
53342
53441
  "full-suite-gate",
53442
+ "verifier",
53343
53443
  "verify-scoped",
53344
53444
  "semantic-review",
53345
53445
  "adversarial-review"
53346
53446
  ],
53347
- "autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "verify-scoped", "adversarial-review"],
53348
- "full-suite-rectify": ["lint-check", "typecheck-check", "full-suite-gate", "verify-scoped", "semantic-review"]
53447
+ "autofix-test-writer": [
53448
+ "lint-check",
53449
+ "typecheck-check",
53450
+ "full-suite-gate",
53451
+ "verifier",
53452
+ "verify-scoped",
53453
+ "adversarial-review"
53454
+ ],
53455
+ "full-suite-rectify": [
53456
+ "lint-check",
53457
+ "typecheck-check",
53458
+ "full-suite-gate",
53459
+ "verifier",
53460
+ "verify-scoped",
53461
+ "semantic-review"
53462
+ ]
53349
53463
  };
53350
53464
  });
53351
53465
 
@@ -53584,8 +53698,6 @@ async function assemblePlanInputsFromCtx(ctx) {
53584
53698
  resolvedTestPatterns,
53585
53699
  semanticConfig: ctx.config.review.semantic
53586
53700
  });
53587
- if (prepared.skipReason)
53588
- return;
53589
53701
  return {
53590
53702
  workdir: ctx.workdir,
53591
53703
  story,
@@ -53597,7 +53709,15 @@ async function assemblePlanInputsFromCtx(ctx) {
53597
53709
  excludePatterns: prepared.excludePatterns,
53598
53710
  featureCtxBlock: buildFeatureCtxBlock(ctx, "reviewer-semantic"),
53599
53711
  priorSemanticIterations: ctx.priorSemanticIterations,
53600
- blockingThreshold: ctx.config.review.blockingThreshold
53712
+ blockingThreshold: ctx.config.review.blockingThreshold,
53713
+ _refresh: {
53714
+ projectDir: ctx.projectDir,
53715
+ storyId: story.id,
53716
+ storyGitRef: ctx.storyGitRef,
53717
+ config: ctx.config,
53718
+ naxIgnoreIndex: ctx.naxIgnoreIndex,
53719
+ resolvedTestPatterns
53720
+ }
53601
53721
  };
53602
53722
  })() : undefined;
53603
53723
  const adversarialEnabled = ctx.config.review?.enabled === true && ctx.config.review.checks?.includes("adversarial") && !!ctx.config.review.adversarial;
@@ -53612,8 +53732,6 @@ async function assemblePlanInputsFromCtx(ctx) {
53612
53732
  resolvedTestPatterns,
53613
53733
  adversarialConfig: ctx.config.review.adversarial
53614
53734
  });
53615
- if (prepared.skipReason)
53616
- return;
53617
53735
  return {
53618
53736
  workdir: ctx.workdir,
53619
53737
  story,
@@ -53628,7 +53746,15 @@ async function assemblePlanInputsFromCtx(ctx) {
53628
53746
  refExcludePatterns: prepared.refExcludePatterns,
53629
53747
  featureCtxBlock: buildFeatureCtxBlock(ctx, "reviewer-adversarial"),
53630
53748
  priorAdversarialIterations: ctx.priorAdversarialIterations,
53631
- blockingThreshold: ctx.config.review.blockingThreshold
53749
+ blockingThreshold: ctx.config.review.blockingThreshold,
53750
+ _refresh: {
53751
+ projectDir: ctx.projectDir,
53752
+ storyId: story.id,
53753
+ storyGitRef: ctx.storyGitRef,
53754
+ config: ctx.config,
53755
+ naxIgnoreIndex: ctx.naxIgnoreIndex,
53756
+ resolvedTestPatterns
53757
+ }
53632
53758
  };
53633
53759
  })() : undefined;
53634
53760
  const rectificationInput = ctx.config.execution?.rectification?.enabled === true ? {
@@ -57683,7 +57809,7 @@ var package_default;
57683
57809
  var init_package = __esm(() => {
57684
57810
  package_default = {
57685
57811
  name: "@nathapp/nax",
57686
- version: "0.67.14",
57812
+ version: "0.67.16",
57687
57813
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
57688
57814
  type: "module",
57689
57815
  bin: {
@@ -57778,8 +57904,8 @@ var init_version = __esm(() => {
57778
57904
  NAX_VERSION = package_default.version;
57779
57905
  NAX_COMMIT = (() => {
57780
57906
  try {
57781
- if (/^[0-9a-f]{6,10}$/.test("5b7acea1"))
57782
- return "5b7acea1";
57907
+ if (/^[0-9a-f]{6,10}$/.test("215c9e93"))
57908
+ return "215c9e93";
57783
57909
  } catch {}
57784
57910
  try {
57785
57911
  const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nathapp/nax",
3
- "version": "0.67.14",
3
+ "version": "0.67.16",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {