@nathapp/nax 0.69.7 → 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 +309 -275
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -37430,7 +37430,7 @@ var init_write_test = __esm(() => {
|
|
|
37430
37430
|
if (!input.beforeRef)
|
|
37431
37431
|
return parsed;
|
|
37432
37432
|
const allowedPaths = ctx.config.tdd?.testWriterAllowedPaths ?? ["src/index.ts", "src/**/index.ts"];
|
|
37433
|
-
const testFilePatterns =
|
|
37433
|
+
const testFilePatterns = input.resolvedTestPatterns?.globs;
|
|
37434
37434
|
const isolation = await verifyTestWriterIsolation(ctx.packageView.packageDir, input.beforeRef, allowedPaths, testFilePatterns, input.lite ? "lite" : "strict");
|
|
37435
37435
|
return { ...parsed, isolation };
|
|
37436
37436
|
}
|
|
@@ -38414,57 +38414,69 @@ var init_plan_critic_llm = __esm(() => {
|
|
|
38414
38414
|
});
|
|
38415
38415
|
|
|
38416
38416
|
// src/context/greenfield.ts
|
|
38417
|
-
|
|
38418
|
-
import { join as join23 } from "path";
|
|
38419
|
-
async function scanForTestFiles(dir, testPatterns, isRootCall = true) {
|
|
38420
|
-
const results = [];
|
|
38421
|
-
const ignoreDirs = new Set(["node_modules", "dist", "build", ".next", ".git"]);
|
|
38417
|
+
async function gitLsFiles2(workdir) {
|
|
38422
38418
|
try {
|
|
38423
|
-
const
|
|
38424
|
-
|
|
38425
|
-
|
|
38426
|
-
|
|
38427
|
-
|
|
38428
|
-
|
|
38429
|
-
|
|
38430
|
-
|
|
38431
|
-
|
|
38432
|
-
|
|
38433
|
-
|
|
38434
|
-
|
|
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;
|
|
38435
38444
|
}
|
|
38436
38445
|
}
|
|
38437
|
-
} catch (error48) {
|
|
38438
|
-
if (isRootCall) {
|
|
38439
|
-
throw error48;
|
|
38440
|
-
}
|
|
38441
38446
|
}
|
|
38442
|
-
return
|
|
38447
|
+
return false;
|
|
38443
38448
|
}
|
|
38444
38449
|
async function isGreenfieldStory(_story, workdir, patterns) {
|
|
38445
38450
|
try {
|
|
38446
|
-
|
|
38447
|
-
|
|
38448
|
-
return testFiles.length === 0;
|
|
38449
|
-
} catch (error48) {
|
|
38451
|
+
return !await hasTestFiles(workdir, patterns ?? DEFAULT_TEST_FILE_PATTERNS);
|
|
38452
|
+
} catch {
|
|
38450
38453
|
return false;
|
|
38451
38454
|
}
|
|
38452
38455
|
}
|
|
38453
|
-
var
|
|
38456
|
+
var _greenfieldDeps, IGNORE_DIRS;
|
|
38454
38457
|
var init_greenfield = __esm(() => {
|
|
38455
|
-
|
|
38456
|
-
|
|
38457
|
-
|
|
38458
|
-
|
|
38459
|
-
|
|
38460
|
-
"
|
|
38461
|
-
"
|
|
38462
|
-
"
|
|
38463
|
-
"
|
|
38464
|
-
"
|
|
38465
|
-
"
|
|
38466
|
-
"
|
|
38467
|
-
"
|
|
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"
|
|
38468
38480
|
]);
|
|
38469
38481
|
});
|
|
38470
38482
|
|
|
@@ -38627,13 +38639,13 @@ __export(exports_runners, {
|
|
|
38627
38639
|
_regressionRunnerDeps: () => _regressionRunnerDeps
|
|
38628
38640
|
});
|
|
38629
38641
|
import { existsSync as existsSync6 } from "fs";
|
|
38630
|
-
import { join as
|
|
38642
|
+
import { join as join23 } from "path";
|
|
38631
38643
|
async function verifyAssets(workingDirectory, expectedFiles) {
|
|
38632
38644
|
if (!expectedFiles || expectedFiles.length === 0)
|
|
38633
38645
|
return { success: true, missingFiles: [] };
|
|
38634
38646
|
const missingFiles = [];
|
|
38635
38647
|
for (const file3 of expectedFiles) {
|
|
38636
|
-
if (!existsSync6(
|
|
38648
|
+
if (!existsSync6(join23(workingDirectory, file3)))
|
|
38637
38649
|
missingFiles.push(file3);
|
|
38638
38650
|
}
|
|
38639
38651
|
if (missingFiles.length > 0) {
|
|
@@ -39080,7 +39092,7 @@ var init_apply_test_edit_declarations = __esm(() => {
|
|
|
39080
39092
|
});
|
|
39081
39093
|
|
|
39082
39094
|
// src/operations/validate-mock-structure-files.ts
|
|
39083
|
-
import { join as
|
|
39095
|
+
import { join as join24 } from "path";
|
|
39084
39096
|
async function validateMockStructureFiles(declarations, resolvedTestPatterns, packageDir, deps) {
|
|
39085
39097
|
const fileExists = deps?.fileExists ?? defaultFileExists;
|
|
39086
39098
|
const valid = [];
|
|
@@ -39093,7 +39105,7 @@ async function validateMockStructureFiles(declarations, resolvedTestPatterns, pa
|
|
|
39093
39105
|
const files = d.files ?? [d.file];
|
|
39094
39106
|
let allValid = true;
|
|
39095
39107
|
for (const file3 of files) {
|
|
39096
|
-
const absolutePath =
|
|
39108
|
+
const absolutePath = join24(packageDir, file3);
|
|
39097
39109
|
const exists = await fileExists(absolutePath);
|
|
39098
39110
|
if (!exists) {
|
|
39099
39111
|
allValid = false;
|
|
@@ -40693,7 +40705,7 @@ var init_lint_parsing = __esm(() => {
|
|
|
40693
40705
|
});
|
|
40694
40706
|
|
|
40695
40707
|
// src/review/scoped-lint.ts
|
|
40696
|
-
import { join as
|
|
40708
|
+
import { join as join25, relative as relative10 } from "path";
|
|
40697
40709
|
function shellQuotePath4(path5) {
|
|
40698
40710
|
return `'${path5.replaceAll("'", "'\\''")}'`;
|
|
40699
40711
|
}
|
|
@@ -40741,7 +40753,7 @@ function uniqueFiles(files) {
|
|
|
40741
40753
|
async function filterFilesToScope(files, workdir, projectDir, activePackageDir) {
|
|
40742
40754
|
const inScope = [];
|
|
40743
40755
|
for (const relPath of files) {
|
|
40744
|
-
const absPath =
|
|
40756
|
+
const absPath = join25(workdir, relPath);
|
|
40745
40757
|
const exists = await _scopedLintDeps.fileExists(absPath);
|
|
40746
40758
|
if (!exists)
|
|
40747
40759
|
continue;
|
|
@@ -44115,7 +44127,7 @@ var init_call = __esm(() => {
|
|
|
44115
44127
|
|
|
44116
44128
|
// src/runtime/cost-aggregator.ts
|
|
44117
44129
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
44118
|
-
import { join as
|
|
44130
|
+
import { join as join26 } from "path";
|
|
44119
44131
|
function makeCorrelationId() {
|
|
44120
44132
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
44121
44133
|
}
|
|
@@ -44306,7 +44318,7 @@ class CostAggregator {
|
|
|
44306
44318
|
if (events.length === 0 && errors3.length === 0)
|
|
44307
44319
|
return;
|
|
44308
44320
|
mkdirSync2(this._drainDir, { recursive: true });
|
|
44309
|
-
const path5 =
|
|
44321
|
+
const path5 = join26(this._drainDir, `${this._runId}.jsonl`);
|
|
44310
44322
|
const sorted = [...events, ...errors3].sort((a, b) => a.ts - b.ts);
|
|
44311
44323
|
await _costAggDeps.write(path5, `${sorted.map((e) => JSON.stringify(e)).join(`
|
|
44312
44324
|
`)}
|
|
@@ -44346,7 +44358,7 @@ var init_cost_aggregator = __esm(() => {
|
|
|
44346
44358
|
// src/runtime/prompt-auditor.ts
|
|
44347
44359
|
import { appendFileSync } from "fs";
|
|
44348
44360
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
44349
|
-
import { join as
|
|
44361
|
+
import { join as join27 } from "path";
|
|
44350
44362
|
function createNoOpPromptAuditor() {
|
|
44351
44363
|
return {
|
|
44352
44364
|
record() {},
|
|
@@ -44412,8 +44424,8 @@ class PromptAuditor {
|
|
|
44412
44424
|
_jsonlPath;
|
|
44413
44425
|
_featureDir;
|
|
44414
44426
|
constructor(runId, flushDir, featureName) {
|
|
44415
|
-
this._featureDir =
|
|
44416
|
-
this._jsonlPath =
|
|
44427
|
+
this._featureDir = join27(flushDir, featureName);
|
|
44428
|
+
this._jsonlPath = join27(this._featureDir, `${runId}.jsonl`);
|
|
44417
44429
|
}
|
|
44418
44430
|
record(entry) {
|
|
44419
44431
|
this._enqueue(entry);
|
|
@@ -44462,7 +44474,7 @@ class PromptAuditor {
|
|
|
44462
44474
|
const auditEntry = entry;
|
|
44463
44475
|
const filename = deriveTxtFilename(auditEntry);
|
|
44464
44476
|
try {
|
|
44465
|
-
await _promptAuditorDeps.write(
|
|
44477
|
+
await _promptAuditorDeps.write(join27(this._featureDir, filename), buildTxtContent(auditEntry));
|
|
44466
44478
|
} catch (err) {
|
|
44467
44479
|
throw tagAuditError(err, "txt");
|
|
44468
44480
|
}
|
|
@@ -44600,6 +44612,7 @@ function createPackageView(config2, packageDir, repoRoot, hasOverride) {
|
|
|
44600
44612
|
function createPackageRegistry(loader, repoRoot) {
|
|
44601
44613
|
const cache = new Map;
|
|
44602
44614
|
const mergedConfigs = new Map;
|
|
44615
|
+
let hydrated = false;
|
|
44603
44616
|
function toRelativeKey(packageDir) {
|
|
44604
44617
|
if (!packageDir)
|
|
44605
44618
|
return "";
|
|
@@ -44618,6 +44631,9 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44618
44631
|
}
|
|
44619
44632
|
const overrideConfig = mergedConfigs.get(key);
|
|
44620
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
|
+
}
|
|
44621
44637
|
const config2 = overrideConfig ?? loader.current();
|
|
44622
44638
|
const view = createPackageView(config2, key, repoRoot, hasOverride);
|
|
44623
44639
|
cache.set(key, view);
|
|
@@ -44638,6 +44654,7 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44638
44654
|
cache.delete(dir);
|
|
44639
44655
|
}
|
|
44640
44656
|
}
|
|
44657
|
+
hydrated = true;
|
|
44641
44658
|
}
|
|
44642
44659
|
return {
|
|
44643
44660
|
all() {
|
|
@@ -44650,8 +44667,11 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44650
44667
|
hydrate
|
|
44651
44668
|
};
|
|
44652
44669
|
}
|
|
44670
|
+
var _packagesDeps;
|
|
44653
44671
|
var init_packages = __esm(() => {
|
|
44654
44672
|
init_config();
|
|
44673
|
+
init_logger2();
|
|
44674
|
+
_packagesDeps = { getSafeLogger };
|
|
44655
44675
|
});
|
|
44656
44676
|
|
|
44657
44677
|
// src/runtime/agent-stream-events.ts
|
|
@@ -45610,7 +45630,7 @@ var init_pid_registry = __esm(() => {
|
|
|
45610
45630
|
// src/session/manager-deps.ts
|
|
45611
45631
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
45612
45632
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
45613
|
-
import { isAbsolute as isAbsolute9, join as
|
|
45633
|
+
import { isAbsolute as isAbsolute9, join as join28, relative as relative11, sep as sep2 } from "path";
|
|
45614
45634
|
function resolveProjectDirFromScratchDir(scratchDir) {
|
|
45615
45635
|
const marker = `${sep2}.nax${sep2}features${sep2}`;
|
|
45616
45636
|
const markerIdx = scratchDir.lastIndexOf(marker);
|
|
@@ -45631,7 +45651,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45631
45651
|
now: () => new Date().toISOString(),
|
|
45632
45652
|
nowMs: () => Date.now(),
|
|
45633
45653
|
uuid: () => randomUUID3(),
|
|
45634
|
-
sessionScratchDir: (projectDir, featureName, sessionId) =>
|
|
45654
|
+
sessionScratchDir: (projectDir, featureName, sessionId) => join28(projectDir, ".nax", "features", featureName, "sessions", sessionId),
|
|
45635
45655
|
writeDescriptor: async (scratchDir, descriptor, projectDir) => {
|
|
45636
45656
|
await mkdir5(scratchDir, { recursive: true });
|
|
45637
45657
|
const { handle: _handle, ...persistable } = descriptor;
|
|
@@ -45642,7 +45662,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45642
45662
|
persistable.scratchDir = toProjectRelativePath(derivedProjectDir, persistable.scratchDir);
|
|
45643
45663
|
}
|
|
45644
45664
|
}
|
|
45645
|
-
await Bun.write(
|
|
45665
|
+
await Bun.write(join28(scratchDir, "descriptor.json"), JSON.stringify(persistable, null, 2));
|
|
45646
45666
|
}
|
|
45647
45667
|
};
|
|
45648
45668
|
});
|
|
@@ -46393,7 +46413,7 @@ __export(exports_runtime, {
|
|
|
46393
46413
|
CostAggregator: () => CostAggregator,
|
|
46394
46414
|
AgentStreamEventBus: () => AgentStreamEventBus
|
|
46395
46415
|
});
|
|
46396
|
-
import { basename as basename5, join as
|
|
46416
|
+
import { basename as basename5, join as join29 } from "path";
|
|
46397
46417
|
function createRuntime(config2, workdir, opts) {
|
|
46398
46418
|
const runId = crypto.randomUUID();
|
|
46399
46419
|
const controller = new AbortController;
|
|
@@ -46409,10 +46429,10 @@ function createRuntime(config2, workdir, opts) {
|
|
|
46409
46429
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
46410
46430
|
const globalDir = globalOutputDir();
|
|
46411
46431
|
const curatorRollupPathValue = curatorRollupPath(globalDir, config2.curator?.rollupPath);
|
|
46412
|
-
const costDir =
|
|
46432
|
+
const costDir = join29(outputDir, "cost");
|
|
46413
46433
|
const costAggregator = opts?.costAggregator ?? new CostAggregator(runId, costDir);
|
|
46414
46434
|
const auditEnabled = config2.agent?.promptAudit?.enabled ?? false;
|
|
46415
|
-
const auditDir = config2.agent?.promptAudit?.dir ??
|
|
46435
|
+
const auditDir = config2.agent?.promptAudit?.dir ?? join29(outputDir, "prompt-audit");
|
|
46416
46436
|
let promptAuditor;
|
|
46417
46437
|
if (opts?.promptAuditor) {
|
|
46418
46438
|
promptAuditor = opts.promptAuditor;
|
|
@@ -46565,9 +46585,9 @@ async function allSettledBounded(tasks, limit) {
|
|
|
46565
46585
|
|
|
46566
46586
|
// src/context/injector.ts
|
|
46567
46587
|
import { existsSync as existsSync8 } from "fs";
|
|
46568
|
-
import { join as
|
|
46588
|
+
import { join as join30 } from "path";
|
|
46569
46589
|
async function detectNode(workdir) {
|
|
46570
|
-
const pkgPath =
|
|
46590
|
+
const pkgPath = join30(workdir, "package.json");
|
|
46571
46591
|
if (!existsSync8(pkgPath))
|
|
46572
46592
|
return null;
|
|
46573
46593
|
try {
|
|
@@ -46584,7 +46604,7 @@ async function detectNode(workdir) {
|
|
|
46584
46604
|
}
|
|
46585
46605
|
}
|
|
46586
46606
|
async function detectGo(workdir) {
|
|
46587
|
-
const goMod =
|
|
46607
|
+
const goMod = join30(workdir, "go.mod");
|
|
46588
46608
|
if (!existsSync8(goMod))
|
|
46589
46609
|
return null;
|
|
46590
46610
|
try {
|
|
@@ -46608,7 +46628,7 @@ async function detectGo(workdir) {
|
|
|
46608
46628
|
}
|
|
46609
46629
|
}
|
|
46610
46630
|
async function detectRust(workdir) {
|
|
46611
|
-
const cargoPath =
|
|
46631
|
+
const cargoPath = join30(workdir, "Cargo.toml");
|
|
46612
46632
|
if (!existsSync8(cargoPath))
|
|
46613
46633
|
return null;
|
|
46614
46634
|
try {
|
|
@@ -46624,8 +46644,8 @@ async function detectRust(workdir) {
|
|
|
46624
46644
|
}
|
|
46625
46645
|
}
|
|
46626
46646
|
async function detectPython(workdir) {
|
|
46627
|
-
const pyproject =
|
|
46628
|
-
const requirements =
|
|
46647
|
+
const pyproject = join30(workdir, "pyproject.toml");
|
|
46648
|
+
const requirements = join30(workdir, "requirements.txt");
|
|
46629
46649
|
if (!existsSync8(pyproject) && !existsSync8(requirements))
|
|
46630
46650
|
return null;
|
|
46631
46651
|
try {
|
|
@@ -46644,7 +46664,7 @@ async function detectPython(workdir) {
|
|
|
46644
46664
|
}
|
|
46645
46665
|
}
|
|
46646
46666
|
async function detectPhp(workdir) {
|
|
46647
|
-
const composerPath =
|
|
46667
|
+
const composerPath = join30(workdir, "composer.json");
|
|
46648
46668
|
if (!existsSync8(composerPath))
|
|
46649
46669
|
return null;
|
|
46650
46670
|
try {
|
|
@@ -46657,7 +46677,7 @@ async function detectPhp(workdir) {
|
|
|
46657
46677
|
}
|
|
46658
46678
|
}
|
|
46659
46679
|
async function detectRuby(workdir) {
|
|
46660
|
-
const gemfile =
|
|
46680
|
+
const gemfile = join30(workdir, "Gemfile");
|
|
46661
46681
|
if (!existsSync8(gemfile))
|
|
46662
46682
|
return null;
|
|
46663
46683
|
try {
|
|
@@ -46669,9 +46689,9 @@ async function detectRuby(workdir) {
|
|
|
46669
46689
|
}
|
|
46670
46690
|
}
|
|
46671
46691
|
async function detectJvm(workdir) {
|
|
46672
|
-
const pom =
|
|
46673
|
-
const gradle =
|
|
46674
|
-
const gradleKts =
|
|
46692
|
+
const pom = join30(workdir, "pom.xml");
|
|
46693
|
+
const gradle = join30(workdir, "build.gradle");
|
|
46694
|
+
const gradleKts = join30(workdir, "build.gradle.kts");
|
|
46675
46695
|
if (!existsSync8(pom) && !existsSync8(gradle) && !existsSync8(gradleKts))
|
|
46676
46696
|
return null;
|
|
46677
46697
|
try {
|
|
@@ -46679,7 +46699,7 @@ async function detectJvm(workdir) {
|
|
|
46679
46699
|
const content2 = await Bun.file(pom).text();
|
|
46680
46700
|
const nameMatch = content2.match(/<artifactId>([^<]+)<\/artifactId>/);
|
|
46681
46701
|
const deps2 = [...content2.matchAll(/<artifactId>([^<]+)<\/artifactId>/g)].map((m) => m[1]).filter((d) => d !== nameMatch?.[1]).slice(0, 10);
|
|
46682
|
-
const lang2 = existsSync8(
|
|
46702
|
+
const lang2 = existsSync8(join30(workdir, "src/main/kotlin")) ? "Kotlin" : "Java";
|
|
46683
46703
|
return { name: nameMatch?.[1], lang: lang2, dependencies: deps2 };
|
|
46684
46704
|
}
|
|
46685
46705
|
const gradleFile = existsSync8(gradleKts) ? gradleKts : gradle;
|
|
@@ -46933,7 +46953,7 @@ var init_windsurf = __esm(() => {
|
|
|
46933
46953
|
|
|
46934
46954
|
// src/context/generator.ts
|
|
46935
46955
|
import { existsSync as existsSync9 } from "fs";
|
|
46936
|
-
import { join as
|
|
46956
|
+
import { join as join31, relative as relative12 } from "path";
|
|
46937
46957
|
async function loadContextContent(options, config2) {
|
|
46938
46958
|
if (!_generatorDeps.existsSync(options.contextPath)) {
|
|
46939
46959
|
throw new Error(`Context file not found: ${options.contextPath}`);
|
|
@@ -46951,7 +46971,7 @@ async function generateFor(agent, options, config2) {
|
|
|
46951
46971
|
try {
|
|
46952
46972
|
const context = await loadContextContent(options, config2);
|
|
46953
46973
|
const content = generator.generate(context);
|
|
46954
|
-
const outputPath =
|
|
46974
|
+
const outputPath = join31(options.outputDir, generator.outputFile);
|
|
46955
46975
|
validateFilePath(outputPath, options.outputDir);
|
|
46956
46976
|
if (!options.dryRun) {
|
|
46957
46977
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46969,7 +46989,7 @@ async function generateAll(options, config2, agentFilter) {
|
|
|
46969
46989
|
for (const [agentKey, generator] of entries) {
|
|
46970
46990
|
try {
|
|
46971
46991
|
const content = generator.generate(context);
|
|
46972
|
-
const outputPath =
|
|
46992
|
+
const outputPath = join31(options.outputDir, generator.outputFile);
|
|
46973
46993
|
validateFilePath(outputPath, options.outputDir);
|
|
46974
46994
|
if (!options.dryRun) {
|
|
46975
46995
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46989,7 +47009,7 @@ async function discoverPackages(repoRoot) {
|
|
|
46989
47009
|
const glob = new Bun.Glob(pattern);
|
|
46990
47010
|
for await (const match of glob.scan({ cwd: repoRoot, dot: true })) {
|
|
46991
47011
|
const pkgRelative = match.replace(/^\.nax\/mono\//, "").replace(/\/context\.md$/, "");
|
|
46992
|
-
const pkgAbsolute =
|
|
47012
|
+
const pkgAbsolute = join31(repoRoot, pkgRelative);
|
|
46993
47013
|
if (!seen.has(pkgAbsolute)) {
|
|
46994
47014
|
seen.add(pkgAbsolute);
|
|
46995
47015
|
packages.push(pkgAbsolute);
|
|
@@ -47021,14 +47041,14 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
47021
47041
|
}
|
|
47022
47042
|
}
|
|
47023
47043
|
}
|
|
47024
|
-
const turboPath =
|
|
47044
|
+
const turboPath = join31(repoRoot, "turbo.json");
|
|
47025
47045
|
try {
|
|
47026
47046
|
const turbo = JSON.parse(await _generatorDeps.readTextFile(turboPath));
|
|
47027
47047
|
if (Array.isArray(turbo.packages)) {
|
|
47028
47048
|
await resolveGlobs(turbo.packages);
|
|
47029
47049
|
}
|
|
47030
47050
|
} catch {}
|
|
47031
|
-
const pkgPath =
|
|
47051
|
+
const pkgPath = join31(repoRoot, "package.json");
|
|
47032
47052
|
try {
|
|
47033
47053
|
const pkg = JSON.parse(await _generatorDeps.readTextFile(pkgPath));
|
|
47034
47054
|
const ws = pkg.workspaces;
|
|
@@ -47036,7 +47056,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
47036
47056
|
if (patterns.length > 0)
|
|
47037
47057
|
await resolveGlobs(patterns);
|
|
47038
47058
|
} catch {}
|
|
47039
|
-
const pnpmPath =
|
|
47059
|
+
const pnpmPath = join31(repoRoot, "pnpm-workspace.yaml");
|
|
47040
47060
|
try {
|
|
47041
47061
|
const raw = await _generatorDeps.readTextFile(pnpmPath);
|
|
47042
47062
|
const lines = raw.split(`
|
|
@@ -47062,7 +47082,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
47062
47082
|
async function generateForPackage(packageDir, config2, dryRun = false, repoRoot) {
|
|
47063
47083
|
const resolvedRepoRoot = repoRoot ?? packageDir;
|
|
47064
47084
|
const relativePkgPath = relative12(resolvedRepoRoot, packageDir);
|
|
47065
|
-
const contextPath =
|
|
47085
|
+
const contextPath = join31(resolvedRepoRoot, ".nax", "mono", relativePkgPath, "context.md");
|
|
47066
47086
|
if (!_generatorDeps.existsSync(contextPath)) {
|
|
47067
47087
|
return [
|
|
47068
47088
|
{
|
|
@@ -47130,7 +47150,7 @@ var init_generator2 = __esm(() => {
|
|
|
47130
47150
|
});
|
|
47131
47151
|
|
|
47132
47152
|
// src/analyze/scanner.ts
|
|
47133
|
-
import { join as
|
|
47153
|
+
import { join as join32 } from "path";
|
|
47134
47154
|
function resolveFrameworkAndRunner(language, pkg) {
|
|
47135
47155
|
if (language === "go")
|
|
47136
47156
|
return { framework: "", testRunner: "go-test" };
|
|
@@ -47152,7 +47172,7 @@ async function scanSourceRoots(workdir) {
|
|
|
47152
47172
|
});
|
|
47153
47173
|
try {
|
|
47154
47174
|
const language = await deps.detectLanguage(workdir);
|
|
47155
|
-
const pkg = await deps.readPackageJson(
|
|
47175
|
+
const pkg = await deps.readPackageJson(join32(workdir, "package.json"));
|
|
47156
47176
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
47157
47177
|
return [{ path: ".", language, framework, testRunner }];
|
|
47158
47178
|
} catch {
|
|
@@ -47170,9 +47190,9 @@ async function scanSourceRoots(workdir) {
|
|
|
47170
47190
|
packages = packages.slice(0, MAX_SOURCE_ROOTS);
|
|
47171
47191
|
}
|
|
47172
47192
|
return Promise.all(packages.map(async (pkgPath) => {
|
|
47173
|
-
const pkgDir = pkgPath === "." ? workdir :
|
|
47193
|
+
const pkgDir = pkgPath === "." ? workdir : join32(workdir, pkgPath);
|
|
47174
47194
|
const language = await deps.detectLanguage(pkgDir);
|
|
47175
|
-
const pkg = await deps.readPackageJson(
|
|
47195
|
+
const pkg = await deps.readPackageJson(join32(pkgDir, "package.json"));
|
|
47176
47196
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
47177
47197
|
return { path: pkgPath, language, framework, testRunner };
|
|
47178
47198
|
}));
|
|
@@ -47205,7 +47225,7 @@ var init_analyze = __esm(() => {
|
|
|
47205
47225
|
});
|
|
47206
47226
|
|
|
47207
47227
|
// src/debate/pre-phase/grounder.ts
|
|
47208
|
-
import { join as
|
|
47228
|
+
import { join as join33 } from "path";
|
|
47209
47229
|
async function buildCodebaseContext(workdir) {
|
|
47210
47230
|
const roots = await _grounderDeps.scanSourceRoots(workdir);
|
|
47211
47231
|
return buildSourceRootsSection(normalizeRoots(workdir, roots));
|
|
@@ -47217,7 +47237,7 @@ function normalizeRoots(workdir, roots) {
|
|
|
47217
47237
|
}));
|
|
47218
47238
|
}
|
|
47219
47239
|
async function writeManifestArtifact(ctx, manifest) {
|
|
47220
|
-
const manifestPath =
|
|
47240
|
+
const manifestPath = join33(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
47221
47241
|
await _grounderDeps.write(manifestPath, JSON.stringify(manifest, null, 2));
|
|
47222
47242
|
}
|
|
47223
47243
|
var _grounderDeps, grounderStrategy = async (ctx) => {
|
|
@@ -47560,7 +47580,7 @@ function formatSpecDeltas(blockers, manifest) {
|
|
|
47560
47580
|
|
|
47561
47581
|
// src/debate/verifiers/checks.ts
|
|
47562
47582
|
import { existsSync as defaultExistsSync } from "fs";
|
|
47563
|
-
import { join as
|
|
47583
|
+
import { join as join34 } from "path";
|
|
47564
47584
|
function checkFilesExist(prd, workdir, deps) {
|
|
47565
47585
|
const existsSync10 = deps?.existsSync ?? defaultExistsSync;
|
|
47566
47586
|
const findings = [];
|
|
@@ -47570,7 +47590,7 @@ function checkFilesExist(prd, workdir, deps) {
|
|
|
47570
47590
|
for (const entry of story.contextFiles) {
|
|
47571
47591
|
const filePath = typeof entry === "string" ? entry : entry.path;
|
|
47572
47592
|
const factId = typeof entry === "string" ? undefined : entry.factId;
|
|
47573
|
-
const absPath =
|
|
47593
|
+
const absPath = join34(workdir, filePath);
|
|
47574
47594
|
if (existsSync10(absPath))
|
|
47575
47595
|
continue;
|
|
47576
47596
|
if (factId) {
|
|
@@ -47681,7 +47701,7 @@ var init_checks3 = () => {};
|
|
|
47681
47701
|
|
|
47682
47702
|
// src/debate/verifiers/plan-checklist.ts
|
|
47683
47703
|
import { existsSync as existsSync10 } from "fs";
|
|
47684
|
-
import { join as
|
|
47704
|
+
import { join as join35 } from "path";
|
|
47685
47705
|
function parsePrd(output) {
|
|
47686
47706
|
if (!output)
|
|
47687
47707
|
return null;
|
|
@@ -47692,7 +47712,7 @@ function parsePrd(output) {
|
|
|
47692
47712
|
}
|
|
47693
47713
|
}
|
|
47694
47714
|
async function loadManifest(ctx) {
|
|
47695
|
-
const manifestPath =
|
|
47715
|
+
const manifestPath = join35(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
47696
47716
|
const raw = await _planChecklistDeps.readFile(manifestPath);
|
|
47697
47717
|
if (!raw)
|
|
47698
47718
|
return null;
|
|
@@ -47705,7 +47725,7 @@ async function loadManifest(ctx) {
|
|
|
47705
47725
|
}
|
|
47706
47726
|
}
|
|
47707
47727
|
async function emitSpecDeltas(ctx, blockers, manifest) {
|
|
47708
|
-
const artifactPath =
|
|
47728
|
+
const artifactPath = join35(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "spec-deltas.md");
|
|
47709
47729
|
const content = formatSpecDeltas(blockers, manifest ?? { repoFacts: [], specClaims: [], gaps: [] });
|
|
47710
47730
|
await _planChecklistDeps.write(artifactPath, content);
|
|
47711
47731
|
return artifactPath;
|
|
@@ -48051,7 +48071,7 @@ var init_runner_plan_helpers = __esm(() => {
|
|
|
48051
48071
|
});
|
|
48052
48072
|
|
|
48053
48073
|
// src/debate/runner-plan.ts
|
|
48054
|
-
import { join as
|
|
48074
|
+
import { join as join36 } from "path";
|
|
48055
48075
|
async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
48056
48076
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
48057
48077
|
const config2 = ctx.stageConfig;
|
|
@@ -48110,7 +48130,7 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
48110
48130
|
sessionMode: ctx.stageConfig.sessionMode ?? "one-shot",
|
|
48111
48131
|
proposers: ctx.stageConfig.proposers
|
|
48112
48132
|
});
|
|
48113
|
-
const outputPaths = resolved.map((_, i) =>
|
|
48133
|
+
const outputPaths = resolved.map((_, i) => join36(opts.outputDir, `prd-debate-${i}.json`));
|
|
48114
48134
|
const successful = [];
|
|
48115
48135
|
let rebuttalList;
|
|
48116
48136
|
if (selectorKind === "verifier-pick") {
|
|
@@ -50353,9 +50373,9 @@ function validateFeatureName(feature) {
|
|
|
50353
50373
|
|
|
50354
50374
|
// src/plan/critic.ts
|
|
50355
50375
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
50356
|
-
import { dirname as dirname7, join as
|
|
50376
|
+
import { dirname as dirname7, join as join39 } from "path";
|
|
50357
50377
|
async function writeSpecDeltas(findings, workdir, runId, storyId, manifest) {
|
|
50358
|
-
const path7 =
|
|
50378
|
+
const path7 = join39(workdir, ".nax", "runs", runId, "plan", storyId, "spec-deltas.md");
|
|
50359
50379
|
await mkdir6(dirname7(path7), { recursive: true });
|
|
50360
50380
|
await Bun.write(path7, formatSpecDeltas(findings, manifest));
|
|
50361
50381
|
return path7;
|
|
@@ -51568,9 +51588,9 @@ __export(exports_plan_decompose, {
|
|
|
51568
51588
|
runReplanLoop: () => runReplanLoop,
|
|
51569
51589
|
planDecomposeCommand: () => planDecomposeCommand
|
|
51570
51590
|
});
|
|
51571
|
-
import { join as
|
|
51591
|
+
import { join as join40 } from "path";
|
|
51572
51592
|
async function planDecomposeCommand(workdir, config2, options) {
|
|
51573
|
-
const prdPath =
|
|
51593
|
+
const prdPath = join40(workdir, ".nax", "features", options.feature, "prd.json");
|
|
51574
51594
|
if (!_planDeps.existsSync(prdPath)) {
|
|
51575
51595
|
throw new NaxError(`PRD not found: ${prdPath}`, "PRD_NOT_FOUND", {
|
|
51576
51596
|
stage: "decompose",
|
|
@@ -51744,7 +51764,7 @@ var init_plan_decompose = __esm(() => {
|
|
|
51744
51764
|
|
|
51745
51765
|
// src/cli/plan-runtime.ts
|
|
51746
51766
|
import { existsSync as existsSync15 } from "fs";
|
|
51747
|
-
import { join as
|
|
51767
|
+
import { join as join41 } from "path";
|
|
51748
51768
|
function isRuntimeWithAgentManager(value) {
|
|
51749
51769
|
return typeof value === "object" && value !== null && "agentManager" in value;
|
|
51750
51770
|
}
|
|
@@ -51796,7 +51816,7 @@ var init_plan_runtime = __esm(() => {
|
|
|
51796
51816
|
writeFile: (path7, content) => Bun.write(path7, content).then(() => {}),
|
|
51797
51817
|
scanSourceRoots: (workdir) => scanSourceRoots(workdir),
|
|
51798
51818
|
createRuntime: (cfg, wd, featureName) => createRuntime(cfg, wd, { featureName }),
|
|
51799
|
-
readPackageJson: (workdir) => Bun.file(
|
|
51819
|
+
readPackageJson: (workdir) => Bun.file(join41(workdir, "package.json")).json().catch(() => null),
|
|
51800
51820
|
spawnSync: (cmd, opts) => {
|
|
51801
51821
|
const result = Bun.spawnSync(cmd, opts ? { cwd: opts.cwd } : {});
|
|
51802
51822
|
return { stdout: result.stdout, exitCode: result.exitCode };
|
|
@@ -52181,7 +52201,7 @@ var init_metrics = __esm(() => {
|
|
|
52181
52201
|
|
|
52182
52202
|
// src/commands/common.ts
|
|
52183
52203
|
import { existsSync as existsSync16, readdirSync as readdirSync2, realpathSync as realpathSync3 } from "fs";
|
|
52184
|
-
import { join as
|
|
52204
|
+
import { join as join42, resolve as resolve13 } from "path";
|
|
52185
52205
|
function resolveProject(options = {}) {
|
|
52186
52206
|
const { dir, feature } = options;
|
|
52187
52207
|
let projectRoot;
|
|
@@ -52189,12 +52209,12 @@ function resolveProject(options = {}) {
|
|
|
52189
52209
|
let configPath;
|
|
52190
52210
|
if (dir) {
|
|
52191
52211
|
projectRoot = realpathSync3(resolve13(dir));
|
|
52192
|
-
naxDir =
|
|
52212
|
+
naxDir = join42(projectRoot, ".nax");
|
|
52193
52213
|
if (!existsSync16(naxDir)) {
|
|
52194
52214
|
throw new NaxError(`Directory does not contain a nax project: ${projectRoot}
|
|
52195
52215
|
Expected to find: ${naxDir}`, "NAX_DIR_NOT_FOUND", { projectRoot, naxDir });
|
|
52196
52216
|
}
|
|
52197
|
-
configPath =
|
|
52217
|
+
configPath = join42(naxDir, "config.json");
|
|
52198
52218
|
if (!existsSync16(configPath)) {
|
|
52199
52219
|
throw new NaxError(`.nax directory found but config.json is missing: ${naxDir}
|
|
52200
52220
|
Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
@@ -52202,17 +52222,17 @@ Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
|
52202
52222
|
} else {
|
|
52203
52223
|
const found = findProjectRoot(process.cwd());
|
|
52204
52224
|
if (!found) {
|
|
52205
|
-
const cwdNaxDir =
|
|
52225
|
+
const cwdNaxDir = join42(process.cwd(), ".nax");
|
|
52206
52226
|
if (existsSync16(cwdNaxDir)) {
|
|
52207
|
-
const cwdConfigPath =
|
|
52227
|
+
const cwdConfigPath = join42(cwdNaxDir, "config.json");
|
|
52208
52228
|
throw new NaxError(`.nax directory found but config.json is missing: ${cwdNaxDir}
|
|
52209
52229
|
Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, configPath: cwdConfigPath });
|
|
52210
52230
|
}
|
|
52211
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() });
|
|
52212
52232
|
}
|
|
52213
52233
|
projectRoot = found;
|
|
52214
|
-
naxDir =
|
|
52215
|
-
configPath =
|
|
52234
|
+
naxDir = join42(projectRoot, ".nax");
|
|
52235
|
+
configPath = join42(naxDir, "config.json");
|
|
52216
52236
|
}
|
|
52217
52237
|
let featureDir;
|
|
52218
52238
|
if (feature) {
|
|
@@ -52221,8 +52241,8 @@ Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, co
|
|
|
52221
52241
|
} catch (error48) {
|
|
52222
52242
|
throw new NaxError(error48.message, "FEATURE_INVALID", { feature });
|
|
52223
52243
|
}
|
|
52224
|
-
const featuresDir =
|
|
52225
|
-
featureDir =
|
|
52244
|
+
const featuresDir = join42(naxDir, "features");
|
|
52245
|
+
featureDir = join42(featuresDir, feature);
|
|
52226
52246
|
if (!existsSync16(featureDir)) {
|
|
52227
52247
|
const availableFeatures = existsSync16(featuresDir) ? readdirSync2(featuresDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name) : [];
|
|
52228
52248
|
const availableMsg = availableFeatures.length > 0 ? `
|
|
@@ -52255,7 +52275,7 @@ async function resolveProjectAsync(options = {}) {
|
|
|
52255
52275
|
}
|
|
52256
52276
|
const isPlainName = !dir.includes("/") && !dir.includes("\\");
|
|
52257
52277
|
if (isPlainName) {
|
|
52258
|
-
const registryIdentityPath =
|
|
52278
|
+
const registryIdentityPath = join42(globalConfigDir(), dir, ".identity");
|
|
52259
52279
|
const identityFile = Bun.file(registryIdentityPath);
|
|
52260
52280
|
if (await identityFile.exists()) {
|
|
52261
52281
|
try {
|
|
@@ -52287,12 +52307,12 @@ function findProjectRoot(startDir) {
|
|
|
52287
52307
|
let current = resolve13(startDir);
|
|
52288
52308
|
let depth = 0;
|
|
52289
52309
|
while (depth < MAX_DIRECTORY_DEPTH) {
|
|
52290
|
-
const naxDir =
|
|
52291
|
-
const configPath =
|
|
52310
|
+
const naxDir = join42(current, ".nax");
|
|
52311
|
+
const configPath = join42(naxDir, "config.json");
|
|
52292
52312
|
if (existsSync16(configPath)) {
|
|
52293
52313
|
return realpathSync3(current);
|
|
52294
52314
|
}
|
|
52295
|
-
const parent =
|
|
52315
|
+
const parent = join42(current, "..");
|
|
52296
52316
|
if (parent === current) {
|
|
52297
52317
|
break;
|
|
52298
52318
|
}
|
|
@@ -52619,8 +52639,8 @@ var init_semantic_verdict = __esm(() => {
|
|
|
52619
52639
|
await Bun.write(filePath, content);
|
|
52620
52640
|
},
|
|
52621
52641
|
readdir: async (dir) => {
|
|
52622
|
-
const { readdir:
|
|
52623
|
-
return
|
|
52642
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
52643
|
+
return readdir2(dir);
|
|
52624
52644
|
},
|
|
52625
52645
|
readFile: async (filePath) => {
|
|
52626
52646
|
return Bun.file(filePath).text();
|
|
@@ -53071,10 +53091,10 @@ var init_acceptance_setup = __esm(() => {
|
|
|
53071
53091
|
},
|
|
53072
53092
|
deleteSemanticVerdicts: async (featureDir) => {
|
|
53073
53093
|
const dir = `${featureDir}/semantic-verdicts`;
|
|
53074
|
-
const { readdir:
|
|
53094
|
+
const { readdir: readdir2, unlink: unlink2 } = await import("fs/promises");
|
|
53075
53095
|
let files;
|
|
53076
53096
|
try {
|
|
53077
|
-
files = await
|
|
53097
|
+
files = await readdir2(dir);
|
|
53078
53098
|
} catch (err) {
|
|
53079
53099
|
if (err.code === "ENOENT")
|
|
53080
53100
|
return;
|
|
@@ -53451,10 +53471,10 @@ var init_effectiveness = __esm(() => {
|
|
|
53451
53471
|
|
|
53452
53472
|
// src/execution/progress.ts
|
|
53453
53473
|
import { appendFile as appendFile2, mkdir as mkdir7 } from "fs/promises";
|
|
53454
|
-
import { join as
|
|
53474
|
+
import { join as join45 } from "path";
|
|
53455
53475
|
async function appendProgress(featureDir, storyId, status, message) {
|
|
53456
53476
|
await mkdir7(featureDir, { recursive: true });
|
|
53457
|
-
const progressPath =
|
|
53477
|
+
const progressPath = join45(featureDir, "progress.txt");
|
|
53458
53478
|
const timestamp = new Date().toISOString();
|
|
53459
53479
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
53460
53480
|
`;
|
|
@@ -53648,7 +53668,7 @@ var init_completion = __esm(() => {
|
|
|
53648
53668
|
|
|
53649
53669
|
// src/constitution/loader.ts
|
|
53650
53670
|
import { existsSync as existsSync19 } from "fs";
|
|
53651
|
-
import { join as
|
|
53671
|
+
import { join as join46 } from "path";
|
|
53652
53672
|
function truncateToTokens(text, maxTokens) {
|
|
53653
53673
|
const maxChars = maxTokens * 3;
|
|
53654
53674
|
if (text.length <= maxChars) {
|
|
@@ -53670,7 +53690,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53670
53690
|
}
|
|
53671
53691
|
let combinedContent = "";
|
|
53672
53692
|
if (!config2.skipGlobal) {
|
|
53673
|
-
const globalPath =
|
|
53693
|
+
const globalPath = join46(globalConfigDir(), config2.path);
|
|
53674
53694
|
if (existsSync19(globalPath)) {
|
|
53675
53695
|
const validatedPath = validateFilePath(globalPath, globalConfigDir());
|
|
53676
53696
|
const globalFile = Bun.file(validatedPath);
|
|
@@ -53680,7 +53700,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53680
53700
|
}
|
|
53681
53701
|
}
|
|
53682
53702
|
}
|
|
53683
|
-
const projectPath =
|
|
53703
|
+
const projectPath = join46(projectDir, config2.path);
|
|
53684
53704
|
if (existsSync19(projectPath)) {
|
|
53685
53705
|
const validatedPath = validateFilePath(projectPath, projectDir);
|
|
53686
53706
|
const projectFile = Bun.file(validatedPath);
|
|
@@ -55114,7 +55134,7 @@ var init_story_orchestrator = __esm(() => {
|
|
|
55114
55134
|
});
|
|
55115
55135
|
|
|
55116
55136
|
// src/execution/build-plan-for-strategy.ts
|
|
55117
|
-
import { join as
|
|
55137
|
+
import { join as join47 } from "path";
|
|
55118
55138
|
function requiresInitialRefCapture(strategy) {
|
|
55119
55139
|
return isThreeSessionStrategy(strategy);
|
|
55120
55140
|
}
|
|
@@ -55160,7 +55180,7 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55160
55180
|
}
|
|
55161
55181
|
if (shouldRunRectification(config2) && inputs.rectification) {
|
|
55162
55182
|
const sink = makeDeclarationSink();
|
|
55163
|
-
const packageDir =
|
|
55183
|
+
const packageDir = join47(ctx.packageDir, story.workdir ?? "");
|
|
55164
55184
|
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.packageDir, story.workdir);
|
|
55165
55185
|
const strategies = [];
|
|
55166
55186
|
const pkgQuality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
@@ -55230,8 +55250,27 @@ var init_build_plan_for_strategy = __esm(() => {
|
|
|
55230
55250
|
init_story_orchestrator();
|
|
55231
55251
|
});
|
|
55232
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
|
+
|
|
55233
55273
|
// src/execution/plan-inputs.ts
|
|
55234
|
-
import { relative as relative13, sep as sep4 } from "path";
|
|
55235
55274
|
function validatePlanInputs(story, config2) {
|
|
55236
55275
|
if (!story.id || story.id.trim() === "") {
|
|
55237
55276
|
throw new NaxError("Story ID is required and must be non-empty", "STORY_ID_INVALID", {
|
|
@@ -55307,15 +55346,8 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55307
55346
|
if (!_isTdd && !ctx.prompt?.trim()) {
|
|
55308
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 });
|
|
55309
55348
|
}
|
|
55310
|
-
const
|
|
55311
|
-
|
|
55312
|
-
return;
|
|
55313
|
-
const rel = relative13(ctx.projectDir, ctx.workdir);
|
|
55314
|
-
if (rel === ".." || rel.startsWith(`..${sep4}`))
|
|
55315
|
-
return;
|
|
55316
|
-
return rel && rel !== "." ? rel : undefined;
|
|
55317
|
-
})();
|
|
55318
|
-
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);
|
|
55319
55351
|
const [testWriterPrompt, implementerPrompt, verifierPrompt] = _isTdd ? await Promise.all([
|
|
55320
55352
|
_isFreshRun ? buildThreeSessionPrompt("test-writer", ctx, isLite) : Promise.resolve(""),
|
|
55321
55353
|
buildThreeSessionPrompt("implementer", ctx, isLite),
|
|
@@ -55326,7 +55358,8 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55326
55358
|
promptMarkdown: testWriterPrompt,
|
|
55327
55359
|
featureContextMarkdown: ctx.featureContextMarkdown,
|
|
55328
55360
|
constitution: ctx.constitution?.content,
|
|
55329
|
-
lite: isLite
|
|
55361
|
+
lite: isLite,
|
|
55362
|
+
resolvedTestPatterns
|
|
55330
55363
|
} : undefined;
|
|
55331
55364
|
const greenfieldGateInput = _isTdd && _isFreshRun && resolvedTestPatterns ? { story, workdir: ctx.workdir, resolvedTestPatterns } : undefined;
|
|
55332
55365
|
const implementerInput = {
|
|
@@ -55351,7 +55384,7 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55351
55384
|
naxIgnoreIndex: ctx.naxIgnoreIndex,
|
|
55352
55385
|
regressionMode: toVerifyScopedMode(ctx.config.execution?.regressionGate?.mode),
|
|
55353
55386
|
repoRoot: ctx.projectDir,
|
|
55354
|
-
packagePrefix:
|
|
55387
|
+
packagePrefix: packageDirRel,
|
|
55355
55388
|
resolvedTestPatterns
|
|
55356
55389
|
} : undefined;
|
|
55357
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;
|
|
@@ -55456,6 +55489,7 @@ var init_plan_inputs = __esm(() => {
|
|
|
55456
55489
|
init_prompts();
|
|
55457
55490
|
init_review();
|
|
55458
55491
|
init_resolver();
|
|
55492
|
+
init_paths3();
|
|
55459
55493
|
});
|
|
55460
55494
|
|
|
55461
55495
|
// src/pipeline/stages/execution-helpers.ts
|
|
@@ -56521,6 +56555,8 @@ var init_queue_check = __esm(() => {
|
|
|
56521
56555
|
// src/pipeline/stages/routing.ts
|
|
56522
56556
|
var routingStage, _routingDeps;
|
|
56523
56557
|
var init_routing2 = __esm(() => {
|
|
56558
|
+
init_test_runners();
|
|
56559
|
+
init_paths3();
|
|
56524
56560
|
init_greenfield();
|
|
56525
56561
|
init_logger2();
|
|
56526
56562
|
init_prd();
|
|
@@ -56564,7 +56600,16 @@ var init_routing2 = __esm(() => {
|
|
|
56564
56600
|
const greenfieldDetectionEnabled = ctx.config.tdd.greenfieldDetection ?? true;
|
|
56565
56601
|
if (greenfieldDetectionEnabled && routing.testStrategy.startsWith("three-session-tdd")) {
|
|
56566
56602
|
const greenfieldScanDir = ctx.workdir;
|
|
56567
|
-
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);
|
|
56568
56613
|
if (isGreenfield) {
|
|
56569
56614
|
logger.info("routing", "Greenfield detected \u2014 forcing test-after strategy", {
|
|
56570
56615
|
storyId: ctx.story.id,
|
|
@@ -56592,6 +56637,7 @@ var init_routing2 = __esm(() => {
|
|
|
56592
56637
|
resolveRouting,
|
|
56593
56638
|
complexityToModelTier,
|
|
56594
56639
|
isGreenfieldStory,
|
|
56640
|
+
resolveTestFilePatterns,
|
|
56595
56641
|
clearCache,
|
|
56596
56642
|
savePRD
|
|
56597
56643
|
};
|
|
@@ -59508,18 +59554,6 @@ var init_loader4 = __esm(() => {
|
|
|
59508
59554
|
FALLBACK_TEST_FILE_RE = /\.(test|spec)\.(ts|js|tsx|jsx|mjs)$/;
|
|
59509
59555
|
});
|
|
59510
59556
|
|
|
59511
|
-
// src/utils/paths.ts
|
|
59512
|
-
import { join as join68 } from "path";
|
|
59513
|
-
function getRunsDir() {
|
|
59514
|
-
return process.env.NAX_RUNS_DIR ?? join68(globalConfigDir(), "runs");
|
|
59515
|
-
}
|
|
59516
|
-
function getEventsRootDir() {
|
|
59517
|
-
return join68(globalConfigDir(), "events");
|
|
59518
|
-
}
|
|
59519
|
-
var init_paths3 = __esm(() => {
|
|
59520
|
-
init_paths();
|
|
59521
|
-
});
|
|
59522
|
-
|
|
59523
59557
|
// src/utils/command-argv.ts
|
|
59524
59558
|
function parseCommandToArgv(command) {
|
|
59525
59559
|
const safeEnv = buildAllowedEnv();
|
|
@@ -59574,7 +59608,7 @@ var init_command_argv = __esm(() => {
|
|
|
59574
59608
|
});
|
|
59575
59609
|
|
|
59576
59610
|
// src/hooks/runner.ts
|
|
59577
|
-
import { join as
|
|
59611
|
+
import { join as join74 } from "path";
|
|
59578
59612
|
function createDrainDeadline2(deadlineMs) {
|
|
59579
59613
|
let timeoutId;
|
|
59580
59614
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -59593,14 +59627,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
59593
59627
|
let globalHooks = { hooks: {} };
|
|
59594
59628
|
let projectHooks = { hooks: {} };
|
|
59595
59629
|
let skipGlobal = false;
|
|
59596
|
-
const projectPath =
|
|
59630
|
+
const projectPath = join74(projectDir, "hooks.json");
|
|
59597
59631
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
59598
59632
|
if (projectData) {
|
|
59599
59633
|
projectHooks = projectData;
|
|
59600
59634
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
59601
59635
|
}
|
|
59602
59636
|
if (!skipGlobal && globalDir) {
|
|
59603
|
-
const globalPath =
|
|
59637
|
+
const globalPath = join74(globalDir, "hooks.json");
|
|
59604
59638
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
59605
59639
|
if (globalData) {
|
|
59606
59640
|
globalHooks = globalData;
|
|
@@ -59770,7 +59804,7 @@ var package_default;
|
|
|
59770
59804
|
var init_package = __esm(() => {
|
|
59771
59805
|
package_default = {
|
|
59772
59806
|
name: "@nathapp/nax",
|
|
59773
|
-
version: "0.69.
|
|
59807
|
+
version: "0.69.8",
|
|
59774
59808
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
59775
59809
|
type: "module",
|
|
59776
59810
|
bin: {
|
|
@@ -59865,8 +59899,8 @@ var init_version = __esm(() => {
|
|
|
59865
59899
|
NAX_VERSION = package_default.version;
|
|
59866
59900
|
NAX_COMMIT = (() => {
|
|
59867
59901
|
try {
|
|
59868
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
59869
|
-
return "
|
|
59902
|
+
if (/^[0-9a-f]{6,10}$/.test("0b7fc5bf"))
|
|
59903
|
+
return "0b7fc5bf";
|
|
59870
59904
|
} catch {}
|
|
59871
59905
|
try {
|
|
59872
59906
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -60743,15 +60777,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
60743
60777
|
|
|
60744
60778
|
// src/session/scratch-purge.ts
|
|
60745
60779
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
60746
|
-
import { dirname as dirname12, join as
|
|
60780
|
+
import { dirname as dirname12, join as join75 } from "path";
|
|
60747
60781
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
60748
|
-
const sessionsDir =
|
|
60782
|
+
const sessionsDir = join75(projectDir, ".nax", "features", featureName, "sessions");
|
|
60749
60783
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
60750
60784
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
60751
60785
|
let purged = 0;
|
|
60752
60786
|
for (const sessionId of sessionIds) {
|
|
60753
|
-
const sessionDir =
|
|
60754
|
-
const descriptorPath =
|
|
60787
|
+
const sessionDir = join75(sessionsDir, sessionId);
|
|
60788
|
+
const descriptorPath = join75(sessionDir, "descriptor.json");
|
|
60755
60789
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
60756
60790
|
continue;
|
|
60757
60791
|
let lastActivityAt;
|
|
@@ -60767,7 +60801,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
60767
60801
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
60768
60802
|
continue;
|
|
60769
60803
|
if (archiveInsteadOfDelete) {
|
|
60770
|
-
const archiveDest =
|
|
60804
|
+
const archiveDest = join75(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
60771
60805
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
60772
60806
|
} else {
|
|
60773
60807
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -61505,12 +61539,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
61505
61539
|
|
|
61506
61540
|
// src/pipeline/subscribers/events-writer.ts
|
|
61507
61541
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
61508
|
-
import { basename as basename13, join as
|
|
61542
|
+
import { basename as basename13, join as join76 } from "path";
|
|
61509
61543
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
61510
61544
|
const logger = getSafeLogger();
|
|
61511
61545
|
const project = basename13(workdir);
|
|
61512
|
-
const eventsDir =
|
|
61513
|
-
const eventsFile =
|
|
61546
|
+
const eventsDir = join76(getEventsRootDir(), project);
|
|
61547
|
+
const eventsFile = join76(eventsDir, "events.jsonl");
|
|
61514
61548
|
let dirReady = false;
|
|
61515
61549
|
const write = (line) => {
|
|
61516
61550
|
return (async () => {
|
|
@@ -61691,12 +61725,12 @@ var init_interaction2 = __esm(() => {
|
|
|
61691
61725
|
|
|
61692
61726
|
// src/pipeline/subscribers/registry.ts
|
|
61693
61727
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
61694
|
-
import { basename as basename14, join as
|
|
61728
|
+
import { basename as basename14, join as join77 } from "path";
|
|
61695
61729
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
61696
61730
|
const logger = getSafeLogger();
|
|
61697
61731
|
const project = basename14(workdir);
|
|
61698
|
-
const runDir =
|
|
61699
|
-
const metaFile =
|
|
61732
|
+
const runDir = join77(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
61733
|
+
const metaFile = join77(runDir, "meta.json");
|
|
61700
61734
|
const unsub = bus.on("run:started", (_ev) => {
|
|
61701
61735
|
return (async () => {
|
|
61702
61736
|
try {
|
|
@@ -61706,8 +61740,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
61706
61740
|
project,
|
|
61707
61741
|
feature,
|
|
61708
61742
|
workdir,
|
|
61709
|
-
statusPath:
|
|
61710
|
-
eventsDir:
|
|
61743
|
+
statusPath: join77(outputDir, "features", feature, "status.json"),
|
|
61744
|
+
eventsDir: join77(outputDir, "features", feature, "runs"),
|
|
61711
61745
|
registeredAt: new Date().toISOString()
|
|
61712
61746
|
};
|
|
61713
61747
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -61953,7 +61987,7 @@ var init_types9 = __esm(() => {
|
|
|
61953
61987
|
|
|
61954
61988
|
// src/worktree/dependencies.ts
|
|
61955
61989
|
import { existsSync as existsSync30 } from "fs";
|
|
61956
|
-
import { join as
|
|
61990
|
+
import { join as join78 } from "path";
|
|
61957
61991
|
async function prepareWorktreeDependencies(options) {
|
|
61958
61992
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
61959
61993
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -61967,7 +62001,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
61967
62001
|
}
|
|
61968
62002
|
}
|
|
61969
62003
|
function resolveDependencyCwd(options) {
|
|
61970
|
-
return options.storyWorkdir ?
|
|
62004
|
+
return options.storyWorkdir ? join78(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
61971
62005
|
}
|
|
61972
62006
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
61973
62007
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -61977,7 +62011,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
61977
62011
|
}
|
|
61978
62012
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
61979
62013
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
61980
|
-
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))));
|
|
61981
62015
|
}
|
|
61982
62016
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
61983
62017
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -62041,13 +62075,13 @@ __export(exports_manager, {
|
|
|
62041
62075
|
});
|
|
62042
62076
|
import { existsSync as existsSync31, symlinkSync } from "fs";
|
|
62043
62077
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
62044
|
-
import { join as
|
|
62078
|
+
import { join as join79 } from "path";
|
|
62045
62079
|
|
|
62046
62080
|
class WorktreeManager {
|
|
62047
62081
|
async ensureGitExcludes(projectRoot) {
|
|
62048
62082
|
const logger = getSafeLogger();
|
|
62049
|
-
const infoDir =
|
|
62050
|
-
const excludePath =
|
|
62083
|
+
const infoDir = join79(projectRoot, ".git", "info");
|
|
62084
|
+
const excludePath = join79(infoDir, "exclude");
|
|
62051
62085
|
try {
|
|
62052
62086
|
await mkdir15(infoDir, { recursive: true });
|
|
62053
62087
|
let existing = "";
|
|
@@ -62074,7 +62108,7 @@ ${missing.join(`
|
|
|
62074
62108
|
}
|
|
62075
62109
|
async create(projectRoot, storyId) {
|
|
62076
62110
|
validateStoryId(storyId);
|
|
62077
|
-
const worktreePath =
|
|
62111
|
+
const worktreePath = join79(projectRoot, ".nax-wt", storyId);
|
|
62078
62112
|
const branchName = `nax/${storyId}`;
|
|
62079
62113
|
try {
|
|
62080
62114
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -62115,9 +62149,9 @@ ${missing.join(`
|
|
|
62115
62149
|
}
|
|
62116
62150
|
throw new Error(`Failed to create worktree: ${String(error48)}`);
|
|
62117
62151
|
}
|
|
62118
|
-
const envSource =
|
|
62152
|
+
const envSource = join79(projectRoot, ".env");
|
|
62119
62153
|
if (existsSync31(envSource)) {
|
|
62120
|
-
const envTarget =
|
|
62154
|
+
const envTarget = join79(worktreePath, ".env");
|
|
62121
62155
|
try {
|
|
62122
62156
|
symlinkSync(envSource, envTarget, "file");
|
|
62123
62157
|
} catch (error48) {
|
|
@@ -62128,7 +62162,7 @@ ${missing.join(`
|
|
|
62128
62162
|
}
|
|
62129
62163
|
async remove(projectRoot, storyId) {
|
|
62130
62164
|
validateStoryId(storyId);
|
|
62131
|
-
const worktreePath =
|
|
62165
|
+
const worktreePath = join79(projectRoot, ".nax-wt", storyId);
|
|
62132
62166
|
const branchName = `nax/${storyId}`;
|
|
62133
62167
|
try {
|
|
62134
62168
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -62940,10 +62974,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
62940
62974
|
});
|
|
62941
62975
|
|
|
62942
62976
|
// src/execution/pipeline-result-handler.ts
|
|
62943
|
-
import { join as
|
|
62977
|
+
import { join as join80 } from "path";
|
|
62944
62978
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
62945
62979
|
const logger = getSafeLogger();
|
|
62946
|
-
const worktreePath =
|
|
62980
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62947
62981
|
try {
|
|
62948
62982
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
62949
62983
|
cwd: projectRoot,
|
|
@@ -63160,7 +63194,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
63160
63194
|
|
|
63161
63195
|
// src/execution/iteration-runner.ts
|
|
63162
63196
|
import { existsSync as existsSync32 } from "fs";
|
|
63163
|
-
import { join as
|
|
63197
|
+
import { join as join81 } from "path";
|
|
63164
63198
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
63165
63199
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
63166
63200
|
if (ctx.dryRun) {
|
|
@@ -63185,7 +63219,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63185
63219
|
const storyStartTime = Date.now();
|
|
63186
63220
|
let effectiveWorkdir = ctx.workdir;
|
|
63187
63221
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63188
|
-
const worktreePath =
|
|
63222
|
+
const worktreePath = join81(ctx.workdir, ".nax-wt", story.id);
|
|
63189
63223
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
63190
63224
|
if (!worktreeExists) {
|
|
63191
63225
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -63205,7 +63239,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63205
63239
|
}
|
|
63206
63240
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
63207
63241
|
const profileOverride = ctx.config.profile && ctx.config.profile !== "default" ? { profile: ctx.config.profile } : undefined;
|
|
63208
|
-
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;
|
|
63209
63243
|
let dependencyContext;
|
|
63210
63244
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63211
63245
|
try {
|
|
@@ -63232,7 +63266,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63232
63266
|
};
|
|
63233
63267
|
}
|
|
63234
63268
|
}
|
|
63235
|
-
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;
|
|
63236
63270
|
const pipelineContext = {
|
|
63237
63271
|
config: effectiveConfig,
|
|
63238
63272
|
rootConfig: ctx.config,
|
|
@@ -63434,7 +63468,7 @@ __export(exports_parallel_worker, {
|
|
|
63434
63468
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
63435
63469
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
63436
63470
|
});
|
|
63437
|
-
import { join as
|
|
63471
|
+
import { join as join82 } from "path";
|
|
63438
63472
|
function buildWorktreePipelineContext(base, _story) {
|
|
63439
63473
|
return { ...base, prd: structuredClone(base.prd) };
|
|
63440
63474
|
}
|
|
@@ -63457,7 +63491,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
63457
63491
|
story,
|
|
63458
63492
|
stories: [story],
|
|
63459
63493
|
projectDir: context.projectDir,
|
|
63460
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
63494
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join82(worktreePath, story.workdir) : worktreePath),
|
|
63461
63495
|
worktreeDependencyContext: dependencyContext,
|
|
63462
63496
|
routing,
|
|
63463
63497
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -64344,7 +64378,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
64344
64378
|
var init_status_file = () => {};
|
|
64345
64379
|
|
|
64346
64380
|
// src/execution/status-writer.ts
|
|
64347
|
-
import { join as
|
|
64381
|
+
import { join as join83 } from "path";
|
|
64348
64382
|
|
|
64349
64383
|
class StatusWriter {
|
|
64350
64384
|
statusFile;
|
|
@@ -64463,7 +64497,7 @@ class StatusWriter {
|
|
|
64463
64497
|
if (!this._prd)
|
|
64464
64498
|
return;
|
|
64465
64499
|
const safeLogger = getSafeLogger();
|
|
64466
|
-
const featureStatusPath =
|
|
64500
|
+
const featureStatusPath = join83(featureDir, "status.json");
|
|
64467
64501
|
const write = async () => {
|
|
64468
64502
|
try {
|
|
64469
64503
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -64495,7 +64529,7 @@ __export(exports_migrate, {
|
|
|
64495
64529
|
detectGeneratedContent: () => detectGeneratedContent
|
|
64496
64530
|
});
|
|
64497
64531
|
import { existsSync as existsSync33 } from "fs";
|
|
64498
|
-
import { mkdir as mkdir16, readdir as
|
|
64532
|
+
import { mkdir as mkdir16, readdir as readdir5, rename as rename3 } from "fs/promises";
|
|
64499
64533
|
import path22 from "path";
|
|
64500
64534
|
async function detectGeneratedContent(naxDir) {
|
|
64501
64535
|
if (!existsSync33(naxDir))
|
|
@@ -64503,7 +64537,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64503
64537
|
const candidates = [];
|
|
64504
64538
|
let entries = [];
|
|
64505
64539
|
try {
|
|
64506
|
-
entries = await
|
|
64540
|
+
entries = await readdir5(naxDir);
|
|
64507
64541
|
} catch {
|
|
64508
64542
|
return [];
|
|
64509
64543
|
}
|
|
@@ -64516,13 +64550,13 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64516
64550
|
if (existsSync33(featuresDir)) {
|
|
64517
64551
|
let featureDirs = [];
|
|
64518
64552
|
try {
|
|
64519
|
-
featureDirs = await
|
|
64553
|
+
featureDirs = await readdir5(featuresDir);
|
|
64520
64554
|
} catch {}
|
|
64521
64555
|
for (const fid of featureDirs) {
|
|
64522
64556
|
const featureDir = path22.join(featuresDir, fid);
|
|
64523
64557
|
let subEntries = [];
|
|
64524
64558
|
try {
|
|
64525
|
-
subEntries = await
|
|
64559
|
+
subEntries = await readdir5(featureDir);
|
|
64526
64560
|
} catch {
|
|
64527
64561
|
continue;
|
|
64528
64562
|
}
|
|
@@ -64537,7 +64571,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64537
64571
|
const storiesDir = path22.join(featureDir, "stories");
|
|
64538
64572
|
let storyDirs = [];
|
|
64539
64573
|
try {
|
|
64540
|
-
storyDirs = await
|
|
64574
|
+
storyDirs = await readdir5(storiesDir);
|
|
64541
64575
|
} catch {
|
|
64542
64576
|
continue;
|
|
64543
64577
|
}
|
|
@@ -64545,7 +64579,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64545
64579
|
const storyDir = path22.join(storiesDir, sid);
|
|
64546
64580
|
let storyEntries = [];
|
|
64547
64581
|
try {
|
|
64548
|
-
storyEntries = await
|
|
64582
|
+
storyEntries = await readdir5(storyDir);
|
|
64549
64583
|
} catch {
|
|
64550
64584
|
continue;
|
|
64551
64585
|
}
|
|
@@ -64897,7 +64931,7 @@ __export(exports_run_initialization, {
|
|
|
64897
64931
|
initializeRun: () => initializeRun,
|
|
64898
64932
|
_reconcileDeps: () => _reconcileDeps
|
|
64899
64933
|
});
|
|
64900
|
-
import { join as
|
|
64934
|
+
import { join as join84 } from "path";
|
|
64901
64935
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
64902
64936
|
const logger = getSafeLogger();
|
|
64903
64937
|
let reconciledCount = 0;
|
|
@@ -64914,7 +64948,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
64914
64948
|
});
|
|
64915
64949
|
continue;
|
|
64916
64950
|
}
|
|
64917
|
-
const effectiveWorkdir = story.workdir ?
|
|
64951
|
+
const effectiveWorkdir = story.workdir ? join84(workdir, story.workdir) : workdir;
|
|
64918
64952
|
try {
|
|
64919
64953
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
64920
64954
|
if (!reviewResult.success) {
|
|
@@ -94718,7 +94752,7 @@ __export(exports_curator, {
|
|
|
94718
94752
|
});
|
|
94719
94753
|
import { readdirSync as readdirSync8 } from "fs";
|
|
94720
94754
|
import { unlink as unlink4 } from "fs/promises";
|
|
94721
|
-
import { basename as basename15, join as
|
|
94755
|
+
import { basename as basename15, join as join86 } from "path";
|
|
94722
94756
|
function getProjectKey(config2, projectDir) {
|
|
94723
94757
|
return config2.name?.trim() || basename15(projectDir);
|
|
94724
94758
|
}
|
|
@@ -94801,7 +94835,7 @@ async function curatorStatus(options) {
|
|
|
94801
94835
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94802
94836
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94803
94837
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94804
|
-
const runsDir =
|
|
94838
|
+
const runsDir = join86(outputDir, "runs");
|
|
94805
94839
|
const runIds = listRunIds(runsDir);
|
|
94806
94840
|
let runId;
|
|
94807
94841
|
if (options.run) {
|
|
@@ -94818,8 +94852,8 @@ async function curatorStatus(options) {
|
|
|
94818
94852
|
runId = runIds[runIds.length - 1];
|
|
94819
94853
|
}
|
|
94820
94854
|
console.log(`Run: ${runId}`);
|
|
94821
|
-
const runDir =
|
|
94822
|
-
const observationsPath =
|
|
94855
|
+
const runDir = join86(runsDir, runId);
|
|
94856
|
+
const observationsPath = join86(runDir, "observations.jsonl");
|
|
94823
94857
|
const observations = await parseObservations(observationsPath);
|
|
94824
94858
|
const counts = new Map;
|
|
94825
94859
|
for (const obs of observations) {
|
|
@@ -94829,7 +94863,7 @@ async function curatorStatus(options) {
|
|
|
94829
94863
|
for (const [kind, count] of counts.entries()) {
|
|
94830
94864
|
console.log(` ${kind}: ${count}`);
|
|
94831
94865
|
}
|
|
94832
|
-
const proposalsPath =
|
|
94866
|
+
const proposalsPath = join86(runDir, "curator-proposals.md");
|
|
94833
94867
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94834
94868
|
if (proposalText !== null) {
|
|
94835
94869
|
console.log("");
|
|
@@ -94843,8 +94877,8 @@ async function curatorCommit(options) {
|
|
|
94843
94877
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94844
94878
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94845
94879
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94846
|
-
const runDir =
|
|
94847
|
-
const proposalsPath =
|
|
94880
|
+
const runDir = join86(outputDir, "runs", options.runId);
|
|
94881
|
+
const proposalsPath = join86(runDir, "curator-proposals.md");
|
|
94848
94882
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94849
94883
|
if (proposalText === null) {
|
|
94850
94884
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -94860,7 +94894,7 @@ async function curatorCommit(options) {
|
|
|
94860
94894
|
const dropFileState = new Map;
|
|
94861
94895
|
const skippedDrops = new Set;
|
|
94862
94896
|
for (const drop2 of drops) {
|
|
94863
|
-
const targetPath =
|
|
94897
|
+
const targetPath = join86(resolved.projectDir, drop2.canonicalFile);
|
|
94864
94898
|
if (!dropFileState.has(targetPath)) {
|
|
94865
94899
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
94866
94900
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -94894,7 +94928,7 @@ async function curatorCommit(options) {
|
|
|
94894
94928
|
if (skippedDrops.has(drop2)) {
|
|
94895
94929
|
continue;
|
|
94896
94930
|
}
|
|
94897
|
-
const targetPath =
|
|
94931
|
+
const targetPath = join86(resolved.projectDir, drop2.canonicalFile);
|
|
94898
94932
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
94899
94933
|
const filtered = filterDropContent(existing, drop2.description);
|
|
94900
94934
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -94903,7 +94937,7 @@ async function curatorCommit(options) {
|
|
|
94903
94937
|
}
|
|
94904
94938
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
94905
94939
|
for (const add2 of adds) {
|
|
94906
|
-
const targetPath =
|
|
94940
|
+
const targetPath = join86(resolved.projectDir, add2.canonicalFile);
|
|
94907
94941
|
const content = buildAddContent(add2);
|
|
94908
94942
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
94909
94943
|
modifiedFiles.add(targetPath);
|
|
@@ -94940,7 +94974,7 @@ async function curatorDryrun(options) {
|
|
|
94940
94974
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94941
94975
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94942
94976
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94943
|
-
const runsDir =
|
|
94977
|
+
const runsDir = join86(outputDir, "runs");
|
|
94944
94978
|
const runIds = listRunIds(runsDir);
|
|
94945
94979
|
if (runIds.length === 0) {
|
|
94946
94980
|
console.log("No runs found.");
|
|
@@ -94951,7 +94985,7 @@ async function curatorDryrun(options) {
|
|
|
94951
94985
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
94952
94986
|
return;
|
|
94953
94987
|
}
|
|
94954
|
-
const observationsPath =
|
|
94988
|
+
const observationsPath = join86(runsDir, runId, "observations.jsonl");
|
|
94955
94989
|
const observations = await parseObservations(observationsPath);
|
|
94956
94990
|
const thresholds = getThresholds(config2);
|
|
94957
94991
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -94992,12 +95026,12 @@ async function curatorGc(options) {
|
|
|
94992
95026
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
94993
95027
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94994
95028
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94995
|
-
const perRunsDir =
|
|
95029
|
+
const perRunsDir = join86(outputDir, "runs");
|
|
94996
95030
|
for (const runId of uniqueRunIds) {
|
|
94997
95031
|
if (!keepSet.has(runId)) {
|
|
94998
|
-
const runDir =
|
|
94999
|
-
await _curatorCmdDeps.removeFile(
|
|
95000
|
-
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"));
|
|
95001
95035
|
}
|
|
95002
95036
|
}
|
|
95003
95037
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -95042,7 +95076,7 @@ var init_curator2 = __esm(() => {
|
|
|
95042
95076
|
init_source();
|
|
95043
95077
|
import { existsSync as existsSync35, mkdirSync as mkdirSync7 } from "fs";
|
|
95044
95078
|
import { homedir as homedir3 } from "os";
|
|
95045
|
-
import { basename as basename16, join as
|
|
95079
|
+
import { basename as basename16, join as join87 } from "path";
|
|
95046
95080
|
|
|
95047
95081
|
// node_modules/commander/esm.mjs
|
|
95048
95082
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -95066,12 +95100,12 @@ init_errors();
|
|
|
95066
95100
|
init_operations();
|
|
95067
95101
|
|
|
95068
95102
|
// src/plan/strategies/context-builder.ts
|
|
95069
|
-
import { join as
|
|
95103
|
+
import { join as join38 } from "path";
|
|
95070
95104
|
init_config();
|
|
95071
95105
|
init_errors();
|
|
95072
95106
|
init_interaction();
|
|
95073
95107
|
async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
95074
|
-
const naxDir =
|
|
95108
|
+
const naxDir = join38(workdir, ".nax");
|
|
95075
95109
|
if (!deps.existsSync(naxDir)) {
|
|
95076
95110
|
throw new NaxError(`.nax directory not found. Run 'nax init' first in ${workdir}`, "PLAN_CONTEXT_NO_NAX_DIR", {
|
|
95077
95111
|
stage: "plan",
|
|
@@ -95079,8 +95113,8 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95079
95113
|
});
|
|
95080
95114
|
}
|
|
95081
95115
|
validateFeatureName(options.feature);
|
|
95082
|
-
const outputDir =
|
|
95083
|
-
const outputPath =
|
|
95116
|
+
const outputDir = join38(naxDir, "features", options.feature);
|
|
95117
|
+
const outputPath = join38(outputDir, "prd.json");
|
|
95084
95118
|
const [specContent, sourceRoots, pkg] = await Promise.all([
|
|
95085
95119
|
deps.readFile(options.from),
|
|
95086
95120
|
deps.scanSourceRoots(workdir),
|
|
@@ -95095,7 +95129,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95095
95129
|
...new Set(sourceRoots.map((root) => root.path).filter((path7) => path7 !== ".").map((path7) => path7.startsWith("/") ? path7.replace(`${workdir}/`, "") : path7))
|
|
95096
95130
|
];
|
|
95097
95131
|
const packageDetails = relativePackages.length === 0 ? [] : await Promise.all(relativePackages.map(async (relativePath) => {
|
|
95098
|
-
const packageJson = await deps.readPackageJsonAt(
|
|
95132
|
+
const packageJson = await deps.readPackageJsonAt(join38(workdir, relativePath, "package.json"));
|
|
95099
95133
|
return buildPackageSummary(relativePath, packageJson);
|
|
95100
95134
|
}));
|
|
95101
95135
|
const projectName = detectProjectName(workdir, pkg);
|
|
@@ -95698,7 +95732,7 @@ init_interaction();
|
|
|
95698
95732
|
init_prd();
|
|
95699
95733
|
init_runtime();
|
|
95700
95734
|
import { existsSync as existsSync17, readdirSync as readdirSync3 } from "fs";
|
|
95701
|
-
import { basename as basename7, join as
|
|
95735
|
+
import { basename as basename7, join as join43, resolve as resolve14 } from "path";
|
|
95702
95736
|
var _statusFeaturesDeps = {
|
|
95703
95737
|
projectOutputDir,
|
|
95704
95738
|
loadConfig
|
|
@@ -95712,7 +95746,7 @@ function isPidAlive(pid) {
|
|
|
95712
95746
|
}
|
|
95713
95747
|
}
|
|
95714
95748
|
async function loadStatusFile(featureDir) {
|
|
95715
|
-
const statusPath =
|
|
95749
|
+
const statusPath = join43(featureDir, "status.json");
|
|
95716
95750
|
if (!existsSync17(statusPath)) {
|
|
95717
95751
|
return null;
|
|
95718
95752
|
}
|
|
@@ -95727,7 +95761,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95727
95761
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95728
95762
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95729
95763
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95730
|
-
const statusPath =
|
|
95764
|
+
const statusPath = join43(outputDir, "status.json");
|
|
95731
95765
|
if (!existsSync17(statusPath)) {
|
|
95732
95766
|
return null;
|
|
95733
95767
|
}
|
|
@@ -95739,7 +95773,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95739
95773
|
}
|
|
95740
95774
|
}
|
|
95741
95775
|
async function getFeatureSummary(featureName, featureDir) {
|
|
95742
|
-
const prdPath =
|
|
95776
|
+
const prdPath = join43(featureDir, "prd.json");
|
|
95743
95777
|
if (!existsSync17(prdPath)) {
|
|
95744
95778
|
return {
|
|
95745
95779
|
name: featureName,
|
|
@@ -95782,7 +95816,7 @@ async function getFeatureSummary(featureName, featureDir) {
|
|
|
95782
95816
|
};
|
|
95783
95817
|
}
|
|
95784
95818
|
}
|
|
95785
|
-
const runsDir =
|
|
95819
|
+
const runsDir = join43(featureDir, "runs");
|
|
95786
95820
|
if (existsSync17(runsDir)) {
|
|
95787
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();
|
|
95788
95822
|
if (runs.length > 0) {
|
|
@@ -95796,7 +95830,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95796
95830
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95797
95831
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95798
95832
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95799
|
-
const featuresDir =
|
|
95833
|
+
const featuresDir = join43(outputDir, "features");
|
|
95800
95834
|
if (!existsSync17(featuresDir)) {
|
|
95801
95835
|
console.log(source_default.dim("No features found."));
|
|
95802
95836
|
return;
|
|
@@ -95837,7 +95871,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95837
95871
|
console.log();
|
|
95838
95872
|
}
|
|
95839
95873
|
}
|
|
95840
|
-
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name,
|
|
95874
|
+
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name, join43(featuresDir, name))));
|
|
95841
95875
|
console.log(source_default.bold(`\uD83D\uDCCA Features
|
|
95842
95876
|
`));
|
|
95843
95877
|
const header = ` ${"Feature".padEnd(25)} ${"Done".padEnd(6)} ${"Failed".padEnd(8)} ${"Pending".padEnd(9)} ${"Last Run".padEnd(22)} ${"Cost".padEnd(10)} Status`;
|
|
@@ -95863,7 +95897,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95863
95897
|
console.log();
|
|
95864
95898
|
}
|
|
95865
95899
|
async function displayFeatureDetails(featureName, featureDir) {
|
|
95866
|
-
const prdPath =
|
|
95900
|
+
const prdPath = join43(featureDir, "prd.json");
|
|
95867
95901
|
if (!existsSync17(prdPath)) {
|
|
95868
95902
|
console.log(source_default.bold(`
|
|
95869
95903
|
\uD83D\uDCCA ${featureName}
|
|
@@ -96009,7 +96043,7 @@ async function displayFeatureStatus(options = {}) {
|
|
|
96009
96043
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
96010
96044
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
96011
96045
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
96012
|
-
featureDir =
|
|
96046
|
+
featureDir = join43(outputDir, "features", options.feature);
|
|
96013
96047
|
} else {
|
|
96014
96048
|
const resolved = resolveProject({ feature: options.feature });
|
|
96015
96049
|
if (!resolved.featureDir) {
|
|
@@ -96029,7 +96063,7 @@ init_errors();
|
|
|
96029
96063
|
init_logger2();
|
|
96030
96064
|
init_runtime();
|
|
96031
96065
|
import { existsSync as existsSync18, readdirSync as readdirSync4 } from "fs";
|
|
96032
|
-
import { basename as basename8, join as
|
|
96066
|
+
import { basename as basename8, join as join44 } from "path";
|
|
96033
96067
|
async function resolveOutputDir2(workdir, override) {
|
|
96034
96068
|
if (override)
|
|
96035
96069
|
return override;
|
|
@@ -96053,7 +96087,7 @@ async function runsListCommand(options) {
|
|
|
96053
96087
|
const logger = getLogger();
|
|
96054
96088
|
const { feature, workdir } = options;
|
|
96055
96089
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
96056
|
-
const runsDir =
|
|
96090
|
+
const runsDir = join44(outputDir, "features", feature, "runs");
|
|
96057
96091
|
if (!existsSync18(runsDir)) {
|
|
96058
96092
|
logger.info("cli", "No runs found for feature", { feature, hint: `Directory not found: ${runsDir}` });
|
|
96059
96093
|
return;
|
|
@@ -96065,7 +96099,7 @@ async function runsListCommand(options) {
|
|
|
96065
96099
|
}
|
|
96066
96100
|
logger.info("cli", `Runs for ${feature}`, { count: files.length });
|
|
96067
96101
|
for (const file3 of files.sort().reverse()) {
|
|
96068
|
-
const logPath =
|
|
96102
|
+
const logPath = join44(runsDir, file3);
|
|
96069
96103
|
const entries = await parseRunLog(logPath);
|
|
96070
96104
|
const startEvent = entries.find((e) => e.message === "run.start");
|
|
96071
96105
|
const completeEvent = entries.find((e) => e.message === "run.complete");
|
|
@@ -96092,7 +96126,7 @@ async function runsShowCommand(options) {
|
|
|
96092
96126
|
const logger = getLogger();
|
|
96093
96127
|
const { runId, feature, workdir } = options;
|
|
96094
96128
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
96095
|
-
const logPath =
|
|
96129
|
+
const logPath = join44(outputDir, "features", feature, "runs", `${runId}.jsonl`);
|
|
96096
96130
|
if (!existsSync18(logPath)) {
|
|
96097
96131
|
logger.error("cli", "Run not found", { runId, feature, logPath });
|
|
96098
96132
|
throw new NaxError("Run not found", "RUN_NOT_FOUND", { runId, feature, logPath });
|
|
@@ -97438,19 +97472,19 @@ async function detectCommand(options) {
|
|
|
97438
97472
|
// src/commands/logs.ts
|
|
97439
97473
|
init_common();
|
|
97440
97474
|
import { existsSync as existsSync28 } from "fs";
|
|
97441
|
-
import { join as
|
|
97475
|
+
import { join as join70 } from "path";
|
|
97442
97476
|
|
|
97443
97477
|
// src/commands/logs-formatter.ts
|
|
97444
97478
|
init_source();
|
|
97445
97479
|
init_formatter();
|
|
97446
97480
|
import { readdirSync as readdirSync7 } from "fs";
|
|
97447
|
-
import { join as
|
|
97481
|
+
import { join as join69 } from "path";
|
|
97448
97482
|
|
|
97449
97483
|
// src/commands/logs-reader.ts
|
|
97450
97484
|
init_paths3();
|
|
97451
97485
|
import { existsSync as existsSync27, readdirSync as readdirSync6 } from "fs";
|
|
97452
|
-
import { readdir as
|
|
97453
|
-
import { join as
|
|
97486
|
+
import { readdir as readdir3 } from "fs/promises";
|
|
97487
|
+
import { join as join68 } from "path";
|
|
97454
97488
|
var _logsReaderDeps = {
|
|
97455
97489
|
getRunsDir
|
|
97456
97490
|
};
|
|
@@ -97458,13 +97492,13 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97458
97492
|
const runsDir = _logsReaderDeps.getRunsDir();
|
|
97459
97493
|
let entries;
|
|
97460
97494
|
try {
|
|
97461
|
-
entries = await
|
|
97495
|
+
entries = await readdir3(runsDir);
|
|
97462
97496
|
} catch {
|
|
97463
97497
|
throw new Error(`Run not found in registry: ${runId}`);
|
|
97464
97498
|
}
|
|
97465
97499
|
let matched = null;
|
|
97466
97500
|
for (const entry of entries) {
|
|
97467
|
-
const metaPath =
|
|
97501
|
+
const metaPath = join68(runsDir, entry, "meta.json");
|
|
97468
97502
|
try {
|
|
97469
97503
|
const meta3 = await Bun.file(metaPath).json();
|
|
97470
97504
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -97486,14 +97520,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97486
97520
|
return null;
|
|
97487
97521
|
}
|
|
97488
97522
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
97489
|
-
return
|
|
97523
|
+
return join68(matched.eventsDir, specificFile ?? files[0]);
|
|
97490
97524
|
}
|
|
97491
97525
|
async function selectRunFile(runsDir) {
|
|
97492
97526
|
const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
97493
97527
|
if (files.length === 0) {
|
|
97494
97528
|
return null;
|
|
97495
97529
|
}
|
|
97496
|
-
return
|
|
97530
|
+
return join68(runsDir, files[0]);
|
|
97497
97531
|
}
|
|
97498
97532
|
async function extractRunSummary(filePath) {
|
|
97499
97533
|
const file3 = Bun.file(filePath);
|
|
@@ -97579,7 +97613,7 @@ Runs:
|
|
|
97579
97613
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
97580
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"));
|
|
97581
97615
|
for (const file3 of files) {
|
|
97582
|
-
const filePath =
|
|
97616
|
+
const filePath = join69(runsDir, file3);
|
|
97583
97617
|
const summary = await extractRunSummary(filePath);
|
|
97584
97618
|
const timestamp = file3.replace(".jsonl", "");
|
|
97585
97619
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -97693,7 +97727,7 @@ async function logsCommand(options) {
|
|
|
97693
97727
|
return;
|
|
97694
97728
|
}
|
|
97695
97729
|
const resolved = resolveProject({ dir: options.dir });
|
|
97696
|
-
const naxDir =
|
|
97730
|
+
const naxDir = join70(resolved.projectDir, ".nax");
|
|
97697
97731
|
const configPath = resolved.configPath;
|
|
97698
97732
|
const configFile = Bun.file(configPath);
|
|
97699
97733
|
const config2 = await configFile.json();
|
|
@@ -97701,8 +97735,8 @@ async function logsCommand(options) {
|
|
|
97701
97735
|
if (!featureName) {
|
|
97702
97736
|
throw new Error("No feature specified in config.json");
|
|
97703
97737
|
}
|
|
97704
|
-
const featureDir =
|
|
97705
|
-
const runsDir =
|
|
97738
|
+
const featureDir = join70(naxDir, "features", featureName);
|
|
97739
|
+
const runsDir = join70(featureDir, "runs");
|
|
97706
97740
|
if (!existsSync28(runsDir)) {
|
|
97707
97741
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
97708
97742
|
}
|
|
@@ -97728,7 +97762,7 @@ init_prd();
|
|
|
97728
97762
|
init_precheck();
|
|
97729
97763
|
init_common();
|
|
97730
97764
|
import { existsSync as existsSync29 } from "fs";
|
|
97731
|
-
import { join as
|
|
97765
|
+
import { join as join71 } from "path";
|
|
97732
97766
|
async function precheckCommand(options) {
|
|
97733
97767
|
const resolved = resolveProject({
|
|
97734
97768
|
dir: options.dir,
|
|
@@ -97750,9 +97784,9 @@ async function precheckCommand(options) {
|
|
|
97750
97784
|
process.exit(1);
|
|
97751
97785
|
}
|
|
97752
97786
|
}
|
|
97753
|
-
const naxDir =
|
|
97754
|
-
const featureDir =
|
|
97755
|
-
const prdPath =
|
|
97787
|
+
const naxDir = join71(resolved.projectDir, ".nax");
|
|
97788
|
+
const featureDir = join71(naxDir, "features", featureName);
|
|
97789
|
+
const prdPath = join71(featureDir, "prd.json");
|
|
97756
97790
|
if (!existsSync29(featureDir)) {
|
|
97757
97791
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
97758
97792
|
process.exit(1);
|
|
@@ -97774,8 +97808,8 @@ async function precheckCommand(options) {
|
|
|
97774
97808
|
// src/commands/runs.ts
|
|
97775
97809
|
init_source();
|
|
97776
97810
|
init_paths3();
|
|
97777
|
-
import { readdir as
|
|
97778
|
-
import { join as
|
|
97811
|
+
import { readdir as readdir4 } from "fs/promises";
|
|
97812
|
+
import { join as join72 } from "path";
|
|
97779
97813
|
var DEFAULT_LIMIT = 20;
|
|
97780
97814
|
var _runsCmdDeps = {
|
|
97781
97815
|
getRunsDir
|
|
@@ -97823,14 +97857,14 @@ async function runsCommand(options = {}) {
|
|
|
97823
97857
|
const runsDir = _runsCmdDeps.getRunsDir();
|
|
97824
97858
|
let entries;
|
|
97825
97859
|
try {
|
|
97826
|
-
entries = await
|
|
97860
|
+
entries = await readdir4(runsDir);
|
|
97827
97861
|
} catch {
|
|
97828
97862
|
console.log("No runs found.");
|
|
97829
97863
|
return;
|
|
97830
97864
|
}
|
|
97831
97865
|
const rows = [];
|
|
97832
97866
|
for (const entry of entries) {
|
|
97833
|
-
const metaPath =
|
|
97867
|
+
const metaPath = join72(runsDir, entry, "meta.json");
|
|
97834
97868
|
let meta3;
|
|
97835
97869
|
try {
|
|
97836
97870
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -97907,7 +97941,7 @@ async function runsCommand(options = {}) {
|
|
|
97907
97941
|
|
|
97908
97942
|
// src/commands/unlock.ts
|
|
97909
97943
|
init_source();
|
|
97910
|
-
import { join as
|
|
97944
|
+
import { join as join73 } from "path";
|
|
97911
97945
|
function isProcessAlive2(pid) {
|
|
97912
97946
|
try {
|
|
97913
97947
|
process.kill(pid, 0);
|
|
@@ -97922,7 +97956,7 @@ function formatLockAge(ageMs) {
|
|
|
97922
97956
|
}
|
|
97923
97957
|
async function unlockCommand(options) {
|
|
97924
97958
|
const workdir = options.dir ?? process.cwd();
|
|
97925
|
-
const lockPath =
|
|
97959
|
+
const lockPath = join73(workdir, "nax.lock");
|
|
97926
97960
|
const lockFile = Bun.file(lockPath);
|
|
97927
97961
|
const exists = await lockFile.exists();
|
|
97928
97962
|
if (!exists) {
|
|
@@ -106347,7 +106381,7 @@ Next: nax generate --package ${options.package}`));
|
|
|
106347
106381
|
}
|
|
106348
106382
|
return;
|
|
106349
106383
|
}
|
|
106350
|
-
const naxDir =
|
|
106384
|
+
const naxDir = join87(workdir, ".nax");
|
|
106351
106385
|
if (existsSync35(naxDir) && !options.force) {
|
|
106352
106386
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
106353
106387
|
return;
|
|
@@ -106376,11 +106410,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
106376
106410
|
}
|
|
106377
106411
|
}
|
|
106378
106412
|
}
|
|
106379
|
-
mkdirSync7(
|
|
106380
|
-
mkdirSync7(
|
|
106413
|
+
mkdirSync7(join87(naxDir, "features"), { recursive: true });
|
|
106414
|
+
mkdirSync7(join87(naxDir, "hooks"), { recursive: true });
|
|
106381
106415
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
106382
|
-
await Bun.write(
|
|
106383
|
-
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({
|
|
106384
106418
|
hooks: {
|
|
106385
106419
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
106386
106420
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -106388,12 +106422,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
106388
106422
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
106389
106423
|
}
|
|
106390
106424
|
}, null, 2));
|
|
106391
|
-
await Bun.write(
|
|
106425
|
+
await Bun.write(join87(naxDir, ".gitignore"), `# nax temp files
|
|
106392
106426
|
*.tmp
|
|
106393
106427
|
.paused.json
|
|
106394
106428
|
.nax-verifier-verdict.json
|
|
106395
106429
|
`);
|
|
106396
|
-
await Bun.write(
|
|
106430
|
+
await Bun.write(join87(naxDir, "context.md"), `# Project Context
|
|
106397
106431
|
|
|
106398
106432
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
106399
106433
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -106541,8 +106575,8 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106541
106575
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106542
106576
|
process.exit(1);
|
|
106543
106577
|
}
|
|
106544
|
-
const featureDir =
|
|
106545
|
-
const prdPath =
|
|
106578
|
+
const featureDir = join87(naxDir, "features", options.feature);
|
|
106579
|
+
const prdPath = join87(featureDir, "prd.json");
|
|
106546
106580
|
if (options.plan && options.from) {
|
|
106547
106581
|
if (existsSync35(prdPath) && !options.force) {
|
|
106548
106582
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
@@ -106564,10 +106598,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106564
106598
|
}
|
|
106565
106599
|
}
|
|
106566
106600
|
try {
|
|
106567
|
-
const planLogDir =
|
|
106601
|
+
const planLogDir = join87(featureDir, "plan");
|
|
106568
106602
|
mkdirSync7(planLogDir, { recursive: true });
|
|
106569
106603
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106570
|
-
const planLogPath =
|
|
106604
|
+
const planLogPath = join87(planLogDir, `${planLogId}.jsonl`);
|
|
106571
106605
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106572
106606
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106573
106607
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -106613,10 +106647,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106613
106647
|
resetLogger();
|
|
106614
106648
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
106615
106649
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
106616
|
-
const runsDir =
|
|
106650
|
+
const runsDir = join87(outputDir, "features", options.feature, "runs");
|
|
106617
106651
|
mkdirSync7(runsDir, { recursive: true });
|
|
106618
106652
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106619
|
-
const logFilePath =
|
|
106653
|
+
const logFilePath = join87(runsDir, `${runId}.jsonl`);
|
|
106620
106654
|
const isTTY = process.stdout.isTTY ?? false;
|
|
106621
106655
|
const headlessFlag = options.headless ?? false;
|
|
106622
106656
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -106634,7 +106668,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106634
106668
|
config2.agent.default = options.agent;
|
|
106635
106669
|
}
|
|
106636
106670
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
106637
|
-
const globalNaxDir =
|
|
106671
|
+
const globalNaxDir = join87(homedir3(), ".nax");
|
|
106638
106672
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
106639
106673
|
const eventEmitter = new PipelineEventEmitter;
|
|
106640
106674
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -106654,12 +106688,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106654
106688
|
events: eventEmitter,
|
|
106655
106689
|
ptyOptions: null,
|
|
106656
106690
|
agentStreamEvents,
|
|
106657
|
-
queueFilePath:
|
|
106691
|
+
queueFilePath: join87(workdir, ".queue.txt")
|
|
106658
106692
|
});
|
|
106659
106693
|
} else {
|
|
106660
106694
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
106661
106695
|
}
|
|
106662
|
-
const statusFilePath =
|
|
106696
|
+
const statusFilePath = join87(outputDir, "status.json");
|
|
106663
106697
|
let parallel;
|
|
106664
106698
|
if (options.parallel !== undefined) {
|
|
106665
106699
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -106686,7 +106720,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106686
106720
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
106687
106721
|
agentStreamEvents
|
|
106688
106722
|
});
|
|
106689
|
-
const latestSymlink =
|
|
106723
|
+
const latestSymlink = join87(runsDir, "latest.jsonl");
|
|
106690
106724
|
try {
|
|
106691
106725
|
if (existsSync35(latestSymlink)) {
|
|
106692
106726
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
@@ -106747,9 +106781,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106747
106781
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106748
106782
|
process.exit(1);
|
|
106749
106783
|
}
|
|
106750
|
-
const featureDir =
|
|
106784
|
+
const featureDir = join87(naxDir, "features", name);
|
|
106751
106785
|
mkdirSync7(featureDir, { recursive: true });
|
|
106752
|
-
await Bun.write(
|
|
106786
|
+
await Bun.write(join87(featureDir, "spec.md"), `# Feature: ${name}
|
|
106753
106787
|
|
|
106754
106788
|
## Overview
|
|
106755
106789
|
|
|
@@ -106782,7 +106816,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106782
106816
|
|
|
106783
106817
|
<!-- What this feature explicitly does NOT cover. -->
|
|
106784
106818
|
`);
|
|
106785
|
-
await Bun.write(
|
|
106819
|
+
await Bun.write(join87(featureDir, "progress.txt"), `# Progress: ${name}
|
|
106786
106820
|
|
|
106787
106821
|
Created: ${new Date().toISOString()}
|
|
106788
106822
|
|
|
@@ -106808,7 +106842,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106808
106842
|
console.error(source_default.red("nax not initialized."));
|
|
106809
106843
|
process.exit(1);
|
|
106810
106844
|
}
|
|
106811
|
-
const featuresDir =
|
|
106845
|
+
const featuresDir = join87(naxDir, "features");
|
|
106812
106846
|
if (!existsSync35(featuresDir)) {
|
|
106813
106847
|
console.log(source_default.dim("No features yet."));
|
|
106814
106848
|
return;
|
|
@@ -106823,7 +106857,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106823
106857
|
Features:
|
|
106824
106858
|
`));
|
|
106825
106859
|
for (const name of entries) {
|
|
106826
|
-
const prdPath =
|
|
106860
|
+
const prdPath = join87(featuresDir, name, "prd.json");
|
|
106827
106861
|
if (existsSync35(prdPath)) {
|
|
106828
106862
|
const prd = await loadPRD(prdPath);
|
|
106829
106863
|
const c = countStories(prd);
|
|
@@ -106858,10 +106892,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
106858
106892
|
cliOverrides.profile = options.profile;
|
|
106859
106893
|
}
|
|
106860
106894
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
106861
|
-
const featureLogDir =
|
|
106895
|
+
const featureLogDir = join87(naxDir, "features", options.feature, "plan");
|
|
106862
106896
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
106863
106897
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106864
|
-
const planLogPath =
|
|
106898
|
+
const planLogPath = join87(featureLogDir, `${planLogId}.jsonl`);
|
|
106865
106899
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106866
106900
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106867
106901
|
try {
|