@nathapp/nax 0.69.6 → 0.69.8
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/README.md +12 -6
- package/dist/nax.js +436 -327
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -18041,7 +18041,7 @@ function redactSecrets(input) {
|
|
|
18041
18041
|
}
|
|
18042
18042
|
var SECRET_KEY_PATTERN, SECRET_VALUE_PATTERNS, REDACTED = "[REDACTED]";
|
|
18043
18043
|
var init_redact = __esm(() => {
|
|
18044
|
-
SECRET_KEY_PATTERN = /(SECRET|TOKEN|API_?KEY|PASSWORD|PRIVATE_?KEY|ACCESS_?KEY|WEBHOOK)/i;
|
|
18044
|
+
SECRET_KEY_PATTERN = /(SECRET|TOKEN(?!s\b)|API_?KEY|PASSWORD|PRIVATE_?KEY|ACCESS_?KEY|WEBHOOK)/i;
|
|
18045
18045
|
SECRET_VALUE_PATTERNS = [
|
|
18046
18046
|
/sk-[A-Za-z0-9_-]{16,}/g,
|
|
18047
18047
|
/ghp_[A-Za-z0-9]{16,}/g,
|
|
@@ -24993,12 +24993,15 @@ async function getGitRootMemo(workdir) {
|
|
|
24993
24993
|
}
|
|
24994
24994
|
return result ?? null;
|
|
24995
24995
|
}
|
|
24996
|
-
function
|
|
24997
|
-
const
|
|
24998
|
-
|
|
24996
|
+
function extractBasenamePattern(pattern) {
|
|
24997
|
+
const basename4 = pattern.slice(pattern.lastIndexOf("/") + 1);
|
|
24998
|
+
const parts = basename4.split("*");
|
|
24999
|
+
if (parts.length !== 2)
|
|
24999
25000
|
return null;
|
|
25000
|
-
const suffix =
|
|
25001
|
-
|
|
25001
|
+
const [prefix, suffix] = parts;
|
|
25002
|
+
if (!prefix && !suffix)
|
|
25003
|
+
return null;
|
|
25004
|
+
return { prefix, suffix };
|
|
25002
25005
|
}
|
|
25003
25006
|
function extractSearchTerms(sourceFile) {
|
|
25004
25007
|
const withoutPrefix = sourceFile.replace(/^(?:.*\/)?src\//, "");
|
|
@@ -25036,28 +25039,11 @@ async function importGrepFallback(sourceFiles, workdir, testFilePatterns) {
|
|
|
25036
25039
|
return results.filter((p) => p !== null);
|
|
25037
25040
|
}
|
|
25038
25041
|
async function mapSourceToTests(sourceFiles, workdir, packagePrefix, testFilePatterns = [...DEFAULT_TEST_FILE_PATTERNS]) {
|
|
25039
|
-
const
|
|
25042
|
+
const shapes = dedupeBasenamePatterns(testFilePatterns);
|
|
25043
|
+
const testDirs = [...new Set([...DEFAULT_SEPARATED_TEST_DIRS, ...extractTestDirs(testFilePatterns)])];
|
|
25040
25044
|
const result = [];
|
|
25041
25045
|
for (const sourceFile of sourceFiles) {
|
|
25042
|
-
const
|
|
25043
|
-
let innerRelative;
|
|
25044
|
-
let testBase;
|
|
25045
|
-
if (packagePrefix) {
|
|
25046
|
-
const srcRoot = `${packagePrefix}/src/`;
|
|
25047
|
-
const inner = sourceFile.startsWith(srcRoot) ? sourceFile.slice(srcRoot.length) : sourceFile.replace(/^.*\/src\//, "");
|
|
25048
|
-
innerRelative = inner.replace(/\.[^.]+$/, "");
|
|
25049
|
-
testBase = `${workdir}/${packagePrefix}`;
|
|
25050
|
-
} else {
|
|
25051
|
-
innerRelative = sourceFile.replace(/^src\//, "").replace(/\.[^.]+$/, "");
|
|
25052
|
-
testBase = workdir;
|
|
25053
|
-
}
|
|
25054
|
-
const candidates = [];
|
|
25055
|
-
for (const suffix of testSuffixes) {
|
|
25056
|
-
for (const testDir of DEFAULT_SEPARATED_TEST_DIRS) {
|
|
25057
|
-
candidates.push(`${testBase}/${testDir}/${innerRelative}${suffix}`);
|
|
25058
|
-
}
|
|
25059
|
-
candidates.push(`${workdir}/${sourceWithoutExt}${suffix}`);
|
|
25060
|
-
}
|
|
25046
|
+
const candidates = buildTestCandidates(sourceFile, workdir, packagePrefix, shapes, testDirs);
|
|
25061
25047
|
const existsFlags = await Promise.all(candidates.map((c) => _bunDeps.file(c).exists()));
|
|
25062
25048
|
candidates.forEach((c, i) => {
|
|
25063
25049
|
if (existsFlags[i])
|
|
@@ -25066,6 +25052,58 @@ async function mapSourceToTests(sourceFiles, workdir, packagePrefix, testFilePat
|
|
|
25066
25052
|
}
|
|
25067
25053
|
return result;
|
|
25068
25054
|
}
|
|
25055
|
+
function dedupeBasenamePatterns(testFilePatterns) {
|
|
25056
|
+
const seen = new Set;
|
|
25057
|
+
const shapes = [];
|
|
25058
|
+
for (const pattern of testFilePatterns) {
|
|
25059
|
+
const shape = extractBasenamePattern(pattern);
|
|
25060
|
+
if (!shape)
|
|
25061
|
+
continue;
|
|
25062
|
+
const key = `${shape.prefix}\x00${shape.suffix}`;
|
|
25063
|
+
if (seen.has(key))
|
|
25064
|
+
continue;
|
|
25065
|
+
seen.add(key);
|
|
25066
|
+
shapes.push(shape);
|
|
25067
|
+
}
|
|
25068
|
+
return shapes;
|
|
25069
|
+
}
|
|
25070
|
+
function buildTestCandidates(sourceFile, workdir, packagePrefix, shapes, testDirs) {
|
|
25071
|
+
const sourceWithoutExt = sourceFile.replace(/\.[^.]+$/, "");
|
|
25072
|
+
let innerRelative;
|
|
25073
|
+
let testBase;
|
|
25074
|
+
if (packagePrefix) {
|
|
25075
|
+
const srcRoot = `${packagePrefix}/src/`;
|
|
25076
|
+
const inner = sourceFile.startsWith(srcRoot) ? sourceFile.slice(srcRoot.length) : sourceFile.replace(/^.*\/src\//, "");
|
|
25077
|
+
innerRelative = inner.replace(/\.[^.]+$/, "");
|
|
25078
|
+
testBase = `${workdir}/${packagePrefix}`;
|
|
25079
|
+
} else {
|
|
25080
|
+
innerRelative = sourceFile.replace(/^src\//, "").replace(/\.[^.]+$/, "");
|
|
25081
|
+
testBase = workdir;
|
|
25082
|
+
}
|
|
25083
|
+
const lastSlash = innerRelative.lastIndexOf("/");
|
|
25084
|
+
const innerDir = lastSlash === -1 ? "" : innerRelative.slice(0, lastSlash);
|
|
25085
|
+
const baseName = lastSlash === -1 ? innerRelative : innerRelative.slice(lastSlash + 1);
|
|
25086
|
+
const sourceDirAbs = sourceWithoutExt.includes("/") ? `${workdir}/${sourceWithoutExt.slice(0, sourceWithoutExt.lastIndexOf("/"))}` : workdir;
|
|
25087
|
+
const candidates = [];
|
|
25088
|
+
for (const { prefix, suffix } of shapes) {
|
|
25089
|
+
if (prefix === "") {
|
|
25090
|
+
for (const testDir of testDirs) {
|
|
25091
|
+
candidates.push(`${testBase}/${testDir}/${innerRelative}${suffix}`);
|
|
25092
|
+
}
|
|
25093
|
+
candidates.push(`${workdir}/${sourceWithoutExt}${suffix}`);
|
|
25094
|
+
} else {
|
|
25095
|
+
const named = `${prefix}${baseName}${suffix}`;
|
|
25096
|
+
for (const testDir of testDirs) {
|
|
25097
|
+
candidates.push(`${testBase}/${testDir}/${innerDir ? `${innerDir}/` : ""}${named}`);
|
|
25098
|
+
if (innerDir)
|
|
25099
|
+
candidates.push(`${testBase}/${testDir}/${named}`);
|
|
25100
|
+
}
|
|
25101
|
+
candidates.push(`${sourceDirAbs}/${named}`);
|
|
25102
|
+
}
|
|
25103
|
+
}
|
|
25104
|
+
const sourceAbs = `${workdir}/${sourceFile}`;
|
|
25105
|
+
return [...new Set(candidates)].filter((c) => c !== sourceAbs);
|
|
25106
|
+
}
|
|
25069
25107
|
function buildSmartTestCommand(testFiles, baseCommand) {
|
|
25070
25108
|
if (testFiles.length === 0) {
|
|
25071
25109
|
return baseCommand;
|
|
@@ -37392,7 +37430,7 @@ var init_write_test = __esm(() => {
|
|
|
37392
37430
|
if (!input.beforeRef)
|
|
37393
37431
|
return parsed;
|
|
37394
37432
|
const allowedPaths = ctx.config.tdd?.testWriterAllowedPaths ?? ["src/index.ts", "src/**/index.ts"];
|
|
37395
|
-
const testFilePatterns =
|
|
37433
|
+
const testFilePatterns = input.resolvedTestPatterns?.globs;
|
|
37396
37434
|
const isolation = await verifyTestWriterIsolation(ctx.packageView.packageDir, input.beforeRef, allowedPaths, testFilePatterns, input.lite ? "lite" : "strict");
|
|
37397
37435
|
return { ...parsed, isolation };
|
|
37398
37436
|
}
|
|
@@ -38376,57 +38414,69 @@ var init_plan_critic_llm = __esm(() => {
|
|
|
38376
38414
|
});
|
|
38377
38415
|
|
|
38378
38416
|
// src/context/greenfield.ts
|
|
38379
|
-
|
|
38380
|
-
import { join as join23 } from "path";
|
|
38381
|
-
async function scanForTestFiles(dir, testPatterns, isRootCall = true) {
|
|
38382
|
-
const results = [];
|
|
38383
|
-
const ignoreDirs = new Set(["node_modules", "dist", "build", ".next", ".git"]);
|
|
38417
|
+
async function gitLsFiles2(workdir) {
|
|
38384
38418
|
try {
|
|
38385
|
-
const
|
|
38386
|
-
|
|
38387
|
-
|
|
38388
|
-
|
|
38389
|
-
|
|
38390
|
-
|
|
38391
|
-
|
|
38392
|
-
|
|
38393
|
-
|
|
38394
|
-
|
|
38395
|
-
|
|
38396
|
-
|
|
38419
|
+
const proc = _greenfieldDeps.spawn(["git", "ls-files"], {
|
|
38420
|
+
cwd: workdir,
|
|
38421
|
+
stdout: "pipe",
|
|
38422
|
+
stderr: "pipe"
|
|
38423
|
+
});
|
|
38424
|
+
const exitCode = await proc.exited;
|
|
38425
|
+
if (exitCode !== 0)
|
|
38426
|
+
return null;
|
|
38427
|
+
const output = await new Response(proc.stdout).text();
|
|
38428
|
+
return output.split(`
|
|
38429
|
+
`).filter(Boolean);
|
|
38430
|
+
} catch {
|
|
38431
|
+
return null;
|
|
38432
|
+
}
|
|
38433
|
+
}
|
|
38434
|
+
async function hasTestFiles(workdir, patterns) {
|
|
38435
|
+
const files = await gitLsFiles2(workdir);
|
|
38436
|
+
if (files !== null) {
|
|
38437
|
+
return files.some((f) => isTestFileByPatterns(f, patterns));
|
|
38438
|
+
}
|
|
38439
|
+
for (const pattern of patterns) {
|
|
38440
|
+
const g = new Bun.Glob(pattern);
|
|
38441
|
+
for await (const path5 of g.scan({ cwd: workdir, onlyFiles: true })) {
|
|
38442
|
+
if (!path5.split("/").some((seg) => IGNORE_DIRS.has(seg))) {
|
|
38443
|
+
return true;
|
|
38397
38444
|
}
|
|
38398
38445
|
}
|
|
38399
|
-
} catch (error48) {
|
|
38400
|
-
if (isRootCall) {
|
|
38401
|
-
throw error48;
|
|
38402
|
-
}
|
|
38403
38446
|
}
|
|
38404
|
-
return
|
|
38447
|
+
return false;
|
|
38405
38448
|
}
|
|
38406
38449
|
async function isGreenfieldStory(_story, workdir, patterns) {
|
|
38407
38450
|
try {
|
|
38408
|
-
|
|
38409
|
-
|
|
38410
|
-
return testFiles.length === 0;
|
|
38411
|
-
} catch (error48) {
|
|
38451
|
+
return !await hasTestFiles(workdir, patterns ?? DEFAULT_TEST_FILE_PATTERNS);
|
|
38452
|
+
} catch {
|
|
38412
38453
|
return false;
|
|
38413
38454
|
}
|
|
38414
38455
|
}
|
|
38415
|
-
var
|
|
38456
|
+
var _greenfieldDeps, IGNORE_DIRS;
|
|
38416
38457
|
var init_greenfield = __esm(() => {
|
|
38417
|
-
|
|
38418
|
-
|
|
38419
|
-
|
|
38420
|
-
|
|
38421
|
-
|
|
38422
|
-
"
|
|
38423
|
-
"
|
|
38424
|
-
"
|
|
38425
|
-
"
|
|
38426
|
-
"
|
|
38427
|
-
"
|
|
38428
|
-
"
|
|
38429
|
-
"
|
|
38458
|
+
init_test_runners();
|
|
38459
|
+
_greenfieldDeps = {
|
|
38460
|
+
spawn: Bun.spawn
|
|
38461
|
+
};
|
|
38462
|
+
IGNORE_DIRS = new Set([
|
|
38463
|
+
"node_modules",
|
|
38464
|
+
"dist",
|
|
38465
|
+
".next",
|
|
38466
|
+
".nuxt",
|
|
38467
|
+
".cache",
|
|
38468
|
+
"coverage",
|
|
38469
|
+
"vendor",
|
|
38470
|
+
"__pycache__",
|
|
38471
|
+
".venv",
|
|
38472
|
+
"venv",
|
|
38473
|
+
".eggs",
|
|
38474
|
+
"target",
|
|
38475
|
+
".gradle",
|
|
38476
|
+
"out",
|
|
38477
|
+
"tmp",
|
|
38478
|
+
"temp",
|
|
38479
|
+
".git"
|
|
38430
38480
|
]);
|
|
38431
38481
|
});
|
|
38432
38482
|
|
|
@@ -38589,13 +38639,13 @@ __export(exports_runners, {
|
|
|
38589
38639
|
_regressionRunnerDeps: () => _regressionRunnerDeps
|
|
38590
38640
|
});
|
|
38591
38641
|
import { existsSync as existsSync6 } from "fs";
|
|
38592
|
-
import { join as
|
|
38642
|
+
import { join as join23 } from "path";
|
|
38593
38643
|
async function verifyAssets(workingDirectory, expectedFiles) {
|
|
38594
38644
|
if (!expectedFiles || expectedFiles.length === 0)
|
|
38595
38645
|
return { success: true, missingFiles: [] };
|
|
38596
38646
|
const missingFiles = [];
|
|
38597
38647
|
for (const file3 of expectedFiles) {
|
|
38598
|
-
if (!existsSync6(
|
|
38648
|
+
if (!existsSync6(join23(workingDirectory, file3)))
|
|
38599
38649
|
missingFiles.push(file3);
|
|
38600
38650
|
}
|
|
38601
38651
|
if (missingFiles.length > 0) {
|
|
@@ -39042,7 +39092,7 @@ var init_apply_test_edit_declarations = __esm(() => {
|
|
|
39042
39092
|
});
|
|
39043
39093
|
|
|
39044
39094
|
// src/operations/validate-mock-structure-files.ts
|
|
39045
|
-
import { join as
|
|
39095
|
+
import { join as join24 } from "path";
|
|
39046
39096
|
async function validateMockStructureFiles(declarations, resolvedTestPatterns, packageDir, deps) {
|
|
39047
39097
|
const fileExists = deps?.fileExists ?? defaultFileExists;
|
|
39048
39098
|
const valid = [];
|
|
@@ -39055,7 +39105,7 @@ async function validateMockStructureFiles(declarations, resolvedTestPatterns, pa
|
|
|
39055
39105
|
const files = d.files ?? [d.file];
|
|
39056
39106
|
let allValid = true;
|
|
39057
39107
|
for (const file3 of files) {
|
|
39058
|
-
const absolutePath =
|
|
39108
|
+
const absolutePath = join24(packageDir, file3);
|
|
39059
39109
|
const exists = await fileExists(absolutePath);
|
|
39060
39110
|
if (!exists) {
|
|
39061
39111
|
allValid = false;
|
|
@@ -39763,28 +39813,47 @@ var init_verify_scoped = __esm(() => {
|
|
|
39763
39813
|
timeoutSeconds: scopedTimeout,
|
|
39764
39814
|
isFullSuite: selection.isFullSuite
|
|
39765
39815
|
});
|
|
39816
|
+
const runTests = async (command) => {
|
|
39817
|
+
const result2 = await deps.regression({
|
|
39818
|
+
workdir: cmdWorkdir,
|
|
39819
|
+
command,
|
|
39820
|
+
timeoutSeconds: scopedTimeout,
|
|
39821
|
+
forceExit: quality.quality?.forceExit,
|
|
39822
|
+
detectOpenHandles: quality.quality?.detectOpenHandles,
|
|
39823
|
+
detectOpenHandlesRetries: quality.quality?.detectOpenHandlesRetries,
|
|
39824
|
+
gracePeriodMs: quality.quality?.gracePeriodMs,
|
|
39825
|
+
drainTimeoutMs: quality.quality?.drainTimeoutMs,
|
|
39826
|
+
shell: quality.quality?.shell,
|
|
39827
|
+
stripEnvVars: quality.quality?.stripEnvVars
|
|
39828
|
+
});
|
|
39829
|
+
const parsed2 = result2.output ? deps.parseTestOutput(result2.output) : { passed: 0, failed: 0, failures: [] };
|
|
39830
|
+
return { result: result2, parsed: parsed2 };
|
|
39831
|
+
};
|
|
39766
39832
|
const start = Date.now();
|
|
39767
|
-
|
|
39768
|
-
|
|
39769
|
-
|
|
39770
|
-
|
|
39771
|
-
|
|
39772
|
-
|
|
39773
|
-
|
|
39774
|
-
|
|
39775
|
-
|
|
39776
|
-
|
|
39777
|
-
|
|
39778
|
-
|
|
39833
|
+
let effectiveCommand = selection.effectiveCommand;
|
|
39834
|
+
let isFullSuite = selection.isFullSuite;
|
|
39835
|
+
let scopeTestFallback = selection.scopeTestFallback;
|
|
39836
|
+
let { result, parsed } = await runTests(effectiveCommand);
|
|
39837
|
+
const ranNoTests = parsed.passed === 0 && parsed.failed === 0 && parsed.failures.length === 0;
|
|
39838
|
+
if (!result.success && result.status !== "TIMEOUT" && !isFullSuite && ranNoTests) {
|
|
39839
|
+
logger.warn("verify[scoped]", "Scoped run executed no tests \u2014 falling back to full suite", {
|
|
39840
|
+
storyId: input.storyId,
|
|
39841
|
+
command: effectiveCommand,
|
|
39842
|
+
exitCode: result.exitCode
|
|
39843
|
+
});
|
|
39844
|
+
effectiveCommand = baseCommand;
|
|
39845
|
+
isFullSuite = true;
|
|
39846
|
+
scopeTestFallback = true;
|
|
39847
|
+
({ result, parsed } = await runTests(effectiveCommand));
|
|
39848
|
+
}
|
|
39779
39849
|
const durationMs = Date.now() - start;
|
|
39780
|
-
const parsed = result.output ? deps.parseTestOutput(result.output) : { passed: 0, failed: 0, failures: [] };
|
|
39781
39850
|
if (result.success) {
|
|
39782
39851
|
logger.info("verify[scoped]", "Scoped tests passed", {
|
|
39783
39852
|
storyId: input.storyId,
|
|
39784
39853
|
passCount: parsed.passed,
|
|
39785
39854
|
durationMs,
|
|
39786
|
-
scopeTestFallback:
|
|
39787
|
-
isFullSuite
|
|
39855
|
+
scopeTestFallback: scopeTestFallback ?? false,
|
|
39856
|
+
isFullSuite
|
|
39788
39857
|
});
|
|
39789
39858
|
return {
|
|
39790
39859
|
success: true,
|
|
@@ -39792,16 +39861,16 @@ var init_verify_scoped = __esm(() => {
|
|
|
39792
39861
|
findings: [],
|
|
39793
39862
|
durationMs,
|
|
39794
39863
|
passCount: parsed.passed,
|
|
39795
|
-
isFullSuite
|
|
39796
|
-
scopeTestFallback
|
|
39864
|
+
isFullSuite,
|
|
39865
|
+
scopeTestFallback
|
|
39797
39866
|
};
|
|
39798
39867
|
}
|
|
39799
39868
|
if (result.status === "TIMEOUT") {
|
|
39800
39869
|
logger.warn("verify[scoped]", "Scoped tests timed out", {
|
|
39801
39870
|
storyId: input.storyId,
|
|
39802
39871
|
durationMs,
|
|
39803
|
-
scopeTestFallback:
|
|
39804
|
-
isFullSuite
|
|
39872
|
+
scopeTestFallback: scopeTestFallback ?? false,
|
|
39873
|
+
isFullSuite
|
|
39805
39874
|
});
|
|
39806
39875
|
return {
|
|
39807
39876
|
success: false,
|
|
@@ -39809,8 +39878,8 @@ var init_verify_scoped = __esm(() => {
|
|
|
39809
39878
|
findings: [],
|
|
39810
39879
|
durationMs,
|
|
39811
39880
|
passCount: parsed.passed,
|
|
39812
|
-
isFullSuite
|
|
39813
|
-
scopeTestFallback
|
|
39881
|
+
isFullSuite,
|
|
39882
|
+
scopeTestFallback
|
|
39814
39883
|
};
|
|
39815
39884
|
}
|
|
39816
39885
|
logger.warn("verify[scoped]", "Scoped tests failed", {
|
|
@@ -39818,17 +39887,35 @@ var init_verify_scoped = __esm(() => {
|
|
|
39818
39887
|
passCount: parsed.passed,
|
|
39819
39888
|
failCount: parsed.failed,
|
|
39820
39889
|
durationMs,
|
|
39821
|
-
scopeTestFallback:
|
|
39822
|
-
isFullSuite
|
|
39890
|
+
scopeTestFallback: scopeTestFallback ?? false,
|
|
39891
|
+
isFullSuite
|
|
39823
39892
|
});
|
|
39893
|
+
let findings = deps.testSummaryToFindings(parsed);
|
|
39894
|
+
if (findings.length === 0) {
|
|
39895
|
+
logger.warn("verify[scoped]", "Scoped verify execution-failed \u2014 emitting synth finding", {
|
|
39896
|
+
storyId: input.storyId,
|
|
39897
|
+
command: effectiveCommand,
|
|
39898
|
+
exitCode: result.exitCode,
|
|
39899
|
+
cwd: cmdWorkdir
|
|
39900
|
+
});
|
|
39901
|
+
findings = [
|
|
39902
|
+
executionFailureToFinding({
|
|
39903
|
+
command: result.command ?? effectiveCommand,
|
|
39904
|
+
exitCode: result.exitCode,
|
|
39905
|
+
output: result.output ?? "",
|
|
39906
|
+
packageDir: input.packagePrefix,
|
|
39907
|
+
cwd: cmdWorkdir
|
|
39908
|
+
})
|
|
39909
|
+
];
|
|
39910
|
+
}
|
|
39824
39911
|
return {
|
|
39825
39912
|
success: false,
|
|
39826
39913
|
status: "failed",
|
|
39827
|
-
findings
|
|
39914
|
+
findings,
|
|
39828
39915
|
durationMs,
|
|
39829
39916
|
passCount: parsed.passed,
|
|
39830
|
-
isFullSuite
|
|
39831
|
-
scopeTestFallback
|
|
39917
|
+
isFullSuite,
|
|
39918
|
+
scopeTestFallback
|
|
39832
39919
|
};
|
|
39833
39920
|
}
|
|
39834
39921
|
};
|
|
@@ -40618,7 +40705,7 @@ var init_lint_parsing = __esm(() => {
|
|
|
40618
40705
|
});
|
|
40619
40706
|
|
|
40620
40707
|
// src/review/scoped-lint.ts
|
|
40621
|
-
import { join as
|
|
40708
|
+
import { join as join25, relative as relative10 } from "path";
|
|
40622
40709
|
function shellQuotePath4(path5) {
|
|
40623
40710
|
return `'${path5.replaceAll("'", "'\\''")}'`;
|
|
40624
40711
|
}
|
|
@@ -40666,7 +40753,7 @@ function uniqueFiles(files) {
|
|
|
40666
40753
|
async function filterFilesToScope(files, workdir, projectDir, activePackageDir) {
|
|
40667
40754
|
const inScope = [];
|
|
40668
40755
|
for (const relPath of files) {
|
|
40669
|
-
const absPath =
|
|
40756
|
+
const absPath = join25(workdir, relPath);
|
|
40670
40757
|
const exists = await _scopedLintDeps.fileExists(absPath);
|
|
40671
40758
|
if (!exists)
|
|
40672
40759
|
continue;
|
|
@@ -44040,7 +44127,7 @@ var init_call = __esm(() => {
|
|
|
44040
44127
|
|
|
44041
44128
|
// src/runtime/cost-aggregator.ts
|
|
44042
44129
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
44043
|
-
import { join as
|
|
44130
|
+
import { join as join26 } from "path";
|
|
44044
44131
|
function makeCorrelationId() {
|
|
44045
44132
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
44046
44133
|
}
|
|
@@ -44231,7 +44318,7 @@ class CostAggregator {
|
|
|
44231
44318
|
if (events.length === 0 && errors3.length === 0)
|
|
44232
44319
|
return;
|
|
44233
44320
|
mkdirSync2(this._drainDir, { recursive: true });
|
|
44234
|
-
const path5 =
|
|
44321
|
+
const path5 = join26(this._drainDir, `${this._runId}.jsonl`);
|
|
44235
44322
|
const sorted = [...events, ...errors3].sort((a, b) => a.ts - b.ts);
|
|
44236
44323
|
await _costAggDeps.write(path5, `${sorted.map((e) => JSON.stringify(e)).join(`
|
|
44237
44324
|
`)}
|
|
@@ -44271,7 +44358,7 @@ var init_cost_aggregator = __esm(() => {
|
|
|
44271
44358
|
// src/runtime/prompt-auditor.ts
|
|
44272
44359
|
import { appendFileSync } from "fs";
|
|
44273
44360
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
44274
|
-
import { join as
|
|
44361
|
+
import { join as join27 } from "path";
|
|
44275
44362
|
function createNoOpPromptAuditor() {
|
|
44276
44363
|
return {
|
|
44277
44364
|
record() {},
|
|
@@ -44337,8 +44424,8 @@ class PromptAuditor {
|
|
|
44337
44424
|
_jsonlPath;
|
|
44338
44425
|
_featureDir;
|
|
44339
44426
|
constructor(runId, flushDir, featureName) {
|
|
44340
|
-
this._featureDir =
|
|
44341
|
-
this._jsonlPath =
|
|
44427
|
+
this._featureDir = join27(flushDir, featureName);
|
|
44428
|
+
this._jsonlPath = join27(this._featureDir, `${runId}.jsonl`);
|
|
44342
44429
|
}
|
|
44343
44430
|
record(entry) {
|
|
44344
44431
|
this._enqueue(entry);
|
|
@@ -44387,7 +44474,7 @@ class PromptAuditor {
|
|
|
44387
44474
|
const auditEntry = entry;
|
|
44388
44475
|
const filename = deriveTxtFilename(auditEntry);
|
|
44389
44476
|
try {
|
|
44390
|
-
await _promptAuditorDeps.write(
|
|
44477
|
+
await _promptAuditorDeps.write(join27(this._featureDir, filename), buildTxtContent(auditEntry));
|
|
44391
44478
|
} catch (err) {
|
|
44392
44479
|
throw tagAuditError(err, "txt");
|
|
44393
44480
|
}
|
|
@@ -44525,6 +44612,7 @@ function createPackageView(config2, packageDir, repoRoot, hasOverride) {
|
|
|
44525
44612
|
function createPackageRegistry(loader, repoRoot) {
|
|
44526
44613
|
const cache = new Map;
|
|
44527
44614
|
const mergedConfigs = new Map;
|
|
44615
|
+
let hydrated = false;
|
|
44528
44616
|
function toRelativeKey(packageDir) {
|
|
44529
44617
|
if (!packageDir)
|
|
44530
44618
|
return "";
|
|
@@ -44543,6 +44631,9 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44543
44631
|
}
|
|
44544
44632
|
const overrideConfig = mergedConfigs.get(key);
|
|
44545
44633
|
const hasOverride = overrideConfig !== undefined;
|
|
44634
|
+
if (!hasOverride && key && !hydrated) {
|
|
44635
|
+
_packagesDeps.getSafeLogger()?.warn("packages", "resolve() called for non-root package before hydrate(); returning root config (per-package overrides not applied)", { packageDir: key });
|
|
44636
|
+
}
|
|
44546
44637
|
const config2 = overrideConfig ?? loader.current();
|
|
44547
44638
|
const view = createPackageView(config2, key, repoRoot, hasOverride);
|
|
44548
44639
|
cache.set(key, view);
|
|
@@ -44563,6 +44654,7 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44563
44654
|
cache.delete(dir);
|
|
44564
44655
|
}
|
|
44565
44656
|
}
|
|
44657
|
+
hydrated = true;
|
|
44566
44658
|
}
|
|
44567
44659
|
return {
|
|
44568
44660
|
all() {
|
|
@@ -44575,8 +44667,11 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44575
44667
|
hydrate
|
|
44576
44668
|
};
|
|
44577
44669
|
}
|
|
44670
|
+
var _packagesDeps;
|
|
44578
44671
|
var init_packages = __esm(() => {
|
|
44579
44672
|
init_config();
|
|
44673
|
+
init_logger2();
|
|
44674
|
+
_packagesDeps = { getSafeLogger };
|
|
44580
44675
|
});
|
|
44581
44676
|
|
|
44582
44677
|
// src/runtime/agent-stream-events.ts
|
|
@@ -45535,7 +45630,7 @@ var init_pid_registry = __esm(() => {
|
|
|
45535
45630
|
// src/session/manager-deps.ts
|
|
45536
45631
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
45537
45632
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
45538
|
-
import { isAbsolute as isAbsolute9, join as
|
|
45633
|
+
import { isAbsolute as isAbsolute9, join as join28, relative as relative11, sep as sep2 } from "path";
|
|
45539
45634
|
function resolveProjectDirFromScratchDir(scratchDir) {
|
|
45540
45635
|
const marker = `${sep2}.nax${sep2}features${sep2}`;
|
|
45541
45636
|
const markerIdx = scratchDir.lastIndexOf(marker);
|
|
@@ -45556,7 +45651,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45556
45651
|
now: () => new Date().toISOString(),
|
|
45557
45652
|
nowMs: () => Date.now(),
|
|
45558
45653
|
uuid: () => randomUUID3(),
|
|
45559
|
-
sessionScratchDir: (projectDir, featureName, sessionId) =>
|
|
45654
|
+
sessionScratchDir: (projectDir, featureName, sessionId) => join28(projectDir, ".nax", "features", featureName, "sessions", sessionId),
|
|
45560
45655
|
writeDescriptor: async (scratchDir, descriptor, projectDir) => {
|
|
45561
45656
|
await mkdir5(scratchDir, { recursive: true });
|
|
45562
45657
|
const { handle: _handle, ...persistable } = descriptor;
|
|
@@ -45567,7 +45662,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45567
45662
|
persistable.scratchDir = toProjectRelativePath(derivedProjectDir, persistable.scratchDir);
|
|
45568
45663
|
}
|
|
45569
45664
|
}
|
|
45570
|
-
await Bun.write(
|
|
45665
|
+
await Bun.write(join28(scratchDir, "descriptor.json"), JSON.stringify(persistable, null, 2));
|
|
45571
45666
|
}
|
|
45572
45667
|
};
|
|
45573
45668
|
});
|
|
@@ -46318,7 +46413,7 @@ __export(exports_runtime, {
|
|
|
46318
46413
|
CostAggregator: () => CostAggregator,
|
|
46319
46414
|
AgentStreamEventBus: () => AgentStreamEventBus
|
|
46320
46415
|
});
|
|
46321
|
-
import { basename as basename5, join as
|
|
46416
|
+
import { basename as basename5, join as join29 } from "path";
|
|
46322
46417
|
function createRuntime(config2, workdir, opts) {
|
|
46323
46418
|
const runId = crypto.randomUUID();
|
|
46324
46419
|
const controller = new AbortController;
|
|
@@ -46334,10 +46429,10 @@ function createRuntime(config2, workdir, opts) {
|
|
|
46334
46429
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
46335
46430
|
const globalDir = globalOutputDir();
|
|
46336
46431
|
const curatorRollupPathValue = curatorRollupPath(globalDir, config2.curator?.rollupPath);
|
|
46337
|
-
const costDir =
|
|
46432
|
+
const costDir = join29(outputDir, "cost");
|
|
46338
46433
|
const costAggregator = opts?.costAggregator ?? new CostAggregator(runId, costDir);
|
|
46339
46434
|
const auditEnabled = config2.agent?.promptAudit?.enabled ?? false;
|
|
46340
|
-
const auditDir = config2.agent?.promptAudit?.dir ??
|
|
46435
|
+
const auditDir = config2.agent?.promptAudit?.dir ?? join29(outputDir, "prompt-audit");
|
|
46341
46436
|
let promptAuditor;
|
|
46342
46437
|
if (opts?.promptAuditor) {
|
|
46343
46438
|
promptAuditor = opts.promptAuditor;
|
|
@@ -46490,9 +46585,9 @@ async function allSettledBounded(tasks, limit) {
|
|
|
46490
46585
|
|
|
46491
46586
|
// src/context/injector.ts
|
|
46492
46587
|
import { existsSync as existsSync8 } from "fs";
|
|
46493
|
-
import { join as
|
|
46588
|
+
import { join as join30 } from "path";
|
|
46494
46589
|
async function detectNode(workdir) {
|
|
46495
|
-
const pkgPath =
|
|
46590
|
+
const pkgPath = join30(workdir, "package.json");
|
|
46496
46591
|
if (!existsSync8(pkgPath))
|
|
46497
46592
|
return null;
|
|
46498
46593
|
try {
|
|
@@ -46509,7 +46604,7 @@ async function detectNode(workdir) {
|
|
|
46509
46604
|
}
|
|
46510
46605
|
}
|
|
46511
46606
|
async function detectGo(workdir) {
|
|
46512
|
-
const goMod =
|
|
46607
|
+
const goMod = join30(workdir, "go.mod");
|
|
46513
46608
|
if (!existsSync8(goMod))
|
|
46514
46609
|
return null;
|
|
46515
46610
|
try {
|
|
@@ -46533,7 +46628,7 @@ async function detectGo(workdir) {
|
|
|
46533
46628
|
}
|
|
46534
46629
|
}
|
|
46535
46630
|
async function detectRust(workdir) {
|
|
46536
|
-
const cargoPath =
|
|
46631
|
+
const cargoPath = join30(workdir, "Cargo.toml");
|
|
46537
46632
|
if (!existsSync8(cargoPath))
|
|
46538
46633
|
return null;
|
|
46539
46634
|
try {
|
|
@@ -46549,8 +46644,8 @@ async function detectRust(workdir) {
|
|
|
46549
46644
|
}
|
|
46550
46645
|
}
|
|
46551
46646
|
async function detectPython(workdir) {
|
|
46552
|
-
const pyproject =
|
|
46553
|
-
const requirements =
|
|
46647
|
+
const pyproject = join30(workdir, "pyproject.toml");
|
|
46648
|
+
const requirements = join30(workdir, "requirements.txt");
|
|
46554
46649
|
if (!existsSync8(pyproject) && !existsSync8(requirements))
|
|
46555
46650
|
return null;
|
|
46556
46651
|
try {
|
|
@@ -46569,7 +46664,7 @@ async function detectPython(workdir) {
|
|
|
46569
46664
|
}
|
|
46570
46665
|
}
|
|
46571
46666
|
async function detectPhp(workdir) {
|
|
46572
|
-
const composerPath =
|
|
46667
|
+
const composerPath = join30(workdir, "composer.json");
|
|
46573
46668
|
if (!existsSync8(composerPath))
|
|
46574
46669
|
return null;
|
|
46575
46670
|
try {
|
|
@@ -46582,7 +46677,7 @@ async function detectPhp(workdir) {
|
|
|
46582
46677
|
}
|
|
46583
46678
|
}
|
|
46584
46679
|
async function detectRuby(workdir) {
|
|
46585
|
-
const gemfile =
|
|
46680
|
+
const gemfile = join30(workdir, "Gemfile");
|
|
46586
46681
|
if (!existsSync8(gemfile))
|
|
46587
46682
|
return null;
|
|
46588
46683
|
try {
|
|
@@ -46594,9 +46689,9 @@ async function detectRuby(workdir) {
|
|
|
46594
46689
|
}
|
|
46595
46690
|
}
|
|
46596
46691
|
async function detectJvm(workdir) {
|
|
46597
|
-
const pom =
|
|
46598
|
-
const gradle =
|
|
46599
|
-
const gradleKts =
|
|
46692
|
+
const pom = join30(workdir, "pom.xml");
|
|
46693
|
+
const gradle = join30(workdir, "build.gradle");
|
|
46694
|
+
const gradleKts = join30(workdir, "build.gradle.kts");
|
|
46600
46695
|
if (!existsSync8(pom) && !existsSync8(gradle) && !existsSync8(gradleKts))
|
|
46601
46696
|
return null;
|
|
46602
46697
|
try {
|
|
@@ -46604,7 +46699,7 @@ async function detectJvm(workdir) {
|
|
|
46604
46699
|
const content2 = await Bun.file(pom).text();
|
|
46605
46700
|
const nameMatch = content2.match(/<artifactId>([^<]+)<\/artifactId>/);
|
|
46606
46701
|
const deps2 = [...content2.matchAll(/<artifactId>([^<]+)<\/artifactId>/g)].map((m) => m[1]).filter((d) => d !== nameMatch?.[1]).slice(0, 10);
|
|
46607
|
-
const lang2 = existsSync8(
|
|
46702
|
+
const lang2 = existsSync8(join30(workdir, "src/main/kotlin")) ? "Kotlin" : "Java";
|
|
46608
46703
|
return { name: nameMatch?.[1], lang: lang2, dependencies: deps2 };
|
|
46609
46704
|
}
|
|
46610
46705
|
const gradleFile = existsSync8(gradleKts) ? gradleKts : gradle;
|
|
@@ -46858,7 +46953,7 @@ var init_windsurf = __esm(() => {
|
|
|
46858
46953
|
|
|
46859
46954
|
// src/context/generator.ts
|
|
46860
46955
|
import { existsSync as existsSync9 } from "fs";
|
|
46861
|
-
import { join as
|
|
46956
|
+
import { join as join31, relative as relative12 } from "path";
|
|
46862
46957
|
async function loadContextContent(options, config2) {
|
|
46863
46958
|
if (!_generatorDeps.existsSync(options.contextPath)) {
|
|
46864
46959
|
throw new Error(`Context file not found: ${options.contextPath}`);
|
|
@@ -46876,7 +46971,7 @@ async function generateFor(agent, options, config2) {
|
|
|
46876
46971
|
try {
|
|
46877
46972
|
const context = await loadContextContent(options, config2);
|
|
46878
46973
|
const content = generator.generate(context);
|
|
46879
|
-
const outputPath =
|
|
46974
|
+
const outputPath = join31(options.outputDir, generator.outputFile);
|
|
46880
46975
|
validateFilePath(outputPath, options.outputDir);
|
|
46881
46976
|
if (!options.dryRun) {
|
|
46882
46977
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46894,7 +46989,7 @@ async function generateAll(options, config2, agentFilter) {
|
|
|
46894
46989
|
for (const [agentKey, generator] of entries) {
|
|
46895
46990
|
try {
|
|
46896
46991
|
const content = generator.generate(context);
|
|
46897
|
-
const outputPath =
|
|
46992
|
+
const outputPath = join31(options.outputDir, generator.outputFile);
|
|
46898
46993
|
validateFilePath(outputPath, options.outputDir);
|
|
46899
46994
|
if (!options.dryRun) {
|
|
46900
46995
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46914,7 +47009,7 @@ async function discoverPackages(repoRoot) {
|
|
|
46914
47009
|
const glob = new Bun.Glob(pattern);
|
|
46915
47010
|
for await (const match of glob.scan({ cwd: repoRoot, dot: true })) {
|
|
46916
47011
|
const pkgRelative = match.replace(/^\.nax\/mono\//, "").replace(/\/context\.md$/, "");
|
|
46917
|
-
const pkgAbsolute =
|
|
47012
|
+
const pkgAbsolute = join31(repoRoot, pkgRelative);
|
|
46918
47013
|
if (!seen.has(pkgAbsolute)) {
|
|
46919
47014
|
seen.add(pkgAbsolute);
|
|
46920
47015
|
packages.push(pkgAbsolute);
|
|
@@ -46946,14 +47041,14 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
46946
47041
|
}
|
|
46947
47042
|
}
|
|
46948
47043
|
}
|
|
46949
|
-
const turboPath =
|
|
47044
|
+
const turboPath = join31(repoRoot, "turbo.json");
|
|
46950
47045
|
try {
|
|
46951
47046
|
const turbo = JSON.parse(await _generatorDeps.readTextFile(turboPath));
|
|
46952
47047
|
if (Array.isArray(turbo.packages)) {
|
|
46953
47048
|
await resolveGlobs(turbo.packages);
|
|
46954
47049
|
}
|
|
46955
47050
|
} catch {}
|
|
46956
|
-
const pkgPath =
|
|
47051
|
+
const pkgPath = join31(repoRoot, "package.json");
|
|
46957
47052
|
try {
|
|
46958
47053
|
const pkg = JSON.parse(await _generatorDeps.readTextFile(pkgPath));
|
|
46959
47054
|
const ws = pkg.workspaces;
|
|
@@ -46961,7 +47056,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
46961
47056
|
if (patterns.length > 0)
|
|
46962
47057
|
await resolveGlobs(patterns);
|
|
46963
47058
|
} catch {}
|
|
46964
|
-
const pnpmPath =
|
|
47059
|
+
const pnpmPath = join31(repoRoot, "pnpm-workspace.yaml");
|
|
46965
47060
|
try {
|
|
46966
47061
|
const raw = await _generatorDeps.readTextFile(pnpmPath);
|
|
46967
47062
|
const lines = raw.split(`
|
|
@@ -46987,7 +47082,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
46987
47082
|
async function generateForPackage(packageDir, config2, dryRun = false, repoRoot) {
|
|
46988
47083
|
const resolvedRepoRoot = repoRoot ?? packageDir;
|
|
46989
47084
|
const relativePkgPath = relative12(resolvedRepoRoot, packageDir);
|
|
46990
|
-
const contextPath =
|
|
47085
|
+
const contextPath = join31(resolvedRepoRoot, ".nax", "mono", relativePkgPath, "context.md");
|
|
46991
47086
|
if (!_generatorDeps.existsSync(contextPath)) {
|
|
46992
47087
|
return [
|
|
46993
47088
|
{
|
|
@@ -47055,7 +47150,7 @@ var init_generator2 = __esm(() => {
|
|
|
47055
47150
|
});
|
|
47056
47151
|
|
|
47057
47152
|
// src/analyze/scanner.ts
|
|
47058
|
-
import { join as
|
|
47153
|
+
import { join as join32 } from "path";
|
|
47059
47154
|
function resolveFrameworkAndRunner(language, pkg) {
|
|
47060
47155
|
if (language === "go")
|
|
47061
47156
|
return { framework: "", testRunner: "go-test" };
|
|
@@ -47077,7 +47172,7 @@ async function scanSourceRoots(workdir) {
|
|
|
47077
47172
|
});
|
|
47078
47173
|
try {
|
|
47079
47174
|
const language = await deps.detectLanguage(workdir);
|
|
47080
|
-
const pkg = await deps.readPackageJson(
|
|
47175
|
+
const pkg = await deps.readPackageJson(join32(workdir, "package.json"));
|
|
47081
47176
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
47082
47177
|
return [{ path: ".", language, framework, testRunner }];
|
|
47083
47178
|
} catch {
|
|
@@ -47095,9 +47190,9 @@ async function scanSourceRoots(workdir) {
|
|
|
47095
47190
|
packages = packages.slice(0, MAX_SOURCE_ROOTS);
|
|
47096
47191
|
}
|
|
47097
47192
|
return Promise.all(packages.map(async (pkgPath) => {
|
|
47098
|
-
const pkgDir = pkgPath === "." ? workdir :
|
|
47193
|
+
const pkgDir = pkgPath === "." ? workdir : join32(workdir, pkgPath);
|
|
47099
47194
|
const language = await deps.detectLanguage(pkgDir);
|
|
47100
|
-
const pkg = await deps.readPackageJson(
|
|
47195
|
+
const pkg = await deps.readPackageJson(join32(pkgDir, "package.json"));
|
|
47101
47196
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
47102
47197
|
return { path: pkgPath, language, framework, testRunner };
|
|
47103
47198
|
}));
|
|
@@ -47130,7 +47225,7 @@ var init_analyze = __esm(() => {
|
|
|
47130
47225
|
});
|
|
47131
47226
|
|
|
47132
47227
|
// src/debate/pre-phase/grounder.ts
|
|
47133
|
-
import { join as
|
|
47228
|
+
import { join as join33 } from "path";
|
|
47134
47229
|
async function buildCodebaseContext(workdir) {
|
|
47135
47230
|
const roots = await _grounderDeps.scanSourceRoots(workdir);
|
|
47136
47231
|
return buildSourceRootsSection(normalizeRoots(workdir, roots));
|
|
@@ -47142,7 +47237,7 @@ function normalizeRoots(workdir, roots) {
|
|
|
47142
47237
|
}));
|
|
47143
47238
|
}
|
|
47144
47239
|
async function writeManifestArtifact(ctx, manifest) {
|
|
47145
|
-
const manifestPath =
|
|
47240
|
+
const manifestPath = join33(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
47146
47241
|
await _grounderDeps.write(manifestPath, JSON.stringify(manifest, null, 2));
|
|
47147
47242
|
}
|
|
47148
47243
|
var _grounderDeps, grounderStrategy = async (ctx) => {
|
|
@@ -47485,7 +47580,7 @@ function formatSpecDeltas(blockers, manifest) {
|
|
|
47485
47580
|
|
|
47486
47581
|
// src/debate/verifiers/checks.ts
|
|
47487
47582
|
import { existsSync as defaultExistsSync } from "fs";
|
|
47488
|
-
import { join as
|
|
47583
|
+
import { join as join34 } from "path";
|
|
47489
47584
|
function checkFilesExist(prd, workdir, deps) {
|
|
47490
47585
|
const existsSync10 = deps?.existsSync ?? defaultExistsSync;
|
|
47491
47586
|
const findings = [];
|
|
@@ -47495,7 +47590,7 @@ function checkFilesExist(prd, workdir, deps) {
|
|
|
47495
47590
|
for (const entry of story.contextFiles) {
|
|
47496
47591
|
const filePath = typeof entry === "string" ? entry : entry.path;
|
|
47497
47592
|
const factId = typeof entry === "string" ? undefined : entry.factId;
|
|
47498
|
-
const absPath =
|
|
47593
|
+
const absPath = join34(workdir, filePath);
|
|
47499
47594
|
if (existsSync10(absPath))
|
|
47500
47595
|
continue;
|
|
47501
47596
|
if (factId) {
|
|
@@ -47606,7 +47701,7 @@ var init_checks3 = () => {};
|
|
|
47606
47701
|
|
|
47607
47702
|
// src/debate/verifiers/plan-checklist.ts
|
|
47608
47703
|
import { existsSync as existsSync10 } from "fs";
|
|
47609
|
-
import { join as
|
|
47704
|
+
import { join as join35 } from "path";
|
|
47610
47705
|
function parsePrd(output) {
|
|
47611
47706
|
if (!output)
|
|
47612
47707
|
return null;
|
|
@@ -47617,7 +47712,7 @@ function parsePrd(output) {
|
|
|
47617
47712
|
}
|
|
47618
47713
|
}
|
|
47619
47714
|
async function loadManifest(ctx) {
|
|
47620
|
-
const manifestPath =
|
|
47715
|
+
const manifestPath = join35(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
47621
47716
|
const raw = await _planChecklistDeps.readFile(manifestPath);
|
|
47622
47717
|
if (!raw)
|
|
47623
47718
|
return null;
|
|
@@ -47630,7 +47725,7 @@ async function loadManifest(ctx) {
|
|
|
47630
47725
|
}
|
|
47631
47726
|
}
|
|
47632
47727
|
async function emitSpecDeltas(ctx, blockers, manifest) {
|
|
47633
|
-
const artifactPath =
|
|
47728
|
+
const artifactPath = join35(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "spec-deltas.md");
|
|
47634
47729
|
const content = formatSpecDeltas(blockers, manifest ?? { repoFacts: [], specClaims: [], gaps: [] });
|
|
47635
47730
|
await _planChecklistDeps.write(artifactPath, content);
|
|
47636
47731
|
return artifactPath;
|
|
@@ -47976,7 +48071,7 @@ var init_runner_plan_helpers = __esm(() => {
|
|
|
47976
48071
|
});
|
|
47977
48072
|
|
|
47978
48073
|
// src/debate/runner-plan.ts
|
|
47979
|
-
import { join as
|
|
48074
|
+
import { join as join36 } from "path";
|
|
47980
48075
|
async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
47981
48076
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
47982
48077
|
const config2 = ctx.stageConfig;
|
|
@@ -48035,7 +48130,7 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
48035
48130
|
sessionMode: ctx.stageConfig.sessionMode ?? "one-shot",
|
|
48036
48131
|
proposers: ctx.stageConfig.proposers
|
|
48037
48132
|
});
|
|
48038
|
-
const outputPaths = resolved.map((_, i) =>
|
|
48133
|
+
const outputPaths = resolved.map((_, i) => join36(opts.outputDir, `prd-debate-${i}.json`));
|
|
48039
48134
|
const successful = [];
|
|
48040
48135
|
let rebuttalList;
|
|
48041
48136
|
if (selectorKind === "verifier-pick") {
|
|
@@ -50278,9 +50373,9 @@ function validateFeatureName(feature) {
|
|
|
50278
50373
|
|
|
50279
50374
|
// src/plan/critic.ts
|
|
50280
50375
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
50281
|
-
import { dirname as dirname7, join as
|
|
50376
|
+
import { dirname as dirname7, join as join39 } from "path";
|
|
50282
50377
|
async function writeSpecDeltas(findings, workdir, runId, storyId, manifest) {
|
|
50283
|
-
const path7 =
|
|
50378
|
+
const path7 = join39(workdir, ".nax", "runs", runId, "plan", storyId, "spec-deltas.md");
|
|
50284
50379
|
await mkdir6(dirname7(path7), { recursive: true });
|
|
50285
50380
|
await Bun.write(path7, formatSpecDeltas(findings, manifest));
|
|
50286
50381
|
return path7;
|
|
@@ -51493,9 +51588,9 @@ __export(exports_plan_decompose, {
|
|
|
51493
51588
|
runReplanLoop: () => runReplanLoop,
|
|
51494
51589
|
planDecomposeCommand: () => planDecomposeCommand
|
|
51495
51590
|
});
|
|
51496
|
-
import { join as
|
|
51591
|
+
import { join as join40 } from "path";
|
|
51497
51592
|
async function planDecomposeCommand(workdir, config2, options) {
|
|
51498
|
-
const prdPath =
|
|
51593
|
+
const prdPath = join40(workdir, ".nax", "features", options.feature, "prd.json");
|
|
51499
51594
|
if (!_planDeps.existsSync(prdPath)) {
|
|
51500
51595
|
throw new NaxError(`PRD not found: ${prdPath}`, "PRD_NOT_FOUND", {
|
|
51501
51596
|
stage: "decompose",
|
|
@@ -51669,7 +51764,7 @@ var init_plan_decompose = __esm(() => {
|
|
|
51669
51764
|
|
|
51670
51765
|
// src/cli/plan-runtime.ts
|
|
51671
51766
|
import { existsSync as existsSync15 } from "fs";
|
|
51672
|
-
import { join as
|
|
51767
|
+
import { join as join41 } from "path";
|
|
51673
51768
|
function isRuntimeWithAgentManager(value) {
|
|
51674
51769
|
return typeof value === "object" && value !== null && "agentManager" in value;
|
|
51675
51770
|
}
|
|
@@ -51721,7 +51816,7 @@ var init_plan_runtime = __esm(() => {
|
|
|
51721
51816
|
writeFile: (path7, content) => Bun.write(path7, content).then(() => {}),
|
|
51722
51817
|
scanSourceRoots: (workdir) => scanSourceRoots(workdir),
|
|
51723
51818
|
createRuntime: (cfg, wd, featureName) => createRuntime(cfg, wd, { featureName }),
|
|
51724
|
-
readPackageJson: (workdir) => Bun.file(
|
|
51819
|
+
readPackageJson: (workdir) => Bun.file(join41(workdir, "package.json")).json().catch(() => null),
|
|
51725
51820
|
spawnSync: (cmd, opts) => {
|
|
51726
51821
|
const result = Bun.spawnSync(cmd, opts ? { cwd: opts.cwd } : {});
|
|
51727
51822
|
return { stdout: result.stdout, exitCode: result.exitCode };
|
|
@@ -52106,7 +52201,7 @@ var init_metrics = __esm(() => {
|
|
|
52106
52201
|
|
|
52107
52202
|
// src/commands/common.ts
|
|
52108
52203
|
import { existsSync as existsSync16, readdirSync as readdirSync2, realpathSync as realpathSync3 } from "fs";
|
|
52109
|
-
import { join as
|
|
52204
|
+
import { join as join42, resolve as resolve13 } from "path";
|
|
52110
52205
|
function resolveProject(options = {}) {
|
|
52111
52206
|
const { dir, feature } = options;
|
|
52112
52207
|
let projectRoot;
|
|
@@ -52114,12 +52209,12 @@ function resolveProject(options = {}) {
|
|
|
52114
52209
|
let configPath;
|
|
52115
52210
|
if (dir) {
|
|
52116
52211
|
projectRoot = realpathSync3(resolve13(dir));
|
|
52117
|
-
naxDir =
|
|
52212
|
+
naxDir = join42(projectRoot, ".nax");
|
|
52118
52213
|
if (!existsSync16(naxDir)) {
|
|
52119
52214
|
throw new NaxError(`Directory does not contain a nax project: ${projectRoot}
|
|
52120
52215
|
Expected to find: ${naxDir}`, "NAX_DIR_NOT_FOUND", { projectRoot, naxDir });
|
|
52121
52216
|
}
|
|
52122
|
-
configPath =
|
|
52217
|
+
configPath = join42(naxDir, "config.json");
|
|
52123
52218
|
if (!existsSync16(configPath)) {
|
|
52124
52219
|
throw new NaxError(`.nax directory found but config.json is missing: ${naxDir}
|
|
52125
52220
|
Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
@@ -52127,17 +52222,17 @@ Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
|
52127
52222
|
} else {
|
|
52128
52223
|
const found = findProjectRoot(process.cwd());
|
|
52129
52224
|
if (!found) {
|
|
52130
|
-
const cwdNaxDir =
|
|
52225
|
+
const cwdNaxDir = join42(process.cwd(), ".nax");
|
|
52131
52226
|
if (existsSync16(cwdNaxDir)) {
|
|
52132
|
-
const cwdConfigPath =
|
|
52227
|
+
const cwdConfigPath = join42(cwdNaxDir, "config.json");
|
|
52133
52228
|
throw new NaxError(`.nax directory found but config.json is missing: ${cwdNaxDir}
|
|
52134
52229
|
Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, configPath: cwdConfigPath });
|
|
52135
52230
|
}
|
|
52136
52231
|
throw new NaxError("No nax project found. Run this command from within a nax project directory, or use -d flag to specify the project path.", "PROJECT_NOT_FOUND", { cwd: process.cwd() });
|
|
52137
52232
|
}
|
|
52138
52233
|
projectRoot = found;
|
|
52139
|
-
naxDir =
|
|
52140
|
-
configPath =
|
|
52234
|
+
naxDir = join42(projectRoot, ".nax");
|
|
52235
|
+
configPath = join42(naxDir, "config.json");
|
|
52141
52236
|
}
|
|
52142
52237
|
let featureDir;
|
|
52143
52238
|
if (feature) {
|
|
@@ -52146,8 +52241,8 @@ Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, co
|
|
|
52146
52241
|
} catch (error48) {
|
|
52147
52242
|
throw new NaxError(error48.message, "FEATURE_INVALID", { feature });
|
|
52148
52243
|
}
|
|
52149
|
-
const featuresDir =
|
|
52150
|
-
featureDir =
|
|
52244
|
+
const featuresDir = join42(naxDir, "features");
|
|
52245
|
+
featureDir = join42(featuresDir, feature);
|
|
52151
52246
|
if (!existsSync16(featureDir)) {
|
|
52152
52247
|
const availableFeatures = existsSync16(featuresDir) ? readdirSync2(featuresDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name) : [];
|
|
52153
52248
|
const availableMsg = availableFeatures.length > 0 ? `
|
|
@@ -52180,7 +52275,7 @@ async function resolveProjectAsync(options = {}) {
|
|
|
52180
52275
|
}
|
|
52181
52276
|
const isPlainName = !dir.includes("/") && !dir.includes("\\");
|
|
52182
52277
|
if (isPlainName) {
|
|
52183
|
-
const registryIdentityPath =
|
|
52278
|
+
const registryIdentityPath = join42(globalConfigDir(), dir, ".identity");
|
|
52184
52279
|
const identityFile = Bun.file(registryIdentityPath);
|
|
52185
52280
|
if (await identityFile.exists()) {
|
|
52186
52281
|
try {
|
|
@@ -52212,12 +52307,12 @@ function findProjectRoot(startDir) {
|
|
|
52212
52307
|
let current = resolve13(startDir);
|
|
52213
52308
|
let depth = 0;
|
|
52214
52309
|
while (depth < MAX_DIRECTORY_DEPTH) {
|
|
52215
|
-
const naxDir =
|
|
52216
|
-
const configPath =
|
|
52310
|
+
const naxDir = join42(current, ".nax");
|
|
52311
|
+
const configPath = join42(naxDir, "config.json");
|
|
52217
52312
|
if (existsSync16(configPath)) {
|
|
52218
52313
|
return realpathSync3(current);
|
|
52219
52314
|
}
|
|
52220
|
-
const parent =
|
|
52315
|
+
const parent = join42(current, "..");
|
|
52221
52316
|
if (parent === current) {
|
|
52222
52317
|
break;
|
|
52223
52318
|
}
|
|
@@ -52544,8 +52639,8 @@ var init_semantic_verdict = __esm(() => {
|
|
|
52544
52639
|
await Bun.write(filePath, content);
|
|
52545
52640
|
},
|
|
52546
52641
|
readdir: async (dir) => {
|
|
52547
|
-
const { readdir:
|
|
52548
|
-
return
|
|
52642
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
52643
|
+
return readdir2(dir);
|
|
52549
52644
|
},
|
|
52550
52645
|
readFile: async (filePath) => {
|
|
52551
52646
|
return Bun.file(filePath).text();
|
|
@@ -52996,10 +53091,10 @@ var init_acceptance_setup = __esm(() => {
|
|
|
52996
53091
|
},
|
|
52997
53092
|
deleteSemanticVerdicts: async (featureDir) => {
|
|
52998
53093
|
const dir = `${featureDir}/semantic-verdicts`;
|
|
52999
|
-
const { readdir:
|
|
53094
|
+
const { readdir: readdir2, unlink: unlink2 } = await import("fs/promises");
|
|
53000
53095
|
let files;
|
|
53001
53096
|
try {
|
|
53002
|
-
files = await
|
|
53097
|
+
files = await readdir2(dir);
|
|
53003
53098
|
} catch (err) {
|
|
53004
53099
|
if (err.code === "ENOENT")
|
|
53005
53100
|
return;
|
|
@@ -53376,10 +53471,10 @@ var init_effectiveness = __esm(() => {
|
|
|
53376
53471
|
|
|
53377
53472
|
// src/execution/progress.ts
|
|
53378
53473
|
import { appendFile as appendFile2, mkdir as mkdir7 } from "fs/promises";
|
|
53379
|
-
import { join as
|
|
53474
|
+
import { join as join45 } from "path";
|
|
53380
53475
|
async function appendProgress(featureDir, storyId, status, message) {
|
|
53381
53476
|
await mkdir7(featureDir, { recursive: true });
|
|
53382
|
-
const progressPath =
|
|
53477
|
+
const progressPath = join45(featureDir, "progress.txt");
|
|
53383
53478
|
const timestamp = new Date().toISOString();
|
|
53384
53479
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
53385
53480
|
`;
|
|
@@ -53573,7 +53668,7 @@ var init_completion = __esm(() => {
|
|
|
53573
53668
|
|
|
53574
53669
|
// src/constitution/loader.ts
|
|
53575
53670
|
import { existsSync as existsSync19 } from "fs";
|
|
53576
|
-
import { join as
|
|
53671
|
+
import { join as join46 } from "path";
|
|
53577
53672
|
function truncateToTokens(text, maxTokens) {
|
|
53578
53673
|
const maxChars = maxTokens * 3;
|
|
53579
53674
|
if (text.length <= maxChars) {
|
|
@@ -53595,7 +53690,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53595
53690
|
}
|
|
53596
53691
|
let combinedContent = "";
|
|
53597
53692
|
if (!config2.skipGlobal) {
|
|
53598
|
-
const globalPath =
|
|
53693
|
+
const globalPath = join46(globalConfigDir(), config2.path);
|
|
53599
53694
|
if (existsSync19(globalPath)) {
|
|
53600
53695
|
const validatedPath = validateFilePath(globalPath, globalConfigDir());
|
|
53601
53696
|
const globalFile = Bun.file(validatedPath);
|
|
@@ -53605,7 +53700,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53605
53700
|
}
|
|
53606
53701
|
}
|
|
53607
53702
|
}
|
|
53608
|
-
const projectPath =
|
|
53703
|
+
const projectPath = join46(projectDir, config2.path);
|
|
53609
53704
|
if (existsSync19(projectPath)) {
|
|
53610
53705
|
const validatedPath = validateFilePath(projectPath, projectDir);
|
|
53611
53706
|
const projectFile = Bun.file(validatedPath);
|
|
@@ -55039,7 +55134,7 @@ var init_story_orchestrator = __esm(() => {
|
|
|
55039
55134
|
});
|
|
55040
55135
|
|
|
55041
55136
|
// src/execution/build-plan-for-strategy.ts
|
|
55042
|
-
import { join as
|
|
55137
|
+
import { join as join47 } from "path";
|
|
55043
55138
|
function requiresInitialRefCapture(strategy) {
|
|
55044
55139
|
return isThreeSessionStrategy(strategy);
|
|
55045
55140
|
}
|
|
@@ -55085,7 +55180,7 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55085
55180
|
}
|
|
55086
55181
|
if (shouldRunRectification(config2) && inputs.rectification) {
|
|
55087
55182
|
const sink = makeDeclarationSink();
|
|
55088
|
-
const packageDir =
|
|
55183
|
+
const packageDir = join47(ctx.packageDir, story.workdir ?? "");
|
|
55089
55184
|
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.packageDir, story.workdir);
|
|
55090
55185
|
const strategies = [];
|
|
55091
55186
|
const pkgQuality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
@@ -55155,8 +55250,27 @@ var init_build_plan_for_strategy = __esm(() => {
|
|
|
55155
55250
|
init_story_orchestrator();
|
|
55156
55251
|
});
|
|
55157
55252
|
|
|
55253
|
+
// src/utils/paths.ts
|
|
55254
|
+
import { join as join48, relative as relative13, sep as sep4 } from "path";
|
|
55255
|
+
function packageDirRelative(projectDir, workdir) {
|
|
55256
|
+
if (!projectDir || !workdir || workdir === projectDir)
|
|
55257
|
+
return;
|
|
55258
|
+
const rel = relative13(projectDir, workdir);
|
|
55259
|
+
if (rel === ".." || rel.startsWith(`..${sep4}`))
|
|
55260
|
+
return;
|
|
55261
|
+
return rel && rel !== "." ? rel : undefined;
|
|
55262
|
+
}
|
|
55263
|
+
function getRunsDir() {
|
|
55264
|
+
return process.env.NAX_RUNS_DIR ?? join48(globalConfigDir(), "runs");
|
|
55265
|
+
}
|
|
55266
|
+
function getEventsRootDir() {
|
|
55267
|
+
return join48(globalConfigDir(), "events");
|
|
55268
|
+
}
|
|
55269
|
+
var init_paths3 = __esm(() => {
|
|
55270
|
+
init_paths();
|
|
55271
|
+
});
|
|
55272
|
+
|
|
55158
55273
|
// src/execution/plan-inputs.ts
|
|
55159
|
-
import { relative as relative13, sep as sep4 } from "path";
|
|
55160
55274
|
function validatePlanInputs(story, config2) {
|
|
55161
55275
|
if (!story.id || story.id.trim() === "") {
|
|
55162
55276
|
throw new NaxError("Story ID is required and must be non-empty", "STORY_ID_INVALID", {
|
|
@@ -55232,15 +55346,8 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55232
55346
|
if (!_isTdd && !ctx.prompt?.trim()) {
|
|
55233
55347
|
throw new NaxError(`Prompt missing for strategy "${ctx.routing.testStrategy}" \u2014 non-TDD strategies require ctx.prompt`, "PROMPT_NOT_BUILT", { stage: "plan-inputs", storyId: story.id, testStrategy: ctx.routing.testStrategy });
|
|
55234
55348
|
}
|
|
55235
|
-
const
|
|
55236
|
-
|
|
55237
|
-
return;
|
|
55238
|
-
const rel = relative13(ctx.projectDir, ctx.workdir);
|
|
55239
|
-
if (rel === ".." || rel.startsWith(`..${sep4}`))
|
|
55240
|
-
return;
|
|
55241
|
-
return rel && rel !== "." ? rel : undefined;
|
|
55242
|
-
})();
|
|
55243
|
-
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.projectDir, packageDirRelative);
|
|
55349
|
+
const packageDirRel = packageDirRelative(ctx.projectDir, ctx.workdir);
|
|
55350
|
+
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.projectDir, packageDirRel);
|
|
55244
55351
|
const [testWriterPrompt, implementerPrompt, verifierPrompt] = _isTdd ? await Promise.all([
|
|
55245
55352
|
_isFreshRun ? buildThreeSessionPrompt("test-writer", ctx, isLite) : Promise.resolve(""),
|
|
55246
55353
|
buildThreeSessionPrompt("implementer", ctx, isLite),
|
|
@@ -55251,7 +55358,8 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55251
55358
|
promptMarkdown: testWriterPrompt,
|
|
55252
55359
|
featureContextMarkdown: ctx.featureContextMarkdown,
|
|
55253
55360
|
constitution: ctx.constitution?.content,
|
|
55254
|
-
lite: isLite
|
|
55361
|
+
lite: isLite,
|
|
55362
|
+
resolvedTestPatterns
|
|
55255
55363
|
} : undefined;
|
|
55256
55364
|
const greenfieldGateInput = _isTdd && _isFreshRun && resolvedTestPatterns ? { story, workdir: ctx.workdir, resolvedTestPatterns } : undefined;
|
|
55257
55365
|
const implementerInput = {
|
|
@@ -55276,7 +55384,7 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55276
55384
|
naxIgnoreIndex: ctx.naxIgnoreIndex,
|
|
55277
55385
|
regressionMode: toVerifyScopedMode(ctx.config.execution?.regressionGate?.mode),
|
|
55278
55386
|
repoRoot: ctx.projectDir,
|
|
55279
|
-
packagePrefix:
|
|
55387
|
+
packagePrefix: packageDirRel,
|
|
55280
55388
|
resolvedTestPatterns
|
|
55281
55389
|
} : undefined;
|
|
55282
55390
|
const lintCheckInput = ctx.config.review?.enabled === true && ctx.config.review.checks?.includes("lint") && ctx.config.quality.commands.lint ? { workdir: ctx.workdir, storyId: story.id } : undefined;
|
|
@@ -55381,6 +55489,7 @@ var init_plan_inputs = __esm(() => {
|
|
|
55381
55489
|
init_prompts();
|
|
55382
55490
|
init_review();
|
|
55383
55491
|
init_resolver();
|
|
55492
|
+
init_paths3();
|
|
55384
55493
|
});
|
|
55385
55494
|
|
|
55386
55495
|
// src/pipeline/stages/execution-helpers.ts
|
|
@@ -56446,6 +56555,8 @@ var init_queue_check = __esm(() => {
|
|
|
56446
56555
|
// src/pipeline/stages/routing.ts
|
|
56447
56556
|
var routingStage, _routingDeps;
|
|
56448
56557
|
var init_routing2 = __esm(() => {
|
|
56558
|
+
init_test_runners();
|
|
56559
|
+
init_paths3();
|
|
56449
56560
|
init_greenfield();
|
|
56450
56561
|
init_logger2();
|
|
56451
56562
|
init_prd();
|
|
@@ -56489,7 +56600,16 @@ var init_routing2 = __esm(() => {
|
|
|
56489
56600
|
const greenfieldDetectionEnabled = ctx.config.tdd.greenfieldDetection ?? true;
|
|
56490
56601
|
if (greenfieldDetectionEnabled && routing.testStrategy.startsWith("three-session-tdd")) {
|
|
56491
56602
|
const greenfieldScanDir = ctx.workdir;
|
|
56492
|
-
const
|
|
56603
|
+
const root = ctx.projectDir ?? ctx.workdir;
|
|
56604
|
+
const packageDir = packageDirRelative(root, ctx.workdir);
|
|
56605
|
+
const resolved = await _routingDeps.resolveTestFilePatterns(ctx.config, root, packageDir, { storyId: ctx.story.id }).catch((err) => {
|
|
56606
|
+
logger.debug("routing", "Test-pattern resolution failed; using default greenfield patterns", {
|
|
56607
|
+
storyId: ctx.story.id,
|
|
56608
|
+
error: errorMessage(err)
|
|
56609
|
+
});
|
|
56610
|
+
return;
|
|
56611
|
+
});
|
|
56612
|
+
const isGreenfield = await _routingDeps.isGreenfieldStory(ctx.story, greenfieldScanDir, resolved?.globs);
|
|
56493
56613
|
if (isGreenfield) {
|
|
56494
56614
|
logger.info("routing", "Greenfield detected \u2014 forcing test-after strategy", {
|
|
56495
56615
|
storyId: ctx.story.id,
|
|
@@ -56517,6 +56637,7 @@ var init_routing2 = __esm(() => {
|
|
|
56517
56637
|
resolveRouting,
|
|
56518
56638
|
complexityToModelTier,
|
|
56519
56639
|
isGreenfieldStory,
|
|
56640
|
+
resolveTestFilePatterns,
|
|
56520
56641
|
clearCache,
|
|
56521
56642
|
savePRD
|
|
56522
56643
|
};
|
|
@@ -59433,18 +59554,6 @@ var init_loader4 = __esm(() => {
|
|
|
59433
59554
|
FALLBACK_TEST_FILE_RE = /\.(test|spec)\.(ts|js|tsx|jsx|mjs)$/;
|
|
59434
59555
|
});
|
|
59435
59556
|
|
|
59436
|
-
// src/utils/paths.ts
|
|
59437
|
-
import { join as join68 } from "path";
|
|
59438
|
-
function getRunsDir() {
|
|
59439
|
-
return process.env.NAX_RUNS_DIR ?? join68(globalConfigDir(), "runs");
|
|
59440
|
-
}
|
|
59441
|
-
function getEventsRootDir() {
|
|
59442
|
-
return join68(globalConfigDir(), "events");
|
|
59443
|
-
}
|
|
59444
|
-
var init_paths3 = __esm(() => {
|
|
59445
|
-
init_paths();
|
|
59446
|
-
});
|
|
59447
|
-
|
|
59448
59557
|
// src/utils/command-argv.ts
|
|
59449
59558
|
function parseCommandToArgv(command) {
|
|
59450
59559
|
const safeEnv = buildAllowedEnv();
|
|
@@ -59499,7 +59608,7 @@ var init_command_argv = __esm(() => {
|
|
|
59499
59608
|
});
|
|
59500
59609
|
|
|
59501
59610
|
// src/hooks/runner.ts
|
|
59502
|
-
import { join as
|
|
59611
|
+
import { join as join74 } from "path";
|
|
59503
59612
|
function createDrainDeadline2(deadlineMs) {
|
|
59504
59613
|
let timeoutId;
|
|
59505
59614
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -59518,14 +59627,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
59518
59627
|
let globalHooks = { hooks: {} };
|
|
59519
59628
|
let projectHooks = { hooks: {} };
|
|
59520
59629
|
let skipGlobal = false;
|
|
59521
|
-
const projectPath =
|
|
59630
|
+
const projectPath = join74(projectDir, "hooks.json");
|
|
59522
59631
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
59523
59632
|
if (projectData) {
|
|
59524
59633
|
projectHooks = projectData;
|
|
59525
59634
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
59526
59635
|
}
|
|
59527
59636
|
if (!skipGlobal && globalDir) {
|
|
59528
|
-
const globalPath =
|
|
59637
|
+
const globalPath = join74(globalDir, "hooks.json");
|
|
59529
59638
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
59530
59639
|
if (globalData) {
|
|
59531
59640
|
globalHooks = globalData;
|
|
@@ -59695,7 +59804,7 @@ var package_default;
|
|
|
59695
59804
|
var init_package = __esm(() => {
|
|
59696
59805
|
package_default = {
|
|
59697
59806
|
name: "@nathapp/nax",
|
|
59698
|
-
version: "0.69.
|
|
59807
|
+
version: "0.69.8",
|
|
59699
59808
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
59700
59809
|
type: "module",
|
|
59701
59810
|
bin: {
|
|
@@ -59790,8 +59899,8 @@ var init_version = __esm(() => {
|
|
|
59790
59899
|
NAX_VERSION = package_default.version;
|
|
59791
59900
|
NAX_COMMIT = (() => {
|
|
59792
59901
|
try {
|
|
59793
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
59794
|
-
return "
|
|
59902
|
+
if (/^[0-9a-f]{6,10}$/.test("0b7fc5bf"))
|
|
59903
|
+
return "0b7fc5bf";
|
|
59795
59904
|
} catch {}
|
|
59796
59905
|
try {
|
|
59797
59906
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -60668,15 +60777,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
60668
60777
|
|
|
60669
60778
|
// src/session/scratch-purge.ts
|
|
60670
60779
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
60671
|
-
import { dirname as dirname12, join as
|
|
60780
|
+
import { dirname as dirname12, join as join75 } from "path";
|
|
60672
60781
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
60673
|
-
const sessionsDir =
|
|
60782
|
+
const sessionsDir = join75(projectDir, ".nax", "features", featureName, "sessions");
|
|
60674
60783
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
60675
60784
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
60676
60785
|
let purged = 0;
|
|
60677
60786
|
for (const sessionId of sessionIds) {
|
|
60678
|
-
const sessionDir =
|
|
60679
|
-
const descriptorPath =
|
|
60787
|
+
const sessionDir = join75(sessionsDir, sessionId);
|
|
60788
|
+
const descriptorPath = join75(sessionDir, "descriptor.json");
|
|
60680
60789
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
60681
60790
|
continue;
|
|
60682
60791
|
let lastActivityAt;
|
|
@@ -60692,7 +60801,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
60692
60801
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
60693
60802
|
continue;
|
|
60694
60803
|
if (archiveInsteadOfDelete) {
|
|
60695
|
-
const archiveDest =
|
|
60804
|
+
const archiveDest = join75(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
60696
60805
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
60697
60806
|
} else {
|
|
60698
60807
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -61430,12 +61539,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
61430
61539
|
|
|
61431
61540
|
// src/pipeline/subscribers/events-writer.ts
|
|
61432
61541
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
61433
|
-
import { basename as basename13, join as
|
|
61542
|
+
import { basename as basename13, join as join76 } from "path";
|
|
61434
61543
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
61435
61544
|
const logger = getSafeLogger();
|
|
61436
61545
|
const project = basename13(workdir);
|
|
61437
|
-
const eventsDir =
|
|
61438
|
-
const eventsFile =
|
|
61546
|
+
const eventsDir = join76(getEventsRootDir(), project);
|
|
61547
|
+
const eventsFile = join76(eventsDir, "events.jsonl");
|
|
61439
61548
|
let dirReady = false;
|
|
61440
61549
|
const write = (line) => {
|
|
61441
61550
|
return (async () => {
|
|
@@ -61616,12 +61725,12 @@ var init_interaction2 = __esm(() => {
|
|
|
61616
61725
|
|
|
61617
61726
|
// src/pipeline/subscribers/registry.ts
|
|
61618
61727
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
61619
|
-
import { basename as basename14, join as
|
|
61728
|
+
import { basename as basename14, join as join77 } from "path";
|
|
61620
61729
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
61621
61730
|
const logger = getSafeLogger();
|
|
61622
61731
|
const project = basename14(workdir);
|
|
61623
|
-
const runDir =
|
|
61624
|
-
const metaFile =
|
|
61732
|
+
const runDir = join77(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
61733
|
+
const metaFile = join77(runDir, "meta.json");
|
|
61625
61734
|
const unsub = bus.on("run:started", (_ev) => {
|
|
61626
61735
|
return (async () => {
|
|
61627
61736
|
try {
|
|
@@ -61631,8 +61740,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
61631
61740
|
project,
|
|
61632
61741
|
feature,
|
|
61633
61742
|
workdir,
|
|
61634
|
-
statusPath:
|
|
61635
|
-
eventsDir:
|
|
61743
|
+
statusPath: join77(outputDir, "features", feature, "status.json"),
|
|
61744
|
+
eventsDir: join77(outputDir, "features", feature, "runs"),
|
|
61636
61745
|
registeredAt: new Date().toISOString()
|
|
61637
61746
|
};
|
|
61638
61747
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -61878,7 +61987,7 @@ var init_types9 = __esm(() => {
|
|
|
61878
61987
|
|
|
61879
61988
|
// src/worktree/dependencies.ts
|
|
61880
61989
|
import { existsSync as existsSync30 } from "fs";
|
|
61881
|
-
import { join as
|
|
61990
|
+
import { join as join78 } from "path";
|
|
61882
61991
|
async function prepareWorktreeDependencies(options) {
|
|
61883
61992
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
61884
61993
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -61892,7 +62001,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
61892
62001
|
}
|
|
61893
62002
|
}
|
|
61894
62003
|
function resolveDependencyCwd(options) {
|
|
61895
|
-
return options.storyWorkdir ?
|
|
62004
|
+
return options.storyWorkdir ? join78(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
61896
62005
|
}
|
|
61897
62006
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
61898
62007
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -61902,7 +62011,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
61902
62011
|
}
|
|
61903
62012
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
61904
62013
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
61905
|
-
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(
|
|
62014
|
+
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join78(directory, filename))));
|
|
61906
62015
|
}
|
|
61907
62016
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
61908
62017
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -61966,13 +62075,13 @@ __export(exports_manager, {
|
|
|
61966
62075
|
});
|
|
61967
62076
|
import { existsSync as existsSync31, symlinkSync } from "fs";
|
|
61968
62077
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
61969
|
-
import { join as
|
|
62078
|
+
import { join as join79 } from "path";
|
|
61970
62079
|
|
|
61971
62080
|
class WorktreeManager {
|
|
61972
62081
|
async ensureGitExcludes(projectRoot) {
|
|
61973
62082
|
const logger = getSafeLogger();
|
|
61974
|
-
const infoDir =
|
|
61975
|
-
const excludePath =
|
|
62083
|
+
const infoDir = join79(projectRoot, ".git", "info");
|
|
62084
|
+
const excludePath = join79(infoDir, "exclude");
|
|
61976
62085
|
try {
|
|
61977
62086
|
await mkdir15(infoDir, { recursive: true });
|
|
61978
62087
|
let existing = "";
|
|
@@ -61999,7 +62108,7 @@ ${missing.join(`
|
|
|
61999
62108
|
}
|
|
62000
62109
|
async create(projectRoot, storyId) {
|
|
62001
62110
|
validateStoryId(storyId);
|
|
62002
|
-
const worktreePath =
|
|
62111
|
+
const worktreePath = join79(projectRoot, ".nax-wt", storyId);
|
|
62003
62112
|
const branchName = `nax/${storyId}`;
|
|
62004
62113
|
try {
|
|
62005
62114
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -62040,9 +62149,9 @@ ${missing.join(`
|
|
|
62040
62149
|
}
|
|
62041
62150
|
throw new Error(`Failed to create worktree: ${String(error48)}`);
|
|
62042
62151
|
}
|
|
62043
|
-
const envSource =
|
|
62152
|
+
const envSource = join79(projectRoot, ".env");
|
|
62044
62153
|
if (existsSync31(envSource)) {
|
|
62045
|
-
const envTarget =
|
|
62154
|
+
const envTarget = join79(worktreePath, ".env");
|
|
62046
62155
|
try {
|
|
62047
62156
|
symlinkSync(envSource, envTarget, "file");
|
|
62048
62157
|
} catch (error48) {
|
|
@@ -62053,7 +62162,7 @@ ${missing.join(`
|
|
|
62053
62162
|
}
|
|
62054
62163
|
async remove(projectRoot, storyId) {
|
|
62055
62164
|
validateStoryId(storyId);
|
|
62056
|
-
const worktreePath =
|
|
62165
|
+
const worktreePath = join79(projectRoot, ".nax-wt", storyId);
|
|
62057
62166
|
const branchName = `nax/${storyId}`;
|
|
62058
62167
|
try {
|
|
62059
62168
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -62865,10 +62974,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
62865
62974
|
});
|
|
62866
62975
|
|
|
62867
62976
|
// src/execution/pipeline-result-handler.ts
|
|
62868
|
-
import { join as
|
|
62977
|
+
import { join as join80 } from "path";
|
|
62869
62978
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
62870
62979
|
const logger = getSafeLogger();
|
|
62871
|
-
const worktreePath =
|
|
62980
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62872
62981
|
try {
|
|
62873
62982
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
62874
62983
|
cwd: projectRoot,
|
|
@@ -63085,7 +63194,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
63085
63194
|
|
|
63086
63195
|
// src/execution/iteration-runner.ts
|
|
63087
63196
|
import { existsSync as existsSync32 } from "fs";
|
|
63088
|
-
import { join as
|
|
63197
|
+
import { join as join81 } from "path";
|
|
63089
63198
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
63090
63199
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
63091
63200
|
if (ctx.dryRun) {
|
|
@@ -63110,7 +63219,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63110
63219
|
const storyStartTime = Date.now();
|
|
63111
63220
|
let effectiveWorkdir = ctx.workdir;
|
|
63112
63221
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63113
|
-
const worktreePath =
|
|
63222
|
+
const worktreePath = join81(ctx.workdir, ".nax-wt", story.id);
|
|
63114
63223
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
63115
63224
|
if (!worktreeExists) {
|
|
63116
63225
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -63130,7 +63239,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63130
63239
|
}
|
|
63131
63240
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
63132
63241
|
const profileOverride = ctx.config.profile && ctx.config.profile !== "default" ? { profile: ctx.config.profile } : undefined;
|
|
63133
|
-
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(
|
|
63242
|
+
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join81(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
|
|
63134
63243
|
let dependencyContext;
|
|
63135
63244
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63136
63245
|
try {
|
|
@@ -63157,7 +63266,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63157
63266
|
};
|
|
63158
63267
|
}
|
|
63159
63268
|
}
|
|
63160
|
-
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ?
|
|
63269
|
+
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ? join81(effectiveWorkdir, story.workdir) : effectiveWorkdir : story.workdir ? join81(ctx.workdir, story.workdir) : ctx.workdir;
|
|
63161
63270
|
const pipelineContext = {
|
|
63162
63271
|
config: effectiveConfig,
|
|
63163
63272
|
rootConfig: ctx.config,
|
|
@@ -63359,7 +63468,7 @@ __export(exports_parallel_worker, {
|
|
|
63359
63468
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
63360
63469
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
63361
63470
|
});
|
|
63362
|
-
import { join as
|
|
63471
|
+
import { join as join82 } from "path";
|
|
63363
63472
|
function buildWorktreePipelineContext(base, _story) {
|
|
63364
63473
|
return { ...base, prd: structuredClone(base.prd) };
|
|
63365
63474
|
}
|
|
@@ -63382,7 +63491,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
63382
63491
|
story,
|
|
63383
63492
|
stories: [story],
|
|
63384
63493
|
projectDir: context.projectDir,
|
|
63385
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
63494
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join82(worktreePath, story.workdir) : worktreePath),
|
|
63386
63495
|
worktreeDependencyContext: dependencyContext,
|
|
63387
63496
|
routing,
|
|
63388
63497
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -64269,7 +64378,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
64269
64378
|
var init_status_file = () => {};
|
|
64270
64379
|
|
|
64271
64380
|
// src/execution/status-writer.ts
|
|
64272
|
-
import { join as
|
|
64381
|
+
import { join as join83 } from "path";
|
|
64273
64382
|
|
|
64274
64383
|
class StatusWriter {
|
|
64275
64384
|
statusFile;
|
|
@@ -64388,7 +64497,7 @@ class StatusWriter {
|
|
|
64388
64497
|
if (!this._prd)
|
|
64389
64498
|
return;
|
|
64390
64499
|
const safeLogger = getSafeLogger();
|
|
64391
|
-
const featureStatusPath =
|
|
64500
|
+
const featureStatusPath = join83(featureDir, "status.json");
|
|
64392
64501
|
const write = async () => {
|
|
64393
64502
|
try {
|
|
64394
64503
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -64420,7 +64529,7 @@ __export(exports_migrate, {
|
|
|
64420
64529
|
detectGeneratedContent: () => detectGeneratedContent
|
|
64421
64530
|
});
|
|
64422
64531
|
import { existsSync as existsSync33 } from "fs";
|
|
64423
|
-
import { mkdir as mkdir16, readdir as
|
|
64532
|
+
import { mkdir as mkdir16, readdir as readdir5, rename as rename3 } from "fs/promises";
|
|
64424
64533
|
import path22 from "path";
|
|
64425
64534
|
async function detectGeneratedContent(naxDir) {
|
|
64426
64535
|
if (!existsSync33(naxDir))
|
|
@@ -64428,7 +64537,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64428
64537
|
const candidates = [];
|
|
64429
64538
|
let entries = [];
|
|
64430
64539
|
try {
|
|
64431
|
-
entries = await
|
|
64540
|
+
entries = await readdir5(naxDir);
|
|
64432
64541
|
} catch {
|
|
64433
64542
|
return [];
|
|
64434
64543
|
}
|
|
@@ -64441,13 +64550,13 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64441
64550
|
if (existsSync33(featuresDir)) {
|
|
64442
64551
|
let featureDirs = [];
|
|
64443
64552
|
try {
|
|
64444
|
-
featureDirs = await
|
|
64553
|
+
featureDirs = await readdir5(featuresDir);
|
|
64445
64554
|
} catch {}
|
|
64446
64555
|
for (const fid of featureDirs) {
|
|
64447
64556
|
const featureDir = path22.join(featuresDir, fid);
|
|
64448
64557
|
let subEntries = [];
|
|
64449
64558
|
try {
|
|
64450
|
-
subEntries = await
|
|
64559
|
+
subEntries = await readdir5(featureDir);
|
|
64451
64560
|
} catch {
|
|
64452
64561
|
continue;
|
|
64453
64562
|
}
|
|
@@ -64462,7 +64571,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64462
64571
|
const storiesDir = path22.join(featureDir, "stories");
|
|
64463
64572
|
let storyDirs = [];
|
|
64464
64573
|
try {
|
|
64465
|
-
storyDirs = await
|
|
64574
|
+
storyDirs = await readdir5(storiesDir);
|
|
64466
64575
|
} catch {
|
|
64467
64576
|
continue;
|
|
64468
64577
|
}
|
|
@@ -64470,7 +64579,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64470
64579
|
const storyDir = path22.join(storiesDir, sid);
|
|
64471
64580
|
let storyEntries = [];
|
|
64472
64581
|
try {
|
|
64473
|
-
storyEntries = await
|
|
64582
|
+
storyEntries = await readdir5(storyDir);
|
|
64474
64583
|
} catch {
|
|
64475
64584
|
continue;
|
|
64476
64585
|
}
|
|
@@ -64822,7 +64931,7 @@ __export(exports_run_initialization, {
|
|
|
64822
64931
|
initializeRun: () => initializeRun,
|
|
64823
64932
|
_reconcileDeps: () => _reconcileDeps
|
|
64824
64933
|
});
|
|
64825
|
-
import { join as
|
|
64934
|
+
import { join as join84 } from "path";
|
|
64826
64935
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
64827
64936
|
const logger = getSafeLogger();
|
|
64828
64937
|
let reconciledCount = 0;
|
|
@@ -64839,7 +64948,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
64839
64948
|
});
|
|
64840
64949
|
continue;
|
|
64841
64950
|
}
|
|
64842
|
-
const effectiveWorkdir = story.workdir ?
|
|
64951
|
+
const effectiveWorkdir = story.workdir ? join84(workdir, story.workdir) : workdir;
|
|
64843
64952
|
try {
|
|
64844
64953
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
64845
64954
|
if (!reviewResult.success) {
|
|
@@ -94643,7 +94752,7 @@ __export(exports_curator, {
|
|
|
94643
94752
|
});
|
|
94644
94753
|
import { readdirSync as readdirSync8 } from "fs";
|
|
94645
94754
|
import { unlink as unlink4 } from "fs/promises";
|
|
94646
|
-
import { basename as basename15, join as
|
|
94755
|
+
import { basename as basename15, join as join86 } from "path";
|
|
94647
94756
|
function getProjectKey(config2, projectDir) {
|
|
94648
94757
|
return config2.name?.trim() || basename15(projectDir);
|
|
94649
94758
|
}
|
|
@@ -94726,7 +94835,7 @@ async function curatorStatus(options) {
|
|
|
94726
94835
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94727
94836
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94728
94837
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94729
|
-
const runsDir =
|
|
94838
|
+
const runsDir = join86(outputDir, "runs");
|
|
94730
94839
|
const runIds = listRunIds(runsDir);
|
|
94731
94840
|
let runId;
|
|
94732
94841
|
if (options.run) {
|
|
@@ -94743,8 +94852,8 @@ async function curatorStatus(options) {
|
|
|
94743
94852
|
runId = runIds[runIds.length - 1];
|
|
94744
94853
|
}
|
|
94745
94854
|
console.log(`Run: ${runId}`);
|
|
94746
|
-
const runDir =
|
|
94747
|
-
const observationsPath =
|
|
94855
|
+
const runDir = join86(runsDir, runId);
|
|
94856
|
+
const observationsPath = join86(runDir, "observations.jsonl");
|
|
94748
94857
|
const observations = await parseObservations(observationsPath);
|
|
94749
94858
|
const counts = new Map;
|
|
94750
94859
|
for (const obs of observations) {
|
|
@@ -94754,7 +94863,7 @@ async function curatorStatus(options) {
|
|
|
94754
94863
|
for (const [kind, count] of counts.entries()) {
|
|
94755
94864
|
console.log(` ${kind}: ${count}`);
|
|
94756
94865
|
}
|
|
94757
|
-
const proposalsPath =
|
|
94866
|
+
const proposalsPath = join86(runDir, "curator-proposals.md");
|
|
94758
94867
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94759
94868
|
if (proposalText !== null) {
|
|
94760
94869
|
console.log("");
|
|
@@ -94768,8 +94877,8 @@ async function curatorCommit(options) {
|
|
|
94768
94877
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94769
94878
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94770
94879
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94771
|
-
const runDir =
|
|
94772
|
-
const proposalsPath =
|
|
94880
|
+
const runDir = join86(outputDir, "runs", options.runId);
|
|
94881
|
+
const proposalsPath = join86(runDir, "curator-proposals.md");
|
|
94773
94882
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94774
94883
|
if (proposalText === null) {
|
|
94775
94884
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -94785,7 +94894,7 @@ async function curatorCommit(options) {
|
|
|
94785
94894
|
const dropFileState = new Map;
|
|
94786
94895
|
const skippedDrops = new Set;
|
|
94787
94896
|
for (const drop2 of drops) {
|
|
94788
|
-
const targetPath =
|
|
94897
|
+
const targetPath = join86(resolved.projectDir, drop2.canonicalFile);
|
|
94789
94898
|
if (!dropFileState.has(targetPath)) {
|
|
94790
94899
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
94791
94900
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -94819,7 +94928,7 @@ async function curatorCommit(options) {
|
|
|
94819
94928
|
if (skippedDrops.has(drop2)) {
|
|
94820
94929
|
continue;
|
|
94821
94930
|
}
|
|
94822
|
-
const targetPath =
|
|
94931
|
+
const targetPath = join86(resolved.projectDir, drop2.canonicalFile);
|
|
94823
94932
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
94824
94933
|
const filtered = filterDropContent(existing, drop2.description);
|
|
94825
94934
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -94828,7 +94937,7 @@ async function curatorCommit(options) {
|
|
|
94828
94937
|
}
|
|
94829
94938
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
94830
94939
|
for (const add2 of adds) {
|
|
94831
|
-
const targetPath =
|
|
94940
|
+
const targetPath = join86(resolved.projectDir, add2.canonicalFile);
|
|
94832
94941
|
const content = buildAddContent(add2);
|
|
94833
94942
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
94834
94943
|
modifiedFiles.add(targetPath);
|
|
@@ -94865,7 +94974,7 @@ async function curatorDryrun(options) {
|
|
|
94865
94974
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94866
94975
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94867
94976
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94868
|
-
const runsDir =
|
|
94977
|
+
const runsDir = join86(outputDir, "runs");
|
|
94869
94978
|
const runIds = listRunIds(runsDir);
|
|
94870
94979
|
if (runIds.length === 0) {
|
|
94871
94980
|
console.log("No runs found.");
|
|
@@ -94876,7 +94985,7 @@ async function curatorDryrun(options) {
|
|
|
94876
94985
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
94877
94986
|
return;
|
|
94878
94987
|
}
|
|
94879
|
-
const observationsPath =
|
|
94988
|
+
const observationsPath = join86(runsDir, runId, "observations.jsonl");
|
|
94880
94989
|
const observations = await parseObservations(observationsPath);
|
|
94881
94990
|
const thresholds = getThresholds(config2);
|
|
94882
94991
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -94917,12 +95026,12 @@ async function curatorGc(options) {
|
|
|
94917
95026
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
94918
95027
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94919
95028
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94920
|
-
const perRunsDir =
|
|
95029
|
+
const perRunsDir = join86(outputDir, "runs");
|
|
94921
95030
|
for (const runId of uniqueRunIds) {
|
|
94922
95031
|
if (!keepSet.has(runId)) {
|
|
94923
|
-
const runDir =
|
|
94924
|
-
await _curatorCmdDeps.removeFile(
|
|
94925
|
-
await _curatorCmdDeps.removeFile(
|
|
95032
|
+
const runDir = join86(perRunsDir, runId);
|
|
95033
|
+
await _curatorCmdDeps.removeFile(join86(runDir, "observations.jsonl"));
|
|
95034
|
+
await _curatorCmdDeps.removeFile(join86(runDir, "curator-proposals.md"));
|
|
94926
95035
|
}
|
|
94927
95036
|
}
|
|
94928
95037
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -94967,7 +95076,7 @@ var init_curator2 = __esm(() => {
|
|
|
94967
95076
|
init_source();
|
|
94968
95077
|
import { existsSync as existsSync35, mkdirSync as mkdirSync7 } from "fs";
|
|
94969
95078
|
import { homedir as homedir3 } from "os";
|
|
94970
|
-
import { basename as basename16, join as
|
|
95079
|
+
import { basename as basename16, join as join87 } from "path";
|
|
94971
95080
|
|
|
94972
95081
|
// node_modules/commander/esm.mjs
|
|
94973
95082
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -94991,12 +95100,12 @@ init_errors();
|
|
|
94991
95100
|
init_operations();
|
|
94992
95101
|
|
|
94993
95102
|
// src/plan/strategies/context-builder.ts
|
|
94994
|
-
import { join as
|
|
95103
|
+
import { join as join38 } from "path";
|
|
94995
95104
|
init_config();
|
|
94996
95105
|
init_errors();
|
|
94997
95106
|
init_interaction();
|
|
94998
95107
|
async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
94999
|
-
const naxDir =
|
|
95108
|
+
const naxDir = join38(workdir, ".nax");
|
|
95000
95109
|
if (!deps.existsSync(naxDir)) {
|
|
95001
95110
|
throw new NaxError(`.nax directory not found. Run 'nax init' first in ${workdir}`, "PLAN_CONTEXT_NO_NAX_DIR", {
|
|
95002
95111
|
stage: "plan",
|
|
@@ -95004,8 +95113,8 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95004
95113
|
});
|
|
95005
95114
|
}
|
|
95006
95115
|
validateFeatureName(options.feature);
|
|
95007
|
-
const outputDir =
|
|
95008
|
-
const outputPath =
|
|
95116
|
+
const outputDir = join38(naxDir, "features", options.feature);
|
|
95117
|
+
const outputPath = join38(outputDir, "prd.json");
|
|
95009
95118
|
const [specContent, sourceRoots, pkg] = await Promise.all([
|
|
95010
95119
|
deps.readFile(options.from),
|
|
95011
95120
|
deps.scanSourceRoots(workdir),
|
|
@@ -95020,7 +95129,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95020
95129
|
...new Set(sourceRoots.map((root) => root.path).filter((path7) => path7 !== ".").map((path7) => path7.startsWith("/") ? path7.replace(`${workdir}/`, "") : path7))
|
|
95021
95130
|
];
|
|
95022
95131
|
const packageDetails = relativePackages.length === 0 ? [] : await Promise.all(relativePackages.map(async (relativePath) => {
|
|
95023
|
-
const packageJson = await deps.readPackageJsonAt(
|
|
95132
|
+
const packageJson = await deps.readPackageJsonAt(join38(workdir, relativePath, "package.json"));
|
|
95024
95133
|
return buildPackageSummary(relativePath, packageJson);
|
|
95025
95134
|
}));
|
|
95026
95135
|
const projectName = detectProjectName(workdir, pkg);
|
|
@@ -95623,7 +95732,7 @@ init_interaction();
|
|
|
95623
95732
|
init_prd();
|
|
95624
95733
|
init_runtime();
|
|
95625
95734
|
import { existsSync as existsSync17, readdirSync as readdirSync3 } from "fs";
|
|
95626
|
-
import { basename as basename7, join as
|
|
95735
|
+
import { basename as basename7, join as join43, resolve as resolve14 } from "path";
|
|
95627
95736
|
var _statusFeaturesDeps = {
|
|
95628
95737
|
projectOutputDir,
|
|
95629
95738
|
loadConfig
|
|
@@ -95637,7 +95746,7 @@ function isPidAlive(pid) {
|
|
|
95637
95746
|
}
|
|
95638
95747
|
}
|
|
95639
95748
|
async function loadStatusFile(featureDir) {
|
|
95640
|
-
const statusPath =
|
|
95749
|
+
const statusPath = join43(featureDir, "status.json");
|
|
95641
95750
|
if (!existsSync17(statusPath)) {
|
|
95642
95751
|
return null;
|
|
95643
95752
|
}
|
|
@@ -95652,7 +95761,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95652
95761
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95653
95762
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95654
95763
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95655
|
-
const statusPath =
|
|
95764
|
+
const statusPath = join43(outputDir, "status.json");
|
|
95656
95765
|
if (!existsSync17(statusPath)) {
|
|
95657
95766
|
return null;
|
|
95658
95767
|
}
|
|
@@ -95664,7 +95773,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95664
95773
|
}
|
|
95665
95774
|
}
|
|
95666
95775
|
async function getFeatureSummary(featureName, featureDir) {
|
|
95667
|
-
const prdPath =
|
|
95776
|
+
const prdPath = join43(featureDir, "prd.json");
|
|
95668
95777
|
if (!existsSync17(prdPath)) {
|
|
95669
95778
|
return {
|
|
95670
95779
|
name: featureName,
|
|
@@ -95707,7 +95816,7 @@ async function getFeatureSummary(featureName, featureDir) {
|
|
|
95707
95816
|
};
|
|
95708
95817
|
}
|
|
95709
95818
|
}
|
|
95710
|
-
const runsDir =
|
|
95819
|
+
const runsDir = join43(featureDir, "runs");
|
|
95711
95820
|
if (existsSync17(runsDir)) {
|
|
95712
95821
|
const runs = readdirSync3(runsDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl") && e.name !== "latest.jsonl").map((e) => e.name).sort().reverse();
|
|
95713
95822
|
if (runs.length > 0) {
|
|
@@ -95721,7 +95830,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95721
95830
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95722
95831
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95723
95832
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95724
|
-
const featuresDir =
|
|
95833
|
+
const featuresDir = join43(outputDir, "features");
|
|
95725
95834
|
if (!existsSync17(featuresDir)) {
|
|
95726
95835
|
console.log(source_default.dim("No features found."));
|
|
95727
95836
|
return;
|
|
@@ -95762,7 +95871,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95762
95871
|
console.log();
|
|
95763
95872
|
}
|
|
95764
95873
|
}
|
|
95765
|
-
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name,
|
|
95874
|
+
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name, join43(featuresDir, name))));
|
|
95766
95875
|
console.log(source_default.bold(`\uD83D\uDCCA Features
|
|
95767
95876
|
`));
|
|
95768
95877
|
const header = ` ${"Feature".padEnd(25)} ${"Done".padEnd(6)} ${"Failed".padEnd(8)} ${"Pending".padEnd(9)} ${"Last Run".padEnd(22)} ${"Cost".padEnd(10)} Status`;
|
|
@@ -95788,7 +95897,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95788
95897
|
console.log();
|
|
95789
95898
|
}
|
|
95790
95899
|
async function displayFeatureDetails(featureName, featureDir) {
|
|
95791
|
-
const prdPath =
|
|
95900
|
+
const prdPath = join43(featureDir, "prd.json");
|
|
95792
95901
|
if (!existsSync17(prdPath)) {
|
|
95793
95902
|
console.log(source_default.bold(`
|
|
95794
95903
|
\uD83D\uDCCA ${featureName}
|
|
@@ -95934,7 +96043,7 @@ async function displayFeatureStatus(options = {}) {
|
|
|
95934
96043
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95935
96044
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95936
96045
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95937
|
-
featureDir =
|
|
96046
|
+
featureDir = join43(outputDir, "features", options.feature);
|
|
95938
96047
|
} else {
|
|
95939
96048
|
const resolved = resolveProject({ feature: options.feature });
|
|
95940
96049
|
if (!resolved.featureDir) {
|
|
@@ -95954,7 +96063,7 @@ init_errors();
|
|
|
95954
96063
|
init_logger2();
|
|
95955
96064
|
init_runtime();
|
|
95956
96065
|
import { existsSync as existsSync18, readdirSync as readdirSync4 } from "fs";
|
|
95957
|
-
import { basename as basename8, join as
|
|
96066
|
+
import { basename as basename8, join as join44 } from "path";
|
|
95958
96067
|
async function resolveOutputDir2(workdir, override) {
|
|
95959
96068
|
if (override)
|
|
95960
96069
|
return override;
|
|
@@ -95978,7 +96087,7 @@ async function runsListCommand(options) {
|
|
|
95978
96087
|
const logger = getLogger();
|
|
95979
96088
|
const { feature, workdir } = options;
|
|
95980
96089
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
95981
|
-
const runsDir =
|
|
96090
|
+
const runsDir = join44(outputDir, "features", feature, "runs");
|
|
95982
96091
|
if (!existsSync18(runsDir)) {
|
|
95983
96092
|
logger.info("cli", "No runs found for feature", { feature, hint: `Directory not found: ${runsDir}` });
|
|
95984
96093
|
return;
|
|
@@ -95990,7 +96099,7 @@ async function runsListCommand(options) {
|
|
|
95990
96099
|
}
|
|
95991
96100
|
logger.info("cli", `Runs for ${feature}`, { count: files.length });
|
|
95992
96101
|
for (const file3 of files.sort().reverse()) {
|
|
95993
|
-
const logPath =
|
|
96102
|
+
const logPath = join44(runsDir, file3);
|
|
95994
96103
|
const entries = await parseRunLog(logPath);
|
|
95995
96104
|
const startEvent = entries.find((e) => e.message === "run.start");
|
|
95996
96105
|
const completeEvent = entries.find((e) => e.message === "run.complete");
|
|
@@ -96017,7 +96126,7 @@ async function runsShowCommand(options) {
|
|
|
96017
96126
|
const logger = getLogger();
|
|
96018
96127
|
const { runId, feature, workdir } = options;
|
|
96019
96128
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
96020
|
-
const logPath =
|
|
96129
|
+
const logPath = join44(outputDir, "features", feature, "runs", `${runId}.jsonl`);
|
|
96021
96130
|
if (!existsSync18(logPath)) {
|
|
96022
96131
|
logger.error("cli", "Run not found", { runId, feature, logPath });
|
|
96023
96132
|
throw new NaxError("Run not found", "RUN_NOT_FOUND", { runId, feature, logPath });
|
|
@@ -97363,19 +97472,19 @@ async function detectCommand(options) {
|
|
|
97363
97472
|
// src/commands/logs.ts
|
|
97364
97473
|
init_common();
|
|
97365
97474
|
import { existsSync as existsSync28 } from "fs";
|
|
97366
|
-
import { join as
|
|
97475
|
+
import { join as join70 } from "path";
|
|
97367
97476
|
|
|
97368
97477
|
// src/commands/logs-formatter.ts
|
|
97369
97478
|
init_source();
|
|
97370
97479
|
init_formatter();
|
|
97371
97480
|
import { readdirSync as readdirSync7 } from "fs";
|
|
97372
|
-
import { join as
|
|
97481
|
+
import { join as join69 } from "path";
|
|
97373
97482
|
|
|
97374
97483
|
// src/commands/logs-reader.ts
|
|
97375
97484
|
init_paths3();
|
|
97376
97485
|
import { existsSync as existsSync27, readdirSync as readdirSync6 } from "fs";
|
|
97377
|
-
import { readdir as
|
|
97378
|
-
import { join as
|
|
97486
|
+
import { readdir as readdir3 } from "fs/promises";
|
|
97487
|
+
import { join as join68 } from "path";
|
|
97379
97488
|
var _logsReaderDeps = {
|
|
97380
97489
|
getRunsDir
|
|
97381
97490
|
};
|
|
@@ -97383,13 +97492,13 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97383
97492
|
const runsDir = _logsReaderDeps.getRunsDir();
|
|
97384
97493
|
let entries;
|
|
97385
97494
|
try {
|
|
97386
|
-
entries = await
|
|
97495
|
+
entries = await readdir3(runsDir);
|
|
97387
97496
|
} catch {
|
|
97388
97497
|
throw new Error(`Run not found in registry: ${runId}`);
|
|
97389
97498
|
}
|
|
97390
97499
|
let matched = null;
|
|
97391
97500
|
for (const entry of entries) {
|
|
97392
|
-
const metaPath =
|
|
97501
|
+
const metaPath = join68(runsDir, entry, "meta.json");
|
|
97393
97502
|
try {
|
|
97394
97503
|
const meta3 = await Bun.file(metaPath).json();
|
|
97395
97504
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -97411,14 +97520,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97411
97520
|
return null;
|
|
97412
97521
|
}
|
|
97413
97522
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
97414
|
-
return
|
|
97523
|
+
return join68(matched.eventsDir, specificFile ?? files[0]);
|
|
97415
97524
|
}
|
|
97416
97525
|
async function selectRunFile(runsDir) {
|
|
97417
97526
|
const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
97418
97527
|
if (files.length === 0) {
|
|
97419
97528
|
return null;
|
|
97420
97529
|
}
|
|
97421
|
-
return
|
|
97530
|
+
return join68(runsDir, files[0]);
|
|
97422
97531
|
}
|
|
97423
97532
|
async function extractRunSummary(filePath) {
|
|
97424
97533
|
const file3 = Bun.file(filePath);
|
|
@@ -97504,7 +97613,7 @@ Runs:
|
|
|
97504
97613
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
97505
97614
|
console.log(source_default.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
97506
97615
|
for (const file3 of files) {
|
|
97507
|
-
const filePath =
|
|
97616
|
+
const filePath = join69(runsDir, file3);
|
|
97508
97617
|
const summary = await extractRunSummary(filePath);
|
|
97509
97618
|
const timestamp = file3.replace(".jsonl", "");
|
|
97510
97619
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -97618,7 +97727,7 @@ async function logsCommand(options) {
|
|
|
97618
97727
|
return;
|
|
97619
97728
|
}
|
|
97620
97729
|
const resolved = resolveProject({ dir: options.dir });
|
|
97621
|
-
const naxDir =
|
|
97730
|
+
const naxDir = join70(resolved.projectDir, ".nax");
|
|
97622
97731
|
const configPath = resolved.configPath;
|
|
97623
97732
|
const configFile = Bun.file(configPath);
|
|
97624
97733
|
const config2 = await configFile.json();
|
|
@@ -97626,8 +97735,8 @@ async function logsCommand(options) {
|
|
|
97626
97735
|
if (!featureName) {
|
|
97627
97736
|
throw new Error("No feature specified in config.json");
|
|
97628
97737
|
}
|
|
97629
|
-
const featureDir =
|
|
97630
|
-
const runsDir =
|
|
97738
|
+
const featureDir = join70(naxDir, "features", featureName);
|
|
97739
|
+
const runsDir = join70(featureDir, "runs");
|
|
97631
97740
|
if (!existsSync28(runsDir)) {
|
|
97632
97741
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
97633
97742
|
}
|
|
@@ -97653,7 +97762,7 @@ init_prd();
|
|
|
97653
97762
|
init_precheck();
|
|
97654
97763
|
init_common();
|
|
97655
97764
|
import { existsSync as existsSync29 } from "fs";
|
|
97656
|
-
import { join as
|
|
97765
|
+
import { join as join71 } from "path";
|
|
97657
97766
|
async function precheckCommand(options) {
|
|
97658
97767
|
const resolved = resolveProject({
|
|
97659
97768
|
dir: options.dir,
|
|
@@ -97675,9 +97784,9 @@ async function precheckCommand(options) {
|
|
|
97675
97784
|
process.exit(1);
|
|
97676
97785
|
}
|
|
97677
97786
|
}
|
|
97678
|
-
const naxDir =
|
|
97679
|
-
const featureDir =
|
|
97680
|
-
const prdPath =
|
|
97787
|
+
const naxDir = join71(resolved.projectDir, ".nax");
|
|
97788
|
+
const featureDir = join71(naxDir, "features", featureName);
|
|
97789
|
+
const prdPath = join71(featureDir, "prd.json");
|
|
97681
97790
|
if (!existsSync29(featureDir)) {
|
|
97682
97791
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
97683
97792
|
process.exit(1);
|
|
@@ -97699,8 +97808,8 @@ async function precheckCommand(options) {
|
|
|
97699
97808
|
// src/commands/runs.ts
|
|
97700
97809
|
init_source();
|
|
97701
97810
|
init_paths3();
|
|
97702
|
-
import { readdir as
|
|
97703
|
-
import { join as
|
|
97811
|
+
import { readdir as readdir4 } from "fs/promises";
|
|
97812
|
+
import { join as join72 } from "path";
|
|
97704
97813
|
var DEFAULT_LIMIT = 20;
|
|
97705
97814
|
var _runsCmdDeps = {
|
|
97706
97815
|
getRunsDir
|
|
@@ -97748,14 +97857,14 @@ async function runsCommand(options = {}) {
|
|
|
97748
97857
|
const runsDir = _runsCmdDeps.getRunsDir();
|
|
97749
97858
|
let entries;
|
|
97750
97859
|
try {
|
|
97751
|
-
entries = await
|
|
97860
|
+
entries = await readdir4(runsDir);
|
|
97752
97861
|
} catch {
|
|
97753
97862
|
console.log("No runs found.");
|
|
97754
97863
|
return;
|
|
97755
97864
|
}
|
|
97756
97865
|
const rows = [];
|
|
97757
97866
|
for (const entry of entries) {
|
|
97758
|
-
const metaPath =
|
|
97867
|
+
const metaPath = join72(runsDir, entry, "meta.json");
|
|
97759
97868
|
let meta3;
|
|
97760
97869
|
try {
|
|
97761
97870
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -97832,7 +97941,7 @@ async function runsCommand(options = {}) {
|
|
|
97832
97941
|
|
|
97833
97942
|
// src/commands/unlock.ts
|
|
97834
97943
|
init_source();
|
|
97835
|
-
import { join as
|
|
97944
|
+
import { join as join73 } from "path";
|
|
97836
97945
|
function isProcessAlive2(pid) {
|
|
97837
97946
|
try {
|
|
97838
97947
|
process.kill(pid, 0);
|
|
@@ -97847,7 +97956,7 @@ function formatLockAge(ageMs) {
|
|
|
97847
97956
|
}
|
|
97848
97957
|
async function unlockCommand(options) {
|
|
97849
97958
|
const workdir = options.dir ?? process.cwd();
|
|
97850
|
-
const lockPath =
|
|
97959
|
+
const lockPath = join73(workdir, "nax.lock");
|
|
97851
97960
|
const lockFile = Bun.file(lockPath);
|
|
97852
97961
|
const exists = await lockFile.exists();
|
|
97853
97962
|
if (!exists) {
|
|
@@ -106272,7 +106381,7 @@ Next: nax generate --package ${options.package}`));
|
|
|
106272
106381
|
}
|
|
106273
106382
|
return;
|
|
106274
106383
|
}
|
|
106275
|
-
const naxDir =
|
|
106384
|
+
const naxDir = join87(workdir, ".nax");
|
|
106276
106385
|
if (existsSync35(naxDir) && !options.force) {
|
|
106277
106386
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
106278
106387
|
return;
|
|
@@ -106301,11 +106410,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
106301
106410
|
}
|
|
106302
106411
|
}
|
|
106303
106412
|
}
|
|
106304
|
-
mkdirSync7(
|
|
106305
|
-
mkdirSync7(
|
|
106413
|
+
mkdirSync7(join87(naxDir, "features"), { recursive: true });
|
|
106414
|
+
mkdirSync7(join87(naxDir, "hooks"), { recursive: true });
|
|
106306
106415
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
106307
|
-
await Bun.write(
|
|
106308
|
-
await Bun.write(
|
|
106416
|
+
await Bun.write(join87(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
|
|
106417
|
+
await Bun.write(join87(naxDir, "hooks.json"), JSON.stringify({
|
|
106309
106418
|
hooks: {
|
|
106310
106419
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
106311
106420
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -106313,12 +106422,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
106313
106422
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
106314
106423
|
}
|
|
106315
106424
|
}, null, 2));
|
|
106316
|
-
await Bun.write(
|
|
106425
|
+
await Bun.write(join87(naxDir, ".gitignore"), `# nax temp files
|
|
106317
106426
|
*.tmp
|
|
106318
106427
|
.paused.json
|
|
106319
106428
|
.nax-verifier-verdict.json
|
|
106320
106429
|
`);
|
|
106321
|
-
await Bun.write(
|
|
106430
|
+
await Bun.write(join87(naxDir, "context.md"), `# Project Context
|
|
106322
106431
|
|
|
106323
106432
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
106324
106433
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -106466,8 +106575,8 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106466
106575
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106467
106576
|
process.exit(1);
|
|
106468
106577
|
}
|
|
106469
|
-
const featureDir =
|
|
106470
|
-
const prdPath =
|
|
106578
|
+
const featureDir = join87(naxDir, "features", options.feature);
|
|
106579
|
+
const prdPath = join87(featureDir, "prd.json");
|
|
106471
106580
|
if (options.plan && options.from) {
|
|
106472
106581
|
if (existsSync35(prdPath) && !options.force) {
|
|
106473
106582
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
@@ -106489,10 +106598,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106489
106598
|
}
|
|
106490
106599
|
}
|
|
106491
106600
|
try {
|
|
106492
|
-
const planLogDir =
|
|
106601
|
+
const planLogDir = join87(featureDir, "plan");
|
|
106493
106602
|
mkdirSync7(planLogDir, { recursive: true });
|
|
106494
106603
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106495
|
-
const planLogPath =
|
|
106604
|
+
const planLogPath = join87(planLogDir, `${planLogId}.jsonl`);
|
|
106496
106605
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106497
106606
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106498
106607
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -106538,10 +106647,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106538
106647
|
resetLogger();
|
|
106539
106648
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
106540
106649
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
106541
|
-
const runsDir =
|
|
106650
|
+
const runsDir = join87(outputDir, "features", options.feature, "runs");
|
|
106542
106651
|
mkdirSync7(runsDir, { recursive: true });
|
|
106543
106652
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106544
|
-
const logFilePath =
|
|
106653
|
+
const logFilePath = join87(runsDir, `${runId}.jsonl`);
|
|
106545
106654
|
const isTTY = process.stdout.isTTY ?? false;
|
|
106546
106655
|
const headlessFlag = options.headless ?? false;
|
|
106547
106656
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -106559,7 +106668,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106559
106668
|
config2.agent.default = options.agent;
|
|
106560
106669
|
}
|
|
106561
106670
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
106562
|
-
const globalNaxDir =
|
|
106671
|
+
const globalNaxDir = join87(homedir3(), ".nax");
|
|
106563
106672
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
106564
106673
|
const eventEmitter = new PipelineEventEmitter;
|
|
106565
106674
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -106579,12 +106688,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106579
106688
|
events: eventEmitter,
|
|
106580
106689
|
ptyOptions: null,
|
|
106581
106690
|
agentStreamEvents,
|
|
106582
|
-
queueFilePath:
|
|
106691
|
+
queueFilePath: join87(workdir, ".queue.txt")
|
|
106583
106692
|
});
|
|
106584
106693
|
} else {
|
|
106585
106694
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
106586
106695
|
}
|
|
106587
|
-
const statusFilePath =
|
|
106696
|
+
const statusFilePath = join87(outputDir, "status.json");
|
|
106588
106697
|
let parallel;
|
|
106589
106698
|
if (options.parallel !== undefined) {
|
|
106590
106699
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -106611,7 +106720,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106611
106720
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
106612
106721
|
agentStreamEvents
|
|
106613
106722
|
});
|
|
106614
|
-
const latestSymlink =
|
|
106723
|
+
const latestSymlink = join87(runsDir, "latest.jsonl");
|
|
106615
106724
|
try {
|
|
106616
106725
|
if (existsSync35(latestSymlink)) {
|
|
106617
106726
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
@@ -106672,9 +106781,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106672
106781
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106673
106782
|
process.exit(1);
|
|
106674
106783
|
}
|
|
106675
|
-
const featureDir =
|
|
106784
|
+
const featureDir = join87(naxDir, "features", name);
|
|
106676
106785
|
mkdirSync7(featureDir, { recursive: true });
|
|
106677
|
-
await Bun.write(
|
|
106786
|
+
await Bun.write(join87(featureDir, "spec.md"), `# Feature: ${name}
|
|
106678
106787
|
|
|
106679
106788
|
## Overview
|
|
106680
106789
|
|
|
@@ -106707,7 +106816,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106707
106816
|
|
|
106708
106817
|
<!-- What this feature explicitly does NOT cover. -->
|
|
106709
106818
|
`);
|
|
106710
|
-
await Bun.write(
|
|
106819
|
+
await Bun.write(join87(featureDir, "progress.txt"), `# Progress: ${name}
|
|
106711
106820
|
|
|
106712
106821
|
Created: ${new Date().toISOString()}
|
|
106713
106822
|
|
|
@@ -106733,7 +106842,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106733
106842
|
console.error(source_default.red("nax not initialized."));
|
|
106734
106843
|
process.exit(1);
|
|
106735
106844
|
}
|
|
106736
|
-
const featuresDir =
|
|
106845
|
+
const featuresDir = join87(naxDir, "features");
|
|
106737
106846
|
if (!existsSync35(featuresDir)) {
|
|
106738
106847
|
console.log(source_default.dim("No features yet."));
|
|
106739
106848
|
return;
|
|
@@ -106748,7 +106857,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106748
106857
|
Features:
|
|
106749
106858
|
`));
|
|
106750
106859
|
for (const name of entries) {
|
|
106751
|
-
const prdPath =
|
|
106860
|
+
const prdPath = join87(featuresDir, name, "prd.json");
|
|
106752
106861
|
if (existsSync35(prdPath)) {
|
|
106753
106862
|
const prd = await loadPRD(prdPath);
|
|
106754
106863
|
const c = countStories(prd);
|
|
@@ -106783,10 +106892,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
106783
106892
|
cliOverrides.profile = options.profile;
|
|
106784
106893
|
}
|
|
106785
106894
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
106786
|
-
const featureLogDir =
|
|
106895
|
+
const featureLogDir = join87(naxDir, "features", options.feature, "plan");
|
|
106787
106896
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
106788
106897
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106789
|
-
const planLogPath =
|
|
106898
|
+
const planLogPath = join87(featureLogDir, `${planLogId}.jsonl`);
|
|
106790
106899
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106791
106900
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106792
106901
|
try {
|