@nathapp/nax 0.70.5 → 0.70.6
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 +218 -161
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -60861,7 +60861,7 @@ var init_loader4 = __esm(() => {
|
|
|
60861
60861
|
});
|
|
60862
60862
|
|
|
60863
60863
|
// src/hooks/runner.ts
|
|
60864
|
-
import { join as
|
|
60864
|
+
import { join as join78 } from "path";
|
|
60865
60865
|
function createDrainDeadline2(deadlineMs) {
|
|
60866
60866
|
let timeoutId;
|
|
60867
60867
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -60880,14 +60880,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
60880
60880
|
let globalHooks = { hooks: {} };
|
|
60881
60881
|
let projectHooks = { hooks: {} };
|
|
60882
60882
|
let skipGlobal = false;
|
|
60883
|
-
const projectPath =
|
|
60883
|
+
const projectPath = join78(projectDir, "hooks.json");
|
|
60884
60884
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
60885
60885
|
if (projectData) {
|
|
60886
60886
|
projectHooks = projectData;
|
|
60887
60887
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
60888
60888
|
}
|
|
60889
60889
|
if (!skipGlobal && globalDir) {
|
|
60890
|
-
const globalPath =
|
|
60890
|
+
const globalPath = join78(globalDir, "hooks.json");
|
|
60891
60891
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
60892
60892
|
if (globalData) {
|
|
60893
60893
|
globalHooks = globalData;
|
|
@@ -61057,7 +61057,7 @@ var package_default;
|
|
|
61057
61057
|
var init_package = __esm(() => {
|
|
61058
61058
|
package_default = {
|
|
61059
61059
|
name: "@nathapp/nax",
|
|
61060
|
-
version: "0.70.
|
|
61060
|
+
version: "0.70.6",
|
|
61061
61061
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
61062
61062
|
type: "module",
|
|
61063
61063
|
bin: {
|
|
@@ -61157,8 +61157,8 @@ var init_version = __esm(() => {
|
|
|
61157
61157
|
NAX_VERSION = package_default.version;
|
|
61158
61158
|
NAX_COMMIT = (() => {
|
|
61159
61159
|
try {
|
|
61160
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
61161
|
-
return "
|
|
61160
|
+
if (/^[0-9a-f]{6,10}$/.test("eb4e2b89"))
|
|
61161
|
+
return "eb4e2b89";
|
|
61162
61162
|
} catch {}
|
|
61163
61163
|
try {
|
|
61164
61164
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -62036,15 +62036,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
62036
62036
|
|
|
62037
62037
|
// src/session/scratch-purge.ts
|
|
62038
62038
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
62039
|
-
import { dirname as dirname12, join as
|
|
62039
|
+
import { dirname as dirname12, join as join79 } from "path";
|
|
62040
62040
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
62041
|
-
const sessionsDir =
|
|
62041
|
+
const sessionsDir = join79(projectDir, ".nax", "features", featureName, "sessions");
|
|
62042
62042
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
62043
62043
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
62044
62044
|
let purged = 0;
|
|
62045
62045
|
for (const sessionId of sessionIds) {
|
|
62046
|
-
const sessionDir =
|
|
62047
|
-
const descriptorPath =
|
|
62046
|
+
const sessionDir = join79(sessionsDir, sessionId);
|
|
62047
|
+
const descriptorPath = join79(sessionDir, "descriptor.json");
|
|
62048
62048
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
62049
62049
|
continue;
|
|
62050
62050
|
let lastActivityAt;
|
|
@@ -62060,7 +62060,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
62060
62060
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
62061
62061
|
continue;
|
|
62062
62062
|
if (archiveInsteadOfDelete) {
|
|
62063
|
-
const archiveDest =
|
|
62063
|
+
const archiveDest = join79(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
62064
62064
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
62065
62065
|
} else {
|
|
62066
62066
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -62811,12 +62811,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
62811
62811
|
|
|
62812
62812
|
// src/pipeline/subscribers/events-writer.ts
|
|
62813
62813
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
62814
|
-
import { basename as basename13, join as
|
|
62814
|
+
import { basename as basename13, join as join80 } from "path";
|
|
62815
62815
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
62816
62816
|
const logger = getSafeLogger();
|
|
62817
62817
|
const project = basename13(workdir);
|
|
62818
|
-
const eventsDir =
|
|
62819
|
-
const eventsFile =
|
|
62818
|
+
const eventsDir = join80(getEventsRootDir(), project);
|
|
62819
|
+
const eventsFile = join80(eventsDir, "events.jsonl");
|
|
62820
62820
|
let dirReady = false;
|
|
62821
62821
|
const write = (line) => {
|
|
62822
62822
|
return (async () => {
|
|
@@ -62997,12 +62997,12 @@ var init_interaction2 = __esm(() => {
|
|
|
62997
62997
|
|
|
62998
62998
|
// src/pipeline/subscribers/registry.ts
|
|
62999
62999
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
63000
|
-
import { basename as basename14, join as
|
|
63000
|
+
import { basename as basename14, join as join81 } from "path";
|
|
63001
63001
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
63002
63002
|
const logger = getSafeLogger();
|
|
63003
63003
|
const project = basename14(workdir);
|
|
63004
|
-
const runDir =
|
|
63005
|
-
const metaFile =
|
|
63004
|
+
const runDir = join81(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
63005
|
+
const metaFile = join81(runDir, "meta.json");
|
|
63006
63006
|
const unsub = bus.on("run:started", (_ev) => {
|
|
63007
63007
|
return (async () => {
|
|
63008
63008
|
try {
|
|
@@ -63012,8 +63012,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
63012
63012
|
project,
|
|
63013
63013
|
feature,
|
|
63014
63014
|
workdir,
|
|
63015
|
-
statusPath:
|
|
63016
|
-
eventsDir:
|
|
63015
|
+
statusPath: join81(outputDir, "features", feature, "status.json"),
|
|
63016
|
+
eventsDir: join81(outputDir, "features", feature, "runs"),
|
|
63017
63017
|
registeredAt: new Date().toISOString()
|
|
63018
63018
|
};
|
|
63019
63019
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -63258,8 +63258,8 @@ var init_types10 = __esm(() => {
|
|
|
63258
63258
|
});
|
|
63259
63259
|
|
|
63260
63260
|
// src/worktree/dependencies.ts
|
|
63261
|
-
import { existsSync as
|
|
63262
|
-
import { join as
|
|
63261
|
+
import { existsSync as existsSync32 } from "fs";
|
|
63262
|
+
import { join as join82 } from "path";
|
|
63263
63263
|
async function prepareWorktreeDependencies(options) {
|
|
63264
63264
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
63265
63265
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -63273,7 +63273,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
63273
63273
|
}
|
|
63274
63274
|
}
|
|
63275
63275
|
function resolveDependencyCwd(options) {
|
|
63276
|
-
return options.storyWorkdir ?
|
|
63276
|
+
return options.storyWorkdir ? join82(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
63277
63277
|
}
|
|
63278
63278
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
63279
63279
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -63283,7 +63283,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
63283
63283
|
}
|
|
63284
63284
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
63285
63285
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
63286
|
-
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(
|
|
63286
|
+
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join82(directory, filename))));
|
|
63287
63287
|
}
|
|
63288
63288
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
63289
63289
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -63334,7 +63334,7 @@ var init_dependencies = __esm(() => {
|
|
|
63334
63334
|
"build.gradle.kts"
|
|
63335
63335
|
];
|
|
63336
63336
|
_worktreeDependencyDeps = {
|
|
63337
|
-
existsSync:
|
|
63337
|
+
existsSync: existsSync32,
|
|
63338
63338
|
spawn
|
|
63339
63339
|
};
|
|
63340
63340
|
});
|
|
@@ -63345,19 +63345,19 @@ __export(exports_manager, {
|
|
|
63345
63345
|
_managerDeps: () => _managerDeps,
|
|
63346
63346
|
WorktreeManager: () => WorktreeManager
|
|
63347
63347
|
});
|
|
63348
|
-
import { existsSync as
|
|
63348
|
+
import { existsSync as existsSync33, symlinkSync } from "fs";
|
|
63349
63349
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
63350
|
-
import { join as
|
|
63350
|
+
import { join as join83 } from "path";
|
|
63351
63351
|
|
|
63352
63352
|
class WorktreeManager {
|
|
63353
63353
|
async ensureGitExcludes(projectRoot) {
|
|
63354
63354
|
const logger = getSafeLogger();
|
|
63355
|
-
const infoDir =
|
|
63356
|
-
const excludePath =
|
|
63355
|
+
const infoDir = join83(projectRoot, ".git", "info");
|
|
63356
|
+
const excludePath = join83(infoDir, "exclude");
|
|
63357
63357
|
try {
|
|
63358
63358
|
await mkdir15(infoDir, { recursive: true });
|
|
63359
63359
|
let existing = "";
|
|
63360
|
-
if (
|
|
63360
|
+
if (existsSync33(excludePath)) {
|
|
63361
63361
|
existing = await Bun.file(excludePath).text();
|
|
63362
63362
|
}
|
|
63363
63363
|
const missing = NAX_GITIGNORE_ENTRIES.filter((entry) => !existing.includes(entry));
|
|
@@ -63380,7 +63380,7 @@ ${missing.join(`
|
|
|
63380
63380
|
}
|
|
63381
63381
|
async create(projectRoot, storyId) {
|
|
63382
63382
|
validateStoryId(storyId);
|
|
63383
|
-
const worktreePath =
|
|
63383
|
+
const worktreePath = join83(projectRoot, ".nax-wt", storyId);
|
|
63384
63384
|
const branchName = `nax/${storyId}`;
|
|
63385
63385
|
try {
|
|
63386
63386
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -63441,9 +63441,9 @@ ${missing.join(`
|
|
|
63441
63441
|
projectRoot
|
|
63442
63442
|
});
|
|
63443
63443
|
}
|
|
63444
|
-
const envSource =
|
|
63445
|
-
if (
|
|
63446
|
-
const envTarget =
|
|
63444
|
+
const envSource = join83(projectRoot, ".env");
|
|
63445
|
+
if (existsSync33(envSource)) {
|
|
63446
|
+
const envTarget = join83(worktreePath, ".env");
|
|
63447
63447
|
try {
|
|
63448
63448
|
symlinkSync(envSource, envTarget, "file");
|
|
63449
63449
|
} catch (error48) {
|
|
@@ -63459,7 +63459,7 @@ ${missing.join(`
|
|
|
63459
63459
|
}
|
|
63460
63460
|
async remove(projectRoot, storyId) {
|
|
63461
63461
|
validateStoryId(storyId);
|
|
63462
|
-
const worktreePath =
|
|
63462
|
+
const worktreePath = join83(projectRoot, ".nax-wt", storyId);
|
|
63463
63463
|
const branchName = `nax/${storyId}`;
|
|
63464
63464
|
try {
|
|
63465
63465
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -64306,10 +64306,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
64306
64306
|
});
|
|
64307
64307
|
|
|
64308
64308
|
// src/execution/pipeline-result-handler.ts
|
|
64309
|
-
import { join as
|
|
64309
|
+
import { join as join84 } from "path";
|
|
64310
64310
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
64311
64311
|
const logger = getSafeLogger();
|
|
64312
|
-
const worktreePath =
|
|
64312
|
+
const worktreePath = join84(projectRoot, ".nax-wt", storyId);
|
|
64313
64313
|
try {
|
|
64314
64314
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
64315
64315
|
cwd: projectRoot,
|
|
@@ -64525,8 +64525,8 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
64525
64525
|
});
|
|
64526
64526
|
|
|
64527
64527
|
// src/execution/iteration-runner.ts
|
|
64528
|
-
import { existsSync as
|
|
64529
|
-
import { join as
|
|
64528
|
+
import { existsSync as existsSync34 } from "fs";
|
|
64529
|
+
import { join as join85 } from "path";
|
|
64530
64530
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
64531
64531
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
64532
64532
|
if (ctx.dryRun) {
|
|
@@ -64551,7 +64551,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64551
64551
|
const storyStartTime = Date.now();
|
|
64552
64552
|
let effectiveWorkdir = ctx.workdir;
|
|
64553
64553
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
64554
|
-
const worktreePath =
|
|
64554
|
+
const worktreePath = join85(ctx.workdir, ".nax-wt", story.id);
|
|
64555
64555
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
64556
64556
|
if (!worktreeExists) {
|
|
64557
64557
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -64571,7 +64571,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64571
64571
|
}
|
|
64572
64572
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
64573
64573
|
const profileOverride = profileOverrideFromConfig(ctx.config);
|
|
64574
|
-
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(
|
|
64574
|
+
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join85(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
|
|
64575
64575
|
let dependencyContext;
|
|
64576
64576
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
64577
64577
|
try {
|
|
@@ -64598,7 +64598,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64598
64598
|
};
|
|
64599
64599
|
}
|
|
64600
64600
|
}
|
|
64601
|
-
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ?
|
|
64601
|
+
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ? join85(effectiveWorkdir, story.workdir) : effectiveWorkdir : story.workdir ? join85(ctx.workdir, story.workdir) : ctx.workdir;
|
|
64602
64602
|
const pipelineContext = {
|
|
64603
64603
|
config: effectiveConfig,
|
|
64604
64604
|
rootConfig: ctx.config,
|
|
@@ -64731,7 +64731,7 @@ var init_iteration_runner = __esm(() => {
|
|
|
64731
64731
|
loadConfigForWorkdir,
|
|
64732
64732
|
prepareWorktreeDependencies,
|
|
64733
64733
|
runPipeline,
|
|
64734
|
-
existsSync:
|
|
64734
|
+
existsSync: existsSync34,
|
|
64735
64735
|
worktreeManager: new WorktreeManager
|
|
64736
64736
|
};
|
|
64737
64737
|
});
|
|
@@ -64801,7 +64801,7 @@ __export(exports_parallel_worker, {
|
|
|
64801
64801
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
64802
64802
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
64803
64803
|
});
|
|
64804
|
-
import { join as
|
|
64804
|
+
import { join as join86 } from "path";
|
|
64805
64805
|
function buildWorktreePipelineContext(base, _story) {
|
|
64806
64806
|
return { ...base, prd: structuredClone(base.prd) };
|
|
64807
64807
|
}
|
|
@@ -64824,7 +64824,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
64824
64824
|
story,
|
|
64825
64825
|
stories: [story],
|
|
64826
64826
|
projectDir: context.projectDir,
|
|
64827
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
64827
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join86(worktreePath, story.workdir) : worktreePath),
|
|
64828
64828
|
worktreeDependencyContext: dependencyContext,
|
|
64829
64829
|
routing,
|
|
64830
64830
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -65724,7 +65724,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
65724
65724
|
var init_status_file = () => {};
|
|
65725
65725
|
|
|
65726
65726
|
// src/execution/status-writer.ts
|
|
65727
|
-
import { join as
|
|
65727
|
+
import { join as join87 } from "path";
|
|
65728
65728
|
|
|
65729
65729
|
class StatusWriter {
|
|
65730
65730
|
statusFile;
|
|
@@ -65843,7 +65843,7 @@ class StatusWriter {
|
|
|
65843
65843
|
if (!this._prd)
|
|
65844
65844
|
return;
|
|
65845
65845
|
const safeLogger = getSafeLogger();
|
|
65846
|
-
const featureStatusPath =
|
|
65846
|
+
const featureStatusPath = join87(featureDir, "status.json");
|
|
65847
65847
|
const write = async () => {
|
|
65848
65848
|
try {
|
|
65849
65849
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -65874,11 +65874,11 @@ __export(exports_migrate, {
|
|
|
65874
65874
|
migrateCommand: () => migrateCommand,
|
|
65875
65875
|
detectGeneratedContent: () => detectGeneratedContent
|
|
65876
65876
|
});
|
|
65877
|
-
import { existsSync as
|
|
65877
|
+
import { existsSync as existsSync35 } from "fs";
|
|
65878
65878
|
import { mkdir as mkdir16, readdir as readdir5, rename as rename3 } from "fs/promises";
|
|
65879
65879
|
import path25 from "path";
|
|
65880
65880
|
async function detectGeneratedContent(naxDir) {
|
|
65881
|
-
if (!
|
|
65881
|
+
if (!existsSync35(naxDir))
|
|
65882
65882
|
return [];
|
|
65883
65883
|
const candidates = [];
|
|
65884
65884
|
let entries = [];
|
|
@@ -65893,7 +65893,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
65893
65893
|
}
|
|
65894
65894
|
}
|
|
65895
65895
|
const featuresDir = path25.join(naxDir, "features");
|
|
65896
|
-
if (
|
|
65896
|
+
if (existsSync35(featuresDir)) {
|
|
65897
65897
|
let featureDirs = [];
|
|
65898
65898
|
try {
|
|
65899
65899
|
featureDirs = await readdir5(featuresDir);
|
|
@@ -65955,7 +65955,7 @@ async function migrateCommand(options) {
|
|
|
65955
65955
|
});
|
|
65956
65956
|
}
|
|
65957
65957
|
const src = path25.join(globalConfigDir(), options.reclaim);
|
|
65958
|
-
if (!
|
|
65958
|
+
if (!existsSync35(src)) {
|
|
65959
65959
|
throw new NaxError(`Nothing to reclaim: ~/.nax/${options.reclaim} does not exist`, "MIGRATE_RECLAIM_NOT_FOUND", {
|
|
65960
65960
|
stage: "migrate",
|
|
65961
65961
|
name: options.reclaim
|
|
@@ -66001,7 +66001,7 @@ async function migrateCommand(options) {
|
|
|
66001
66001
|
}
|
|
66002
66002
|
const naxDir = path25.join(options.workdir, ".nax");
|
|
66003
66003
|
const configPath = path25.join(naxDir, "config.json");
|
|
66004
|
-
if (!
|
|
66004
|
+
if (!existsSync35(configPath)) {
|
|
66005
66005
|
throw new NaxError("No .nax/config.json found \u2014 run nax init first", "MIGRATE_NO_CONFIG", {
|
|
66006
66006
|
stage: "migrate",
|
|
66007
66007
|
workdir: options.workdir
|
|
@@ -66036,7 +66036,7 @@ async function migrateCommand(options) {
|
|
|
66036
66036
|
for (const candidate of candidates) {
|
|
66037
66037
|
const dest = path25.join(destBase, candidate.name);
|
|
66038
66038
|
await mkdir16(path25.dirname(dest), { recursive: true });
|
|
66039
|
-
if (
|
|
66039
|
+
if (existsSync35(dest)) {
|
|
66040
66040
|
throw new NaxError(`Migration conflict: destination already exists.
|
|
66041
66041
|
Source: ${candidate.srcPath}
|
|
66042
66042
|
Destination: ${dest}
|
|
@@ -66287,7 +66287,7 @@ __export(exports_run_initialization, {
|
|
|
66287
66287
|
initializeRun: () => initializeRun,
|
|
66288
66288
|
_reconcileDeps: () => _reconcileDeps
|
|
66289
66289
|
});
|
|
66290
|
-
import { join as
|
|
66290
|
+
import { join as join88 } from "path";
|
|
66291
66291
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
66292
66292
|
const logger = getSafeLogger();
|
|
66293
66293
|
let reconciledCount = 0;
|
|
@@ -66304,7 +66304,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
66304
66304
|
});
|
|
66305
66305
|
continue;
|
|
66306
66306
|
}
|
|
66307
|
-
const effectiveWorkdir = story.workdir ?
|
|
66307
|
+
const effectiveWorkdir = story.workdir ? join88(workdir, story.workdir) : workdir;
|
|
66308
66308
|
try {
|
|
66309
66309
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
66310
66310
|
if (!reviewResult.success) {
|
|
@@ -96135,7 +96135,7 @@ __export(exports_curator, {
|
|
|
96135
96135
|
});
|
|
96136
96136
|
import { readdirSync as readdirSync9 } from "fs";
|
|
96137
96137
|
import { unlink as unlink4 } from "fs/promises";
|
|
96138
|
-
import { basename as basename15, join as
|
|
96138
|
+
import { basename as basename15, join as join90 } from "path";
|
|
96139
96139
|
function getProjectKey(config2, projectDir) {
|
|
96140
96140
|
return config2.name?.trim() || basename15(projectDir);
|
|
96141
96141
|
}
|
|
@@ -96218,7 +96218,7 @@ async function curatorStatus(options) {
|
|
|
96218
96218
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
96219
96219
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
96220
96220
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
96221
|
-
const runsDir =
|
|
96221
|
+
const runsDir = join90(outputDir, "runs");
|
|
96222
96222
|
const runIds = listRunIds(runsDir);
|
|
96223
96223
|
let runId;
|
|
96224
96224
|
if (options.run) {
|
|
@@ -96235,8 +96235,8 @@ async function curatorStatus(options) {
|
|
|
96235
96235
|
runId = runIds[runIds.length - 1];
|
|
96236
96236
|
}
|
|
96237
96237
|
console.log(`Run: ${runId}`);
|
|
96238
|
-
const runDir =
|
|
96239
|
-
const observationsPath =
|
|
96238
|
+
const runDir = join90(runsDir, runId);
|
|
96239
|
+
const observationsPath = join90(runDir, "observations.jsonl");
|
|
96240
96240
|
const observations = await parseObservations(observationsPath);
|
|
96241
96241
|
const counts = new Map;
|
|
96242
96242
|
for (const obs of observations) {
|
|
@@ -96246,7 +96246,7 @@ async function curatorStatus(options) {
|
|
|
96246
96246
|
for (const [kind, count] of counts.entries()) {
|
|
96247
96247
|
console.log(` ${kind}: ${count}`);
|
|
96248
96248
|
}
|
|
96249
|
-
const proposalsPath =
|
|
96249
|
+
const proposalsPath = join90(runDir, "curator-proposals.md");
|
|
96250
96250
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
96251
96251
|
if (proposalText !== null) {
|
|
96252
96252
|
console.log("");
|
|
@@ -96260,8 +96260,8 @@ async function curatorCommit(options) {
|
|
|
96260
96260
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
96261
96261
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
96262
96262
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
96263
|
-
const runDir =
|
|
96264
|
-
const proposalsPath =
|
|
96263
|
+
const runDir = join90(outputDir, "runs", options.runId);
|
|
96264
|
+
const proposalsPath = join90(runDir, "curator-proposals.md");
|
|
96265
96265
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
96266
96266
|
if (proposalText === null) {
|
|
96267
96267
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -96277,7 +96277,7 @@ async function curatorCommit(options) {
|
|
|
96277
96277
|
const dropFileState = new Map;
|
|
96278
96278
|
const skippedDrops = new Set;
|
|
96279
96279
|
for (const drop2 of drops) {
|
|
96280
|
-
const targetPath =
|
|
96280
|
+
const targetPath = join90(resolved.projectDir, drop2.canonicalFile);
|
|
96281
96281
|
if (!dropFileState.has(targetPath)) {
|
|
96282
96282
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
96283
96283
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -96311,7 +96311,7 @@ async function curatorCommit(options) {
|
|
|
96311
96311
|
if (skippedDrops.has(drop2)) {
|
|
96312
96312
|
continue;
|
|
96313
96313
|
}
|
|
96314
|
-
const targetPath =
|
|
96314
|
+
const targetPath = join90(resolved.projectDir, drop2.canonicalFile);
|
|
96315
96315
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
96316
96316
|
const filtered = filterDropContent(existing, drop2.description);
|
|
96317
96317
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -96320,7 +96320,7 @@ async function curatorCommit(options) {
|
|
|
96320
96320
|
}
|
|
96321
96321
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
96322
96322
|
for (const add2 of adds) {
|
|
96323
|
-
const targetPath =
|
|
96323
|
+
const targetPath = join90(resolved.projectDir, add2.canonicalFile);
|
|
96324
96324
|
const content = buildAddContent(add2);
|
|
96325
96325
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
96326
96326
|
modifiedFiles.add(targetPath);
|
|
@@ -96357,7 +96357,7 @@ async function curatorDryrun(options) {
|
|
|
96357
96357
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
96358
96358
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
96359
96359
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
96360
|
-
const runsDir =
|
|
96360
|
+
const runsDir = join90(outputDir, "runs");
|
|
96361
96361
|
const runIds = listRunIds(runsDir);
|
|
96362
96362
|
if (runIds.length === 0) {
|
|
96363
96363
|
console.log("No runs found.");
|
|
@@ -96368,7 +96368,7 @@ async function curatorDryrun(options) {
|
|
|
96368
96368
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
96369
96369
|
return;
|
|
96370
96370
|
}
|
|
96371
|
-
const observationsPath =
|
|
96371
|
+
const observationsPath = join90(runsDir, runId, "observations.jsonl");
|
|
96372
96372
|
const observations = await parseObservations(observationsPath);
|
|
96373
96373
|
const thresholds = getThresholds(config2);
|
|
96374
96374
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -96409,12 +96409,12 @@ async function curatorGc(options) {
|
|
|
96409
96409
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
96410
96410
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
96411
96411
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
96412
|
-
const perRunsDir =
|
|
96412
|
+
const perRunsDir = join90(outputDir, "runs");
|
|
96413
96413
|
for (const runId of uniqueRunIds) {
|
|
96414
96414
|
if (!keepSet.has(runId)) {
|
|
96415
|
-
const runDir =
|
|
96416
|
-
await _curatorCmdDeps.removeFile(
|
|
96417
|
-
await _curatorCmdDeps.removeFile(
|
|
96415
|
+
const runDir = join90(perRunsDir, runId);
|
|
96416
|
+
await _curatorCmdDeps.removeFile(join90(runDir, "observations.jsonl"));
|
|
96417
|
+
await _curatorCmdDeps.removeFile(join90(runDir, "curator-proposals.md"));
|
|
96418
96418
|
}
|
|
96419
96419
|
}
|
|
96420
96420
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -96457,9 +96457,9 @@ var init_curator2 = __esm(() => {
|
|
|
96457
96457
|
|
|
96458
96458
|
// bin/nax.ts
|
|
96459
96459
|
init_source();
|
|
96460
|
-
import { existsSync as
|
|
96460
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync7 } from "fs";
|
|
96461
96461
|
import { homedir as homedir3 } from "os";
|
|
96462
|
-
import { basename as basename16, join as
|
|
96462
|
+
import { basename as basename16, join as join91 } from "path";
|
|
96463
96463
|
|
|
96464
96464
|
// node_modules/commander/esm.mjs
|
|
96465
96465
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -98733,64 +98733,119 @@ async function resolveRunProfileOverride(opts) {
|
|
|
98733
98733
|
}
|
|
98734
98734
|
// src/cli/features-resolve.ts
|
|
98735
98735
|
init_config();
|
|
98736
|
-
import { existsSync as
|
|
98736
|
+
import { existsSync as existsSync28, readdirSync as readdirSync6 } from "fs";
|
|
98737
|
+
import { join as join70, relative as relative15 } from "path";
|
|
98738
|
+
|
|
98739
|
+
// src/cli/features-acceptance.ts
|
|
98740
|
+
init_acceptance2();
|
|
98741
|
+
init_config();
|
|
98742
|
+
init_logger2();
|
|
98743
|
+
init_prd();
|
|
98744
|
+
import { existsSync as existsSync27 } from "fs";
|
|
98737
98745
|
import { join as join69, relative as relative14 } from "path";
|
|
98746
|
+
async function resolveFeatureAcceptance(featureName, workdir) {
|
|
98747
|
+
let enabled = true;
|
|
98748
|
+
try {
|
|
98749
|
+
const naxDir = findProjectDir(workdir);
|
|
98750
|
+
if (!naxDir) {
|
|
98751
|
+
return { status: "no-prd", enabled, groups: [] };
|
|
98752
|
+
}
|
|
98753
|
+
const repoRoot = join69(naxDir, "..");
|
|
98754
|
+
const config2 = await loadConfig(workdir);
|
|
98755
|
+
enabled = config2.acceptance?.enabled ?? true;
|
|
98756
|
+
if (!enabled) {
|
|
98757
|
+
return { status: "disabled", enabled: false, groups: [] };
|
|
98758
|
+
}
|
|
98759
|
+
const prdPath = join69(naxDir, "features", featureName, "prd.json");
|
|
98760
|
+
if (!existsSync27(prdPath)) {
|
|
98761
|
+
return { status: "no-prd", enabled, groups: [] };
|
|
98762
|
+
}
|
|
98763
|
+
const prd = await loadPRD(prdPath);
|
|
98764
|
+
const testGroups = await groupStoriesByPackage(prd, repoRoot, featureName, config2.acceptance?.testPath, config2.project?.language);
|
|
98765
|
+
const groups = await Promise.all(testGroups.map(async (g) => {
|
|
98766
|
+
const packageDir = relative14(repoRoot, g.packageDir);
|
|
98767
|
+
const command = await resolveGroupCommand(repoRoot, packageDir, config2.acceptance?.command);
|
|
98768
|
+
return {
|
|
98769
|
+
packageDir,
|
|
98770
|
+
testPath: relative14(repoRoot, g.testPath),
|
|
98771
|
+
exists: await Bun.file(g.testPath).exists(),
|
|
98772
|
+
command,
|
|
98773
|
+
language: g.language
|
|
98774
|
+
};
|
|
98775
|
+
}));
|
|
98776
|
+
return { status: "ok", enabled, groups };
|
|
98777
|
+
} catch (err) {
|
|
98778
|
+
getSafeLogger()?.warn("acceptance", "Failed to resolve feature acceptance targets", {
|
|
98779
|
+
featureName,
|
|
98780
|
+
cause: errorMessage(err)
|
|
98781
|
+
});
|
|
98782
|
+
return { status: "no-prd", enabled, groups: [] };
|
|
98783
|
+
}
|
|
98784
|
+
}
|
|
98785
|
+
async function resolveGroupCommand(repoRoot, packageDir, rootCommand) {
|
|
98786
|
+
if (packageDir === "")
|
|
98787
|
+
return rootCommand;
|
|
98788
|
+
const override = await loadPackageOverride(repoRoot, packageDir);
|
|
98789
|
+
return override?.acceptance?.command ?? rootCommand;
|
|
98790
|
+
}
|
|
98791
|
+
|
|
98792
|
+
// src/cli/features-resolve.ts
|
|
98738
98793
|
async function isNonEmptyFile(absolutePath) {
|
|
98739
|
-
if (!
|
|
98794
|
+
if (!existsSync28(absolutePath))
|
|
98740
98795
|
return false;
|
|
98741
98796
|
const content = await Bun.file(absolutePath).text();
|
|
98742
98797
|
return content.trim().length > 0;
|
|
98743
98798
|
}
|
|
98744
98799
|
async function searchSpecSource(naxDir, repoRoot, name) {
|
|
98745
98800
|
const candidates = [
|
|
98746
|
-
{ abs:
|
|
98747
|
-
{ abs:
|
|
98801
|
+
{ abs: join70(naxDir, "features", name, "spec.md"), kind: "markdown" },
|
|
98802
|
+
{ abs: join70(naxDir, "specs", `${name}.md`), kind: "markdown" }
|
|
98748
98803
|
];
|
|
98749
|
-
const docsSpecExact =
|
|
98804
|
+
const docsSpecExact = join70(repoRoot, "docs", "specs", `SPEC-${name}.md`);
|
|
98750
98805
|
candidates.push({ abs: docsSpecExact, kind: "markdown" });
|
|
98751
|
-
const checked = candidates.map((c) =>
|
|
98806
|
+
const checked = candidates.map((c) => relative15(repoRoot, c.abs));
|
|
98752
98807
|
for (const { abs, kind } of candidates.slice(0, 2)) {
|
|
98753
98808
|
if (kind === "markdown") {
|
|
98754
98809
|
const nonEmpty = await isNonEmptyFile(abs);
|
|
98755
98810
|
if (nonEmpty) {
|
|
98756
|
-
return { source: { kind, path:
|
|
98811
|
+
return { source: { kind, path: relative15(repoRoot, abs) }, checked };
|
|
98757
98812
|
}
|
|
98758
98813
|
}
|
|
98759
98814
|
}
|
|
98760
98815
|
if (await isNonEmptyFile(docsSpecExact)) {
|
|
98761
|
-
return { source: { kind: "markdown", path:
|
|
98816
|
+
return { source: { kind: "markdown", path: relative15(repoRoot, docsSpecExact) }, checked };
|
|
98762
98817
|
}
|
|
98763
|
-
const docsSpecsDir =
|
|
98764
|
-
if (
|
|
98818
|
+
const docsSpecsDir = join70(repoRoot, "docs", "specs");
|
|
98819
|
+
if (existsSync28(docsSpecsDir)) {
|
|
98765
98820
|
const glob = new Bun.Glob(`*${name}*.md`);
|
|
98766
98821
|
for (const match of glob.scanSync({ cwd: docsSpecsDir, absolute: false })) {
|
|
98767
|
-
const abs =
|
|
98822
|
+
const abs = join70(docsSpecsDir, match);
|
|
98768
98823
|
if (await isNonEmptyFile(abs)) {
|
|
98769
|
-
const relPath =
|
|
98824
|
+
const relPath = relative15(repoRoot, abs);
|
|
98770
98825
|
if (!checked.includes(relPath))
|
|
98771
98826
|
checked.push(relPath);
|
|
98772
98827
|
return { source: { kind: "markdown", path: relPath }, checked };
|
|
98773
98828
|
}
|
|
98774
98829
|
}
|
|
98775
98830
|
}
|
|
98776
|
-
const prdAbs =
|
|
98777
|
-
const prdRel =
|
|
98831
|
+
const prdAbs = join70(naxDir, "features", name, "prd.json");
|
|
98832
|
+
const prdRel = relative15(repoRoot, prdAbs);
|
|
98778
98833
|
if (!checked.includes(prdRel))
|
|
98779
98834
|
checked.push(prdRel);
|
|
98780
|
-
if (
|
|
98835
|
+
if (existsSync28(prdAbs)) {
|
|
98781
98836
|
return { source: { kind: "prd", path: prdRel }, checked };
|
|
98782
98837
|
}
|
|
98783
98838
|
return { source: null, checked };
|
|
98784
98839
|
}
|
|
98785
98840
|
function discoverCandidates(naxDir) {
|
|
98786
|
-
const featuresDir =
|
|
98787
|
-
if (!
|
|
98841
|
+
const featuresDir = join70(naxDir, "features");
|
|
98842
|
+
if (!existsSync28(featuresDir))
|
|
98788
98843
|
return [];
|
|
98789
98844
|
return readdirSync6(featuresDir, { withFileTypes: true }).filter((e) => {
|
|
98790
98845
|
if (!e.isDirectory())
|
|
98791
98846
|
return false;
|
|
98792
|
-
const dir =
|
|
98793
|
-
return
|
|
98847
|
+
const dir = join70(featuresDir, e.name);
|
|
98848
|
+
return existsSync28(join70(dir, "prd.json")) || existsSync28(join70(dir, "spec.md"));
|
|
98794
98849
|
}).map((e) => e.name).sort();
|
|
98795
98850
|
}
|
|
98796
98851
|
async function resolveFeatureSpec(name, workdir) {
|
|
@@ -98801,10 +98856,10 @@ async function resolveFeatureSpec(name, workdir) {
|
|
|
98801
98856
|
message: `not a nax repo: no .nax/config.json found from ${workdir}`
|
|
98802
98857
|
};
|
|
98803
98858
|
}
|
|
98804
|
-
const repoRoot =
|
|
98859
|
+
const repoRoot = join70(naxDir, "..");
|
|
98805
98860
|
if (name !== undefined && (name.startsWith("./") || name.startsWith("/") || name.endsWith(".md"))) {
|
|
98806
|
-
const abs = name.startsWith("/") ? name :
|
|
98807
|
-
if (!
|
|
98861
|
+
const abs = name.startsWith("/") ? name : join70(workdir, name);
|
|
98862
|
+
if (!existsSync28(abs)) {
|
|
98808
98863
|
return {
|
|
98809
98864
|
status: "missing",
|
|
98810
98865
|
featureName: null,
|
|
@@ -98826,8 +98881,8 @@ async function resolveFeatureSpec(name, workdir) {
|
|
|
98826
98881
|
return {
|
|
98827
98882
|
status: "ok",
|
|
98828
98883
|
featureName: null,
|
|
98829
|
-
specSource: { kind: "markdown", path:
|
|
98830
|
-
message: `resolved spec: ${
|
|
98884
|
+
specSource: { kind: "markdown", path: relative15(repoRoot, abs) },
|
|
98885
|
+
message: `resolved spec: ${relative15(repoRoot, abs)}`
|
|
98831
98886
|
};
|
|
98832
98887
|
}
|
|
98833
98888
|
if (name !== undefined && name.trim() !== "") {
|
|
@@ -98838,11 +98893,12 @@ async function resolveFeatureSpec(name, workdir) {
|
|
|
98838
98893
|
status: "ok",
|
|
98839
98894
|
featureName: name,
|
|
98840
98895
|
specSource: source2,
|
|
98896
|
+
acceptance: await resolveFeatureAcceptance(name, workdir),
|
|
98841
98897
|
message: `resolved spec: ${source2.path}`
|
|
98842
98898
|
};
|
|
98843
98899
|
}
|
|
98844
|
-
const featureDir =
|
|
98845
|
-
if (
|
|
98900
|
+
const featureDir = join70(naxDir, "features", name);
|
|
98901
|
+
if (existsSync28(featureDir)) {
|
|
98846
98902
|
return {
|
|
98847
98903
|
status: "missing",
|
|
98848
98904
|
featureName: name,
|
|
@@ -98883,6 +98939,7 @@ async function resolveFeatureSpec(name, workdir) {
|
|
|
98883
98939
|
status: "ok",
|
|
98884
98940
|
featureName: onlyName,
|
|
98885
98941
|
specSource: source,
|
|
98942
|
+
acceptance: await resolveFeatureAcceptance(onlyName, workdir),
|
|
98886
98943
|
message: `resolved spec: ${source.path}`
|
|
98887
98944
|
};
|
|
98888
98945
|
}
|
|
@@ -98901,7 +98958,7 @@ init_logger2();
|
|
|
98901
98958
|
init_detect2();
|
|
98902
98959
|
init_workspace();
|
|
98903
98960
|
init_common();
|
|
98904
|
-
import { join as
|
|
98961
|
+
import { join as join71 } from "path";
|
|
98905
98962
|
function resolveEffective(detected, configPatterns) {
|
|
98906
98963
|
if (configPatterns !== undefined)
|
|
98907
98964
|
return "config";
|
|
@@ -98986,7 +99043,7 @@ async function detectCommand(options) {
|
|
|
98986
99043
|
const rootDetected = detectionMap[""] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98987
99044
|
const pkgEntries = await Promise.all(packageDirs.map(async (dir) => {
|
|
98988
99045
|
const det = detectionMap[dir] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98989
|
-
const pkgConfigPath =
|
|
99046
|
+
const pkgConfigPath = join71(workdir, ".nax", "mono", dir, "config.json");
|
|
98990
99047
|
const pkgRaw = await loadRawConfig(pkgConfigPath);
|
|
98991
99048
|
const pkgPatterns = deepGet(pkgRaw, TEST_PATTERNS_KEY);
|
|
98992
99049
|
const effective = Array.isArray(pkgPatterns) ? pkgPatterns : undefined;
|
|
@@ -99040,13 +99097,13 @@ async function detectCommand(options) {
|
|
|
99040
99097
|
if (rootDetected.confidence === "empty") {
|
|
99041
99098
|
console.log(source_default.yellow(" root: skipped (empty detection)"));
|
|
99042
99099
|
} else {
|
|
99043
|
-
const rootConfigPath =
|
|
99100
|
+
const rootConfigPath = join71(workdir, ".nax", "config.json");
|
|
99044
99101
|
try {
|
|
99045
99102
|
const status = await applyToConfig(rootConfigPath, rootDetected.patterns, options.force ?? false);
|
|
99046
99103
|
if (status === "skipped") {
|
|
99047
99104
|
console.log(source_default.dim(" root: skipped (testFilePatterns already set; use --force to overwrite)"));
|
|
99048
99105
|
} else {
|
|
99049
|
-
console.log(source_default.green(` root: ${status} \u2192 ${
|
|
99106
|
+
console.log(source_default.green(` root: ${status} \u2192 ${join71(".nax", "config.json")}`));
|
|
99050
99107
|
}
|
|
99051
99108
|
} catch (err) {
|
|
99052
99109
|
console.error(source_default.red(` root: write failed \u2014 ${err.message}`));
|
|
@@ -99059,13 +99116,13 @@ async function detectCommand(options) {
|
|
|
99059
99116
|
console.log(source_default.dim(` ${dir}: skipped (empty detection)`));
|
|
99060
99117
|
continue;
|
|
99061
99118
|
}
|
|
99062
|
-
const pkgConfigPath =
|
|
99119
|
+
const pkgConfigPath = join71(workdir, ".nax", "mono", dir, "config.json");
|
|
99063
99120
|
try {
|
|
99064
99121
|
const status = await applyToConfig(pkgConfigPath, det.patterns, options.force ?? false);
|
|
99065
99122
|
if (status === "skipped") {
|
|
99066
99123
|
console.log(source_default.dim(` ${dir}: skipped (already set)`));
|
|
99067
99124
|
} else {
|
|
99068
|
-
console.log(source_default.green(` ${dir}: ${status} \u2192 ${
|
|
99125
|
+
console.log(source_default.green(` ${dir}: ${status} \u2192 ${join71(".nax", "mono", dir, "config.json")}`));
|
|
99069
99126
|
}
|
|
99070
99127
|
} catch (err) {
|
|
99071
99128
|
console.error(source_default.red(` ${dir}: write failed \u2014 ${err.message}`));
|
|
@@ -99082,20 +99139,20 @@ async function detectCommand(options) {
|
|
|
99082
99139
|
|
|
99083
99140
|
// src/commands/logs.ts
|
|
99084
99141
|
init_common();
|
|
99085
|
-
import { existsSync as
|
|
99086
|
-
import { join as
|
|
99142
|
+
import { existsSync as existsSync30 } from "fs";
|
|
99143
|
+
import { join as join74 } from "path";
|
|
99087
99144
|
|
|
99088
99145
|
// src/commands/logs-formatter.ts
|
|
99089
99146
|
init_source();
|
|
99090
99147
|
init_formatter();
|
|
99091
99148
|
import { readdirSync as readdirSync8 } from "fs";
|
|
99092
|
-
import { join as
|
|
99149
|
+
import { join as join73 } from "path";
|
|
99093
99150
|
|
|
99094
99151
|
// src/commands/logs-reader.ts
|
|
99095
99152
|
init_paths3();
|
|
99096
|
-
import { existsSync as
|
|
99153
|
+
import { existsSync as existsSync29, readdirSync as readdirSync7 } from "fs";
|
|
99097
99154
|
import { readdir as readdir3 } from "fs/promises";
|
|
99098
|
-
import { join as
|
|
99155
|
+
import { join as join72 } from "path";
|
|
99099
99156
|
var _logsReaderDeps = {
|
|
99100
99157
|
getRunsDir
|
|
99101
99158
|
};
|
|
@@ -99109,7 +99166,7 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
99109
99166
|
}
|
|
99110
99167
|
let matched = null;
|
|
99111
99168
|
for (const entry of entries) {
|
|
99112
|
-
const metaPath =
|
|
99169
|
+
const metaPath = join72(runsDir, entry, "meta.json");
|
|
99113
99170
|
try {
|
|
99114
99171
|
const meta3 = await Bun.file(metaPath).json();
|
|
99115
99172
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -99121,7 +99178,7 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
99121
99178
|
if (!matched) {
|
|
99122
99179
|
throw new Error(`Run not found in registry: ${runId}`);
|
|
99123
99180
|
}
|
|
99124
|
-
if (!
|
|
99181
|
+
if (!existsSync29(matched.eventsDir)) {
|
|
99125
99182
|
console.log(`Log directory unavailable for run: ${runId}`);
|
|
99126
99183
|
return null;
|
|
99127
99184
|
}
|
|
@@ -99131,14 +99188,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
99131
99188
|
return null;
|
|
99132
99189
|
}
|
|
99133
99190
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
99134
|
-
return
|
|
99191
|
+
return join72(matched.eventsDir, specificFile ?? files[0]);
|
|
99135
99192
|
}
|
|
99136
99193
|
async function selectRunFile(runsDir) {
|
|
99137
99194
|
const files = readdirSync7(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
99138
99195
|
if (files.length === 0) {
|
|
99139
99196
|
return null;
|
|
99140
99197
|
}
|
|
99141
|
-
return
|
|
99198
|
+
return join72(runsDir, files[0]);
|
|
99142
99199
|
}
|
|
99143
99200
|
async function extractRunSummary(filePath) {
|
|
99144
99201
|
const file3 = Bun.file(filePath);
|
|
@@ -99224,7 +99281,7 @@ Runs:
|
|
|
99224
99281
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
99225
99282
|
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"));
|
|
99226
99283
|
for (const file3 of files) {
|
|
99227
|
-
const filePath =
|
|
99284
|
+
const filePath = join73(runsDir, file3);
|
|
99228
99285
|
const summary = await extractRunSummary(filePath);
|
|
99229
99286
|
const timestamp = file3.replace(".jsonl", "");
|
|
99230
99287
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -99338,7 +99395,7 @@ async function logsCommand(options) {
|
|
|
99338
99395
|
return;
|
|
99339
99396
|
}
|
|
99340
99397
|
const resolved = resolveProject({ dir: options.dir });
|
|
99341
|
-
const naxDir =
|
|
99398
|
+
const naxDir = join74(resolved.projectDir, ".nax");
|
|
99342
99399
|
const configPath = resolved.configPath;
|
|
99343
99400
|
const configFile = Bun.file(configPath);
|
|
99344
99401
|
const config2 = await configFile.json();
|
|
@@ -99346,9 +99403,9 @@ async function logsCommand(options) {
|
|
|
99346
99403
|
if (!featureName) {
|
|
99347
99404
|
throw new Error("No feature specified in config.json");
|
|
99348
99405
|
}
|
|
99349
|
-
const featureDir =
|
|
99350
|
-
const runsDir =
|
|
99351
|
-
if (!
|
|
99406
|
+
const featureDir = join74(naxDir, "features", featureName);
|
|
99407
|
+
const runsDir = join74(featureDir, "runs");
|
|
99408
|
+
if (!existsSync30(runsDir)) {
|
|
99352
99409
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
99353
99410
|
}
|
|
99354
99411
|
if (options.list) {
|
|
@@ -99372,8 +99429,8 @@ init_config();
|
|
|
99372
99429
|
init_prd();
|
|
99373
99430
|
init_precheck();
|
|
99374
99431
|
init_common();
|
|
99375
|
-
import { existsSync as
|
|
99376
|
-
import { join as
|
|
99432
|
+
import { existsSync as existsSync31 } from "fs";
|
|
99433
|
+
import { join as join75 } from "path";
|
|
99377
99434
|
async function precheckCommand(options) {
|
|
99378
99435
|
const resolved = resolveProject({
|
|
99379
99436
|
dir: options.dir,
|
|
@@ -99395,14 +99452,14 @@ async function precheckCommand(options) {
|
|
|
99395
99452
|
process.exit(1);
|
|
99396
99453
|
}
|
|
99397
99454
|
}
|
|
99398
|
-
const naxDir =
|
|
99399
|
-
const featureDir =
|
|
99400
|
-
const prdPath =
|
|
99401
|
-
if (!
|
|
99455
|
+
const naxDir = join75(resolved.projectDir, ".nax");
|
|
99456
|
+
const featureDir = join75(naxDir, "features", featureName);
|
|
99457
|
+
const prdPath = join75(featureDir, "prd.json");
|
|
99458
|
+
if (!existsSync31(featureDir)) {
|
|
99402
99459
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
99403
99460
|
process.exit(1);
|
|
99404
99461
|
}
|
|
99405
|
-
if (!
|
|
99462
|
+
if (!existsSync31(prdPath)) {
|
|
99406
99463
|
console.error(source_default.red(`Missing prd.json for feature: ${featureName}`));
|
|
99407
99464
|
console.error(source_default.dim(`Run: nax plan -f ${featureName} --from spec.md --auto`));
|
|
99408
99465
|
process.exit(EXIT_CODES.INVALID_PRD);
|
|
@@ -99420,7 +99477,7 @@ async function precheckCommand(options) {
|
|
|
99420
99477
|
init_source();
|
|
99421
99478
|
init_paths3();
|
|
99422
99479
|
import { readdir as readdir4 } from "fs/promises";
|
|
99423
|
-
import { join as
|
|
99480
|
+
import { join as join76 } from "path";
|
|
99424
99481
|
var DEFAULT_LIMIT = 20;
|
|
99425
99482
|
var _runsCmdDeps = {
|
|
99426
99483
|
getRunsDir
|
|
@@ -99475,7 +99532,7 @@ async function runsCommand(options = {}) {
|
|
|
99475
99532
|
}
|
|
99476
99533
|
const rows = [];
|
|
99477
99534
|
for (const entry of entries) {
|
|
99478
|
-
const metaPath =
|
|
99535
|
+
const metaPath = join76(runsDir, entry, "meta.json");
|
|
99479
99536
|
let meta3;
|
|
99480
99537
|
try {
|
|
99481
99538
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -99552,7 +99609,7 @@ async function runsCommand(options = {}) {
|
|
|
99552
99609
|
|
|
99553
99610
|
// src/commands/unlock.ts
|
|
99554
99611
|
init_source();
|
|
99555
|
-
import { join as
|
|
99612
|
+
import { join as join77 } from "path";
|
|
99556
99613
|
function isProcessAlive2(pid) {
|
|
99557
99614
|
try {
|
|
99558
99615
|
process.kill(pid, 0);
|
|
@@ -99567,7 +99624,7 @@ function formatLockAge(ageMs) {
|
|
|
99567
99624
|
}
|
|
99568
99625
|
async function unlockCommand(options) {
|
|
99569
99626
|
const workdir = options.dir ?? process.cwd();
|
|
99570
|
-
const lockPath =
|
|
99627
|
+
const lockPath = join77(workdir, "nax.lock");
|
|
99571
99628
|
const lockFile = Bun.file(lockPath);
|
|
99572
99629
|
const exists = await lockFile.exists();
|
|
99573
99630
|
if (!exists) {
|
|
@@ -108077,8 +108134,8 @@ Next: nax generate --package ${options.package}`));
|
|
|
108077
108134
|
}
|
|
108078
108135
|
return;
|
|
108079
108136
|
}
|
|
108080
|
-
const naxDir =
|
|
108081
|
-
if (
|
|
108137
|
+
const naxDir = join91(workdir, ".nax");
|
|
108138
|
+
if (existsSync37(naxDir) && !options.force) {
|
|
108082
108139
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
108083
108140
|
return;
|
|
108084
108141
|
}
|
|
@@ -108106,11 +108163,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
108106
108163
|
}
|
|
108107
108164
|
}
|
|
108108
108165
|
}
|
|
108109
|
-
mkdirSync7(
|
|
108110
|
-
mkdirSync7(
|
|
108166
|
+
mkdirSync7(join91(naxDir, "features"), { recursive: true });
|
|
108167
|
+
mkdirSync7(join91(naxDir, "hooks"), { recursive: true });
|
|
108111
108168
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
108112
|
-
await Bun.write(
|
|
108113
|
-
await Bun.write(
|
|
108169
|
+
await Bun.write(join91(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
|
|
108170
|
+
await Bun.write(join91(naxDir, "hooks.json"), JSON.stringify({
|
|
108114
108171
|
hooks: {
|
|
108115
108172
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
108116
108173
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -108118,12 +108175,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
108118
108175
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
108119
108176
|
}
|
|
108120
108177
|
}, null, 2));
|
|
108121
|
-
await Bun.write(
|
|
108178
|
+
await Bun.write(join91(naxDir, ".gitignore"), `# nax temp files
|
|
108122
108179
|
*.tmp
|
|
108123
108180
|
.paused.json
|
|
108124
108181
|
.nax-verifier-verdict.json
|
|
108125
108182
|
`);
|
|
108126
|
-
await Bun.write(
|
|
108183
|
+
await Bun.write(join91(naxDir, "context.md"), `# Project Context
|
|
108127
108184
|
|
|
108128
108185
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
108129
108186
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -108238,7 +108295,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108238
108295
|
console.error(source_default.red("Error: --plan requires --from <spec-path>"));
|
|
108239
108296
|
process.exit(1);
|
|
108240
108297
|
}
|
|
108241
|
-
if (options.from && !
|
|
108298
|
+
if (options.from && !existsSync37(options.from)) {
|
|
108242
108299
|
console.error(source_default.red(`Error: File not found: ${options.from} (required with --plan)`));
|
|
108243
108300
|
process.exit(1);
|
|
108244
108301
|
}
|
|
@@ -108265,7 +108322,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108265
108322
|
const cliOverrides = {};
|
|
108266
108323
|
const cliProfiles = options.profile ?? [];
|
|
108267
108324
|
const profileOverride = naxDir ? await resolveRunProfileOverride({
|
|
108268
|
-
prdPath:
|
|
108325
|
+
prdPath: join91(naxDir, "features", options.feature, "prd.json"),
|
|
108269
108326
|
projectRoot: workdir,
|
|
108270
108327
|
cliProfile: cliProfiles,
|
|
108271
108328
|
envProfile: process.env.NAX_PROFILE
|
|
@@ -108278,10 +108335,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108278
108335
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
108279
108336
|
process.exit(1);
|
|
108280
108337
|
}
|
|
108281
|
-
const featureDir =
|
|
108282
|
-
const prdPath =
|
|
108338
|
+
const featureDir = join91(naxDir, "features", options.feature);
|
|
108339
|
+
const prdPath = join91(featureDir, "prd.json");
|
|
108283
108340
|
if (options.plan && options.from) {
|
|
108284
|
-
if (
|
|
108341
|
+
if (existsSync37(prdPath) && !options.force) {
|
|
108285
108342
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
108286
108343
|
console.error(source_default.dim(" Use --force to overwrite, or run without --plan to use the existing PRD."));
|
|
108287
108344
|
process.exit(1);
|
|
@@ -108301,10 +108358,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108301
108358
|
}
|
|
108302
108359
|
}
|
|
108303
108360
|
try {
|
|
108304
|
-
const planLogDir =
|
|
108361
|
+
const planLogDir = join91(featureDir, "plan");
|
|
108305
108362
|
mkdirSync7(planLogDir, { recursive: true });
|
|
108306
108363
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
108307
|
-
const planLogPath =
|
|
108364
|
+
const planLogPath = join91(planLogDir, `${planLogId}.jsonl`);
|
|
108308
108365
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
108309
108366
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
108310
108367
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -108343,17 +108400,17 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108343
108400
|
process.exit(1);
|
|
108344
108401
|
}
|
|
108345
108402
|
}
|
|
108346
|
-
if (!
|
|
108403
|
+
if (!existsSync37(prdPath)) {
|
|
108347
108404
|
console.error(source_default.red(`Feature "${options.feature}" not found or missing prd.json`));
|
|
108348
108405
|
process.exit(1);
|
|
108349
108406
|
}
|
|
108350
108407
|
resetLogger();
|
|
108351
108408
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
108352
108409
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
108353
|
-
const runsDir =
|
|
108410
|
+
const runsDir = join91(outputDir, "features", options.feature, "runs");
|
|
108354
108411
|
mkdirSync7(runsDir, { recursive: true });
|
|
108355
108412
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
108356
|
-
const logFilePath =
|
|
108413
|
+
const logFilePath = join91(runsDir, `${runId}.jsonl`);
|
|
108357
108414
|
const isTTY = process.stdout.isTTY ?? false;
|
|
108358
108415
|
const headlessFlag = options.headless ?? false;
|
|
108359
108416
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -108371,7 +108428,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108371
108428
|
config2.agent.default = options.agent;
|
|
108372
108429
|
}
|
|
108373
108430
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
108374
|
-
const globalNaxDir =
|
|
108431
|
+
const globalNaxDir = join91(homedir3(), ".nax");
|
|
108375
108432
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
108376
108433
|
const eventEmitter = new PipelineEventEmitter;
|
|
108377
108434
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -108391,12 +108448,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108391
108448
|
events: eventEmitter,
|
|
108392
108449
|
ptyOptions: null,
|
|
108393
108450
|
agentStreamEvents,
|
|
108394
|
-
queueFilePath:
|
|
108451
|
+
queueFilePath: join91(workdir, ".queue.txt")
|
|
108395
108452
|
});
|
|
108396
108453
|
} else {
|
|
108397
108454
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
108398
108455
|
}
|
|
108399
|
-
const statusFilePath =
|
|
108456
|
+
const statusFilePath = join91(outputDir, "status.json");
|
|
108400
108457
|
let parallel;
|
|
108401
108458
|
if (options.parallel !== undefined) {
|
|
108402
108459
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -108423,9 +108480,9 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
108423
108480
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
108424
108481
|
agentStreamEvents
|
|
108425
108482
|
});
|
|
108426
|
-
const latestSymlink =
|
|
108483
|
+
const latestSymlink = join91(runsDir, "latest.jsonl");
|
|
108427
108484
|
try {
|
|
108428
|
-
if (
|
|
108485
|
+
if (existsSync37(latestSymlink)) {
|
|
108429
108486
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
108430
108487
|
}
|
|
108431
108488
|
Bun.spawnSync(["ln", "-s", `${runId}.jsonl`, latestSymlink], {
|
|
@@ -108520,9 +108577,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
108520
108577
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
108521
108578
|
process.exit(1);
|
|
108522
108579
|
}
|
|
108523
|
-
const featureDir =
|
|
108580
|
+
const featureDir = join91(naxDir, "features", name);
|
|
108524
108581
|
mkdirSync7(featureDir, { recursive: true });
|
|
108525
|
-
await Bun.write(
|
|
108582
|
+
await Bun.write(join91(featureDir, "spec.md"), `# Feature: ${name}
|
|
108526
108583
|
|
|
108527
108584
|
## Overview
|
|
108528
108585
|
|
|
@@ -108555,7 +108612,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
108555
108612
|
|
|
108556
108613
|
<!-- What this feature explicitly does NOT cover. -->
|
|
108557
108614
|
`);
|
|
108558
|
-
await Bun.write(
|
|
108615
|
+
await Bun.write(join91(featureDir, "progress.txt"), `# Progress: ${name}
|
|
108559
108616
|
|
|
108560
108617
|
Created: ${new Date().toISOString()}
|
|
108561
108618
|
|
|
@@ -108581,8 +108638,8 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
108581
108638
|
console.error(source_default.red("nax not initialized."));
|
|
108582
108639
|
process.exit(1);
|
|
108583
108640
|
}
|
|
108584
|
-
const featuresDir =
|
|
108585
|
-
if (!
|
|
108641
|
+
const featuresDir = join91(naxDir, "features");
|
|
108642
|
+
if (!existsSync37(featuresDir)) {
|
|
108586
108643
|
console.log(source_default.dim("No features yet."));
|
|
108587
108644
|
return;
|
|
108588
108645
|
}
|
|
@@ -108596,8 +108653,8 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
108596
108653
|
Features:
|
|
108597
108654
|
`));
|
|
108598
108655
|
for (const name of entries) {
|
|
108599
|
-
const prdPath =
|
|
108600
|
-
if (
|
|
108656
|
+
const prdPath = join91(featuresDir, name, "prd.json");
|
|
108657
|
+
if (existsSync37(prdPath)) {
|
|
108601
108658
|
const prd = await loadPRD(prdPath);
|
|
108602
108659
|
const c = countStories(prd);
|
|
108603
108660
|
console.log(` ${name} \u2014 ${c.passed}/${c.total} stories done`);
|
|
@@ -108669,10 +108726,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
108669
108726
|
cliOverrides.profile = cliProfiles;
|
|
108670
108727
|
}
|
|
108671
108728
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
108672
|
-
const featureLogDir =
|
|
108729
|
+
const featureLogDir = join91(naxDir, "features", options.feature, "plan");
|
|
108673
108730
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
108674
108731
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
108675
|
-
const planLogPath =
|
|
108732
|
+
const planLogPath = join91(featureLogDir, `${planLogId}.jsonl`);
|
|
108676
108733
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
108677
108734
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
108678
108735
|
try {
|