@nathapp/nax 0.67.4 → 0.67.6

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 +86 -4
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -51902,6 +51902,82 @@ function collectRectificationPhases(state) {
51902
51902
  state.adversarialReview
51903
51903
  ].filter((phase) => phase !== undefined);
51904
51904
  }
51905
+ function toReviewDecisionPayload(opName, output) {
51906
+ if (output === null || output === undefined || typeof output !== "object")
51907
+ return null;
51908
+ const record2 = output;
51909
+ const reviewer = opName === "semantic-review" ? "semantic" : opName === "adversarial-review" ? "adversarial" : null;
51910
+ if (!reviewer)
51911
+ return null;
51912
+ if (record2.failOpen === true) {
51913
+ return { reviewer, parsed: false, passed: true, failOpen: true, result: null };
51914
+ }
51915
+ if (record2.looksLikeFail === true) {
51916
+ return { reviewer, parsed: false, passed: false, looksLikeFail: true, result: null };
51917
+ }
51918
+ if (typeof record2.passed !== "boolean" || !Array.isArray(record2.findings)) {
51919
+ return null;
51920
+ }
51921
+ return {
51922
+ reviewer,
51923
+ parsed: true,
51924
+ passed: record2.passed,
51925
+ result: { passed: record2.passed, findings: record2.findings }
51926
+ };
51927
+ }
51928
+ function emitReviewDecision(ctx, opName, output) {
51929
+ const payload = toReviewDecisionPayload(opName, output);
51930
+ if (!payload)
51931
+ return;
51932
+ ctx.runtime.dispatchEvents.emitReviewDecision({
51933
+ kind: "review-decision",
51934
+ runId: ctx.runtime.runId,
51935
+ reviewer: payload.reviewer,
51936
+ workdir: ctx.packageDir,
51937
+ projectDir: ctx.runtime.projectDir,
51938
+ outputDir: ctx.runtime.outputDir,
51939
+ storyId: ctx.storyId,
51940
+ featureName: ctx.featureName,
51941
+ timestamp: Date.now(),
51942
+ parsed: payload.parsed,
51943
+ looksLikeFail: payload.parsed ? undefined : payload.looksLikeFail,
51944
+ failOpen: payload.parsed ? false : payload.failOpen,
51945
+ passed: payload.passed,
51946
+ result: payload.result
51947
+ });
51948
+ }
51949
+ function logUnifiedReviewPhaseStart(storyId, opName) {
51950
+ const logger = getSafeLogger();
51951
+ if (opName === "semantic-review") {
51952
+ logger?.info("review", "Running semantic check", { storyId });
51953
+ } else if (opName === "adversarial-review") {
51954
+ logger?.info("review", "Running adversarial check", { storyId });
51955
+ }
51956
+ }
51957
+ function logUnifiedReviewPhaseResult(storyId, opName, output) {
51958
+ const logger = getSafeLogger();
51959
+ const payload = toReviewDecisionPayload(opName, output);
51960
+ if (!payload)
51961
+ return;
51962
+ if (!payload.parsed) {
51963
+ if (payload.failOpen) {
51964
+ logger?.warn("review", `${payload.reviewer} review fail-open`, { storyId });
51965
+ } else if (payload.looksLikeFail) {
51966
+ logger?.warn("review", `${payload.reviewer} review returned truncated failure`, { storyId });
51967
+ }
51968
+ return;
51969
+ }
51970
+ const findingsCount = payload.result.findings.length;
51971
+ const title = payload.reviewer === "semantic" ? "Semantic review" : "Adversarial review";
51972
+ if (payload.passed) {
51973
+ logger?.info("review", `${title} passed`, { storyId });
51974
+ } else {
51975
+ logger?.warn("review", `${title} failed: ${findingsCount} findings`, {
51976
+ storyId,
51977
+ findingsCount
51978
+ });
51979
+ }
51980
+ }
51905
51981
  async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = false) {
51906
51982
  const logger = getSafeLogger();
51907
51983
  const opName = slot.op.name;
@@ -51913,11 +51989,14 @@ async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = fa
51913
51989
  } else if (isThreeSession && opName === "full-suite-gate") {
51914
51990
  logger?.info("tdd", "-> Running full test suite gate (before Verifier)", { storyId: ctx.storyId });
51915
51991
  }
51992
+ logUnifiedReviewPhaseStart(ctx.storyId, opName);
51916
51993
  const phaseStartedAt = Date.now();
51917
51994
  const scope = ctx.runtime.costAggregator.openScope();
51918
51995
  try {
51919
51996
  const output = await _storyOrchestratorDeps.callOp({ ...ctx, scopeId: scope.scopeId }, slot.op, dispatchInput);
51920
51997
  phaseOutputs[opName] = output;
51998
+ emitReviewDecision(ctx, opName, output);
51999
+ logUnifiedReviewPhaseResult(ctx.storyId, opName, output);
51921
52000
  if (isTddPhase) {
51922
52001
  const durationMs = Date.now() - phaseStartedAt;
51923
52002
  logger?.info("tdd", `Session complete: ${opName}`, {
@@ -52555,6 +52634,9 @@ async function closeAllRunSessions(sessionManager, agentGetFn, opts) {
52555
52634
  }
52556
52635
 
52557
52636
  // src/execution/post-run.ts
52637
+ function shouldRollbackTddFailure(tddMode, failureCategory) {
52638
+ return tddMode?.rollbackEnabled === true && failureCategory === "isolation-violation";
52639
+ }
52558
52640
  function extractPauseReason(phaseOutputs) {
52559
52641
  for (const output of Object.values(phaseOutputs)) {
52560
52642
  if (output !== null && typeof output === "object") {
@@ -52737,7 +52819,7 @@ async function decideStageAction(ctx, planResult, inspection, opts) {
52737
52819
  const logger = getLogger();
52738
52820
  const isTdd = opts.tddMode !== null;
52739
52821
  const isLiteMode = opts.tddMode?.isLite ?? false;
52740
- const shouldRollback = opts.tddMode?.rollbackEnabled === true;
52822
+ const shouldRollback = shouldRollbackTddFailure(opts.tddMode, inspection.failureCategory);
52741
52823
  const { agentResult, selfVerificationFailed, pauseReason, failureCategory, needsHumanReview, combinedOutput } = inspection;
52742
52824
  if (planResult.rectificationExhausted && planResult.unfixedFindings && planResult.unfixedFindings.length > 0) {
52743
52825
  const sources = new Set(planResult.unfixedFindings.map((f) => f.source));
@@ -56654,7 +56736,7 @@ var package_default;
56654
56736
  var init_package = __esm(() => {
56655
56737
  package_default = {
56656
56738
  name: "@nathapp/nax",
56657
- version: "0.67.4",
56739
+ version: "0.67.6",
56658
56740
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
56659
56741
  type: "module",
56660
56742
  bin: {
@@ -56749,8 +56831,8 @@ var init_version = __esm(() => {
56749
56831
  NAX_VERSION = package_default.version;
56750
56832
  NAX_COMMIT = (() => {
56751
56833
  try {
56752
- if (/^[0-9a-f]{6,10}$/.test("58c1f972"))
56753
- return "58c1f972";
56834
+ if (/^[0-9a-f]{6,10}$/.test("8e8f2b3a"))
56835
+ return "8e8f2b3a";
56754
56836
  } catch {}
56755
56837
  try {
56756
56838
  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.4",
3
+ "version": "0.67.6",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {