@nathapp/nax 0.67.0 → 0.67.2
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 +74 -15
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -35108,6 +35108,24 @@ async function getChangedFiles(workdir, fromRef = "HEAD") {
|
|
|
35108
35108
|
return output.trim().split(`
|
|
35109
35109
|
`).filter(Boolean);
|
|
35110
35110
|
}
|
|
35111
|
+
async function getAddedLinesPerFile(workdir, fromRef = "HEAD") {
|
|
35112
|
+
const proc = _isolationDeps.spawn(["git", "diff", "--numstat", fromRef], {
|
|
35113
|
+
cwd: workdir,
|
|
35114
|
+
stdout: "pipe",
|
|
35115
|
+
stderr: "pipe"
|
|
35116
|
+
});
|
|
35117
|
+
const output = await Bun.readableStreamToText(proc.stdout);
|
|
35118
|
+
await proc.exited;
|
|
35119
|
+
const result = new Map;
|
|
35120
|
+
for (const line of output.trim().split(`
|
|
35121
|
+
`).filter(Boolean)) {
|
|
35122
|
+
const [addedStr, _deletedStr, path4] = line.split("\t");
|
|
35123
|
+
const added = Number.parseInt(addedStr ?? "", 10);
|
|
35124
|
+
if (path4 && Number.isFinite(added))
|
|
35125
|
+
result.set(path4, added);
|
|
35126
|
+
}
|
|
35127
|
+
return result;
|
|
35128
|
+
}
|
|
35111
35129
|
function matchesAllowedPath(filePath, allowedPaths) {
|
|
35112
35130
|
return allowedPaths.some((pattern) => {
|
|
35113
35131
|
const regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\//g, "\\/");
|
|
@@ -35115,17 +35133,25 @@ function matchesAllowedPath(filePath, allowedPaths) {
|
|
|
35115
35133
|
return regex.test(filePath);
|
|
35116
35134
|
});
|
|
35117
35135
|
}
|
|
35118
|
-
async function verifyTestWriterIsolation(workdir, beforeRef, allowedPaths = ["src/index.ts", "src/**/index.ts"], testFilePatterns = DEFAULT_TEST_FILE_PATTERNS) {
|
|
35136
|
+
async function verifyTestWriterIsolation(workdir, beforeRef, allowedPaths = ["src/index.ts", "src/**/index.ts"], testFilePatterns = DEFAULT_TEST_FILE_PATTERNS, mode = "strict") {
|
|
35119
35137
|
const changed = await getChangedFiles(workdir, beforeRef);
|
|
35120
35138
|
const sourceFiles = changed.filter((f) => isSourceFile(f) && !isTestFileByPatterns(f, testFilePatterns));
|
|
35139
|
+
const addedLines = mode === "lite" && sourceFiles.length > 0 ? await getAddedLinesPerFile(workdir, beforeRef) : null;
|
|
35121
35140
|
const softViolations = [];
|
|
35122
35141
|
const violations = [];
|
|
35123
35142
|
for (const file3 of sourceFiles) {
|
|
35124
35143
|
if (matchesAllowedPath(file3, allowedPaths)) {
|
|
35125
35144
|
softViolations.push(file3);
|
|
35126
|
-
|
|
35127
|
-
|
|
35145
|
+
continue;
|
|
35146
|
+
}
|
|
35147
|
+
if (addedLines) {
|
|
35148
|
+
const added = addedLines.get(file3) ?? Number.POSITIVE_INFINITY;
|
|
35149
|
+
if (added <= LITE_STUB_ADDED_LINES_CEILING) {
|
|
35150
|
+
softViolations.push(file3);
|
|
35151
|
+
continue;
|
|
35152
|
+
}
|
|
35128
35153
|
}
|
|
35154
|
+
violations.push(file3);
|
|
35129
35155
|
}
|
|
35130
35156
|
return {
|
|
35131
35157
|
passed: violations.length === 0,
|
|
@@ -35151,7 +35177,7 @@ async function verifyImplementerIsolation(workdir, beforeRef, testFilePatterns =
|
|
|
35151
35177
|
description: "Implementer should not modify test files"
|
|
35152
35178
|
};
|
|
35153
35179
|
}
|
|
35154
|
-
var _isolationDeps, SRC_PATTERNS;
|
|
35180
|
+
var _isolationDeps, SRC_PATTERNS, LITE_STUB_ADDED_LINES_CEILING = 20;
|
|
35155
35181
|
var init_isolation = __esm(() => {
|
|
35156
35182
|
init_test_runners();
|
|
35157
35183
|
init_bun_deps();
|
|
@@ -35235,7 +35261,7 @@ var init_write_test = __esm(() => {
|
|
|
35235
35261
|
return parsed;
|
|
35236
35262
|
const allowedPaths = ctx.config.tdd?.testWriterAllowedPaths ?? ["src/index.ts", "src/**/index.ts"];
|
|
35237
35263
|
const testFilePatterns = typeof ctx.packageView.config.execution?.smartTestRunner === "object" && ctx.packageView.config.execution.smartTestRunner !== null ? ctx.packageView.config.execution.smartTestRunner.testFilePatterns : undefined;
|
|
35238
|
-
const isolation = await verifyTestWriterIsolation(ctx.packageView.packageDir, input.beforeRef, allowedPaths, testFilePatterns);
|
|
35264
|
+
const isolation = await verifyTestWriterIsolation(ctx.packageView.packageDir, input.beforeRef, allowedPaths, testFilePatterns, input.lite ? "lite" : "strict");
|
|
35239
35265
|
return { ...parsed, isolation };
|
|
35240
35266
|
}
|
|
35241
35267
|
};
|
|
@@ -37189,10 +37215,32 @@ async function runRectificationLoop(opts) {
|
|
|
37189
37215
|
}
|
|
37190
37216
|
}
|
|
37191
37217
|
});
|
|
37192
|
-
|
|
37193
|
-
|
|
37194
|
-
|
|
37195
|
-
|
|
37218
|
+
let initialFailure = { testOutput, testSummary };
|
|
37219
|
+
if (rectificationConfig.abortOnIncreasingFailures) {
|
|
37220
|
+
const preCheck = await _rectificationDeps.runVerification({
|
|
37221
|
+
workdir,
|
|
37222
|
+
expectedFiles: getExpectedFiles(story),
|
|
37223
|
+
command: testCommand,
|
|
37224
|
+
timeoutSeconds,
|
|
37225
|
+
forceExit: config2.quality.forceExit,
|
|
37226
|
+
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
37227
|
+
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
37228
|
+
timeoutRetryCount: 0,
|
|
37229
|
+
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
37230
|
+
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
37231
|
+
shell: config2.quality.shell,
|
|
37232
|
+
stripEnvVars: config2.quality.stripEnvVars
|
|
37233
|
+
});
|
|
37234
|
+
if (preCheck.output) {
|
|
37235
|
+
const preCheckSummary = parseTestOutput(preCheck.output);
|
|
37236
|
+
initialFailure = { testOutput: preCheck.output, testSummary: preCheckSummary };
|
|
37237
|
+
} else {
|
|
37238
|
+
logger?.warn("rectification", "pre-check returned no output \u2014 abort baseline may be scope-mismatched", {
|
|
37239
|
+
storyId: story.id,
|
|
37240
|
+
preCheckStatus: preCheck.status
|
|
37241
|
+
});
|
|
37242
|
+
}
|
|
37243
|
+
}
|
|
37196
37244
|
const outcome = await runRetryLoop({
|
|
37197
37245
|
stage: "rectification",
|
|
37198
37246
|
storyId: story.id,
|
|
@@ -54346,10 +54394,13 @@ class ExecutionPlan {
|
|
|
54346
54394
|
const phaseOutputs = {};
|
|
54347
54395
|
const startedAt = Date.now();
|
|
54348
54396
|
const logger = getSafeLogger();
|
|
54349
|
-
const
|
|
54397
|
+
const verifierPresent = this.state.verifier !== undefined;
|
|
54398
|
+
const rectificationExempt = this.state.rectification ? [
|
|
54350
54399
|
...this.state.fullSuiteGate ? [this.state.fullSuiteGate.slot.op.name] : [],
|
|
54351
54400
|
...this.state.verifier ? [this.state.verifier.slot.op.name] : []
|
|
54352
|
-
]
|
|
54401
|
+
] : [];
|
|
54402
|
+
const verifierExempt = verifierPresent && this.state.fullSuiteGate ? [this.state.fullSuiteGate.slot.op.name] : [];
|
|
54403
|
+
const shortCircuitExempt = new Set([...rectificationExempt, ...verifierExempt]);
|
|
54353
54404
|
for (const phase of collectOrderedPhases(this.state)) {
|
|
54354
54405
|
try {
|
|
54355
54406
|
await runPhase(this.ctx, phase.slot, phaseCosts, phaseOutputs, this.isThreeSession);
|
|
@@ -54577,7 +54628,8 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
54577
54628
|
story,
|
|
54578
54629
|
promptMarkdown: testWriterPrompt,
|
|
54579
54630
|
featureContextMarkdown: ctx.featureContextMarkdown,
|
|
54580
|
-
constitution: ctx.constitution?.content
|
|
54631
|
+
constitution: ctx.constitution?.content,
|
|
54632
|
+
lite: isLite
|
|
54581
54633
|
} : undefined;
|
|
54582
54634
|
const greenfieldGateInput = _isTdd && _isFreshRun && resolvedTestPatterns ? { story, workdir: ctx.workdir, resolvedTestPatterns } : undefined;
|
|
54583
54635
|
const implementerInput = {
|
|
@@ -54778,6 +54830,13 @@ function deriveTddFailureCategory(phaseOutputs) {
|
|
|
54778
54830
|
}
|
|
54779
54831
|
return "tests-failing";
|
|
54780
54832
|
}
|
|
54833
|
+
const verifierPassed = verifierOutput?.success === true;
|
|
54834
|
+
if (!verifierPassed) {
|
|
54835
|
+
const gateOutput = phaseOutputs[fullSuiteGateOp.name];
|
|
54836
|
+
if (gateOutput && (gateOutput.success === false || gateOutput.passed === false)) {
|
|
54837
|
+
return "tests-failing";
|
|
54838
|
+
}
|
|
54839
|
+
}
|
|
54781
54840
|
const implOutput = phaseOutputs[implementerOp.name];
|
|
54782
54841
|
if (implOutput?.success === false) {
|
|
54783
54842
|
return "session-failure";
|
|
@@ -59160,7 +59219,7 @@ var package_default;
|
|
|
59160
59219
|
var init_package = __esm(() => {
|
|
59161
59220
|
package_default = {
|
|
59162
59221
|
name: "@nathapp/nax",
|
|
59163
|
-
version: "0.67.
|
|
59222
|
+
version: "0.67.2",
|
|
59164
59223
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
59165
59224
|
type: "module",
|
|
59166
59225
|
bin: {
|
|
@@ -59255,8 +59314,8 @@ var init_version = __esm(() => {
|
|
|
59255
59314
|
NAX_VERSION = package_default.version;
|
|
59256
59315
|
NAX_COMMIT = (() => {
|
|
59257
59316
|
try {
|
|
59258
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
59259
|
-
return "
|
|
59317
|
+
if (/^[0-9a-f]{6,10}$/.test("d2b13ea6"))
|
|
59318
|
+
return "d2b13ea6";
|
|
59260
59319
|
} catch {}
|
|
59261
59320
|
try {
|
|
59262
59321
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|