@nathapp/nax 0.69.1 → 0.69.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nax.js +570 -454
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -16983,10 +16983,10 @@ var init_schemas_execution = __esm(() => {
|
|
|
16983
16983
|
autoApproveVerifier: exports_external.boolean(),
|
|
16984
16984
|
strategy: exports_external.enum(["auto", "strict", "lite", "off"]).default("auto"),
|
|
16985
16985
|
sessionTiers: exports_external.object({
|
|
16986
|
-
testWriter:
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
}).
|
|
16986
|
+
testWriter: ConfiguredModelSchema.default("fast"),
|
|
16987
|
+
verifier: ConfiguredModelSchema.default("fast"),
|
|
16988
|
+
implementer: ConfiguredModelSchema.optional()
|
|
16989
|
+
}).default({ testWriter: "fast", verifier: "fast" }),
|
|
16990
16990
|
testWriterAllowedPaths: exports_external.array(exports_external.string()).optional(),
|
|
16991
16991
|
rollbackOnFailure: exports_external.boolean().optional(),
|
|
16992
16992
|
greenfieldDetection: exports_external.boolean().optional()
|
|
@@ -17413,7 +17413,7 @@ var init_schemas3 = __esm(() => {
|
|
|
17413
17413
|
autoApproveVerifier: true,
|
|
17414
17414
|
strategy: "auto",
|
|
17415
17415
|
sessionTiers: {
|
|
17416
|
-
testWriter: "
|
|
17416
|
+
testWriter: "fast",
|
|
17417
17417
|
verifier: "fast"
|
|
17418
17418
|
},
|
|
17419
17419
|
testWriterAllowedPaths: ["src/index.ts", "src/**/index.ts"],
|
|
@@ -18946,6 +18946,14 @@ ${errors3.join(`
|
|
|
18946
18946
|
}
|
|
18947
18947
|
return result.data;
|
|
18948
18948
|
}
|
|
18949
|
+
async function loadPackageOverride(repoRoot, packageDir) {
|
|
18950
|
+
const packageConfigPath = join3(repoRoot, PROJECT_NAX_DIR, "mono", packageDir, "config.json");
|
|
18951
|
+
const override = await loadJsonFile(packageConfigPath, "config");
|
|
18952
|
+
if (!override)
|
|
18953
|
+
return null;
|
|
18954
|
+
const { profile: _profile, ...fields } = override;
|
|
18955
|
+
return fields;
|
|
18956
|
+
}
|
|
18949
18957
|
async function loadConfigForWorkdir(rootConfigPath, packageDir, cliOverrides) {
|
|
18950
18958
|
const logger = getLogger();
|
|
18951
18959
|
const resolvedRootConfigPath = resolve3(rootConfigPath);
|
|
@@ -19416,8 +19424,10 @@ __export(exports_config, {
|
|
|
19416
19424
|
precheckConfigSelector: () => precheckConfigSelector,
|
|
19417
19425
|
planConfigSelector: () => planConfigSelector,
|
|
19418
19426
|
pickSelector: () => pickSelector,
|
|
19427
|
+
mergePackageConfig: () => mergePackageConfig,
|
|
19419
19428
|
loadProfileEnv: () => loadProfileEnv,
|
|
19420
19429
|
loadProfile: () => loadProfile,
|
|
19430
|
+
loadPackageOverride: () => loadPackageOverride,
|
|
19421
19431
|
loadConfigForWorkdir: () => loadConfigForWorkdir,
|
|
19422
19432
|
loadConfig: () => loadConfig,
|
|
19423
19433
|
llmRoutingConfigSelector: () => llmRoutingConfigSelector,
|
|
@@ -19442,6 +19452,7 @@ __export(exports_config, {
|
|
|
19442
19452
|
acceptanceFixConfigSelector: () => acceptanceFixConfigSelector,
|
|
19443
19453
|
acceptanceConfigSelector: () => acceptanceConfigSelector,
|
|
19444
19454
|
VALID_TEST_STRATEGIES: () => VALID_TEST_STRATEGIES,
|
|
19455
|
+
TddConfigSchema: () => TddConfigSchema,
|
|
19445
19456
|
THREE_SESSION_STRATEGIES: () => THREE_SESSION_STRATEGIES,
|
|
19446
19457
|
TEST_STRATEGY_GUIDE: () => TEST_STRATEGY_GUIDE,
|
|
19447
19458
|
SPEC_ANCHOR_RULES: () => SPEC_ANCHOR_RULES,
|
|
@@ -19463,6 +19474,7 @@ var init_config = __esm(() => {
|
|
|
19463
19474
|
init_schema();
|
|
19464
19475
|
init_schemas_model();
|
|
19465
19476
|
init_schemas_debate();
|
|
19477
|
+
init_schemas_execution();
|
|
19466
19478
|
init_loader();
|
|
19467
19479
|
init_path_security();
|
|
19468
19480
|
init_paths();
|
|
@@ -23959,6 +23971,7 @@ var init_detect = __esm(() => {
|
|
|
23959
23971
|
});
|
|
23960
23972
|
|
|
23961
23973
|
// src/test-runners/detect/workspace.ts
|
|
23974
|
+
import { join as join6 } from "path";
|
|
23962
23975
|
async function expandWorkspaceGlob(workdir, pattern) {
|
|
23963
23976
|
const dirs = [];
|
|
23964
23977
|
try {
|
|
@@ -24032,15 +24045,31 @@ async function detectTurboOrNx(workdir) {
|
|
|
24032
24045
|
}
|
|
24033
24046
|
async function detectNaxMonoLayout(workdir) {
|
|
24034
24047
|
const dirs = [];
|
|
24035
|
-
|
|
24036
|
-
|
|
24037
|
-
|
|
24038
|
-
|
|
24039
|
-
|
|
24040
|
-
|
|
24041
|
-
|
|
24048
|
+
const monoRoot = join6(workdir, ".nax", "mono");
|
|
24049
|
+
async function walk(currentDir, relativeParts) {
|
|
24050
|
+
const entries = [];
|
|
24051
|
+
for await (const entry of _workspaceDeps.glob("*", currentDir)) {
|
|
24052
|
+
entries.push(entry);
|
|
24053
|
+
}
|
|
24054
|
+
let hasConfig = false;
|
|
24055
|
+
for (const entry of entries) {
|
|
24056
|
+
const entryPath = join6(currentDir, entry);
|
|
24057
|
+
const stat = await _workspaceDeps.stat(entryPath);
|
|
24058
|
+
const isDirectory = (stat.mode & 61440) === 16384;
|
|
24059
|
+
if (!isDirectory && entry === "config.json") {
|
|
24060
|
+
hasConfig = true;
|
|
24061
|
+
continue;
|
|
24062
|
+
}
|
|
24063
|
+
if (isDirectory) {
|
|
24064
|
+
await walk(entryPath, [...relativeParts, entry]);
|
|
24042
24065
|
}
|
|
24043
24066
|
}
|
|
24067
|
+
if (hasConfig && relativeParts.length > 0) {
|
|
24068
|
+
dirs.push(relativeParts.join("/"));
|
|
24069
|
+
}
|
|
24070
|
+
}
|
|
24071
|
+
try {
|
|
24072
|
+
await walk(monoRoot, []);
|
|
24044
24073
|
} catch {}
|
|
24045
24074
|
return dirs;
|
|
24046
24075
|
}
|
|
@@ -24084,7 +24113,8 @@ var init_workspace = __esm(() => {
|
|
|
24084
24113
|
return f.text();
|
|
24085
24114
|
},
|
|
24086
24115
|
spawn: Bun.spawn,
|
|
24087
|
-
glob: (pattern, cwd) => new Bun.Glob(pattern).scan({ cwd, onlyFiles: false })
|
|
24116
|
+
glob: (pattern, cwd) => new Bun.Glob(pattern).scan({ cwd, onlyFiles: false }),
|
|
24117
|
+
stat: (path) => Bun.file(path).stat()
|
|
24088
24118
|
};
|
|
24089
24119
|
_workspaceCache = new Map;
|
|
24090
24120
|
});
|
|
@@ -24158,7 +24188,7 @@ var init_detector2 = __esm(() => {
|
|
|
24158
24188
|
});
|
|
24159
24189
|
|
|
24160
24190
|
// src/test-runners/resolver.ts
|
|
24161
|
-
import { dirname as dirname2, isAbsolute as isAbsolute3, join as
|
|
24191
|
+
import { dirname as dirname2, isAbsolute as isAbsolute3, join as join7, relative, resolve as resolve4 } from "path";
|
|
24162
24192
|
function buildResolved(globs, resolution) {
|
|
24163
24193
|
return {
|
|
24164
24194
|
globs,
|
|
@@ -24210,7 +24240,7 @@ async function resolveTestFilePatterns(config2, workdir, packageDir, options) {
|
|
|
24210
24240
|
validateGlobs(rootPatterns, "resolver");
|
|
24211
24241
|
return buildResolved(rootPatterns, "root-config");
|
|
24212
24242
|
}
|
|
24213
|
-
const detectionWorkdir = packageDir ?
|
|
24243
|
+
const detectionWorkdir = packageDir ? join7(workdir, packageDir) : workdir;
|
|
24214
24244
|
const detected = await _resolverDeps.detectTestFilePatterns(detectionWorkdir);
|
|
24215
24245
|
if (detected.confidence !== "empty" && detected.patterns.length > 0) {
|
|
24216
24246
|
getSafeLogger()?.info("resolver", "Test patterns auto-detected", {
|
|
@@ -24789,7 +24819,7 @@ var init_git = __esm(() => {
|
|
|
24789
24819
|
});
|
|
24790
24820
|
|
|
24791
24821
|
// src/utils/path-filters.ts
|
|
24792
|
-
import { join as
|
|
24822
|
+
import { join as join8, relative as relative2 } from "path";
|
|
24793
24823
|
function basename3(path) {
|
|
24794
24824
|
const stripped = path.startsWith("./") ? path.slice(2) : path;
|
|
24795
24825
|
const idx = stripped.lastIndexOf("/");
|
|
@@ -24879,8 +24909,8 @@ async function resolveNaxIgnorePatterns(repoRoot, packageDir) {
|
|
|
24879
24909
|
const normalizedRepoRoot = normalizePath(repoRoot);
|
|
24880
24910
|
const normalizedPackageDir = packageDir ? normalizePath(packageDir) : normalizedRepoRoot;
|
|
24881
24911
|
const packagePrefix = normalizedPackageDir !== normalizedRepoRoot ? normalizePath(relative2(repoRoot, packageDir ?? repoRoot)) : null;
|
|
24882
|
-
const rootFile =
|
|
24883
|
-
const packageFile =
|
|
24912
|
+
const rootFile = join8(repoRoot, NAX_IGNORE_FILENAME);
|
|
24913
|
+
const packageFile = join8(packageDir ?? repoRoot, NAX_IGNORE_FILENAME);
|
|
24884
24914
|
const rootPatterns = await readIgnorePatterns(rootFile);
|
|
24885
24915
|
const packagePatterns = packageDir && packageDir !== repoRoot ? await readIgnorePatterns(packageFile) : [];
|
|
24886
24916
|
return [
|
|
@@ -24949,7 +24979,7 @@ var init_path_filters = __esm(() => {
|
|
|
24949
24979
|
});
|
|
24950
24980
|
|
|
24951
24981
|
// src/verification/smart-runner.ts
|
|
24952
|
-
import { join as
|
|
24982
|
+
import { join as join9, relative as relative3 } from "path";
|
|
24953
24983
|
function clearGitRootCache() {
|
|
24954
24984
|
_gitRootCache.clear();
|
|
24955
24985
|
}
|
|
@@ -25067,7 +25097,7 @@ async function getChangedNonTestFiles(workdir, baseRef, packagePrefix, testFileR
|
|
|
25067
25097
|
const lines = stdout.trim().split(`
|
|
25068
25098
|
`).filter(Boolean);
|
|
25069
25099
|
const effectiveRepoRoot = repoRoot ?? workdir;
|
|
25070
|
-
const packageDir = packagePrefix ?
|
|
25100
|
+
const packageDir = packagePrefix ? join9(effectiveRepoRoot, packagePrefix) : undefined;
|
|
25071
25101
|
const ignoreMatchers = naxIgnoreIndex?.getMatchers(packageDir) ?? await resolveNaxIgnorePatterns(effectiveRepoRoot, packageDir);
|
|
25072
25102
|
let effectivePrefix = packagePrefix;
|
|
25073
25103
|
if (packagePrefix && repoRoot) {
|
|
@@ -25096,7 +25126,7 @@ async function getChangedTestFiles(workdir, repoRoot, baseRef, packagePrefix, te
|
|
|
25096
25126
|
return [];
|
|
25097
25127
|
const lines = stdout.trim().split(`
|
|
25098
25128
|
`).filter(Boolean);
|
|
25099
|
-
const packageDir = packagePrefix ?
|
|
25129
|
+
const packageDir = packagePrefix ? join9(repoRoot, packagePrefix) : undefined;
|
|
25100
25130
|
const ignoreMatchers = naxIgnoreIndex?.getMatchers(packageDir) ?? await resolveNaxIgnorePatterns(repoRoot, packageDir);
|
|
25101
25131
|
const gitRoot = await getGitRootMemo(workdir);
|
|
25102
25132
|
const extraPrefix = gitRoot && gitRoot !== repoRoot ? relative3(gitRoot, repoRoot) : "";
|
|
@@ -25104,7 +25134,7 @@ async function getChangedTestFiles(workdir, repoRoot, baseRef, packagePrefix, te
|
|
|
25104
25134
|
const scopedRaw = effectivePrefix ? lines.filter((f) => f.startsWith(`${effectivePrefix}/`)) : lines;
|
|
25105
25135
|
const scoped = filterNaxInternalPaths(scopedRaw, ignoreMatchers);
|
|
25106
25136
|
const stripped = extraPrefix ? scoped.map((f) => f.slice(`${extraPrefix}/`.length)) : scoped;
|
|
25107
|
-
return stripped.filter((f) => testFileRegex.some((re) => re.test(f))).map((f) =>
|
|
25137
|
+
return stripped.filter((f) => testFileRegex.some((re) => re.test(f))).map((f) => join9(repoRoot, f));
|
|
25108
25138
|
} catch {
|
|
25109
25139
|
return [];
|
|
25110
25140
|
}
|
|
@@ -25236,6 +25266,7 @@ __export(exports_test_runners, {
|
|
|
25236
25266
|
formatFailureSummary: () => formatFailureSummary,
|
|
25237
25267
|
findPackageDir: () => findPackageDir,
|
|
25238
25268
|
extractTestDirs: () => extractTestDirs,
|
|
25269
|
+
discoverWorkspacePackages: () => discoverWorkspacePackages,
|
|
25239
25270
|
detectTestFilePatterns: () => detectTestFilePatterns,
|
|
25240
25271
|
detectManifestFrameworksFromPackageJson: () => detectManifestFrameworksFromPackageJson,
|
|
25241
25272
|
detectFramework: () => detectFramework,
|
|
@@ -25257,6 +25288,7 @@ var init_test_runners = __esm(() => {
|
|
|
25257
25288
|
init_detector2();
|
|
25258
25289
|
init_resolver();
|
|
25259
25290
|
init_parser();
|
|
25291
|
+
init_workspace();
|
|
25260
25292
|
init_ac_parser();
|
|
25261
25293
|
init_scoped_selection();
|
|
25262
25294
|
});
|
|
@@ -25308,7 +25340,7 @@ var init_project = __esm(() => {
|
|
|
25308
25340
|
|
|
25309
25341
|
// src/utils/path-security.ts
|
|
25310
25342
|
import { realpathSync as realpathSync2 } from "fs";
|
|
25311
|
-
import { dirname as dirname3, isAbsolute as isAbsolute4, join as
|
|
25343
|
+
import { dirname as dirname3, isAbsolute as isAbsolute4, join as join10, normalize as normalize3, resolve as resolve5 } from "path";
|
|
25312
25344
|
function safeRealpathForComparison(p) {
|
|
25313
25345
|
try {
|
|
25314
25346
|
return realpathSync2(p);
|
|
@@ -25317,7 +25349,7 @@ function safeRealpathForComparison(p) {
|
|
|
25317
25349
|
if (parent === p)
|
|
25318
25350
|
return normalize3(p);
|
|
25319
25351
|
const resolvedParent = safeRealpathForComparison(parent);
|
|
25320
|
-
return
|
|
25352
|
+
return join10(resolvedParent, p.split("/").pop() ?? "");
|
|
25321
25353
|
}
|
|
25322
25354
|
}
|
|
25323
25355
|
function isRelativeAndSafe(filePath) {
|
|
@@ -25345,7 +25377,7 @@ function validateModulePath(modulePath, allowedRoots) {
|
|
|
25345
25377
|
} else {
|
|
25346
25378
|
for (let i = 0;i < allowedRoots.length; i++) {
|
|
25347
25379
|
const originalRoot = resolve5(allowedRoots[i]);
|
|
25348
|
-
const absoluteInput = resolve5(
|
|
25380
|
+
const absoluteInput = resolve5(join10(originalRoot, modulePath));
|
|
25349
25381
|
const resolved = safeRealpathForComparison(absoluteInput);
|
|
25350
25382
|
const resolvedRoot = resolvedRoots[i];
|
|
25351
25383
|
if (resolved.startsWith(`${resolvedRoot}/`) || resolved === resolvedRoot) {
|
|
@@ -25362,7 +25394,7 @@ var init_path_security2 = () => {};
|
|
|
25362
25394
|
|
|
25363
25395
|
// src/context/engine/providers/code-neighbor.ts
|
|
25364
25396
|
import { createHash as createHash3 } from "crypto";
|
|
25365
|
-
import { join as
|
|
25397
|
+
import { join as join11, relative as relative4, resolve as resolve6 } from "path";
|
|
25366
25398
|
function isExcludedPath(file3, ignoreMatchers) {
|
|
25367
25399
|
for (const prefix of EXCLUDED_DIR_PREFIXES2) {
|
|
25368
25400
|
if (file3.startsWith(prefix) || file3.includes(`/${prefix}`))
|
|
@@ -25500,7 +25532,7 @@ async function readCached(absolutePath, cache) {
|
|
|
25500
25532
|
async function collectNeighbors(filePath, workdir, scannedDirs, contentCache, siblingTestContext) {
|
|
25501
25533
|
const neighbors = new Set;
|
|
25502
25534
|
let anyTruncated = false;
|
|
25503
|
-
const ownAbsPath =
|
|
25535
|
+
const ownAbsPath = join11(workdir, filePath);
|
|
25504
25536
|
if (await _codeNeighborDeps.fileExists(ownAbsPath)) {
|
|
25505
25537
|
const ownContent = await readCached(ownAbsPath, contentCache);
|
|
25506
25538
|
if (ownContent !== null && ownContent.length > 0) {
|
|
@@ -25522,7 +25554,7 @@ async function collectNeighbors(filePath, workdir, scannedDirs, contentCache, si
|
|
|
25522
25554
|
break outer;
|
|
25523
25555
|
if (srcFile === filePath)
|
|
25524
25556
|
continue;
|
|
25525
|
-
const content = await readCached(
|
|
25557
|
+
const content = await readCached(join11(scanWorkdir, srcFile), contentCache);
|
|
25526
25558
|
if (content?.includes(fileBaseName)) {
|
|
25527
25559
|
for (const spec of parseImportSpecifiers(content)) {
|
|
25528
25560
|
const resolved = resolveImport(spec, srcFile, scanWorkdir);
|
|
@@ -25538,7 +25570,7 @@ async function collectNeighbors(filePath, workdir, scannedDirs, contentCache, si
|
|
|
25538
25570
|
const candidates = deriveSiblingTestCandidates(filePath, siblingTestContext.globs);
|
|
25539
25571
|
let chosen = null;
|
|
25540
25572
|
for (const candidate of candidates) {
|
|
25541
|
-
if (await _codeNeighborDeps.fileExists(
|
|
25573
|
+
if (await _codeNeighborDeps.fileExists(join11(workdir, candidate))) {
|
|
25542
25574
|
chosen = candidate;
|
|
25543
25575
|
break;
|
|
25544
25576
|
}
|
|
@@ -25562,7 +25594,7 @@ async function resolveExtraGlobWorkdirs(neighborScope, crossPackageDepth, repoRo
|
|
|
25562
25594
|
const relPkgDirs = await _codeNeighborDeps.discoverWorkspacePackages(repoRoot);
|
|
25563
25595
|
if (relPkgDirs.length === 0)
|
|
25564
25596
|
return [repoRoot];
|
|
25565
|
-
return relPkgDirs.map((rel) =>
|
|
25597
|
+
return relPkgDirs.map((rel) => join11(repoRoot, rel)).filter((abs) => abs !== packageDir);
|
|
25566
25598
|
} catch {
|
|
25567
25599
|
return [repoRoot];
|
|
25568
25600
|
}
|
|
@@ -26859,7 +26891,7 @@ var init_orchestrator = __esm(() => {
|
|
|
26859
26891
|
});
|
|
26860
26892
|
|
|
26861
26893
|
// src/context/rules/canonical-loader.ts
|
|
26862
|
-
import { basename as basename4, join as
|
|
26894
|
+
import { basename as basename4, join as join12 } from "path";
|
|
26863
26895
|
function parseRuleAllowMarker(line) {
|
|
26864
26896
|
const allowed = new Set;
|
|
26865
26897
|
RULE_ALLOW_MARKER.lastIndex = 0;
|
|
@@ -26994,7 +27026,7 @@ function applyCanonicalRulesBudget(rules, budgetTokens) {
|
|
|
26994
27026
|
}
|
|
26995
27027
|
async function loadCanonicalRules(workdir, options = {}) {
|
|
26996
27028
|
const logger = _canonicalLoaderDeps.getLogger();
|
|
26997
|
-
const rulesDir =
|
|
27029
|
+
const rulesDir = join12(workdir, CANONICAL_RULES_DIR);
|
|
26998
27030
|
const allFilePaths = _canonicalLoaderDeps.globInDir(rulesDir);
|
|
26999
27031
|
const filePaths = allFilePaths.filter((filePath) => {
|
|
27000
27032
|
const normalized = filePath.replaceAll("\\", "/");
|
|
@@ -27095,7 +27127,7 @@ var init_canonical_loader = __esm(() => {
|
|
|
27095
27127
|
for (const rel of files) {
|
|
27096
27128
|
const depth = rel.split("/").length - 1;
|
|
27097
27129
|
if (depth <= 1) {
|
|
27098
|
-
kept.push(
|
|
27130
|
+
kept.push(join12(dir, rel));
|
|
27099
27131
|
} else {
|
|
27100
27132
|
ignored.push(rel);
|
|
27101
27133
|
}
|
|
@@ -27377,7 +27409,7 @@ var init_session_scratch = __esm(() => {
|
|
|
27377
27409
|
|
|
27378
27410
|
// src/context/engine/providers/static-rules.ts
|
|
27379
27411
|
import { createHash as createHash8 } from "crypto";
|
|
27380
|
-
import { join as
|
|
27412
|
+
import { join as join13, relative as relative5 } from "path";
|
|
27381
27413
|
function contentHash85(content) {
|
|
27382
27414
|
return createHash8("sha256").update(content).digest("hex").slice(0, 8);
|
|
27383
27415
|
}
|
|
@@ -27585,7 +27617,7 @@ ${rule.content}`,
|
|
|
27585
27617
|
const existingCandidates = [];
|
|
27586
27618
|
for (const fileName of LEGACY_CANDIDATE_FILES) {
|
|
27587
27619
|
try {
|
|
27588
|
-
if (await _staticRulesDeps.fileExists(
|
|
27620
|
+
if (await _staticRulesDeps.fileExists(join13(rootDir, fileName))) {
|
|
27589
27621
|
existingCandidates.push(fileName);
|
|
27590
27622
|
}
|
|
27591
27623
|
} catch {}
|
|
@@ -27601,11 +27633,11 @@ ${rule.content}`,
|
|
|
27601
27633
|
for (const fileName of LEGACY_CANDIDATE_FILES) {
|
|
27602
27634
|
legacySources.push({
|
|
27603
27635
|
sourceId: fileName,
|
|
27604
|
-
filePath:
|
|
27636
|
+
filePath: join13(rootDir, fileName),
|
|
27605
27637
|
heading: fileName
|
|
27606
27638
|
});
|
|
27607
27639
|
}
|
|
27608
|
-
const rulesDir =
|
|
27640
|
+
const rulesDir = join13(rootDir, LEGACY_RULES_DIR);
|
|
27609
27641
|
const nestedRulePaths = _staticRulesDeps.globInDir(rulesDir);
|
|
27610
27642
|
for (const filePath of nestedRulePaths) {
|
|
27611
27643
|
const normalized = normalizePath2(filePath);
|
|
@@ -27664,7 +27696,7 @@ var init_static_rules = __esm(() => {
|
|
|
27664
27696
|
fileExists: async (path) => Bun.file(path).exists(),
|
|
27665
27697
|
globInDir: (dir) => {
|
|
27666
27698
|
try {
|
|
27667
|
-
return [...new Bun.Glob("**/*.md").scanSync({ cwd: dir, absolute: false })].sort().map((f) =>
|
|
27699
|
+
return [...new Bun.Glob("**/*.md").scanSync({ cwd: dir, absolute: false })].sort().map((f) => join13(dir, f));
|
|
27668
27700
|
} catch {
|
|
27669
27701
|
return [];
|
|
27670
27702
|
}
|
|
@@ -28003,7 +28035,7 @@ function validateStory(raw, index, allIds) {
|
|
|
28003
28035
|
routing: {
|
|
28004
28036
|
complexity,
|
|
28005
28037
|
testStrategy,
|
|
28006
|
-
reasoning: "validated from LLM output",
|
|
28038
|
+
reasoning: typeof routing.reasoning === "string" && routing.reasoning.trim().length > 0 ? routing.reasoning.trim() : "validated from LLM output",
|
|
28007
28039
|
...noTestJustification !== undefined ? { noTestJustification } : {}
|
|
28008
28040
|
},
|
|
28009
28041
|
...workdir !== undefined ? { workdir } : {},
|
|
@@ -28554,7 +28586,7 @@ var init_orchestrator_factory = __esm(() => {
|
|
|
28554
28586
|
});
|
|
28555
28587
|
|
|
28556
28588
|
// src/context/engine/providers/plugin-loader.ts
|
|
28557
|
-
import { isAbsolute as isAbsolute5, join as
|
|
28589
|
+
import { isAbsolute as isAbsolute5, join as join14, resolve as resolve7 } from "path";
|
|
28558
28590
|
function isInitialisable(p) {
|
|
28559
28591
|
return typeof p.init === "function";
|
|
28560
28592
|
}
|
|
@@ -28582,7 +28614,7 @@ function resolveModuleSpecifier(specifier, workdir) {
|
|
|
28582
28614
|
}
|
|
28583
28615
|
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
28584
28616
|
const resolvedWorkdir = resolve7(workdir);
|
|
28585
|
-
const resolved = resolve7(
|
|
28617
|
+
const resolved = resolve7(join14(workdir, specifier));
|
|
28586
28618
|
if (resolved !== resolvedWorkdir && !resolved.startsWith(`${resolvedWorkdir}/`)) {
|
|
28587
28619
|
throw new Error(`Plugin module path escapes project workdir: "${specifier}" resolves to "${resolved}" (workdir: "${resolvedWorkdir}")`);
|
|
28588
28620
|
}
|
|
@@ -28728,15 +28760,15 @@ var init_available_budget = __esm(() => {
|
|
|
28728
28760
|
|
|
28729
28761
|
// src/context/engine/manifest-store.ts
|
|
28730
28762
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
28731
|
-
import { dirname as dirname5, isAbsolute as isAbsolute6, join as
|
|
28763
|
+
import { dirname as dirname5, isAbsolute as isAbsolute6, join as join15, relative as relative7, resolve as resolve8 } from "path";
|
|
28732
28764
|
function contextStoryDir(projectDir, featureId, storyId) {
|
|
28733
|
-
return
|
|
28765
|
+
return join15(projectDir, ".nax", "features", featureId, "stories", storyId);
|
|
28734
28766
|
}
|
|
28735
28767
|
function contextManifestPath(projectDir, featureId, storyId, stage) {
|
|
28736
|
-
return
|
|
28768
|
+
return join15(contextStoryDir(projectDir, featureId, storyId), `context-manifest-${stage}.json`);
|
|
28737
28769
|
}
|
|
28738
28770
|
function rebuildManifestPath(projectDir, featureId, storyId) {
|
|
28739
|
-
return
|
|
28771
|
+
return join15(contextStoryDir(projectDir, featureId, storyId), "rebuild-manifest.json");
|
|
28740
28772
|
}
|
|
28741
28773
|
function toStoredPath(projectDir, pathValue) {
|
|
28742
28774
|
const relativePath = isAbsolute6(pathValue) ? relative7(projectDir, pathValue) : pathValue;
|
|
@@ -28792,7 +28824,7 @@ async function loadContextManifests(projectDir, storyId, featureId) {
|
|
|
28792
28824
|
const storyDir = contextStoryDir(projectDir, feature, storyId);
|
|
28793
28825
|
const manifestFiles = await _manifestStoreDeps.listManifestFiles(storyDir);
|
|
28794
28826
|
for (const fileName of manifestFiles) {
|
|
28795
|
-
const fullPath =
|
|
28827
|
+
const fullPath = join15(storyDir, fileName);
|
|
28796
28828
|
if (!await _manifestStoreDeps.fileExists(fullPath))
|
|
28797
28829
|
continue;
|
|
28798
28830
|
try {
|
|
@@ -28817,7 +28849,7 @@ var init_manifest_store = __esm(() => {
|
|
|
28817
28849
|
fileExists: (path2) => Bun.file(path2).exists(),
|
|
28818
28850
|
readFile: (path2) => Bun.file(path2).text(),
|
|
28819
28851
|
listFeatureDirs: async (projectDir) => {
|
|
28820
|
-
const baseDir =
|
|
28852
|
+
const baseDir = join15(projectDir, ".nax", "features");
|
|
28821
28853
|
try {
|
|
28822
28854
|
const dirs = [];
|
|
28823
28855
|
for await (const entry of new Bun.Glob("*").scan({ cwd: baseDir, absolute: false })) {
|
|
@@ -28844,7 +28876,7 @@ var init_manifest_store = __esm(() => {
|
|
|
28844
28876
|
|
|
28845
28877
|
// src/context/engine/stage-assembler.ts
|
|
28846
28878
|
import { readdir } from "fs/promises";
|
|
28847
|
-
import { isAbsolute as isAbsolute7, join as
|
|
28879
|
+
import { isAbsolute as isAbsolute7, join as join16, resolve as resolve9 } from "path";
|
|
28848
28880
|
function dedupeScratchDirs(dirs) {
|
|
28849
28881
|
return [...new Set(dirs.filter((dir) => Boolean(dir)))];
|
|
28850
28882
|
}
|
|
@@ -28853,7 +28885,7 @@ function toAbsolutePath2(projectDir, pathValue) {
|
|
|
28853
28885
|
}
|
|
28854
28886
|
async function discoverSessionScratchDirsOnDisk(projectDir, featureName, storyId, ttlMs) {
|
|
28855
28887
|
const logger = getLogger();
|
|
28856
|
-
const sessionsRoot =
|
|
28888
|
+
const sessionsRoot = join16(projectDir, ".nax", "features", featureName, "sessions");
|
|
28857
28889
|
let entries;
|
|
28858
28890
|
try {
|
|
28859
28891
|
entries = await _stageAssemblerDeps.readdir(sessionsRoot);
|
|
@@ -28863,7 +28895,7 @@ async function discoverSessionScratchDirsOnDisk(projectDir, featureName, storyId
|
|
|
28863
28895
|
const cutoff = _stageAssemblerDeps.now() - ttlMs;
|
|
28864
28896
|
const found = [];
|
|
28865
28897
|
for (const entry of entries) {
|
|
28866
|
-
const descriptorPath =
|
|
28898
|
+
const descriptorPath = join16(sessionsRoot, entry, "descriptor.json");
|
|
28867
28899
|
try {
|
|
28868
28900
|
const parsed = await _stageAssemblerDeps.readDescriptor(descriptorPath);
|
|
28869
28901
|
if (!parsed || parsed.storyId !== storyId || !parsed.scratchDir)
|
|
@@ -30528,13 +30560,13 @@ var exports_loader = {};
|
|
|
30528
30560
|
__export(exports_loader, {
|
|
30529
30561
|
loadOverride: () => loadOverride
|
|
30530
30562
|
});
|
|
30531
|
-
import { join as
|
|
30563
|
+
import { join as join17 } from "path";
|
|
30532
30564
|
async function loadOverride(role, workdir, config2) {
|
|
30533
30565
|
const overridePath = config2.prompts?.overrides?.[role];
|
|
30534
30566
|
if (!overridePath) {
|
|
30535
30567
|
return null;
|
|
30536
30568
|
}
|
|
30537
|
-
const absolutePath =
|
|
30569
|
+
const absolutePath = join17(workdir, overridePath);
|
|
30538
30570
|
const file3 = Bun.file(absolutePath);
|
|
30539
30571
|
if (!await file3.exists()) {
|
|
30540
30572
|
return null;
|
|
@@ -33201,11 +33233,11 @@ var init_prepare_inputs = __esm(() => {
|
|
|
33201
33233
|
});
|
|
33202
33234
|
|
|
33203
33235
|
// src/utils/nax-project-root.ts
|
|
33204
|
-
import { dirname as dirname6, join as
|
|
33236
|
+
import { dirname as dirname6, join as join18, resolve as resolve10 } from "path";
|
|
33205
33237
|
async function findNaxProjectRoot(startDir) {
|
|
33206
33238
|
let dir = resolve10(startDir);
|
|
33207
33239
|
for (let depth = 0;depth < MAX_NAX_WALK_DEPTH; depth++) {
|
|
33208
|
-
if (await _naxProjectRootDeps.exists(
|
|
33240
|
+
if (await _naxProjectRootDeps.exists(join18(dir, ".nax", "config.json"))) {
|
|
33209
33241
|
return dir;
|
|
33210
33242
|
}
|
|
33211
33243
|
const parent = dirname6(dir);
|
|
@@ -33226,7 +33258,7 @@ var init_nax_project_root = __esm(() => {
|
|
|
33226
33258
|
|
|
33227
33259
|
// src/review/review-audit.ts
|
|
33228
33260
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
33229
|
-
import { join as
|
|
33261
|
+
import { join as join19 } from "path";
|
|
33230
33262
|
function auditKey(reviewer, storyId) {
|
|
33231
33263
|
return `${reviewer}:${storyId ?? "_feature"}`;
|
|
33232
33264
|
}
|
|
@@ -33259,15 +33291,15 @@ function toPersistedEntry(entry, epochMs) {
|
|
|
33259
33291
|
async function persistReviewAudit(entry) {
|
|
33260
33292
|
let resolvedDir;
|
|
33261
33293
|
if (entry.outputDir) {
|
|
33262
|
-
resolvedDir =
|
|
33294
|
+
resolvedDir = join19(entry.outputDir, "review-audit", entry.featureName ?? "_unknown");
|
|
33263
33295
|
} else {
|
|
33264
33296
|
const projectRoot = entry.projectDir ?? await _reviewAuditDeps.findNaxProjectRoot(entry.workdir);
|
|
33265
|
-
resolvedDir =
|
|
33297
|
+
resolvedDir = join19(projectRoot, ".nax", "review-audit", entry.featureName ?? "_unknown");
|
|
33266
33298
|
}
|
|
33267
33299
|
await _reviewAuditDeps.mkdir(resolvedDir);
|
|
33268
33300
|
const epochMs = _reviewAuditDeps.now();
|
|
33269
33301
|
const filename = `${epochMs}-${entry.sessionName}.json`;
|
|
33270
|
-
await _reviewAuditDeps.writeFile(
|
|
33302
|
+
await _reviewAuditDeps.writeFile(join19(resolvedDir, filename), toPersistedEntry(entry, epochMs));
|
|
33271
33303
|
}
|
|
33272
33304
|
function createNoOpReviewAuditor() {
|
|
33273
33305
|
return {
|
|
@@ -33868,6 +33900,17 @@ function createDrainDeadline(deadlineMs) {
|
|
|
33868
33900
|
}
|
|
33869
33901
|
async function runQualityCommand(opts) {
|
|
33870
33902
|
const { commandName, command, workdir, storyId, timeoutMs = DEFAULT_TIMEOUT_MS, env: env2, stripEnvVars } = opts;
|
|
33903
|
+
if (!command || command.trim() === "") {
|
|
33904
|
+
return {
|
|
33905
|
+
commandName,
|
|
33906
|
+
command,
|
|
33907
|
+
success: false,
|
|
33908
|
+
exitCode: -1,
|
|
33909
|
+
output: `[nax] ${commandName} skipped: empty command`,
|
|
33910
|
+
durationMs: 0,
|
|
33911
|
+
timedOut: false
|
|
33912
|
+
};
|
|
33913
|
+
}
|
|
33871
33914
|
const startTime = Date.now();
|
|
33872
33915
|
const logger = getSafeLogger();
|
|
33873
33916
|
logger?.info("quality", `Running ${commandName}`, { storyId, commandName, command, workdir });
|
|
@@ -33982,7 +34025,7 @@ __export(exports_command_resolver, {
|
|
|
33982
34025
|
resolveQualityTestCommands: () => resolveQualityTestCommands,
|
|
33983
34026
|
_commandResolverDeps: () => _commandResolverDeps
|
|
33984
34027
|
});
|
|
33985
|
-
import { join as
|
|
34028
|
+
import { join as join20 } from "path";
|
|
33986
34029
|
async function resolveQualityTestCommands(config2, workdir, storyWorkdir) {
|
|
33987
34030
|
const rawTestCommand = config2.review?.commands?.test ?? config2.quality?.commands?.test;
|
|
33988
34031
|
const rawScopedTemplate = config2.quality?.commands?.testScoped;
|
|
@@ -34009,7 +34052,7 @@ var init_command_resolver = __esm(() => {
|
|
|
34009
34052
|
_commandResolverDeps = {
|
|
34010
34053
|
readPackageName: async (dir) => {
|
|
34011
34054
|
try {
|
|
34012
|
-
const content = await Bun.file(
|
|
34055
|
+
const content = await Bun.file(join20(dir, "package.json")).json();
|
|
34013
34056
|
return typeof content.name === "string" ? content.name : null;
|
|
34014
34057
|
} catch {
|
|
34015
34058
|
return null;
|
|
@@ -34458,7 +34501,7 @@ ${outputFormat}`, overridable: false }
|
|
|
34458
34501
|
});
|
|
34459
34502
|
|
|
34460
34503
|
// src/operations/plan-refine.ts
|
|
34461
|
-
import { join as
|
|
34504
|
+
import { join as join21 } from "path";
|
|
34462
34505
|
function hasToken(text, tokens) {
|
|
34463
34506
|
const lower = text.toLowerCase();
|
|
34464
34507
|
return tokens.some((token) => lower.includes(token));
|
|
@@ -34550,7 +34593,7 @@ async function normalizeStoryFiles(story, workdir, fileExists, upstreamProduced)
|
|
|
34550
34593
|
for (const entry of contextFiles) {
|
|
34551
34594
|
const filePath = typeof entry === "string" ? entry : entry.path;
|
|
34552
34595
|
const factId = typeof entry === "string" ? undefined : entry.factId;
|
|
34553
|
-
if (expected.has(filePath) || await fileExists(
|
|
34596
|
+
if (expected.has(filePath) || await fileExists(join21(workdir, filePath))) {
|
|
34554
34597
|
kept.push(entry);
|
|
34555
34598
|
continue;
|
|
34556
34599
|
}
|
|
@@ -35702,11 +35745,11 @@ function extractTestCode(output) {
|
|
|
35702
35745
|
|
|
35703
35746
|
// src/acceptance/generator.ts
|
|
35704
35747
|
import { existsSync as existsSync5 } from "fs";
|
|
35705
|
-
import { join as
|
|
35748
|
+
import { join as join22 } from "path";
|
|
35706
35749
|
function resolvePytestBin(packageDir) {
|
|
35707
35750
|
if (packageDir) {
|
|
35708
35751
|
for (const venvDir of [".venv", "venv", "env"]) {
|
|
35709
|
-
const candidate =
|
|
35752
|
+
const candidate = join22(packageDir, venvDir, "bin", "pytest");
|
|
35710
35753
|
if (existsSync5(candidate))
|
|
35711
35754
|
return candidate;
|
|
35712
35755
|
}
|
|
@@ -37292,6 +37335,7 @@ var init_write_test = __esm(() => {
|
|
|
37292
37335
|
stage: "run",
|
|
37293
37336
|
session: { role: "test-writer", lifetime: "warm" },
|
|
37294
37337
|
config: tddConfigSelector,
|
|
37338
|
+
model: (_input, ctx) => ctx.config.tdd?.sessionTiers?.testWriter,
|
|
37295
37339
|
keepOpen: (_input, ctx) => shouldKeepSessionOpen(ctx.config, "test-writer"),
|
|
37296
37340
|
build(input, _ctx) {
|
|
37297
37341
|
if (input.promptMarkdown?.trim()) {
|
|
@@ -37352,6 +37396,7 @@ var init_implement = __esm(() => {
|
|
|
37352
37396
|
stage: "run",
|
|
37353
37397
|
session: { role: "implementer", lifetime: "warm" },
|
|
37354
37398
|
config: tddConfigSelector,
|
|
37399
|
+
model: (input) => input.story.routing?.modelTier,
|
|
37355
37400
|
keepOpen: (_input, ctx) => shouldKeepSessionOpen(ctx.config, "implementer"),
|
|
37356
37401
|
build(input, _ctx) {
|
|
37357
37402
|
if (input.promptMarkdown?.trim()) {
|
|
@@ -37749,6 +37794,7 @@ var init_verify = __esm(() => {
|
|
|
37749
37794
|
stage: "verify",
|
|
37750
37795
|
session: { role: "verifier", lifetime: "fresh" },
|
|
37751
37796
|
config: tddConfigSelector,
|
|
37797
|
+
model: (_input, ctx) => ctx.config.tdd?.sessionTiers?.verifier,
|
|
37752
37798
|
retry: makeParseRetryStrategy({
|
|
37753
37799
|
validate: (parsed) => {
|
|
37754
37800
|
if (!parsed || typeof parsed !== "object")
|
|
@@ -38315,14 +38361,14 @@ var init_plan_critic_llm = __esm(() => {
|
|
|
38315
38361
|
|
|
38316
38362
|
// src/context/greenfield.ts
|
|
38317
38363
|
import { readdir as readdir2 } from "fs/promises";
|
|
38318
|
-
import { join as
|
|
38364
|
+
import { join as join23 } from "path";
|
|
38319
38365
|
async function scanForTestFiles(dir, testPatterns, isRootCall = true) {
|
|
38320
38366
|
const results = [];
|
|
38321
38367
|
const ignoreDirs = new Set(["node_modules", "dist", "build", ".next", ".git"]);
|
|
38322
38368
|
try {
|
|
38323
38369
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
38324
38370
|
for (const entry of entries) {
|
|
38325
|
-
const fullPath =
|
|
38371
|
+
const fullPath = join23(dir, entry.name);
|
|
38326
38372
|
if (entry.isDirectory()) {
|
|
38327
38373
|
if (ignoreDirs.has(entry.name))
|
|
38328
38374
|
continue;
|
|
@@ -38527,13 +38573,13 @@ __export(exports_runners, {
|
|
|
38527
38573
|
_regressionRunnerDeps: () => _regressionRunnerDeps
|
|
38528
38574
|
});
|
|
38529
38575
|
import { existsSync as existsSync6 } from "fs";
|
|
38530
|
-
import { join as
|
|
38576
|
+
import { join as join24 } from "path";
|
|
38531
38577
|
async function verifyAssets(workingDirectory, expectedFiles) {
|
|
38532
38578
|
if (!expectedFiles || expectedFiles.length === 0)
|
|
38533
38579
|
return { success: true, missingFiles: [] };
|
|
38534
38580
|
const missingFiles = [];
|
|
38535
38581
|
for (const file3 of expectedFiles) {
|
|
38536
|
-
if (!existsSync6(
|
|
38582
|
+
if (!existsSync6(join24(workingDirectory, file3)))
|
|
38537
38583
|
missingFiles.push(file3);
|
|
38538
38584
|
}
|
|
38539
38585
|
if (missingFiles.length > 0) {
|
|
@@ -38659,7 +38705,7 @@ var init_full_suite_gate = __esm(() => {
|
|
|
38659
38705
|
_fullSuiteGateDeps = {
|
|
38660
38706
|
resolveGateContext: async (input, ctx) => {
|
|
38661
38707
|
const { resolveQualityTestCommands: resolveQualityTestCommands2 } = await Promise.resolve().then(() => (init_command_resolver(), exports_command_resolver));
|
|
38662
|
-
const config2 = ctx.
|
|
38708
|
+
const config2 = ctx.packageView.config;
|
|
38663
38709
|
const fullSuiteTimeout = config2.execution?.regressionGate?.timeoutSeconds ?? config2.execution?.rectification?.fullSuiteTimeoutSeconds ?? 300;
|
|
38664
38710
|
const { testCommand: resolvedTestCmd } = await resolveQualityTestCommands2(config2, input.workdir, input.story.workdir);
|
|
38665
38711
|
if (!resolvedTestCmd) {
|
|
@@ -38708,7 +38754,7 @@ var init_full_suite_gate = __esm(() => {
|
|
|
38708
38754
|
config: fullSuiteGateConfigSelector,
|
|
38709
38755
|
async execute(input, ctx, deps = _fullSuiteGateDeps) {
|
|
38710
38756
|
const logger = getLogger();
|
|
38711
|
-
const ctxConfig = ctx.config;
|
|
38757
|
+
const ctxConfig = ctx.packageView.config;
|
|
38712
38758
|
const enabled = ctxConfig?.execution?.regressionGate?.enabled ?? true;
|
|
38713
38759
|
if (!enabled) {
|
|
38714
38760
|
logger.info("verify[regression]", "Regression gate disabled \u2014 skipping full-suite run", {
|
|
@@ -38979,7 +39025,7 @@ var init_apply_test_edit_declarations = __esm(() => {
|
|
|
38979
39025
|
});
|
|
38980
39026
|
|
|
38981
39027
|
// src/operations/validate-mock-structure-files.ts
|
|
38982
|
-
import { join as
|
|
39028
|
+
import { join as join25 } from "path";
|
|
38983
39029
|
async function validateMockStructureFiles(declarations, resolvedTestPatterns, packageDir, deps) {
|
|
38984
39030
|
const fileExists = deps?.fileExists ?? defaultFileExists;
|
|
38985
39031
|
const valid = [];
|
|
@@ -38992,7 +39038,7 @@ async function validateMockStructureFiles(declarations, resolvedTestPatterns, pa
|
|
|
38992
39038
|
const files = d.files ?? [d.file];
|
|
38993
39039
|
let allValid = true;
|
|
38994
39040
|
for (const file3 of files) {
|
|
38995
|
-
const absolutePath =
|
|
39041
|
+
const absolutePath = join25(packageDir, file3);
|
|
38996
39042
|
const exists = await fileExists(absolutePath);
|
|
38997
39043
|
if (!exists) {
|
|
38998
39044
|
allValid = false;
|
|
@@ -39214,9 +39260,9 @@ var init_mechanical_lintfix_strategy = __esm(() => {
|
|
|
39214
39260
|
stage: "rectification",
|
|
39215
39261
|
config: qualityConfigSelector,
|
|
39216
39262
|
async execute(input, ctx, deps = _mechanicalLintFixDeps) {
|
|
39217
|
-
const
|
|
39218
|
-
const broad =
|
|
39219
|
-
const scoped2 =
|
|
39263
|
+
const quality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
39264
|
+
const broad = quality?.commands?.lintFix;
|
|
39265
|
+
const scoped2 = quality?.commands?.lintFixScoped;
|
|
39220
39266
|
const command = buildCommand(broad, scoped2, input.scopeFiles);
|
|
39221
39267
|
if (!command)
|
|
39222
39268
|
return { applied: true, exitCode: 0 };
|
|
@@ -39225,7 +39271,7 @@ var init_mechanical_lintfix_strategy = __esm(() => {
|
|
|
39225
39271
|
command,
|
|
39226
39272
|
workdir: input.workdir,
|
|
39227
39273
|
storyId: input.storyId,
|
|
39228
|
-
stripEnvVars:
|
|
39274
|
+
stripEnvVars: quality?.stripEnvVars ?? []
|
|
39229
39275
|
});
|
|
39230
39276
|
return { applied: true, exitCode: result.exitCode };
|
|
39231
39277
|
}
|
|
@@ -39273,9 +39319,9 @@ var init_mechanical_formatfix_strategy = __esm(() => {
|
|
|
39273
39319
|
stage: "rectification",
|
|
39274
39320
|
config: qualityConfigSelector,
|
|
39275
39321
|
async execute(input, ctx, deps = _mechanicalFormatFixDeps) {
|
|
39276
|
-
const
|
|
39277
|
-
const broad =
|
|
39278
|
-
const scoped2 =
|
|
39322
|
+
const quality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
39323
|
+
const broad = quality?.commands?.formatFix;
|
|
39324
|
+
const scoped2 = quality?.commands?.formatFixScoped;
|
|
39279
39325
|
const command = buildCommand2(broad, scoped2, input.scopeFiles);
|
|
39280
39326
|
if (!command)
|
|
39281
39327
|
return { applied: true, exitCode: 0 };
|
|
@@ -39284,7 +39330,7 @@ var init_mechanical_formatfix_strategy = __esm(() => {
|
|
|
39284
39330
|
command,
|
|
39285
39331
|
workdir: input.workdir,
|
|
39286
39332
|
storyId: input.storyId,
|
|
39287
|
-
stripEnvVars:
|
|
39333
|
+
stripEnvVars: quality?.stripEnvVars ?? []
|
|
39288
39334
|
});
|
|
39289
39335
|
return { applied: true, exitCode: result.exitCode };
|
|
39290
39336
|
}
|
|
@@ -39295,6 +39341,7 @@ var init_mechanical_formatfix_strategy = __esm(() => {
|
|
|
39295
39341
|
var _lintCheckDeps, lintCheckOp;
|
|
39296
39342
|
var init_lint_check = __esm(() => {
|
|
39297
39343
|
init_config();
|
|
39344
|
+
init_logger2();
|
|
39298
39345
|
init_runner();
|
|
39299
39346
|
init_lint_parsing();
|
|
39300
39347
|
_lintCheckDeps = {
|
|
@@ -39307,21 +39354,25 @@ var init_lint_check = __esm(() => {
|
|
|
39307
39354
|
stage: "review",
|
|
39308
39355
|
config: qualityConfigSelector,
|
|
39309
39356
|
async execute(input, ctx, deps = _lintCheckDeps) {
|
|
39310
|
-
const
|
|
39311
|
-
const command =
|
|
39312
|
-
if (
|
|
39313
|
-
|
|
39357
|
+
const quality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
39358
|
+
const command = quality?.commands?.lint;
|
|
39359
|
+
if (!command) {
|
|
39360
|
+
getSafeLogger()?.warn("quality", "No lint command configured \u2014 skipping lint gate", {
|
|
39361
|
+
storyId: input.storyId,
|
|
39362
|
+
packageDir: ctx.packageView.packageDir
|
|
39363
|
+
});
|
|
39364
|
+
return { success: true, status: "skipped", findings: [], durationMs: 0 };
|
|
39314
39365
|
}
|
|
39315
39366
|
const start = Date.now();
|
|
39316
39367
|
const result = await deps.runQualityCommand({
|
|
39317
39368
|
commandName: "lint",
|
|
39318
|
-
command
|
|
39369
|
+
command,
|
|
39319
39370
|
workdir: input.workdir,
|
|
39320
39371
|
storyId: input.storyId,
|
|
39321
|
-
stripEnvVars:
|
|
39372
|
+
stripEnvVars: quality?.stripEnvVars ?? []
|
|
39322
39373
|
});
|
|
39323
39374
|
if (result.exitCode === 0) {
|
|
39324
|
-
return { success: true, findings: [], durationMs: Date.now() - start };
|
|
39375
|
+
return { success: true, status: "passed", findings: [], durationMs: Date.now() - start };
|
|
39325
39376
|
}
|
|
39326
39377
|
const parsed = deps.parseLintOutput(result.output, "auto", { workdir: input.workdir });
|
|
39327
39378
|
return { success: false, findings: parsed?.findings ?? [], durationMs: Date.now() - start };
|
|
@@ -39545,6 +39596,7 @@ var init_typecheck_parsing = __esm(() => {
|
|
|
39545
39596
|
var _typecheckCheckDeps, typecheckCheckOp;
|
|
39546
39597
|
var init_typecheck_check = __esm(() => {
|
|
39547
39598
|
init_config();
|
|
39599
|
+
init_logger2();
|
|
39548
39600
|
init_runner();
|
|
39549
39601
|
init_typecheck_parsing();
|
|
39550
39602
|
_typecheckCheckDeps = {
|
|
@@ -39557,21 +39609,25 @@ var init_typecheck_check = __esm(() => {
|
|
|
39557
39609
|
stage: "review",
|
|
39558
39610
|
config: qualityConfigSelector,
|
|
39559
39611
|
async execute(input, ctx, deps = _typecheckCheckDeps) {
|
|
39560
|
-
const
|
|
39561
|
-
const command =
|
|
39562
|
-
if (
|
|
39563
|
-
|
|
39612
|
+
const quality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
39613
|
+
const command = quality?.commands?.typecheck;
|
|
39614
|
+
if (!command) {
|
|
39615
|
+
getSafeLogger()?.warn("quality", "No typecheck command configured \u2014 skipping typecheck gate", {
|
|
39616
|
+
storyId: input.storyId,
|
|
39617
|
+
packageDir: ctx.packageView.packageDir
|
|
39618
|
+
});
|
|
39619
|
+
return { success: true, status: "skipped", findings: [], durationMs: 0 };
|
|
39564
39620
|
}
|
|
39565
39621
|
const start = Date.now();
|
|
39566
39622
|
const result = await deps.runQualityCommand({
|
|
39567
39623
|
commandName: "typecheck",
|
|
39568
|
-
command
|
|
39624
|
+
command,
|
|
39569
39625
|
workdir: input.workdir,
|
|
39570
39626
|
storyId: input.storyId,
|
|
39571
|
-
stripEnvVars:
|
|
39627
|
+
stripEnvVars: quality?.stripEnvVars ?? []
|
|
39572
39628
|
});
|
|
39573
39629
|
if (result.exitCode === 0) {
|
|
39574
|
-
return { success: true, findings: [], durationMs: Date.now() - start };
|
|
39630
|
+
return { success: true, status: "passed", findings: [], durationMs: Date.now() - start };
|
|
39575
39631
|
}
|
|
39576
39632
|
const parsed = deps.parseTypecheckOutput(result.output, "auto", { workdir: input.workdir });
|
|
39577
39633
|
return { success: false, findings: parsed?.findings ?? [], durationMs: Date.now() - start };
|
|
@@ -39600,12 +39656,16 @@ var init_verify_scoped = __esm(() => {
|
|
|
39600
39656
|
config: qualityConfigSelector,
|
|
39601
39657
|
async execute(input, ctx, deps = _verifyScopedDeps) {
|
|
39602
39658
|
const logger = getLogger();
|
|
39603
|
-
const
|
|
39604
|
-
const baseCommand =
|
|
39605
|
-
if (!
|
|
39659
|
+
const quality = ctx.packageView.select(qualityConfigSelector);
|
|
39660
|
+
const baseCommand = quality.quality?.commands?.test;
|
|
39661
|
+
if (!baseCommand) {
|
|
39662
|
+
logger.warn("quality", "No test command configured \u2014 skipping scoped verify", {
|
|
39663
|
+
storyId: input.storyId,
|
|
39664
|
+
packageDir: ctx.packageView.packageDir
|
|
39665
|
+
});
|
|
39606
39666
|
return {
|
|
39607
39667
|
success: true,
|
|
39608
|
-
status: "
|
|
39668
|
+
status: "skipped",
|
|
39609
39669
|
findings: [],
|
|
39610
39670
|
durationMs: 0,
|
|
39611
39671
|
passCount: 0,
|
|
@@ -39617,11 +39677,11 @@ var init_verify_scoped = __esm(() => {
|
|
|
39617
39677
|
workdir: input.workdir,
|
|
39618
39678
|
storyId: input.storyId,
|
|
39619
39679
|
storyGitRef: input.storyGitRef,
|
|
39620
|
-
testCommand: baseCommand
|
|
39621
|
-
testScopedTemplate:
|
|
39622
|
-
smartRunnerConfig:
|
|
39623
|
-
scopeTestThreshold:
|
|
39624
|
-
fallbackFullSuiteCommand:
|
|
39680
|
+
testCommand: baseCommand,
|
|
39681
|
+
testScopedTemplate: quality.quality?.commands?.testScoped,
|
|
39682
|
+
smartRunnerConfig: quality.execution?.smartTestRunner,
|
|
39683
|
+
scopeTestThreshold: quality.quality?.scopeTestThreshold,
|
|
39684
|
+
fallbackFullSuiteCommand: quality.quality?.commands?.test,
|
|
39625
39685
|
naxIgnoreIndex: input.naxIgnoreIndex
|
|
39626
39686
|
});
|
|
39627
39687
|
if (selection.isFullSuite && regressionMode === "deferred" && !selection.isMonorepoOrchestrator && !selection.thresholdFallback) {
|
|
@@ -39648,7 +39708,7 @@ var init_verify_scoped = __esm(() => {
|
|
|
39648
39708
|
command: selection.effectiveCommand
|
|
39649
39709
|
});
|
|
39650
39710
|
}
|
|
39651
|
-
const scopedTimeout =
|
|
39711
|
+
const scopedTimeout = quality.execution?.regressionGate?.timeoutSeconds ?? 600;
|
|
39652
39712
|
logger.info("verify[scoped]", "Running scoped tests", {
|
|
39653
39713
|
storyId: input.storyId,
|
|
39654
39714
|
packageDir: input.packageDir,
|
|
@@ -39661,14 +39721,14 @@ var init_verify_scoped = __esm(() => {
|
|
|
39661
39721
|
const result = await deps.regression({
|
|
39662
39722
|
workdir: input.workdir,
|
|
39663
39723
|
command: selection.effectiveCommand,
|
|
39664
|
-
timeoutSeconds:
|
|
39665
|
-
forceExit:
|
|
39666
|
-
detectOpenHandles:
|
|
39667
|
-
detectOpenHandlesRetries:
|
|
39668
|
-
gracePeriodMs:
|
|
39669
|
-
drainTimeoutMs:
|
|
39670
|
-
shell:
|
|
39671
|
-
stripEnvVars:
|
|
39724
|
+
timeoutSeconds: quality.execution?.regressionGate?.timeoutSeconds ?? 600,
|
|
39725
|
+
forceExit: quality.quality?.forceExit,
|
|
39726
|
+
detectOpenHandles: quality.quality?.detectOpenHandles,
|
|
39727
|
+
detectOpenHandlesRetries: quality.quality?.detectOpenHandlesRetries,
|
|
39728
|
+
gracePeriodMs: quality.quality?.gracePeriodMs,
|
|
39729
|
+
drainTimeoutMs: quality.quality?.drainTimeoutMs,
|
|
39730
|
+
shell: quality.quality?.shell,
|
|
39731
|
+
stripEnvVars: quality.quality?.stripEnvVars
|
|
39672
39732
|
});
|
|
39673
39733
|
const durationMs = Date.now() - start;
|
|
39674
39734
|
const parsed = result.output ? deps.parseTestOutput(result.output) : { passed: 0, failed: 0, failures: [] };
|
|
@@ -40440,7 +40500,7 @@ var init_lint_parsing = __esm(() => {
|
|
|
40440
40500
|
});
|
|
40441
40501
|
|
|
40442
40502
|
// src/review/scoped-lint.ts
|
|
40443
|
-
import { join as
|
|
40503
|
+
import { join as join26, relative as relative10 } from "path";
|
|
40444
40504
|
function shellQuotePath4(path5) {
|
|
40445
40505
|
return `'${path5.replaceAll("'", "'\\''")}'`;
|
|
40446
40506
|
}
|
|
@@ -40488,7 +40548,7 @@ function uniqueFiles(files) {
|
|
|
40488
40548
|
async function filterFilesToScope(files, workdir, projectDir, activePackageDir) {
|
|
40489
40549
|
const inScope = [];
|
|
40490
40550
|
for (const relPath of files) {
|
|
40491
|
-
const absPath =
|
|
40551
|
+
const absPath = join26(workdir, relPath);
|
|
40492
40552
|
const exists = await _scopedLintDeps.fileExists(absPath);
|
|
40493
40553
|
if (!exists)
|
|
40494
40554
|
continue;
|
|
@@ -43862,7 +43922,7 @@ var init_call = __esm(() => {
|
|
|
43862
43922
|
|
|
43863
43923
|
// src/runtime/cost-aggregator.ts
|
|
43864
43924
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
43865
|
-
import { join as
|
|
43925
|
+
import { join as join27 } from "path";
|
|
43866
43926
|
function makeCorrelationId() {
|
|
43867
43927
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
43868
43928
|
}
|
|
@@ -44053,7 +44113,7 @@ class CostAggregator {
|
|
|
44053
44113
|
if (events.length === 0 && errors3.length === 0)
|
|
44054
44114
|
return;
|
|
44055
44115
|
mkdirSync2(this._drainDir, { recursive: true });
|
|
44056
|
-
const path5 =
|
|
44116
|
+
const path5 = join27(this._drainDir, `${this._runId}.jsonl`);
|
|
44057
44117
|
const sorted = [...events, ...errors3].sort((a, b) => a.ts - b.ts);
|
|
44058
44118
|
await _costAggDeps.write(path5, `${sorted.map((e) => JSON.stringify(e)).join(`
|
|
44059
44119
|
`)}
|
|
@@ -44093,7 +44153,7 @@ var init_cost_aggregator = __esm(() => {
|
|
|
44093
44153
|
// src/runtime/prompt-auditor.ts
|
|
44094
44154
|
import { appendFileSync } from "fs";
|
|
44095
44155
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
44096
|
-
import { join as
|
|
44156
|
+
import { join as join28 } from "path";
|
|
44097
44157
|
function createNoOpPromptAuditor() {
|
|
44098
44158
|
return {
|
|
44099
44159
|
record() {},
|
|
@@ -44159,8 +44219,8 @@ class PromptAuditor {
|
|
|
44159
44219
|
_jsonlPath;
|
|
44160
44220
|
_featureDir;
|
|
44161
44221
|
constructor(runId, flushDir, featureName) {
|
|
44162
|
-
this._featureDir =
|
|
44163
|
-
this._jsonlPath =
|
|
44222
|
+
this._featureDir = join28(flushDir, featureName);
|
|
44223
|
+
this._jsonlPath = join28(this._featureDir, `${runId}.jsonl`);
|
|
44164
44224
|
}
|
|
44165
44225
|
record(entry) {
|
|
44166
44226
|
this._enqueue(entry);
|
|
@@ -44209,7 +44269,7 @@ class PromptAuditor {
|
|
|
44209
44269
|
const auditEntry = entry;
|
|
44210
44270
|
const filename = deriveTxtFilename(auditEntry);
|
|
44211
44271
|
try {
|
|
44212
|
-
await _promptAuditorDeps.write(
|
|
44272
|
+
await _promptAuditorDeps.write(join28(this._featureDir, filename), buildTxtContent(auditEntry));
|
|
44213
44273
|
} catch (err) {
|
|
44214
44274
|
throw tagAuditError(err, "txt");
|
|
44215
44275
|
}
|
|
@@ -44344,17 +44404,44 @@ function createPackageView(config2, packageDir, repoRoot) {
|
|
|
44344
44404
|
}
|
|
44345
44405
|
function createPackageRegistry(loader, repoRoot) {
|
|
44346
44406
|
const cache = new Map;
|
|
44407
|
+
const mergedConfigs = new Map;
|
|
44408
|
+
function toRelativeKey(packageDir) {
|
|
44409
|
+
if (!packageDir)
|
|
44410
|
+
return "";
|
|
44411
|
+
const prefix = repoRoot.endsWith("/") ? repoRoot : `${repoRoot}/`;
|
|
44412
|
+
if (packageDir.startsWith(prefix))
|
|
44413
|
+
return packageDir.slice(prefix.length);
|
|
44414
|
+
if (packageDir === repoRoot)
|
|
44415
|
+
return "";
|
|
44416
|
+
return packageDir;
|
|
44417
|
+
}
|
|
44347
44418
|
function resolve12(packageDir) {
|
|
44348
|
-
const key = packageDir
|
|
44419
|
+
const key = toRelativeKey(packageDir);
|
|
44349
44420
|
const cached2 = cache.get(key);
|
|
44350
44421
|
if (cached2 !== undefined) {
|
|
44351
44422
|
return cached2;
|
|
44352
44423
|
}
|
|
44353
|
-
const config2 = loader.current();
|
|
44424
|
+
const config2 = mergedConfigs.get(key) ?? loader.current();
|
|
44354
44425
|
const view = createPackageView(config2, key, repoRoot);
|
|
44355
44426
|
cache.set(key, view);
|
|
44356
44427
|
return view;
|
|
44357
44428
|
}
|
|
44429
|
+
async function hydrate(packageDirs, loadOverride2) {
|
|
44430
|
+
const load = loadOverride2 ?? (await Promise.resolve().then(() => (init_config(), exports_config))).loadPackageOverride;
|
|
44431
|
+
for (const dir of packageDirs) {
|
|
44432
|
+
if (!dir) {
|
|
44433
|
+
continue;
|
|
44434
|
+
}
|
|
44435
|
+
if (mergedConfigs.has(dir)) {
|
|
44436
|
+
continue;
|
|
44437
|
+
}
|
|
44438
|
+
const override = await load(repoRoot, dir);
|
|
44439
|
+
if (override !== null) {
|
|
44440
|
+
mergedConfigs.set(dir, mergePackageConfig(loader.current(), override));
|
|
44441
|
+
cache.delete(dir);
|
|
44442
|
+
}
|
|
44443
|
+
}
|
|
44444
|
+
}
|
|
44358
44445
|
return {
|
|
44359
44446
|
all() {
|
|
44360
44447
|
return [...cache.values()];
|
|
@@ -44362,9 +44449,13 @@ function createPackageRegistry(loader, repoRoot) {
|
|
|
44362
44449
|
resolve: resolve12,
|
|
44363
44450
|
repo() {
|
|
44364
44451
|
return resolve12(undefined);
|
|
44365
|
-
}
|
|
44452
|
+
},
|
|
44453
|
+
hydrate
|
|
44366
44454
|
};
|
|
44367
44455
|
}
|
|
44456
|
+
var init_packages = __esm(() => {
|
|
44457
|
+
init_config();
|
|
44458
|
+
});
|
|
44368
44459
|
|
|
44369
44460
|
// src/runtime/agent-stream-events.ts
|
|
44370
44461
|
class AgentStreamEventBus {
|
|
@@ -45322,7 +45413,7 @@ var init_pid_registry = __esm(() => {
|
|
|
45322
45413
|
// src/session/manager-deps.ts
|
|
45323
45414
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
45324
45415
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
45325
|
-
import { isAbsolute as isAbsolute9, join as
|
|
45416
|
+
import { isAbsolute as isAbsolute9, join as join29, relative as relative11, sep as sep2 } from "path";
|
|
45326
45417
|
function resolveProjectDirFromScratchDir(scratchDir) {
|
|
45327
45418
|
const marker = `${sep2}.nax${sep2}features${sep2}`;
|
|
45328
45419
|
const markerIdx = scratchDir.lastIndexOf(marker);
|
|
@@ -45343,7 +45434,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45343
45434
|
now: () => new Date().toISOString(),
|
|
45344
45435
|
nowMs: () => Date.now(),
|
|
45345
45436
|
uuid: () => randomUUID3(),
|
|
45346
|
-
sessionScratchDir: (projectDir, featureName, sessionId) =>
|
|
45437
|
+
sessionScratchDir: (projectDir, featureName, sessionId) => join29(projectDir, ".nax", "features", featureName, "sessions", sessionId),
|
|
45347
45438
|
writeDescriptor: async (scratchDir, descriptor, projectDir) => {
|
|
45348
45439
|
await mkdir5(scratchDir, { recursive: true });
|
|
45349
45440
|
const { handle: _handle, ...persistable } = descriptor;
|
|
@@ -45354,7 +45445,7 @@ var init_manager_deps = __esm(() => {
|
|
|
45354
45445
|
persistable.scratchDir = toProjectRelativePath(derivedProjectDir, persistable.scratchDir);
|
|
45355
45446
|
}
|
|
45356
45447
|
}
|
|
45357
|
-
await Bun.write(
|
|
45448
|
+
await Bun.write(join29(scratchDir, "descriptor.json"), JSON.stringify(persistable, null, 2));
|
|
45358
45449
|
}
|
|
45359
45450
|
};
|
|
45360
45451
|
});
|
|
@@ -46105,7 +46196,7 @@ __export(exports_runtime, {
|
|
|
46105
46196
|
CostAggregator: () => CostAggregator,
|
|
46106
46197
|
AgentStreamEventBus: () => AgentStreamEventBus
|
|
46107
46198
|
});
|
|
46108
|
-
import { basename as basename5, join as
|
|
46199
|
+
import { basename as basename5, join as join30 } from "path";
|
|
46109
46200
|
function createRuntime(config2, workdir, opts) {
|
|
46110
46201
|
const runId = crypto.randomUUID();
|
|
46111
46202
|
const controller = new AbortController;
|
|
@@ -46121,10 +46212,10 @@ function createRuntime(config2, workdir, opts) {
|
|
|
46121
46212
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
46122
46213
|
const globalDir = globalOutputDir();
|
|
46123
46214
|
const curatorRollupPathValue = curatorRollupPath(globalDir, config2.curator?.rollupPath);
|
|
46124
|
-
const costDir =
|
|
46215
|
+
const costDir = join30(outputDir, "cost");
|
|
46125
46216
|
const costAggregator = opts?.costAggregator ?? new CostAggregator(runId, costDir);
|
|
46126
46217
|
const auditEnabled = config2.agent?.promptAudit?.enabled ?? false;
|
|
46127
|
-
const auditDir = config2.agent?.promptAudit?.dir ??
|
|
46218
|
+
const auditDir = config2.agent?.promptAudit?.dir ?? join30(outputDir, "prompt-audit");
|
|
46128
46219
|
let promptAuditor;
|
|
46129
46220
|
if (opts?.promptAuditor) {
|
|
46130
46221
|
promptAuditor = opts.promptAuditor;
|
|
@@ -46230,6 +46321,7 @@ var init_runtime = __esm(() => {
|
|
|
46230
46321
|
init_prompt_auditor();
|
|
46231
46322
|
init_review_audit();
|
|
46232
46323
|
init_paths2();
|
|
46324
|
+
init_packages();
|
|
46233
46325
|
init_dispatch_events();
|
|
46234
46326
|
init_agent_stream_events();
|
|
46235
46327
|
init_middleware();
|
|
@@ -46247,6 +46339,7 @@ var init_runtime = __esm(() => {
|
|
|
46247
46339
|
init_cost_aggregator();
|
|
46248
46340
|
init_dispatch_events();
|
|
46249
46341
|
init_middleware();
|
|
46342
|
+
init_packages();
|
|
46250
46343
|
init_paths2();
|
|
46251
46344
|
init_prompt_auditor();
|
|
46252
46345
|
init_session_run_hop();
|
|
@@ -46275,9 +46368,9 @@ async function allSettledBounded(tasks, limit) {
|
|
|
46275
46368
|
|
|
46276
46369
|
// src/context/injector.ts
|
|
46277
46370
|
import { existsSync as existsSync8 } from "fs";
|
|
46278
|
-
import { join as
|
|
46371
|
+
import { join as join31 } from "path";
|
|
46279
46372
|
async function detectNode(workdir) {
|
|
46280
|
-
const pkgPath =
|
|
46373
|
+
const pkgPath = join31(workdir, "package.json");
|
|
46281
46374
|
if (!existsSync8(pkgPath))
|
|
46282
46375
|
return null;
|
|
46283
46376
|
try {
|
|
@@ -46294,7 +46387,7 @@ async function detectNode(workdir) {
|
|
|
46294
46387
|
}
|
|
46295
46388
|
}
|
|
46296
46389
|
async function detectGo(workdir) {
|
|
46297
|
-
const goMod =
|
|
46390
|
+
const goMod = join31(workdir, "go.mod");
|
|
46298
46391
|
if (!existsSync8(goMod))
|
|
46299
46392
|
return null;
|
|
46300
46393
|
try {
|
|
@@ -46318,7 +46411,7 @@ async function detectGo(workdir) {
|
|
|
46318
46411
|
}
|
|
46319
46412
|
}
|
|
46320
46413
|
async function detectRust(workdir) {
|
|
46321
|
-
const cargoPath =
|
|
46414
|
+
const cargoPath = join31(workdir, "Cargo.toml");
|
|
46322
46415
|
if (!existsSync8(cargoPath))
|
|
46323
46416
|
return null;
|
|
46324
46417
|
try {
|
|
@@ -46334,8 +46427,8 @@ async function detectRust(workdir) {
|
|
|
46334
46427
|
}
|
|
46335
46428
|
}
|
|
46336
46429
|
async function detectPython(workdir) {
|
|
46337
|
-
const pyproject =
|
|
46338
|
-
const requirements =
|
|
46430
|
+
const pyproject = join31(workdir, "pyproject.toml");
|
|
46431
|
+
const requirements = join31(workdir, "requirements.txt");
|
|
46339
46432
|
if (!existsSync8(pyproject) && !existsSync8(requirements))
|
|
46340
46433
|
return null;
|
|
46341
46434
|
try {
|
|
@@ -46354,7 +46447,7 @@ async function detectPython(workdir) {
|
|
|
46354
46447
|
}
|
|
46355
46448
|
}
|
|
46356
46449
|
async function detectPhp(workdir) {
|
|
46357
|
-
const composerPath =
|
|
46450
|
+
const composerPath = join31(workdir, "composer.json");
|
|
46358
46451
|
if (!existsSync8(composerPath))
|
|
46359
46452
|
return null;
|
|
46360
46453
|
try {
|
|
@@ -46367,7 +46460,7 @@ async function detectPhp(workdir) {
|
|
|
46367
46460
|
}
|
|
46368
46461
|
}
|
|
46369
46462
|
async function detectRuby(workdir) {
|
|
46370
|
-
const gemfile =
|
|
46463
|
+
const gemfile = join31(workdir, "Gemfile");
|
|
46371
46464
|
if (!existsSync8(gemfile))
|
|
46372
46465
|
return null;
|
|
46373
46466
|
try {
|
|
@@ -46379,9 +46472,9 @@ async function detectRuby(workdir) {
|
|
|
46379
46472
|
}
|
|
46380
46473
|
}
|
|
46381
46474
|
async function detectJvm(workdir) {
|
|
46382
|
-
const pom =
|
|
46383
|
-
const gradle =
|
|
46384
|
-
const gradleKts =
|
|
46475
|
+
const pom = join31(workdir, "pom.xml");
|
|
46476
|
+
const gradle = join31(workdir, "build.gradle");
|
|
46477
|
+
const gradleKts = join31(workdir, "build.gradle.kts");
|
|
46385
46478
|
if (!existsSync8(pom) && !existsSync8(gradle) && !existsSync8(gradleKts))
|
|
46386
46479
|
return null;
|
|
46387
46480
|
try {
|
|
@@ -46389,7 +46482,7 @@ async function detectJvm(workdir) {
|
|
|
46389
46482
|
const content2 = await Bun.file(pom).text();
|
|
46390
46483
|
const nameMatch = content2.match(/<artifactId>([^<]+)<\/artifactId>/);
|
|
46391
46484
|
const deps2 = [...content2.matchAll(/<artifactId>([^<]+)<\/artifactId>/g)].map((m) => m[1]).filter((d) => d !== nameMatch?.[1]).slice(0, 10);
|
|
46392
|
-
const lang2 = existsSync8(
|
|
46485
|
+
const lang2 = existsSync8(join31(workdir, "src/main/kotlin")) ? "Kotlin" : "Java";
|
|
46393
46486
|
return { name: nameMatch?.[1], lang: lang2, dependencies: deps2 };
|
|
46394
46487
|
}
|
|
46395
46488
|
const gradleFile = existsSync8(gradleKts) ? gradleKts : gradle;
|
|
@@ -46643,7 +46736,7 @@ var init_windsurf = __esm(() => {
|
|
|
46643
46736
|
|
|
46644
46737
|
// src/context/generator.ts
|
|
46645
46738
|
import { existsSync as existsSync9 } from "fs";
|
|
46646
|
-
import { join as
|
|
46739
|
+
import { join as join32, relative as relative12 } from "path";
|
|
46647
46740
|
async function loadContextContent(options, config2) {
|
|
46648
46741
|
if (!_generatorDeps.existsSync(options.contextPath)) {
|
|
46649
46742
|
throw new Error(`Context file not found: ${options.contextPath}`);
|
|
@@ -46661,7 +46754,7 @@ async function generateFor(agent, options, config2) {
|
|
|
46661
46754
|
try {
|
|
46662
46755
|
const context = await loadContextContent(options, config2);
|
|
46663
46756
|
const content = generator.generate(context);
|
|
46664
|
-
const outputPath =
|
|
46757
|
+
const outputPath = join32(options.outputDir, generator.outputFile);
|
|
46665
46758
|
validateFilePath(outputPath, options.outputDir);
|
|
46666
46759
|
if (!options.dryRun) {
|
|
46667
46760
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46679,7 +46772,7 @@ async function generateAll(options, config2, agentFilter) {
|
|
|
46679
46772
|
for (const [agentKey, generator] of entries) {
|
|
46680
46773
|
try {
|
|
46681
46774
|
const content = generator.generate(context);
|
|
46682
|
-
const outputPath =
|
|
46775
|
+
const outputPath = join32(options.outputDir, generator.outputFile);
|
|
46683
46776
|
validateFilePath(outputPath, options.outputDir);
|
|
46684
46777
|
if (!options.dryRun) {
|
|
46685
46778
|
await _generatorDeps.writeFile(outputPath, content);
|
|
@@ -46699,7 +46792,7 @@ async function discoverPackages(repoRoot) {
|
|
|
46699
46792
|
const glob = new Bun.Glob(pattern);
|
|
46700
46793
|
for await (const match of glob.scan({ cwd: repoRoot, dot: true })) {
|
|
46701
46794
|
const pkgRelative = match.replace(/^\.nax\/mono\//, "").replace(/\/context\.md$/, "");
|
|
46702
|
-
const pkgAbsolute =
|
|
46795
|
+
const pkgAbsolute = join32(repoRoot, pkgRelative);
|
|
46703
46796
|
if (!seen.has(pkgAbsolute)) {
|
|
46704
46797
|
seen.add(pkgAbsolute);
|
|
46705
46798
|
packages.push(pkgAbsolute);
|
|
@@ -46731,14 +46824,14 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
46731
46824
|
}
|
|
46732
46825
|
}
|
|
46733
46826
|
}
|
|
46734
|
-
const turboPath =
|
|
46827
|
+
const turboPath = join32(repoRoot, "turbo.json");
|
|
46735
46828
|
try {
|
|
46736
46829
|
const turbo = JSON.parse(await _generatorDeps.readTextFile(turboPath));
|
|
46737
46830
|
if (Array.isArray(turbo.packages)) {
|
|
46738
46831
|
await resolveGlobs(turbo.packages);
|
|
46739
46832
|
}
|
|
46740
46833
|
} catch {}
|
|
46741
|
-
const pkgPath =
|
|
46834
|
+
const pkgPath = join32(repoRoot, "package.json");
|
|
46742
46835
|
try {
|
|
46743
46836
|
const pkg = JSON.parse(await _generatorDeps.readTextFile(pkgPath));
|
|
46744
46837
|
const ws = pkg.workspaces;
|
|
@@ -46746,7 +46839,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
46746
46839
|
if (patterns.length > 0)
|
|
46747
46840
|
await resolveGlobs(patterns);
|
|
46748
46841
|
} catch {}
|
|
46749
|
-
const pnpmPath =
|
|
46842
|
+
const pnpmPath = join32(repoRoot, "pnpm-workspace.yaml");
|
|
46750
46843
|
try {
|
|
46751
46844
|
const raw = await _generatorDeps.readTextFile(pnpmPath);
|
|
46752
46845
|
const lines = raw.split(`
|
|
@@ -46772,7 +46865,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
46772
46865
|
async function generateForPackage(packageDir, config2, dryRun = false, repoRoot) {
|
|
46773
46866
|
const resolvedRepoRoot = repoRoot ?? packageDir;
|
|
46774
46867
|
const relativePkgPath = relative12(resolvedRepoRoot, packageDir);
|
|
46775
|
-
const contextPath =
|
|
46868
|
+
const contextPath = join32(resolvedRepoRoot, ".nax", "mono", relativePkgPath, "context.md");
|
|
46776
46869
|
if (!_generatorDeps.existsSync(contextPath)) {
|
|
46777
46870
|
return [
|
|
46778
46871
|
{
|
|
@@ -46840,7 +46933,7 @@ var init_generator2 = __esm(() => {
|
|
|
46840
46933
|
});
|
|
46841
46934
|
|
|
46842
46935
|
// src/analyze/scanner.ts
|
|
46843
|
-
import { join as
|
|
46936
|
+
import { join as join33 } from "path";
|
|
46844
46937
|
function resolveFrameworkAndRunner(language, pkg) {
|
|
46845
46938
|
if (language === "go")
|
|
46846
46939
|
return { framework: "", testRunner: "go-test" };
|
|
@@ -46862,7 +46955,7 @@ async function scanSourceRoots(workdir) {
|
|
|
46862
46955
|
});
|
|
46863
46956
|
try {
|
|
46864
46957
|
const language = await deps.detectLanguage(workdir);
|
|
46865
|
-
const pkg = await deps.readPackageJson(
|
|
46958
|
+
const pkg = await deps.readPackageJson(join33(workdir, "package.json"));
|
|
46866
46959
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
46867
46960
|
return [{ path: ".", language, framework, testRunner }];
|
|
46868
46961
|
} catch {
|
|
@@ -46880,9 +46973,9 @@ async function scanSourceRoots(workdir) {
|
|
|
46880
46973
|
packages = packages.slice(0, MAX_SOURCE_ROOTS);
|
|
46881
46974
|
}
|
|
46882
46975
|
return Promise.all(packages.map(async (pkgPath) => {
|
|
46883
|
-
const pkgDir = pkgPath === "." ? workdir :
|
|
46976
|
+
const pkgDir = pkgPath === "." ? workdir : join33(workdir, pkgPath);
|
|
46884
46977
|
const language = await deps.detectLanguage(pkgDir);
|
|
46885
|
-
const pkg = await deps.readPackageJson(
|
|
46978
|
+
const pkg = await deps.readPackageJson(join33(pkgDir, "package.json"));
|
|
46886
46979
|
const { framework, testRunner } = resolveFrameworkAndRunner(language, pkg);
|
|
46887
46980
|
return { path: pkgPath, language, framework, testRunner };
|
|
46888
46981
|
}));
|
|
@@ -46915,7 +47008,7 @@ var init_analyze = __esm(() => {
|
|
|
46915
47008
|
});
|
|
46916
47009
|
|
|
46917
47010
|
// src/debate/pre-phase/grounder.ts
|
|
46918
|
-
import { join as
|
|
47011
|
+
import { join as join34 } from "path";
|
|
46919
47012
|
async function buildCodebaseContext(workdir) {
|
|
46920
47013
|
const roots = await _grounderDeps.scanSourceRoots(workdir);
|
|
46921
47014
|
return buildSourceRootsSection(normalizeRoots(workdir, roots));
|
|
@@ -46927,7 +47020,7 @@ function normalizeRoots(workdir, roots) {
|
|
|
46927
47020
|
}));
|
|
46928
47021
|
}
|
|
46929
47022
|
async function writeManifestArtifact(ctx, manifest) {
|
|
46930
|
-
const manifestPath =
|
|
47023
|
+
const manifestPath = join34(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
46931
47024
|
await _grounderDeps.write(manifestPath, JSON.stringify(manifest, null, 2));
|
|
46932
47025
|
}
|
|
46933
47026
|
var _grounderDeps, grounderStrategy = async (ctx) => {
|
|
@@ -47270,7 +47363,7 @@ function formatSpecDeltas(blockers, manifest) {
|
|
|
47270
47363
|
|
|
47271
47364
|
// src/debate/verifiers/checks.ts
|
|
47272
47365
|
import { existsSync as defaultExistsSync } from "fs";
|
|
47273
|
-
import { join as
|
|
47366
|
+
import { join as join35 } from "path";
|
|
47274
47367
|
function checkFilesExist(prd, workdir, deps) {
|
|
47275
47368
|
const existsSync10 = deps?.existsSync ?? defaultExistsSync;
|
|
47276
47369
|
const findings = [];
|
|
@@ -47280,7 +47373,7 @@ function checkFilesExist(prd, workdir, deps) {
|
|
|
47280
47373
|
for (const entry of story.contextFiles) {
|
|
47281
47374
|
const filePath = typeof entry === "string" ? entry : entry.path;
|
|
47282
47375
|
const factId = typeof entry === "string" ? undefined : entry.factId;
|
|
47283
|
-
const absPath =
|
|
47376
|
+
const absPath = join35(workdir, filePath);
|
|
47284
47377
|
if (existsSync10(absPath))
|
|
47285
47378
|
continue;
|
|
47286
47379
|
if (factId) {
|
|
@@ -47391,7 +47484,7 @@ var init_checks3 = () => {};
|
|
|
47391
47484
|
|
|
47392
47485
|
// src/debate/verifiers/plan-checklist.ts
|
|
47393
47486
|
import { existsSync as existsSync10 } from "fs";
|
|
47394
|
-
import { join as
|
|
47487
|
+
import { join as join36 } from "path";
|
|
47395
47488
|
function parsePrd(output) {
|
|
47396
47489
|
if (!output)
|
|
47397
47490
|
return null;
|
|
@@ -47402,7 +47495,7 @@ function parsePrd(output) {
|
|
|
47402
47495
|
}
|
|
47403
47496
|
}
|
|
47404
47497
|
async function loadManifest(ctx) {
|
|
47405
|
-
const manifestPath =
|
|
47498
|
+
const manifestPath = join36(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "facts-manifest.json");
|
|
47406
47499
|
const raw = await _planChecklistDeps.readFile(manifestPath);
|
|
47407
47500
|
if (!raw)
|
|
47408
47501
|
return null;
|
|
@@ -47415,7 +47508,7 @@ async function loadManifest(ctx) {
|
|
|
47415
47508
|
}
|
|
47416
47509
|
}
|
|
47417
47510
|
async function emitSpecDeltas(ctx, blockers, manifest) {
|
|
47418
|
-
const artifactPath =
|
|
47511
|
+
const artifactPath = join36(ctx.workdir, ".nax", "runs", ctx.ctx.runtime.runId, "plan", ctx.storyId, "spec-deltas.md");
|
|
47419
47512
|
const content = formatSpecDeltas(blockers, manifest ?? { repoFacts: [], specClaims: [], gaps: [] });
|
|
47420
47513
|
await _planChecklistDeps.write(artifactPath, content);
|
|
47421
47514
|
return artifactPath;
|
|
@@ -47761,7 +47854,7 @@ var init_runner_plan_helpers = __esm(() => {
|
|
|
47761
47854
|
});
|
|
47762
47855
|
|
|
47763
47856
|
// src/debate/runner-plan.ts
|
|
47764
|
-
import { join as
|
|
47857
|
+
import { join as join37 } from "path";
|
|
47765
47858
|
async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
47766
47859
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
47767
47860
|
const config2 = ctx.stageConfig;
|
|
@@ -47820,7 +47913,7 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
47820
47913
|
sessionMode: ctx.stageConfig.sessionMode ?? "one-shot",
|
|
47821
47914
|
proposers: ctx.stageConfig.proposers
|
|
47822
47915
|
});
|
|
47823
|
-
const outputPaths = resolved.map((_, i) =>
|
|
47916
|
+
const outputPaths = resolved.map((_, i) => join37(opts.outputDir, `prd-debate-${i}.json`));
|
|
47824
47917
|
const successful = [];
|
|
47825
47918
|
let rebuttalList;
|
|
47826
47919
|
if (selectorKind === "verifier-pick") {
|
|
@@ -50063,9 +50156,9 @@ function validateFeatureName(feature) {
|
|
|
50063
50156
|
|
|
50064
50157
|
// src/plan/critic.ts
|
|
50065
50158
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
50066
|
-
import { dirname as dirname7, join as
|
|
50159
|
+
import { dirname as dirname7, join as join40 } from "path";
|
|
50067
50160
|
async function writeSpecDeltas(findings, workdir, runId, storyId, manifest) {
|
|
50068
|
-
const path7 =
|
|
50161
|
+
const path7 = join40(workdir, ".nax", "runs", runId, "plan", storyId, "spec-deltas.md");
|
|
50069
50162
|
await mkdir6(dirname7(path7), { recursive: true });
|
|
50070
50163
|
await Bun.write(path7, formatSpecDeltas(findings, manifest));
|
|
50071
50164
|
return path7;
|
|
@@ -51278,9 +51371,9 @@ __export(exports_plan_decompose, {
|
|
|
51278
51371
|
runReplanLoop: () => runReplanLoop,
|
|
51279
51372
|
planDecomposeCommand: () => planDecomposeCommand
|
|
51280
51373
|
});
|
|
51281
|
-
import { join as
|
|
51374
|
+
import { join as join41 } from "path";
|
|
51282
51375
|
async function planDecomposeCommand(workdir, config2, options) {
|
|
51283
|
-
const prdPath =
|
|
51376
|
+
const prdPath = join41(workdir, ".nax", "features", options.feature, "prd.json");
|
|
51284
51377
|
if (!_planDeps.existsSync(prdPath)) {
|
|
51285
51378
|
throw new NaxError(`PRD not found: ${prdPath}`, "PRD_NOT_FOUND", {
|
|
51286
51379
|
stage: "decompose",
|
|
@@ -51454,7 +51547,7 @@ var init_plan_decompose = __esm(() => {
|
|
|
51454
51547
|
|
|
51455
51548
|
// src/cli/plan-runtime.ts
|
|
51456
51549
|
import { existsSync as existsSync15 } from "fs";
|
|
51457
|
-
import { join as
|
|
51550
|
+
import { join as join42 } from "path";
|
|
51458
51551
|
function isRuntimeWithAgentManager(value) {
|
|
51459
51552
|
return typeof value === "object" && value !== null && "agentManager" in value;
|
|
51460
51553
|
}
|
|
@@ -51506,7 +51599,7 @@ var init_plan_runtime = __esm(() => {
|
|
|
51506
51599
|
writeFile: (path7, content) => Bun.write(path7, content).then(() => {}),
|
|
51507
51600
|
scanSourceRoots: (workdir) => scanSourceRoots(workdir),
|
|
51508
51601
|
createRuntime: (cfg, wd, featureName) => createRuntime(cfg, wd, { featureName }),
|
|
51509
|
-
readPackageJson: (workdir) => Bun.file(
|
|
51602
|
+
readPackageJson: (workdir) => Bun.file(join42(workdir, "package.json")).json().catch(() => null),
|
|
51510
51603
|
spawnSync: (cmd, opts) => {
|
|
51511
51604
|
const result = Bun.spawnSync(cmd, opts ? { cwd: opts.cwd } : {});
|
|
51512
51605
|
return { stdout: result.stdout, exitCode: result.exitCode };
|
|
@@ -51891,7 +51984,7 @@ var init_metrics = __esm(() => {
|
|
|
51891
51984
|
|
|
51892
51985
|
// src/commands/common.ts
|
|
51893
51986
|
import { existsSync as existsSync16, readdirSync as readdirSync2, realpathSync as realpathSync3 } from "fs";
|
|
51894
|
-
import { join as
|
|
51987
|
+
import { join as join43, resolve as resolve13 } from "path";
|
|
51895
51988
|
function resolveProject(options = {}) {
|
|
51896
51989
|
const { dir, feature } = options;
|
|
51897
51990
|
let projectRoot;
|
|
@@ -51899,12 +51992,12 @@ function resolveProject(options = {}) {
|
|
|
51899
51992
|
let configPath;
|
|
51900
51993
|
if (dir) {
|
|
51901
51994
|
projectRoot = realpathSync3(resolve13(dir));
|
|
51902
|
-
naxDir =
|
|
51995
|
+
naxDir = join43(projectRoot, ".nax");
|
|
51903
51996
|
if (!existsSync16(naxDir)) {
|
|
51904
51997
|
throw new NaxError(`Directory does not contain a nax project: ${projectRoot}
|
|
51905
51998
|
Expected to find: ${naxDir}`, "NAX_DIR_NOT_FOUND", { projectRoot, naxDir });
|
|
51906
51999
|
}
|
|
51907
|
-
configPath =
|
|
52000
|
+
configPath = join43(naxDir, "config.json");
|
|
51908
52001
|
if (!existsSync16(configPath)) {
|
|
51909
52002
|
throw new NaxError(`.nax directory found but config.json is missing: ${naxDir}
|
|
51910
52003
|
Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
@@ -51912,17 +52005,17 @@ Expected to find: ${configPath}`, "CONFIG_NOT_FOUND", { naxDir, configPath });
|
|
|
51912
52005
|
} else {
|
|
51913
52006
|
const found = findProjectRoot(process.cwd());
|
|
51914
52007
|
if (!found) {
|
|
51915
|
-
const cwdNaxDir =
|
|
52008
|
+
const cwdNaxDir = join43(process.cwd(), ".nax");
|
|
51916
52009
|
if (existsSync16(cwdNaxDir)) {
|
|
51917
|
-
const cwdConfigPath =
|
|
52010
|
+
const cwdConfigPath = join43(cwdNaxDir, "config.json");
|
|
51918
52011
|
throw new NaxError(`.nax directory found but config.json is missing: ${cwdNaxDir}
|
|
51919
52012
|
Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, configPath: cwdConfigPath });
|
|
51920
52013
|
}
|
|
51921
52014
|
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() });
|
|
51922
52015
|
}
|
|
51923
52016
|
projectRoot = found;
|
|
51924
|
-
naxDir =
|
|
51925
|
-
configPath =
|
|
52017
|
+
naxDir = join43(projectRoot, ".nax");
|
|
52018
|
+
configPath = join43(naxDir, "config.json");
|
|
51926
52019
|
}
|
|
51927
52020
|
let featureDir;
|
|
51928
52021
|
if (feature) {
|
|
@@ -51931,8 +52024,8 @@ Expected to find: ${cwdConfigPath}`, "CONFIG_NOT_FOUND", { naxDir: cwdNaxDir, co
|
|
|
51931
52024
|
} catch (error48) {
|
|
51932
52025
|
throw new NaxError(error48.message, "FEATURE_INVALID", { feature });
|
|
51933
52026
|
}
|
|
51934
|
-
const featuresDir =
|
|
51935
|
-
featureDir =
|
|
52027
|
+
const featuresDir = join43(naxDir, "features");
|
|
52028
|
+
featureDir = join43(featuresDir, feature);
|
|
51936
52029
|
if (!existsSync16(featureDir)) {
|
|
51937
52030
|
const availableFeatures = existsSync16(featuresDir) ? readdirSync2(featuresDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name) : [];
|
|
51938
52031
|
const availableMsg = availableFeatures.length > 0 ? `
|
|
@@ -51965,7 +52058,7 @@ async function resolveProjectAsync(options = {}) {
|
|
|
51965
52058
|
}
|
|
51966
52059
|
const isPlainName = !dir.includes("/") && !dir.includes("\\");
|
|
51967
52060
|
if (isPlainName) {
|
|
51968
|
-
const registryIdentityPath =
|
|
52061
|
+
const registryIdentityPath = join43(globalConfigDir(), dir, ".identity");
|
|
51969
52062
|
const identityFile = Bun.file(registryIdentityPath);
|
|
51970
52063
|
if (await identityFile.exists()) {
|
|
51971
52064
|
try {
|
|
@@ -51997,12 +52090,12 @@ function findProjectRoot(startDir) {
|
|
|
51997
52090
|
let current = resolve13(startDir);
|
|
51998
52091
|
let depth = 0;
|
|
51999
52092
|
while (depth < MAX_DIRECTORY_DEPTH) {
|
|
52000
|
-
const naxDir =
|
|
52001
|
-
const configPath =
|
|
52093
|
+
const naxDir = join43(current, ".nax");
|
|
52094
|
+
const configPath = join43(naxDir, "config.json");
|
|
52002
52095
|
if (existsSync16(configPath)) {
|
|
52003
52096
|
return realpathSync3(current);
|
|
52004
52097
|
}
|
|
52005
|
-
const parent =
|
|
52098
|
+
const parent = join43(current, "..");
|
|
52006
52099
|
if (parent === current) {
|
|
52007
52100
|
break;
|
|
52008
52101
|
}
|
|
@@ -53161,10 +53254,10 @@ var init_effectiveness = __esm(() => {
|
|
|
53161
53254
|
|
|
53162
53255
|
// src/execution/progress.ts
|
|
53163
53256
|
import { appendFile as appendFile2, mkdir as mkdir7 } from "fs/promises";
|
|
53164
|
-
import { join as
|
|
53257
|
+
import { join as join46 } from "path";
|
|
53165
53258
|
async function appendProgress(featureDir, storyId, status, message) {
|
|
53166
53259
|
await mkdir7(featureDir, { recursive: true });
|
|
53167
|
-
const progressPath =
|
|
53260
|
+
const progressPath = join46(featureDir, "progress.txt");
|
|
53168
53261
|
const timestamp = new Date().toISOString();
|
|
53169
53262
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
53170
53263
|
`;
|
|
@@ -53358,7 +53451,7 @@ var init_completion = __esm(() => {
|
|
|
53358
53451
|
|
|
53359
53452
|
// src/constitution/loader.ts
|
|
53360
53453
|
import { existsSync as existsSync19 } from "fs";
|
|
53361
|
-
import { join as
|
|
53454
|
+
import { join as join47 } from "path";
|
|
53362
53455
|
function truncateToTokens(text, maxTokens) {
|
|
53363
53456
|
const maxChars = maxTokens * 3;
|
|
53364
53457
|
if (text.length <= maxChars) {
|
|
@@ -53380,7 +53473,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53380
53473
|
}
|
|
53381
53474
|
let combinedContent = "";
|
|
53382
53475
|
if (!config2.skipGlobal) {
|
|
53383
|
-
const globalPath =
|
|
53476
|
+
const globalPath = join47(globalConfigDir(), config2.path);
|
|
53384
53477
|
if (existsSync19(globalPath)) {
|
|
53385
53478
|
const validatedPath = validateFilePath(globalPath, globalConfigDir());
|
|
53386
53479
|
const globalFile = Bun.file(validatedPath);
|
|
@@ -53390,7 +53483,7 @@ async function loadConstitution(projectDir, config2) {
|
|
|
53390
53483
|
}
|
|
53391
53484
|
}
|
|
53392
53485
|
}
|
|
53393
|
-
const projectPath =
|
|
53486
|
+
const projectPath = join47(projectDir, config2.path);
|
|
53394
53487
|
if (existsSync19(projectPath)) {
|
|
53395
53488
|
const validatedPath = validateFilePath(projectPath, projectDir);
|
|
53396
53489
|
const projectFile = Bun.file(validatedPath);
|
|
@@ -53964,6 +54057,64 @@ var init_non_blocking_fix = __esm(() => {
|
|
|
53964
54057
|
DEFAULT_DEPS = { captureSnapshotRef, rollbackToRef };
|
|
53965
54058
|
});
|
|
53966
54059
|
|
|
54060
|
+
// src/execution/story-orchestrator-logging.ts
|
|
54061
|
+
function formatPhaseResultMessage(opName, success2, stage, status) {
|
|
54062
|
+
if (opName === "greenfield-gate") {
|
|
54063
|
+
return success2 ? "Greenfield-gate: pre-existing tests detected (not greenfield) \u2014 proceeding with normal TDD" : "Greenfield-gate: no pre-existing tests \u2014 greenfield run, pausing TDD test-writer";
|
|
54064
|
+
}
|
|
54065
|
+
if (status === "skipped") {
|
|
54066
|
+
return `Phase skipped: ${opName}`;
|
|
54067
|
+
}
|
|
54068
|
+
if (stage === "rectification") {
|
|
54069
|
+
return `Rectification strategy completed: ${opName}`;
|
|
54070
|
+
}
|
|
54071
|
+
return success2 ? `Phase passed: ${opName}` : `Phase failed: ${opName}`;
|
|
54072
|
+
}
|
|
54073
|
+
function buildPhaseOutcomeLogData(storyId, opName, output, durationMs) {
|
|
54074
|
+
if (output === null || output === undefined || typeof output !== "object")
|
|
54075
|
+
return null;
|
|
54076
|
+
const r = output;
|
|
54077
|
+
const success2 = r.success === true || r.passed === true;
|
|
54078
|
+
const findingsCount = Array.isArray(r.normalizedFindings) ? r.normalizedFindings.length : Array.isArray(r.findings) ? r.findings.length : undefined;
|
|
54079
|
+
const status = typeof r.status === "string" ? r.status : undefined;
|
|
54080
|
+
const data = { storyId, phase: opName, durationMs };
|
|
54081
|
+
if (findingsCount !== undefined)
|
|
54082
|
+
data.findingsCount = findingsCount;
|
|
54083
|
+
if (status !== undefined)
|
|
54084
|
+
data.status = status;
|
|
54085
|
+
if (typeof r.failureCategory === "string")
|
|
54086
|
+
data.failureCategory = r.failureCategory;
|
|
54087
|
+
if (typeof r.reviewReason === "string")
|
|
54088
|
+
data.reviewReason = r.reviewReason;
|
|
54089
|
+
return { success: success2, data };
|
|
54090
|
+
}
|
|
54091
|
+
function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTddPhase, stage, progressData = {}) {
|
|
54092
|
+
if (isTddPhase)
|
|
54093
|
+
return;
|
|
54094
|
+
if (opName === "semantic-review" || opName === "adversarial-review")
|
|
54095
|
+
return;
|
|
54096
|
+
const built = buildPhaseOutcomeLogData(storyId, opName, output, durationMs);
|
|
54097
|
+
if (!built)
|
|
54098
|
+
return;
|
|
54099
|
+
const { success: success2 } = built;
|
|
54100
|
+
const data = { ...built.data, ...progressData };
|
|
54101
|
+
const status = typeof built.data.status === "string" ? built.data.status : undefined;
|
|
54102
|
+
const logger = getSafeLogger();
|
|
54103
|
+
const message = formatPhaseResultMessage(opName, success2, stage, status);
|
|
54104
|
+
if (stage === "rectification") {
|
|
54105
|
+
logger?.info("story-orchestrator", message, data);
|
|
54106
|
+
return;
|
|
54107
|
+
}
|
|
54108
|
+
if (success2) {
|
|
54109
|
+
logger?.info("story-orchestrator", message, data);
|
|
54110
|
+
} else {
|
|
54111
|
+
logger?.warn("story-orchestrator", message, data);
|
|
54112
|
+
}
|
|
54113
|
+
}
|
|
54114
|
+
var init_story_orchestrator_logging = __esm(() => {
|
|
54115
|
+
init_logger2();
|
|
54116
|
+
});
|
|
54117
|
+
|
|
53967
54118
|
// src/execution/story-orchestrator.ts
|
|
53968
54119
|
async function refreshReviewInputForDispatch(opName, input) {
|
|
53969
54120
|
if (opName !== "semantic-review" && opName !== "adversarial-review")
|
|
@@ -54024,15 +54175,6 @@ async function refreshReviewInputForDispatch(opName, input) {
|
|
|
54024
54175
|
return fallback;
|
|
54025
54176
|
}
|
|
54026
54177
|
}
|
|
54027
|
-
function formatPhaseResultMessage(opName, success2, stage) {
|
|
54028
|
-
if (opName === "greenfield-gate") {
|
|
54029
|
-
return success2 ? "Greenfield-gate: pre-existing tests detected (not greenfield) \u2014 proceeding with normal TDD" : "Greenfield-gate: no pre-existing tests \u2014 greenfield run, pausing TDD test-writer";
|
|
54030
|
-
}
|
|
54031
|
-
if (stage === "rectification") {
|
|
54032
|
-
return `Rectification strategy completed: ${opName}`;
|
|
54033
|
-
}
|
|
54034
|
-
return success2 ? `Phase passed: ${opName}` : `Phase failed: ${opName}`;
|
|
54035
|
-
}
|
|
54036
54178
|
function isSlot(value) {
|
|
54037
54179
|
return value !== null && typeof value === "object" && "op" in value && "input" in value && typeof value.op?.kind === "string";
|
|
54038
54180
|
}
|
|
@@ -54228,46 +54370,6 @@ function logUnifiedReviewPhaseStart(storyId, opName) {
|
|
|
54228
54370
|
logger?.info("review", "Running adversarial check", { storyId });
|
|
54229
54371
|
}
|
|
54230
54372
|
}
|
|
54231
|
-
function buildPhaseOutcomeLogData(storyId, opName, output, durationMs) {
|
|
54232
|
-
if (output === null || output === undefined || typeof output !== "object")
|
|
54233
|
-
return null;
|
|
54234
|
-
const r = output;
|
|
54235
|
-
const success2 = r.success === true || r.passed === true;
|
|
54236
|
-
const findingsCount = Array.isArray(r.normalizedFindings) ? r.normalizedFindings.length : Array.isArray(r.findings) ? r.findings.length : undefined;
|
|
54237
|
-
const status = typeof r.status === "string" ? r.status : undefined;
|
|
54238
|
-
const data = { storyId, phase: opName, durationMs };
|
|
54239
|
-
if (findingsCount !== undefined)
|
|
54240
|
-
data.findingsCount = findingsCount;
|
|
54241
|
-
if (status !== undefined)
|
|
54242
|
-
data.status = status;
|
|
54243
|
-
if (typeof r.failureCategory === "string")
|
|
54244
|
-
data.failureCategory = r.failureCategory;
|
|
54245
|
-
if (typeof r.reviewReason === "string")
|
|
54246
|
-
data.reviewReason = r.reviewReason;
|
|
54247
|
-
return { success: success2, data };
|
|
54248
|
-
}
|
|
54249
|
-
function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTddPhase, stage, progressData = {}) {
|
|
54250
|
-
if (isTddPhase)
|
|
54251
|
-
return;
|
|
54252
|
-
if (opName === "semantic-review" || opName === "adversarial-review")
|
|
54253
|
-
return;
|
|
54254
|
-
const built = buildPhaseOutcomeLogData(storyId, opName, output, durationMs);
|
|
54255
|
-
if (!built)
|
|
54256
|
-
return;
|
|
54257
|
-
const { success: success2 } = built;
|
|
54258
|
-
const data = { ...built.data, ...progressData };
|
|
54259
|
-
const logger = getSafeLogger();
|
|
54260
|
-
const message = formatPhaseResultMessage(opName, success2, stage);
|
|
54261
|
-
if (stage === "rectification") {
|
|
54262
|
-
logger?.info("story-orchestrator", message, data);
|
|
54263
|
-
return;
|
|
54264
|
-
}
|
|
54265
|
-
if (success2) {
|
|
54266
|
-
logger?.info("story-orchestrator", message, data);
|
|
54267
|
-
} else {
|
|
54268
|
-
logger?.warn("story-orchestrator", message, data);
|
|
54269
|
-
}
|
|
54270
|
-
}
|
|
54271
54373
|
function logUnifiedReviewPhaseResult(storyId, opName, output) {
|
|
54272
54374
|
const logger = getSafeLogger();
|
|
54273
54375
|
const payload = toReviewDecisionPayload(opName, output);
|
|
@@ -54723,6 +54825,7 @@ var init_story_orchestrator = __esm(() => {
|
|
|
54723
54825
|
init_prepare_inputs();
|
|
54724
54826
|
init_git();
|
|
54725
54827
|
init_non_blocking_fix();
|
|
54828
|
+
init_story_orchestrator_logging();
|
|
54726
54829
|
_storyOrchestratorDeps = {
|
|
54727
54830
|
callOp,
|
|
54728
54831
|
runFixCycle,
|
|
@@ -54787,7 +54890,7 @@ var init_story_orchestrator = __esm(() => {
|
|
|
54787
54890
|
});
|
|
54788
54891
|
|
|
54789
54892
|
// src/execution/build-plan-for-strategy.ts
|
|
54790
|
-
import { join as
|
|
54893
|
+
import { join as join48 } from "path";
|
|
54791
54894
|
function requiresInitialRefCapture(strategy) {
|
|
54792
54895
|
return isThreeSessionStrategy(strategy);
|
|
54793
54896
|
}
|
|
@@ -54833,13 +54936,14 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
54833
54936
|
}
|
|
54834
54937
|
if (shouldRunRectification(config2) && inputs.rectification) {
|
|
54835
54938
|
const sink = makeDeclarationSink();
|
|
54836
|
-
const packageDir =
|
|
54939
|
+
const packageDir = join48(ctx.packageDir, story.workdir ?? "");
|
|
54837
54940
|
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.packageDir, story.workdir);
|
|
54838
54941
|
const strategies = [];
|
|
54839
|
-
|
|
54942
|
+
const pkgQuality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
54943
|
+
if (pkgQuality?.commands?.lintFix || pkgQuality?.commands?.lintFixScoped) {
|
|
54840
54944
|
strategies.push(makeMechanicalLintFixStrategy());
|
|
54841
54945
|
}
|
|
54842
|
-
if (
|
|
54946
|
+
if (pkgQuality?.commands?.formatFix || pkgQuality?.commands?.formatFixScoped) {
|
|
54843
54947
|
strategies.push(makeMechanicalFormatFixStrategy());
|
|
54844
54948
|
}
|
|
54845
54949
|
if (inputs.fullSuiteGate && (isThreeSession || regressionMode === "per-story")) {
|
|
@@ -56366,7 +56470,7 @@ function buildFrontmatter(story, ctx, role) {
|
|
|
56366
56470
|
}
|
|
56367
56471
|
|
|
56368
56472
|
// src/cli/prompts-tdd.ts
|
|
56369
|
-
import { join as
|
|
56473
|
+
import { join as join49 } from "path";
|
|
56370
56474
|
async function handleThreeSessionTddPrompts(story, ctx, outputDir, logger) {
|
|
56371
56475
|
const [testWriterPrompt, implementerPrompt, verifierPrompt] = await Promise.all([
|
|
56372
56476
|
TddPromptBuilder.for("test-writer", { isolation: "strict" }).withLoader(ctx.workdir, ctx.config).story(story).context(ctx.contextMarkdown).constitution(ctx.constitution?.content).testCommand(ctx.config.quality?.commands?.test).build(),
|
|
@@ -56385,7 +56489,7 @@ ${frontmatter}---
|
|
|
56385
56489
|
|
|
56386
56490
|
${session.prompt}`;
|
|
56387
56491
|
if (outputDir) {
|
|
56388
|
-
const promptFile =
|
|
56492
|
+
const promptFile = join49(outputDir, `${story.id}.${session.role}.md`);
|
|
56389
56493
|
await Bun.write(promptFile, fullOutput);
|
|
56390
56494
|
logger.info("cli", "Written TDD prompt file", {
|
|
56391
56495
|
storyId: story.id,
|
|
@@ -56401,7 +56505,7 @@ ${"=".repeat(80)}`);
|
|
|
56401
56505
|
}
|
|
56402
56506
|
}
|
|
56403
56507
|
if (outputDir && ctx.contextMarkdown) {
|
|
56404
|
-
const contextFile =
|
|
56508
|
+
const contextFile = join49(outputDir, `${story.id}.context.md`);
|
|
56405
56509
|
const frontmatter = buildFrontmatter(story, ctx);
|
|
56406
56510
|
const contextOutput = `---
|
|
56407
56511
|
${frontmatter}---
|
|
@@ -56416,16 +56520,16 @@ var init_prompts_tdd = __esm(() => {
|
|
|
56416
56520
|
|
|
56417
56521
|
// src/cli/prompts-main.ts
|
|
56418
56522
|
import { existsSync as existsSync20, mkdirSync as mkdirSync3 } from "fs";
|
|
56419
|
-
import { join as
|
|
56523
|
+
import { join as join50 } from "path";
|
|
56420
56524
|
async function promptsCommand(options) {
|
|
56421
56525
|
const logger = getLogger();
|
|
56422
56526
|
const { feature, workdir, config: config2, storyId, outputDir } = options;
|
|
56423
|
-
const naxDir =
|
|
56527
|
+
const naxDir = join50(workdir, ".nax");
|
|
56424
56528
|
if (!existsSync20(naxDir)) {
|
|
56425
56529
|
throw new Error(`.nax directory not found. Run 'nax init' first in ${workdir}`);
|
|
56426
56530
|
}
|
|
56427
|
-
const featureDir =
|
|
56428
|
-
const prdPath =
|
|
56531
|
+
const featureDir = join50(naxDir, "features", feature);
|
|
56532
|
+
const prdPath = join50(featureDir, "prd.json");
|
|
56429
56533
|
if (!existsSync20(prdPath)) {
|
|
56430
56534
|
throw new Error(`Feature "${feature}" not found or missing prd.json`);
|
|
56431
56535
|
}
|
|
@@ -56492,10 +56596,10 @@ ${frontmatter}---
|
|
|
56492
56596
|
|
|
56493
56597
|
${ctx.prompt}`;
|
|
56494
56598
|
if (outputDir) {
|
|
56495
|
-
const promptFile =
|
|
56599
|
+
const promptFile = join50(outputDir, `${story.id}.prompt.md`);
|
|
56496
56600
|
await Bun.write(promptFile, fullOutput);
|
|
56497
56601
|
if (ctx.contextMarkdown) {
|
|
56498
|
-
const contextFile =
|
|
56602
|
+
const contextFile = join50(outputDir, `${story.id}.context.md`);
|
|
56499
56603
|
const contextOutput = `---
|
|
56500
56604
|
${frontmatter}---
|
|
56501
56605
|
|
|
@@ -56531,12 +56635,12 @@ var init_prompts_main = __esm(() => {
|
|
|
56531
56635
|
|
|
56532
56636
|
// src/cli/prompts-init.ts
|
|
56533
56637
|
import { existsSync as existsSync21, mkdirSync as mkdirSync4 } from "fs";
|
|
56534
|
-
import { join as
|
|
56638
|
+
import { join as join51 } from "path";
|
|
56535
56639
|
async function promptsInitCommand(options) {
|
|
56536
56640
|
const { workdir, force = false, autoWireConfig = true } = options;
|
|
56537
|
-
const templatesDir =
|
|
56641
|
+
const templatesDir = join51(workdir, ".nax", "templates");
|
|
56538
56642
|
mkdirSync4(templatesDir, { recursive: true });
|
|
56539
|
-
const existingFiles = TEMPLATE_ROLES.map((t) => t.file).filter((f) => existsSync21(
|
|
56643
|
+
const existingFiles = TEMPLATE_ROLES.map((t) => t.file).filter((f) => existsSync21(join51(templatesDir, f)));
|
|
56540
56644
|
if (existingFiles.length > 0 && !force) {
|
|
56541
56645
|
_promptsInitDeps.warn(`[WARN] nax/templates/ already contains files: ${existingFiles.join(", ")}. No files overwritten.
|
|
56542
56646
|
Pass --force to overwrite existing templates.`);
|
|
@@ -56544,7 +56648,7 @@ async function promptsInitCommand(options) {
|
|
|
56544
56648
|
}
|
|
56545
56649
|
const written = [];
|
|
56546
56650
|
for (const template of TEMPLATE_ROLES) {
|
|
56547
|
-
const filePath =
|
|
56651
|
+
const filePath = join51(templatesDir, template.file);
|
|
56548
56652
|
const roleBody = template.role === "implementer" ? buildRoleTaskSection(template.role, template.variant) : buildRoleTaskSection(template.role);
|
|
56549
56653
|
const content = TEMPLATE_HEADER + roleBody;
|
|
56550
56654
|
await Bun.write(filePath, content);
|
|
@@ -56560,7 +56664,7 @@ async function promptsInitCommand(options) {
|
|
|
56560
56664
|
return written;
|
|
56561
56665
|
}
|
|
56562
56666
|
async function autoWirePromptsConfig(workdir) {
|
|
56563
|
-
const configPath =
|
|
56667
|
+
const configPath = join51(workdir, "nax.config.json");
|
|
56564
56668
|
if (!existsSync21(configPath)) {
|
|
56565
56669
|
const exampleConfig = JSON.stringify({
|
|
56566
56670
|
prompts: {
|
|
@@ -56728,7 +56832,7 @@ __export(exports_init_context, {
|
|
|
56728
56832
|
generateContextTemplate: () => generateContextTemplate,
|
|
56729
56833
|
_initContextDeps: () => _initContextDeps
|
|
56730
56834
|
});
|
|
56731
|
-
import { basename as basename9, join as
|
|
56835
|
+
import { basename as basename9, join as join52 } from "path";
|
|
56732
56836
|
async function bunFileExists(path13) {
|
|
56733
56837
|
return Bun.file(path13).exists();
|
|
56734
56838
|
}
|
|
@@ -56763,7 +56867,7 @@ async function findFiles(dir, maxFiles = 200) {
|
|
|
56763
56867
|
return [];
|
|
56764
56868
|
}
|
|
56765
56869
|
async function readPackageManifest(projectRoot) {
|
|
56766
|
-
const packageJsonPath =
|
|
56870
|
+
const packageJsonPath = join52(projectRoot, "package.json");
|
|
56767
56871
|
if (!await bunFileExists(packageJsonPath)) {
|
|
56768
56872
|
return null;
|
|
56769
56873
|
}
|
|
@@ -56781,7 +56885,7 @@ async function readPackageManifest(projectRoot) {
|
|
|
56781
56885
|
}
|
|
56782
56886
|
}
|
|
56783
56887
|
async function readReadmeSnippet(projectRoot) {
|
|
56784
|
-
const readmePath =
|
|
56888
|
+
const readmePath = join52(projectRoot, "README.md");
|
|
56785
56889
|
if (!await bunFileExists(readmePath)) {
|
|
56786
56890
|
return null;
|
|
56787
56891
|
}
|
|
@@ -56799,7 +56903,7 @@ async function detectEntryPoints(projectRoot) {
|
|
|
56799
56903
|
const candidates = ["src/index.ts", "src/main.ts", "main.go", "src/lib.rs"];
|
|
56800
56904
|
const found = [];
|
|
56801
56905
|
for (const candidate of candidates) {
|
|
56802
|
-
const path13 =
|
|
56906
|
+
const path13 = join52(projectRoot, candidate);
|
|
56803
56907
|
if (await bunFileExists(path13)) {
|
|
56804
56908
|
found.push(candidate);
|
|
56805
56909
|
}
|
|
@@ -56810,7 +56914,7 @@ async function detectConfigFiles(projectRoot) {
|
|
|
56810
56914
|
const candidates = ["tsconfig.json", "biome.json", "turbo.json", ".env.example"];
|
|
56811
56915
|
const found = [];
|
|
56812
56916
|
for (const candidate of candidates) {
|
|
56813
|
-
const path13 =
|
|
56917
|
+
const path13 = join52(projectRoot, candidate);
|
|
56814
56918
|
if (await bunFileExists(path13)) {
|
|
56815
56919
|
found.push(candidate);
|
|
56816
56920
|
}
|
|
@@ -56971,8 +57075,8 @@ function generatePackageContextTemplate(packagePath) {
|
|
|
56971
57075
|
}
|
|
56972
57076
|
async function initPackage(repoRoot, packagePath, force = false) {
|
|
56973
57077
|
const logger = getLogger();
|
|
56974
|
-
const naxDir =
|
|
56975
|
-
const contextPath =
|
|
57078
|
+
const naxDir = join52(repoRoot, ".nax", "mono", packagePath);
|
|
57079
|
+
const contextPath = join52(naxDir, "context.md");
|
|
56976
57080
|
if (await bunFileExists(contextPath) && !force) {
|
|
56977
57081
|
logger.info("init", "Package context.md already exists (use --force to overwrite)", {
|
|
56978
57082
|
storyId: "init-context",
|
|
@@ -56989,8 +57093,8 @@ async function initPackage(repoRoot, packagePath, force = false) {
|
|
|
56989
57093
|
}
|
|
56990
57094
|
async function initContext(projectRoot, options = {}) {
|
|
56991
57095
|
const logger = getLogger();
|
|
56992
|
-
const naxDir =
|
|
56993
|
-
const contextPath =
|
|
57096
|
+
const naxDir = join52(projectRoot, ".nax");
|
|
57097
|
+
const contextPath = join52(naxDir, "context.md");
|
|
56994
57098
|
if (await bunFileExists(contextPath) && !options.force) {
|
|
56995
57099
|
logger.info("init", "context.md already exists, skipping (use --force to overwrite)", {
|
|
56996
57100
|
storyId: "init-context",
|
|
@@ -57026,9 +57130,9 @@ var init_init_context = __esm(() => {
|
|
|
57026
57130
|
|
|
57027
57131
|
// src/cli/init-detect.ts
|
|
57028
57132
|
import { existsSync as existsSync22, readFileSync } from "fs";
|
|
57029
|
-
import { join as
|
|
57133
|
+
import { join as join53 } from "path";
|
|
57030
57134
|
function readPackageJson(projectRoot) {
|
|
57031
|
-
const pkgPath =
|
|
57135
|
+
const pkgPath = join53(projectRoot, "package.json");
|
|
57032
57136
|
if (!existsSync22(pkgPath))
|
|
57033
57137
|
return;
|
|
57034
57138
|
try {
|
|
@@ -57071,41 +57175,41 @@ function detectStack(projectRoot) {
|
|
|
57071
57175
|
};
|
|
57072
57176
|
}
|
|
57073
57177
|
function detectRuntime(projectRoot) {
|
|
57074
|
-
if (existsSync22(
|
|
57178
|
+
if (existsSync22(join53(projectRoot, "bun.lockb")) || existsSync22(join53(projectRoot, "bunfig.toml"))) {
|
|
57075
57179
|
return "bun";
|
|
57076
57180
|
}
|
|
57077
|
-
if (existsSync22(
|
|
57181
|
+
if (existsSync22(join53(projectRoot, "package-lock.json")) || existsSync22(join53(projectRoot, "yarn.lock")) || existsSync22(join53(projectRoot, "pnpm-lock.yaml"))) {
|
|
57078
57182
|
return "node";
|
|
57079
57183
|
}
|
|
57080
57184
|
return "unknown";
|
|
57081
57185
|
}
|
|
57082
57186
|
function detectLanguage2(projectRoot) {
|
|
57083
|
-
if (existsSync22(
|
|
57187
|
+
if (existsSync22(join53(projectRoot, "tsconfig.json")))
|
|
57084
57188
|
return "typescript";
|
|
57085
|
-
if (existsSync22(
|
|
57189
|
+
if (existsSync22(join53(projectRoot, "pyproject.toml")) || existsSync22(join53(projectRoot, "setup.py"))) {
|
|
57086
57190
|
return "python";
|
|
57087
57191
|
}
|
|
57088
|
-
if (existsSync22(
|
|
57192
|
+
if (existsSync22(join53(projectRoot, "Cargo.toml")))
|
|
57089
57193
|
return "rust";
|
|
57090
|
-
if (existsSync22(
|
|
57194
|
+
if (existsSync22(join53(projectRoot, "go.mod")))
|
|
57091
57195
|
return "go";
|
|
57092
57196
|
return "unknown";
|
|
57093
57197
|
}
|
|
57094
57198
|
function detectLinter(projectRoot) {
|
|
57095
|
-
if (existsSync22(
|
|
57199
|
+
if (existsSync22(join53(projectRoot, "biome.json")) || existsSync22(join53(projectRoot, "biome.jsonc"))) {
|
|
57096
57200
|
return "biome";
|
|
57097
57201
|
}
|
|
57098
|
-
if (existsSync22(
|
|
57202
|
+
if (existsSync22(join53(projectRoot, ".eslintrc.json")) || existsSync22(join53(projectRoot, ".eslintrc.js")) || existsSync22(join53(projectRoot, "eslint.config.js"))) {
|
|
57099
57203
|
return "eslint";
|
|
57100
57204
|
}
|
|
57101
57205
|
return "unknown";
|
|
57102
57206
|
}
|
|
57103
57207
|
function detectMonorepo(projectRoot) {
|
|
57104
|
-
if (existsSync22(
|
|
57208
|
+
if (existsSync22(join53(projectRoot, "turbo.json")))
|
|
57105
57209
|
return "turborepo";
|
|
57106
|
-
if (existsSync22(
|
|
57210
|
+
if (existsSync22(join53(projectRoot, "nx.json")))
|
|
57107
57211
|
return "nx";
|
|
57108
|
-
if (existsSync22(
|
|
57212
|
+
if (existsSync22(join53(projectRoot, "pnpm-workspace.yaml")))
|
|
57109
57213
|
return "pnpm-workspaces";
|
|
57110
57214
|
const pkg = readPackageJson(projectRoot);
|
|
57111
57215
|
if (pkg?.workspaces)
|
|
@@ -57249,7 +57353,7 @@ __export(exports_init, {
|
|
|
57249
57353
|
});
|
|
57250
57354
|
import { existsSync as existsSync23 } from "fs";
|
|
57251
57355
|
import { mkdir as mkdir8 } from "fs/promises";
|
|
57252
|
-
import { join as
|
|
57356
|
+
import { join as join54 } from "path";
|
|
57253
57357
|
function validateProjectName(name) {
|
|
57254
57358
|
if (!name)
|
|
57255
57359
|
return { valid: false, error: "name must be non-empty" };
|
|
@@ -57285,7 +57389,7 @@ async function checkInitCollision(name, currentWorkdir, currentRemote) {
|
|
|
57285
57389
|
}
|
|
57286
57390
|
async function updateGitignore(projectRoot) {
|
|
57287
57391
|
const logger = getLogger();
|
|
57288
|
-
const gitignorePath =
|
|
57392
|
+
const gitignorePath = join54(projectRoot, ".gitignore");
|
|
57289
57393
|
let existing = "";
|
|
57290
57394
|
if (existsSync23(gitignorePath)) {
|
|
57291
57395
|
existing = await Bun.file(gitignorePath).text();
|
|
@@ -57371,7 +57475,7 @@ async function initGlobal() {
|
|
|
57371
57475
|
await mkdir8(globalDir, { recursive: true });
|
|
57372
57476
|
logger.info("init", "Created global config directory", { path: globalDir });
|
|
57373
57477
|
}
|
|
57374
|
-
const configPath =
|
|
57478
|
+
const configPath = join54(globalDir, "config.json");
|
|
57375
57479
|
if (!existsSync23(configPath)) {
|
|
57376
57480
|
await Bun.write(configPath, `${JSON.stringify(MINIMAL_GLOBAL_CONFIG, null, 2)}
|
|
57377
57481
|
`);
|
|
@@ -57379,14 +57483,14 @@ async function initGlobal() {
|
|
|
57379
57483
|
} else {
|
|
57380
57484
|
logger.info("init", "Global config already exists", { path: configPath });
|
|
57381
57485
|
}
|
|
57382
|
-
const constitutionPath =
|
|
57486
|
+
const constitutionPath = join54(globalDir, "constitution.md");
|
|
57383
57487
|
if (!existsSync23(constitutionPath)) {
|
|
57384
57488
|
await Bun.write(constitutionPath, buildConstitution({ runtime: "unknown", language: "unknown", linter: "unknown", monorepo: "none" }));
|
|
57385
57489
|
logger.info("init", "Created global constitution", { path: constitutionPath });
|
|
57386
57490
|
} else {
|
|
57387
57491
|
logger.info("init", "Global constitution already exists", { path: constitutionPath });
|
|
57388
57492
|
}
|
|
57389
|
-
const hooksDir =
|
|
57493
|
+
const hooksDir = join54(globalDir, "hooks");
|
|
57390
57494
|
if (!existsSync23(hooksDir)) {
|
|
57391
57495
|
await mkdir8(hooksDir, { recursive: true });
|
|
57392
57496
|
logger.info("init", "Created global hooks directory", { path: hooksDir });
|
|
@@ -57419,7 +57523,7 @@ async function initProject(projectRoot, options) {
|
|
|
57419
57523
|
if (detectedName && !options?.force) {
|
|
57420
57524
|
const collision = await checkInitCollision(detectedName, projectRoot, currentRemote);
|
|
57421
57525
|
if (collision.collision && collision.existing) {
|
|
57422
|
-
const configPath2 =
|
|
57526
|
+
const configPath2 = join54(projectDir, "config.json");
|
|
57423
57527
|
throw new NaxError([
|
|
57424
57528
|
`Project name collision: "${detectedName}"`,
|
|
57425
57529
|
` This project: ${projectRoot}`,
|
|
@@ -57447,7 +57551,7 @@ async function initProject(projectRoot, options) {
|
|
|
57447
57551
|
linter: stack.linter,
|
|
57448
57552
|
monorepo: stack.monorepo
|
|
57449
57553
|
});
|
|
57450
|
-
const configPath =
|
|
57554
|
+
const configPath = join54(projectDir, "config.json");
|
|
57451
57555
|
if (!existsSync23(configPath)) {
|
|
57452
57556
|
await Bun.write(configPath, `${JSON.stringify(projectConfig, null, 2)}
|
|
57453
57557
|
`);
|
|
@@ -57456,14 +57560,14 @@ async function initProject(projectRoot, options) {
|
|
|
57456
57560
|
logger.info("init", "Project config already exists", { path: configPath });
|
|
57457
57561
|
}
|
|
57458
57562
|
await initContext(projectRoot, { ai: options?.ai, force: options?.force });
|
|
57459
|
-
const constitutionPath =
|
|
57563
|
+
const constitutionPath = join54(projectDir, "constitution.md");
|
|
57460
57564
|
if (!existsSync23(constitutionPath) || options?.force) {
|
|
57461
57565
|
await Bun.write(constitutionPath, buildConstitution(stack));
|
|
57462
57566
|
logger.info("init", "Created project constitution", { path: constitutionPath });
|
|
57463
57567
|
} else {
|
|
57464
57568
|
logger.info("init", "Project constitution already exists", { path: constitutionPath });
|
|
57465
57569
|
}
|
|
57466
|
-
const hooksDir =
|
|
57570
|
+
const hooksDir = join54(projectDir, "hooks");
|
|
57467
57571
|
if (!existsSync23(hooksDir)) {
|
|
57468
57572
|
await mkdir8(hooksDir, { recursive: true });
|
|
57469
57573
|
logger.info("init", "Created project hooks directory", { path: hooksDir });
|
|
@@ -57525,36 +57629,36 @@ var init_init2 = __esm(() => {
|
|
|
57525
57629
|
});
|
|
57526
57630
|
|
|
57527
57631
|
// src/cli/setup-analyze.ts
|
|
57528
|
-
import { join as
|
|
57632
|
+
import { join as join55 } from "path";
|
|
57529
57633
|
async function detectPackageManager(workdir) {
|
|
57530
57634
|
const { fileExists } = _analyzeRepoDeps;
|
|
57531
|
-
if (await fileExists(
|
|
57635
|
+
if (await fileExists(join55(workdir, "bun.lock")))
|
|
57532
57636
|
return { pmRunPrefix: "bun run", pmDlx: "bunx" };
|
|
57533
|
-
if (await fileExists(
|
|
57637
|
+
if (await fileExists(join55(workdir, "bun.lockb")))
|
|
57534
57638
|
return { pmRunPrefix: "bun run", pmDlx: "bunx" };
|
|
57535
|
-
if (await fileExists(
|
|
57639
|
+
if (await fileExists(join55(workdir, "package-lock.json")))
|
|
57536
57640
|
return { pmRunPrefix: "npm run", pmDlx: "npx" };
|
|
57537
|
-
if (await fileExists(
|
|
57641
|
+
if (await fileExists(join55(workdir, "yarn.lock")))
|
|
57538
57642
|
return { pmRunPrefix: "yarn", pmDlx: "yarn dlx" };
|
|
57539
|
-
if (await fileExists(
|
|
57643
|
+
if (await fileExists(join55(workdir, "pnpm-lock.yaml")))
|
|
57540
57644
|
return { pmRunPrefix: "pnpm run", pmDlx: "pnpx" };
|
|
57541
57645
|
return { pmRunPrefix: "npm run", pmDlx: "npx" };
|
|
57542
57646
|
}
|
|
57543
57647
|
async function detectOrchestrator(workdir) {
|
|
57544
57648
|
const { fileExists } = _analyzeRepoDeps;
|
|
57545
|
-
if (await fileExists(
|
|
57649
|
+
if (await fileExists(join55(workdir, "turbo.json")))
|
|
57546
57650
|
return "turbo";
|
|
57547
|
-
if (await fileExists(
|
|
57651
|
+
if (await fileExists(join55(workdir, "nx.json")))
|
|
57548
57652
|
return "nx";
|
|
57549
57653
|
return "none";
|
|
57550
57654
|
}
|
|
57551
57655
|
async function getMissingScripts(packageDir) {
|
|
57552
|
-
const pkg = await _analyzeRepoDeps.readJson(
|
|
57656
|
+
const pkg = await _analyzeRepoDeps.readJson(join55(packageDir, "package.json"));
|
|
57553
57657
|
const scripts = pkg?.scripts ?? {};
|
|
57554
57658
|
return CANONICAL_SCRIPTS.filter((s) => !(s in scripts));
|
|
57555
57659
|
}
|
|
57556
57660
|
async function buildPackageFacts(workdir, relativeDir, testPatternMap) {
|
|
57557
|
-
const packageDir = relativeDir === "" ? workdir :
|
|
57661
|
+
const packageDir = relativeDir === "" ? workdir : join55(workdir, relativeDir);
|
|
57558
57662
|
const [profile, missingScripts] = await Promise.all([
|
|
57559
57663
|
_analyzeRepoDeps.detectProjectProfile(packageDir, {}),
|
|
57560
57664
|
getMissingScripts(packageDir)
|
|
@@ -57615,7 +57719,7 @@ var init_setup_analyze = __esm(() => {
|
|
|
57615
57719
|
});
|
|
57616
57720
|
|
|
57617
57721
|
// src/cli/setup-fill.ts
|
|
57618
|
-
import { join as
|
|
57722
|
+
import { join as join56 } from "path";
|
|
57619
57723
|
async function addScriptToPackageJson(pkgJsonPath, key, value) {
|
|
57620
57724
|
const pkg = await _fillScriptsDeps.readJson(pkgJsonPath) ?? {};
|
|
57621
57725
|
const scripts = pkg.scripts ?? {};
|
|
@@ -57638,18 +57742,18 @@ async function fillScripts(workdir, analysis) {
|
|
|
57638
57742
|
if (shape === "single") {
|
|
57639
57743
|
const rootPkg = packages[0];
|
|
57640
57744
|
if (rootPkg?.missingScripts.includes(TYPE_CHECK_KEY)) {
|
|
57641
|
-
await addScriptToPackageJson(
|
|
57745
|
+
await addScriptToPackageJson(join56(workdir, "package.json"), TYPE_CHECK_KEY, TYPE_CHECK_SCRIPT);
|
|
57642
57746
|
}
|
|
57643
57747
|
return;
|
|
57644
57748
|
}
|
|
57645
57749
|
for (const pkg of packages) {
|
|
57646
57750
|
if (!pkg.missingScripts.includes(TYPE_CHECK_KEY))
|
|
57647
57751
|
continue;
|
|
57648
|
-
await addScriptToPackageJson(
|
|
57752
|
+
await addScriptToPackageJson(join56(workdir, pkg.relativeDir, "package.json"), TYPE_CHECK_KEY, TYPE_CHECK_SCRIPT);
|
|
57649
57753
|
}
|
|
57650
57754
|
if (orchestrator === "turbo" && packages.some((p) => p.missingScripts.includes(TYPE_CHECK_KEY))) {
|
|
57651
|
-
await addTurboTask(
|
|
57652
|
-
await addScriptToPackageJson(
|
|
57755
|
+
await addTurboTask(join56(workdir, "turbo.json"), TYPE_CHECK_KEY);
|
|
57756
|
+
await addScriptToPackageJson(join56(workdir, "package.json"), TYPE_CHECK_KEY, TYPE_CHECK_TURBO_PASSTHROUGH);
|
|
57653
57757
|
}
|
|
57654
57758
|
}
|
|
57655
57759
|
var TYPE_CHECK_KEY = "type-check", TYPE_CHECK_SCRIPT = "tsc --noEmit -p tsconfig.json", TYPE_CHECK_TURBO_PASSTHROUGH = "turbo run type-check", _fillScriptsDeps;
|
|
@@ -57710,11 +57814,11 @@ __export(exports_setup, {
|
|
|
57710
57814
|
setupCommand: () => setupCommand,
|
|
57711
57815
|
_setupDeps: () => _setupDeps
|
|
57712
57816
|
});
|
|
57713
|
-
import { join as
|
|
57817
|
+
import { join as join57 } from "path";
|
|
57714
57818
|
async function setupCommand(options = {}) {
|
|
57715
57819
|
const workdir = options.dir ?? process.cwd();
|
|
57716
|
-
const naxDir =
|
|
57717
|
-
const naxConfigPath =
|
|
57820
|
+
const naxDir = join57(workdir, ".nax");
|
|
57821
|
+
const naxConfigPath = join57(naxDir, "config.json");
|
|
57718
57822
|
const exists = await _setupDeps.fileExists(naxConfigPath);
|
|
57719
57823
|
if (exists && !options.force) {
|
|
57720
57824
|
_setupDeps.stderr("[setup] .nax/config.json already exists. Use --force to overwrite.");
|
|
@@ -57747,9 +57851,9 @@ ${JSON.stringify(plan.config, null, 2)}`);
|
|
|
57747
57851
|
await _setupDeps.mkdir(naxDir);
|
|
57748
57852
|
await _setupDeps.writeFile(naxConfigPath, JSON.stringify(plan.config, null, 2));
|
|
57749
57853
|
for (const mc of plan.monoConfigs) {
|
|
57750
|
-
const monoDir =
|
|
57854
|
+
const monoDir = join57(naxDir, "mono", mc.relativeDir);
|
|
57751
57855
|
await _setupDeps.mkdir(monoDir);
|
|
57752
|
-
await _setupDeps.writeFile(
|
|
57856
|
+
await _setupDeps.writeFile(join57(monoDir, "config.json"), JSON.stringify(mc.config, null, 2));
|
|
57753
57857
|
}
|
|
57754
57858
|
const gateResult = await _setupDeps.runGate(workdir, plan.config);
|
|
57755
57859
|
if (gateResult !== 0) {
|
|
@@ -59178,12 +59282,12 @@ var init_loader4 = __esm(() => {
|
|
|
59178
59282
|
});
|
|
59179
59283
|
|
|
59180
59284
|
// src/utils/paths.ts
|
|
59181
|
-
import { join as
|
|
59285
|
+
import { join as join68 } from "path";
|
|
59182
59286
|
function getRunsDir() {
|
|
59183
|
-
return process.env.NAX_RUNS_DIR ??
|
|
59287
|
+
return process.env.NAX_RUNS_DIR ?? join68(globalConfigDir(), "runs");
|
|
59184
59288
|
}
|
|
59185
59289
|
function getEventsRootDir() {
|
|
59186
|
-
return
|
|
59290
|
+
return join68(globalConfigDir(), "events");
|
|
59187
59291
|
}
|
|
59188
59292
|
var init_paths3 = __esm(() => {
|
|
59189
59293
|
init_paths();
|
|
@@ -59243,7 +59347,7 @@ var init_command_argv = __esm(() => {
|
|
|
59243
59347
|
});
|
|
59244
59348
|
|
|
59245
59349
|
// src/hooks/runner.ts
|
|
59246
|
-
import { join as
|
|
59350
|
+
import { join as join75 } from "path";
|
|
59247
59351
|
function createDrainDeadline2(deadlineMs) {
|
|
59248
59352
|
let timeoutId;
|
|
59249
59353
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -59262,14 +59366,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
59262
59366
|
let globalHooks = { hooks: {} };
|
|
59263
59367
|
let projectHooks = { hooks: {} };
|
|
59264
59368
|
let skipGlobal = false;
|
|
59265
|
-
const projectPath =
|
|
59369
|
+
const projectPath = join75(projectDir, "hooks.json");
|
|
59266
59370
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
59267
59371
|
if (projectData) {
|
|
59268
59372
|
projectHooks = projectData;
|
|
59269
59373
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
59270
59374
|
}
|
|
59271
59375
|
if (!skipGlobal && globalDir) {
|
|
59272
|
-
const globalPath =
|
|
59376
|
+
const globalPath = join75(globalDir, "hooks.json");
|
|
59273
59377
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
59274
59378
|
if (globalData) {
|
|
59275
59379
|
globalHooks = globalData;
|
|
@@ -59439,7 +59543,7 @@ var package_default;
|
|
|
59439
59543
|
var init_package = __esm(() => {
|
|
59440
59544
|
package_default = {
|
|
59441
59545
|
name: "@nathapp/nax",
|
|
59442
|
-
version: "0.69.
|
|
59546
|
+
version: "0.69.2",
|
|
59443
59547
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
59444
59548
|
type: "module",
|
|
59445
59549
|
bin: {
|
|
@@ -59534,8 +59638,8 @@ var init_version = __esm(() => {
|
|
|
59534
59638
|
NAX_VERSION = package_default.version;
|
|
59535
59639
|
NAX_COMMIT = (() => {
|
|
59536
59640
|
try {
|
|
59537
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
59538
|
-
return "
|
|
59641
|
+
if (/^[0-9a-f]{6,10}$/.test("99db370f"))
|
|
59642
|
+
return "99db370f";
|
|
59539
59643
|
} catch {}
|
|
59540
59644
|
try {
|
|
59541
59645
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -60412,15 +60516,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
60412
60516
|
|
|
60413
60517
|
// src/session/scratch-purge.ts
|
|
60414
60518
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
60415
|
-
import { dirname as dirname12, join as
|
|
60519
|
+
import { dirname as dirname12, join as join76 } from "path";
|
|
60416
60520
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
60417
|
-
const sessionsDir =
|
|
60521
|
+
const sessionsDir = join76(projectDir, ".nax", "features", featureName, "sessions");
|
|
60418
60522
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
60419
60523
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
60420
60524
|
let purged = 0;
|
|
60421
60525
|
for (const sessionId of sessionIds) {
|
|
60422
|
-
const sessionDir =
|
|
60423
|
-
const descriptorPath =
|
|
60526
|
+
const sessionDir = join76(sessionsDir, sessionId);
|
|
60527
|
+
const descriptorPath = join76(sessionDir, "descriptor.json");
|
|
60424
60528
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
60425
60529
|
continue;
|
|
60426
60530
|
let lastActivityAt;
|
|
@@ -60436,7 +60540,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
60436
60540
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
60437
60541
|
continue;
|
|
60438
60542
|
if (archiveInsteadOfDelete) {
|
|
60439
|
-
const archiveDest =
|
|
60543
|
+
const archiveDest = join76(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
60440
60544
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
60441
60545
|
} else {
|
|
60442
60546
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -61174,12 +61278,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
61174
61278
|
|
|
61175
61279
|
// src/pipeline/subscribers/events-writer.ts
|
|
61176
61280
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
61177
|
-
import { basename as basename13, join as
|
|
61281
|
+
import { basename as basename13, join as join77 } from "path";
|
|
61178
61282
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
61179
61283
|
const logger = getSafeLogger();
|
|
61180
61284
|
const project = basename13(workdir);
|
|
61181
|
-
const eventsDir =
|
|
61182
|
-
const eventsFile =
|
|
61285
|
+
const eventsDir = join77(getEventsRootDir(), project);
|
|
61286
|
+
const eventsFile = join77(eventsDir, "events.jsonl");
|
|
61183
61287
|
let dirReady = false;
|
|
61184
61288
|
const write = (line) => {
|
|
61185
61289
|
return (async () => {
|
|
@@ -61360,12 +61464,12 @@ var init_interaction2 = __esm(() => {
|
|
|
61360
61464
|
|
|
61361
61465
|
// src/pipeline/subscribers/registry.ts
|
|
61362
61466
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
61363
|
-
import { basename as basename14, join as
|
|
61467
|
+
import { basename as basename14, join as join78 } from "path";
|
|
61364
61468
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
61365
61469
|
const logger = getSafeLogger();
|
|
61366
61470
|
const project = basename14(workdir);
|
|
61367
|
-
const runDir =
|
|
61368
|
-
const metaFile =
|
|
61471
|
+
const runDir = join78(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
61472
|
+
const metaFile = join78(runDir, "meta.json");
|
|
61369
61473
|
const unsub = bus.on("run:started", (_ev) => {
|
|
61370
61474
|
return (async () => {
|
|
61371
61475
|
try {
|
|
@@ -61375,8 +61479,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
61375
61479
|
project,
|
|
61376
61480
|
feature,
|
|
61377
61481
|
workdir,
|
|
61378
|
-
statusPath:
|
|
61379
|
-
eventsDir:
|
|
61482
|
+
statusPath: join78(outputDir, "features", feature, "status.json"),
|
|
61483
|
+
eventsDir: join78(outputDir, "features", feature, "runs"),
|
|
61380
61484
|
registeredAt: new Date().toISOString()
|
|
61381
61485
|
};
|
|
61382
61486
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -61622,7 +61726,7 @@ var init_types9 = __esm(() => {
|
|
|
61622
61726
|
|
|
61623
61727
|
// src/worktree/dependencies.ts
|
|
61624
61728
|
import { existsSync as existsSync30 } from "fs";
|
|
61625
|
-
import { join as
|
|
61729
|
+
import { join as join79 } from "path";
|
|
61626
61730
|
async function prepareWorktreeDependencies(options) {
|
|
61627
61731
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
61628
61732
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -61636,7 +61740,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
61636
61740
|
}
|
|
61637
61741
|
}
|
|
61638
61742
|
function resolveDependencyCwd(options) {
|
|
61639
|
-
return options.storyWorkdir ?
|
|
61743
|
+
return options.storyWorkdir ? join79(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
61640
61744
|
}
|
|
61641
61745
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
61642
61746
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -61646,7 +61750,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
61646
61750
|
}
|
|
61647
61751
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
61648
61752
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
61649
|
-
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(
|
|
61753
|
+
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join79(directory, filename))));
|
|
61650
61754
|
}
|
|
61651
61755
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
61652
61756
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -61710,13 +61814,13 @@ __export(exports_manager, {
|
|
|
61710
61814
|
});
|
|
61711
61815
|
import { existsSync as existsSync31, symlinkSync } from "fs";
|
|
61712
61816
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
61713
|
-
import { join as
|
|
61817
|
+
import { join as join80 } from "path";
|
|
61714
61818
|
|
|
61715
61819
|
class WorktreeManager {
|
|
61716
61820
|
async ensureGitExcludes(projectRoot) {
|
|
61717
61821
|
const logger = getSafeLogger();
|
|
61718
|
-
const infoDir =
|
|
61719
|
-
const excludePath =
|
|
61822
|
+
const infoDir = join80(projectRoot, ".git", "info");
|
|
61823
|
+
const excludePath = join80(infoDir, "exclude");
|
|
61720
61824
|
try {
|
|
61721
61825
|
await mkdir15(infoDir, { recursive: true });
|
|
61722
61826
|
let existing = "";
|
|
@@ -61743,7 +61847,7 @@ ${missing.join(`
|
|
|
61743
61847
|
}
|
|
61744
61848
|
async create(projectRoot, storyId) {
|
|
61745
61849
|
validateStoryId(storyId);
|
|
61746
|
-
const worktreePath =
|
|
61850
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
61747
61851
|
const branchName = `nax/${storyId}`;
|
|
61748
61852
|
try {
|
|
61749
61853
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -61784,9 +61888,9 @@ ${missing.join(`
|
|
|
61784
61888
|
}
|
|
61785
61889
|
throw new Error(`Failed to create worktree: ${String(error48)}`);
|
|
61786
61890
|
}
|
|
61787
|
-
const envSource =
|
|
61891
|
+
const envSource = join80(projectRoot, ".env");
|
|
61788
61892
|
if (existsSync31(envSource)) {
|
|
61789
|
-
const envTarget =
|
|
61893
|
+
const envTarget = join80(worktreePath, ".env");
|
|
61790
61894
|
try {
|
|
61791
61895
|
symlinkSync(envSource, envTarget, "file");
|
|
61792
61896
|
} catch (error48) {
|
|
@@ -61797,7 +61901,7 @@ ${missing.join(`
|
|
|
61797
61901
|
}
|
|
61798
61902
|
async remove(projectRoot, storyId) {
|
|
61799
61903
|
validateStoryId(storyId);
|
|
61800
|
-
const worktreePath =
|
|
61904
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
61801
61905
|
const branchName = `nax/${storyId}`;
|
|
61802
61906
|
try {
|
|
61803
61907
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -62609,10 +62713,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
62609
62713
|
});
|
|
62610
62714
|
|
|
62611
62715
|
// src/execution/pipeline-result-handler.ts
|
|
62612
|
-
import { join as
|
|
62716
|
+
import { join as join81 } from "path";
|
|
62613
62717
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
62614
62718
|
const logger = getSafeLogger();
|
|
62615
|
-
const worktreePath =
|
|
62719
|
+
const worktreePath = join81(projectRoot, ".nax-wt", storyId);
|
|
62616
62720
|
try {
|
|
62617
62721
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
62618
62722
|
cwd: projectRoot,
|
|
@@ -62829,7 +62933,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
62829
62933
|
|
|
62830
62934
|
// src/execution/iteration-runner.ts
|
|
62831
62935
|
import { existsSync as existsSync32 } from "fs";
|
|
62832
|
-
import { join as
|
|
62936
|
+
import { join as join82 } from "path";
|
|
62833
62937
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
62834
62938
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
62835
62939
|
if (ctx.dryRun) {
|
|
@@ -62854,7 +62958,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
62854
62958
|
const storyStartTime = Date.now();
|
|
62855
62959
|
let effectiveWorkdir = ctx.workdir;
|
|
62856
62960
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
62857
|
-
const worktreePath =
|
|
62961
|
+
const worktreePath = join82(ctx.workdir, ".nax-wt", story.id);
|
|
62858
62962
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
62859
62963
|
if (!worktreeExists) {
|
|
62860
62964
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -62874,7 +62978,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
62874
62978
|
}
|
|
62875
62979
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
62876
62980
|
const profileOverride = ctx.config.profile && ctx.config.profile !== "default" ? { profile: ctx.config.profile } : undefined;
|
|
62877
|
-
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(
|
|
62981
|
+
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join82(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
|
|
62878
62982
|
let dependencyContext;
|
|
62879
62983
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
62880
62984
|
try {
|
|
@@ -62901,7 +63005,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
62901
63005
|
};
|
|
62902
63006
|
}
|
|
62903
63007
|
}
|
|
62904
|
-
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ?
|
|
63008
|
+
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ? join82(effectiveWorkdir, story.workdir) : effectiveWorkdir : story.workdir ? join82(ctx.workdir, story.workdir) : ctx.workdir;
|
|
62905
63009
|
const pipelineContext = {
|
|
62906
63010
|
config: effectiveConfig,
|
|
62907
63011
|
rootConfig: ctx.config,
|
|
@@ -63103,7 +63207,7 @@ __export(exports_parallel_worker, {
|
|
|
63103
63207
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
63104
63208
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
63105
63209
|
});
|
|
63106
|
-
import { join as
|
|
63210
|
+
import { join as join83 } from "path";
|
|
63107
63211
|
function buildWorktreePipelineContext(base, _story) {
|
|
63108
63212
|
return { ...base, prd: structuredClone(base.prd) };
|
|
63109
63213
|
}
|
|
@@ -63126,7 +63230,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
63126
63230
|
story,
|
|
63127
63231
|
stories: [story],
|
|
63128
63232
|
projectDir: context.projectDir,
|
|
63129
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
63233
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join83(worktreePath, story.workdir) : worktreePath),
|
|
63130
63234
|
worktreeDependencyContext: dependencyContext,
|
|
63131
63235
|
routing,
|
|
63132
63236
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -64013,7 +64117,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
64013
64117
|
var init_status_file = () => {};
|
|
64014
64118
|
|
|
64015
64119
|
// src/execution/status-writer.ts
|
|
64016
|
-
import { join as
|
|
64120
|
+
import { join as join84 } from "path";
|
|
64017
64121
|
|
|
64018
64122
|
class StatusWriter {
|
|
64019
64123
|
statusFile;
|
|
@@ -64132,7 +64236,7 @@ class StatusWriter {
|
|
|
64132
64236
|
if (!this._prd)
|
|
64133
64237
|
return;
|
|
64134
64238
|
const safeLogger = getSafeLogger();
|
|
64135
|
-
const featureStatusPath =
|
|
64239
|
+
const featureStatusPath = join84(featureDir, "status.json");
|
|
64136
64240
|
const write = async () => {
|
|
64137
64241
|
try {
|
|
64138
64242
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -64566,7 +64670,7 @@ __export(exports_run_initialization, {
|
|
|
64566
64670
|
initializeRun: () => initializeRun,
|
|
64567
64671
|
_reconcileDeps: () => _reconcileDeps
|
|
64568
64672
|
});
|
|
64569
|
-
import { join as
|
|
64673
|
+
import { join as join85 } from "path";
|
|
64570
64674
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
64571
64675
|
const logger = getSafeLogger();
|
|
64572
64676
|
let reconciledCount = 0;
|
|
@@ -64583,7 +64687,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
64583
64687
|
});
|
|
64584
64688
|
continue;
|
|
64585
64689
|
}
|
|
64586
|
-
const effectiveWorkdir = story.workdir ?
|
|
64690
|
+
const effectiveWorkdir = story.workdir ? join85(workdir, story.workdir) : workdir;
|
|
64587
64691
|
try {
|
|
64588
64692
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
64589
64693
|
if (!reviewResult.success) {
|
|
@@ -64849,6 +64953,17 @@ async function setupRun(options) {
|
|
|
64849
64953
|
featureName: options.feature,
|
|
64850
64954
|
agentStreamEvents: options.agentStreamEvents
|
|
64851
64955
|
});
|
|
64956
|
+
try {
|
|
64957
|
+
const workspacePackages = await discoverWorkspacePackages(workdir);
|
|
64958
|
+
if (workspacePackages.length > 0) {
|
|
64959
|
+
await runtime.packages.hydrate(workspacePackages);
|
|
64960
|
+
}
|
|
64961
|
+
} catch (err) {
|
|
64962
|
+
getSafeLogger()?.warn("run-setup", "Per-package config hydration failed \u2014 using root config", {
|
|
64963
|
+
storyId: "_setup",
|
|
64964
|
+
error: errorMessage(err)
|
|
64965
|
+
});
|
|
64966
|
+
}
|
|
64852
64967
|
await runtime.pidRegistry.cleanupStale();
|
|
64853
64968
|
const cleanupCrashHandlers = installCrashHandlers({
|
|
64854
64969
|
statusWriter,
|
|
@@ -65015,6 +65130,7 @@ async function setupRun(options) {
|
|
|
65015
65130
|
var _runSetupDeps;
|
|
65016
65131
|
var init_run_setup = __esm(() => {
|
|
65017
65132
|
init_pipeline();
|
|
65133
|
+
init_test_runners();
|
|
65018
65134
|
init_paths();
|
|
65019
65135
|
init_errors();
|
|
65020
65136
|
init_interaction();
|
|
@@ -65024,7 +65140,6 @@ var init_run_setup = __esm(() => {
|
|
|
65024
65140
|
init_project();
|
|
65025
65141
|
init_runtime();
|
|
65026
65142
|
init_session();
|
|
65027
|
-
init_resolver();
|
|
65028
65143
|
init_version();
|
|
65029
65144
|
init_crash_recovery();
|
|
65030
65145
|
init_helpers();
|
|
@@ -94376,7 +94491,7 @@ __export(exports_curator, {
|
|
|
94376
94491
|
});
|
|
94377
94492
|
import { readdirSync as readdirSync8 } from "fs";
|
|
94378
94493
|
import { unlink as unlink4 } from "fs/promises";
|
|
94379
|
-
import { basename as basename15, join as
|
|
94494
|
+
import { basename as basename15, join as join87 } from "path";
|
|
94380
94495
|
function getProjectKey(config2, projectDir) {
|
|
94381
94496
|
return config2.name?.trim() || basename15(projectDir);
|
|
94382
94497
|
}
|
|
@@ -94459,7 +94574,7 @@ async function curatorStatus(options) {
|
|
|
94459
94574
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94460
94575
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94461
94576
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94462
|
-
const runsDir =
|
|
94577
|
+
const runsDir = join87(outputDir, "runs");
|
|
94463
94578
|
const runIds = listRunIds(runsDir);
|
|
94464
94579
|
let runId;
|
|
94465
94580
|
if (options.run) {
|
|
@@ -94476,8 +94591,8 @@ async function curatorStatus(options) {
|
|
|
94476
94591
|
runId = runIds[runIds.length - 1];
|
|
94477
94592
|
}
|
|
94478
94593
|
console.log(`Run: ${runId}`);
|
|
94479
|
-
const runDir =
|
|
94480
|
-
const observationsPath =
|
|
94594
|
+
const runDir = join87(runsDir, runId);
|
|
94595
|
+
const observationsPath = join87(runDir, "observations.jsonl");
|
|
94481
94596
|
const observations = await parseObservations(observationsPath);
|
|
94482
94597
|
const counts = new Map;
|
|
94483
94598
|
for (const obs of observations) {
|
|
@@ -94487,7 +94602,7 @@ async function curatorStatus(options) {
|
|
|
94487
94602
|
for (const [kind, count] of counts.entries()) {
|
|
94488
94603
|
console.log(` ${kind}: ${count}`);
|
|
94489
94604
|
}
|
|
94490
|
-
const proposalsPath =
|
|
94605
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
94491
94606
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94492
94607
|
if (proposalText !== null) {
|
|
94493
94608
|
console.log("");
|
|
@@ -94501,8 +94616,8 @@ async function curatorCommit(options) {
|
|
|
94501
94616
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94502
94617
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94503
94618
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94504
|
-
const runDir =
|
|
94505
|
-
const proposalsPath =
|
|
94619
|
+
const runDir = join87(outputDir, "runs", options.runId);
|
|
94620
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
94506
94621
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
94507
94622
|
if (proposalText === null) {
|
|
94508
94623
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -94518,7 +94633,7 @@ async function curatorCommit(options) {
|
|
|
94518
94633
|
const dropFileState = new Map;
|
|
94519
94634
|
const skippedDrops = new Set;
|
|
94520
94635
|
for (const drop2 of drops) {
|
|
94521
|
-
const targetPath =
|
|
94636
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
94522
94637
|
if (!dropFileState.has(targetPath)) {
|
|
94523
94638
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
94524
94639
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -94552,7 +94667,7 @@ async function curatorCommit(options) {
|
|
|
94552
94667
|
if (skippedDrops.has(drop2)) {
|
|
94553
94668
|
continue;
|
|
94554
94669
|
}
|
|
94555
|
-
const targetPath =
|
|
94670
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
94556
94671
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
94557
94672
|
const filtered = filterDropContent(existing, drop2.description);
|
|
94558
94673
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -94561,7 +94676,7 @@ async function curatorCommit(options) {
|
|
|
94561
94676
|
}
|
|
94562
94677
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
94563
94678
|
for (const add2 of adds) {
|
|
94564
|
-
const targetPath =
|
|
94679
|
+
const targetPath = join87(resolved.projectDir, add2.canonicalFile);
|
|
94565
94680
|
const content = buildAddContent(add2);
|
|
94566
94681
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
94567
94682
|
modifiedFiles.add(targetPath);
|
|
@@ -94598,7 +94713,7 @@ async function curatorDryrun(options) {
|
|
|
94598
94713
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
94599
94714
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94600
94715
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94601
|
-
const runsDir =
|
|
94716
|
+
const runsDir = join87(outputDir, "runs");
|
|
94602
94717
|
const runIds = listRunIds(runsDir);
|
|
94603
94718
|
if (runIds.length === 0) {
|
|
94604
94719
|
console.log("No runs found.");
|
|
@@ -94609,7 +94724,7 @@ async function curatorDryrun(options) {
|
|
|
94609
94724
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
94610
94725
|
return;
|
|
94611
94726
|
}
|
|
94612
|
-
const observationsPath =
|
|
94727
|
+
const observationsPath = join87(runsDir, runId, "observations.jsonl");
|
|
94613
94728
|
const observations = await parseObservations(observationsPath);
|
|
94614
94729
|
const thresholds = getThresholds(config2);
|
|
94615
94730
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -94650,12 +94765,12 @@ async function curatorGc(options) {
|
|
|
94650
94765
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
94651
94766
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
94652
94767
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
94653
|
-
const perRunsDir =
|
|
94768
|
+
const perRunsDir = join87(outputDir, "runs");
|
|
94654
94769
|
for (const runId of uniqueRunIds) {
|
|
94655
94770
|
if (!keepSet.has(runId)) {
|
|
94656
|
-
const runDir =
|
|
94657
|
-
await _curatorCmdDeps.removeFile(
|
|
94658
|
-
await _curatorCmdDeps.removeFile(
|
|
94771
|
+
const runDir = join87(perRunsDir, runId);
|
|
94772
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "observations.jsonl"));
|
|
94773
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "curator-proposals.md"));
|
|
94659
94774
|
}
|
|
94660
94775
|
}
|
|
94661
94776
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -94700,7 +94815,7 @@ var init_curator2 = __esm(() => {
|
|
|
94700
94815
|
init_source();
|
|
94701
94816
|
import { existsSync as existsSync35, mkdirSync as mkdirSync7 } from "fs";
|
|
94702
94817
|
import { homedir as homedir3 } from "os";
|
|
94703
|
-
import { basename as basename16, join as
|
|
94818
|
+
import { basename as basename16, join as join88 } from "path";
|
|
94704
94819
|
|
|
94705
94820
|
// node_modules/commander/esm.mjs
|
|
94706
94821
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -94724,12 +94839,12 @@ init_errors();
|
|
|
94724
94839
|
init_operations();
|
|
94725
94840
|
|
|
94726
94841
|
// src/plan/strategies/context-builder.ts
|
|
94727
|
-
import { join as
|
|
94842
|
+
import { join as join39 } from "path";
|
|
94728
94843
|
init_config();
|
|
94729
94844
|
init_errors();
|
|
94730
94845
|
init_interaction();
|
|
94731
94846
|
async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
94732
|
-
const naxDir =
|
|
94847
|
+
const naxDir = join39(workdir, ".nax");
|
|
94733
94848
|
if (!deps.existsSync(naxDir)) {
|
|
94734
94849
|
throw new NaxError(`.nax directory not found. Run 'nax init' first in ${workdir}`, "PLAN_CONTEXT_NO_NAX_DIR", {
|
|
94735
94850
|
stage: "plan",
|
|
@@ -94737,8 +94852,8 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
94737
94852
|
});
|
|
94738
94853
|
}
|
|
94739
94854
|
validateFeatureName(options.feature);
|
|
94740
|
-
const outputDir =
|
|
94741
|
-
const outputPath =
|
|
94855
|
+
const outputDir = join39(naxDir, "features", options.feature);
|
|
94856
|
+
const outputPath = join39(outputDir, "prd.json");
|
|
94742
94857
|
const [specContent, sourceRoots, pkg] = await Promise.all([
|
|
94743
94858
|
deps.readFile(options.from),
|
|
94744
94859
|
deps.scanSourceRoots(workdir),
|
|
@@ -94753,7 +94868,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
94753
94868
|
...new Set(sourceRoots.map((root) => root.path).filter((path7) => path7 !== ".").map((path7) => path7.startsWith("/") ? path7.replace(`${workdir}/`, "") : path7))
|
|
94754
94869
|
];
|
|
94755
94870
|
const packageDetails = relativePackages.length === 0 ? [] : await Promise.all(relativePackages.map(async (relativePath) => {
|
|
94756
|
-
const packageJson = await deps.readPackageJsonAt(
|
|
94871
|
+
const packageJson = await deps.readPackageJsonAt(join39(workdir, relativePath, "package.json"));
|
|
94757
94872
|
return buildPackageSummary(relativePath, packageJson);
|
|
94758
94873
|
}));
|
|
94759
94874
|
const projectName = detectProjectName(workdir, pkg);
|
|
@@ -95356,7 +95471,7 @@ init_interaction();
|
|
|
95356
95471
|
init_prd();
|
|
95357
95472
|
init_runtime();
|
|
95358
95473
|
import { existsSync as existsSync17, readdirSync as readdirSync3 } from "fs";
|
|
95359
|
-
import { basename as basename7, join as
|
|
95474
|
+
import { basename as basename7, join as join44, resolve as resolve14 } from "path";
|
|
95360
95475
|
var _statusFeaturesDeps = {
|
|
95361
95476
|
projectOutputDir,
|
|
95362
95477
|
loadConfig
|
|
@@ -95370,7 +95485,7 @@ function isPidAlive(pid) {
|
|
|
95370
95485
|
}
|
|
95371
95486
|
}
|
|
95372
95487
|
async function loadStatusFile(featureDir) {
|
|
95373
|
-
const statusPath =
|
|
95488
|
+
const statusPath = join44(featureDir, "status.json");
|
|
95374
95489
|
if (!existsSync17(statusPath)) {
|
|
95375
95490
|
return null;
|
|
95376
95491
|
}
|
|
@@ -95385,7 +95500,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95385
95500
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95386
95501
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95387
95502
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95388
|
-
const statusPath =
|
|
95503
|
+
const statusPath = join44(outputDir, "status.json");
|
|
95389
95504
|
if (!existsSync17(statusPath)) {
|
|
95390
95505
|
return null;
|
|
95391
95506
|
}
|
|
@@ -95397,7 +95512,7 @@ async function loadProjectStatusFile(projectDir) {
|
|
|
95397
95512
|
}
|
|
95398
95513
|
}
|
|
95399
95514
|
async function getFeatureSummary(featureName, featureDir) {
|
|
95400
|
-
const prdPath =
|
|
95515
|
+
const prdPath = join44(featureDir, "prd.json");
|
|
95401
95516
|
if (!existsSync17(prdPath)) {
|
|
95402
95517
|
return {
|
|
95403
95518
|
name: featureName,
|
|
@@ -95440,7 +95555,7 @@ async function getFeatureSummary(featureName, featureDir) {
|
|
|
95440
95555
|
};
|
|
95441
95556
|
}
|
|
95442
95557
|
}
|
|
95443
|
-
const runsDir =
|
|
95558
|
+
const runsDir = join44(featureDir, "runs");
|
|
95444
95559
|
if (existsSync17(runsDir)) {
|
|
95445
95560
|
const runs = readdirSync3(runsDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl") && e.name !== "latest.jsonl").map((e) => e.name).sort().reverse();
|
|
95446
95561
|
if (runs.length > 0) {
|
|
@@ -95454,7 +95569,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95454
95569
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95455
95570
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95456
95571
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95457
|
-
const featuresDir =
|
|
95572
|
+
const featuresDir = join44(outputDir, "features");
|
|
95458
95573
|
if (!existsSync17(featuresDir)) {
|
|
95459
95574
|
console.log(source_default.dim("No features found."));
|
|
95460
95575
|
return;
|
|
@@ -95495,7 +95610,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95495
95610
|
console.log();
|
|
95496
95611
|
}
|
|
95497
95612
|
}
|
|
95498
|
-
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name,
|
|
95613
|
+
const summaries = await Promise.all(features.map((name) => getFeatureSummary(name, join44(featuresDir, name))));
|
|
95499
95614
|
console.log(source_default.bold(`\uD83D\uDCCA Features
|
|
95500
95615
|
`));
|
|
95501
95616
|
const header = ` ${"Feature".padEnd(25)} ${"Done".padEnd(6)} ${"Failed".padEnd(8)} ${"Pending".padEnd(9)} ${"Last Run".padEnd(22)} ${"Cost".padEnd(10)} Status`;
|
|
@@ -95521,7 +95636,7 @@ async function displayAllFeatures(projectDir) {
|
|
|
95521
95636
|
console.log();
|
|
95522
95637
|
}
|
|
95523
95638
|
async function displayFeatureDetails(featureName, featureDir) {
|
|
95524
|
-
const prdPath =
|
|
95639
|
+
const prdPath = join44(featureDir, "prd.json");
|
|
95525
95640
|
if (!existsSync17(prdPath)) {
|
|
95526
95641
|
console.log(source_default.bold(`
|
|
95527
95642
|
\uD83D\uDCCA ${featureName}
|
|
@@ -95667,7 +95782,7 @@ async function displayFeatureStatus(options = {}) {
|
|
|
95667
95782
|
const config2 = await _statusFeaturesDeps.loadConfig(projectDir).catch(() => null);
|
|
95668
95783
|
const projectKey = config2?.name?.trim() || basename7(projectDir);
|
|
95669
95784
|
const outputDir = _statusFeaturesDeps.projectOutputDir(projectKey, config2?.outputDir);
|
|
95670
|
-
featureDir =
|
|
95785
|
+
featureDir = join44(outputDir, "features", options.feature);
|
|
95671
95786
|
} else {
|
|
95672
95787
|
const resolved = resolveProject({ feature: options.feature });
|
|
95673
95788
|
if (!resolved.featureDir) {
|
|
@@ -95687,7 +95802,7 @@ init_errors();
|
|
|
95687
95802
|
init_logger2();
|
|
95688
95803
|
init_runtime();
|
|
95689
95804
|
import { existsSync as existsSync18, readdirSync as readdirSync4 } from "fs";
|
|
95690
|
-
import { basename as basename8, join as
|
|
95805
|
+
import { basename as basename8, join as join45 } from "path";
|
|
95691
95806
|
async function resolveOutputDir2(workdir, override) {
|
|
95692
95807
|
if (override)
|
|
95693
95808
|
return override;
|
|
@@ -95711,7 +95826,7 @@ async function runsListCommand(options) {
|
|
|
95711
95826
|
const logger = getLogger();
|
|
95712
95827
|
const { feature, workdir } = options;
|
|
95713
95828
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
95714
|
-
const runsDir =
|
|
95829
|
+
const runsDir = join45(outputDir, "features", feature, "runs");
|
|
95715
95830
|
if (!existsSync18(runsDir)) {
|
|
95716
95831
|
logger.info("cli", "No runs found for feature", { feature, hint: `Directory not found: ${runsDir}` });
|
|
95717
95832
|
return;
|
|
@@ -95723,7 +95838,7 @@ async function runsListCommand(options) {
|
|
|
95723
95838
|
}
|
|
95724
95839
|
logger.info("cli", `Runs for ${feature}`, { count: files.length });
|
|
95725
95840
|
for (const file3 of files.sort().reverse()) {
|
|
95726
|
-
const logPath =
|
|
95841
|
+
const logPath = join45(runsDir, file3);
|
|
95727
95842
|
const entries = await parseRunLog(logPath);
|
|
95728
95843
|
const startEvent = entries.find((e) => e.message === "run.start");
|
|
95729
95844
|
const completeEvent = entries.find((e) => e.message === "run.complete");
|
|
@@ -95750,7 +95865,7 @@ async function runsShowCommand(options) {
|
|
|
95750
95865
|
const logger = getLogger();
|
|
95751
95866
|
const { runId, feature, workdir } = options;
|
|
95752
95867
|
const outputDir = await resolveOutputDir2(workdir, options.outputDir);
|
|
95753
|
-
const logPath =
|
|
95868
|
+
const logPath = join45(outputDir, "features", feature, "runs", `${runId}.jsonl`);
|
|
95754
95869
|
if (!existsSync18(logPath)) {
|
|
95755
95870
|
logger.error("cli", "Run not found", { runId, feature, logPath });
|
|
95756
95871
|
throw new NaxError("Run not found", "RUN_NOT_FOUND", { runId, feature, logPath });
|
|
@@ -95866,7 +95981,7 @@ init_source();
|
|
|
95866
95981
|
init_loader();
|
|
95867
95982
|
init_generator2();
|
|
95868
95983
|
import { existsSync as existsSync24 } from "fs";
|
|
95869
|
-
import { join as
|
|
95984
|
+
import { join as join62 } from "path";
|
|
95870
95985
|
var VALID_AGENTS = ["claude", "codex", "opencode", "cursor", "windsurf", "aider", "gemini"];
|
|
95871
95986
|
async function generateCommand(options) {
|
|
95872
95987
|
const workdir = options.dir ?? process.cwd();
|
|
@@ -95909,7 +96024,7 @@ async function generateCommand(options) {
|
|
|
95909
96024
|
return;
|
|
95910
96025
|
}
|
|
95911
96026
|
if (options.package) {
|
|
95912
|
-
const packageDir =
|
|
96027
|
+
const packageDir = join62(workdir, options.package);
|
|
95913
96028
|
if (dryRun) {
|
|
95914
96029
|
console.log(source_default.yellow("\u26A0 Dry run \u2014 no files will be written"));
|
|
95915
96030
|
}
|
|
@@ -95929,8 +96044,8 @@ async function generateCommand(options) {
|
|
|
95929
96044
|
process.exit(1);
|
|
95930
96045
|
return;
|
|
95931
96046
|
}
|
|
95932
|
-
const contextPath = options.context ?
|
|
95933
|
-
const outputDir = options.output ?
|
|
96047
|
+
const contextPath = options.context ? join62(workdir, options.context) : join62(workdir, ".nax/context.md");
|
|
96048
|
+
const outputDir = options.output ? join62(workdir, options.output) : workdir;
|
|
95934
96049
|
const autoInject = !options.noAutoInject;
|
|
95935
96050
|
if (!existsSync24(contextPath)) {
|
|
95936
96051
|
console.error(source_default.red(`\u2717 Context file not found: ${contextPath}`));
|
|
@@ -96036,7 +96151,7 @@ async function generateCommand(options) {
|
|
|
96036
96151
|
// src/cli/config-display.ts
|
|
96037
96152
|
init_loader();
|
|
96038
96153
|
import { existsSync as existsSync26 } from "fs";
|
|
96039
|
-
import { join as
|
|
96154
|
+
import { join as join64 } from "path";
|
|
96040
96155
|
|
|
96041
96156
|
// src/cli/config-descriptions.ts
|
|
96042
96157
|
var FIELD_DESCRIPTIONS = {
|
|
@@ -96288,7 +96403,7 @@ function deepEqual(a, b) {
|
|
|
96288
96403
|
init_defaults();
|
|
96289
96404
|
init_loader();
|
|
96290
96405
|
import { existsSync as existsSync25 } from "fs";
|
|
96291
|
-
import { join as
|
|
96406
|
+
import { join as join63 } from "path";
|
|
96292
96407
|
async function loadConfigFile(path18) {
|
|
96293
96408
|
if (!existsSync25(path18))
|
|
96294
96409
|
return null;
|
|
@@ -96310,7 +96425,7 @@ async function loadProjectConfig() {
|
|
|
96310
96425
|
const projectDir = findProjectDir();
|
|
96311
96426
|
if (!projectDir)
|
|
96312
96427
|
return null;
|
|
96313
|
-
const projectPath =
|
|
96428
|
+
const projectPath = join63(projectDir, "config.json");
|
|
96314
96429
|
return await loadConfigFile(projectPath);
|
|
96315
96430
|
}
|
|
96316
96431
|
|
|
@@ -96370,7 +96485,7 @@ async function configCommand(config2, options = {}) {
|
|
|
96370
96485
|
function determineConfigSources() {
|
|
96371
96486
|
const globalPath = globalConfigPath();
|
|
96372
96487
|
const projectDir = findProjectDir();
|
|
96373
|
-
const projectPath = projectDir ?
|
|
96488
|
+
const projectPath = projectDir ? join64(projectDir, "config.json") : null;
|
|
96374
96489
|
return {
|
|
96375
96490
|
global: fileExists(globalPath) ? globalPath : null,
|
|
96376
96491
|
project: projectPath && fileExists(projectPath) ? projectPath : null
|
|
@@ -96519,15 +96634,15 @@ init_paths();
|
|
|
96519
96634
|
init_profile();
|
|
96520
96635
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
96521
96636
|
import { readdirSync as readdirSync5 } from "fs";
|
|
96522
|
-
import { join as
|
|
96637
|
+
import { join as join65 } from "path";
|
|
96523
96638
|
var _profileCLIDeps = {
|
|
96524
96639
|
env: process.env
|
|
96525
96640
|
};
|
|
96526
96641
|
var SENSITIVE_KEY_PATTERN = /key|token|secret|password|credential/i;
|
|
96527
96642
|
var VAR_PATTERN = /\$[A-Za-z_][A-Za-z0-9_]*/;
|
|
96528
96643
|
async function profileListCommand(startDir) {
|
|
96529
|
-
const globalProfilesDir =
|
|
96530
|
-
const projectProfilesDir =
|
|
96644
|
+
const globalProfilesDir = join65(globalConfigDir(), "profiles");
|
|
96645
|
+
const projectProfilesDir = join65(projectConfigDir(startDir), "profiles");
|
|
96531
96646
|
const globalProfiles = scanProfileDir(globalProfilesDir);
|
|
96532
96647
|
const projectProfiles = scanProfileDir(projectProfilesDir);
|
|
96533
96648
|
const activeProfile = await resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
@@ -96586,7 +96701,7 @@ function maskProfileValues(obj) {
|
|
|
96586
96701
|
return result;
|
|
96587
96702
|
}
|
|
96588
96703
|
async function profileUseCommand(profileName, startDir) {
|
|
96589
|
-
const configPath =
|
|
96704
|
+
const configPath = join65(projectConfigDir(startDir), "config.json");
|
|
96590
96705
|
const configFile = Bun.file(configPath);
|
|
96591
96706
|
let existing = {};
|
|
96592
96707
|
if (await configFile.exists()) {
|
|
@@ -96605,8 +96720,8 @@ async function profileCurrentCommand(startDir) {
|
|
|
96605
96720
|
return resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
96606
96721
|
}
|
|
96607
96722
|
async function profileCreateCommand(profileName, startDir) {
|
|
96608
|
-
const profilesDir =
|
|
96609
|
-
const profilePath =
|
|
96723
|
+
const profilesDir = join65(projectConfigDir(startDir), "profiles");
|
|
96724
|
+
const profilePath = join65(profilesDir, `${profileName}.json`);
|
|
96610
96725
|
const profileFile = Bun.file(profilePath);
|
|
96611
96726
|
if (await profileFile.exists()) {
|
|
96612
96727
|
throw new Error(`Profile "${profileName}" already exists at ${profilePath}`);
|
|
@@ -96728,7 +96843,7 @@ async function contextInspectCommand(options) {
|
|
|
96728
96843
|
init_canonical_loader();
|
|
96729
96844
|
init_errors();
|
|
96730
96845
|
import { mkdir as mkdir11 } from "fs/promises";
|
|
96731
|
-
import { basename as basename12, join as
|
|
96846
|
+
import { basename as basename12, join as join66 } from "path";
|
|
96732
96847
|
var _rulesCLIDeps = {
|
|
96733
96848
|
readFile: async (path18) => Bun.file(path18).text(),
|
|
96734
96849
|
writeFile: async (path18, content) => {
|
|
@@ -96737,7 +96852,7 @@ var _rulesCLIDeps = {
|
|
|
96737
96852
|
fileExists: async (path18) => Bun.file(path18).exists(),
|
|
96738
96853
|
globInDir: (dir) => {
|
|
96739
96854
|
try {
|
|
96740
|
-
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) =>
|
|
96855
|
+
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join66(dir, f));
|
|
96741
96856
|
} catch {
|
|
96742
96857
|
return [];
|
|
96743
96858
|
}
|
|
@@ -96786,7 +96901,7 @@ ${r.content}`).join(`
|
|
|
96786
96901
|
`);
|
|
96787
96902
|
const shimContent = `${header + body}
|
|
96788
96903
|
`;
|
|
96789
|
-
const shimPath =
|
|
96904
|
+
const shimPath = join66(workdir, shimFileName);
|
|
96790
96905
|
if (options.dryRun) {
|
|
96791
96906
|
console.log(`[dry-run] Would write ${shimPath} (${shimContent.length} bytes)`);
|
|
96792
96907
|
return;
|
|
@@ -96815,14 +96930,14 @@ function neutralizeContent(content) {
|
|
|
96815
96930
|
}
|
|
96816
96931
|
async function collectMigrationSources(workdir) {
|
|
96817
96932
|
const sources = [];
|
|
96818
|
-
const claudeMdPath =
|
|
96933
|
+
const claudeMdPath = join66(workdir, "CLAUDE.md");
|
|
96819
96934
|
if (await _rulesCLIDeps.fileExists(claudeMdPath)) {
|
|
96820
96935
|
const content = await _rulesCLIDeps.readFile(claudeMdPath);
|
|
96821
96936
|
if (content.trim()) {
|
|
96822
96937
|
sources.push({ sourcePath: claudeMdPath, targetFileName: "project-conventions.md", content });
|
|
96823
96938
|
}
|
|
96824
96939
|
}
|
|
96825
|
-
const rulesDir =
|
|
96940
|
+
const rulesDir = join66(workdir, ".claude", "rules");
|
|
96826
96941
|
const ruleFiles = _rulesCLIDeps.globInDir(rulesDir);
|
|
96827
96942
|
for (const filePath of ruleFiles) {
|
|
96828
96943
|
try {
|
|
@@ -96842,7 +96957,7 @@ async function rulesMigrateCommand(options) {
|
|
|
96842
96957
|
console.log("[WARN] No source files found (checked CLAUDE.md and .claude/rules/*.md). Nothing to migrate.");
|
|
96843
96958
|
return;
|
|
96844
96959
|
}
|
|
96845
|
-
const targetDir =
|
|
96960
|
+
const targetDir = join66(workdir, CANONICAL_RULES_DIR);
|
|
96846
96961
|
if (!options.dryRun) {
|
|
96847
96962
|
try {
|
|
96848
96963
|
await _rulesCLIDeps.mkdir(targetDir);
|
|
@@ -96853,7 +96968,7 @@ async function rulesMigrateCommand(options) {
|
|
|
96853
96968
|
let written = 0;
|
|
96854
96969
|
let skipped = 0;
|
|
96855
96970
|
for (const { sourcePath, targetFileName, content } of sources) {
|
|
96856
|
-
const targetPath =
|
|
96971
|
+
const targetPath = join66(targetDir, targetFileName);
|
|
96857
96972
|
if (!force && !options.dryRun && await _rulesCLIDeps.fileExists(targetPath)) {
|
|
96858
96973
|
console.log(`[skip] ${targetFileName} already exists (use --force to overwrite)`);
|
|
96859
96974
|
skipped++;
|
|
@@ -96892,7 +97007,7 @@ function collectCanonicalRuleRoots(workdir) {
|
|
|
96892
97007
|
const packageRel = normalized.slice(0, idx);
|
|
96893
97008
|
if (!packageRel)
|
|
96894
97009
|
continue;
|
|
96895
|
-
roots.add(
|
|
97010
|
+
roots.add(join66(workdir, packageRel));
|
|
96896
97011
|
}
|
|
96897
97012
|
return [...roots].sort();
|
|
96898
97013
|
}
|
|
@@ -96914,7 +97029,7 @@ init_logger2();
|
|
|
96914
97029
|
init_detect2();
|
|
96915
97030
|
init_workspace();
|
|
96916
97031
|
init_common();
|
|
96917
|
-
import { join as
|
|
97032
|
+
import { join as join67 } from "path";
|
|
96918
97033
|
function resolveEffective(detected, configPatterns) {
|
|
96919
97034
|
if (configPatterns !== undefined)
|
|
96920
97035
|
return "config";
|
|
@@ -96999,7 +97114,7 @@ async function detectCommand(options) {
|
|
|
96999
97114
|
const rootDetected = detectionMap[""] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
97000
97115
|
const pkgEntries = await Promise.all(packageDirs.map(async (dir) => {
|
|
97001
97116
|
const det = detectionMap[dir] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
97002
|
-
const pkgConfigPath =
|
|
97117
|
+
const pkgConfigPath = join67(workdir, ".nax", "mono", dir, "config.json");
|
|
97003
97118
|
const pkgRaw = await loadRawConfig(pkgConfigPath);
|
|
97004
97119
|
const pkgPatterns = deepGet(pkgRaw, TEST_PATTERNS_KEY);
|
|
97005
97120
|
const effective = Array.isArray(pkgPatterns) ? pkgPatterns : undefined;
|
|
@@ -97053,13 +97168,13 @@ async function detectCommand(options) {
|
|
|
97053
97168
|
if (rootDetected.confidence === "empty") {
|
|
97054
97169
|
console.log(source_default.yellow(" root: skipped (empty detection)"));
|
|
97055
97170
|
} else {
|
|
97056
|
-
const rootConfigPath =
|
|
97171
|
+
const rootConfigPath = join67(workdir, ".nax", "config.json");
|
|
97057
97172
|
try {
|
|
97058
97173
|
const status = await applyToConfig(rootConfigPath, rootDetected.patterns, options.force ?? false);
|
|
97059
97174
|
if (status === "skipped") {
|
|
97060
97175
|
console.log(source_default.dim(" root: skipped (testFilePatterns already set; use --force to overwrite)"));
|
|
97061
97176
|
} else {
|
|
97062
|
-
console.log(source_default.green(` root: ${status} \u2192 ${
|
|
97177
|
+
console.log(source_default.green(` root: ${status} \u2192 ${join67(".nax", "config.json")}`));
|
|
97063
97178
|
}
|
|
97064
97179
|
} catch (err) {
|
|
97065
97180
|
console.error(source_default.red(` root: write failed \u2014 ${err.message}`));
|
|
@@ -97072,13 +97187,13 @@ async function detectCommand(options) {
|
|
|
97072
97187
|
console.log(source_default.dim(` ${dir}: skipped (empty detection)`));
|
|
97073
97188
|
continue;
|
|
97074
97189
|
}
|
|
97075
|
-
const pkgConfigPath =
|
|
97190
|
+
const pkgConfigPath = join67(workdir, ".nax", "mono", dir, "config.json");
|
|
97076
97191
|
try {
|
|
97077
97192
|
const status = await applyToConfig(pkgConfigPath, det.patterns, options.force ?? false);
|
|
97078
97193
|
if (status === "skipped") {
|
|
97079
97194
|
console.log(source_default.dim(` ${dir}: skipped (already set)`));
|
|
97080
97195
|
} else {
|
|
97081
|
-
console.log(source_default.green(` ${dir}: ${status} \u2192 ${
|
|
97196
|
+
console.log(source_default.green(` ${dir}: ${status} \u2192 ${join67(".nax", "mono", dir, "config.json")}`));
|
|
97082
97197
|
}
|
|
97083
97198
|
} catch (err) {
|
|
97084
97199
|
console.error(source_default.red(` ${dir}: write failed \u2014 ${err.message}`));
|
|
@@ -97096,19 +97211,19 @@ async function detectCommand(options) {
|
|
|
97096
97211
|
// src/commands/logs.ts
|
|
97097
97212
|
init_common();
|
|
97098
97213
|
import { existsSync as existsSync28 } from "fs";
|
|
97099
|
-
import { join as
|
|
97214
|
+
import { join as join71 } from "path";
|
|
97100
97215
|
|
|
97101
97216
|
// src/commands/logs-formatter.ts
|
|
97102
97217
|
init_source();
|
|
97103
97218
|
init_formatter();
|
|
97104
97219
|
import { readdirSync as readdirSync7 } from "fs";
|
|
97105
|
-
import { join as
|
|
97220
|
+
import { join as join70 } from "path";
|
|
97106
97221
|
|
|
97107
97222
|
// src/commands/logs-reader.ts
|
|
97108
97223
|
init_paths3();
|
|
97109
97224
|
import { existsSync as existsSync27, readdirSync as readdirSync6 } from "fs";
|
|
97110
97225
|
import { readdir as readdir4 } from "fs/promises";
|
|
97111
|
-
import { join as
|
|
97226
|
+
import { join as join69 } from "path";
|
|
97112
97227
|
var _logsReaderDeps = {
|
|
97113
97228
|
getRunsDir
|
|
97114
97229
|
};
|
|
@@ -97122,7 +97237,7 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97122
97237
|
}
|
|
97123
97238
|
let matched = null;
|
|
97124
97239
|
for (const entry of entries) {
|
|
97125
|
-
const metaPath =
|
|
97240
|
+
const metaPath = join69(runsDir, entry, "meta.json");
|
|
97126
97241
|
try {
|
|
97127
97242
|
const meta3 = await Bun.file(metaPath).json();
|
|
97128
97243
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -97144,14 +97259,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
97144
97259
|
return null;
|
|
97145
97260
|
}
|
|
97146
97261
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
97147
|
-
return
|
|
97262
|
+
return join69(matched.eventsDir, specificFile ?? files[0]);
|
|
97148
97263
|
}
|
|
97149
97264
|
async function selectRunFile(runsDir) {
|
|
97150
97265
|
const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
97151
97266
|
if (files.length === 0) {
|
|
97152
97267
|
return null;
|
|
97153
97268
|
}
|
|
97154
|
-
return
|
|
97269
|
+
return join69(runsDir, files[0]);
|
|
97155
97270
|
}
|
|
97156
97271
|
async function extractRunSummary(filePath) {
|
|
97157
97272
|
const file3 = Bun.file(filePath);
|
|
@@ -97237,7 +97352,7 @@ Runs:
|
|
|
97237
97352
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
97238
97353
|
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"));
|
|
97239
97354
|
for (const file3 of files) {
|
|
97240
|
-
const filePath =
|
|
97355
|
+
const filePath = join70(runsDir, file3);
|
|
97241
97356
|
const summary = await extractRunSummary(filePath);
|
|
97242
97357
|
const timestamp = file3.replace(".jsonl", "");
|
|
97243
97358
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -97351,7 +97466,7 @@ async function logsCommand(options) {
|
|
|
97351
97466
|
return;
|
|
97352
97467
|
}
|
|
97353
97468
|
const resolved = resolveProject({ dir: options.dir });
|
|
97354
|
-
const naxDir =
|
|
97469
|
+
const naxDir = join71(resolved.projectDir, ".nax");
|
|
97355
97470
|
const configPath = resolved.configPath;
|
|
97356
97471
|
const configFile = Bun.file(configPath);
|
|
97357
97472
|
const config2 = await configFile.json();
|
|
@@ -97359,8 +97474,8 @@ async function logsCommand(options) {
|
|
|
97359
97474
|
if (!featureName) {
|
|
97360
97475
|
throw new Error("No feature specified in config.json");
|
|
97361
97476
|
}
|
|
97362
|
-
const featureDir =
|
|
97363
|
-
const runsDir =
|
|
97477
|
+
const featureDir = join71(naxDir, "features", featureName);
|
|
97478
|
+
const runsDir = join71(featureDir, "runs");
|
|
97364
97479
|
if (!existsSync28(runsDir)) {
|
|
97365
97480
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
97366
97481
|
}
|
|
@@ -97386,7 +97501,7 @@ init_prd();
|
|
|
97386
97501
|
init_precheck();
|
|
97387
97502
|
init_common();
|
|
97388
97503
|
import { existsSync as existsSync29 } from "fs";
|
|
97389
|
-
import { join as
|
|
97504
|
+
import { join as join72 } from "path";
|
|
97390
97505
|
async function precheckCommand(options) {
|
|
97391
97506
|
const resolved = resolveProject({
|
|
97392
97507
|
dir: options.dir,
|
|
@@ -97408,9 +97523,9 @@ async function precheckCommand(options) {
|
|
|
97408
97523
|
process.exit(1);
|
|
97409
97524
|
}
|
|
97410
97525
|
}
|
|
97411
|
-
const naxDir =
|
|
97412
|
-
const featureDir =
|
|
97413
|
-
const prdPath =
|
|
97526
|
+
const naxDir = join72(resolved.projectDir, ".nax");
|
|
97527
|
+
const featureDir = join72(naxDir, "features", featureName);
|
|
97528
|
+
const prdPath = join72(featureDir, "prd.json");
|
|
97414
97529
|
if (!existsSync29(featureDir)) {
|
|
97415
97530
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
97416
97531
|
process.exit(1);
|
|
@@ -97433,7 +97548,7 @@ async function precheckCommand(options) {
|
|
|
97433
97548
|
init_source();
|
|
97434
97549
|
init_paths3();
|
|
97435
97550
|
import { readdir as readdir5 } from "fs/promises";
|
|
97436
|
-
import { join as
|
|
97551
|
+
import { join as join73 } from "path";
|
|
97437
97552
|
var DEFAULT_LIMIT = 20;
|
|
97438
97553
|
var _runsCmdDeps = {
|
|
97439
97554
|
getRunsDir
|
|
@@ -97488,7 +97603,7 @@ async function runsCommand(options = {}) {
|
|
|
97488
97603
|
}
|
|
97489
97604
|
const rows = [];
|
|
97490
97605
|
for (const entry of entries) {
|
|
97491
|
-
const metaPath =
|
|
97606
|
+
const metaPath = join73(runsDir, entry, "meta.json");
|
|
97492
97607
|
let meta3;
|
|
97493
97608
|
try {
|
|
97494
97609
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -97565,7 +97680,7 @@ async function runsCommand(options = {}) {
|
|
|
97565
97680
|
|
|
97566
97681
|
// src/commands/unlock.ts
|
|
97567
97682
|
init_source();
|
|
97568
|
-
import { join as
|
|
97683
|
+
import { join as join74 } from "path";
|
|
97569
97684
|
function isProcessAlive2(pid) {
|
|
97570
97685
|
try {
|
|
97571
97686
|
process.kill(pid, 0);
|
|
@@ -97580,7 +97695,7 @@ function formatLockAge(ageMs) {
|
|
|
97580
97695
|
}
|
|
97581
97696
|
async function unlockCommand(options) {
|
|
97582
97697
|
const workdir = options.dir ?? process.cwd();
|
|
97583
|
-
const lockPath =
|
|
97698
|
+
const lockPath = join74(workdir, "nax.lock");
|
|
97584
97699
|
const lockFile = Bun.file(lockPath);
|
|
97585
97700
|
const exists = await lockFile.exists();
|
|
97586
97701
|
if (!exists) {
|
|
@@ -98128,6 +98243,7 @@ init_run_regression();
|
|
|
98128
98243
|
|
|
98129
98244
|
// src/execution/index.ts
|
|
98130
98245
|
init_story_orchestrator();
|
|
98246
|
+
init_story_orchestrator_logging();
|
|
98131
98247
|
init_plan_inputs();
|
|
98132
98248
|
init_build_plan_for_strategy();
|
|
98133
98249
|
init_post_run();
|
|
@@ -106004,7 +106120,7 @@ Next: nax generate --package ${options.package}`));
|
|
|
106004
106120
|
}
|
|
106005
106121
|
return;
|
|
106006
106122
|
}
|
|
106007
|
-
const naxDir =
|
|
106123
|
+
const naxDir = join88(workdir, ".nax");
|
|
106008
106124
|
if (existsSync35(naxDir) && !options.force) {
|
|
106009
106125
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
106010
106126
|
return;
|
|
@@ -106033,11 +106149,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
106033
106149
|
}
|
|
106034
106150
|
}
|
|
106035
106151
|
}
|
|
106036
|
-
mkdirSync7(
|
|
106037
|
-
mkdirSync7(
|
|
106152
|
+
mkdirSync7(join88(naxDir, "features"), { recursive: true });
|
|
106153
|
+
mkdirSync7(join88(naxDir, "hooks"), { recursive: true });
|
|
106038
106154
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
106039
|
-
await Bun.write(
|
|
106040
|
-
await Bun.write(
|
|
106155
|
+
await Bun.write(join88(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
|
|
106156
|
+
await Bun.write(join88(naxDir, "hooks.json"), JSON.stringify({
|
|
106041
106157
|
hooks: {
|
|
106042
106158
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
106043
106159
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -106045,12 +106161,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
106045
106161
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
106046
106162
|
}
|
|
106047
106163
|
}, null, 2));
|
|
106048
|
-
await Bun.write(
|
|
106164
|
+
await Bun.write(join88(naxDir, ".gitignore"), `# nax temp files
|
|
106049
106165
|
*.tmp
|
|
106050
106166
|
.paused.json
|
|
106051
106167
|
.nax-verifier-verdict.json
|
|
106052
106168
|
`);
|
|
106053
|
-
await Bun.write(
|
|
106169
|
+
await Bun.write(join88(naxDir, "context.md"), `# Project Context
|
|
106054
106170
|
|
|
106055
106171
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
106056
106172
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -106198,8 +106314,8 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106198
106314
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106199
106315
|
process.exit(1);
|
|
106200
106316
|
}
|
|
106201
|
-
const featureDir =
|
|
106202
|
-
const prdPath =
|
|
106317
|
+
const featureDir = join88(naxDir, "features", options.feature);
|
|
106318
|
+
const prdPath = join88(featureDir, "prd.json");
|
|
106203
106319
|
if (options.plan && options.from) {
|
|
106204
106320
|
if (existsSync35(prdPath) && !options.force) {
|
|
106205
106321
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
@@ -106221,10 +106337,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106221
106337
|
}
|
|
106222
106338
|
}
|
|
106223
106339
|
try {
|
|
106224
|
-
const planLogDir =
|
|
106340
|
+
const planLogDir = join88(featureDir, "plan");
|
|
106225
106341
|
mkdirSync7(planLogDir, { recursive: true });
|
|
106226
106342
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106227
|
-
const planLogPath =
|
|
106343
|
+
const planLogPath = join88(planLogDir, `${planLogId}.jsonl`);
|
|
106228
106344
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106229
106345
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106230
106346
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -106270,10 +106386,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106270
106386
|
resetLogger();
|
|
106271
106387
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
106272
106388
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
106273
|
-
const runsDir =
|
|
106389
|
+
const runsDir = join88(outputDir, "features", options.feature, "runs");
|
|
106274
106390
|
mkdirSync7(runsDir, { recursive: true });
|
|
106275
106391
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106276
|
-
const logFilePath =
|
|
106392
|
+
const logFilePath = join88(runsDir, `${runId}.jsonl`);
|
|
106277
106393
|
const isTTY = process.stdout.isTTY ?? false;
|
|
106278
106394
|
const headlessFlag = options.headless ?? false;
|
|
106279
106395
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -106291,7 +106407,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106291
106407
|
config2.agent.default = options.agent;
|
|
106292
106408
|
}
|
|
106293
106409
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
106294
|
-
const globalNaxDir =
|
|
106410
|
+
const globalNaxDir = join88(homedir3(), ".nax");
|
|
106295
106411
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
106296
106412
|
const eventEmitter = new PipelineEventEmitter;
|
|
106297
106413
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -106311,12 +106427,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106311
106427
|
events: eventEmitter,
|
|
106312
106428
|
ptyOptions: null,
|
|
106313
106429
|
agentStreamEvents,
|
|
106314
|
-
queueFilePath:
|
|
106430
|
+
queueFilePath: join88(workdir, ".queue.txt")
|
|
106315
106431
|
});
|
|
106316
106432
|
} else {
|
|
106317
106433
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
106318
106434
|
}
|
|
106319
|
-
const statusFilePath =
|
|
106435
|
+
const statusFilePath = join88(outputDir, "status.json");
|
|
106320
106436
|
let parallel;
|
|
106321
106437
|
if (options.parallel !== undefined) {
|
|
106322
106438
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -106343,7 +106459,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
106343
106459
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
106344
106460
|
agentStreamEvents
|
|
106345
106461
|
});
|
|
106346
|
-
const latestSymlink =
|
|
106462
|
+
const latestSymlink = join88(runsDir, "latest.jsonl");
|
|
106347
106463
|
try {
|
|
106348
106464
|
if (existsSync35(latestSymlink)) {
|
|
106349
106465
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
@@ -106404,9 +106520,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106404
106520
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
106405
106521
|
process.exit(1);
|
|
106406
106522
|
}
|
|
106407
|
-
const featureDir =
|
|
106523
|
+
const featureDir = join88(naxDir, "features", name);
|
|
106408
106524
|
mkdirSync7(featureDir, { recursive: true });
|
|
106409
|
-
await Bun.write(
|
|
106525
|
+
await Bun.write(join88(featureDir, "spec.md"), `# Feature: ${name}
|
|
106410
106526
|
|
|
106411
106527
|
## Overview
|
|
106412
106528
|
|
|
@@ -106439,7 +106555,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
106439
106555
|
|
|
106440
106556
|
<!-- What this feature explicitly does NOT cover. -->
|
|
106441
106557
|
`);
|
|
106442
|
-
await Bun.write(
|
|
106558
|
+
await Bun.write(join88(featureDir, "progress.txt"), `# Progress: ${name}
|
|
106443
106559
|
|
|
106444
106560
|
Created: ${new Date().toISOString()}
|
|
106445
106561
|
|
|
@@ -106465,7 +106581,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106465
106581
|
console.error(source_default.red("nax not initialized."));
|
|
106466
106582
|
process.exit(1);
|
|
106467
106583
|
}
|
|
106468
|
-
const featuresDir =
|
|
106584
|
+
const featuresDir = join88(naxDir, "features");
|
|
106469
106585
|
if (!existsSync35(featuresDir)) {
|
|
106470
106586
|
console.log(source_default.dim("No features yet."));
|
|
106471
106587
|
return;
|
|
@@ -106480,7 +106596,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
106480
106596
|
Features:
|
|
106481
106597
|
`));
|
|
106482
106598
|
for (const name of entries) {
|
|
106483
|
-
const prdPath =
|
|
106599
|
+
const prdPath = join88(featuresDir, name, "prd.json");
|
|
106484
106600
|
if (existsSync35(prdPath)) {
|
|
106485
106601
|
const prd = await loadPRD(prdPath);
|
|
106486
106602
|
const c = countStories(prd);
|
|
@@ -106515,10 +106631,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
106515
106631
|
cliOverrides.profile = options.profile;
|
|
106516
106632
|
}
|
|
106517
106633
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
106518
|
-
const featureLogDir =
|
|
106634
|
+
const featureLogDir = join88(naxDir, "features", options.feature, "plan");
|
|
106519
106635
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
106520
106636
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
106521
|
-
const planLogPath =
|
|
106637
|
+
const planLogPath = join88(featureLogDir, `${planLogId}.jsonl`);
|
|
106522
106638
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
106523
106639
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
106524
106640
|
try {
|