@nathapp/nax 0.69.7 → 0.69.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/dist/nax.js +327 -286
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -35598,7 +35598,7 @@ function resolveAcceptanceTestCandidates(options) {
|
|
|
35598
35598
|
return [];
|
|
35599
35599
|
return [resolveAcceptanceFeatureTestPath(options.featureDir, options.testPathConfig, options.language)];
|
|
35600
35600
|
}
|
|
35601
|
-
function groupStoriesByPackage(prd, workdir, featureName, testPathConfig, language) {
|
|
35601
|
+
async function groupStoriesByPackage(prd, workdir, featureName, testPathConfig, language) {
|
|
35602
35602
|
const nonFixStories = prd.userStories.filter((s) => !s.id.startsWith("US-FIX-") && s.status !== "decomposed");
|
|
35603
35603
|
const groupMap = new Map;
|
|
35604
35604
|
for (const story of nonFixStories) {
|
|
@@ -35615,13 +35615,13 @@ function groupStoriesByPackage(prd, workdir, featureName, testPathConfig, langua
|
|
|
35615
35615
|
if (groupMap.size === 0) {
|
|
35616
35616
|
groupMap.set("", { stories: [], criteria: [] });
|
|
35617
35617
|
}
|
|
35618
|
-
|
|
35619
|
-
for (const [wd, { stories, criteria }] of groupMap) {
|
|
35618
|
+
return Promise.all(Array.from(groupMap.entries()).map(async ([wd, { stories, criteria }]) => {
|
|
35620
35619
|
const packageDir = wd ? path3.join(workdir, wd) : workdir;
|
|
35621
|
-
const
|
|
35622
|
-
|
|
35623
|
-
|
|
35624
|
-
|
|
35620
|
+
const detectedLang = await _groupDeps.detectLanguage(packageDir);
|
|
35621
|
+
const resolvedLang = detectedLang ?? language;
|
|
35622
|
+
const testPath = resolveAcceptancePackageFeatureTestPath(packageDir, featureName, testPathConfig, resolvedLang);
|
|
35623
|
+
return { testPath, packageDir, stories, criteria };
|
|
35624
|
+
}));
|
|
35625
35625
|
}
|
|
35626
35626
|
function suggestedTestFilename(language) {
|
|
35627
35627
|
switch (language?.toLowerCase()) {
|
|
@@ -35664,7 +35664,13 @@ async function findExistingAcceptanceTestPath(options) {
|
|
|
35664
35664
|
}
|
|
35665
35665
|
return;
|
|
35666
35666
|
}
|
|
35667
|
-
var
|
|
35667
|
+
var _groupDeps;
|
|
35668
|
+
var init_test_path = __esm(() => {
|
|
35669
|
+
init_detector();
|
|
35670
|
+
_groupDeps = {
|
|
35671
|
+
detectLanguage
|
|
35672
|
+
};
|
|
35673
|
+
});
|
|
35668
35674
|
|
|
35669
35675
|
// src/acceptance/generator-helpers.ts
|
|
35670
35676
|
function skeletonImportLine(testFramework) {
|
|
@@ -37430,7 +37436,7 @@ var init_write_test = __esm(() => {
|
|
|
37430
37436
|
if (!input.beforeRef)
|
|
37431
37437
|
return parsed;
|
|
37432
37438
|
const allowedPaths = ctx.config.tdd?.testWriterAllowedPaths ?? ["src/index.ts", "src/**/index.ts"];
|
|
37433
|
-
const testFilePatterns =
|
|
37439
|
+
const testFilePatterns = input.resolvedTestPatterns?.globs;
|
|
37434
37440
|
const isolation = await verifyTestWriterIsolation(ctx.packageView.packageDir, input.beforeRef, allowedPaths, testFilePatterns, input.lite ? "lite" : "strict");
|
|
37435
37441
|
return { ...parsed, isolation };
|
|
37436
37442
|
}
|
|
@@ -38414,57 +38420,69 @@ var init_plan_critic_llm = __esm(() => {
|
|
|
38414
38420
|
});
|
|
38415
38421
|
|
|
38416
38422
|
// 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"]);
|
|
38423
|
+
async function gitLsFiles2(workdir) {
|
|
38422
38424
|
try {
|
|
38423
|
-
const
|
|
38424
|
-
|
|
38425
|
-
|
|
38426
|
-
|
|
38427
|
-
|
|
38428
|
-
|
|
38429
|
-
|
|
38430
|
-
|
|
38431
|
-
|
|
38432
|
-
|
|
38433
|
-
|
|
38434
|
-
|
|
38425
|
+
const proc = _greenfieldDeps.spawn(["git", "ls-files"], {
|
|
38426
|
+
cwd: workdir,
|
|
38427
|
+
stdout: "pipe",
|
|
38428
|
+
stderr: "pipe"
|
|
38429
|
+
});
|
|
38430
|
+
const exitCode = await proc.exited;
|
|
38431
|
+
if (exitCode !== 0)
|
|
38432
|
+
return null;
|
|
38433
|
+
const output = await new Response(proc.stdout).text();
|
|
38434
|
+
return output.split(`
|
|
38435
|
+
`).filter(Boolean);
|
|
38436
|
+
} catch {
|
|
38437
|
+
return null;
|
|
38438
|
+
}
|
|
38439
|
+
}
|
|
38440
|
+
async function hasTestFiles(workdir, patterns) {
|
|
38441
|
+
const files = await gitLsFiles2(workdir);
|
|
38442
|
+
if (files !== null) {
|
|
38443
|
+
return files.some((f) => isTestFileByPatterns(f, patterns));
|
|
38444
|
+
}
|
|
38445
|
+
for (const pattern of patterns) {
|
|
38446
|
+
const g = new Bun.Glob(pattern);
|
|
38447
|
+
for await (const path5 of g.scan({ cwd: workdir, onlyFiles: true })) {
|
|
38448
|
+
if (!path5.split("/").some((seg) => IGNORE_DIRS.has(seg))) {
|
|
38449
|
+
return true;
|
|
38435
38450
|
}
|
|
38436
38451
|
}
|
|
38437
|
-
} catch (error48) {
|
|
38438
|
-
if (isRootCall) {
|
|
38439
|
-
throw error48;
|
|
38440
|
-
}
|
|
38441
38452
|
}
|
|
38442
|
-
return
|
|
38453
|
+
return false;
|
|
38443
38454
|
}
|
|
38444
38455
|
async function isGreenfieldStory(_story, workdir, patterns) {
|
|
38445
38456
|
try {
|
|
38446
|
-
|
|
38447
|
-
|
|
38448
|
-
return testFiles.length === 0;
|
|
38449
|
-
} catch (error48) {
|
|
38457
|
+
return !await hasTestFiles(workdir, patterns ?? DEFAULT_TEST_FILE_PATTERNS);
|
|
38458
|
+
} catch {
|
|
38450
38459
|
return false;
|
|
38451
38460
|
}
|
|
38452
38461
|
}
|
|
38453
|
-
var
|
|
38462
|
+
var _greenfieldDeps, IGNORE_DIRS;
|
|
38454
38463
|
var init_greenfield = __esm(() => {
|
|
38455
|
-
|
|
38456
|
-
|
|
38457
|
-
|
|
38458
|
-
|
|
38459
|
-
|
|
38460
|
-
"
|
|
38461
|
-
"
|
|
38462
|
-
"
|
|
38463
|
-
"
|
|
38464
|
-
"
|
|
38465
|
-
"
|
|
38466
|
-
"
|
|
38467
|
-
"
|
|
38464
|
+
init_test_runners();
|
|
38465
|
+
_greenfieldDeps = {
|
|
38466
|
+
spawn: Bun.spawn
|
|
38467
|
+
};
|
|
38468
|
+
IGNORE_DIRS = new Set([
|
|
38469
|
+
"node_modules",
|
|
38470
|
+
"dist",
|
|
38471
|
+
".next",
|
|
38472
|
+
".nuxt",
|
|
38473
|
+
".cache",
|
|
38474
|
+
"coverage",
|
|
38475
|
+
"vendor",
|
|
38476
|
+
"__pycache__",
|
|
38477
|
+
".venv",
|
|
38478
|
+
"venv",
|
|
38479
|
+
".eggs",
|
|
38480
|
+
"target",
|
|
38481
|
+
".gradle",
|
|
38482
|
+
"out",
|
|
38483
|
+
"tmp",
|
|
38484
|
+
"temp",
|
|
38485
|
+
".git"
|
|
38468
38486
|
]);
|
|
38469
38487
|
});
|
|
38470
38488
|
|
|
@@ -38627,13 +38645,13 @@ __export(exports_runners, {
|
|
|
38627
38645
|
_regressionRunnerDeps: () => _regressionRunnerDeps
|
|
38628
38646
|
});
|
|
38629
38647
|
import { existsSync as existsSync6 } from "fs";
|
|
38630
|
-
import { join as
|
|
38648
|
+
import { join as join23 } from "path";
|
|
38631
38649
|
async function verifyAssets(workingDirectory, expectedFiles) {
|
|
38632
38650
|
if (!expectedFiles || expectedFiles.length === 0)
|
|
38633
38651
|
return { success: true, missingFiles: [] };
|
|
38634
38652
|
const missingFiles = [];
|
|
38635
38653
|
for (const file3 of expectedFiles) {
|
|
38636
|
-
if (!existsSync6(
|
|
38654
|
+
if (!existsSync6(join23(workingDirectory, file3)))
|
|
38637
38655
|
missingFiles.push(file3);
|
|
38638
38656
|
}
|
|
38639
38657
|
if (missingFiles.length > 0) {
|
|
@@ -39080,7 +39098,7 @@ var init_apply_test_edit_declarations = __esm(() => {
|
|
|
39080
39098
|
});
|
|
39081
39099
|
|
|
39082
39100
|
// src/operations/validate-mock-structure-files.ts
|
|
39083
|
-
import { join as
|
|
39101
|
+
import { join as join24 } from "path";
|
|
39084
39102
|
async function validateMockStructureFiles(declarations, resolvedTestPatterns, packageDir, deps) {
|
|
39085
39103
|
const fileExists = deps?.fileExists ?? defaultFileExists;
|
|
39086
39104
|
const valid = [];
|
|
@@ -39093,7 +39111,7 @@ async function validateMockStructureFiles(declarations, resolvedTestPatterns, pa
|
|
|
39093
39111
|
const files = d.files ?? [d.file];
|
|
39094
39112
|
let allValid = true;
|
|
39095
39113
|
for (const file3 of files) {
|
|
39096
|
-
const absolutePath =
|
|
39114
|
+
const absolutePath = join24(packageDir, file3);
|
|
39097
39115
|
const exists = await fileExists(absolutePath);
|
|
39098
39116
|
if (!exists) {
|
|
39099
39117
|
allValid = false;
|
|
@@ -40693,7 +40711,7 @@ var init_lint_parsing = __esm(() => {
|
|
|
40693
40711
|
});
|
|
40694
40712
|
|
|
40695
40713
|
// src/review/scoped-lint.ts
|
|
40696
|
-
import { join as
|
|
40714
|
+
import { join as join25, relative as relative10 } from "path";
|
|
40697
40715
|
function shellQuotePath4(path5) {
|
|
40698
40716
|
return `'${path5.replaceAll("'", "'\\''")}'`;
|
|
40699
40717
|
}
|
|
@@ -40741,7 +40759,7 @@ function uniqueFiles(files) {
|
|
|
40741
40759
|
async function filterFilesToScope(files, workdir, projectDir, activePackageDir) {
|
|
40742
40760
|
const inScope = [];
|
|
40743
40761
|
for (const relPath of files) {
|
|
40744
|
-
const absPath =
|
|
40762
|
+
const absPath = join25(workdir, relPath);
|
|
40745
40763
|
const exists = await _scopedLintDeps.fileExists(absPath);
|
|
40746
40764
|
if (!exists)
|
|
40747
40765
|
continue;
|
|
@@ -44115,7 +44133,7 @@ var init_call = __esm(() => {
|
|
|
44115
44133
|
|
|
44116
44134
|
// src/runtime/cost-aggregator.ts
|
|
44117
44135
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
44118
|
-
import { join as
|
|
44136
|
+
import { join as join26 } from "path";
|
|
44119
44137
|
function makeCorrelationId() {
|
|
44120
44138
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
44121
44139
|
}
|
|
@@ -44306,7 +44324,7 @@ class CostAggregator {
|
|
|
44306
44324
|
if (events.length === 0 && errors3.length === 0)
|
|
44307
44325
|
return;
|
|
44308
44326
|
mkdirSync2(this._drainDir, { recursive: true });
|
|
44309
|
-
const path5 =
|
|
44327
|
+
const path5 = join26(this._drainDir, `${this._runId}.jsonl`);
|
|
44310
44328
|
const sorted = [...events, ...errors3].sort((a, b) => a.ts - b.ts);
|
|
44311
44329
|
await _costAggDeps.write(path5, `${sorted.map((e) => JSON.stringify(e)).join(`
|
|
44312
44330
|
`)}
|
|
@@ -44346,7 +44364,7 @@ var init_cost_aggregator = __esm(() => {
|
|
|
44346
44364
|
// src/runtime/prompt-auditor.ts
|
|
44347
44365
|
import { appendFileSync } from "fs";
|
|
44348
44366
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
44349
|
-
import { join as
|
|
44367
|
+
import { join as join27 } from "path";
|
|
44350
44368
|
function createNoOpPromptAuditor() {
|
|
44351
44369
|
return {
|
|
44352
44370
|
record() {},
|
|
@@ -44412,8 +44430,8 @@ class PromptAuditor {
|
|
|
44412
44430
|
_jsonlPath;
|
|
44413
44431
|
_featureDir;
|
|
44414
44432
|
constructor(runId, flushDir, featureName) {
|
|
44415
|
-
this._featureDir =
|
|
44416
|
-
this._jsonlPath =
|
|
44433
|
+
this._featureDir = join27(flushDir, featureName);
|
|
44434
|
+
this._jsonlPath = join27(this._featureDir, `${runId}.jsonl`);
|
|
44417
44435
|
}
|
|
44418
44436
|
record(entry) {
|
|
44419
44437
|
this._enqueue(entry);
|
|
@@ -44462,7 +44480,7 @@ class PromptAuditor {
|
|
|
44462
44480
|
const auditEntry = entry;
|
|
44463
44481
|
const filename = deriveTxtFilename(auditEntry);
|
|
44464
44482
|
try {
|
|
44465
|
-
await _promptAuditorDeps.write(
|
|
44483
|
+
await _promptAuditorDeps.write(join27(this._featureDir, filename), buildTxtContent(auditEntry));
|
|
44466
44484
|
} catch (err) {
|
|
44467
44485
|
throw tagAuditError(err, "txt");
|
|
44468
44486
|
}
|
|
@@ -44600,6 +44618,7 @@ function createPackageView(config2, packageDir, repoRoot, hasOverride) {
|
|
|
44600
44618
|
function createPackageRegistry(loader, repoRoot) {
|
|
44601
44619
|
const cache = new Map;
|
|
44602
44620
|
const mergedConfigs = new Map;
|
|
44621
|
+
let hydrated = false;
|
|
44603
44622
|
function toRelativeKey(packageDir) {
|
|
44604
44623
|
if (!packageDir)
|
|
44605
44624
|
return "";
|
|
@@ -44618,6 +44637,9 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44618
44637
|
}
|
|
44619
44638
|
const overrideConfig = mergedConfigs.get(key);
|
|
44620
44639
|
const hasOverride = overrideConfig !== undefined;
|
|
44640
|
+
if (!hasOverride && key && !hydrated) {
|
|
44641
|
+
_packagesDeps.getSafeLogger()?.warn("packages", "resolve() called for non-root package before hydrate(); returning root config (per-package overrides not applied)", { packageDir: key });
|
|
44642
|
+
}
|
|
44621
44643
|
const config2 = overrideConfig ?? loader.current();
|
|
44622
44644
|
const view = createPackageView(config2, key, repoRoot, hasOverride);
|
|
44623
44645
|
cache.set(key, view);
|
|
@@ -44638,6 +44660,7 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44638
44660
|
cache.delete(dir);
|
|
44639
44661
|
}
|
|
44640
44662
|
}
|
|
44663
|
+
hydrated = true;
|
|
44641
44664
|
}
|
|
44642
44665
|
return {
|
|
44643
44666
|
all() {
|
|
@@ -44650,8 +44673,11 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44650
44673
|
hydrate
|
|
44651
44674
|
};
|
|
44652
44675
|
}
|
|
44676
|
+
var _packagesDeps;
|
|
44653
44677
|
var init_packages = __esm(() => {
|
|
44654
44678
|
init_config();
|
|
44679
|
+
init_logger2();
|
|
44680
|
+
_packagesDeps = { getSafeLogger };
|
|
44655
44681
|
});
|
|
44656
44682
|
|
|
44657
44683
|
// src/runtime/agent-stream-events.ts
|
|
@@ -45610,7 +45636,7 @@ var init_pid_registry = __esm(() => {
|
|
|
45610
45636
|
// src/session/manager-deps.ts
|
|
45611
45637
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
45612
45638
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
45613
|
-
import { isAbsolute as isAbsolute9, join as
|
|
45639
|
+
import { isAbsolute as isAbsolute9, join as join28, relative as relative11, sep as sep2 } from "path";
|
|
45614
45640
|
function resolveProjectDirFromScratchDir(scratchDir) {
|
|
45615
45641
|
const marker = `${sep2}.nax${sep2}features${sep2}`;
|
|
45616
45642
|
const markerIdx = scratchDir.lastIndexOf(marker);
|
|
@@ -45631,7 +45657,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45631
45657
|
now: () => new Date().toISOString(),
|
|
45632
45658
|
nowMs: () => Date.now(),
|
|
45633
45659
|
uuid: () => randomUUID3(),
|
|
45634
|
-
sessionScratchDir: (projectDir, featureName, sessionId) =>
|
|
45660
|
+
sessionScratchDir: (projectDir, featureName, sessionId) => join28(projectDir, ".nax", "features", featureName, "sessions", sessionId),
|
|
45635
45661
|
writeDescriptor: async (scratchDir, descriptor, projectDir) => {
|
|
45636
45662
|
await mkdir5(scratchDir, { recursive: true });
|
|
45637
45663
|
const { handle: _handle, ...persistable } = descriptor;
|
|
@@ -45642,7 +45668,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45642
45668
|
persistable.scratchDir = toProjectRelativePath(derivedProjectDir, persistable.scratchDir);
|
|
45643
45669
|
}
|
|
45644
45670
|
}
|
|
45645
|
-
await Bun.write(
|
|
45671
|
+
await Bun.write(join28(scratchDir, "descriptor.json"), JSON.stringify(persistable, null, 2));
|
|
45646
45672
|
}
|
|
45647
45673
|
};
|
|
45648
45674
|
});
|
|
@@ -46393,7 +46419,7 @@ __export(exports_runtime, {
|
|
|
46393
46419
|
CostAggregator: () => CostAggregator,
|
|
46394
46420
|
AgentStreamEventBus: () => AgentStreamEventBus
|
|
46395
46421
|
});
|
|
46396
|
-
import { basename as basename5, join as
|
|
46422
|
+
import { basename as basename5, join as join29 } from "path";
|
|
46397
46423
|
function createRuntime(config2, workdir, opts) {
|
|
46398
46424
|
const runId = crypto.randomUUID();
|
|
46399
46425
|
const controller = new AbortController;
|
|
@@ -46409,10 +46435,10 @@ function createRuntime(config2, workdir, opts) {
|
|
|
46409
46435
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
46410
46436
|
const globalDir = globalOutputDir();
|
|
46411
46437
|
const curatorRollupPathValue = curatorRollupPath(globalDir, config2.curator?.rollupPath);
|
|
46412
|
-
const costDir =
|
|
46438
|
+
const costDir = join29(outputDir, "cost");
|
|
46413
46439
|
const costAggregator = opts?.costAggregator ?? new CostAggregator(runId, costDir);
|
|
46414
46440
|
const auditEnabled = config2.agent?.promptAudit?.enabled ?? false;
|
|
46415
|
-
const auditDir = config2.agent?.promptAudit?.dir ??
|
|
46441
|
+
const auditDir = config2.agent?.promptAudit?.dir ?? join29(outputDir, "prompt-audit");
|
|
46416
46442
|
let promptAuditor;
|
|
46417
46443
|
if (opts?.promptAuditor) {
|
|
46418
46444
|
promptAuditor = opts.promptAuditor;
|
|
@@ -46565,9 +46591,9 @@ async function allSettledBounded(tasks, limit) {
|
|
|
46565
46591
|
|
|
46566
46592
|
// src/context/injector.ts
|
|
46567
46593
|
import { existsSync as existsSync8 } from "fs";
|
|
46568
|
-
import { join as
|
|
46594
|
+
import { join as join30 } from "path";
|
|
46569
46595
|
async function detectNode(workdir) {
|
|
46570
|
-
const pkgPath =
|
|
46596
|
+
const pkgPath = join30(workdir, "package.json");
|
|
46571
46597
|
if (!existsSync8(pkgPath))
|
|
46572
46598
|
return null;
|
|
46573
46599
|
try {
|
|
@@ -46584,7 +46610,7 @@ async function detectNode(workdir) {
|
|
|
46584
46610
|
}
|
|
46585
46611
|
}
|
|
46586
46612
|
async function detectGo(workdir) {
|
|
46587
|
-
const goMod =
|
|
46613
|
+
const goMod = join30(workdir, "go.mod");
|
|
46588
46614
|
if (!existsSync8(goMod))
|
|
46589
46615
|
return null;
|
|
46590
46616
|
try {
|
|
@@ -46608,7 +46634,7 @@ async function detectGo(workdir) {
|
|
|
46608
46634
|
}
|
|
46609
46635
|
}
|
|
46610
46636
|
async function detectRust(workdir) {
|
|
46611
|
-
const cargoPath =
|
|
46637
|
+
const cargoPath = join30(workdir, "Cargo.toml");
|
|
46612
46638
|
if (!existsSync8(cargoPath))
|
|
46613
46639
|
return null;
|
|
46614
46640
|
try {
|
|
@@ -46624,8 +46650,8 @@ async function detectRust(workdir) {
|
|
|
46624
46650
|
}
|
|
46625
46651
|
}
|
|
46626
46652
|
async function detectPython(workdir) {
|
|
46627
|
-
const pyproject =
|
|
46628
|
-
const requirements =
|
|
46653
|
+
const pyproject = join30(workdir, "pyproject.toml");
|
|
46654
|
+
const requirements = join30(workdir, "requirements.txt");
|
|
46629
46655
|
if (!existsSync8(pyproject) && !existsSync8(requirements))
|
|
46630
46656
|
return null;
|
|
46631
46657
|
try {
|
|
@@ -46644,7 +46670,7 @@ async function detectPython(workdir) {
|
|
|
46644
46670
|
}
|
|
46645
46671
|
}
|
|
46646
46672
|
async function detectPhp(workdir) {
|
|
46647
|
-
const composerPath =
|
|
46673
|
+
const composerPath = join30(workdir, "composer.json");
|
|
46648
46674
|
if (!existsSync8(composerPath))
|
|
46649
46675
|
return null;
|
|
46650
46676
|
try {
|
|
@@ -46657,7 +46683,7 @@ async function detectPhp(workdir) {
|
|
|
46657
46683
|
}
|
|
46658
46684
|
}
|
|
46659
46685
|
async function detectRuby(workdir) {
|
|
46660
|
-
const gemfile =
|
|
46686
|
+
const gemfile = join30(workdir, "Gemfile");
|
|
46661
46687
|
if (!existsSync8(gemfile))
|
|
46662
46688
|
return null;
|
|
46663
46689
|
try {
|
|
@@ -46669,9 +46695,9 @@ async function detectRuby(workdir) {
|
|
|
46669
46695
|
}
|
|
46670
46696
|
}
|
|
46671
46697
|
async function detectJvm(workdir) {
|
|
46672
|
-
const pom =
|
|
46673
|
-
const gradle =
|
|
46674
|
-
const gradleKts =
|
|
46698
|
+
const pom = join30(workdir, "pom.xml");
|
|
46699
|
+
const gradle = join30(workdir, "build.gradle");
|
|
46700
|
+
const gradleKts = join30(workdir, "build.gradle.kts");
|
|
46675
46701
|
if (!existsSync8(pom) && !existsSync8(gradle) && !existsSync8(gradleKts))
|
|
46676
46702
|
return null;
|
|
46677
46703
|
try {
|
|
@@ -46679,7 +46705,7 @@ async function detectJvm(workdir) {
|
|
|
46679
46705
|
const content2 = await Bun.file(pom).text();
|
|
46680
46706
|
const nameMatch = content2.match(/<artifactId>([^<]+)<\/artifactId>/);
|
|
46681
46707
|
const deps2 = [...content2.matchAll(/<artifactId>([^<]+)<\/artifactId>/g)].map((m) => m[1]).filter((d) => d !== nameMatch?.[1]).slice(0, 10);
|
|
46682
|
-
const lang2 = existsSync8(
|
|
46708
|
+
const lang2 = existsSync8(join30(workdir, "src/main/kotlin")) ? "Kotlin" : "Java";
|
|
46683
46709
|
return { name: nameMatch?.[1], lang: lang2, dependencies: deps2 };
|
|
46684
46710
|
}
|
|
46685
46711
|
const gradleFile = existsSync8(gradleKts) ? gradleKts : gradle;
|
|
@@ -46933,7 +46959,7 @@ var init_windsurf = __esm(() => {
|
|
|
46933
46959
|
|
|
46934
46960
|
// src/context/generator.ts
|
|
46935
46961
|
import { existsSync as existsSync9 } from "fs";
|
|
46936
|
-
import { join as
|
|
46962
|
+
import { join as join31, relative as relative12 } from "path";
|
|
46937
46963
|
async function loadContextContent(options, config2) {
|
|
46938
46964
|
if (!_generatorDeps.existsSync(options.contextPath)) {
|
|
46939
46965
|
throw new Error(`Context file not found: ${options.contextPath}`);
|
|
@@ -46951,7 +46977,7 @@ async function generateFor(agent, options, config2) {
|
|
|
46951
46977
|
try {
|
|
46952
46978
|
const context = await loadContextContent(options, config2);
|
|
46953
46979
|
const content = generator.generate(context);
|
|
46954
|
-
const outputPath =
|
|
46980
|
+
const outputPath = join31(options.outputDir, generator.outputFile);
|
|
46955
46981
|
validateFilePath(outputPath, options.outputDir);
|
|
46956
46982
|
if (!options.dryRun) {
|
|
46957
46983
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46969,7 +46995,7 @@ async function generateAll(options, config2, agentFilter) {
|
|
|
46969
46995
|
for (const [agentKey, generator] of entries) {
|
|
46970
46996
|
try {
|
|
46971
46997
|
const content = generator.generate(context);
|
|
46972
|
-
const outputPath =
|
|
46998
|
+
const outputPath = join31(options.outputDir, generator.outputFile);
|
|
46973
46999
|
validateFilePath(outputPath, options.outputDir);
|
|
46974
47000
|
if (!options.dryRun) {
|
|
46975
47001
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46989,7 +47015,7 @@ async function discoverPackages(repoRoot) {
|
|
|
46989
47015
|
const glob = new Bun.Glob(pattern);
|
|
46990
47016
|
for await (const match of glob.scan({ cwd: repoRoot, dot: true })) {
|
|
46991
47017
|
const pkgRelative = match.replace(/^\.nax\/mono\//, "").replace(/\/context\.md$/, "");
|
|
46992
|
-
const pkgAbsolute =
|
|
47018
|
+
const pkgAbsolute = join31(repoRoot, pkgRelative);
|
|
46993
47019
|
if (!seen.has(pkgAbsolute)) {
|
|
46994
47020
|
seen.add(pkgAbsolute);
|
|
46995
47021
|
packages.push(pkgAbsolute);
|
|
@@ -47021,14 +47047,14 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
47021
47047
|
}
|
|
47022
47048
|
}
|
|
47023
47049
|
}
|
|
47024
|
-
const turboPath =
|
|
47050
|
+
const turboPath = join31(repoRoot, "turbo.json");
|
|
47025
47051
|
try {
|
|
47026
47052
|
const turbo = JSON.parse(await _generatorDeps.readTextFile(turboPath));
|
|
47027
47053
|
if (Array.isArray(turbo.packages)) {
|
|
47028
47054
|
await resolveGlobs(turbo.packages);
|
|
47029
47055
|
}
|
|
47030
47056
|
} catch {}
|
|
47031
|
-
const pkgPath =
|
|
47057
|
+
const pkgPath = join31(repoRoot, "package.json");
|
|
47032
47058
|
try {
|
|
47033
47059
|
const pkg = JSON.parse(await _generatorDeps.readTextFile(pkgPath));
|
|
47034
47060
|
const ws = pkg.workspaces;
|
|
@@ -47036,7 +47062,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
47036
47062
|
if (patterns.length > 0)
|
|
47037
47063
|
await resolveGlobs(patterns);
|
|
47038
47064
|
} catch {}
|
|
47039
|
-
const pnpmPath =
|
|
47065
|
+
const pnpmPath = join31(repoRoot, "pnpm-workspace.yaml");
|
|
47040
47066
|
try {
|
|
47041
47067
|
const raw = await _generatorDeps.readTextFile(pnpmPath);
|
|
47042
47068
|
const lines = raw.split(`
|
|
@@ -47062,7 +47088,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
47062
47088
|
async function generateForPackage(packageDir, config2, dryRun = false, repoRoot) {
|
|
47063
47089
|
const resolvedRepoRoot = repoRoot ?? packageDir;
|
|
47064
47090
|
const relativePkgPath = relative12(resolvedRepoRoot, packageDir);
|
|
47065
|
-
const contextPath =
|
|
47091
|
+
const contextPath = join31(resolvedRepoRoot, ".nax", "mono", relativePkgPath, "context.md");
|
|
47066
47092
|
if (!_generatorDeps.existsSync(contextPath)) {
|
|
47067
47093
|
return [
|
|
47068
47094
|
{
|
|
@@ -47130,7 +47156,7 @@ var init_generator2 = __esm(() => {
|
|
|
47130
47156
|
});
|
|
47131
47157
|
|
|
47132
47158
|
// src/analyze/scanner.ts
|
|
47133
|
-
import { join as
|
|
47159
|
+
import { join as join32 } from "path";
|
|
47134
47160
|
function resolveFrameworkAndRunner(language, pkg) {
|
|
47135
47161
|
if (language === "go")
|
|
47136
47162
|
return { framework: "", testRunner: "go-test" };
|
|
@@ -47152,7 +47178,7 @@ async function scanSourceRoots(workdir) {
|
|
|
47152
47178
|
});
|
|
47153
47179
|
try {
|
|
47154
47180
|
const language = await deps.detectLanguage(workdir);
|
|
47155
|
-
const pkg = await deps.readPackageJson(
|
|
47181
|
+
const pkg = await deps.readPackageJson(join32(workdir, "package.json"));
|
|
47156
47182
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
47157
47183
|
return [{ path: ".", language, framework, testRunner }];
|
|
47158
47184
|
} catch {
|
|
@@ -47170,9 +47196,9 @@ async function scanSourceRoots(workdir) {
|
|
|
47170
47196
|
packages = packages.slice(0, MAX_SOURCE_ROOTS);
|
|
47171
47197
|
}
|
|
47172
47198
|
return Promise.all(packages.map(async (pkgPath) => {
|
|
47173
|
-
const pkgDir = pkgPath === "." ? workdir :
|
|
47199
|
+
const pkgDir = pkgPath === "." ? workdir : join32(workdir, pkgPath);
|
|
47174
47200
|
const language = await deps.detectLanguage(pkgDir);
|
|
47175
|
-
const pkg = await deps.readPackageJson(
|
|
47201
|
+
const pkg = await deps.readPackageJson(join32(pkgDir, "package.json"));
|
|
47176
47202
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
47177
47203
|
return { path: pkgPath, language, framework, testRunner };
|
|
47178
47204
|
}));
|
|
@@ -47205,7 +47231,7 @@ var init_analyze = __esm(() => {
|
|
|
47205
47231
|
});
|
|
47206
47232
|
|
|
47207
47233
|
// src/debate/pre-phase/grounder.ts
|
|
47208
|
-
import { join as
|
|
47234
|
+
import { join as join33 } from "path";
|
|
47209
47235
|
async function buildCodebaseContext(workdir) {
|
|
47210
47236
|
const roots = await _grounderDeps.scanSourceRoots(workdir);
|
|
47211
47237
|
return buildSourceRootsSection(normalizeRoots(workdir, roots));
|
|
@@ -47217,7 +47243,7 @@ function normalizeRoots(workdir, roots) {
|
|
|
47217
47243
|
}));
|
|
47218
47244
|
}
|
|
47219
47245
|
async function writeManifestArtifact(ctx, manifest) {
|
|
47220
|
-
const manifestPath =
|
|
47246
|
+
const manifestPath = join33(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
47221
47247
|
await _grounderDeps.write(manifestPath, JSON.stringify(manifest, null, 2));
|
|
47222
47248
|
}
|
|
47223
47249
|
var _grounderDeps, grounderStrategy = async (ctx) => {
|
|
@@ -47560,7 +47586,7 @@ function formatSpecDeltas(blockers, manifest) {
|
|
|
47560
47586
|
|
|
47561
47587
|
// src/debate/verifiers/checks.ts
|
|
47562
47588
|
import { existsSync as defaultExistsSync } from "fs";
|
|
47563
|
-
import { join as
|
|
47589
|
+
import { join as join34 } from "path";
|
|
47564
47590
|
function checkFilesExist(prd, workdir, deps) {
|
|
47565
47591
|
const existsSync10 = deps?.existsSync ?? defaultExistsSync;
|
|
47566
47592
|
const findings = [];
|
|
@@ -47570,7 +47596,7 @@ function checkFilesExist(prd, workdir, deps) {
|
|
|
47570
47596
|
for (const entry of story.contextFiles) {
|
|
47571
47597
|
const filePath = typeof entry === "string" ? entry : entry.path;
|
|
47572
47598
|
const factId = typeof entry === "string" ? undefined : entry.factId;
|
|
47573
|
-
const absPath =
|
|
47599
|
+
const absPath = join34(workdir, filePath);
|
|
47574
47600
|
if (existsSync10(absPath))
|
|
47575
47601
|
continue;
|
|
47576
47602
|
if (factId) {
|
|
@@ -47681,7 +47707,7 @@ var init_checks3 = () => {};
|
|
|
47681
47707
|
|
|
47682
47708
|
// src/debate/verifiers/plan-checklist.ts
|
|
47683
47709
|
import { existsSync as existsSync10 } from "fs";
|
|
47684
|
-
import { join as
|
|
47710
|
+
import { join as join35 } from "path";
|
|
47685
47711
|
function parsePrd(output) {
|
|
47686
47712
|
if (!output)
|
|
47687
47713
|
return null;
|
|
@@ -47692,7 +47718,7 @@ function parsePrd(output) {
|
|
|
47692
47718
|
}
|
|
47693
47719
|
}
|
|
47694
47720
|
async function loadManifest(ctx) {
|
|
47695
|
-
const manifestPath =
|
|
47721
|
+
const manifestPath = join35(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
47696
47722
|
const raw = await _planChecklistDeps.readFile(manifestPath);
|
|
47697
47723
|
if (!raw)
|
|
47698
47724
|
return null;
|
|
@@ -47705,7 +47731,7 @@ async function loadManifest(ctx) {
|
|
|
47705
47731
|
}
|
|
47706
47732
|
}
|
|
47707
47733
|
async function emitSpecDeltas(ctx, blockers, manifest) {
|
|
47708
|
-
const artifactPath =
|
|
47734
|
+
const artifactPath = join35(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "spec-deltas.md");
|
|
47709
47735
|
const content = formatSpecDeltas(blockers, manifest ?? { repoFacts: [], specClaims: [], gaps: [] });
|
|
47710
47736
|
await _planChecklistDeps.write(artifactPath, content);
|
|
47711
47737
|
return artifactPath;
|
|
@@ -48051,7 +48077,7 @@ var init_runner_plan_helpers = __esm(() => {
|
|
|
48051
48077
|
});
|
|
48052
48078
|
|
|
48053
48079
|
// src/debate/runner-plan.ts
|
|
48054
|
-
import { join as
|
|
48080
|
+
import { join as join36 } from "path";
|
|
48055
48081
|
async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
48056
48082
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
48057
48083
|
const config2 = ctx.stageConfig;
|
|
@@ -48110,7 +48136,7 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
48110
48136
|
sessionMode: ctx.stageConfig.sessionMode ?? "one-shot",
|
|
48111
48137
|
proposers: ctx.stageConfig.proposers
|
|
48112
48138
|
});
|
|
48113
|
-
const outputPaths = resolved.map((_, i) =>
|
|
48139
|
+
const outputPaths = resolved.map((_, i) => join36(opts.outputDir, `prd-debate-${i}.json`));
|
|
48114
48140
|
const successful = [];
|
|
48115
48141
|
let rebuttalList;
|
|
48116
48142
|
if (selectorKind === "verifier-pick") {
|
|
@@ -50353,9 +50379,9 @@ function validateFeatureName(feature) {
|
|
|
50353
50379
|
|
|
50354
50380
|
// src/plan/critic.ts
|
|
50355
50381
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
50356
|
-
import { dirname as dirname7, join as
|
|
50382
|
+
import { dirname as dirname7, join as join39 } from "path";
|
|
50357
50383
|
async function writeSpecDeltas(findings, workdir, runId, storyId, manifest) {
|
|
50358
|
-
const path7 =
|
|
50384
|
+
const path7 = join39(workdir, ".nax", "runs", runId, "plan", storyId, "spec-deltas.md");
|
|
50359
50385
|
await mkdir6(dirname7(path7), { recursive: true });
|
|
50360
50386
|
await Bun.write(path7, formatSpecDeltas(findings, manifest));
|
|
50361
50387
|
return path7;
|
|
@@ -51568,9 +51594,9 @@ __export(exports_plan_decompose, {
|
|
|
51568
51594
|
runReplanLoop: () => runReplanLoop,
|
|
51569
51595
|
planDecomposeCommand: () => planDecomposeCommand
|
|
51570
51596
|
});
|
|
51571
|
-
import { join as
|
|
51597
|
+
import { join as join40 } from "path";
|
|
51572
51598
|
async function planDecomposeCommand(workdir, config2, options) {
|
|
51573
|
-
const prdPath =
|
|
51599
|
+
const prdPath = join40(workdir, ".nax", "features", options.feature, "prd.json");
|
|
51574
51600
|
if (!_planDeps.existsSync(prdPath)) {
|
|
51575
51601
|
throw new NaxError(`PRD not found: ${prdPath}`, "PRD_NOT_FOUND", {
|
|
51576
51602
|
stage: "decompose",
|
|
@@ -51744,7 +51770,7 @@ var init_plan_decompose = __esm(() => {
|
|
|
51744
51770
|
|
|
51745
51771
|
// src/cli/plan-runtime.ts
|
|
51746
51772
|
import { existsSync as existsSync15 } from "fs";
|
|
51747
|
-
import { join as
|
|
51773
|
+
import { join as join41 } from "path";
|
|
51748
51774
|
function isRuntimeWithAgentManager(value) {
|
|
51749
51775
|
return typeof value === "object" && value !== null && "agentManager" in value;
|
|
51750
51776
|
}
|
|
@@ -51796,7 +51822,7 @@ var init_plan_runtime = __esm(() => {
|
|
|
51796
51822
|
writeFile: (path7, content) => Bun.write(path7, content).then(() => {}),
|
|
51797
51823
|
scanSourceRoots: (workdir) => scanSourceRoots(workdir),
|
|
51798
51824
|
createRuntime: (cfg, wd, featureName) => createRuntime(cfg, wd, { featureName }),
|
|
51799
|
-
readPackageJson: (workdir) => Bun.file(
|
|
51825
|
+
readPackageJson: (workdir) => Bun.file(join41(workdir, "package.json")).json().catch(() => null),
|
|
51800
51826
|
spawnSync: (cmd, opts) => {
|
|
51801
51827
|
const result = Bun.spawnSync(cmd, opts ? { cwd: opts.cwd } : {});
|
|
51802
51828
|
return { stdout: result.stdout, exitCode: result.exitCode };
|
|
@@ -52181,7 +52207,7 @@ var init_metrics = __esm(() => {
|
|
|
52181
52207
|
|
|
52182
52208
|
// src/commands/common.ts
|
|
52183
52209
|
import { existsSync as existsSync16, readdirSync as readdirSync2, realpathSync as realpathSync3 } from "fs";
|
|
52184
|
-
import { join as
|
|
52210
|
+
import { join as join42, resolve as resolve13 } from "path";
|
|
52185
52211
|
function resolveProject(options = {}) {
|
|
52186
52212
|
const { dir, feature } = options;
|
|
52187
52213
|
let projectRoot;
|
|
@@ -52189,12 +52215,12 @@ function resolveProject(options = {}) {
|
|
|
52189
52215
|
let configPath;
|
|
52190
52216
|
if (dir) {
|
|
52191
52217
|
projectRoot = realpathSync3(resolve13(dir));
|
|
52192
|
-
naxDir =
|
|
52218
|
+
naxDir = join42(projectRoot, ".nax");
|
|
52193
52219
|
if (!existsSync16(naxDir)) {
|
|
52194
52220
|
throw new NaxError(`Directory does not contain a nax project: ${projectRoot}
|
|
52195
52221
|
Expected to find: ${naxDir}`, "NAX_DIR_NOT_FOUND", { projectRoot, naxDir });
|
|
52196
52222
|
}
|
|
52197
|
-
configPath =
|
|
52223
|
+
configPath = join42(naxDir, "config.json");
|
|
52198
52224
|
if (!existsSync16(configPath)) {
|
|
52199
52225
|
throw new NaxError(`.nax directory found but config.json is missing: ${naxDir}
|
|
52200
52226
|
Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
@@ -52202,17 +52228,17 @@ Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
|
52202
52228
|
} else {
|
|
52203
52229
|
const found = findProjectRoot(process.cwd());
|
|
52204
52230
|
if (!found) {
|
|
52205
|
-
const cwdNaxDir =
|
|
52231
|
+
const cwdNaxDir = join42(process.cwd(), ".nax");
|
|
52206
52232
|
if (existsSync16(cwdNaxDir)) {
|
|
52207
|
-
const cwdConfigPath =
|
|
52233
|
+
const cwdConfigPath = join42(cwdNaxDir, "config.json");
|
|
52208
52234
|
throw new NaxError(`.nax directory found but config.json is missing: ${cwdNaxDir}
|
|
52209
52235
|
Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, configPath: cwdConfigPath });
|
|
52210
52236
|
}
|
|
52211
52237
|
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
52238
|
}
|
|
52213
52239
|
projectRoot = found;
|
|
52214
|
-
naxDir =
|
|
52215
|
-
configPath =
|
|
52240
|
+
naxDir = join42(projectRoot, ".nax");
|
|
52241
|
+
configPath = join42(naxDir, "config.json");
|
|
52216
52242
|
}
|
|
52217
52243
|
let featureDir;
|
|
52218
52244
|
if (feature) {
|
|
@@ -52221,8 +52247,8 @@ Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, co
|
|
|
52221
52247
|
} catch (error48) {
|
|
52222
52248
|
throw new NaxError(error48.message, "FEATURE_INVALID", { feature });
|
|
52223
52249
|
}
|
|
52224
|
-
const featuresDir =
|
|
52225
|
-
featureDir =
|
|
52250
|
+
const featuresDir = join42(naxDir, "features");
|
|
52251
|
+
featureDir = join42(featuresDir, feature);
|
|
52226
52252
|
if (!existsSync16(featureDir)) {
|
|
52227
52253
|
const availableFeatures = existsSync16(featuresDir) ? readdirSync2(featuresDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name) : [];
|
|
52228
52254
|
const availableMsg = availableFeatures.length > 0 ? `
|
|
@@ -52255,7 +52281,7 @@ async function resolveProjectAsync(options = {}) {
|
|
|
52255
52281
|
}
|
|
52256
52282
|
const isPlainName = !dir.includes("/") && !dir.includes("\\");
|
|
52257
52283
|
if (isPlainName) {
|
|
52258
|
-
const registryIdentityPath =
|
|
52284
|
+
const registryIdentityPath = join42(globalConfigDir(), dir, ".identity");
|
|
52259
52285
|
const identityFile = Bun.file(registryIdentityPath);
|
|
52260
52286
|
if (await identityFile.exists()) {
|
|
52261
52287
|
try {
|
|
@@ -52287,12 +52313,12 @@ function findProjectRoot(startDir) {
|
|
|
52287
52313
|
let current = resolve13(startDir);
|
|
52288
52314
|
let depth = 0;
|
|
52289
52315
|
while (depth < MAX_DIRECTORY_DEPTH) {
|
|
52290
|
-
const naxDir =
|
|
52291
|
-
const configPath =
|
|
52316
|
+
const naxDir = join42(current, ".nax");
|
|
52317
|
+
const configPath = join42(naxDir, "config.json");
|
|
52292
52318
|
if (existsSync16(configPath)) {
|
|
52293
52319
|
return realpathSync3(current);
|
|
52294
52320
|
}
|
|
52295
|
-
const parent =
|
|
52321
|
+
const parent = join42(current, "..");
|
|
52296
52322
|
if (parent === current) {
|
|
52297
52323
|
break;
|
|
52298
52324
|
}
|
|
@@ -52619,8 +52645,8 @@ var init_semantic_verdict = __esm(() => {
|
|
|
52619
52645
|
await Bun.write(filePath, content);
|
|
52620
52646
|
},
|
|
52621
52647
|
readdir: async (dir) => {
|
|
52622
|
-
const { readdir:
|
|
52623
|
-
return
|
|
52648
|
+
const { readdir: readdir2 } = await import("fs/promises");
|
|
52649
|
+
return readdir2(dir);
|
|
52624
52650
|
},
|
|
52625
52651
|
readFile: async (filePath) => {
|
|
52626
52652
|
return Bun.file(filePath).text();
|
|
@@ -52800,7 +52826,8 @@ __export(exports_acceptance, {
|
|
|
52800
52826
|
convertFixStoryToUserStory: () => convertFixStoryToUserStory,
|
|
52801
52827
|
buildAcceptanceTestPrompt: () => buildAcceptanceTestPrompt,
|
|
52802
52828
|
buildAcceptanceRunCommand: () => buildAcceptanceRunCommand,
|
|
52803
|
-
acceptanceTestFilename: () => acceptanceTestFilename2
|
|
52829
|
+
acceptanceTestFilename: () => acceptanceTestFilename2,
|
|
52830
|
+
_groupDeps: () => _groupDeps
|
|
52804
52831
|
});
|
|
52805
52832
|
var init_acceptance2 = __esm(() => {
|
|
52806
52833
|
init_refinement();
|
|
@@ -53071,10 +53098,10 @@ var init_acceptance_setup = __esm(() => {
|
|
|
53071
53098
|
},
|
|
53072
53099
|
deleteSemanticVerdicts: async (featureDir) => {
|
|
53073
53100
|
const dir = `${featureDir}/semantic-verdicts`;
|
|
53074
|
-
const { readdir:
|
|
53101
|
+
const { readdir: readdir2, unlink: unlink2 } = await import("fs/promises");
|
|
53075
53102
|
let files;
|
|
53076
53103
|
try {
|
|
53077
|
-
files = await
|
|
53104
|
+
files = await readdir2(dir);
|
|
53078
53105
|
} catch (err) {
|
|
53079
53106
|
if (err.code === "ENOENT")
|
|
53080
53107
|
return;
|
|
@@ -53149,7 +53176,7 @@ ${stderr}` };
|
|
|
53149
53176
|
const metaPath = path10.join(ctx.featureDir, "acceptance-meta.json");
|
|
53150
53177
|
const allCriteria = ctx.prd.userStories.filter((s) => !s.id.startsWith("US-FIX-") && s.status !== "decomposed").flatMap((s) => s.acceptanceCriteria);
|
|
53151
53178
|
const featureName = ctx.prd.feature ?? ctx.prd.featureName;
|
|
53152
|
-
const groups = groupStoriesByPackage(ctx.prd, ctx.workdir, featureName, testPathConfig, language);
|
|
53179
|
+
const groups = await groupStoriesByPackage(ctx.prd, ctx.workdir, featureName, testPathConfig, language);
|
|
53153
53180
|
const nonFixStories = groups.flatMap((g) => g.stories);
|
|
53154
53181
|
let totalCriteria = 0;
|
|
53155
53182
|
let testableCount = 0;
|
|
@@ -53451,10 +53478,10 @@ var init_effectiveness = __esm(() => {
|
|
|
53451
53478
|
|
|
53452
53479
|
// src/execution/progress.ts
|
|
53453
53480
|
import { appendFile as appendFile2, mkdir as mkdir7 } from "fs/promises";
|
|
53454
|
-
import { join as
|
|
53481
|
+
import { join as join45 } from "path";
|
|
53455
53482
|
async function appendProgress(featureDir, storyId, status, message) {
|
|
53456
53483
|
await mkdir7(featureDir, { recursive: true });
|
|
53457
|
-
const progressPath =
|
|
53484
|
+
const progressPath = join45(featureDir, "progress.txt");
|
|
53458
53485
|
const timestamp = new Date().toISOString();
|
|
53459
53486
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
53460
53487
|
`;
|
|
@@ -53648,7 +53675,7 @@ var init_completion = __esm(() => {
|
|
|
53648
53675
|
|
|
53649
53676
|
// src/constitution/loader.ts
|
|
53650
53677
|
import { existsSync as existsSync19 } from "fs";
|
|
53651
|
-
import { join as
|
|
53678
|
+
import { join as join46 } from "path";
|
|
53652
53679
|
function truncateToTokens(text, maxTokens) {
|
|
53653
53680
|
const maxChars = maxTokens * 3;
|
|
53654
53681
|
if (text.length <= maxChars) {
|
|
@@ -53670,7 +53697,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53670
53697
|
}
|
|
53671
53698
|
let combinedContent = "";
|
|
53672
53699
|
if (!config2.skipGlobal) {
|
|
53673
|
-
const globalPath =
|
|
53700
|
+
const globalPath = join46(globalConfigDir(), config2.path);
|
|
53674
53701
|
if (existsSync19(globalPath)) {
|
|
53675
53702
|
const validatedPath = validateFilePath(globalPath, globalConfigDir());
|
|
53676
53703
|
const globalFile = Bun.file(validatedPath);
|
|
@@ -53680,7 +53707,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53680
53707
|
}
|
|
53681
53708
|
}
|
|
53682
53709
|
}
|
|
53683
|
-
const projectPath =
|
|
53710
|
+
const projectPath = join46(projectDir, config2.path);
|
|
53684
53711
|
if (existsSync19(projectPath)) {
|
|
53685
53712
|
const validatedPath = validateFilePath(projectPath, projectDir);
|
|
53686
53713
|
const projectFile = Bun.file(validatedPath);
|
|
@@ -55114,7 +55141,7 @@ var init_story_orchestrator = __esm(() => {
|
|
|
55114
55141
|
});
|
|
55115
55142
|
|
|
55116
55143
|
// src/execution/build-plan-for-strategy.ts
|
|
55117
|
-
import { join as
|
|
55144
|
+
import { join as join47 } from "path";
|
|
55118
55145
|
function requiresInitialRefCapture(strategy) {
|
|
55119
55146
|
return isThreeSessionStrategy(strategy);
|
|
55120
55147
|
}
|
|
@@ -55160,7 +55187,7 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55160
55187
|
}
|
|
55161
55188
|
if (shouldRunRectification(config2) && inputs.rectification) {
|
|
55162
55189
|
const sink = makeDeclarationSink();
|
|
55163
|
-
const packageDir =
|
|
55190
|
+
const packageDir = join47(ctx.packageDir, story.workdir ?? "");
|
|
55164
55191
|
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.packageDir, story.workdir);
|
|
55165
55192
|
const strategies = [];
|
|
55166
55193
|
const pkgQuality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
@@ -55230,8 +55257,27 @@ var init_build_plan_for_strategy = __esm(() => {
|
|
|
55230
55257
|
init_story_orchestrator();
|
|
55231
55258
|
});
|
|
55232
55259
|
|
|
55260
|
+
// src/utils/paths.ts
|
|
55261
|
+
import { join as join48, relative as relative13, sep as sep4 } from "path";
|
|
55262
|
+
function packageDirRelative(projectDir, workdir) {
|
|
55263
|
+
if (!projectDir || !workdir || workdir === projectDir)
|
|
55264
|
+
return;
|
|
55265
|
+
const rel = relative13(projectDir, workdir);
|
|
55266
|
+
if (rel === ".." || rel.startsWith(`..${sep4}`))
|
|
55267
|
+
return;
|
|
55268
|
+
return rel && rel !== "." ? rel : undefined;
|
|
55269
|
+
}
|
|
55270
|
+
function getRunsDir() {
|
|
55271
|
+
return process.env.NAX_RUNS_DIR ?? join48(globalConfigDir(), "runs");
|
|
55272
|
+
}
|
|
55273
|
+
function getEventsRootDir() {
|
|
55274
|
+
return join48(globalConfigDir(), "events");
|
|
55275
|
+
}
|
|
55276
|
+
var init_paths3 = __esm(() => {
|
|
55277
|
+
init_paths();
|
|
55278
|
+
});
|
|
55279
|
+
|
|
55233
55280
|
// src/execution/plan-inputs.ts
|
|
55234
|
-
import { relative as relative13, sep as sep4 } from "path";
|
|
55235
55281
|
function validatePlanInputs(story, config2) {
|
|
55236
55282
|
if (!story.id || story.id.trim() === "") {
|
|
55237
55283
|
throw new NaxError("Story ID is required and must be non-empty", "STORY_ID_INVALID", {
|
|
@@ -55307,15 +55353,8 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55307
55353
|
if (!_isTdd && !ctx.prompt?.trim()) {
|
|
55308
55354
|
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
55355
|
}
|
|
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);
|
|
55356
|
+
const packageDirRel = packageDirRelative(ctx.projectDir, ctx.workdir);
|
|
55357
|
+
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.projectDir, packageDirRel);
|
|
55319
55358
|
const [testWriterPrompt, implementerPrompt, verifierPrompt] = _isTdd ? await Promise.all([
|
|
55320
55359
|
_isFreshRun ? buildThreeSessionPrompt("test-writer", ctx, isLite) : Promise.resolve(""),
|
|
55321
55360
|
buildThreeSessionPrompt("implementer", ctx, isLite),
|
|
@@ -55326,7 +55365,8 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55326
55365
|
promptMarkdown: testWriterPrompt,
|
|
55327
55366
|
featureContextMarkdown: ctx.featureContextMarkdown,
|
|
55328
55367
|
constitution: ctx.constitution?.content,
|
|
55329
|
-
lite: isLite
|
|
55368
|
+
lite: isLite,
|
|
55369
|
+
resolvedTestPatterns
|
|
55330
55370
|
} : undefined;
|
|
55331
55371
|
const greenfieldGateInput = _isTdd && _isFreshRun && resolvedTestPatterns ? { story, workdir: ctx.workdir, resolvedTestPatterns } : undefined;
|
|
55332
55372
|
const implementerInput = {
|
|
@@ -55351,7 +55391,7 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
55351
55391
|
naxIgnoreIndex: ctx.naxIgnoreIndex,
|
|
55352
55392
|
regressionMode: toVerifyScopedMode(ctx.config.execution?.regressionGate?.mode),
|
|
55353
55393
|
repoRoot: ctx.projectDir,
|
|
55354
|
-
packagePrefix:
|
|
55394
|
+
packagePrefix: packageDirRel,
|
|
55355
55395
|
resolvedTestPatterns
|
|
55356
55396
|
} : undefined;
|
|
55357
55397
|
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 +55496,7 @@ var init_plan_inputs = __esm(() => {
|
|
|
55456
55496
|
init_prompts();
|
|
55457
55497
|
init_review();
|
|
55458
55498
|
init_resolver();
|
|
55499
|
+
init_paths3();
|
|
55459
55500
|
});
|
|
55460
55501
|
|
|
55461
55502
|
// src/pipeline/stages/execution-helpers.ts
|
|
@@ -56521,6 +56562,8 @@ var init_queue_check = __esm(() => {
|
|
|
56521
56562
|
// src/pipeline/stages/routing.ts
|
|
56522
56563
|
var routingStage, _routingDeps;
|
|
56523
56564
|
var init_routing2 = __esm(() => {
|
|
56565
|
+
init_test_runners();
|
|
56566
|
+
init_paths3();
|
|
56524
56567
|
init_greenfield();
|
|
56525
56568
|
init_logger2();
|
|
56526
56569
|
init_prd();
|
|
@@ -56564,7 +56607,16 @@ var init_routing2 = __esm(() => {
|
|
|
56564
56607
|
const greenfieldDetectionEnabled = ctx.config.tdd.greenfieldDetection ?? true;
|
|
56565
56608
|
if (greenfieldDetectionEnabled && routing.testStrategy.startsWith("three-session-tdd")) {
|
|
56566
56609
|
const greenfieldScanDir = ctx.workdir;
|
|
56567
|
-
const
|
|
56610
|
+
const root = ctx.projectDir ?? ctx.workdir;
|
|
56611
|
+
const packageDir = packageDirRelative(root, ctx.workdir);
|
|
56612
|
+
const resolved = await _routingDeps.resolveTestFilePatterns(ctx.config, root, packageDir, { storyId: ctx.story.id }).catch((err) => {
|
|
56613
|
+
logger.debug("routing", "Test-pattern resolution failed; using default greenfield patterns", {
|
|
56614
|
+
storyId: ctx.story.id,
|
|
56615
|
+
error: errorMessage(err)
|
|
56616
|
+
});
|
|
56617
|
+
return;
|
|
56618
|
+
});
|
|
56619
|
+
const isGreenfield = await _routingDeps.isGreenfieldStory(ctx.story, greenfieldScanDir, resolved?.globs);
|
|
56568
56620
|
if (isGreenfield) {
|
|
56569
56621
|
logger.info("routing", "Greenfield detected \u2014 forcing test-after strategy", {
|
|
56570
56622
|
storyId: ctx.story.id,
|
|
@@ -56592,6 +56644,7 @@ var init_routing2 = __esm(() => {
|
|
|
56592
56644
|
resolveRouting,
|
|
56593
56645
|
complexityToModelTier,
|
|
56594
56646
|
isGreenfieldStory,
|
|
56647
|
+
resolveTestFilePatterns,
|
|
56595
56648
|
clearCache,
|
|
56596
56649
|
savePRD
|
|
56597
56650
|
};
|
|
@@ -59508,18 +59561,6 @@ var init_loader4 = __esm(() => {
|
|
|
59508
59561
|
FALLBACK_TEST_FILE_RE = /\.(test|spec)\.(ts|js|tsx|jsx|mjs)$/;
|
|
59509
59562
|
});
|
|
59510
59563
|
|
|
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
59564
|
// src/utils/command-argv.ts
|
|
59524
59565
|
function parseCommandToArgv(command) {
|
|
59525
59566
|
const safeEnv = buildAllowedEnv();
|
|
@@ -59574,7 +59615,7 @@ var init_command_argv = __esm(() => {
|
|
|
59574
59615
|
});
|
|
59575
59616
|
|
|
59576
59617
|
// src/hooks/runner.ts
|
|
59577
|
-
import { join as
|
|
59618
|
+
import { join as join74 } from "path";
|
|
59578
59619
|
function createDrainDeadline2(deadlineMs) {
|
|
59579
59620
|
let timeoutId;
|
|
59580
59621
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -59593,14 +59634,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
59593
59634
|
let globalHooks = { hooks: {} };
|
|
59594
59635
|
let projectHooks = { hooks: {} };
|
|
59595
59636
|
let skipGlobal = false;
|
|
59596
|
-
const projectPath =
|
|
59637
|
+
const projectPath = join74(projectDir, "hooks.json");
|
|
59597
59638
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
59598
59639
|
if (projectData) {
|
|
59599
59640
|
projectHooks = projectData;
|
|
59600
59641
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
59601
59642
|
}
|
|
59602
59643
|
if (!skipGlobal && globalDir) {
|
|
59603
|
-
const globalPath =
|
|
59644
|
+
const globalPath = join74(globalDir, "hooks.json");
|
|
59604
59645
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
59605
59646
|
if (globalData) {
|
|
59606
59647
|
globalHooks = globalData;
|
|
@@ -59770,7 +59811,7 @@ var package_default;
|
|
|
59770
59811
|
var init_package = __esm(() => {
|
|
59771
59812
|
package_default = {
|
|
59772
59813
|
name: "@nathapp/nax",
|
|
59773
|
-
version: "0.69.
|
|
59814
|
+
version: "0.69.9",
|
|
59774
59815
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
59775
59816
|
type: "module",
|
|
59776
59817
|
bin: {
|
|
@@ -59865,8 +59906,8 @@ var init_version = __esm(() => {
|
|
|
59865
59906
|
NAX_VERSION = package_default.version;
|
|
59866
59907
|
NAX_COMMIT = (() => {
|
|
59867
59908
|
try {
|
|
59868
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
59869
|
-
return "
|
|
59909
|
+
if (/^[0-9a-f]{6,10}$/.test("03eecdb1"))
|
|
59910
|
+
return "03eecdb1";
|
|
59870
59911
|
} catch {}
|
|
59871
59912
|
try {
|
|
59872
59913
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -60743,15 +60784,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
60743
60784
|
|
|
60744
60785
|
// src/session/scratch-purge.ts
|
|
60745
60786
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
60746
|
-
import { dirname as dirname12, join as
|
|
60787
|
+
import { dirname as dirname12, join as join75 } from "path";
|
|
60747
60788
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
60748
|
-
const sessionsDir =
|
|
60789
|
+
const sessionsDir = join75(projectDir, ".nax", "features", featureName, "sessions");
|
|
60749
60790
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
60750
60791
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
60751
60792
|
let purged = 0;
|
|
60752
60793
|
for (const sessionId of sessionIds) {
|
|
60753
|
-
const sessionDir =
|
|
60754
|
-
const descriptorPath =
|
|
60794
|
+
const sessionDir = join75(sessionsDir, sessionId);
|
|
60795
|
+
const descriptorPath = join75(sessionDir, "descriptor.json");
|
|
60755
60796
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
60756
60797
|
continue;
|
|
60757
60798
|
let lastActivityAt;
|
|
@@ -60767,7 +60808,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
60767
60808
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
60768
60809
|
continue;
|
|
60769
60810
|
if (archiveInsteadOfDelete) {
|
|
60770
|
-
const archiveDest =
|
|
60811
|
+
const archiveDest = join75(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
60771
60812
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
60772
60813
|
} else {
|
|
60773
60814
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -61505,12 +61546,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
61505
61546
|
|
|
61506
61547
|
// src/pipeline/subscribers/events-writer.ts
|
|
61507
61548
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
61508
|
-
import { basename as basename13, join as
|
|
61549
|
+
import { basename as basename13, join as join76 } from "path";
|
|
61509
61550
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
61510
61551
|
const logger = getSafeLogger();
|
|
61511
61552
|
const project = basename13(workdir);
|
|
61512
|
-
const eventsDir =
|
|
61513
|
-
const eventsFile =
|
|
61553
|
+
const eventsDir = join76(getEventsRootDir(), project);
|
|
61554
|
+
const eventsFile = join76(eventsDir, "events.jsonl");
|
|
61514
61555
|
let dirReady = false;
|
|
61515
61556
|
const write = (line) => {
|
|
61516
61557
|
return (async () => {
|
|
@@ -61691,12 +61732,12 @@ var init_interaction2 = __esm(() => {
|
|
|
61691
61732
|
|
|
61692
61733
|
// src/pipeline/subscribers/registry.ts
|
|
61693
61734
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
61694
|
-
import { basename as basename14, join as
|
|
61735
|
+
import { basename as basename14, join as join77 } from "path";
|
|
61695
61736
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
61696
61737
|
const logger = getSafeLogger();
|
|
61697
61738
|
const project = basename14(workdir);
|
|
61698
|
-
const runDir =
|
|
61699
|
-
const metaFile =
|
|
61739
|
+
const runDir = join77(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
61740
|
+
const metaFile = join77(runDir, "meta.json");
|
|
61700
61741
|
const unsub = bus.on("run:started", (_ev) => {
|
|
61701
61742
|
return (async () => {
|
|
61702
61743
|
try {
|
|
@@ -61706,8 +61747,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
61706
61747
|
project,
|
|
61707
61748
|
feature,
|
|
61708
61749
|
workdir,
|
|
61709
|
-
statusPath:
|
|
61710
|
-
eventsDir:
|
|
61750
|
+
statusPath: join77(outputDir, "features", feature, "status.json"),
|
|
61751
|
+
eventsDir: join77(outputDir, "features", feature, "runs"),
|
|
61711
61752
|
registeredAt: new Date().toISOString()
|
|
61712
61753
|
};
|
|
61713
61754
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -61953,7 +61994,7 @@ var init_types9 = __esm(() => {
|
|
|
61953
61994
|
|
|
61954
61995
|
// src/worktree/dependencies.ts
|
|
61955
61996
|
import { existsSync as existsSync30 } from "fs";
|
|
61956
|
-
import { join as
|
|
61997
|
+
import { join as join78 } from "path";
|
|
61957
61998
|
async function prepareWorktreeDependencies(options) {
|
|
61958
61999
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
61959
62000
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -61967,7 +62008,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
61967
62008
|
}
|
|
61968
62009
|
}
|
|
61969
62010
|
function resolveDependencyCwd(options) {
|
|
61970
|
-
return options.storyWorkdir ?
|
|
62011
|
+
return options.storyWorkdir ? join78(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
61971
62012
|
}
|
|
61972
62013
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
61973
62014
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -61977,7 +62018,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
61977
62018
|
}
|
|
61978
62019
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
61979
62020
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
61980
|
-
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(
|
|
62021
|
+
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join78(directory, filename))));
|
|
61981
62022
|
}
|
|
61982
62023
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
61983
62024
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -62041,13 +62082,13 @@ __export(exports_manager, {
|
|
|
62041
62082
|
});
|
|
62042
62083
|
import { existsSync as existsSync31, symlinkSync } from "fs";
|
|
62043
62084
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
62044
|
-
import { join as
|
|
62085
|
+
import { join as join79 } from "path";
|
|
62045
62086
|
|
|
62046
62087
|
class WorktreeManager {
|
|
62047
62088
|
async ensureGitExcludes(projectRoot) {
|
|
62048
62089
|
const logger = getSafeLogger();
|
|
62049
|
-
const infoDir =
|
|
62050
|
-
const excludePath =
|
|
62090
|
+
const infoDir = join79(projectRoot, ".git", "info");
|
|
62091
|
+
const excludePath = join79(infoDir, "exclude");
|
|
62051
62092
|
try {
|
|
62052
62093
|
await mkdir15(infoDir, { recursive: true });
|
|
62053
62094
|
let existing = "";
|
|
@@ -62074,7 +62115,7 @@ ${missing.join(`
|
|
|
62074
62115
|
}
|
|
62075
62116
|
async create(projectRoot, storyId) {
|
|
62076
62117
|
validateStoryId(storyId);
|
|
62077
|
-
const worktreePath =
|
|
62118
|
+
const worktreePath = join79(projectRoot, ".nax-wt", storyId);
|
|
62078
62119
|
const branchName = `nax/${storyId}`;
|
|
62079
62120
|
try {
|
|
62080
62121
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -62115,9 +62156,9 @@ ${missing.join(`
|
|
|
62115
62156
|
}
|
|
62116
62157
|
throw new Error(`Failed to create worktree: ${String(error48)}`);
|
|
62117
62158
|
}
|
|
62118
|
-
const envSource =
|
|
62159
|
+
const envSource = join79(projectRoot, ".env");
|
|
62119
62160
|
if (existsSync31(envSource)) {
|
|
62120
|
-
const envTarget =
|
|
62161
|
+
const envTarget = join79(worktreePath, ".env");
|
|
62121
62162
|
try {
|
|
62122
62163
|
symlinkSync(envSource, envTarget, "file");
|
|
62123
62164
|
} catch (error48) {
|
|
@@ -62128,7 +62169,7 @@ ${missing.join(`
|
|
|
62128
62169
|
}
|
|
62129
62170
|
async remove(projectRoot, storyId) {
|
|
62130
62171
|
validateStoryId(storyId);
|
|
62131
|
-
const worktreePath =
|
|
62172
|
+
const worktreePath = join79(projectRoot, ".nax-wt", storyId);
|
|
62132
62173
|
const branchName = `nax/${storyId}`;
|
|
62133
62174
|
try {
|
|
62134
62175
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -62940,10 +62981,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
62940
62981
|
});
|
|
62941
62982
|
|
|
62942
62983
|
// src/execution/pipeline-result-handler.ts
|
|
62943
|
-
import { join as
|
|
62984
|
+
import { join as join80 } from "path";
|
|
62944
62985
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
62945
62986
|
const logger = getSafeLogger();
|
|
62946
|
-
const worktreePath =
|
|
62987
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62947
62988
|
try {
|
|
62948
62989
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
62949
62990
|
cwd: projectRoot,
|
|
@@ -63160,7 +63201,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
63160
63201
|
|
|
63161
63202
|
// src/execution/iteration-runner.ts
|
|
63162
63203
|
import { existsSync as existsSync32 } from "fs";
|
|
63163
|
-
import { join as
|
|
63204
|
+
import { join as join81 } from "path";
|
|
63164
63205
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
63165
63206
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
63166
63207
|
if (ctx.dryRun) {
|
|
@@ -63185,7 +63226,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63185
63226
|
const storyStartTime = Date.now();
|
|
63186
63227
|
let effectiveWorkdir = ctx.workdir;
|
|
63187
63228
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63188
|
-
const worktreePath =
|
|
63229
|
+
const worktreePath = join81(ctx.workdir, ".nax-wt", story.id);
|
|
63189
63230
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
63190
63231
|
if (!worktreeExists) {
|
|
63191
63232
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -63205,7 +63246,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63205
63246
|
}
|
|
63206
63247
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
63207
63248
|
const profileOverride = ctx.config.profile && ctx.config.profile !== "default" ? { profile: ctx.config.profile } : undefined;
|
|
63208
|
-
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(
|
|
63249
|
+
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join81(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
|
|
63209
63250
|
let dependencyContext;
|
|
63210
63251
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63211
63252
|
try {
|
|
@@ -63232,7 +63273,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63232
63273
|
};
|
|
63233
63274
|
}
|
|
63234
63275
|
}
|
|
63235
|
-
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ?
|
|
63276
|
+
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
63277
|
const pipelineContext = {
|
|
63237
63278
|
config: effectiveConfig,
|
|
63238
63279
|
rootConfig: ctx.config,
|
|
@@ -63434,7 +63475,7 @@ __export(exports_parallel_worker, {
|
|
|
63434
63475
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
63435
63476
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
63436
63477
|
});
|
|
63437
|
-
import { join as
|
|
63478
|
+
import { join as join82 } from "path";
|
|
63438
63479
|
function buildWorktreePipelineContext(base, _story) {
|
|
63439
63480
|
return { ...base, prd: structuredClone(base.prd) };
|
|
63440
63481
|
}
|
|
@@ -63457,7 +63498,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
63457
63498
|
story,
|
|
63458
63499
|
stories: [story],
|
|
63459
63500
|
projectDir: context.projectDir,
|
|
63460
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
63501
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join82(worktreePath, story.workdir) : worktreePath),
|
|
63461
63502
|
worktreeDependencyContext: dependencyContext,
|
|
63462
63503
|
routing,
|
|
63463
63504
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -64344,7 +64385,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
64344
64385
|
var init_status_file = () => {};
|
|
64345
64386
|
|
|
64346
64387
|
// src/execution/status-writer.ts
|
|
64347
|
-
import { join as
|
|
64388
|
+
import { join as join83 } from "path";
|
|
64348
64389
|
|
|
64349
64390
|
class StatusWriter {
|
|
64350
64391
|
statusFile;
|
|
@@ -64463,7 +64504,7 @@ class StatusWriter {
|
|
|
64463
64504
|
if (!this._prd)
|
|
64464
64505
|
return;
|
|
64465
64506
|
const safeLogger = getSafeLogger();
|
|
64466
|
-
const featureStatusPath =
|
|
64507
|
+
const featureStatusPath = join83(featureDir, "status.json");
|
|
64467
64508
|
const write = async () => {
|
|
64468
64509
|
try {
|
|
64469
64510
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -64495,7 +64536,7 @@ __export(exports_migrate, {
|
|
|
64495
64536
|
detectGeneratedContent: () => detectGeneratedContent
|
|
64496
64537
|
});
|
|
64497
64538
|
import { existsSync as existsSync33 } from "fs";
|
|
64498
|
-
import { mkdir as mkdir16, readdir as
|
|
64539
|
+
import { mkdir as mkdir16, readdir as readdir5, rename as rename3 } from "fs/promises";
|
|
64499
64540
|
import path22 from "path";
|
|
64500
64541
|
async function detectGeneratedContent(naxDir) {
|
|
64501
64542
|
if (!existsSync33(naxDir))
|
|
@@ -64503,7 +64544,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64503
64544
|
const candidates = [];
|
|
64504
64545
|
let entries = [];
|
|
64505
64546
|
try {
|
|
64506
|
-
entries = await
|
|
64547
|
+
entries = await readdir5(naxDir);
|
|
64507
64548
|
} catch {
|
|
64508
64549
|
return [];
|
|
64509
64550
|
}
|
|
@@ -64516,13 +64557,13 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64516
64557
|
if (existsSync33(featuresDir)) {
|
|
64517
64558
|
let featureDirs = [];
|
|
64518
64559
|
try {
|
|
64519
|
-
featureDirs = await
|
|
64560
|
+
featureDirs = await readdir5(featuresDir);
|
|
64520
64561
|
} catch {}
|
|
64521
64562
|
for (const fid of featureDirs) {
|
|
64522
64563
|
const featureDir = path22.join(featuresDir, fid);
|
|
64523
64564
|
let subEntries = [];
|
|
64524
64565
|
try {
|
|
64525
|
-
subEntries = await
|
|
64566
|
+
subEntries = await readdir5(featureDir);
|
|
64526
64567
|
} catch {
|
|
64527
64568
|
continue;
|
|
64528
64569
|
}
|
|
@@ -64537,7 +64578,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64537
64578
|
const storiesDir = path22.join(featureDir, "stories");
|
|
64538
64579
|
let storyDirs = [];
|
|
64539
64580
|
try {
|
|
64540
|
-
storyDirs = await
|
|
64581
|
+
storyDirs = await readdir5(storiesDir);
|
|
64541
64582
|
} catch {
|
|
64542
64583
|
continue;
|
|
64543
64584
|
}
|
|
@@ -64545,7 +64586,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
64545
64586
|
const storyDir = path22.join(storiesDir, sid);
|
|
64546
64587
|
let storyEntries = [];
|
|
64547
64588
|
try {
|
|
64548
|
-
storyEntries = await
|
|
64589
|
+
storyEntries = await readdir5(storyDir);
|
|
64549
64590
|
} catch {
|
|
64550
64591
|
continue;
|
|
64551
64592
|
}
|
|
@@ -64897,7 +64938,7 @@ __export(exports_run_initialization, {
|
|
|
64897
64938
|
initializeRun: () => initializeRun,
|
|
64898
64939
|
_reconcileDeps: () => _reconcileDeps
|
|
64899
64940
|
});
|
|
64900
|
-
import { join as
|
|
64941
|
+
import { join as join84 } from "path";
|
|
64901
64942
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
64902
64943
|
const logger = getSafeLogger();
|
|
64903
64944
|
let reconciledCount = 0;
|
|
@@ -64914,7 +64955,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
64914
64955
|
});
|
|
64915
64956
|
continue;
|
|
64916
64957
|
}
|
|
64917
|
-
const effectiveWorkdir = story.workdir ?
|
|
64958
|
+
const effectiveWorkdir = story.workdir ? join84(workdir, story.workdir) : workdir;
|
|
64918
64959
|
try {
|
|
64919
64960
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
64920
64961
|
if (!reviewResult.success) {
|
|
@@ -94718,7 +94759,7 @@ __export(exports_curator, {
|
|
|
94718
94759
|
});
|
|
94719
94760
|
import { readdirSync as readdirSync8 } from "fs";
|
|
94720
94761
|
import { unlink as unlink4 } from "fs/promises";
|
|
94721
|
-
import { basename as basename15, join as
|
|
94762
|
+
import { basename as basename15, join as join86 } from "path";
|
|
94722
94763
|
function getProjectKey(config2, projectDir) {
|
|
94723
94764
|
return config2.name?.trim() || basename15(projectDir);
|
|
94724
94765
|
}
|
|
@@ -94801,7 +94842,7 @@ async function curatorStatus(options) {
|
|
|
94801
94842
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94802
94843
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94803
94844
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94804
|
-
const runsDir =
|
|
94845
|
+
const runsDir = join86(outputDir, "runs");
|
|
94805
94846
|
const runIds = listRunIds(runsDir);
|
|
94806
94847
|
let runId;
|
|
94807
94848
|
if (options.run) {
|
|
@@ -94818,8 +94859,8 @@ async function curatorStatus(options) {
|
|
|
94818
94859
|
runId = runIds[runIds.length - 1];
|
|
94819
94860
|
}
|
|
94820
94861
|
console.log(`Run: ${runId}`);
|
|
94821
|
-
const runDir =
|
|
94822
|
-
const observationsPath =
|
|
94862
|
+
const runDir = join86(runsDir, runId);
|
|
94863
|
+
const observationsPath = join86(runDir, "observations.jsonl");
|
|
94823
94864
|
const observations = await parseObservations(observationsPath);
|
|
94824
94865
|
const counts = new Map;
|
|
94825
94866
|
for (const obs of observations) {
|
|
@@ -94829,7 +94870,7 @@ async function curatorStatus(options) {
|
|
|
94829
94870
|
for (const [kind, count] of counts.entries()) {
|
|
94830
94871
|
console.log(` ${kind}: ${count}`);
|
|
94831
94872
|
}
|
|
94832
|
-
const proposalsPath =
|
|
94873
|
+
const proposalsPath = join86(runDir, "curator-proposals.md");
|
|
94833
94874
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94834
94875
|
if (proposalText !== null) {
|
|
94835
94876
|
console.log("");
|
|
@@ -94843,8 +94884,8 @@ async function curatorCommit(options) {
|
|
|
94843
94884
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94844
94885
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94845
94886
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94846
|
-
const runDir =
|
|
94847
|
-
const proposalsPath =
|
|
94887
|
+
const runDir = join86(outputDir, "runs", options.runId);
|
|
94888
|
+
const proposalsPath = join86(runDir, "curator-proposals.md");
|
|
94848
94889
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94849
94890
|
if (proposalText === null) {
|
|
94850
94891
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -94860,7 +94901,7 @@ async function curatorCommit(options) {
|
|
|
94860
94901
|
const dropFileState = new Map;
|
|
94861
94902
|
const skippedDrops = new Set;
|
|
94862
94903
|
for (const drop2 of drops) {
|
|
94863
|
-
const targetPath =
|
|
94904
|
+
const targetPath = join86(resolved.projectDir, drop2.canonicalFile);
|
|
94864
94905
|
if (!dropFileState.has(targetPath)) {
|
|
94865
94906
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
94866
94907
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -94894,7 +94935,7 @@ async function curatorCommit(options) {
|
|
|
94894
94935
|
if (skippedDrops.has(drop2)) {
|
|
94895
94936
|
continue;
|
|
94896
94937
|
}
|
|
94897
|
-
const targetPath =
|
|
94938
|
+
const targetPath = join86(resolved.projectDir, drop2.canonicalFile);
|
|
94898
94939
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
94899
94940
|
const filtered = filterDropContent(existing, drop2.description);
|
|
94900
94941
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -94903,7 +94944,7 @@ async function curatorCommit(options) {
|
|
|
94903
94944
|
}
|
|
94904
94945
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
94905
94946
|
for (const add2 of adds) {
|
|
94906
|
-
const targetPath =
|
|
94947
|
+
const targetPath = join86(resolved.projectDir, add2.canonicalFile);
|
|
94907
94948
|
const content = buildAddContent(add2);
|
|
94908
94949
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
94909
94950
|
modifiedFiles.add(targetPath);
|
|
@@ -94940,7 +94981,7 @@ async function curatorDryrun(options) {
|
|
|
94940
94981
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94941
94982
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94942
94983
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94943
|
-
const runsDir =
|
|
94984
|
+
const runsDir = join86(outputDir, "runs");
|
|
94944
94985
|
const runIds = listRunIds(runsDir);
|
|
94945
94986
|
if (runIds.length === 0) {
|
|
94946
94987
|
console.log("No runs found.");
|
|
@@ -94951,7 +94992,7 @@ async function curatorDryrun(options) {
|
|
|
94951
94992
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
94952
94993
|
return;
|
|
94953
94994
|
}
|
|
94954
|
-
const observationsPath =
|
|
94995
|
+
const observationsPath = join86(runsDir, runId, "observations.jsonl");
|
|
94955
94996
|
const observations = await parseObservations(observationsPath);
|
|
94956
94997
|
const thresholds = getThresholds(config2);
|
|
94957
94998
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -94992,12 +95033,12 @@ async function curatorGc(options) {
|
|
|
94992
95033
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
94993
95034
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94994
95035
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94995
|
-
const perRunsDir =
|
|
95036
|
+
const perRunsDir = join86(outputDir, "runs");
|
|
94996
95037
|
for (const runId of uniqueRunIds) {
|
|
94997
95038
|
if (!keepSet.has(runId)) {
|
|
94998
|
-
const runDir =
|
|
94999
|
-
await _curatorCmdDeps.removeFile(
|
|
95000
|
-
await _curatorCmdDeps.removeFile(
|
|
95039
|
+
const runDir = join86(perRunsDir, runId);
|
|
95040
|
+
await _curatorCmdDeps.removeFile(join86(runDir, "observations.jsonl"));
|
|
95041
|
+
await _curatorCmdDeps.removeFile(join86(runDir, "curator-proposals.md"));
|
|
95001
95042
|
}
|
|
95002
95043
|
}
|
|
95003
95044
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -95042,7 +95083,7 @@ var init_curator2 = __esm(() => {
|
|
|
95042
95083
|
init_source();
|
|
95043
95084
|
import { existsSync as existsSync35, mkdirSync as mkdirSync7 } from "fs";
|
|
95044
95085
|
import { homedir as homedir3 } from "os";
|
|
95045
|
-
import { basename as basename16, join as
|
|
95086
|
+
import { basename as basename16, join as join87 } from "path";
|
|
95046
95087
|
|
|
95047
95088
|
// node_modules/commander/esm.mjs
|
|
95048
95089
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -95066,12 +95107,12 @@ init_errors();
|
|
|
95066
95107
|
init_operations();
|
|
95067
95108
|
|
|
95068
95109
|
// src/plan/strategies/context-builder.ts
|
|
95069
|
-
import { join as
|
|
95110
|
+
import { join as join38 } from "path";
|
|
95070
95111
|
init_config();
|
|
95071
95112
|
init_errors();
|
|
95072
95113
|
init_interaction();
|
|
95073
95114
|
async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
95074
|
-
const naxDir =
|
|
95115
|
+
const naxDir = join38(workdir, ".nax");
|
|
95075
95116
|
if (!deps.existsSync(naxDir)) {
|
|
95076
95117
|
throw new NaxError(`.nax directory not found. Run 'nax init' first in ${workdir}`, "PLAN_CONTEXT_NO_NAX_DIR", {
|
|
95077
95118
|
stage: "plan",
|
|
@@ -95079,8 +95120,8 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95079
95120
|
});
|
|
95080
95121
|
}
|
|
95081
95122
|
validateFeatureName(options.feature);
|
|
95082
|
-
const outputDir =
|
|
95083
|
-
const outputPath =
|
|
95123
|
+
const outputDir = join38(naxDir, "features", options.feature);
|
|
95124
|
+
const outputPath = join38(outputDir, "prd.json");
|
|
95084
95125
|
const [specContent, sourceRoots, pkg] = await Promise.all([
|
|
95085
95126
|
deps.readFile(options.from),
|
|
95086
95127
|
deps.scanSourceRoots(workdir),
|
|
@@ -95095,7 +95136,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95095
95136
|
...new Set(sourceRoots.map((root) => root.path).filter((path7) => path7 !== ".").map((path7) => path7.startsWith("/") ? path7.replace(`${workdir}/`, "") : path7))
|
|
95096
95137
|
];
|
|
95097
95138
|
const packageDetails = relativePackages.length === 0 ? [] : await Promise.all(relativePackages.map(async (relativePath) => {
|
|
95098
|
-
const packageJson = await deps.readPackageJsonAt(
|
|
95139
|
+
const packageJson = await deps.readPackageJsonAt(join38(workdir, relativePath, "package.json"));
|
|
95099
95140
|
return buildPackageSummary(relativePath, packageJson);
|
|
95100
95141
|
}));
|
|
95101
95142
|
const projectName = detectProjectName(workdir, pkg);
|
|
@@ -95698,7 +95739,7 @@ init_interaction();
|
|
|
95698
95739
|
init_prd();
|
|
95699
95740
|
init_runtime();
|
|
95700
95741
|
import { existsSync as existsSync17, readdirSync as readdirSync3 } from "fs";
|
|
95701
|
-
import { basename as basename7, join as
|
|
95742
|
+
import { basename as basename7, join as join43, resolve as resolve14 } from "path";
|
|
95702
95743
|
var _statusFeaturesDeps = {
|
|
95703
95744
|
projectOutputDir,
|
|
95704
95745
|
loadConfig
|
|
@@ -95712,7 +95753,7 @@ function isPidAlive(pid) {
|
|
|
95712
95753
|
}
|
|
95713
95754
|
}
|
|
95714
95755
|
async function loadStatusFile(featureDir) {
|
|
95715
|
-
const statusPath =
|
|
95756
|
+
const statusPath = join43(featureDir, "status.json");
|
|
95716
95757
|
if (!existsSync17(statusPath)) {
|
|
95717
95758
|
return null;
|
|
95718
95759
|
}
|
|
@@ -95727,7 +95768,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95727
95768
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95728
95769
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95729
95770
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95730
|
-
const statusPath =
|
|
95771
|
+
const statusPath = join43(outputDir, "status.json");
|
|
95731
95772
|
if (!existsSync17(statusPath)) {
|
|
95732
95773
|
return null;
|
|
95733
95774
|
}
|
|
@@ -95739,7 +95780,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95739
95780
|
}
|
|
95740
95781
|
}
|
|
95741
95782
|
async function getFeatureSummary(featureName, featureDir) {
|
|
95742
|
-
const prdPath =
|
|
95783
|
+
const prdPath = join43(featureDir, "prd.json");
|
|
95743
95784
|
if (!existsSync17(prdPath)) {
|
|
95744
95785
|
return {
|
|
95745
95786
|
name: featureName,
|
|
@@ -95782,7 +95823,7 @@ async function getFeatureSummary(featureName, featureDir) {
|
|
|
95782
95823
|
};
|
|
95783
95824
|
}
|
|
95784
95825
|
}
|
|
95785
|
-
const runsDir =
|
|
95826
|
+
const runsDir = join43(featureDir, "runs");
|
|
95786
95827
|
if (existsSync17(runsDir)) {
|
|
95787
95828
|
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
95829
|
if (runs.length > 0) {
|
|
@@ -95796,7 +95837,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95796
95837
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95797
95838
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95798
95839
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95799
|
-
const featuresDir =
|
|
95840
|
+
const featuresDir = join43(outputDir, "features");
|
|
95800
95841
|
if (!existsSync17(featuresDir)) {
|
|
95801
95842
|
console.log(source_default.dim("No features found."));
|
|
95802
95843
|
return;
|
|
@@ -95837,7 +95878,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95837
95878
|
console.log();
|
|
95838
95879
|
}
|
|
95839
95880
|
}
|
|
95840
|
-
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name,
|
|
95881
|
+
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name, join43(featuresDir, name))));
|
|
95841
95882
|
console.log(source_default.bold(`\uD83D\uDCCA Features
|
|
95842
95883
|
`));
|
|
95843
95884
|
const header = ` ${"Feature".padEnd(25)} ${"Done".padEnd(6)} ${"Failed".padEnd(8)} ${"Pending".padEnd(9)} ${"Last Run".padEnd(22)} ${"Cost".padEnd(10)} Status`;
|
|
@@ -95863,7 +95904,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95863
95904
|
console.log();
|
|
95864
95905
|
}
|
|
95865
95906
|
async function displayFeatureDetails(featureName, featureDir) {
|
|
95866
|
-
const prdPath =
|
|
95907
|
+
const prdPath = join43(featureDir, "prd.json");
|
|
95867
95908
|
if (!existsSync17(prdPath)) {
|
|
95868
95909
|
console.log(source_default.bold(`
|
|
95869
95910
|
\uD83D\uDCCA ${featureName}
|
|
@@ -96009,7 +96050,7 @@ async function displayFeatureStatus(options = {}) {
|
|
|
96009
96050
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
96010
96051
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
96011
96052
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
96012
|
-
featureDir =
|
|
96053
|
+
featureDir = join43(outputDir, "features", options.feature);
|
|
96013
96054
|
} else {
|
|
96014
96055
|
const resolved = resolveProject({ feature: options.feature });
|
|
96015
96056
|
if (!resolved.featureDir) {
|
|
@@ -96029,7 +96070,7 @@ init_errors();
|
|
|
96029
96070
|
init_logger2();
|
|
96030
96071
|
init_runtime();
|
|
96031
96072
|
import { existsSync as existsSync18, readdirSync as readdirSync4 } from "fs";
|
|
96032
|
-
import { basename as basename8, join as
|
|
96073
|
+
import { basename as basename8, join as join44 } from "path";
|
|
96033
96074
|
async function resolveOutputDir2(workdir, override) {
|
|
96034
96075
|
if (override)
|
|
96035
96076
|
return override;
|
|
@@ -96053,7 +96094,7 @@ async function runsListCommand(options) {
|
|
|
96053
96094
|
const logger = getLogger();
|
|
96054
96095
|
const { feature, workdir } = options;
|
|
96055
96096
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
96056
|
-
const runsDir =
|
|
96097
|
+
const runsDir = join44(outputDir, "features", feature, "runs");
|
|
96057
96098
|
if (!existsSync18(runsDir)) {
|
|
96058
96099
|
logger.info("cli", "No runs found for feature", { feature, hint: `Directory not found: ${runsDir}` });
|
|
96059
96100
|
return;
|
|
@@ -96065,7 +96106,7 @@ async function runsListCommand(options) {
|
|
|
96065
96106
|
}
|
|
96066
96107
|
logger.info("cli", `Runs for ${feature}`, { count: files.length });
|
|
96067
96108
|
for (const file3 of files.sort().reverse()) {
|
|
96068
|
-
const logPath =
|
|
96109
|
+
const logPath = join44(runsDir, file3);
|
|
96069
96110
|
const entries = await parseRunLog(logPath);
|
|
96070
96111
|
const startEvent = entries.find((e) => e.message === "run.start");
|
|
96071
96112
|
const completeEvent = entries.find((e) => e.message === "run.complete");
|
|
@@ -96092,7 +96133,7 @@ async function runsShowCommand(options) {
|
|
|
96092
96133
|
const logger = getLogger();
|
|
96093
96134
|
const { runId, feature, workdir } = options;
|
|
96094
96135
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
96095
|
-
const logPath =
|
|
96136
|
+
const logPath = join44(outputDir, "features", feature, "runs", `${runId}.jsonl`);
|
|
96096
96137
|
if (!existsSync18(logPath)) {
|
|
96097
96138
|
logger.error("cli", "Run not found", { runId, feature, logPath });
|
|
96098
96139
|
throw new NaxError("Run not found", "RUN_NOT_FOUND", { runId, feature, logPath });
|
|
@@ -97438,19 +97479,19 @@ async function detectCommand(options) {
|
|
|
97438
97479
|
// src/commands/logs.ts
|
|
97439
97480
|
init_common();
|
|
97440
97481
|
import { existsSync as existsSync28 } from "fs";
|
|
97441
|
-
import { join as
|
|
97482
|
+
import { join as join70 } from "path";
|
|
97442
97483
|
|
|
97443
97484
|
// src/commands/logs-formatter.ts
|
|
97444
97485
|
init_source();
|
|
97445
97486
|
init_formatter();
|
|
97446
97487
|
import { readdirSync as readdirSync7 } from "fs";
|
|
97447
|
-
import { join as
|
|
97488
|
+
import { join as join69 } from "path";
|
|
97448
97489
|
|
|
97449
97490
|
// src/commands/logs-reader.ts
|
|
97450
97491
|
init_paths3();
|
|
97451
97492
|
import { existsSync as existsSync27, readdirSync as readdirSync6 } from "fs";
|
|
97452
|
-
import { readdir as
|
|
97453
|
-
import { join as
|
|
97493
|
+
import { readdir as readdir3 } from "fs/promises";
|
|
97494
|
+
import { join as join68 } from "path";
|
|
97454
97495
|
var _logsReaderDeps = {
|
|
97455
97496
|
getRunsDir
|
|
97456
97497
|
};
|
|
@@ -97458,13 +97499,13 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97458
97499
|
const runsDir = _logsReaderDeps.getRunsDir();
|
|
97459
97500
|
let entries;
|
|
97460
97501
|
try {
|
|
97461
|
-
entries = await
|
|
97502
|
+
entries = await readdir3(runsDir);
|
|
97462
97503
|
} catch {
|
|
97463
97504
|
throw new Error(`Run not found in registry: ${runId}`);
|
|
97464
97505
|
}
|
|
97465
97506
|
let matched = null;
|
|
97466
97507
|
for (const entry of entries) {
|
|
97467
|
-
const metaPath =
|
|
97508
|
+
const metaPath = join68(runsDir, entry, "meta.json");
|
|
97468
97509
|
try {
|
|
97469
97510
|
const meta3 = await Bun.file(metaPath).json();
|
|
97470
97511
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -97486,14 +97527,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97486
97527
|
return null;
|
|
97487
97528
|
}
|
|
97488
97529
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
97489
|
-
return
|
|
97530
|
+
return join68(matched.eventsDir, specificFile ?? files[0]);
|
|
97490
97531
|
}
|
|
97491
97532
|
async function selectRunFile(runsDir) {
|
|
97492
97533
|
const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
97493
97534
|
if (files.length === 0) {
|
|
97494
97535
|
return null;
|
|
97495
97536
|
}
|
|
97496
|
-
return
|
|
97537
|
+
return join68(runsDir, files[0]);
|
|
97497
97538
|
}
|
|
97498
97539
|
async function extractRunSummary(filePath) {
|
|
97499
97540
|
const file3 = Bun.file(filePath);
|
|
@@ -97579,7 +97620,7 @@ Runs:
|
|
|
97579
97620
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
97580
97621
|
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
97622
|
for (const file3 of files) {
|
|
97582
|
-
const filePath =
|
|
97623
|
+
const filePath = join69(runsDir, file3);
|
|
97583
97624
|
const summary = await extractRunSummary(filePath);
|
|
97584
97625
|
const timestamp = file3.replace(".jsonl", "");
|
|
97585
97626
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -97693,7 +97734,7 @@ async function logsCommand(options) {
|
|
|
97693
97734
|
return;
|
|
97694
97735
|
}
|
|
97695
97736
|
const resolved = resolveProject({ dir: options.dir });
|
|
97696
|
-
const naxDir =
|
|
97737
|
+
const naxDir = join70(resolved.projectDir, ".nax");
|
|
97697
97738
|
const configPath = resolved.configPath;
|
|
97698
97739
|
const configFile = Bun.file(configPath);
|
|
97699
97740
|
const config2 = await configFile.json();
|
|
@@ -97701,8 +97742,8 @@ async function logsCommand(options) {
|
|
|
97701
97742
|
if (!featureName) {
|
|
97702
97743
|
throw new Error("No feature specified in config.json");
|
|
97703
97744
|
}
|
|
97704
|
-
const featureDir =
|
|
97705
|
-
const runsDir =
|
|
97745
|
+
const featureDir = join70(naxDir, "features", featureName);
|
|
97746
|
+
const runsDir = join70(featureDir, "runs");
|
|
97706
97747
|
if (!existsSync28(runsDir)) {
|
|
97707
97748
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
97708
97749
|
}
|
|
@@ -97728,7 +97769,7 @@ init_prd();
|
|
|
97728
97769
|
init_precheck();
|
|
97729
97770
|
init_common();
|
|
97730
97771
|
import { existsSync as existsSync29 } from "fs";
|
|
97731
|
-
import { join as
|
|
97772
|
+
import { join as join71 } from "path";
|
|
97732
97773
|
async function precheckCommand(options) {
|
|
97733
97774
|
const resolved = resolveProject({
|
|
97734
97775
|
dir: options.dir,
|
|
@@ -97750,9 +97791,9 @@ async function precheckCommand(options) {
|
|
|
97750
97791
|
process.exit(1);
|
|
97751
97792
|
}
|
|
97752
97793
|
}
|
|
97753
|
-
const naxDir =
|
|
97754
|
-
const featureDir =
|
|
97755
|
-
const prdPath =
|
|
97794
|
+
const naxDir = join71(resolved.projectDir, ".nax");
|
|
97795
|
+
const featureDir = join71(naxDir, "features", featureName);
|
|
97796
|
+
const prdPath = join71(featureDir, "prd.json");
|
|
97756
97797
|
if (!existsSync29(featureDir)) {
|
|
97757
97798
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
97758
97799
|
process.exit(1);
|
|
@@ -97774,8 +97815,8 @@ async function precheckCommand(options) {
|
|
|
97774
97815
|
// src/commands/runs.ts
|
|
97775
97816
|
init_source();
|
|
97776
97817
|
init_paths3();
|
|
97777
|
-
import { readdir as
|
|
97778
|
-
import { join as
|
|
97818
|
+
import { readdir as readdir4 } from "fs/promises";
|
|
97819
|
+
import { join as join72 } from "path";
|
|
97779
97820
|
var DEFAULT_LIMIT = 20;
|
|
97780
97821
|
var _runsCmdDeps = {
|
|
97781
97822
|
getRunsDir
|
|
@@ -97823,14 +97864,14 @@ async function runsCommand(options = {}) {
|
|
|
97823
97864
|
const runsDir = _runsCmdDeps.getRunsDir();
|
|
97824
97865
|
let entries;
|
|
97825
97866
|
try {
|
|
97826
|
-
entries = await
|
|
97867
|
+
entries = await readdir4(runsDir);
|
|
97827
97868
|
} catch {
|
|
97828
97869
|
console.log("No runs found.");
|
|
97829
97870
|
return;
|
|
97830
97871
|
}
|
|
97831
97872
|
const rows = [];
|
|
97832
97873
|
for (const entry of entries) {
|
|
97833
|
-
const metaPath =
|
|
97874
|
+
const metaPath = join72(runsDir, entry, "meta.json");
|
|
97834
97875
|
let meta3;
|
|
97835
97876
|
try {
|
|
97836
97877
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -97907,7 +97948,7 @@ async function runsCommand(options = {}) {
|
|
|
97907
97948
|
|
|
97908
97949
|
// src/commands/unlock.ts
|
|
97909
97950
|
init_source();
|
|
97910
|
-
import { join as
|
|
97951
|
+
import { join as join73 } from "path";
|
|
97911
97952
|
function isProcessAlive2(pid) {
|
|
97912
97953
|
try {
|
|
97913
97954
|
process.kill(pid, 0);
|
|
@@ -97922,7 +97963,7 @@ function formatLockAge(ageMs) {
|
|
|
97922
97963
|
}
|
|
97923
97964
|
async function unlockCommand(options) {
|
|
97924
97965
|
const workdir = options.dir ?? process.cwd();
|
|
97925
|
-
const lockPath =
|
|
97966
|
+
const lockPath = join73(workdir, "nax.lock");
|
|
97926
97967
|
const lockFile = Bun.file(lockPath);
|
|
97927
97968
|
const exists = await lockFile.exists();
|
|
97928
97969
|
if (!exists) {
|
|
@@ -98009,7 +98050,7 @@ async function runCompletionPhase(options) {
|
|
|
98009
98050
|
} else if (options.config.acceptance.enabled && isComplete(options.prd)) {
|
|
98010
98051
|
options.statusWriter.setPostRunPhase("acceptance", { status: "running" });
|
|
98011
98052
|
pipelineEventBus.emit({ type: "postrun:phase:started", phase: "acceptance" });
|
|
98012
|
-
const acceptanceTestPaths = options.featureDir ? await Promise.all(groupStoriesByPackage(options.prd, options.workdir, options.feature, options.config.acceptance.testPath, options.config.project?.language).map(async (g) => {
|
|
98053
|
+
const acceptanceTestPaths = options.featureDir ? await Promise.all((await groupStoriesByPackage(options.prd, options.workdir, options.feature, options.config.acceptance.testPath, options.config.project?.language)).map(async (g) => {
|
|
98013
98054
|
const relativeWorkdir = path19.relative(options.workdir, g.packageDir);
|
|
98014
98055
|
let groupConfig = options.config;
|
|
98015
98056
|
if (relativeWorkdir && relativeWorkdir !== ".") {
|
|
@@ -106347,7 +106388,7 @@ Next: nax generate --package ${options.package}`));
|
|
|
106347
106388
|
}
|
|
106348
106389
|
return;
|
|
106349
106390
|
}
|
|
106350
|
-
const naxDir =
|
|
106391
|
+
const naxDir = join87(workdir, ".nax");
|
|
106351
106392
|
if (existsSync35(naxDir) && !options.force) {
|
|
106352
106393
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
106353
106394
|
return;
|
|
@@ -106376,11 +106417,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
106376
106417
|
}
|
|
106377
106418
|
}
|
|
106378
106419
|
}
|
|
106379
|
-
mkdirSync7(
|
|
106380
|
-
mkdirSync7(
|
|
106420
|
+
mkdirSync7(join87(naxDir, "features"), { recursive: true });
|
|
106421
|
+
mkdirSync7(join87(naxDir, "hooks"), { recursive: true });
|
|
106381
106422
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
106382
|
-
await Bun.write(
|
|
106383
|
-
await Bun.write(
|
|
106423
|
+
await Bun.write(join87(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
|
|
106424
|
+
await Bun.write(join87(naxDir, "hooks.json"), JSON.stringify({
|
|
106384
106425
|
hooks: {
|
|
106385
106426
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
106386
106427
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -106388,12 +106429,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
106388
106429
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
106389
106430
|
}
|
|
106390
106431
|
}, null, 2));
|
|
106391
|
-
await Bun.write(
|
|
106432
|
+
await Bun.write(join87(naxDir, ".gitignore"), `# nax temp files
|
|
106392
106433
|
*.tmp
|
|
106393
106434
|
.paused.json
|
|
106394
106435
|
.nax-verifier-verdict.json
|
|
106395
106436
|
`);
|
|
106396
|
-
await Bun.write(
|
|
106437
|
+
await Bun.write(join87(naxDir, "context.md"), `# Project Context
|
|
106397
106438
|
|
|
106398
106439
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
106399
106440
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -106541,8 +106582,8 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106541
106582
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106542
106583
|
process.exit(1);
|
|
106543
106584
|
}
|
|
106544
|
-
const featureDir =
|
|
106545
|
-
const prdPath =
|
|
106585
|
+
const featureDir = join87(naxDir, "features", options.feature);
|
|
106586
|
+
const prdPath = join87(featureDir, "prd.json");
|
|
106546
106587
|
if (options.plan && options.from) {
|
|
106547
106588
|
if (existsSync35(prdPath) && !options.force) {
|
|
106548
106589
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
@@ -106564,10 +106605,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106564
106605
|
}
|
|
106565
106606
|
}
|
|
106566
106607
|
try {
|
|
106567
|
-
const planLogDir =
|
|
106608
|
+
const planLogDir = join87(featureDir, "plan");
|
|
106568
106609
|
mkdirSync7(planLogDir, { recursive: true });
|
|
106569
106610
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106570
|
-
const planLogPath =
|
|
106611
|
+
const planLogPath = join87(planLogDir, `${planLogId}.jsonl`);
|
|
106571
106612
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106572
106613
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106573
106614
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -106613,10 +106654,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106613
106654
|
resetLogger();
|
|
106614
106655
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
106615
106656
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
106616
|
-
const runsDir =
|
|
106657
|
+
const runsDir = join87(outputDir, "features", options.feature, "runs");
|
|
106617
106658
|
mkdirSync7(runsDir, { recursive: true });
|
|
106618
106659
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106619
|
-
const logFilePath =
|
|
106660
|
+
const logFilePath = join87(runsDir, `${runId}.jsonl`);
|
|
106620
106661
|
const isTTY = process.stdout.isTTY ?? false;
|
|
106621
106662
|
const headlessFlag = options.headless ?? false;
|
|
106622
106663
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -106634,7 +106675,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106634
106675
|
config2.agent.default = options.agent;
|
|
106635
106676
|
}
|
|
106636
106677
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
106637
|
-
const globalNaxDir =
|
|
106678
|
+
const globalNaxDir = join87(homedir3(), ".nax");
|
|
106638
106679
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
106639
106680
|
const eventEmitter = new PipelineEventEmitter;
|
|
106640
106681
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -106654,12 +106695,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106654
106695
|
events: eventEmitter,
|
|
106655
106696
|
ptyOptions: null,
|
|
106656
106697
|
agentStreamEvents,
|
|
106657
|
-
queueFilePath:
|
|
106698
|
+
queueFilePath: join87(workdir, ".queue.txt")
|
|
106658
106699
|
});
|
|
106659
106700
|
} else {
|
|
106660
106701
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
106661
106702
|
}
|
|
106662
|
-
const statusFilePath =
|
|
106703
|
+
const statusFilePath = join87(outputDir, "status.json");
|
|
106663
106704
|
let parallel;
|
|
106664
106705
|
if (options.parallel !== undefined) {
|
|
106665
106706
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -106686,7 +106727,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106686
106727
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
106687
106728
|
agentStreamEvents
|
|
106688
106729
|
});
|
|
106689
|
-
const latestSymlink =
|
|
106730
|
+
const latestSymlink = join87(runsDir, "latest.jsonl");
|
|
106690
106731
|
try {
|
|
106691
106732
|
if (existsSync35(latestSymlink)) {
|
|
106692
106733
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
@@ -106747,9 +106788,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106747
106788
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106748
106789
|
process.exit(1);
|
|
106749
106790
|
}
|
|
106750
|
-
const featureDir =
|
|
106791
|
+
const featureDir = join87(naxDir, "features", name);
|
|
106751
106792
|
mkdirSync7(featureDir, { recursive: true });
|
|
106752
|
-
await Bun.write(
|
|
106793
|
+
await Bun.write(join87(featureDir, "spec.md"), `# Feature: ${name}
|
|
106753
106794
|
|
|
106754
106795
|
## Overview
|
|
106755
106796
|
|
|
@@ -106782,7 +106823,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106782
106823
|
|
|
106783
106824
|
<!-- What this feature explicitly does NOT cover. -->
|
|
106784
106825
|
`);
|
|
106785
|
-
await Bun.write(
|
|
106826
|
+
await Bun.write(join87(featureDir, "progress.txt"), `# Progress: ${name}
|
|
106786
106827
|
|
|
106787
106828
|
Created: ${new Date().toISOString()}
|
|
106788
106829
|
|
|
@@ -106808,7 +106849,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106808
106849
|
console.error(source_default.red("nax not initialized."));
|
|
106809
106850
|
process.exit(1);
|
|
106810
106851
|
}
|
|
106811
|
-
const featuresDir =
|
|
106852
|
+
const featuresDir = join87(naxDir, "features");
|
|
106812
106853
|
if (!existsSync35(featuresDir)) {
|
|
106813
106854
|
console.log(source_default.dim("No features yet."));
|
|
106814
106855
|
return;
|
|
@@ -106823,7 +106864,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106823
106864
|
Features:
|
|
106824
106865
|
`));
|
|
106825
106866
|
for (const name of entries) {
|
|
106826
|
-
const prdPath =
|
|
106867
|
+
const prdPath = join87(featuresDir, name, "prd.json");
|
|
106827
106868
|
if (existsSync35(prdPath)) {
|
|
106828
106869
|
const prd = await loadPRD(prdPath);
|
|
106829
106870
|
const c = countStories(prd);
|
|
@@ -106858,10 +106899,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
106858
106899
|
cliOverrides.profile = options.profile;
|
|
106859
106900
|
}
|
|
106860
106901
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
106861
|
-
const featureLogDir =
|
|
106902
|
+
const featureLogDir = join87(naxDir, "features", options.feature, "plan");
|
|
106862
106903
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
106863
106904
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106864
|
-
const planLogPath =
|
|
106905
|
+
const planLogPath = join87(featureLogDir, `${planLogId}.jsonl`);
|
|
106865
106906
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106866
106907
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106867
106908
|
try {
|