@nathapp/nax 0.65.4 → 0.65.5
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 +111 -57
- package/package.json +5 -2
package/dist/nax.js
CHANGED
|
@@ -29424,53 +29424,71 @@ var init_debate_builder = __esm(() => {
|
|
|
29424
29424
|
function buildPriorIterationsBlock(iterations) {
|
|
29425
29425
|
if (iterations.length === 0)
|
|
29426
29426
|
return "";
|
|
29427
|
-
const
|
|
29428
|
-
|
|
29429
|
-
|
|
29430
|
-
|
|
29431
|
-
|
|
29432
|
-
|
|
29433
|
-
|
|
29434
|
-
|
|
29435
|
-
|
|
29436
|
-
|
|
29427
|
+
const sections2 = iterations.map((iter) => renderIteration(iter));
|
|
29428
|
+
const { displaySections, visibleIterations } = applyTokenGuard(sections2, iterations);
|
|
29429
|
+
const verdictTemplate = renderVerdictTemplate(visibleIterations);
|
|
29430
|
+
return [
|
|
29431
|
+
"## Prior Iterations \u2014 verdict required before new analysis",
|
|
29432
|
+
"",
|
|
29433
|
+
...displaySections,
|
|
29434
|
+
"",
|
|
29435
|
+
verdictTemplate,
|
|
29436
|
+
""
|
|
29437
|
+
].join(`
|
|
29437
29438
|
`);
|
|
29438
|
-
|
|
29439
|
-
|
|
29440
|
-
|
|
29441
|
-
return `## Prior Iterations \u2014 verdict required before new analysis
|
|
29442
|
-
|
|
29443
|
-
${table}${unchangedNote}
|
|
29439
|
+
}
|
|
29440
|
+
function applyTokenGuard(sections2, iterations) {
|
|
29441
|
+
if (sections2.join(`
|
|
29444
29442
|
|
|
29445
|
-
|
|
29443
|
+
`).length <= MAX_BLOCK_CHARS || sections2.length <= 2) {
|
|
29444
|
+
return { displaySections: sections2, visibleIterations: iterations };
|
|
29445
|
+
}
|
|
29446
|
+
const n = sections2.length;
|
|
29447
|
+
const collapsed = iterations.slice(0, n - 2).map((iter) => `### Round ${iter.iterationNum} \u2014 outcome: ${iter.outcome} (${iter.findingsAfter.length} findings, omitted for brevity)`);
|
|
29448
|
+
const verbatim = sections2.slice(n - 2);
|
|
29449
|
+
return { displaySections: [...collapsed, ...verbatim], visibleIterations: iterations.slice(n - 2) };
|
|
29446
29450
|
}
|
|
29447
|
-
function
|
|
29448
|
-
const
|
|
29449
|
-
|
|
29450
|
-
|
|
29451
|
+
function renderIteration(iter) {
|
|
29452
|
+
const header = `### Round ${iter.iterationNum} \u2014 outcome: ${iter.outcome} (${iter.findingsBefore.length} \u2192 ${iter.findingsAfter.length})`;
|
|
29453
|
+
if (iter.findingsAfter.length === 0) {
|
|
29454
|
+
return [header, "_All prior findings cleared._"].join(`
|
|
29455
|
+
`);
|
|
29456
|
+
}
|
|
29457
|
+
const lines = iter.findingsAfter.map((f, i) => renderFinding(f, i + 1));
|
|
29458
|
+
return [header, "Findings flagged previously:", ...lines].join(`
|
|
29459
|
+
`);
|
|
29451
29460
|
}
|
|
29452
|
-
function
|
|
29453
|
-
const
|
|
29454
|
-
const
|
|
29455
|
-
|
|
29461
|
+
function renderFinding(f, n) {
|
|
29462
|
+
const message = truncate(f.message ?? "", 240);
|
|
29463
|
+
const suggestion = truncate(f.suggestion ?? "", 200);
|
|
29464
|
+
const loc = f.file ? f.line != null ? `${f.file}:${f.line}` : f.file : "(workdir-global)";
|
|
29465
|
+
const tag = `[${f.severity} / ${f.category}]`;
|
|
29466
|
+
const ac = typeof f.meta?.acQuote === "string" ? f.meta.acQuote : undefined;
|
|
29467
|
+
const acLine = ac ? `
|
|
29468
|
+
acQuote: "${truncate(ac, 160)}"` : "";
|
|
29469
|
+
return `${n}. ${tag} ${loc}
|
|
29470
|
+
Message: ${message}
|
|
29471
|
+
Suggestion: ${suggestion}${acLine}`;
|
|
29472
|
+
}
|
|
29473
|
+
function renderVerdictTemplate(iterations) {
|
|
29474
|
+
const total = iterations.reduce((sum, it) => sum + it.findingsAfter.length, 0);
|
|
29475
|
+
const hasUnchanged = iterations.some((i) => i.outcome === "unchanged");
|
|
29476
|
+
const unchangedNote = hasUnchanged ? `
|
|
29477
|
+
|
|
29478
|
+
When outcome is "unchanged", the prior hypothesis is FALSIFIED \u2014 the change did not affect what was tested. Choose a different category before producing a new verdict. Do NOT repeat fixes listed above.` : "";
|
|
29479
|
+
return [
|
|
29480
|
+
`**Required:** before adding any new finding, classify each of the ${total} prior finding(s) above as one of:`,
|
|
29481
|
+
"- `addressed` \u2014 the current diff resolves it (cite the diff line that fixes it in your `message` field)",
|
|
29482
|
+
"- `still-blocking` \u2014 the implementer did not fix it; re-flag it with the IDENTICAL `file`, `line`, `category`, and substantively the same `message` wording",
|
|
29483
|
+
`- \`never-an-issue\` \u2014 your prior judgment was wrong; explain why in \`message\` and emit severity \`"info"\``,
|
|
29484
|
+
`Then surface any genuinely new findings.${unchangedNote}`
|
|
29485
|
+
].join(`
|
|
29486
|
+
`);
|
|
29456
29487
|
}
|
|
29457
|
-
function
|
|
29458
|
-
|
|
29459
|
-
return null;
|
|
29460
|
-
const freq = new Map;
|
|
29461
|
-
for (const f of findings) {
|
|
29462
|
-
freq.set(f.category, (freq.get(f.category) ?? 0) + 1);
|
|
29463
|
-
}
|
|
29464
|
-
let top = null;
|
|
29465
|
-
let topCount = 0;
|
|
29466
|
-
for (const [cat, cnt] of freq) {
|
|
29467
|
-
if (cnt > topCount) {
|
|
29468
|
-
topCount = cnt;
|
|
29469
|
-
top = cat;
|
|
29470
|
-
}
|
|
29471
|
-
}
|
|
29472
|
-
return top;
|
|
29488
|
+
function truncate(s, max) {
|
|
29489
|
+
return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
29473
29490
|
}
|
|
29491
|
+
var MAX_BLOCK_CHARS = 6000;
|
|
29474
29492
|
|
|
29475
29493
|
// src/prompts/builders/review-builder.ts
|
|
29476
29494
|
class ReviewPromptBuilder {
|
|
@@ -47468,6 +47486,16 @@ function buildFailureReason(checks3) {
|
|
|
47468
47486
|
}
|
|
47469
47487
|
|
|
47470
47488
|
class ReviewOrchestrator {
|
|
47489
|
+
priorAdversarialByStory = new Map;
|
|
47490
|
+
priorSemanticByStory = new Map;
|
|
47491
|
+
clearStory(storyId) {
|
|
47492
|
+
this.priorAdversarialByStory.delete(storyId);
|
|
47493
|
+
this.priorSemanticByStory.delete(storyId);
|
|
47494
|
+
}
|
|
47495
|
+
reset() {
|
|
47496
|
+
this.priorAdversarialByStory.clear();
|
|
47497
|
+
this.priorSemanticByStory.clear();
|
|
47498
|
+
}
|
|
47471
47499
|
async review(opts) {
|
|
47472
47500
|
const {
|
|
47473
47501
|
reviewConfig,
|
|
@@ -47795,6 +47823,8 @@ class ReviewOrchestrator {
|
|
|
47795
47823
|
assembleForStage(ctx, "review-adversarial")
|
|
47796
47824
|
]);
|
|
47797
47825
|
const contextBundles = semanticBundle || adversarialBundle ? { semantic: semanticBundle ?? undefined, adversarial: adversarialBundle ?? undefined } : undefined;
|
|
47826
|
+
const priorAdversarialIterations = this.priorAdversarialByStory.get(ctx.story.id) ?? [];
|
|
47827
|
+
const priorSemanticIterations = this.priorSemanticByStory.get(ctx.story.id) ?? [];
|
|
47798
47828
|
const result = await this.review({
|
|
47799
47829
|
reviewConfig: ctx.config.review,
|
|
47800
47830
|
workdir: ctx.workdir,
|
|
@@ -47816,23 +47846,24 @@ class ReviewOrchestrator {
|
|
|
47816
47846
|
featureName: ctx.prd.feature,
|
|
47817
47847
|
resolverSession,
|
|
47818
47848
|
priorFailures: ctx.story.priorFailures,
|
|
47819
|
-
priorSemanticIterations
|
|
47849
|
+
priorSemanticIterations,
|
|
47820
47850
|
featureContextMarkdown: ctx.featureContextMarkdown,
|
|
47821
47851
|
contextBundles,
|
|
47822
47852
|
projectDir: ctx.projectDir,
|
|
47823
47853
|
env: ctx.worktreeDependencyContext?.env,
|
|
47824
47854
|
naxIgnoreIndex: ctx.naxIgnoreIndex,
|
|
47825
47855
|
runtime: ctx.runtime,
|
|
47826
|
-
priorAdversarialIterations
|
|
47856
|
+
priorAdversarialIterations
|
|
47827
47857
|
});
|
|
47858
|
+
const logger = getSafeLogger();
|
|
47828
47859
|
const advCheck = result.builtIn.checks?.find((c) => c.check === "adversarial");
|
|
47829
47860
|
if (advCheck) {
|
|
47830
47861
|
if (!advCheck.success && !advCheck.skipped) {
|
|
47831
|
-
const prior = ctx.
|
|
47862
|
+
const prior = this.priorAdversarialByStory.get(ctx.story.id) ?? [];
|
|
47832
47863
|
const findingsBefore = prior.length > 0 ? prior[prior.length - 1].findingsAfter ?? [] : [];
|
|
47833
47864
|
const findingsAfter = advCheck.findings ?? [];
|
|
47834
47865
|
const now = new Date().toISOString();
|
|
47835
|
-
const
|
|
47866
|
+
const next = {
|
|
47836
47867
|
iterationNum: prior.length + 1,
|
|
47837
47868
|
findingsBefore,
|
|
47838
47869
|
fixesApplied: [],
|
|
@@ -47841,21 +47872,27 @@ class ReviewOrchestrator {
|
|
|
47841
47872
|
startedAt: now,
|
|
47842
47873
|
finishedAt: now
|
|
47843
47874
|
};
|
|
47844
|
-
ctx.
|
|
47875
|
+
this.priorAdversarialByStory.set(ctx.story.id, [...prior, next]);
|
|
47876
|
+
logger?.debug("review", "Adversarial iteration recorded", {
|
|
47877
|
+
storyId: ctx.story.id,
|
|
47878
|
+
iterationNum: next.iterationNum,
|
|
47879
|
+
outcome: next.outcome,
|
|
47880
|
+
findingsCount: findingsAfter.length
|
|
47881
|
+
});
|
|
47845
47882
|
} else if (advCheck.success && !advCheck.skipped) {
|
|
47846
|
-
ctx.
|
|
47883
|
+
this.priorAdversarialByStory.delete(ctx.story.id);
|
|
47847
47884
|
}
|
|
47848
47885
|
} else if (retrySkipChecks?.has("adversarial")) {
|
|
47849
|
-
ctx.
|
|
47886
|
+
this.priorAdversarialByStory.delete(ctx.story.id);
|
|
47850
47887
|
}
|
|
47851
47888
|
const semCheck = result.builtIn.checks?.find((c) => c.check === "semantic");
|
|
47852
47889
|
if (semCheck) {
|
|
47853
47890
|
if (!semCheck.success && !semCheck.skipped) {
|
|
47854
|
-
const prior = ctx.
|
|
47891
|
+
const prior = this.priorSemanticByStory.get(ctx.story.id) ?? [];
|
|
47855
47892
|
const findingsBefore = prior.length > 0 ? prior[prior.length - 1].findingsAfter ?? [] : [];
|
|
47856
47893
|
const findingsAfter = semCheck.findings ?? [];
|
|
47857
47894
|
const now = new Date().toISOString();
|
|
47858
|
-
const
|
|
47895
|
+
const next = {
|
|
47859
47896
|
iterationNum: prior.length + 1,
|
|
47860
47897
|
findingsBefore,
|
|
47861
47898
|
fixesApplied: [],
|
|
@@ -47864,12 +47901,18 @@ class ReviewOrchestrator {
|
|
|
47864
47901
|
startedAt: now,
|
|
47865
47902
|
finishedAt: now
|
|
47866
47903
|
};
|
|
47867
|
-
ctx.
|
|
47904
|
+
this.priorSemanticByStory.set(ctx.story.id, [...prior, next]);
|
|
47905
|
+
logger?.debug("review", "Semantic iteration recorded", {
|
|
47906
|
+
storyId: ctx.story.id,
|
|
47907
|
+
iterationNum: next.iterationNum,
|
|
47908
|
+
outcome: next.outcome,
|
|
47909
|
+
findingsCount: findingsAfter.length
|
|
47910
|
+
});
|
|
47868
47911
|
} else if (semCheck.success && !semCheck.skipped) {
|
|
47869
|
-
ctx.
|
|
47912
|
+
this.priorSemanticByStory.delete(ctx.story.id);
|
|
47870
47913
|
}
|
|
47871
47914
|
} else if (retrySkipChecks?.has("semantic")) {
|
|
47872
|
-
ctx.
|
|
47915
|
+
this.priorSemanticByStory.delete(ctx.story.id);
|
|
47873
47916
|
}
|
|
47874
47917
|
return result;
|
|
47875
47918
|
}
|
|
@@ -48561,6 +48604,7 @@ var init_completion = __esm(() => {
|
|
|
48561
48604
|
init_logger2();
|
|
48562
48605
|
init_metrics();
|
|
48563
48606
|
init_prd();
|
|
48607
|
+
init_orchestrator2();
|
|
48564
48608
|
init_event_bus();
|
|
48565
48609
|
completionStage = {
|
|
48566
48610
|
name: "completion",
|
|
@@ -48594,6 +48638,7 @@ var init_completion = __esm(() => {
|
|
|
48594
48638
|
}
|
|
48595
48639
|
for (const completedStory of ctx.stories) {
|
|
48596
48640
|
markStoryPassed(ctx.prd, completedStory.id);
|
|
48641
|
+
reviewOrchestrator.clearStory(completedStory.id);
|
|
48597
48642
|
const costPerStory = sessionCost / ctx.stories.length;
|
|
48598
48643
|
logger.info("completion", "Story passed", {
|
|
48599
48644
|
storyId: completedStory.id,
|
|
@@ -55138,7 +55183,7 @@ var package_default;
|
|
|
55138
55183
|
var init_package = __esm(() => {
|
|
55139
55184
|
package_default = {
|
|
55140
55185
|
name: "@nathapp/nax",
|
|
55141
|
-
version: "0.65.
|
|
55186
|
+
version: "0.65.5",
|
|
55142
55187
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
55143
55188
|
type: "module",
|
|
55144
55189
|
bin: {
|
|
@@ -55149,10 +55194,13 @@ var init_package = __esm(() => {
|
|
|
55149
55194
|
dev: "bun run bin/nax.ts",
|
|
55150
55195
|
build: 'bun build bin/nax.ts --outdir dist --target bun --define "GIT_COMMIT=\\"$(git rev-parse --short HEAD)\\""',
|
|
55151
55196
|
typecheck: "bun x tsc --noEmit",
|
|
55152
|
-
lint: "bun x biome check src/ bin/ && bun run check:no-real-global-nax",
|
|
55197
|
+
lint: "bun x biome check src/ bin/ && bun run check:no-real-global-nax && bun run check:alias-internals && bun run check:deep-relatives",
|
|
55153
55198
|
"lint:json": "bun x biome check src/ bin/ --reporter json",
|
|
55154
55199
|
"lint:fix": "bun x biome check --write src/ bin/",
|
|
55155
55200
|
"check:no-real-global-nax": "bun run scripts/check-no-real-global-nax.ts",
|
|
55201
|
+
"check:alias-internals": "bun run scripts/check-alias-internals.ts",
|
|
55202
|
+
"check:deep-relatives": "bun run scripts/check-deep-relatives.ts",
|
|
55203
|
+
"check:deep-relatives:update": "bun run scripts/check-deep-relatives.ts --update-baseline",
|
|
55156
55204
|
release: "bun scripts/release.ts",
|
|
55157
55205
|
test: "bun run scripts/run-tests.ts",
|
|
55158
55206
|
"test:bail": "bun run scripts/run-tests.ts --bail",
|
|
@@ -55224,8 +55272,8 @@ var init_version = __esm(() => {
|
|
|
55224
55272
|
NAX_VERSION = package_default.version;
|
|
55225
55273
|
NAX_COMMIT = (() => {
|
|
55226
55274
|
try {
|
|
55227
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
55228
|
-
return "
|
|
55275
|
+
if (/^[0-9a-f]{6,10}$/.test("a329264b"))
|
|
55276
|
+
return "a329264b";
|
|
55229
55277
|
} catch {}
|
|
55230
55278
|
try {
|
|
55231
55279
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -58380,6 +58428,7 @@ async function handlePipelineFailure(ctx, pipelineResult) {
|
|
|
58380
58428
|
break;
|
|
58381
58429
|
case "fail":
|
|
58382
58430
|
markStoryFailed(prd, ctx.story.id, pipelineResult.context.tddFailureCategory, pipelineResult.stoppedAtStage, ctx.statusWriter);
|
|
58431
|
+
reviewOrchestrator.clearStory(ctx.story.id);
|
|
58383
58432
|
await savePRD(prd, ctx.prdPath);
|
|
58384
58433
|
prdDirty = true;
|
|
58385
58434
|
logger?.error("pipeline", "Story failed", { storyId: ctx.story.id, reason: pipelineResult.reason });
|
|
@@ -58442,6 +58491,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
58442
58491
|
init_logger2();
|
|
58443
58492
|
init_event_bus();
|
|
58444
58493
|
init_prd();
|
|
58494
|
+
init_orchestrator2();
|
|
58445
58495
|
init_bun_deps();
|
|
58446
58496
|
init_git();
|
|
58447
58497
|
init_manager3();
|
|
@@ -58515,6 +58565,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
58515
58565
|
});
|
|
58516
58566
|
} catch (error48) {
|
|
58517
58567
|
markStoryFailed(prd, story.id, "dependency-prep", "worktree-dependencies", ctx.statusWriter);
|
|
58568
|
+
reviewOrchestrator.clearStory(story.id);
|
|
58518
58569
|
await savePRD(prd, ctx.prdPath);
|
|
58519
58570
|
try {
|
|
58520
58571
|
await _iterationRunnerDeps.worktreeManager.remove(ctx.workdir, story.id);
|
|
@@ -58648,6 +58699,7 @@ var init_iteration_runner = __esm(() => {
|
|
|
58648
58699
|
init_runner3();
|
|
58649
58700
|
init_stages();
|
|
58650
58701
|
init_prd();
|
|
58702
|
+
init_orchestrator2();
|
|
58651
58703
|
init_git();
|
|
58652
58704
|
init_dependencies();
|
|
58653
58705
|
init_manager3();
|
|
@@ -94915,6 +94967,7 @@ init_test_path();
|
|
|
94915
94967
|
init_hooks();
|
|
94916
94968
|
init_logger2();
|
|
94917
94969
|
init_prd();
|
|
94970
|
+
init_orchestrator2();
|
|
94918
94971
|
init_git();
|
|
94919
94972
|
init_crash_recovery();
|
|
94920
94973
|
init_story_context();
|
|
@@ -95038,6 +95091,7 @@ async function runCompletionPhase(options) {
|
|
|
95038
95091
|
await writeExitSummary(options.logFilePath, options.totalCost, options.iterations, options.storiesCompleted, durationMs);
|
|
95039
95092
|
logger?.debug("execution", "Completion phase \u2014 auto-committing dirty files");
|
|
95040
95093
|
await autoCommitIfDirty(options.workdir, "run.complete", "run-summary", options.feature);
|
|
95094
|
+
reviewOrchestrator.reset();
|
|
95041
95095
|
await options.runtime?.close();
|
|
95042
95096
|
logger?.debug("execution", "Completion phase done \u2014 returning to runner");
|
|
95043
95097
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nathapp/nax",
|
|
3
|
-
"version": "0.65.
|
|
3
|
+
"version": "0.65.5",
|
|
4
4
|
"description": "AI Coding Agent Orchestrator — loops until done",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,10 +11,13 @@
|
|
|
11
11
|
"dev": "bun run bin/nax.ts",
|
|
12
12
|
"build": "bun build bin/nax.ts --outdir dist --target bun --define \"GIT_COMMIT=\\\"$(git rev-parse --short HEAD)\\\"\"",
|
|
13
13
|
"typecheck": "bun x tsc --noEmit",
|
|
14
|
-
"lint": "bun x biome check src/ bin/ && bun run check:no-real-global-nax",
|
|
14
|
+
"lint": "bun x biome check src/ bin/ && bun run check:no-real-global-nax && bun run check:alias-internals && bun run check:deep-relatives",
|
|
15
15
|
"lint:json": "bun x biome check src/ bin/ --reporter json",
|
|
16
16
|
"lint:fix": "bun x biome check --write src/ bin/",
|
|
17
17
|
"check:no-real-global-nax": "bun run scripts/check-no-real-global-nax.ts",
|
|
18
|
+
"check:alias-internals": "bun run scripts/check-alias-internals.ts",
|
|
19
|
+
"check:deep-relatives": "bun run scripts/check-deep-relatives.ts",
|
|
20
|
+
"check:deep-relatives:update": "bun run scripts/check-deep-relatives.ts --update-baseline",
|
|
18
21
|
"release": "bun scripts/release.ts",
|
|
19
22
|
"test": "bun run scripts/run-tests.ts",
|
|
20
23
|
"test:bail": "bun run scripts/run-tests.ts --bail",
|