@nathapp/nax 0.70.0 → 0.70.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 +695 -466
- package/package.json +6 -2
package/dist/nax.js
CHANGED
|
@@ -17277,9 +17277,13 @@ var init_schemas_review = __esm(() => {
|
|
|
17277
17277
|
}).optional(),
|
|
17278
17278
|
nonBlockingFix: exports_external.object({
|
|
17279
17279
|
enabled: exports_external.boolean().default(false),
|
|
17280
|
-
scope: exports_external.enum(["source", "both"]).default("both"),
|
|
17280
|
+
scope: exports_external.enum(["source", "both", "triage"]).default("both"),
|
|
17281
17281
|
regressionAttempts: exports_external.number().int().min(0).default(1),
|
|
17282
|
-
verifierGuard: exports_external.boolean().default(true)
|
|
17282
|
+
verifierGuard: exports_external.boolean().default(true),
|
|
17283
|
+
sourceDiffCap: exports_external.object({
|
|
17284
|
+
maxFiles: exports_external.number().int().min(0).default(10),
|
|
17285
|
+
maxLines: exports_external.number().int().min(0).default(500)
|
|
17286
|
+
}).optional().default({ maxFiles: 10, maxLines: 500 })
|
|
17283
17287
|
}).optional()
|
|
17284
17288
|
});
|
|
17285
17289
|
ReviewConfigSchema = exports_external.object({
|
|
@@ -17733,7 +17737,7 @@ var init_schema = __esm(() => {
|
|
|
17733
17737
|
init_defaults();
|
|
17734
17738
|
});
|
|
17735
17739
|
|
|
17736
|
-
// src/
|
|
17740
|
+
// src/log-format/types.ts
|
|
17737
17741
|
var EMOJI;
|
|
17738
17742
|
var init_types2 = __esm(() => {
|
|
17739
17743
|
EMOJI = {
|
|
@@ -17755,7 +17759,7 @@ var init_types2 = __esm(() => {
|
|
|
17755
17759
|
};
|
|
17756
17760
|
});
|
|
17757
17761
|
|
|
17758
|
-
// src/
|
|
17762
|
+
// src/log-format/formatter.ts
|
|
17759
17763
|
function formatTimestamp(isoTimestamp) {
|
|
17760
17764
|
const date5 = new Date(isoTimestamp);
|
|
17761
17765
|
return date5.toLocaleTimeString("en-US", {
|
|
@@ -18068,8 +18072,8 @@ var init_formatter = __esm(() => {
|
|
|
18068
18072
|
];
|
|
18069
18073
|
});
|
|
18070
18074
|
|
|
18071
|
-
// src/
|
|
18072
|
-
var
|
|
18075
|
+
// src/log-format/index.ts
|
|
18076
|
+
var init_log_format = __esm(() => {
|
|
18073
18077
|
init_formatter();
|
|
18074
18078
|
init_types2();
|
|
18075
18079
|
});
|
|
@@ -18306,7 +18310,7 @@ function resetLogger() {
|
|
|
18306
18310
|
}
|
|
18307
18311
|
var LOG_LEVEL_PRIORITY, instance = null, noopLogger;
|
|
18308
18312
|
var init_logger = __esm(() => {
|
|
18309
|
-
|
|
18313
|
+
init_log_format();
|
|
18310
18314
|
init_formatters();
|
|
18311
18315
|
init_redact();
|
|
18312
18316
|
LOG_LEVEL_PRIORITY = {
|
|
@@ -18959,6 +18963,19 @@ function rejectLegacyRectificationKeys(conf) {
|
|
|
18959
18963
|
`);
|
|
18960
18964
|
throw new NaxError(message, "CONFIG_LEGACY_RECTIFICATION_KEYS", { stage: "config", legacyKeys });
|
|
18961
18965
|
}
|
|
18966
|
+
function rejectUnimplementedScopedProfile(conf) {
|
|
18967
|
+
const execution = conf.execution;
|
|
18968
|
+
if (execution?.permissionProfile !== "scoped")
|
|
18969
|
+
return;
|
|
18970
|
+
const message = [
|
|
18971
|
+
'Invalid configuration \u2014 execution.permissionProfile: "scoped" is not yet implemented.',
|
|
18972
|
+
"The scoped (per-stage tool allowlist) profile is tracked by GitHub #374 and would",
|
|
18973
|
+
'otherwise silently run as "safe", giving you weaker permissions than intended.',
|
|
18974
|
+
'Use "unrestricted" or "safe" for now.'
|
|
18975
|
+
].join(`
|
|
18976
|
+
`);
|
|
18977
|
+
throw new NaxError(message, "CONFIG_SCOPED_PROFILE_UNIMPLEMENTED", { stage: "config" });
|
|
18978
|
+
}
|
|
18962
18979
|
function applyBatchModeCompat(conf) {
|
|
18963
18980
|
const routing = conf.routing;
|
|
18964
18981
|
const llm = routing?.llm;
|
|
@@ -19068,6 +19085,7 @@ async function loadConfig(startDir, cliOverrides) {
|
|
|
19068
19085
|
}
|
|
19069
19086
|
rejectLegacyAgentKeys(rawConfig);
|
|
19070
19087
|
rejectLegacyRectificationKeys(rawConfig);
|
|
19088
|
+
rejectUnimplementedScopedProfile(rawConfig);
|
|
19071
19089
|
const result = NaxConfigSchema.safeParse(rawConfig);
|
|
19072
19090
|
if (!result.success) {
|
|
19073
19091
|
const errors3 = result.error.issues.map((err) => {
|
|
@@ -19137,6 +19155,7 @@ async function loadConfigForWorkdir(rootConfigPath, packageDir, cliOverrides) {
|
|
|
19137
19155
|
rawMerged.profileChain = packageChain;
|
|
19138
19156
|
rejectLegacyAgentKeys(rawMerged);
|
|
19139
19157
|
rejectLegacyRectificationKeys(rawMerged);
|
|
19158
|
+
rejectUnimplementedScopedProfile(rawMerged);
|
|
19140
19159
|
const result = NaxConfigSchema.safeParse(rawMerged);
|
|
19141
19160
|
if (!result.success) {
|
|
19142
19161
|
const errors3 = result.error.issues.map((err) => {
|
|
@@ -32581,6 +32600,14 @@ var init_ac_structural_counterfactual = __esm(() => {
|
|
|
32581
32600
|
BLOCKING_CATEGORIES = new Set(["input", "error-path", "abandonment", "assumption"]);
|
|
32582
32601
|
});
|
|
32583
32602
|
|
|
32603
|
+
// src/review/category-fix-target.ts
|
|
32604
|
+
function categoryToFixTarget(category) {
|
|
32605
|
+
return category != null && BLOCKING_CATEGORIES.has(category) ? "source" : "test";
|
|
32606
|
+
}
|
|
32607
|
+
var init_category_fix_target = __esm(() => {
|
|
32608
|
+
init_ac_structural_counterfactual();
|
|
32609
|
+
});
|
|
32610
|
+
|
|
32584
32611
|
// src/review/severity.ts
|
|
32585
32612
|
function isBlockingSeverity(sev, threshold = "error") {
|
|
32586
32613
|
return (SEVERITY_RANK[sev] ?? 0) >= SEVERITY_RANK[threshold];
|
|
@@ -32637,12 +32664,13 @@ function toAdversarialReviewFindings(findings) {
|
|
|
32637
32664
|
line: f.line,
|
|
32638
32665
|
message: f.issue,
|
|
32639
32666
|
suggestion: f.suggestion,
|
|
32640
|
-
fixTarget: f.category
|
|
32667
|
+
fixTarget: categoryToFixTarget(f.category),
|
|
32641
32668
|
meta: Object.keys(metaExtras).length > 0 ? metaExtras : undefined
|
|
32642
32669
|
};
|
|
32643
32670
|
});
|
|
32644
32671
|
}
|
|
32645
32672
|
var init_adversarial_helpers = __esm(() => {
|
|
32673
|
+
init_category_fix_target();
|
|
32646
32674
|
init_severity();
|
|
32647
32675
|
});
|
|
32648
32676
|
|
|
@@ -33448,9 +33476,16 @@ function buildMeta(f, originalSeverity) {
|
|
|
33448
33476
|
function findingCategory(f) {
|
|
33449
33477
|
return "category" in f && f.category ? f.category : undefined;
|
|
33450
33478
|
}
|
|
33479
|
+
function deriveFixTargetForReviewFinding(category, source) {
|
|
33480
|
+
if (source === "semantic-review" || source === "semantic-debate-review") {
|
|
33481
|
+
return "source";
|
|
33482
|
+
}
|
|
33483
|
+
return categoryToFixTarget(category);
|
|
33484
|
+
}
|
|
33451
33485
|
function llmFindingToReviewFinding(f, opts = {}) {
|
|
33452
33486
|
const category = findingCategory(f);
|
|
33453
33487
|
const narrowed = narrowSeverity(f.severity);
|
|
33488
|
+
const source = opts.source;
|
|
33454
33489
|
const result = {
|
|
33455
33490
|
ruleId: deriveRuleId(category, f.issue),
|
|
33456
33491
|
severity: narrowed,
|
|
@@ -33460,8 +33495,9 @@ function llmFindingToReviewFinding(f, opts = {}) {
|
|
|
33460
33495
|
};
|
|
33461
33496
|
if (category)
|
|
33462
33497
|
result.category = category;
|
|
33463
|
-
if (
|
|
33464
|
-
result.source =
|
|
33498
|
+
if (source)
|
|
33499
|
+
result.source = source;
|
|
33500
|
+
result.fixTarget = deriveFixTargetForReviewFinding(category, source);
|
|
33465
33501
|
const meta3 = buildMeta(f, f.severity !== narrowed ? f.severity : undefined);
|
|
33466
33502
|
if (meta3)
|
|
33467
33503
|
result.meta = meta3;
|
|
@@ -33472,6 +33508,7 @@ function llmFindingsToReviewFindings(findings, opts = {}) {
|
|
|
33472
33508
|
}
|
|
33473
33509
|
var SEVERITY_MAP, RULE_ID_SLUG_TOKENS = 6;
|
|
33474
33510
|
var init_finding_projection = __esm(() => {
|
|
33511
|
+
init_category_fix_target();
|
|
33475
33512
|
SEVERITY_MAP = {
|
|
33476
33513
|
critical: "critical",
|
|
33477
33514
|
error: "error",
|
|
@@ -39375,9 +39412,10 @@ var init__finding_to_check = __esm(() => {
|
|
|
39375
39412
|
// src/operations/autofix-implementer-strategy.ts
|
|
39376
39413
|
function makeAutofixImplementerStrategy(story, config2, sink, opts = {}) {
|
|
39377
39414
|
const claimsAdversarial = opts.includeAdversarialReview === true;
|
|
39415
|
+
const adversarialReviewByFixTarget = opts.adversarialReviewByFixTarget;
|
|
39378
39416
|
return {
|
|
39379
39417
|
name: "autofix-implementer",
|
|
39380
|
-
appliesTo: (f) => (f.fixTarget === "source" || f.fixTarget == null) && IMPLEMENTER_SOURCES.has(f.source) || claimsAdversarial && f.source === "adversarial-review",
|
|
39418
|
+
appliesTo: (f) => (f.fixTarget === "source" || f.fixTarget == null) && IMPLEMENTER_SOURCES.has(f.source) || adversarialReviewByFixTarget !== undefined && f.source === "adversarial-review" && f.fixTarget === adversarialReviewByFixTarget || adversarialReviewByFixTarget === undefined && claimsAdversarial && f.source === "adversarial-review",
|
|
39381
39419
|
fixOp: implementerRectifyOp,
|
|
39382
39420
|
buildInput: (findings, _prior, _cycleCtx) => ({
|
|
39383
39421
|
failedChecks: findingsToFailedChecks(findings),
|
|
@@ -39409,10 +39447,11 @@ var init_autofix_implementer_strategy = __esm(() => {
|
|
|
39409
39447
|
});
|
|
39410
39448
|
|
|
39411
39449
|
// src/operations/autofix-test-writer-strategy.ts
|
|
39412
|
-
function makeAutofixTestWriterStrategy(story, config2, sink) {
|
|
39450
|
+
function makeAutofixTestWriterStrategy(story, config2, sink, opts = {}) {
|
|
39451
|
+
const includeAdversarial = opts.includeAdversarialReview !== false;
|
|
39413
39452
|
return {
|
|
39414
39453
|
name: "autofix-test-writer",
|
|
39415
|
-
appliesTo: (f) => f.fixTarget === "test" || f.source === "adversarial-review" || sink.mockHandoffs.length > 0,
|
|
39454
|
+
appliesTo: (f) => f.fixTarget === "test" || includeAdversarial && f.source === "adversarial-review" || sink.mockHandoffs.length > 0,
|
|
39416
39455
|
fixOp: testWriterRectifyOp,
|
|
39417
39456
|
buildInput: (findings, _prior, _cycleCtx) => {
|
|
39418
39457
|
if (sink.mockHandoffs.length > 0) {
|
|
@@ -42307,6 +42346,7 @@ var init_runner2 = __esm(() => {
|
|
|
42307
42346
|
// src/review/index.ts
|
|
42308
42347
|
var init_review = __esm(() => {
|
|
42309
42348
|
init_semantic_helpers();
|
|
42349
|
+
init_category_fix_target();
|
|
42310
42350
|
init_ac_quote_validator();
|
|
42311
42351
|
init_ac_structural_counterfactual();
|
|
42312
42352
|
init_adversarial();
|
|
@@ -45251,7 +45291,7 @@ function attachLoggingSubscriber(bus, runId) {
|
|
|
45251
45291
|
offError();
|
|
45252
45292
|
};
|
|
45253
45293
|
}
|
|
45254
|
-
var
|
|
45294
|
+
var init_logging = __esm(() => {
|
|
45255
45295
|
init_logger2();
|
|
45256
45296
|
});
|
|
45257
45297
|
|
|
@@ -45769,7 +45809,7 @@ var init_idle_watchdog = __esm(() => {
|
|
|
45769
45809
|
// src/runtime/middleware/index.ts
|
|
45770
45810
|
var init_middleware = __esm(() => {
|
|
45771
45811
|
init_cancellation();
|
|
45772
|
-
|
|
45812
|
+
init_logging();
|
|
45773
45813
|
init_agent_stream_logging();
|
|
45774
45814
|
init_idle_watchdog();
|
|
45775
45815
|
});
|
|
@@ -54815,6 +54855,26 @@ var init_rollback = __esm(() => {
|
|
|
54815
54855
|
};
|
|
54816
54856
|
});
|
|
54817
54857
|
|
|
54858
|
+
// src/utils/paths.ts
|
|
54859
|
+
import { join as join47, relative as relative13, sep as sep4 } from "path";
|
|
54860
|
+
function packageDirRelative(projectDir, workdir) {
|
|
54861
|
+
if (!projectDir || !workdir || workdir === projectDir)
|
|
54862
|
+
return;
|
|
54863
|
+
const rel = relative13(projectDir, workdir);
|
|
54864
|
+
if (rel === ".." || rel.startsWith(`..${sep4}`))
|
|
54865
|
+
return;
|
|
54866
|
+
return rel && rel !== "." ? rel : undefined;
|
|
54867
|
+
}
|
|
54868
|
+
function getRunsDir() {
|
|
54869
|
+
return process.env.NAX_RUNS_DIR ?? join47(globalConfigDir(), "runs");
|
|
54870
|
+
}
|
|
54871
|
+
function getEventsRootDir() {
|
|
54872
|
+
return join47(globalConfigDir(), "events");
|
|
54873
|
+
}
|
|
54874
|
+
var init_paths3 = __esm(() => {
|
|
54875
|
+
init_paths();
|
|
54876
|
+
});
|
|
54877
|
+
|
|
54818
54878
|
// src/execution/non-blocking-fix.ts
|
|
54819
54879
|
function shouldRunNonBlockingFix(cfg, advisoryCount) {
|
|
54820
54880
|
return cfg?.enabled === true && advisoryCount > 0;
|
|
@@ -54823,9 +54883,42 @@ function nonBlockingExcludePhases() {
|
|
|
54823
54883
|
return REVIEW_PHASE_KINDS;
|
|
54824
54884
|
}
|
|
54825
54885
|
function nonBlockingExtraPhases(cfg) {
|
|
54826
|
-
return cfg.scope === "both" && cfg.verifierGuard ? ["verifier"] : [];
|
|
54886
|
+
return (cfg.scope === "both" || cfg.scope === "triage") && cfg.verifierGuard ? ["verifier"] : [];
|
|
54887
|
+
}
|
|
54888
|
+
function createMeasureSourceDiff(args) {
|
|
54889
|
+
const packageDirRel = packageDirRelative(args.projectDir, args.packageDir);
|
|
54890
|
+
return async (workdir, fromRef) => {
|
|
54891
|
+
const resolved = await _nonBlockingFixDeps.resolveTestFilePatterns(args.config, args.projectDir, packageDirRel);
|
|
54892
|
+
const isTestFile3 = createTestFileClassifier(resolved);
|
|
54893
|
+
const proc = _nonBlockingFixDeps.spawn(["git", "diff", "--numstat", fromRef], {
|
|
54894
|
+
cwd: workdir,
|
|
54895
|
+
stdout: "pipe",
|
|
54896
|
+
stderr: "pipe"
|
|
54897
|
+
});
|
|
54898
|
+
const stdout = await Bun.readableStreamToText(proc.stdout);
|
|
54899
|
+
const stderr = await Bun.readableStreamToText(proc.stderr);
|
|
54900
|
+
const exitCode = await proc.exited;
|
|
54901
|
+
if (exitCode !== 0) {
|
|
54902
|
+
const detail = stderr.trim() || `exit ${exitCode}`;
|
|
54903
|
+
throw new Error(`[non-blocking-fix] git diff --numstat failed: ${detail}`);
|
|
54904
|
+
}
|
|
54905
|
+
let fileCount = 0;
|
|
54906
|
+
let sourceLineCount = 0;
|
|
54907
|
+
for (const line of stdout.trim().split(`
|
|
54908
|
+
`).filter(Boolean)) {
|
|
54909
|
+
const [addedStr, _deletedStr, filePath] = line.split("\t");
|
|
54910
|
+
if (!filePath || isTestFile3(filePath))
|
|
54911
|
+
continue;
|
|
54912
|
+
fileCount += 1;
|
|
54913
|
+
const added = Number.parseInt(addedStr ?? "", 10);
|
|
54914
|
+
if (Number.isFinite(added))
|
|
54915
|
+
sourceLineCount += added;
|
|
54916
|
+
}
|
|
54917
|
+
return { fileCount, sourceLineCount };
|
|
54918
|
+
};
|
|
54827
54919
|
}
|
|
54828
|
-
async function runNonBlockingFix(args,
|
|
54920
|
+
async function runNonBlockingFix(args, overrides = {}) {
|
|
54921
|
+
const _deps = { ...DEFAULT_DEPS, ...overrides };
|
|
54829
54922
|
const logger = getSafeLogger();
|
|
54830
54923
|
if (!shouldRunNonBlockingFix(args.cfg, args.advisoryFindings.length)) {
|
|
54831
54924
|
return { ran: false, kept: false, restored: false };
|
|
@@ -54845,9 +54938,34 @@ async function runNonBlockingFix(args, _deps = DEFAULT_DEPS) {
|
|
|
54845
54938
|
exhausted = true;
|
|
54846
54939
|
}
|
|
54847
54940
|
if (!exhausted) {
|
|
54941
|
+
const cap = args.cfg.sourceDiffCap;
|
|
54942
|
+
if (cap) {
|
|
54943
|
+
let metrics;
|
|
54944
|
+
try {
|
|
54945
|
+
metrics = await _deps.measureSourceDiff(args.workdir, restoreRef);
|
|
54946
|
+
} catch (err) {
|
|
54947
|
+
logger?.warn("non-blocking-fix", "source-diff measurement threw \u2014 restoring", {
|
|
54948
|
+
storyId: args.storyId,
|
|
54949
|
+
error: err instanceof Error ? err.message : String(err)
|
|
54950
|
+
});
|
|
54951
|
+
return restoreToSnapshot(args, _deps, restoreRef, phaseOutputsSnapshot, logger);
|
|
54952
|
+
}
|
|
54953
|
+
if (metrics.fileCount > cap.maxFiles || metrics.sourceLineCount > cap.maxLines) {
|
|
54954
|
+
logger?.info("non-blocking-fix", "source diff exceeded cap \u2014 restoring", {
|
|
54955
|
+
storyId: args.storyId,
|
|
54956
|
+
fileCount: metrics.fileCount,
|
|
54957
|
+
sourceLineCount: metrics.sourceLineCount,
|
|
54958
|
+
cap
|
|
54959
|
+
});
|
|
54960
|
+
return restoreToSnapshot(args, _deps, restoreRef, phaseOutputsSnapshot, logger);
|
|
54961
|
+
}
|
|
54962
|
+
}
|
|
54848
54963
|
logger?.info("non-blocking-fix", "best-effort fix kept", { storyId: args.storyId });
|
|
54849
54964
|
return { ran: true, kept: true, restored: false };
|
|
54850
54965
|
}
|
|
54966
|
+
return restoreToSnapshot(args, _deps, restoreRef, phaseOutputsSnapshot, logger);
|
|
54967
|
+
}
|
|
54968
|
+
async function restoreToSnapshot(args, _deps, restoreRef, phaseOutputsSnapshot, logger) {
|
|
54851
54969
|
await _deps.rollbackToRef(args.workdir, restoreRef);
|
|
54852
54970
|
for (const key of Object.keys(args.phaseOutputs))
|
|
54853
54971
|
delete args.phaseOutputs[key];
|
|
@@ -54857,167 +54975,85 @@ async function runNonBlockingFix(args, _deps = DEFAULT_DEPS) {
|
|
|
54857
54975
|
});
|
|
54858
54976
|
return { ran: true, kept: false, restored: true };
|
|
54859
54977
|
}
|
|
54860
|
-
var REVIEW_PHASE_KINDS, DEFAULT_DEPS;
|
|
54978
|
+
var REVIEW_PHASE_KINDS, _nonBlockingFixDeps, DEFAULT_DEPS;
|
|
54861
54979
|
var init_non_blocking_fix = __esm(() => {
|
|
54862
54980
|
init_logger2();
|
|
54863
54981
|
init_rollback();
|
|
54982
|
+
init_test_runners();
|
|
54983
|
+
init_bun_deps();
|
|
54984
|
+
init_paths3();
|
|
54864
54985
|
REVIEW_PHASE_KINDS = ["semantic-review", "adversarial-review"];
|
|
54865
|
-
|
|
54986
|
+
_nonBlockingFixDeps = {
|
|
54987
|
+
spawn: typedSpawn,
|
|
54988
|
+
resolveTestFilePatterns
|
|
54989
|
+
};
|
|
54990
|
+
DEFAULT_DEPS = {
|
|
54991
|
+
captureSnapshotRef,
|
|
54992
|
+
rollbackToRef,
|
|
54993
|
+
measureSourceDiff: async () => ({ fileCount: 0, sourceLineCount: 0 })
|
|
54994
|
+
};
|
|
54866
54995
|
});
|
|
54867
54996
|
|
|
54868
|
-
// src/execution/story-orchestrator
|
|
54869
|
-
|
|
54870
|
-
|
|
54871
|
-
|
|
54872
|
-
|
|
54873
|
-
|
|
54874
|
-
|
|
54875
|
-
|
|
54876
|
-
|
|
54877
|
-
|
|
54878
|
-
|
|
54879
|
-
|
|
54880
|
-
|
|
54881
|
-
|
|
54882
|
-
|
|
54883
|
-
|
|
54884
|
-
|
|
54885
|
-
|
|
54886
|
-
|
|
54887
|
-
|
|
54888
|
-
|
|
54889
|
-
|
|
54890
|
-
|
|
54891
|
-
|
|
54892
|
-
|
|
54893
|
-
|
|
54894
|
-
|
|
54895
|
-
|
|
54896
|
-
|
|
54897
|
-
|
|
54898
|
-
|
|
54899
|
-
|
|
54900
|
-
|
|
54901
|
-
|
|
54902
|
-
|
|
54903
|
-
|
|
54904
|
-
|
|
54905
|
-
|
|
54906
|
-
|
|
54907
|
-
|
|
54908
|
-
|
|
54909
|
-
|
|
54910
|
-
|
|
54911
|
-
|
|
54912
|
-
|
|
54913
|
-
|
|
54914
|
-
|
|
54915
|
-
|
|
54916
|
-
|
|
54917
|
-
|
|
54918
|
-
|
|
54919
|
-
|
|
54920
|
-
|
|
54921
|
-
|
|
54922
|
-
|
|
54923
|
-
|
|
54997
|
+
// src/execution/story-orchestrator/types.ts
|
|
54998
|
+
var EXHAUSTED_EXIT_REASONS, TDD_OP_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY, STRATEGY_TO_REVALIDATION_PHASES, STRICT_VERDICT_PHASE_NAMES;
|
|
54999
|
+
var init_types9 = __esm(() => {
|
|
55000
|
+
EXHAUSTED_EXIT_REASONS = new Set([
|
|
55001
|
+
"max-attempts-total",
|
|
55002
|
+
"max-attempts-per-strategy",
|
|
55003
|
+
"bail-when",
|
|
55004
|
+
"no-strategy",
|
|
55005
|
+
"agent-gave-up",
|
|
55006
|
+
"validate-short-circuit"
|
|
55007
|
+
]);
|
|
55008
|
+
TDD_OP_NAMES = new Set(["test-writer", "implementer", "verifier"]);
|
|
55009
|
+
CANONICAL_ORDER = [
|
|
55010
|
+
"test-writer",
|
|
55011
|
+
"greenfield-gate",
|
|
55012
|
+
"implementer",
|
|
55013
|
+
"full-suite-gate",
|
|
55014
|
+
"verifier",
|
|
55015
|
+
"verify-scoped",
|
|
55016
|
+
"lint-check",
|
|
55017
|
+
"typecheck-check",
|
|
55018
|
+
"semantic-review",
|
|
55019
|
+
"adversarial-review"
|
|
55020
|
+
];
|
|
55021
|
+
PHASE_KIND_TO_STATE_KEY = {
|
|
55022
|
+
"test-writer": "testWriter",
|
|
55023
|
+
"greenfield-gate": "greenfieldGate",
|
|
55024
|
+
implementer: "implementer",
|
|
55025
|
+
"full-suite-gate": "fullSuiteGate",
|
|
55026
|
+
verifier: "verifier",
|
|
55027
|
+
"verify-scoped": "verifyScoped",
|
|
55028
|
+
"lint-check": "lintCheck",
|
|
55029
|
+
"typecheck-check": "typecheckCheck",
|
|
55030
|
+
"semantic-review": "semanticReview",
|
|
55031
|
+
"adversarial-review": "adversarialReview"
|
|
55032
|
+
};
|
|
55033
|
+
STRATEGY_TO_REVALIDATION_PHASES = {
|
|
55034
|
+
"mechanical-lintfix": ["lint-check"],
|
|
55035
|
+
"mechanical-formatfix": ["lint-check"],
|
|
55036
|
+
"autofix-implementer": ["lint-check", "typecheck-check", "full-suite-gate", "semantic-review", "adversarial-review"],
|
|
55037
|
+
"autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "adversarial-review"],
|
|
55038
|
+
"full-suite-rectify": [
|
|
55039
|
+
"lint-check",
|
|
55040
|
+
"typecheck-check",
|
|
55041
|
+
"full-suite-gate",
|
|
55042
|
+
"verifier",
|
|
55043
|
+
"verify-scoped",
|
|
55044
|
+
"semantic-review"
|
|
55045
|
+
]
|
|
55046
|
+
};
|
|
55047
|
+
STRICT_VERDICT_PHASE_NAMES = new Set([
|
|
55048
|
+
"full-suite-gate",
|
|
55049
|
+
"verify-scoped",
|
|
55050
|
+
"lint-check",
|
|
55051
|
+
"typecheck-check",
|
|
55052
|
+
"verifier"
|
|
55053
|
+
]);
|
|
54924
55054
|
});
|
|
54925
55055
|
|
|
54926
|
-
// src/execution/story-orchestrator.ts
|
|
54927
|
-
async function refreshReviewInputForDispatch(opName, input) {
|
|
54928
|
-
if (opName !== "semantic-review" && opName !== "adversarial-review")
|
|
54929
|
-
return input;
|
|
54930
|
-
const i = input;
|
|
54931
|
-
const { _refresh } = i;
|
|
54932
|
-
if (!_refresh || !i.workdir)
|
|
54933
|
-
return input;
|
|
54934
|
-
try {
|
|
54935
|
-
if (opName === "semantic-review") {
|
|
54936
|
-
const { _refresh: _, ...semInput } = input;
|
|
54937
|
-
const fresh2 = await _storyOrchestratorDeps.prepareSemanticReviewInput({
|
|
54938
|
-
workdir: semInput.workdir,
|
|
54939
|
-
projectDir: _refresh.projectDir,
|
|
54940
|
-
storyId: _refresh.storyId,
|
|
54941
|
-
storyGitRef: _refresh.storyGitRef,
|
|
54942
|
-
config: _refresh.config,
|
|
54943
|
-
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
54944
|
-
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
54945
|
-
semanticConfig: semInput.semanticConfig
|
|
54946
|
-
});
|
|
54947
|
-
return {
|
|
54948
|
-
...semInput,
|
|
54949
|
-
stat: fresh2.stat,
|
|
54950
|
-
diff: fresh2.diff,
|
|
54951
|
-
excludePatterns: fresh2.excludePatterns,
|
|
54952
|
-
storyGitRef: fresh2.effectiveRef ?? semInput.storyGitRef
|
|
54953
|
-
};
|
|
54954
|
-
}
|
|
54955
|
-
const { _refresh: __, ...advInput } = input;
|
|
54956
|
-
const fresh = await _storyOrchestratorDeps.prepareAdversarialReviewInput({
|
|
54957
|
-
workdir: advInput.workdir,
|
|
54958
|
-
projectDir: _refresh.projectDir,
|
|
54959
|
-
storyId: _refresh.storyId,
|
|
54960
|
-
storyGitRef: _refresh.storyGitRef,
|
|
54961
|
-
config: _refresh.config,
|
|
54962
|
-
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
54963
|
-
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
54964
|
-
adversarialConfig: advInput.adversarialConfig
|
|
54965
|
-
});
|
|
54966
|
-
return {
|
|
54967
|
-
...advInput,
|
|
54968
|
-
stat: fresh.stat,
|
|
54969
|
-
diff: fresh.diff,
|
|
54970
|
-
testInventory: fresh.testInventory,
|
|
54971
|
-
excludePatterns: fresh.excludePatterns,
|
|
54972
|
-
testGlobs: fresh.testGlobs,
|
|
54973
|
-
refExcludePatterns: fresh.refExcludePatterns,
|
|
54974
|
-
storyGitRef: fresh.effectiveRef ?? advInput.storyGitRef
|
|
54975
|
-
};
|
|
54976
|
-
} catch (err) {
|
|
54977
|
-
getSafeLogger()?.warn("story-orchestrator", "review input refresh failed \u2014 dispatching with stale input", {
|
|
54978
|
-
storyId: _refresh.storyId,
|
|
54979
|
-
phase: opName,
|
|
54980
|
-
error: errorMessage(err)
|
|
54981
|
-
});
|
|
54982
|
-
const { _refresh: _stripped, ...fallback } = input;
|
|
54983
|
-
return fallback;
|
|
54984
|
-
}
|
|
54985
|
-
}
|
|
54986
|
-
function isSlot(value) {
|
|
54987
|
-
return value !== null && typeof value === "object" && "op" in value && "input" in value && typeof value.op?.kind === "string";
|
|
54988
|
-
}
|
|
54989
|
-
function setPhase(state, kind, slot) {
|
|
54990
|
-
const key = PHASE_KIND_TO_STATE_KEY[kind];
|
|
54991
|
-
if (state[key] !== undefined) {
|
|
54992
|
-
throw new NaxError(`StoryOrchestratorBuilder: addX was called twice for phase "${kind}"`, "ORCHESTRATOR_PHASE_DUPLICATE", { stage: "execution", kind });
|
|
54993
|
-
}
|
|
54994
|
-
state[key] = { kind, slot };
|
|
54995
|
-
}
|
|
54996
|
-
function collectOrderedPhases(state) {
|
|
54997
|
-
return CANONICAL_ORDER.flatMap((kind) => {
|
|
54998
|
-
if (kind === "test-writer" && state.testWriter)
|
|
54999
|
-
return [state.testWriter];
|
|
55000
|
-
if (kind === "greenfield-gate" && state.greenfieldGate)
|
|
55001
|
-
return [state.greenfieldGate];
|
|
55002
|
-
if (kind === "implementer" && state.implementer)
|
|
55003
|
-
return [state.implementer];
|
|
55004
|
-
if (kind === "full-suite-gate" && state.fullSuiteGate)
|
|
55005
|
-
return [state.fullSuiteGate];
|
|
55006
|
-
if (kind === "verifier" && state.verifier)
|
|
55007
|
-
return [state.verifier];
|
|
55008
|
-
if (kind === "verify-scoped" && state.verifyScoped)
|
|
55009
|
-
return [state.verifyScoped];
|
|
55010
|
-
if (kind === "lint-check" && state.lintCheck)
|
|
55011
|
-
return [state.lintCheck];
|
|
55012
|
-
if (kind === "typecheck-check" && state.typecheckCheck)
|
|
55013
|
-
return [state.typecheckCheck];
|
|
55014
|
-
if (kind === "semantic-review" && state.semanticReview)
|
|
55015
|
-
return [state.semanticReview];
|
|
55016
|
-
if (kind === "adversarial-review" && state.adversarialReview)
|
|
55017
|
-
return [state.adversarialReview];
|
|
55018
|
-
return [];
|
|
55019
|
-
});
|
|
55020
|
-
}
|
|
55056
|
+
// src/execution/story-orchestrator/phase-eval.ts
|
|
55021
55057
|
function phaseExplicitlyPassed(output) {
|
|
55022
55058
|
if (output === null || output === undefined || typeof output !== "object")
|
|
55023
55059
|
return false;
|
|
@@ -55075,34 +55111,6 @@ function gateFailureKeys(gateOutput) {
|
|
|
55075
55111
|
}
|
|
55076
55112
|
return keys;
|
|
55077
55113
|
}
|
|
55078
|
-
function shouldSkipPhaseForRectification(phase, state, phaseOutputs) {
|
|
55079
|
-
if (phase.kind !== "full-suite-gate")
|
|
55080
|
-
return false;
|
|
55081
|
-
const verifierName = state.verifier?.slot.op.name;
|
|
55082
|
-
if (!verifierName)
|
|
55083
|
-
return false;
|
|
55084
|
-
return phaseExplicitlyPassed(phaseOutputs[verifierName]);
|
|
55085
|
-
}
|
|
55086
|
-
function gatherRectificationFindings(phaseOutputs, phases, state) {
|
|
55087
|
-
const findings = [];
|
|
55088
|
-
for (const phase of phases) {
|
|
55089
|
-
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
55090
|
-
continue;
|
|
55091
|
-
findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
|
|
55092
|
-
}
|
|
55093
|
-
return findings;
|
|
55094
|
-
}
|
|
55095
|
-
function collectRectificationPhases(state) {
|
|
55096
|
-
return [
|
|
55097
|
-
state.fullSuiteGate,
|
|
55098
|
-
state.verifier,
|
|
55099
|
-
state.verifyScoped,
|
|
55100
|
-
state.lintCheck,
|
|
55101
|
-
state.typecheckCheck,
|
|
55102
|
-
state.semanticReview,
|
|
55103
|
-
state.adversarialReview
|
|
55104
|
-
].filter((phase) => phase !== undefined);
|
|
55105
|
-
}
|
|
55106
55114
|
function phasesToRevalidate(strategiesRun, allPhases) {
|
|
55107
55115
|
if (!strategiesRun || strategiesRun.length === 0)
|
|
55108
55116
|
return allPhases;
|
|
@@ -55122,6 +55130,111 @@ function orderGateLast(phases) {
|
|
|
55122
55130
|
const gates = phases.filter((p) => p.kind === "full-suite-gate");
|
|
55123
55131
|
return [...rest, ...gates];
|
|
55124
55132
|
}
|
|
55133
|
+
var init_phase_eval = __esm(() => {
|
|
55134
|
+
init_logger2();
|
|
55135
|
+
init_types9();
|
|
55136
|
+
});
|
|
55137
|
+
|
|
55138
|
+
// src/execution/story-orchestrator/phase-state.ts
|
|
55139
|
+
function isSlot(value) {
|
|
55140
|
+
return value !== null && typeof value === "object" && "op" in value && "input" in value && typeof value.op?.kind === "string";
|
|
55141
|
+
}
|
|
55142
|
+
function setPhase(state, kind, slot) {
|
|
55143
|
+
const key = PHASE_KIND_TO_STATE_KEY[kind];
|
|
55144
|
+
if (state[key] !== undefined) {
|
|
55145
|
+
throw new NaxError(`StoryOrchestratorBuilder: addX was called twice for phase "${kind}"`, "ORCHESTRATOR_PHASE_DUPLICATE", { stage: "execution", kind });
|
|
55146
|
+
}
|
|
55147
|
+
state[key] = { kind, slot };
|
|
55148
|
+
}
|
|
55149
|
+
function collectOrderedPhases(state) {
|
|
55150
|
+
return CANONICAL_ORDER.flatMap((kind) => {
|
|
55151
|
+
if (kind === "test-writer" && state.testWriter)
|
|
55152
|
+
return [state.testWriter];
|
|
55153
|
+
if (kind === "greenfield-gate" && state.greenfieldGate)
|
|
55154
|
+
return [state.greenfieldGate];
|
|
55155
|
+
if (kind === "implementer" && state.implementer)
|
|
55156
|
+
return [state.implementer];
|
|
55157
|
+
if (kind === "full-suite-gate" && state.fullSuiteGate)
|
|
55158
|
+
return [state.fullSuiteGate];
|
|
55159
|
+
if (kind === "verifier" && state.verifier)
|
|
55160
|
+
return [state.verifier];
|
|
55161
|
+
if (kind === "verify-scoped" && state.verifyScoped)
|
|
55162
|
+
return [state.verifyScoped];
|
|
55163
|
+
if (kind === "lint-check" && state.lintCheck)
|
|
55164
|
+
return [state.lintCheck];
|
|
55165
|
+
if (kind === "typecheck-check" && state.typecheckCheck)
|
|
55166
|
+
return [state.typecheckCheck];
|
|
55167
|
+
if (kind === "semantic-review" && state.semanticReview)
|
|
55168
|
+
return [state.semanticReview];
|
|
55169
|
+
if (kind === "adversarial-review" && state.adversarialReview)
|
|
55170
|
+
return [state.adversarialReview];
|
|
55171
|
+
return [];
|
|
55172
|
+
});
|
|
55173
|
+
}
|
|
55174
|
+
var init_phase_state = __esm(() => {
|
|
55175
|
+
init_errors();
|
|
55176
|
+
init_types9();
|
|
55177
|
+
});
|
|
55178
|
+
|
|
55179
|
+
// src/execution/story-orchestrator-logging.ts
|
|
55180
|
+
function formatPhaseResultMessage(opName, success2, stage, status) {
|
|
55181
|
+
if (opName === "greenfield-gate") {
|
|
55182
|
+
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";
|
|
55183
|
+
}
|
|
55184
|
+
if (status === "skipped") {
|
|
55185
|
+
return `Phase skipped: ${opName}`;
|
|
55186
|
+
}
|
|
55187
|
+
if (stage === "rectification") {
|
|
55188
|
+
return `Rectification strategy completed: ${opName}`;
|
|
55189
|
+
}
|
|
55190
|
+
return success2 ? `Phase passed: ${opName}` : `Phase failed: ${opName}`;
|
|
55191
|
+
}
|
|
55192
|
+
function buildPhaseOutcomeLogData(storyId, opName, output, durationMs) {
|
|
55193
|
+
if (output === null || output === undefined || typeof output !== "object")
|
|
55194
|
+
return null;
|
|
55195
|
+
const r = output;
|
|
55196
|
+
const success2 = r.success === true || r.passed === true;
|
|
55197
|
+
const findingsCount = Array.isArray(r.normalizedFindings) ? r.normalizedFindings.length : Array.isArray(r.findings) ? r.findings.length : undefined;
|
|
55198
|
+
const status = typeof r.status === "string" ? r.status : undefined;
|
|
55199
|
+
const data = { storyId, phase: opName, durationMs };
|
|
55200
|
+
if (findingsCount !== undefined)
|
|
55201
|
+
data.findingsCount = findingsCount;
|
|
55202
|
+
if (status !== undefined)
|
|
55203
|
+
data.status = status;
|
|
55204
|
+
if (typeof r.failureCategory === "string")
|
|
55205
|
+
data.failureCategory = r.failureCategory;
|
|
55206
|
+
if (typeof r.reviewReason === "string")
|
|
55207
|
+
data.reviewReason = r.reviewReason;
|
|
55208
|
+
return { success: success2, data };
|
|
55209
|
+
}
|
|
55210
|
+
function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTddPhase, stage, progressData = {}) {
|
|
55211
|
+
if (isTddPhase)
|
|
55212
|
+
return;
|
|
55213
|
+
if (opName === "semantic-review" || opName === "adversarial-review")
|
|
55214
|
+
return;
|
|
55215
|
+
const built = buildPhaseOutcomeLogData(storyId, opName, output, durationMs);
|
|
55216
|
+
if (!built)
|
|
55217
|
+
return;
|
|
55218
|
+
const { success: success2 } = built;
|
|
55219
|
+
const data = { ...built.data, ...progressData };
|
|
55220
|
+
const status = typeof built.data.status === "string" ? built.data.status : undefined;
|
|
55221
|
+
const logger = getSafeLogger();
|
|
55222
|
+
const message = formatPhaseResultMessage(opName, success2, stage, status);
|
|
55223
|
+
if (stage === "rectification") {
|
|
55224
|
+
logger?.info("story-orchestrator", message, data);
|
|
55225
|
+
return;
|
|
55226
|
+
}
|
|
55227
|
+
if (success2) {
|
|
55228
|
+
logger?.info("story-orchestrator", message, data);
|
|
55229
|
+
} else {
|
|
55230
|
+
logger?.warn("story-orchestrator", message, data);
|
|
55231
|
+
}
|
|
55232
|
+
}
|
|
55233
|
+
var init_story_orchestrator_logging = __esm(() => {
|
|
55234
|
+
init_logger2();
|
|
55235
|
+
});
|
|
55236
|
+
|
|
55237
|
+
// src/execution/story-orchestrator/review-decision.ts
|
|
55125
55238
|
function toReviewDecisionPayload(opName, output) {
|
|
55126
55239
|
if (output === null || output === undefined || typeof output !== "object")
|
|
55127
55240
|
return null;
|
|
@@ -55237,6 +55350,70 @@ function logUnifiedReviewPhaseResult(storyId, opName, output) {
|
|
|
55237
55350
|
truncated: findingsCount > findingsSummary.length
|
|
55238
55351
|
});
|
|
55239
55352
|
}
|
|
55353
|
+
var init_review_decision = __esm(() => {
|
|
55354
|
+
init_logger2();
|
|
55355
|
+
});
|
|
55356
|
+
|
|
55357
|
+
// src/execution/story-orchestrator/run-phase.ts
|
|
55358
|
+
async function refreshReviewInputForDispatch(opName, input) {
|
|
55359
|
+
if (opName !== "semantic-review" && opName !== "adversarial-review")
|
|
55360
|
+
return input;
|
|
55361
|
+
const i = input;
|
|
55362
|
+
const { _refresh } = i;
|
|
55363
|
+
if (!_refresh || !i.workdir)
|
|
55364
|
+
return input;
|
|
55365
|
+
try {
|
|
55366
|
+
if (opName === "semantic-review") {
|
|
55367
|
+
const { _refresh: _, ...semInput } = input;
|
|
55368
|
+
const fresh2 = await _storyOrchestratorDeps.prepareSemanticReviewInput({
|
|
55369
|
+
workdir: semInput.workdir,
|
|
55370
|
+
projectDir: _refresh.projectDir,
|
|
55371
|
+
storyId: _refresh.storyId,
|
|
55372
|
+
storyGitRef: _refresh.storyGitRef,
|
|
55373
|
+
config: _refresh.config,
|
|
55374
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55375
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55376
|
+
semanticConfig: semInput.semanticConfig
|
|
55377
|
+
});
|
|
55378
|
+
return {
|
|
55379
|
+
...semInput,
|
|
55380
|
+
stat: fresh2.stat,
|
|
55381
|
+
diff: fresh2.diff,
|
|
55382
|
+
excludePatterns: fresh2.excludePatterns,
|
|
55383
|
+
storyGitRef: fresh2.effectiveRef ?? semInput.storyGitRef
|
|
55384
|
+
};
|
|
55385
|
+
}
|
|
55386
|
+
const { _refresh: __, ...advInput } = input;
|
|
55387
|
+
const fresh = await _storyOrchestratorDeps.prepareAdversarialReviewInput({
|
|
55388
|
+
workdir: advInput.workdir,
|
|
55389
|
+
projectDir: _refresh.projectDir,
|
|
55390
|
+
storyId: _refresh.storyId,
|
|
55391
|
+
storyGitRef: _refresh.storyGitRef,
|
|
55392
|
+
config: _refresh.config,
|
|
55393
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55394
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55395
|
+
adversarialConfig: advInput.adversarialConfig
|
|
55396
|
+
});
|
|
55397
|
+
return {
|
|
55398
|
+
...advInput,
|
|
55399
|
+
stat: fresh.stat,
|
|
55400
|
+
diff: fresh.diff,
|
|
55401
|
+
testInventory: fresh.testInventory,
|
|
55402
|
+
excludePatterns: fresh.excludePatterns,
|
|
55403
|
+
testGlobs: fresh.testGlobs,
|
|
55404
|
+
refExcludePatterns: fresh.refExcludePatterns,
|
|
55405
|
+
storyGitRef: fresh.effectiveRef ?? advInput.storyGitRef
|
|
55406
|
+
};
|
|
55407
|
+
} catch (err) {
|
|
55408
|
+
getSafeLogger()?.warn("story-orchestrator", "review input refresh failed \u2014 dispatching with stale input", {
|
|
55409
|
+
storyId: _refresh.storyId,
|
|
55410
|
+
phase: opName,
|
|
55411
|
+
error: errorMessage(err)
|
|
55412
|
+
});
|
|
55413
|
+
const { _refresh: _stripped, ...fallback } = input;
|
|
55414
|
+
return fallback;
|
|
55415
|
+
}
|
|
55416
|
+
}
|
|
55240
55417
|
async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = false, progress) {
|
|
55241
55418
|
const logger = getSafeLogger();
|
|
55242
55419
|
const opName = slot.op.name;
|
|
@@ -55322,6 +55499,57 @@ function withIncreasingFailuresBail(strategies, enabled, consecutiveIncreases) {
|
|
|
55322
55499
|
}
|
|
55323
55500
|
}));
|
|
55324
55501
|
}
|
|
55502
|
+
var _storyOrchestratorDeps;
|
|
55503
|
+
var init_run_phase = __esm(() => {
|
|
55504
|
+
init_findings();
|
|
55505
|
+
init_logger2();
|
|
55506
|
+
init_operations();
|
|
55507
|
+
init_pipeline();
|
|
55508
|
+
init_review();
|
|
55509
|
+
init_git();
|
|
55510
|
+
init_non_blocking_fix();
|
|
55511
|
+
init_story_orchestrator_logging();
|
|
55512
|
+
init_review_decision();
|
|
55513
|
+
init_types9();
|
|
55514
|
+
_storyOrchestratorDeps = {
|
|
55515
|
+
callOp,
|
|
55516
|
+
runFixCycle,
|
|
55517
|
+
captureGitRef,
|
|
55518
|
+
prepareSemanticReviewInput,
|
|
55519
|
+
prepareAdversarialReviewInput,
|
|
55520
|
+
runNonBlockingFix
|
|
55521
|
+
};
|
|
55522
|
+
});
|
|
55523
|
+
|
|
55524
|
+
// src/execution/story-orchestrator/rectification.ts
|
|
55525
|
+
function shouldSkipPhaseForRectification(phase, state, phaseOutputs) {
|
|
55526
|
+
if (phase.kind !== "full-suite-gate")
|
|
55527
|
+
return false;
|
|
55528
|
+
const verifierName = state.verifier?.slot.op.name;
|
|
55529
|
+
if (!verifierName)
|
|
55530
|
+
return false;
|
|
55531
|
+
return phaseExplicitlyPassed(phaseOutputs[verifierName]);
|
|
55532
|
+
}
|
|
55533
|
+
function gatherRectificationFindings(phaseOutputs, phases, state) {
|
|
55534
|
+
const findings = [];
|
|
55535
|
+
for (const phase of phases) {
|
|
55536
|
+
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
55537
|
+
continue;
|
|
55538
|
+
findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
|
|
55539
|
+
}
|
|
55540
|
+
return findings;
|
|
55541
|
+
}
|
|
55542
|
+
function collectRectificationPhases(state) {
|
|
55543
|
+
return [
|
|
55544
|
+
state.fullSuiteGate,
|
|
55545
|
+
state.verifier,
|
|
55546
|
+
state.verifyScoped,
|
|
55547
|
+
state.lintCheck,
|
|
55548
|
+
state.typecheckCheck,
|
|
55549
|
+
state.semanticReview,
|
|
55550
|
+
state.adversarialReview
|
|
55551
|
+
].filter((phase) => phase !== undefined);
|
|
55552
|
+
}
|
|
55325
55553
|
async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides) {
|
|
55326
55554
|
const rectification = state.rectification;
|
|
55327
55555
|
const baseValidationPhases = collectRectificationPhases(state);
|
|
@@ -55419,7 +55647,15 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides)
|
|
|
55419
55647
|
}
|
|
55420
55648
|
return {};
|
|
55421
55649
|
}
|
|
55650
|
+
var init_rectification = __esm(() => {
|
|
55651
|
+
init_logger2();
|
|
55652
|
+
init_phase_eval();
|
|
55653
|
+
init_phase_eval();
|
|
55654
|
+
init_run_phase();
|
|
55655
|
+
init_types9();
|
|
55656
|
+
});
|
|
55422
55657
|
|
|
55658
|
+
// src/execution/story-orchestrator/execution-plan.ts
|
|
55423
55659
|
class ExecutionPlan {
|
|
55424
55660
|
ctx;
|
|
55425
55661
|
state;
|
|
@@ -55542,7 +55778,7 @@ class ExecutionPlan {
|
|
|
55542
55778
|
const advisoryOut = phaseOutputs["adversarial-review"];
|
|
55543
55779
|
const advisoryFindings = advisoryOut?.advisoryFindings ?? [];
|
|
55544
55780
|
if (advCfg && this.state.rectification && this.ctx.storyId && shouldRunNonBlockingFix(advCfg, advisoryFindings.length)) {
|
|
55545
|
-
await runNonBlockingFix({
|
|
55781
|
+
await _storyOrchestratorDeps.runNonBlockingFix({
|
|
55546
55782
|
workdir: this.ctx.packageDir,
|
|
55547
55783
|
storyId: this.ctx.storyId,
|
|
55548
55784
|
advisoryFindings,
|
|
@@ -55556,6 +55792,12 @@ class ExecutionPlan {
|
|
|
55556
55792
|
maxAttempts,
|
|
55557
55793
|
postValidate: this.state.nonBlockingFixPostValidate
|
|
55558
55794
|
})
|
|
55795
|
+
}, {
|
|
55796
|
+
measureSourceDiff: createMeasureSourceDiff({
|
|
55797
|
+
config: this.ctx.runtime.configLoader.current(),
|
|
55798
|
+
projectDir: this.ctx.runtime.projectDir,
|
|
55799
|
+
packageDir: this.ctx.packageDir
|
|
55800
|
+
})
|
|
55559
55801
|
});
|
|
55560
55802
|
}
|
|
55561
55803
|
const verifierName = this.state.verifier?.slot.op.name;
|
|
@@ -55567,18 +55809,29 @@ class ExecutionPlan {
|
|
|
55567
55809
|
} else if (verifierPassedSsot && gateName !== undefined && !phasePassed(gateName, phaseOutputs[gateName], this.ctx.storyId)) {
|
|
55568
55810
|
logger?.warn("story-orchestrator", "Full-suite gate failed but verifier judged story OK \u2014 treating gate failures as unrelated regressions", { storyId: this.ctx.storyId, packageDir: this.ctx.packageDir });
|
|
55569
55811
|
}
|
|
55570
|
-
const
|
|
55812
|
+
const requiredReviewPhaseNames = [
|
|
55813
|
+
this.state.semanticReview?.slot.op.name,
|
|
55814
|
+
this.state.adversarialReview?.slot.op.name
|
|
55815
|
+
].filter((name) => name !== undefined);
|
|
55816
|
+
const missingRequiredReviewPhases = requiredReviewPhaseNames.filter((name) => !(name in phaseOutputs));
|
|
55817
|
+
if (missingRequiredReviewPhases.length > 0) {
|
|
55818
|
+
logger?.warn("story-orchestrator", "Configured review phase(s) never ran \u2014 story cannot pass without review judgment, failing for escalation", { storyId: this.ctx.storyId, packageDir: this.ctx.packageDir, missingRequiredReviewPhases });
|
|
55819
|
+
}
|
|
55820
|
+
const success2 = missingRequiredReviewPhases.length === 0 && Object.entries(phaseOutputs).every(([name, output]) => {
|
|
55571
55821
|
if (verifierPassedSsot && name === gateName)
|
|
55572
55822
|
return true;
|
|
55573
55823
|
return phasePassed(name, output, this.ctx.storyId);
|
|
55574
55824
|
});
|
|
55575
55825
|
const totalCostUsd = Object.values(phaseCosts).reduce((sum, cost) => sum + cost, 0);
|
|
55576
55826
|
const durationMs = Date.now() - startedAt;
|
|
55577
|
-
const failedPhases =
|
|
55578
|
-
|
|
55579
|
-
|
|
55580
|
-
|
|
55581
|
-
|
|
55827
|
+
const failedPhases = [
|
|
55828
|
+
...Object.entries(phaseOutputs).filter(([name, output]) => {
|
|
55829
|
+
if (verifierPassedSsot && name === gateName)
|
|
55830
|
+
return false;
|
|
55831
|
+
return !phasePassed(name, output, this.ctx.storyId);
|
|
55832
|
+
}).map(([name]) => name),
|
|
55833
|
+
...missingRequiredReviewPhases.map((name) => `${name} (never ran)`)
|
|
55834
|
+
];
|
|
55582
55835
|
const summary = {
|
|
55583
55836
|
storyId: this.ctx.storyId,
|
|
55584
55837
|
success: success2,
|
|
@@ -55591,6 +55844,8 @@ class ExecutionPlan {
|
|
|
55591
55844
|
summary.rectificationExhausted = true;
|
|
55592
55845
|
if (rectResult.unfixedFindings)
|
|
55593
55846
|
summary.unfixedFindingsCount = rectResult.unfixedFindings.length;
|
|
55847
|
+
if (missingRequiredReviewPhases.length > 0)
|
|
55848
|
+
summary.missingRequiredReviewPhases = missingRequiredReviewPhases;
|
|
55594
55849
|
if (success2) {
|
|
55595
55850
|
logger?.info("story-orchestrator", "Story orchestration complete", summary);
|
|
55596
55851
|
} else {
|
|
@@ -55603,11 +55858,21 @@ class ExecutionPlan {
|
|
|
55603
55858
|
durationMs,
|
|
55604
55859
|
phaseOutputs,
|
|
55605
55860
|
...rectResult,
|
|
55606
|
-
gateRegressedDuringRect
|
|
55861
|
+
gateRegressedDuringRect,
|
|
55862
|
+
missingRequiredReviewPhases: missingRequiredReviewPhases.length > 0 ? missingRequiredReviewPhases : undefined
|
|
55607
55863
|
};
|
|
55608
55864
|
}
|
|
55609
55865
|
}
|
|
55866
|
+
var init_execution_plan = __esm(() => {
|
|
55867
|
+
init_logger2();
|
|
55868
|
+
init_non_blocking_fix();
|
|
55869
|
+
init_phase_eval();
|
|
55870
|
+
init_phase_state();
|
|
55871
|
+
init_rectification();
|
|
55872
|
+
init_run_phase();
|
|
55873
|
+
});
|
|
55610
55874
|
|
|
55875
|
+
// src/execution/story-orchestrator/builder.ts
|
|
55611
55876
|
class StoryOrchestratorBuilder {
|
|
55612
55877
|
state = {};
|
|
55613
55878
|
addImplementer(value) {
|
|
@@ -55667,83 +55932,25 @@ class StoryOrchestratorBuilder {
|
|
|
55667
55932
|
return new ExecutionPlan(ctx, { ...this.state }, opts.isThreeSession ?? false);
|
|
55668
55933
|
}
|
|
55669
55934
|
}
|
|
55670
|
-
var
|
|
55671
|
-
var init_story_orchestrator = __esm(() => {
|
|
55935
|
+
var init_builder2 = __esm(() => {
|
|
55672
55936
|
init_errors();
|
|
55673
|
-
init_findings();
|
|
55674
|
-
init_logger2();
|
|
55675
55937
|
init_operations();
|
|
55676
|
-
|
|
55677
|
-
|
|
55678
|
-
|
|
55679
|
-
|
|
55680
|
-
|
|
55681
|
-
|
|
55682
|
-
|
|
55683
|
-
|
|
55684
|
-
|
|
55685
|
-
|
|
55686
|
-
|
|
55687
|
-
|
|
55688
|
-
};
|
|
55689
|
-
EXHAUSTED_EXIT_REASONS = new Set([
|
|
55690
|
-
"max-attempts-total",
|
|
55691
|
-
"max-attempts-per-strategy",
|
|
55692
|
-
"bail-when",
|
|
55693
|
-
"no-strategy",
|
|
55694
|
-
"agent-gave-up",
|
|
55695
|
-
"validate-short-circuit"
|
|
55696
|
-
]);
|
|
55697
|
-
TDD_OP_NAMES = new Set(["test-writer", "implementer", "verifier"]);
|
|
55698
|
-
STRICT_VERDICT_PHASE_NAMES = new Set([
|
|
55699
|
-
fullSuiteGateOp.name,
|
|
55700
|
-
verifyScopedOp.name,
|
|
55701
|
-
lintCheckOp.name,
|
|
55702
|
-
typecheckCheckOp.name,
|
|
55703
|
-
verifierOp.name
|
|
55704
|
-
]);
|
|
55705
|
-
CANONICAL_ORDER = [
|
|
55706
|
-
"test-writer",
|
|
55707
|
-
"greenfield-gate",
|
|
55708
|
-
"implementer",
|
|
55709
|
-
"full-suite-gate",
|
|
55710
|
-
"verifier",
|
|
55711
|
-
"verify-scoped",
|
|
55712
|
-
"lint-check",
|
|
55713
|
-
"typecheck-check",
|
|
55714
|
-
"semantic-review",
|
|
55715
|
-
"adversarial-review"
|
|
55716
|
-
];
|
|
55717
|
-
PHASE_KIND_TO_STATE_KEY = {
|
|
55718
|
-
"test-writer": "testWriter",
|
|
55719
|
-
"greenfield-gate": "greenfieldGate",
|
|
55720
|
-
implementer: "implementer",
|
|
55721
|
-
"full-suite-gate": "fullSuiteGate",
|
|
55722
|
-
verifier: "verifier",
|
|
55723
|
-
"verify-scoped": "verifyScoped",
|
|
55724
|
-
"lint-check": "lintCheck",
|
|
55725
|
-
"typecheck-check": "typecheckCheck",
|
|
55726
|
-
"semantic-review": "semanticReview",
|
|
55727
|
-
"adversarial-review": "adversarialReview"
|
|
55728
|
-
};
|
|
55729
|
-
STRATEGY_TO_REVALIDATION_PHASES = {
|
|
55730
|
-
"mechanical-lintfix": ["lint-check"],
|
|
55731
|
-
"mechanical-formatfix": ["lint-check"],
|
|
55732
|
-
"autofix-implementer": ["lint-check", "typecheck-check", "full-suite-gate", "semantic-review", "adversarial-review"],
|
|
55733
|
-
"autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "adversarial-review"],
|
|
55734
|
-
"full-suite-rectify": [
|
|
55735
|
-
"lint-check",
|
|
55736
|
-
"typecheck-check",
|
|
55737
|
-
"full-suite-gate",
|
|
55738
|
-
"verifier",
|
|
55739
|
-
"verify-scoped",
|
|
55740
|
-
"semantic-review"
|
|
55741
|
-
]
|
|
55742
|
-
};
|
|
55938
|
+
init_execution_plan();
|
|
55939
|
+
init_phase_state();
|
|
55940
|
+
});
|
|
55941
|
+
|
|
55942
|
+
// src/execution/story-orchestrator/index.ts
|
|
55943
|
+
var init_story_orchestrator = __esm(() => {
|
|
55944
|
+
init_builder2();
|
|
55945
|
+
init_execution_plan();
|
|
55946
|
+
init_phase_eval();
|
|
55947
|
+
init_rectification();
|
|
55948
|
+
init_run_phase();
|
|
55949
|
+
init_types9();
|
|
55743
55950
|
});
|
|
55744
55951
|
|
|
55745
55952
|
// src/execution/build-plan-for-strategy.ts
|
|
55746
|
-
import { join as
|
|
55953
|
+
import { join as join48 } from "path";
|
|
55747
55954
|
function requiresInitialRefCapture(strategy) {
|
|
55748
55955
|
return isThreeSessionStrategy(strategy);
|
|
55749
55956
|
}
|
|
@@ -55787,7 +55994,7 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55787
55994
|
if (inputs.adversarialReview) {
|
|
55788
55995
|
builder.addAdversarialReview(inputs.adversarialReview);
|
|
55789
55996
|
}
|
|
55790
|
-
const packageDir =
|
|
55997
|
+
const packageDir = join48(ctx.packageDir, story.workdir ?? "");
|
|
55791
55998
|
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.packageDir, story.workdir);
|
|
55792
55999
|
if (shouldRunRectification(config2) && inputs.rectification) {
|
|
55793
56000
|
const sink = makeDeclarationSink();
|
|
@@ -55842,6 +56049,12 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55842
56049
|
nbStrategies.push(makeAutofixImplementerStrategy(story, config2, nbSink, {
|
|
55843
56050
|
includeAdversarialReview: true
|
|
55844
56051
|
}));
|
|
56052
|
+
} else if (nbf.scope === "triage") {
|
|
56053
|
+
nbStrategies.push(makeAutofixImplementerStrategy(story, config2, nbSink, {
|
|
56054
|
+
adversarialReviewByFixTarget: "source"
|
|
56055
|
+
}), makeAutofixTestWriterStrategy(story, config2, nbSink, {
|
|
56056
|
+
includeAdversarialReview: false
|
|
56057
|
+
}));
|
|
55845
56058
|
} else {
|
|
55846
56059
|
nbStrategies.push(makeAutofixImplementerStrategy(story, config2, nbSink, {
|
|
55847
56060
|
includeAdversarialReview: false
|
|
@@ -55876,26 +56089,6 @@ var init_build_plan_for_strategy = __esm(() => {
|
|
|
55876
56089
|
init_story_orchestrator();
|
|
55877
56090
|
});
|
|
55878
56091
|
|
|
55879
|
-
// src/utils/paths.ts
|
|
55880
|
-
import { join as join48, relative as relative13, sep as sep4 } from "path";
|
|
55881
|
-
function packageDirRelative(projectDir, workdir) {
|
|
55882
|
-
if (!projectDir || !workdir || workdir === projectDir)
|
|
55883
|
-
return;
|
|
55884
|
-
const rel = relative13(projectDir, workdir);
|
|
55885
|
-
if (rel === ".." || rel.startsWith(`..${sep4}`))
|
|
55886
|
-
return;
|
|
55887
|
-
return rel && rel !== "." ? rel : undefined;
|
|
55888
|
-
}
|
|
55889
|
-
function getRunsDir() {
|
|
55890
|
-
return process.env.NAX_RUNS_DIR ?? join48(globalConfigDir(), "runs");
|
|
55891
|
-
}
|
|
55892
|
-
function getEventsRootDir() {
|
|
55893
|
-
return join48(globalConfigDir(), "events");
|
|
55894
|
-
}
|
|
55895
|
-
var init_paths3 = __esm(() => {
|
|
55896
|
-
init_paths();
|
|
55897
|
-
});
|
|
55898
|
-
|
|
55899
56092
|
// src/execution/plan-inputs.ts
|
|
55900
56093
|
function validatePlanInputs(story, config2) {
|
|
55901
56094
|
if (!story.id || story.id.trim() === "") {
|
|
@@ -56140,7 +56333,7 @@ function routeTddFailure(failureCategory, isLiteMode, ctx, reviewReason, failure
|
|
|
56140
56333
|
}
|
|
56141
56334
|
return { action: "escalate", reason: buildReason("isolation-violation") };
|
|
56142
56335
|
}
|
|
56143
|
-
if (failureCategory === "session-failure" || failureCategory === "tests-failing" || failureCategory === "full-suite-gate-exhausted" || failureCategory === "verifier-rejected" || failureCategory === "runtime-crash") {
|
|
56336
|
+
if (failureCategory === "session-failure" || failureCategory === "tests-failing" || failureCategory === "full-suite-gate-exhausted" || failureCategory === "verifier-rejected" || failureCategory === "runtime-crash" || failureCategory === "review-incomplete") {
|
|
56144
56337
|
return { action: "escalate", reason: buildReason(failureCategory) };
|
|
56145
56338
|
}
|
|
56146
56339
|
if (failureCategory === "greenfield-no-tests") {
|
|
@@ -56239,22 +56432,8 @@ async function closeAllRunSessions(sessionManager, agentGetFn, opts) {
|
|
|
56239
56432
|
return totalClosed;
|
|
56240
56433
|
}
|
|
56241
56434
|
|
|
56242
|
-
// src/execution/
|
|
56243
|
-
function
|
|
56244
|
-
return tddMode?.rollbackEnabled === true && failureCategory === "isolation-violation";
|
|
56245
|
-
}
|
|
56246
|
-
function extractPauseReason(phaseOutputs) {
|
|
56247
|
-
for (const output of Object.values(phaseOutputs)) {
|
|
56248
|
-
if (output !== null && typeof output === "object") {
|
|
56249
|
-
const record2 = output;
|
|
56250
|
-
if (typeof record2.pauseReason === "string" && record2.pauseReason) {
|
|
56251
|
-
return record2.pauseReason;
|
|
56252
|
-
}
|
|
56253
|
-
}
|
|
56254
|
-
}
|
|
56255
|
-
return;
|
|
56256
|
-
}
|
|
56257
|
-
function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDuringRect) {
|
|
56435
|
+
// src/execution/tdd-failure-category.ts
|
|
56436
|
+
function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDuringRect, missingRequiredReviewPhases) {
|
|
56258
56437
|
const testWriterOutput = phaseOutputs[testWriterOp.name];
|
|
56259
56438
|
if (testWriterOutput?.success === false) {
|
|
56260
56439
|
return "session-failure";
|
|
@@ -56293,6 +56472,29 @@ function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDu
|
|
|
56293
56472
|
if (implOutput?.success === false) {
|
|
56294
56473
|
return "session-failure";
|
|
56295
56474
|
}
|
|
56475
|
+
if (missingRequiredReviewPhases && missingRequiredReviewPhases.length > 0) {
|
|
56476
|
+
return "review-incomplete";
|
|
56477
|
+
}
|
|
56478
|
+
return;
|
|
56479
|
+
}
|
|
56480
|
+
var init_tdd_failure_category = __esm(() => {
|
|
56481
|
+
init_operations();
|
|
56482
|
+
init_story_orchestrator();
|
|
56483
|
+
});
|
|
56484
|
+
|
|
56485
|
+
// src/execution/post-run.ts
|
|
56486
|
+
function shouldRollbackTddFailure(tddMode, failureCategory) {
|
|
56487
|
+
return tddMode?.rollbackEnabled === true && failureCategory === "isolation-violation";
|
|
56488
|
+
}
|
|
56489
|
+
function extractPauseReason(phaseOutputs) {
|
|
56490
|
+
for (const output of Object.values(phaseOutputs)) {
|
|
56491
|
+
if (output !== null && typeof output === "object") {
|
|
56492
|
+
const record2 = output;
|
|
56493
|
+
if (typeof record2.pauseReason === "string" && record2.pauseReason) {
|
|
56494
|
+
return record2.pauseReason;
|
|
56495
|
+
}
|
|
56496
|
+
}
|
|
56497
|
+
}
|
|
56296
56498
|
return;
|
|
56297
56499
|
}
|
|
56298
56500
|
async function cleanupSessionOnFailure(ctx) {
|
|
@@ -56390,7 +56592,7 @@ async function applyPostRunInspection(ctx, planResult, opts) {
|
|
|
56390
56592
|
}
|
|
56391
56593
|
}
|
|
56392
56594
|
const pauseReason = extractPauseReason(planResult.phaseOutputs);
|
|
56393
|
-
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs, planResult.unfixedFindings, planResult.gateRegressedDuringRect) : undefined;
|
|
56595
|
+
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs, planResult.unfixedFindings, planResult.gateRegressedDuringRect, planResult.missingRequiredReviewPhases) : undefined;
|
|
56394
56596
|
if (isTdd && !planResult.success && !failureCategory) {
|
|
56395
56597
|
const phaseSignals = {};
|
|
56396
56598
|
for (const [name, output] of Object.entries(planResult.phaseOutputs)) {
|
|
@@ -56609,7 +56811,7 @@ var init_post_run = __esm(() => {
|
|
|
56609
56811
|
init_scratch_writer();
|
|
56610
56812
|
init_rollback();
|
|
56611
56813
|
init_git();
|
|
56612
|
-
|
|
56814
|
+
init_tdd_failure_category();
|
|
56613
56815
|
_postRunDeps = {
|
|
56614
56816
|
detectMergeConflict,
|
|
56615
56817
|
checkMergeConflict,
|
|
@@ -58746,17 +58948,46 @@ var init_setup_verify = __esm(() => {
|
|
|
58746
58948
|
};
|
|
58747
58949
|
});
|
|
58748
58950
|
|
|
58951
|
+
// src/cli/setup-write.ts
|
|
58952
|
+
import { join as join57 } from "path";
|
|
58953
|
+
async function writeSetupConfig(workdir, config2, monoConfigs, _opts, deps = _writeSetupDeps) {
|
|
58954
|
+
const naxDir = join57(workdir, ".nax");
|
|
58955
|
+
const naxConfigPath = join57(naxDir, "config.json");
|
|
58956
|
+
const written = [];
|
|
58957
|
+
await deps.mkdir(naxDir);
|
|
58958
|
+
await deps.writeFile(naxConfigPath, JSON.stringify(config2, null, 2));
|
|
58959
|
+
written.push(naxConfigPath);
|
|
58960
|
+
for (const mc of monoConfigs) {
|
|
58961
|
+
const monoDir = join57(naxDir, "mono", mc.relativeDir);
|
|
58962
|
+
const monoConfigPath = join57(monoDir, "config.json");
|
|
58963
|
+
await deps.mkdir(monoDir);
|
|
58964
|
+
await deps.writeFile(monoConfigPath, JSON.stringify(mc.config, null, 2));
|
|
58965
|
+
written.push(monoConfigPath);
|
|
58966
|
+
}
|
|
58967
|
+
return { written };
|
|
58968
|
+
}
|
|
58969
|
+
var _writeSetupDeps;
|
|
58970
|
+
var init_setup_write = __esm(() => {
|
|
58971
|
+
_writeSetupDeps = {
|
|
58972
|
+
writeFile: (path14, content) => Bun.write(path14, content).then(() => {}),
|
|
58973
|
+
mkdir: async (path14) => {
|
|
58974
|
+
const proc = Bun.spawn(["mkdir", "-p", path14]);
|
|
58975
|
+
await proc.exited;
|
|
58976
|
+
}
|
|
58977
|
+
};
|
|
58978
|
+
});
|
|
58979
|
+
|
|
58749
58980
|
// src/cli/setup.ts
|
|
58750
58981
|
var exports_setup = {};
|
|
58751
58982
|
__export(exports_setup, {
|
|
58752
58983
|
setupCommand: () => setupCommand,
|
|
58753
58984
|
_setupDeps: () => _setupDeps
|
|
58754
58985
|
});
|
|
58755
|
-
import { join as
|
|
58986
|
+
import { join as join58 } from "path";
|
|
58756
58987
|
async function setupCommand(options = {}) {
|
|
58757
58988
|
const workdir = options.dir ?? process.cwd();
|
|
58758
|
-
const naxDir =
|
|
58759
|
-
const naxConfigPath =
|
|
58989
|
+
const naxDir = join58(workdir, ".nax");
|
|
58990
|
+
const naxConfigPath = join58(naxDir, "config.json");
|
|
58760
58991
|
const exists = await _setupDeps.fileExists(naxConfigPath);
|
|
58761
58992
|
if (exists && !options.force) {
|
|
58762
58993
|
_setupDeps.stderr("[setup] .nax/config.json already exists. Use --force to overwrite.");
|
|
@@ -58786,13 +59017,7 @@ ${JSON.stringify(plan.config, null, 2)}`);
|
|
|
58786
59017
|
if (options.fillScripts) {
|
|
58787
59018
|
await _setupDeps.fillScripts(workdir, analysis);
|
|
58788
59019
|
}
|
|
58789
|
-
await _setupDeps.
|
|
58790
|
-
await _setupDeps.writeFile(naxConfigPath, JSON.stringify(plan.config, null, 2));
|
|
58791
|
-
for (const mc of plan.monoConfigs) {
|
|
58792
|
-
const monoDir = join57(naxDir, "mono", mc.relativeDir);
|
|
58793
|
-
await _setupDeps.mkdir(monoDir);
|
|
58794
|
-
await _setupDeps.writeFile(join57(monoDir, "config.json"), JSON.stringify(mc.config, null, 2));
|
|
58795
|
-
}
|
|
59020
|
+
await _setupDeps.writeSetupConfig(workdir, plan.config, plan.monoConfigs, { force: options.force });
|
|
58796
59021
|
const gateResult = await _setupDeps.runGate(workdir, plan.config);
|
|
58797
59022
|
if (gateResult !== 0) {
|
|
58798
59023
|
return gateResult;
|
|
@@ -58809,6 +59034,7 @@ var init_setup = __esm(() => {
|
|
|
58809
59034
|
init_setup_fill();
|
|
58810
59035
|
init_setup_llm();
|
|
58811
59036
|
init_setup_verify();
|
|
59037
|
+
init_setup_write();
|
|
58812
59038
|
_setupDeps = {
|
|
58813
59039
|
analyzeRepo,
|
|
58814
59040
|
fillScripts,
|
|
@@ -58830,11 +59056,7 @@ var init_setup = __esm(() => {
|
|
|
58830
59056
|
generateSetupPlan: (ctx, analysis) => generateSetupPlan(ctx, analysis),
|
|
58831
59057
|
runGate: (workdir, config2) => runSetupGate(workdir, config2),
|
|
58832
59058
|
fileExists: (path14) => Bun.file(path14).exists(),
|
|
58833
|
-
|
|
58834
|
-
mkdir: async (path14) => {
|
|
58835
|
-
const proc = Bun.spawn(["mkdir", "-p", path14]);
|
|
58836
|
-
await proc.exited;
|
|
58837
|
-
},
|
|
59059
|
+
writeSetupConfig: (workdir, config2, monoConfigs, opts) => writeSetupConfig(workdir, config2, monoConfigs, opts),
|
|
58838
59060
|
stdout: (msg) => {
|
|
58839
59061
|
process.stdout.write(`${msg}
|
|
58840
59062
|
`);
|
|
@@ -60273,7 +60495,7 @@ var init_command_argv = __esm(() => {
|
|
|
60273
60495
|
});
|
|
60274
60496
|
|
|
60275
60497
|
// src/hooks/runner.ts
|
|
60276
|
-
import { join as
|
|
60498
|
+
import { join as join75 } from "path";
|
|
60277
60499
|
function createDrainDeadline2(deadlineMs) {
|
|
60278
60500
|
let timeoutId;
|
|
60279
60501
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -60292,14 +60514,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
60292
60514
|
let globalHooks = { hooks: {} };
|
|
60293
60515
|
let projectHooks = { hooks: {} };
|
|
60294
60516
|
let skipGlobal = false;
|
|
60295
|
-
const projectPath =
|
|
60517
|
+
const projectPath = join75(projectDir, "hooks.json");
|
|
60296
60518
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
60297
60519
|
if (projectData) {
|
|
60298
60520
|
projectHooks = projectData;
|
|
60299
60521
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
60300
60522
|
}
|
|
60301
60523
|
if (!skipGlobal && globalDir) {
|
|
60302
|
-
const globalPath =
|
|
60524
|
+
const globalPath = join75(globalDir, "hooks.json");
|
|
60303
60525
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
60304
60526
|
if (globalData) {
|
|
60305
60527
|
globalHooks = globalData;
|
|
@@ -60469,7 +60691,7 @@ var package_default;
|
|
|
60469
60691
|
var init_package = __esm(() => {
|
|
60470
60692
|
package_default = {
|
|
60471
60693
|
name: "@nathapp/nax",
|
|
60472
|
-
version: "0.70.
|
|
60694
|
+
version: "0.70.2",
|
|
60473
60695
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
60474
60696
|
type: "module",
|
|
60475
60697
|
bin: {
|
|
@@ -60480,7 +60702,7 @@ var init_package = __esm(() => {
|
|
|
60480
60702
|
dev: "bun run bin/nax.ts",
|
|
60481
60703
|
build: 'bun build bin/nax.ts --outdir dist --target bun --define "GIT_COMMIT=\\"$(git rev-parse --short HEAD)\\""',
|
|
60482
60704
|
typecheck: "bun x tsc --noEmit && bun x tsc --noEmit -p tsconfig.contracts.json",
|
|
60483
|
-
lint: "bun x biome check src/ bin/ && bun run check:no-real-global-nax && bun run check:alias-internals && bun run check:deep-relatives && bun run check:nax-error && bun run check:logger-storyid",
|
|
60705
|
+
lint: "bun x biome check src/ bin/ && bun run check:no-real-global-nax && bun run check:alias-internals && bun run check:deep-relatives && bun run check:nax-error && bun run check:logger-storyid && bun run check:file-sizes",
|
|
60484
60706
|
"lint:json": "bun x biome check src/ bin/ --reporter json && bun run check:nax-error 1>&2 && bun run check:logger-storyid 1>&2",
|
|
60485
60707
|
"lint:fix": "bun x biome check --write src/ bin/",
|
|
60486
60708
|
"check:no-real-global-nax": "bun run scripts/check-no-real-global-nax.ts",
|
|
@@ -60491,6 +60713,8 @@ var init_package = __esm(() => {
|
|
|
60491
60713
|
"check:nax-error:update": "bun run scripts/check-nax-error.ts --update-baseline",
|
|
60492
60714
|
"check:logger-storyid": "bun run scripts/check-logger-storyid.ts",
|
|
60493
60715
|
"check:logger-storyid:update": "bun run scripts/check-logger-storyid.ts --update-baseline",
|
|
60716
|
+
"check:file-sizes": "bun run scripts/check-file-sizes.ts",
|
|
60717
|
+
"check:file-sizes:update": "bun run scripts/check-file-sizes.ts --update-baseline",
|
|
60494
60718
|
release: "bun scripts/release.ts",
|
|
60495
60719
|
test: "AGENT=1 bun run scripts/run-tests.ts",
|
|
60496
60720
|
"test:verbose": "bun run scripts/run-tests.ts",
|
|
@@ -60502,6 +60726,8 @@ var init_package = __esm(() => {
|
|
|
60502
60726
|
"test:integration": "bun test ./test/integration/ --timeout=60000",
|
|
60503
60727
|
"test:ui": "bun test ./test/ui/ --timeout=60000",
|
|
60504
60728
|
"test:e2e": "timeout -k 5s 180s bun test test/e2e/ --timeout=60000",
|
|
60729
|
+
"test:coverage": "bun run scripts/check-coverage.ts",
|
|
60730
|
+
"test:coverage:report": "bun run scripts/check-coverage.ts --report",
|
|
60505
60731
|
"check-test-overlap": "bun run scripts/check-test-overlap.ts",
|
|
60506
60732
|
"check-dead-tests": "bun run scripts/check-dead-tests.ts",
|
|
60507
60733
|
"check:test-sizes": "bun run scripts/check-test-sizes.ts",
|
|
@@ -60565,8 +60791,8 @@ var init_version = __esm(() => {
|
|
|
60565
60791
|
NAX_VERSION = package_default.version;
|
|
60566
60792
|
NAX_COMMIT = (() => {
|
|
60567
60793
|
try {
|
|
60568
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
60569
|
-
return "
|
|
60794
|
+
if (/^[0-9a-f]{6,10}$/.test("0e202cfa"))
|
|
60795
|
+
return "0e202cfa";
|
|
60570
60796
|
} catch {}
|
|
60571
60797
|
try {
|
|
60572
60798
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -61444,15 +61670,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
61444
61670
|
|
|
61445
61671
|
// src/session/scratch-purge.ts
|
|
61446
61672
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
61447
|
-
import { dirname as dirname12, join as
|
|
61673
|
+
import { dirname as dirname12, join as join76 } from "path";
|
|
61448
61674
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
61449
|
-
const sessionsDir =
|
|
61675
|
+
const sessionsDir = join76(projectDir, ".nax", "features", featureName, "sessions");
|
|
61450
61676
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
61451
61677
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
61452
61678
|
let purged = 0;
|
|
61453
61679
|
for (const sessionId of sessionIds) {
|
|
61454
|
-
const sessionDir =
|
|
61455
|
-
const descriptorPath =
|
|
61680
|
+
const sessionDir = join76(sessionsDir, sessionId);
|
|
61681
|
+
const descriptorPath = join76(sessionDir, "descriptor.json");
|
|
61456
61682
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
61457
61683
|
continue;
|
|
61458
61684
|
let lastActivityAt;
|
|
@@ -61468,7 +61694,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
61468
61694
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
61469
61695
|
continue;
|
|
61470
61696
|
if (archiveInsteadOfDelete) {
|
|
61471
|
-
const archiveDest =
|
|
61697
|
+
const archiveDest = join76(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
61472
61698
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
61473
61699
|
} else {
|
|
61474
61700
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -62173,7 +62399,7 @@ function outputRunFooter(options) {
|
|
|
62173
62399
|
}
|
|
62174
62400
|
var init_headless_formatter = __esm(() => {
|
|
62175
62401
|
init_source();
|
|
62176
|
-
|
|
62402
|
+
init_log_format();
|
|
62177
62403
|
init_version();
|
|
62178
62404
|
});
|
|
62179
62405
|
|
|
@@ -62219,12 +62445,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
62219
62445
|
|
|
62220
62446
|
// src/pipeline/subscribers/events-writer.ts
|
|
62221
62447
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
62222
|
-
import { basename as basename13, join as
|
|
62448
|
+
import { basename as basename13, join as join77 } from "path";
|
|
62223
62449
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
62224
62450
|
const logger = getSafeLogger();
|
|
62225
62451
|
const project = basename13(workdir);
|
|
62226
|
-
const eventsDir =
|
|
62227
|
-
const eventsFile =
|
|
62452
|
+
const eventsDir = join77(getEventsRootDir(), project);
|
|
62453
|
+
const eventsFile = join77(eventsDir, "events.jsonl");
|
|
62228
62454
|
let dirReady = false;
|
|
62229
62455
|
const write = (line) => {
|
|
62230
62456
|
return (async () => {
|
|
@@ -62405,12 +62631,12 @@ var init_interaction2 = __esm(() => {
|
|
|
62405
62631
|
|
|
62406
62632
|
// src/pipeline/subscribers/registry.ts
|
|
62407
62633
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
62408
|
-
import { basename as basename14, join as
|
|
62634
|
+
import { basename as basename14, join as join78 } from "path";
|
|
62409
62635
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
62410
62636
|
const logger = getSafeLogger();
|
|
62411
62637
|
const project = basename14(workdir);
|
|
62412
|
-
const runDir =
|
|
62413
|
-
const metaFile =
|
|
62638
|
+
const runDir = join78(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
62639
|
+
const metaFile = join78(runDir, "meta.json");
|
|
62414
62640
|
const unsub = bus.on("run:started", (_ev) => {
|
|
62415
62641
|
return (async () => {
|
|
62416
62642
|
try {
|
|
@@ -62420,8 +62646,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
62420
62646
|
project,
|
|
62421
62647
|
feature,
|
|
62422
62648
|
workdir,
|
|
62423
|
-
statusPath:
|
|
62424
|
-
eventsDir:
|
|
62649
|
+
statusPath: join78(outputDir, "features", feature, "status.json"),
|
|
62650
|
+
eventsDir: join78(outputDir, "features", feature, "runs"),
|
|
62425
62651
|
registeredAt: new Date().toISOString()
|
|
62426
62652
|
};
|
|
62427
62653
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -62653,7 +62879,7 @@ function buildPreviewRouting(story, config2) {
|
|
|
62653
62879
|
|
|
62654
62880
|
// src/worktree/types.ts
|
|
62655
62881
|
var WorktreeDependencyPreparationError;
|
|
62656
|
-
var
|
|
62882
|
+
var init_types10 = __esm(() => {
|
|
62657
62883
|
WorktreeDependencyPreparationError = class WorktreeDependencyPreparationError extends Error {
|
|
62658
62884
|
mode;
|
|
62659
62885
|
failureCategory = "dependency-prep";
|
|
@@ -62667,7 +62893,7 @@ var init_types9 = __esm(() => {
|
|
|
62667
62893
|
|
|
62668
62894
|
// src/worktree/dependencies.ts
|
|
62669
62895
|
import { existsSync as existsSync30 } from "fs";
|
|
62670
|
-
import { join as
|
|
62896
|
+
import { join as join79 } from "path";
|
|
62671
62897
|
async function prepareWorktreeDependencies(options) {
|
|
62672
62898
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
62673
62899
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -62681,7 +62907,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
62681
62907
|
}
|
|
62682
62908
|
}
|
|
62683
62909
|
function resolveDependencyCwd(options) {
|
|
62684
|
-
return options.storyWorkdir ?
|
|
62910
|
+
return options.storyWorkdir ? join79(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
62685
62911
|
}
|
|
62686
62912
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
62687
62913
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -62691,7 +62917,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
62691
62917
|
}
|
|
62692
62918
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
62693
62919
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
62694
|
-
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(
|
|
62920
|
+
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join79(directory, filename))));
|
|
62695
62921
|
}
|
|
62696
62922
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
62697
62923
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -62723,7 +62949,7 @@ var PHASE_ONE_INHERIT_UNSUPPORTED_FILES, _worktreeDependencyDeps;
|
|
|
62723
62949
|
var init_dependencies = __esm(() => {
|
|
62724
62950
|
init_bun_deps();
|
|
62725
62951
|
init_command_argv();
|
|
62726
|
-
|
|
62952
|
+
init_types10();
|
|
62727
62953
|
PHASE_ONE_INHERIT_UNSUPPORTED_FILES = [
|
|
62728
62954
|
"package.json",
|
|
62729
62955
|
"bun.lock",
|
|
@@ -62755,13 +62981,13 @@ __export(exports_manager, {
|
|
|
62755
62981
|
});
|
|
62756
62982
|
import { existsSync as existsSync31, symlinkSync } from "fs";
|
|
62757
62983
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
62758
|
-
import { join as
|
|
62984
|
+
import { join as join80 } from "path";
|
|
62759
62985
|
|
|
62760
62986
|
class WorktreeManager {
|
|
62761
62987
|
async ensureGitExcludes(projectRoot) {
|
|
62762
62988
|
const logger = getSafeLogger();
|
|
62763
|
-
const infoDir =
|
|
62764
|
-
const excludePath =
|
|
62989
|
+
const infoDir = join80(projectRoot, ".git", "info");
|
|
62990
|
+
const excludePath = join80(infoDir, "exclude");
|
|
62765
62991
|
try {
|
|
62766
62992
|
await mkdir15(infoDir, { recursive: true });
|
|
62767
62993
|
let existing = "";
|
|
@@ -62788,7 +63014,7 @@ ${missing.join(`
|
|
|
62788
63014
|
}
|
|
62789
63015
|
async create(projectRoot, storyId) {
|
|
62790
63016
|
validateStoryId(storyId);
|
|
62791
|
-
const worktreePath =
|
|
63017
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62792
63018
|
const branchName = `nax/${storyId}`;
|
|
62793
63019
|
try {
|
|
62794
63020
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -62828,9 +63054,9 @@ ${missing.join(`
|
|
|
62828
63054
|
}
|
|
62829
63055
|
throw new Error(`Failed to create worktree: ${String(error48)}`);
|
|
62830
63056
|
}
|
|
62831
|
-
const envSource =
|
|
63057
|
+
const envSource = join80(projectRoot, ".env");
|
|
62832
63058
|
if (existsSync31(envSource)) {
|
|
62833
|
-
const envTarget =
|
|
63059
|
+
const envTarget = join80(worktreePath, ".env");
|
|
62834
63060
|
try {
|
|
62835
63061
|
symlinkSync(envSource, envTarget, "file");
|
|
62836
63062
|
} catch (error48) {
|
|
@@ -62841,7 +63067,7 @@ ${missing.join(`
|
|
|
62841
63067
|
}
|
|
62842
63068
|
async remove(projectRoot, storyId) {
|
|
62843
63069
|
validateStoryId(storyId);
|
|
62844
|
-
const worktreePath =
|
|
63070
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62845
63071
|
const branchName = `nax/${storyId}`;
|
|
62846
63072
|
try {
|
|
62847
63073
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -63425,6 +63651,8 @@ function resolveMaxAttemptsOutcome(failureCategory) {
|
|
|
63425
63651
|
return "pause";
|
|
63426
63652
|
case "runtime-crash":
|
|
63427
63653
|
return "pause";
|
|
63654
|
+
case "review-incomplete":
|
|
63655
|
+
return "pause";
|
|
63428
63656
|
case "session-failure":
|
|
63429
63657
|
case "tests-failing":
|
|
63430
63658
|
case "full-suite-gate-exhausted":
|
|
@@ -63663,10 +63891,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
63663
63891
|
});
|
|
63664
63892
|
|
|
63665
63893
|
// src/execution/pipeline-result-handler.ts
|
|
63666
|
-
import { join as
|
|
63894
|
+
import { join as join81 } from "path";
|
|
63667
63895
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
63668
63896
|
const logger = getSafeLogger();
|
|
63669
|
-
const worktreePath =
|
|
63897
|
+
const worktreePath = join81(projectRoot, ".nax-wt", storyId);
|
|
63670
63898
|
try {
|
|
63671
63899
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
63672
63900
|
cwd: projectRoot,
|
|
@@ -63883,7 +64111,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
63883
64111
|
|
|
63884
64112
|
// src/execution/iteration-runner.ts
|
|
63885
64113
|
import { existsSync as existsSync32 } from "fs";
|
|
63886
|
-
import { join as
|
|
64114
|
+
import { join as join82 } from "path";
|
|
63887
64115
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
63888
64116
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
63889
64117
|
if (ctx.dryRun) {
|
|
@@ -63908,7 +64136,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63908
64136
|
const storyStartTime = Date.now();
|
|
63909
64137
|
let effectiveWorkdir = ctx.workdir;
|
|
63910
64138
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63911
|
-
const worktreePath =
|
|
64139
|
+
const worktreePath = join82(ctx.workdir, ".nax-wt", story.id);
|
|
63912
64140
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
63913
64141
|
if (!worktreeExists) {
|
|
63914
64142
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -63928,7 +64156,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63928
64156
|
}
|
|
63929
64157
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
63930
64158
|
const profileOverride = profileOverrideFromConfig(ctx.config);
|
|
63931
|
-
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(
|
|
64159
|
+
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join82(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
|
|
63932
64160
|
let dependencyContext;
|
|
63933
64161
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
63934
64162
|
try {
|
|
@@ -63955,7 +64183,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
63955
64183
|
};
|
|
63956
64184
|
}
|
|
63957
64185
|
}
|
|
63958
|
-
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ?
|
|
64186
|
+
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;
|
|
63959
64187
|
const pipelineContext = {
|
|
63960
64188
|
config: effectiveConfig,
|
|
63961
64189
|
rootConfig: ctx.config,
|
|
@@ -64158,7 +64386,7 @@ __export(exports_parallel_worker, {
|
|
|
64158
64386
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
64159
64387
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
64160
64388
|
});
|
|
64161
|
-
import { join as
|
|
64389
|
+
import { join as join83 } from "path";
|
|
64162
64390
|
function buildWorktreePipelineContext(base, _story) {
|
|
64163
64391
|
return { ...base, prd: structuredClone(base.prd) };
|
|
64164
64392
|
}
|
|
@@ -64181,7 +64409,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
64181
64409
|
story,
|
|
64182
64410
|
stories: [story],
|
|
64183
64411
|
projectDir: context.projectDir,
|
|
64184
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
64412
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join83(worktreePath, story.workdir) : worktreePath),
|
|
64185
64413
|
worktreeDependencyContext: dependencyContext,
|
|
64186
64414
|
routing,
|
|
64187
64415
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -65081,7 +65309,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
65081
65309
|
var init_status_file = () => {};
|
|
65082
65310
|
|
|
65083
65311
|
// src/execution/status-writer.ts
|
|
65084
|
-
import { join as
|
|
65312
|
+
import { join as join84 } from "path";
|
|
65085
65313
|
|
|
65086
65314
|
class StatusWriter {
|
|
65087
65315
|
statusFile;
|
|
@@ -65200,7 +65428,7 @@ class StatusWriter {
|
|
|
65200
65428
|
if (!this._prd)
|
|
65201
65429
|
return;
|
|
65202
65430
|
const safeLogger = getSafeLogger();
|
|
65203
|
-
const featureStatusPath =
|
|
65431
|
+
const featureStatusPath = join84(featureDir, "status.json");
|
|
65204
65432
|
const write = async () => {
|
|
65205
65433
|
try {
|
|
65206
65434
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -65634,7 +65862,7 @@ __export(exports_run_initialization, {
|
|
|
65634
65862
|
initializeRun: () => initializeRun,
|
|
65635
65863
|
_reconcileDeps: () => _reconcileDeps
|
|
65636
65864
|
});
|
|
65637
|
-
import { join as
|
|
65865
|
+
import { join as join85 } from "path";
|
|
65638
65866
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
65639
65867
|
const logger = getSafeLogger();
|
|
65640
65868
|
let reconciledCount = 0;
|
|
@@ -65651,7 +65879,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
65651
65879
|
});
|
|
65652
65880
|
continue;
|
|
65653
65881
|
}
|
|
65654
|
-
const effectiveWorkdir = story.workdir ?
|
|
65882
|
+
const effectiveWorkdir = story.workdir ? join85(workdir, story.workdir) : workdir;
|
|
65655
65883
|
try {
|
|
65656
65884
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
65657
65885
|
if (!reviewResult.success) {
|
|
@@ -95482,7 +95710,7 @@ __export(exports_curator, {
|
|
|
95482
95710
|
});
|
|
95483
95711
|
import { readdirSync as readdirSync8 } from "fs";
|
|
95484
95712
|
import { unlink as unlink4 } from "fs/promises";
|
|
95485
|
-
import { basename as basename15, join as
|
|
95713
|
+
import { basename as basename15, join as join87 } from "path";
|
|
95486
95714
|
function getProjectKey(config2, projectDir) {
|
|
95487
95715
|
return config2.name?.trim() || basename15(projectDir);
|
|
95488
95716
|
}
|
|
@@ -95565,7 +95793,7 @@ async function curatorStatus(options) {
|
|
|
95565
95793
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95566
95794
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95567
95795
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95568
|
-
const runsDir =
|
|
95796
|
+
const runsDir = join87(outputDir, "runs");
|
|
95569
95797
|
const runIds = listRunIds(runsDir);
|
|
95570
95798
|
let runId;
|
|
95571
95799
|
if (options.run) {
|
|
@@ -95582,8 +95810,8 @@ async function curatorStatus(options) {
|
|
|
95582
95810
|
runId = runIds[runIds.length - 1];
|
|
95583
95811
|
}
|
|
95584
95812
|
console.log(`Run: ${runId}`);
|
|
95585
|
-
const runDir =
|
|
95586
|
-
const observationsPath =
|
|
95813
|
+
const runDir = join87(runsDir, runId);
|
|
95814
|
+
const observationsPath = join87(runDir, "observations.jsonl");
|
|
95587
95815
|
const observations = await parseObservations(observationsPath);
|
|
95588
95816
|
const counts = new Map;
|
|
95589
95817
|
for (const obs of observations) {
|
|
@@ -95593,7 +95821,7 @@ async function curatorStatus(options) {
|
|
|
95593
95821
|
for (const [kind, count] of counts.entries()) {
|
|
95594
95822
|
console.log(` ${kind}: ${count}`);
|
|
95595
95823
|
}
|
|
95596
|
-
const proposalsPath =
|
|
95824
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
95597
95825
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
95598
95826
|
if (proposalText !== null) {
|
|
95599
95827
|
console.log("");
|
|
@@ -95607,8 +95835,8 @@ async function curatorCommit(options) {
|
|
|
95607
95835
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95608
95836
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95609
95837
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95610
|
-
const runDir =
|
|
95611
|
-
const proposalsPath =
|
|
95838
|
+
const runDir = join87(outputDir, "runs", options.runId);
|
|
95839
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
95612
95840
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
95613
95841
|
if (proposalText === null) {
|
|
95614
95842
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -95624,7 +95852,7 @@ async function curatorCommit(options) {
|
|
|
95624
95852
|
const dropFileState = new Map;
|
|
95625
95853
|
const skippedDrops = new Set;
|
|
95626
95854
|
for (const drop2 of drops) {
|
|
95627
|
-
const targetPath =
|
|
95855
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
95628
95856
|
if (!dropFileState.has(targetPath)) {
|
|
95629
95857
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
95630
95858
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -95658,7 +95886,7 @@ async function curatorCommit(options) {
|
|
|
95658
95886
|
if (skippedDrops.has(drop2)) {
|
|
95659
95887
|
continue;
|
|
95660
95888
|
}
|
|
95661
|
-
const targetPath =
|
|
95889
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
95662
95890
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
95663
95891
|
const filtered = filterDropContent(existing, drop2.description);
|
|
95664
95892
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -95667,7 +95895,7 @@ async function curatorCommit(options) {
|
|
|
95667
95895
|
}
|
|
95668
95896
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
95669
95897
|
for (const add2 of adds) {
|
|
95670
|
-
const targetPath =
|
|
95898
|
+
const targetPath = join87(resolved.projectDir, add2.canonicalFile);
|
|
95671
95899
|
const content = buildAddContent(add2);
|
|
95672
95900
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
95673
95901
|
modifiedFiles.add(targetPath);
|
|
@@ -95704,7 +95932,7 @@ async function curatorDryrun(options) {
|
|
|
95704
95932
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95705
95933
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95706
95934
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95707
|
-
const runsDir =
|
|
95935
|
+
const runsDir = join87(outputDir, "runs");
|
|
95708
95936
|
const runIds = listRunIds(runsDir);
|
|
95709
95937
|
if (runIds.length === 0) {
|
|
95710
95938
|
console.log("No runs found.");
|
|
@@ -95715,7 +95943,7 @@ async function curatorDryrun(options) {
|
|
|
95715
95943
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
95716
95944
|
return;
|
|
95717
95945
|
}
|
|
95718
|
-
const observationsPath =
|
|
95946
|
+
const observationsPath = join87(runsDir, runId, "observations.jsonl");
|
|
95719
95947
|
const observations = await parseObservations(observationsPath);
|
|
95720
95948
|
const thresholds = getThresholds(config2);
|
|
95721
95949
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -95756,12 +95984,12 @@ async function curatorGc(options) {
|
|
|
95756
95984
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
95757
95985
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95758
95986
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95759
|
-
const perRunsDir =
|
|
95987
|
+
const perRunsDir = join87(outputDir, "runs");
|
|
95760
95988
|
for (const runId of uniqueRunIds) {
|
|
95761
95989
|
if (!keepSet.has(runId)) {
|
|
95762
|
-
const runDir =
|
|
95763
|
-
await _curatorCmdDeps.removeFile(
|
|
95764
|
-
await _curatorCmdDeps.removeFile(
|
|
95990
|
+
const runDir = join87(perRunsDir, runId);
|
|
95991
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "observations.jsonl"));
|
|
95992
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "curator-proposals.md"));
|
|
95765
95993
|
}
|
|
95766
95994
|
}
|
|
95767
95995
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -95806,7 +96034,7 @@ var init_curator2 = __esm(() => {
|
|
|
95806
96034
|
init_source();
|
|
95807
96035
|
import { existsSync as existsSync35, mkdirSync as mkdirSync7 } from "fs";
|
|
95808
96036
|
import { homedir as homedir3 } from "os";
|
|
95809
|
-
import { basename as basename16, join as
|
|
96037
|
+
import { basename as basename16, join as join88 } from "path";
|
|
95810
96038
|
|
|
95811
96039
|
// node_modules/commander/esm.mjs
|
|
95812
96040
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -96930,6 +97158,7 @@ async function runsShowCommand(options) {
|
|
|
96930
97158
|
init_prompts2();
|
|
96931
97159
|
init_init2();
|
|
96932
97160
|
init_setup();
|
|
97161
|
+
init_setup_write();
|
|
96933
97162
|
|
|
96934
97163
|
// src/cli/plugins.ts
|
|
96935
97164
|
init_paths();
|
|
@@ -97005,7 +97234,7 @@ init_source();
|
|
|
97005
97234
|
init_loader();
|
|
97006
97235
|
init_generator2();
|
|
97007
97236
|
import { existsSync as existsSync24 } from "fs";
|
|
97008
|
-
import { join as
|
|
97237
|
+
import { join as join63 } from "path";
|
|
97009
97238
|
var VALID_AGENTS = ["claude", "codex", "opencode", "cursor", "windsurf", "aider", "gemini"];
|
|
97010
97239
|
async function generateCommand(options) {
|
|
97011
97240
|
const workdir = options.dir ?? process.cwd();
|
|
@@ -97048,7 +97277,7 @@ async function generateCommand(options) {
|
|
|
97048
97277
|
return;
|
|
97049
97278
|
}
|
|
97050
97279
|
if (options.package) {
|
|
97051
|
-
const packageDir =
|
|
97280
|
+
const packageDir = join63(workdir, options.package);
|
|
97052
97281
|
if (dryRun) {
|
|
97053
97282
|
console.log(source_default.yellow("\u26A0 Dry run \u2014 no files will be written"));
|
|
97054
97283
|
}
|
|
@@ -97068,8 +97297,8 @@ async function generateCommand(options) {
|
|
|
97068
97297
|
process.exit(1);
|
|
97069
97298
|
return;
|
|
97070
97299
|
}
|
|
97071
|
-
const contextPath = options.context ?
|
|
97072
|
-
const outputDir = options.output ?
|
|
97300
|
+
const contextPath = options.context ? join63(workdir, options.context) : join63(workdir, ".nax/context.md");
|
|
97301
|
+
const outputDir = options.output ? join63(workdir, options.output) : workdir;
|
|
97073
97302
|
const autoInject = !options.noAutoInject;
|
|
97074
97303
|
if (!existsSync24(contextPath)) {
|
|
97075
97304
|
console.error(source_default.red(`\u2717 Context file not found: ${contextPath}`));
|
|
@@ -97175,7 +97404,7 @@ async function generateCommand(options) {
|
|
|
97175
97404
|
// src/cli/config-display.ts
|
|
97176
97405
|
init_loader();
|
|
97177
97406
|
import { existsSync as existsSync26 } from "fs";
|
|
97178
|
-
import { join as
|
|
97407
|
+
import { join as join65 } from "path";
|
|
97179
97408
|
|
|
97180
97409
|
// src/cli/config-descriptions.ts
|
|
97181
97410
|
var FIELD_DESCRIPTIONS = {
|
|
@@ -97428,7 +97657,7 @@ function deepEqual(a, b) {
|
|
|
97428
97657
|
init_defaults();
|
|
97429
97658
|
init_loader();
|
|
97430
97659
|
import { existsSync as existsSync25 } from "fs";
|
|
97431
|
-
import { join as
|
|
97660
|
+
import { join as join64 } from "path";
|
|
97432
97661
|
async function loadConfigFile(path19) {
|
|
97433
97662
|
if (!existsSync25(path19))
|
|
97434
97663
|
return null;
|
|
@@ -97450,7 +97679,7 @@ async function loadProjectConfig() {
|
|
|
97450
97679
|
const projectDir = findProjectDir();
|
|
97451
97680
|
if (!projectDir)
|
|
97452
97681
|
return null;
|
|
97453
|
-
const projectPath =
|
|
97682
|
+
const projectPath = join64(projectDir, "config.json");
|
|
97454
97683
|
return await loadConfigFile(projectPath);
|
|
97455
97684
|
}
|
|
97456
97685
|
|
|
@@ -97510,7 +97739,7 @@ async function configCommand(config2, options = {}) {
|
|
|
97510
97739
|
function determineConfigSources() {
|
|
97511
97740
|
const globalPath = globalConfigPath();
|
|
97512
97741
|
const projectDir = findProjectDir();
|
|
97513
|
-
const projectPath = projectDir ?
|
|
97742
|
+
const projectPath = projectDir ? join65(projectDir, "config.json") : null;
|
|
97514
97743
|
return {
|
|
97515
97744
|
global: fileExists(globalPath) ? globalPath : null,
|
|
97516
97745
|
project: projectPath && fileExists(projectPath) ? projectPath : null
|
|
@@ -97659,15 +97888,15 @@ init_paths();
|
|
|
97659
97888
|
init_profile();
|
|
97660
97889
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
97661
97890
|
import { readdirSync as readdirSync5 } from "fs";
|
|
97662
|
-
import { join as
|
|
97891
|
+
import { join as join66 } from "path";
|
|
97663
97892
|
var _profileCLIDeps = {
|
|
97664
97893
|
env: process.env
|
|
97665
97894
|
};
|
|
97666
97895
|
var SENSITIVE_KEY_PATTERN = /key|token|secret|password|credential/i;
|
|
97667
97896
|
var VAR_PATTERN = /\$[A-Za-z_][A-Za-z0-9_]*/;
|
|
97668
97897
|
async function profileListCommand(startDir) {
|
|
97669
|
-
const globalProfilesDir =
|
|
97670
|
-
const projectProfilesDir =
|
|
97898
|
+
const globalProfilesDir = join66(globalConfigDir(), "profiles");
|
|
97899
|
+
const projectProfilesDir = join66(projectConfigDir(startDir), "profiles");
|
|
97671
97900
|
const globalProfiles = scanProfileDir(globalProfilesDir);
|
|
97672
97901
|
const projectProfiles = scanProfileDir(projectProfilesDir);
|
|
97673
97902
|
const activeProfile = await resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
@@ -97726,7 +97955,7 @@ function maskProfileValues(obj) {
|
|
|
97726
97955
|
return result;
|
|
97727
97956
|
}
|
|
97728
97957
|
async function profileUseCommand(profileName, startDir) {
|
|
97729
|
-
const configPath =
|
|
97958
|
+
const configPath = join66(projectConfigDir(startDir), "config.json");
|
|
97730
97959
|
const configFile = Bun.file(configPath);
|
|
97731
97960
|
let existing = {};
|
|
97732
97961
|
if (await configFile.exists()) {
|
|
@@ -97745,8 +97974,8 @@ async function profileCurrentCommand(startDir) {
|
|
|
97745
97974
|
return resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
97746
97975
|
}
|
|
97747
97976
|
async function profileCreateCommand(profileName, startDir) {
|
|
97748
|
-
const profilesDir =
|
|
97749
|
-
const profilePath =
|
|
97977
|
+
const profilesDir = join66(projectConfigDir(startDir), "profiles");
|
|
97978
|
+
const profilePath = join66(profilesDir, `${profileName}.json`);
|
|
97750
97979
|
const profileFile = Bun.file(profilePath);
|
|
97751
97980
|
if (await profileFile.exists()) {
|
|
97752
97981
|
throw new Error(`Profile "${profileName}" already exists at ${profilePath}`);
|
|
@@ -97868,7 +98097,7 @@ async function contextInspectCommand(options) {
|
|
|
97868
98097
|
init_canonical_loader();
|
|
97869
98098
|
init_errors();
|
|
97870
98099
|
import { mkdir as mkdir11 } from "fs/promises";
|
|
97871
|
-
import { basename as basename12, join as
|
|
98100
|
+
import { basename as basename12, join as join67 } from "path";
|
|
97872
98101
|
var _rulesCLIDeps = {
|
|
97873
98102
|
readFile: async (path19) => Bun.file(path19).text(),
|
|
97874
98103
|
writeFile: async (path19, content) => {
|
|
@@ -97877,7 +98106,7 @@ var _rulesCLIDeps = {
|
|
|
97877
98106
|
fileExists: async (path19) => Bun.file(path19).exists(),
|
|
97878
98107
|
globInDir: (dir) => {
|
|
97879
98108
|
try {
|
|
97880
|
-
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) =>
|
|
98109
|
+
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join67(dir, f));
|
|
97881
98110
|
} catch {
|
|
97882
98111
|
return [];
|
|
97883
98112
|
}
|
|
@@ -97926,7 +98155,7 @@ ${r.content}`).join(`
|
|
|
97926
98155
|
`);
|
|
97927
98156
|
const shimContent = `${header + body}
|
|
97928
98157
|
`;
|
|
97929
|
-
const shimPath =
|
|
98158
|
+
const shimPath = join67(workdir, shimFileName);
|
|
97930
98159
|
if (options.dryRun) {
|
|
97931
98160
|
console.log(`[dry-run] Would write ${shimPath} (${shimContent.length} bytes)`);
|
|
97932
98161
|
return;
|
|
@@ -97955,14 +98184,14 @@ function neutralizeContent(content) {
|
|
|
97955
98184
|
}
|
|
97956
98185
|
async function collectMigrationSources(workdir) {
|
|
97957
98186
|
const sources = [];
|
|
97958
|
-
const claudeMdPath =
|
|
98187
|
+
const claudeMdPath = join67(workdir, "CLAUDE.md");
|
|
97959
98188
|
if (await _rulesCLIDeps.fileExists(claudeMdPath)) {
|
|
97960
98189
|
const content = await _rulesCLIDeps.readFile(claudeMdPath);
|
|
97961
98190
|
if (content.trim()) {
|
|
97962
98191
|
sources.push({ sourcePath: claudeMdPath, targetFileName: "project-conventions.md", content });
|
|
97963
98192
|
}
|
|
97964
98193
|
}
|
|
97965
|
-
const rulesDir =
|
|
98194
|
+
const rulesDir = join67(workdir, ".claude", "rules");
|
|
97966
98195
|
const ruleFiles = _rulesCLIDeps.globInDir(rulesDir);
|
|
97967
98196
|
for (const filePath of ruleFiles) {
|
|
97968
98197
|
try {
|
|
@@ -97982,7 +98211,7 @@ async function rulesMigrateCommand(options) {
|
|
|
97982
98211
|
console.log("[WARN] No source files found (checked CLAUDE.md and .claude/rules/*.md). Nothing to migrate.");
|
|
97983
98212
|
return;
|
|
97984
98213
|
}
|
|
97985
|
-
const targetDir =
|
|
98214
|
+
const targetDir = join67(workdir, CANONICAL_RULES_DIR);
|
|
97986
98215
|
if (!options.dryRun) {
|
|
97987
98216
|
try {
|
|
97988
98217
|
await _rulesCLIDeps.mkdir(targetDir);
|
|
@@ -97993,7 +98222,7 @@ async function rulesMigrateCommand(options) {
|
|
|
97993
98222
|
let written = 0;
|
|
97994
98223
|
let skipped = 0;
|
|
97995
98224
|
for (const { sourcePath, targetFileName, content } of sources) {
|
|
97996
|
-
const targetPath =
|
|
98225
|
+
const targetPath = join67(targetDir, targetFileName);
|
|
97997
98226
|
if (!force && !options.dryRun && await _rulesCLIDeps.fileExists(targetPath)) {
|
|
97998
98227
|
console.log(`[skip] ${targetFileName} already exists (use --force to overwrite)`);
|
|
97999
98228
|
skipped++;
|
|
@@ -98032,7 +98261,7 @@ function collectCanonicalRuleRoots(workdir) {
|
|
|
98032
98261
|
const packageRel = normalized.slice(0, idx);
|
|
98033
98262
|
if (!packageRel)
|
|
98034
98263
|
continue;
|
|
98035
|
-
roots.add(
|
|
98264
|
+
roots.add(join67(workdir, packageRel));
|
|
98036
98265
|
}
|
|
98037
98266
|
return [...roots].sort();
|
|
98038
98267
|
}
|
|
@@ -98084,7 +98313,7 @@ init_logger2();
|
|
|
98084
98313
|
init_detect2();
|
|
98085
98314
|
init_workspace();
|
|
98086
98315
|
init_common();
|
|
98087
|
-
import { join as
|
|
98316
|
+
import { join as join68 } from "path";
|
|
98088
98317
|
function resolveEffective(detected, configPatterns) {
|
|
98089
98318
|
if (configPatterns !== undefined)
|
|
98090
98319
|
return "config";
|
|
@@ -98169,7 +98398,7 @@ async function detectCommand(options) {
|
|
|
98169
98398
|
const rootDetected = detectionMap[""] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98170
98399
|
const pkgEntries = await Promise.all(packageDirs.map(async (dir) => {
|
|
98171
98400
|
const det = detectionMap[dir] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98172
|
-
const pkgConfigPath =
|
|
98401
|
+
const pkgConfigPath = join68(workdir, ".nax", "mono", dir, "config.json");
|
|
98173
98402
|
const pkgRaw = await loadRawConfig(pkgConfigPath);
|
|
98174
98403
|
const pkgPatterns = deepGet(pkgRaw, TEST_PATTERNS_KEY);
|
|
98175
98404
|
const effective = Array.isArray(pkgPatterns) ? pkgPatterns : undefined;
|
|
@@ -98223,13 +98452,13 @@ async function detectCommand(options) {
|
|
|
98223
98452
|
if (rootDetected.confidence === "empty") {
|
|
98224
98453
|
console.log(source_default.yellow(" root: skipped (empty detection)"));
|
|
98225
98454
|
} else {
|
|
98226
|
-
const rootConfigPath =
|
|
98455
|
+
const rootConfigPath = join68(workdir, ".nax", "config.json");
|
|
98227
98456
|
try {
|
|
98228
98457
|
const status = await applyToConfig(rootConfigPath, rootDetected.patterns, options.force ?? false);
|
|
98229
98458
|
if (status === "skipped") {
|
|
98230
98459
|
console.log(source_default.dim(" root: skipped (testFilePatterns already set; use --force to overwrite)"));
|
|
98231
98460
|
} else {
|
|
98232
|
-
console.log(source_default.green(` root: ${status} \u2192 ${
|
|
98461
|
+
console.log(source_default.green(` root: ${status} \u2192 ${join68(".nax", "config.json")}`));
|
|
98233
98462
|
}
|
|
98234
98463
|
} catch (err) {
|
|
98235
98464
|
console.error(source_default.red(` root: write failed \u2014 ${err.message}`));
|
|
@@ -98242,13 +98471,13 @@ async function detectCommand(options) {
|
|
|
98242
98471
|
console.log(source_default.dim(` ${dir}: skipped (empty detection)`));
|
|
98243
98472
|
continue;
|
|
98244
98473
|
}
|
|
98245
|
-
const pkgConfigPath =
|
|
98474
|
+
const pkgConfigPath = join68(workdir, ".nax", "mono", dir, "config.json");
|
|
98246
98475
|
try {
|
|
98247
98476
|
const status = await applyToConfig(pkgConfigPath, det.patterns, options.force ?? false);
|
|
98248
98477
|
if (status === "skipped") {
|
|
98249
98478
|
console.log(source_default.dim(` ${dir}: skipped (already set)`));
|
|
98250
98479
|
} else {
|
|
98251
|
-
console.log(source_default.green(` ${dir}: ${status} \u2192 ${
|
|
98480
|
+
console.log(source_default.green(` ${dir}: ${status} \u2192 ${join68(".nax", "mono", dir, "config.json")}`));
|
|
98252
98481
|
}
|
|
98253
98482
|
} catch (err) {
|
|
98254
98483
|
console.error(source_default.red(` ${dir}: write failed \u2014 ${err.message}`));
|
|
@@ -98266,19 +98495,19 @@ async function detectCommand(options) {
|
|
|
98266
98495
|
// src/commands/logs.ts
|
|
98267
98496
|
init_common();
|
|
98268
98497
|
import { existsSync as existsSync28 } from "fs";
|
|
98269
|
-
import { join as
|
|
98498
|
+
import { join as join71 } from "path";
|
|
98270
98499
|
|
|
98271
98500
|
// src/commands/logs-formatter.ts
|
|
98272
98501
|
init_source();
|
|
98273
98502
|
init_formatter();
|
|
98274
98503
|
import { readdirSync as readdirSync7 } from "fs";
|
|
98275
|
-
import { join as
|
|
98504
|
+
import { join as join70 } from "path";
|
|
98276
98505
|
|
|
98277
98506
|
// src/commands/logs-reader.ts
|
|
98278
98507
|
init_paths3();
|
|
98279
98508
|
import { existsSync as existsSync27, readdirSync as readdirSync6 } from "fs";
|
|
98280
98509
|
import { readdir as readdir3 } from "fs/promises";
|
|
98281
|
-
import { join as
|
|
98510
|
+
import { join as join69 } from "path";
|
|
98282
98511
|
var _logsReaderDeps = {
|
|
98283
98512
|
getRunsDir
|
|
98284
98513
|
};
|
|
@@ -98292,7 +98521,7 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
98292
98521
|
}
|
|
98293
98522
|
let matched = null;
|
|
98294
98523
|
for (const entry of entries) {
|
|
98295
|
-
const metaPath =
|
|
98524
|
+
const metaPath = join69(runsDir, entry, "meta.json");
|
|
98296
98525
|
try {
|
|
98297
98526
|
const meta3 = await Bun.file(metaPath).json();
|
|
98298
98527
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -98314,14 +98543,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
98314
98543
|
return null;
|
|
98315
98544
|
}
|
|
98316
98545
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
98317
|
-
return
|
|
98546
|
+
return join69(matched.eventsDir, specificFile ?? files[0]);
|
|
98318
98547
|
}
|
|
98319
98548
|
async function selectRunFile(runsDir) {
|
|
98320
98549
|
const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
98321
98550
|
if (files.length === 0) {
|
|
98322
98551
|
return null;
|
|
98323
98552
|
}
|
|
98324
|
-
return
|
|
98553
|
+
return join69(runsDir, files[0]);
|
|
98325
98554
|
}
|
|
98326
98555
|
async function extractRunSummary(filePath) {
|
|
98327
98556
|
const file3 = Bun.file(filePath);
|
|
@@ -98407,7 +98636,7 @@ Runs:
|
|
|
98407
98636
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
98408
98637
|
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"));
|
|
98409
98638
|
for (const file3 of files) {
|
|
98410
|
-
const filePath =
|
|
98639
|
+
const filePath = join70(runsDir, file3);
|
|
98411
98640
|
const summary = await extractRunSummary(filePath);
|
|
98412
98641
|
const timestamp = file3.replace(".jsonl", "");
|
|
98413
98642
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -98521,7 +98750,7 @@ async function logsCommand(options) {
|
|
|
98521
98750
|
return;
|
|
98522
98751
|
}
|
|
98523
98752
|
const resolved = resolveProject({ dir: options.dir });
|
|
98524
|
-
const naxDir =
|
|
98753
|
+
const naxDir = join71(resolved.projectDir, ".nax");
|
|
98525
98754
|
const configPath = resolved.configPath;
|
|
98526
98755
|
const configFile = Bun.file(configPath);
|
|
98527
98756
|
const config2 = await configFile.json();
|
|
@@ -98529,8 +98758,8 @@ async function logsCommand(options) {
|
|
|
98529
98758
|
if (!featureName) {
|
|
98530
98759
|
throw new Error("No feature specified in config.json");
|
|
98531
98760
|
}
|
|
98532
|
-
const featureDir =
|
|
98533
|
-
const runsDir =
|
|
98761
|
+
const featureDir = join71(naxDir, "features", featureName);
|
|
98762
|
+
const runsDir = join71(featureDir, "runs");
|
|
98534
98763
|
if (!existsSync28(runsDir)) {
|
|
98535
98764
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
98536
98765
|
}
|
|
@@ -98556,7 +98785,7 @@ init_prd();
|
|
|
98556
98785
|
init_precheck();
|
|
98557
98786
|
init_common();
|
|
98558
98787
|
import { existsSync as existsSync29 } from "fs";
|
|
98559
|
-
import { join as
|
|
98788
|
+
import { join as join72 } from "path";
|
|
98560
98789
|
async function precheckCommand(options) {
|
|
98561
98790
|
const resolved = resolveProject({
|
|
98562
98791
|
dir: options.dir,
|
|
@@ -98578,9 +98807,9 @@ async function precheckCommand(options) {
|
|
|
98578
98807
|
process.exit(1);
|
|
98579
98808
|
}
|
|
98580
98809
|
}
|
|
98581
|
-
const naxDir =
|
|
98582
|
-
const featureDir =
|
|
98583
|
-
const prdPath =
|
|
98810
|
+
const naxDir = join72(resolved.projectDir, ".nax");
|
|
98811
|
+
const featureDir = join72(naxDir, "features", featureName);
|
|
98812
|
+
const prdPath = join72(featureDir, "prd.json");
|
|
98584
98813
|
if (!existsSync29(featureDir)) {
|
|
98585
98814
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
98586
98815
|
process.exit(1);
|
|
@@ -98603,7 +98832,7 @@ async function precheckCommand(options) {
|
|
|
98603
98832
|
init_source();
|
|
98604
98833
|
init_paths3();
|
|
98605
98834
|
import { readdir as readdir4 } from "fs/promises";
|
|
98606
|
-
import { join as
|
|
98835
|
+
import { join as join73 } from "path";
|
|
98607
98836
|
var DEFAULT_LIMIT = 20;
|
|
98608
98837
|
var _runsCmdDeps = {
|
|
98609
98838
|
getRunsDir
|
|
@@ -98658,7 +98887,7 @@ async function runsCommand(options = {}) {
|
|
|
98658
98887
|
}
|
|
98659
98888
|
const rows = [];
|
|
98660
98889
|
for (const entry of entries) {
|
|
98661
|
-
const metaPath =
|
|
98890
|
+
const metaPath = join73(runsDir, entry, "meta.json");
|
|
98662
98891
|
let meta3;
|
|
98663
98892
|
try {
|
|
98664
98893
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -98735,7 +98964,7 @@ async function runsCommand(options = {}) {
|
|
|
98735
98964
|
|
|
98736
98965
|
// src/commands/unlock.ts
|
|
98737
98966
|
init_source();
|
|
98738
|
-
import { join as
|
|
98967
|
+
import { join as join74 } from "path";
|
|
98739
98968
|
function isProcessAlive2(pid) {
|
|
98740
98969
|
try {
|
|
98741
98970
|
process.kill(pid, 0);
|
|
@@ -98750,7 +98979,7 @@ function formatLockAge(ageMs) {
|
|
|
98750
98979
|
}
|
|
98751
98980
|
async function unlockCommand(options) {
|
|
98752
98981
|
const workdir = options.dir ?? process.cwd();
|
|
98753
|
-
const lockPath =
|
|
98982
|
+
const lockPath = join74(workdir, "nax.lock");
|
|
98754
98983
|
const lockFile = Bun.file(lockPath);
|
|
98755
98984
|
const exists = await lockFile.exists();
|
|
98756
98985
|
if (!exists) {
|
|
@@ -107188,7 +107417,7 @@ Next: nax generate --package ${options.package}`));
|
|
|
107188
107417
|
}
|
|
107189
107418
|
return;
|
|
107190
107419
|
}
|
|
107191
|
-
const naxDir =
|
|
107420
|
+
const naxDir = join88(workdir, ".nax");
|
|
107192
107421
|
if (existsSync35(naxDir) && !options.force) {
|
|
107193
107422
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
107194
107423
|
return;
|
|
@@ -107217,11 +107446,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
107217
107446
|
}
|
|
107218
107447
|
}
|
|
107219
107448
|
}
|
|
107220
|
-
mkdirSync7(
|
|
107221
|
-
mkdirSync7(
|
|
107449
|
+
mkdirSync7(join88(naxDir, "features"), { recursive: true });
|
|
107450
|
+
mkdirSync7(join88(naxDir, "hooks"), { recursive: true });
|
|
107222
107451
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
107223
|
-
await Bun.write(
|
|
107224
|
-
await Bun.write(
|
|
107452
|
+
await Bun.write(join88(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
|
|
107453
|
+
await Bun.write(join88(naxDir, "hooks.json"), JSON.stringify({
|
|
107225
107454
|
hooks: {
|
|
107226
107455
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
107227
107456
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -107229,12 +107458,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
107229
107458
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
107230
107459
|
}
|
|
107231
107460
|
}, null, 2));
|
|
107232
|
-
await Bun.write(
|
|
107461
|
+
await Bun.write(join88(naxDir, ".gitignore"), `# nax temp files
|
|
107233
107462
|
*.tmp
|
|
107234
107463
|
.paused.json
|
|
107235
107464
|
.nax-verifier-verdict.json
|
|
107236
107465
|
`);
|
|
107237
|
-
await Bun.write(
|
|
107466
|
+
await Bun.write(join88(naxDir, "context.md"), `# Project Context
|
|
107238
107467
|
|
|
107239
107468
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
107240
107469
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -107376,7 +107605,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107376
107605
|
const cliOverrides = {};
|
|
107377
107606
|
const cliProfiles = options.profile ?? [];
|
|
107378
107607
|
const profileOverride = naxDir ? await resolveRunProfileOverride({
|
|
107379
|
-
prdPath:
|
|
107608
|
+
prdPath: join88(naxDir, "features", options.feature, "prd.json"),
|
|
107380
107609
|
projectRoot: workdir,
|
|
107381
107610
|
cliProfile: cliProfiles,
|
|
107382
107611
|
envProfile: process.env.NAX_PROFILE
|
|
@@ -107389,8 +107618,8 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107389
107618
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
107390
107619
|
process.exit(1);
|
|
107391
107620
|
}
|
|
107392
|
-
const featureDir =
|
|
107393
|
-
const prdPath =
|
|
107621
|
+
const featureDir = join88(naxDir, "features", options.feature);
|
|
107622
|
+
const prdPath = join88(featureDir, "prd.json");
|
|
107394
107623
|
if (options.plan && options.from) {
|
|
107395
107624
|
if (existsSync35(prdPath) && !options.force) {
|
|
107396
107625
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
@@ -107412,10 +107641,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107412
107641
|
}
|
|
107413
107642
|
}
|
|
107414
107643
|
try {
|
|
107415
|
-
const planLogDir =
|
|
107644
|
+
const planLogDir = join88(featureDir, "plan");
|
|
107416
107645
|
mkdirSync7(planLogDir, { recursive: true });
|
|
107417
107646
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107418
|
-
const planLogPath =
|
|
107647
|
+
const planLogPath = join88(planLogDir, `${planLogId}.jsonl`);
|
|
107419
107648
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
107420
107649
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
107421
107650
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -107461,10 +107690,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107461
107690
|
resetLogger();
|
|
107462
107691
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
107463
107692
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
107464
|
-
const runsDir =
|
|
107693
|
+
const runsDir = join88(outputDir, "features", options.feature, "runs");
|
|
107465
107694
|
mkdirSync7(runsDir, { recursive: true });
|
|
107466
107695
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107467
|
-
const logFilePath =
|
|
107696
|
+
const logFilePath = join88(runsDir, `${runId}.jsonl`);
|
|
107468
107697
|
const isTTY = process.stdout.isTTY ?? false;
|
|
107469
107698
|
const headlessFlag = options.headless ?? false;
|
|
107470
107699
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -107482,7 +107711,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107482
107711
|
config2.agent.default = options.agent;
|
|
107483
107712
|
}
|
|
107484
107713
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
107485
|
-
const globalNaxDir =
|
|
107714
|
+
const globalNaxDir = join88(homedir3(), ".nax");
|
|
107486
107715
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
107487
107716
|
const eventEmitter = new PipelineEventEmitter;
|
|
107488
107717
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -107502,12 +107731,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107502
107731
|
events: eventEmitter,
|
|
107503
107732
|
ptyOptions: null,
|
|
107504
107733
|
agentStreamEvents,
|
|
107505
|
-
queueFilePath:
|
|
107734
|
+
queueFilePath: join88(workdir, ".queue.txt")
|
|
107506
107735
|
});
|
|
107507
107736
|
} else {
|
|
107508
107737
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
107509
107738
|
}
|
|
107510
|
-
const statusFilePath =
|
|
107739
|
+
const statusFilePath = join88(outputDir, "status.json");
|
|
107511
107740
|
let parallel;
|
|
107512
107741
|
if (options.parallel !== undefined) {
|
|
107513
107742
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -107534,7 +107763,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107534
107763
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
107535
107764
|
agentStreamEvents
|
|
107536
107765
|
});
|
|
107537
|
-
const latestSymlink =
|
|
107766
|
+
const latestSymlink = join88(runsDir, "latest.jsonl");
|
|
107538
107767
|
try {
|
|
107539
107768
|
if (existsSync35(latestSymlink)) {
|
|
107540
107769
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
@@ -107595,9 +107824,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
107595
107824
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
107596
107825
|
process.exit(1);
|
|
107597
107826
|
}
|
|
107598
|
-
const featureDir =
|
|
107827
|
+
const featureDir = join88(naxDir, "features", name);
|
|
107599
107828
|
mkdirSync7(featureDir, { recursive: true });
|
|
107600
|
-
await Bun.write(
|
|
107829
|
+
await Bun.write(join88(featureDir, "spec.md"), `# Feature: ${name}
|
|
107601
107830
|
|
|
107602
107831
|
## Overview
|
|
107603
107832
|
|
|
@@ -107630,7 +107859,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
107630
107859
|
|
|
107631
107860
|
<!-- What this feature explicitly does NOT cover. -->
|
|
107632
107861
|
`);
|
|
107633
|
-
await Bun.write(
|
|
107862
|
+
await Bun.write(join88(featureDir, "progress.txt"), `# Progress: ${name}
|
|
107634
107863
|
|
|
107635
107864
|
Created: ${new Date().toISOString()}
|
|
107636
107865
|
|
|
@@ -107656,7 +107885,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
107656
107885
|
console.error(source_default.red("nax not initialized."));
|
|
107657
107886
|
process.exit(1);
|
|
107658
107887
|
}
|
|
107659
|
-
const featuresDir =
|
|
107888
|
+
const featuresDir = join88(naxDir, "features");
|
|
107660
107889
|
if (!existsSync35(featuresDir)) {
|
|
107661
107890
|
console.log(source_default.dim("No features yet."));
|
|
107662
107891
|
return;
|
|
@@ -107671,7 +107900,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
107671
107900
|
Features:
|
|
107672
107901
|
`));
|
|
107673
107902
|
for (const name of entries) {
|
|
107674
|
-
const prdPath =
|
|
107903
|
+
const prdPath = join88(featuresDir, name, "prd.json");
|
|
107675
107904
|
if (existsSync35(prdPath)) {
|
|
107676
107905
|
const prd = await loadPRD(prdPath);
|
|
107677
107906
|
const c = countStories(prd);
|
|
@@ -107707,10 +107936,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
107707
107936
|
cliOverrides.profile = cliProfiles;
|
|
107708
107937
|
}
|
|
107709
107938
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
107710
|
-
const featureLogDir =
|
|
107939
|
+
const featureLogDir = join88(naxDir, "features", options.feature, "plan");
|
|
107711
107940
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
107712
107941
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107713
|
-
const planLogPath =
|
|
107942
|
+
const planLogPath = join88(featureLogDir, `${planLogId}.jsonl`);
|
|
107714
107943
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
107715
107944
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
107716
107945
|
try {
|