@nathapp/nax 0.67.8 → 0.67.9

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 +120 -21
  2. package/package.json +1 -1
package/dist/nax.js CHANGED
@@ -30381,18 +30381,19 @@ Schema: {"passed": boolean, "findings": [{"severity": string, "category": string
30381
30381
  const line = opts.finding.verifiedBy?.line ?? opts.finding.line;
30382
30382
  return `Your previous verifiedBy.observed value did not match the referenced file on disk.
30383
30383
 
30384
+ You MUST use your file-reading tool to open ${file3} and copy the actual bytes around line ${line}. Do NOT quote from memory or from the prior conversation \u2014 the previous quote was wrong precisely because it was not read from disk. If you reply without a file-read tool call, the quote will be rejected.
30385
+
30384
30386
  Return ONLY this JSON object:
30385
30387
  {"file":"${file3}","line":${line},"observed":"exact 1-3 line quote"}
30386
30388
 
30387
30389
  Finding issue: ${opts.finding.issue}
30388
30390
  Referenced file: ${file3}
30389
30391
  Referenced line: ${line}
30390
- Previous observed: ${opts.previousObserved}
30391
30392
 
30392
30393
  Rules:
30393
- - Copy observed verbatim from the file. Do not paraphrase.
30394
- - observed must be a 1-3 line excerpt that proves the claim.
30395
- - If you cannot quote proof exactly, set observed to "".
30394
+ - Read ${file3} with your file tool first. Then copy observed verbatim from the read result.
30395
+ - observed must be a 1-3 line excerpt that proves the claim, taken from at or near line ${line}.
30396
+ - If after reading the file you cannot find anything that proves the claim, set observed to "".
30396
30397
  - Do not return a full review. Do not include markdown fences or explanation.`;
30397
30398
  }
30398
30399
  }
@@ -31851,7 +31852,20 @@ async function checkFindingEvidence(opts) {
31851
31852
  const contents = await readSafeFile(opts.workdir, file3);
31852
31853
  if (contents === null)
31853
31854
  return { status: "unreadable", file: file3, line, observed };
31854
- return normalizedIncludes(contents, observed) ? { status: "matched", file: file3, line, observed } : { status: "unmatched", file: file3, line, observed };
31855
+ return matchesEvidence(contents, observed, line) ? { status: "matched", file: file3, line, observed } : { status: "unmatched", file: file3, line, observed };
31856
+ }
31857
+ function matchesEvidence(contents, observed, line) {
31858
+ if (!line || line <= 0) {
31859
+ return normalizedIncludes(contents, observed);
31860
+ }
31861
+ const lines = contents.split(`
31862
+ `);
31863
+ const cited = Math.min(Math.max(0, line - 1), lines.length - 1);
31864
+ const start = Math.max(0, cited - EVIDENCE_LINE_WINDOW);
31865
+ const end = Math.min(lines.length, cited + EVIDENCE_LINE_WINDOW + 1);
31866
+ const windowText = lines.slice(start, end).join(`
31867
+ `);
31868
+ return normalizedIncludes(windowText, observed);
31855
31869
  }
31856
31870
  function downgradeUnsubstantiatedFinding(opts) {
31857
31871
  _evidenceDeps.getLogger()?.warn("review", "Downgraded unsubstantiated review finding", {
@@ -31899,7 +31913,7 @@ function stripWrappingQuotes(text) {
31899
31913
  function isMatchingWrapper(first, last) {
31900
31914
  return first === "`" && last === "`" || first === `"` && last === `"` || first === "'" && last === "'";
31901
31915
  }
31902
- var OBSERVED_PREVIEW_CHARS = 160, ISSUE_PREVIEW_CHARS = 200, SEMANTIC_FINDING_DOWNGRADED_EVENT = "review.semantic.finding.downgraded", ADVERSARIAL_FINDING_DOWNGRADED_EVENT = "review.adversarial.finding.downgraded", _evidenceDeps;
31916
+ var OBSERVED_PREVIEW_CHARS = 160, ISSUE_PREVIEW_CHARS = 200, EVIDENCE_LINE_WINDOW = 10, SEMANTIC_FINDING_DOWNGRADED_EVENT = "review.semantic.finding.downgraded", ADVERSARIAL_FINDING_DOWNGRADED_EVENT = "review.adversarial.finding.downgraded", _evidenceDeps;
31903
31917
  var init_semantic_evidence = __esm(() => {
31904
31918
  init_logger2();
31905
31919
  init_path_security2();
@@ -35057,7 +35071,7 @@ async function requoteBlockingFindings(findings, ctx) {
35057
35071
  if (used >= maxRequotes)
35058
35072
  break;
35059
35073
  used += 1;
35060
- const retry = await ctx.send(ReviewPromptBuilder.requoteVerbatim({ finding, previousObserved: initialEvidence.observed ?? "" }));
35074
+ const retry = await ctx.send(ReviewPromptBuilder.requoteVerbatim({ finding }));
35061
35075
  extraCostUsd += retry.estimatedCostUsd ?? 0;
35062
35076
  const requote = parseRequoteResponse(retry.output);
35063
35077
  if (!requote) {
@@ -37334,14 +37348,45 @@ var init_full_suite_rectify = __esm(() => {
37334
37348
  init_implement();
37335
37349
  });
37336
37350
 
37351
+ // src/operations/_finding-to-check.ts
37352
+ function findingsToFailedChecks(findings) {
37353
+ const grouped = new Map;
37354
+ for (const finding of findings) {
37355
+ const check2 = SOURCE_TO_CHECK[finding.source];
37356
+ if (!check2)
37357
+ continue;
37358
+ const bucket = grouped.get(check2) ?? [];
37359
+ bucket.push(finding);
37360
+ grouped.set(check2, bucket);
37361
+ }
37362
+ return [...grouped.entries()].map(([check2, grpFindings]) => ({
37363
+ check: check2,
37364
+ success: false,
37365
+ command: "",
37366
+ exitCode: 1,
37367
+ output: "",
37368
+ durationMs: 0,
37369
+ findings: grpFindings
37370
+ }));
37371
+ }
37372
+ var SOURCE_TO_CHECK;
37373
+ var init__finding_to_check = __esm(() => {
37374
+ SOURCE_TO_CHECK = {
37375
+ "semantic-review": "semantic",
37376
+ "adversarial-review": "adversarial",
37377
+ lint: "lint",
37378
+ typecheck: "typecheck"
37379
+ };
37380
+ });
37381
+
37337
37382
  // src/operations/autofix-implementer-strategy.ts
37338
37383
  function makeAutofixImplementerStrategy(story) {
37339
37384
  return {
37340
37385
  name: "autofix-implementer",
37341
37386
  appliesTo: (f) => f.fixTarget === "source" && IMPLEMENTER_SOURCES.has(f.source),
37342
37387
  fixOp: implementerRectifyOp,
37343
- buildInput: (_findings, _prior, _cycleCtx) => ({
37344
- failedChecks: [],
37388
+ buildInput: (findings, _prior, _cycleCtx) => ({
37389
+ failedChecks: findingsToFailedChecks(findings),
37345
37390
  story
37346
37391
  }),
37347
37392
  extractApplied: (output) => ({
@@ -37354,6 +37399,7 @@ function makeAutofixImplementerStrategy(story) {
37354
37399
  }
37355
37400
  var IMPLEMENTER_SOURCES;
37356
37401
  var init_autofix_implementer_strategy = __esm(() => {
37402
+ init__finding_to_check();
37357
37403
  init_autofix_implementer();
37358
37404
  IMPLEMENTER_SOURCES = new Set(["lint", "typecheck", "semantic-review"]);
37359
37405
  });
@@ -37364,8 +37410,8 @@ function makeAutofixTestWriterStrategy(story, config2) {
37364
37410
  name: "autofix-test-writer",
37365
37411
  appliesTo: (f) => f.fixTarget === "test" || f.source === "adversarial-review",
37366
37412
  fixOp: testWriterRectifyOp,
37367
- buildInput: (_findings, _prior, _cycleCtx) => ({
37368
- failedChecks: [],
37413
+ buildInput: (findings, _prior, _cycleCtx) => ({
37414
+ failedChecks: findingsToFailedChecks(findings),
37369
37415
  story,
37370
37416
  blockingThreshold: config2.review?.blockingThreshold
37371
37417
  }),
@@ -37374,6 +37420,7 @@ function makeAutofixTestWriterStrategy(story, config2) {
37374
37420
  };
37375
37421
  }
37376
37422
  var init_autofix_test_writer_strategy = __esm(() => {
37423
+ init__finding_to_check();
37377
37424
  init_autofix_test_writer();
37378
37425
  });
37379
37426
 
@@ -37857,6 +37904,7 @@ var init_operations = __esm(() => {
37857
37904
  init_full_suite_rectify();
37858
37905
  init_autofix_implementer_strategy();
37859
37906
  init_autofix_test_writer_strategy();
37907
+ init__finding_to_check();
37860
37908
  init_mechanical_lintfix_strategy();
37861
37909
  init_mechanical_formatfix_strategy();
37862
37910
  init_lint_check();
@@ -38062,7 +38110,10 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
38062
38110
  if (allExhausted) {
38063
38111
  let liteFindingsAfter;
38064
38112
  try {
38065
- liteFindingsAfter = await cycle.validate(ctx, { mode: "lite" });
38113
+ liteFindingsAfter = await cycle.validate(ctx, {
38114
+ mode: "lite",
38115
+ strategiesRun: group.map((s) => s.name)
38116
+ });
38066
38117
  } catch (err) {
38067
38118
  const finishedAt3 = now();
38068
38119
  cycle.iterations.push({
@@ -38134,7 +38185,7 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
38134
38185
  let validatorAttempt = 0;
38135
38186
  for (;; ) {
38136
38187
  try {
38137
- findingsAfter = await cycle.validate(ctx, { mode: "full" });
38188
+ findingsAfter = await cycle.validate(ctx, { mode: "full", strategiesRun: group.map((s) => s.name) });
38138
38189
  break;
38139
38190
  } catch (err) {
38140
38191
  if (validatorAttempt >= cycle.config.validatorRetries) {
@@ -51975,9 +52026,19 @@ function extractPhaseFindings(output) {
51975
52026
  const success2 = "success" in record2 ? record2.success === true : ("passed" in record2) ? record2.passed === true : findings.length === 0;
51976
52027
  return success2 ? [] : findings;
51977
52028
  }
51978
- function gatherRectificationFindings(phaseOutputs, phases) {
52029
+ function shouldSkipPhaseForRectification(phase, state, phaseOutputs) {
52030
+ if (phase.kind !== "full-suite-gate")
52031
+ return false;
52032
+ const verifierName = state.verifier?.slot.op.name;
52033
+ if (!verifierName)
52034
+ return false;
52035
+ return phaseExplicitlyPassed(phaseOutputs[verifierName]);
52036
+ }
52037
+ function gatherRectificationFindings(phaseOutputs, phases, state) {
51979
52038
  const findings = [];
51980
52039
  for (const phase of phases) {
52040
+ if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
52041
+ continue;
51981
52042
  findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
51982
52043
  }
51983
52044
  return findings;
@@ -51993,6 +52054,21 @@ function collectRectificationPhases(state) {
51993
52054
  state.adversarialReview
51994
52055
  ].filter((phase) => phase !== undefined);
51995
52056
  }
52057
+ function phasesToRevalidate(strategiesRun, allPhases) {
52058
+ const sourceFiltered = allPhases.filter((p) => p.kind !== "verifier");
52059
+ if (!strategiesRun || strategiesRun.length === 0)
52060
+ return sourceFiltered;
52061
+ const unknown2 = strategiesRun.some((name) => STRATEGY_TO_REVALIDATION_PHASES[name] === undefined);
52062
+ if (unknown2)
52063
+ return sourceFiltered;
52064
+ const needed = new Set;
52065
+ for (const name of strategiesRun) {
52066
+ for (const kind of STRATEGY_TO_REVALIDATION_PHASES[name] ?? []) {
52067
+ needed.add(kind);
52068
+ }
52069
+ }
52070
+ return sourceFiltered.filter((p) => needed.has(p.kind));
52071
+ }
51996
52072
  function toReviewDecisionPayload(opName, output) {
51997
52073
  if (output === null || output === undefined || typeof output !== "object")
51998
52074
  return null;
@@ -52148,7 +52224,7 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
52148
52224
  if (ctx.runtime.signal?.aborted) {
52149
52225
  return {};
52150
52226
  }
52151
- const initialFindings = gatherRectificationFindings(phaseOutputs, validationPhases);
52227
+ const initialFindings = gatherRectificationFindings(phaseOutputs, validationPhases, state);
52152
52228
  if (initialFindings.length === 0) {
52153
52229
  return {};
52154
52230
  }
@@ -52168,13 +52244,22 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs) {
52168
52244
  validate: async (_validateCtx, opts) => {
52169
52245
  if (ctx.runtime.signal?.aborted)
52170
52246
  return [];
52171
- const lite = opts?.mode === "lite";
52247
+ const lite = (opts?.mode ?? "full") === "lite";
52248
+ const phases = phasesToRevalidate(opts?.strategiesRun, validationPhases);
52249
+ getSafeLogger()?.debug("story-orchestrator", "rectification validate scope", {
52250
+ storyId: ctx.storyId,
52251
+ mode: opts?.mode ?? "full",
52252
+ strategiesRun: opts?.strategiesRun,
52253
+ phasesSelected: phases.map((p) => p.kind)
52254
+ });
52172
52255
  const findings = [];
52173
- for (const phase of validationPhases) {
52256
+ for (const phase of phases) {
52174
52257
  if (lite && phase.kind === "full-suite-gate") {
52175
52258
  continue;
52176
52259
  }
52177
52260
  await runPhase(ctx, phase.slot, phaseCosts, phaseOutputs);
52261
+ if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
52262
+ continue;
52178
52263
  findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
52179
52264
  }
52180
52265
  return findings;
@@ -52321,7 +52406,7 @@ class StoryOrchestratorBuilder {
52321
52406
  return new ExecutionPlan(ctx, { ...this.state }, opts.isThreeSession ?? false);
52322
52407
  }
52323
52408
  }
52324
- var _storyOrchestratorDeps, TDD_OP_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY;
52409
+ var _storyOrchestratorDeps, TDD_OP_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY, STRATEGY_TO_REVALIDATION_PHASES;
52325
52410
  var init_story_orchestrator = __esm(() => {
52326
52411
  init_errors();
52327
52412
  init_findings();
@@ -52359,6 +52444,20 @@ var init_story_orchestrator = __esm(() => {
52359
52444
  "semantic-review": "semanticReview",
52360
52445
  "adversarial-review": "adversarialReview"
52361
52446
  };
52447
+ STRATEGY_TO_REVALIDATION_PHASES = {
52448
+ "mechanical-lintfix": ["lint-check"],
52449
+ "mechanical-formatfix": ["lint-check"],
52450
+ "autofix-implementer": [
52451
+ "lint-check",
52452
+ "typecheck-check",
52453
+ "full-suite-gate",
52454
+ "verify-scoped",
52455
+ "semantic-review",
52456
+ "adversarial-review"
52457
+ ],
52458
+ "autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "verify-scoped", "adversarial-review"],
52459
+ "full-suite-rectify": ["lint-check", "typecheck-check", "full-suite-gate", "verify-scoped", "semantic-review"]
52460
+ };
52362
52461
  });
52363
52462
 
52364
52463
  // src/execution/build-plan-for-strategy.ts
@@ -56844,7 +56943,7 @@ var package_default;
56844
56943
  var init_package = __esm(() => {
56845
56944
  package_default = {
56846
56945
  name: "@nathapp/nax",
56847
- version: "0.67.8",
56946
+ version: "0.67.9",
56848
56947
  description: "AI Coding Agent Orchestrator \u2014 loops until done",
56849
56948
  type: "module",
56850
56949
  bin: {
@@ -56939,8 +57038,8 @@ var init_version = __esm(() => {
56939
57038
  NAX_VERSION = package_default.version;
56940
57039
  NAX_COMMIT = (() => {
56941
57040
  try {
56942
- if (/^[0-9a-f]{6,10}$/.test("1e88267c"))
56943
- return "1e88267c";
57041
+ if (/^[0-9a-f]{6,10}$/.test("ab2db4bb"))
57042
+ return "ab2db4bb";
56944
57043
  } catch {}
56945
57044
  try {
56946
57045
  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.8",
3
+ "version": "0.67.9",
4
4
  "description": "AI Coding Agent Orchestrator — loops until done",
5
5
  "type": "module",
6
6
  "bin": {