@nathapp/nax 0.70.1 → 0.70.3
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 +571 -440
- package/package.json +6 -2
package/dist/nax.js
CHANGED
|
@@ -17737,7 +17737,7 @@ var init_schema = __esm(() => {
|
|
|
17737
17737
|
init_defaults();
|
|
17738
17738
|
});
|
|
17739
17739
|
|
|
17740
|
-
// src/
|
|
17740
|
+
// src/log-format/types.ts
|
|
17741
17741
|
var EMOJI;
|
|
17742
17742
|
var init_types2 = __esm(() => {
|
|
17743
17743
|
EMOJI = {
|
|
@@ -17759,7 +17759,7 @@ var init_types2 = __esm(() => {
|
|
|
17759
17759
|
};
|
|
17760
17760
|
});
|
|
17761
17761
|
|
|
17762
|
-
// src/
|
|
17762
|
+
// src/log-format/formatter.ts
|
|
17763
17763
|
function formatTimestamp(isoTimestamp) {
|
|
17764
17764
|
const date5 = new Date(isoTimestamp);
|
|
17765
17765
|
return date5.toLocaleTimeString("en-US", {
|
|
@@ -18072,8 +18072,8 @@ var init_formatter = __esm(() => {
|
|
|
18072
18072
|
];
|
|
18073
18073
|
});
|
|
18074
18074
|
|
|
18075
|
-
// src/
|
|
18076
|
-
var
|
|
18075
|
+
// src/log-format/index.ts
|
|
18076
|
+
var init_log_format = __esm(() => {
|
|
18077
18077
|
init_formatter();
|
|
18078
18078
|
init_types2();
|
|
18079
18079
|
});
|
|
@@ -18310,7 +18310,7 @@ function resetLogger() {
|
|
|
18310
18310
|
}
|
|
18311
18311
|
var LOG_LEVEL_PRIORITY, instance = null, noopLogger;
|
|
18312
18312
|
var init_logger = __esm(() => {
|
|
18313
|
-
|
|
18313
|
+
init_log_format();
|
|
18314
18314
|
init_formatters();
|
|
18315
18315
|
init_redact();
|
|
18316
18316
|
LOG_LEVEL_PRIORITY = {
|
|
@@ -18963,6 +18963,19 @@ function rejectLegacyRectificationKeys(conf) {
|
|
|
18963
18963
|
`);
|
|
18964
18964
|
throw new NaxError(message, "CONFIG_LEGACY_RECTIFICATION_KEYS", { stage: "config", legacyKeys });
|
|
18965
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
|
+
}
|
|
18966
18979
|
function applyBatchModeCompat(conf) {
|
|
18967
18980
|
const routing = conf.routing;
|
|
18968
18981
|
const llm = routing?.llm;
|
|
@@ -19072,6 +19085,7 @@ async function loadConfig(startDir, cliOverrides) {
|
|
|
19072
19085
|
}
|
|
19073
19086
|
rejectLegacyAgentKeys(rawConfig);
|
|
19074
19087
|
rejectLegacyRectificationKeys(rawConfig);
|
|
19088
|
+
rejectUnimplementedScopedProfile(rawConfig);
|
|
19075
19089
|
const result = NaxConfigSchema.safeParse(rawConfig);
|
|
19076
19090
|
if (!result.success) {
|
|
19077
19091
|
const errors3 = result.error.issues.map((err) => {
|
|
@@ -19141,6 +19155,7 @@ async function loadConfigForWorkdir(rootConfigPath, packageDir, cliOverrides) {
|
|
|
19141
19155
|
rawMerged.profileChain = packageChain;
|
|
19142
19156
|
rejectLegacyAgentKeys(rawMerged);
|
|
19143
19157
|
rejectLegacyRectificationKeys(rawMerged);
|
|
19158
|
+
rejectUnimplementedScopedProfile(rawMerged);
|
|
19144
19159
|
const result = NaxConfigSchema.safeParse(rawMerged);
|
|
19145
19160
|
if (!result.success) {
|
|
19146
19161
|
const errors3 = result.error.issues.map((err) => {
|
|
@@ -39398,6 +39413,7 @@ var init__finding_to_check = __esm(() => {
|
|
|
39398
39413
|
function makeAutofixImplementerStrategy(story, config2, sink, opts = {}) {
|
|
39399
39414
|
const claimsAdversarial = opts.includeAdversarialReview === true;
|
|
39400
39415
|
const adversarialReviewByFixTarget = opts.adversarialReviewByFixTarget;
|
|
39416
|
+
const blockingThreshold = opts.promptSeverityFloor ?? config2.review?.blockingThreshold;
|
|
39401
39417
|
return {
|
|
39402
39418
|
name: "autofix-implementer",
|
|
39403
39419
|
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",
|
|
@@ -39405,7 +39421,8 @@ function makeAutofixImplementerStrategy(story, config2, sink, opts = {}) {
|
|
|
39405
39421
|
buildInput: (findings, _prior, _cycleCtx) => ({
|
|
39406
39422
|
failedChecks: findingsToFailedChecks(findings),
|
|
39407
39423
|
story,
|
|
39408
|
-
findings
|
|
39424
|
+
findings,
|
|
39425
|
+
blockingThreshold
|
|
39409
39426
|
}),
|
|
39410
39427
|
extractApplied: (output) => {
|
|
39411
39428
|
for (const decl of output.testEditDeclarations) {
|
|
@@ -39434,6 +39451,7 @@ var init_autofix_implementer_strategy = __esm(() => {
|
|
|
39434
39451
|
// src/operations/autofix-test-writer-strategy.ts
|
|
39435
39452
|
function makeAutofixTestWriterStrategy(story, config2, sink, opts = {}) {
|
|
39436
39453
|
const includeAdversarial = opts.includeAdversarialReview !== false;
|
|
39454
|
+
const blockingThreshold = opts.promptSeverityFloor ?? config2.review?.blockingThreshold;
|
|
39437
39455
|
return {
|
|
39438
39456
|
name: "autofix-test-writer",
|
|
39439
39457
|
appliesTo: (f) => f.fixTarget === "test" || includeAdversarial && f.source === "adversarial-review" || sink.mockHandoffs.length > 0,
|
|
@@ -39458,7 +39476,7 @@ function makeAutofixTestWriterStrategy(story, config2, sink, opts = {}) {
|
|
|
39458
39476
|
failedChecks: findingsToFailedChecks(findings),
|
|
39459
39477
|
story,
|
|
39460
39478
|
mode: "mock-restructure",
|
|
39461
|
-
blockingThreshold
|
|
39479
|
+
blockingThreshold,
|
|
39462
39480
|
handoffReason,
|
|
39463
39481
|
handoffFiles
|
|
39464
39482
|
};
|
|
@@ -39466,7 +39484,7 @@ function makeAutofixTestWriterStrategy(story, config2, sink, opts = {}) {
|
|
|
39466
39484
|
return {
|
|
39467
39485
|
failedChecks: findingsToFailedChecks(findings),
|
|
39468
39486
|
story,
|
|
39469
|
-
blockingThreshold
|
|
39487
|
+
blockingThreshold
|
|
39470
39488
|
};
|
|
39471
39489
|
},
|
|
39472
39490
|
maxAttempts: config2.execution.rectification.maxAttemptsPerStrategy,
|
|
@@ -45276,7 +45294,7 @@ function attachLoggingSubscriber(bus, runId) {
|
|
|
45276
45294
|
offError();
|
|
45277
45295
|
};
|
|
45278
45296
|
}
|
|
45279
|
-
var
|
|
45297
|
+
var init_logging = __esm(() => {
|
|
45280
45298
|
init_logger2();
|
|
45281
45299
|
});
|
|
45282
45300
|
|
|
@@ -45794,7 +45812,7 @@ var init_idle_watchdog = __esm(() => {
|
|
|
45794
45812
|
// src/runtime/middleware/index.ts
|
|
45795
45813
|
var init_middleware = __esm(() => {
|
|
45796
45814
|
init_cancellation();
|
|
45797
|
-
|
|
45815
|
+
init_logging();
|
|
45798
45816
|
init_agent_stream_logging();
|
|
45799
45817
|
init_idle_watchdog();
|
|
45800
45818
|
});
|
|
@@ -54979,159 +54997,66 @@ var init_non_blocking_fix = __esm(() => {
|
|
|
54979
54997
|
};
|
|
54980
54998
|
});
|
|
54981
54999
|
|
|
54982
|
-
// src/execution/story-orchestrator
|
|
54983
|
-
|
|
54984
|
-
|
|
54985
|
-
|
|
54986
|
-
|
|
54987
|
-
|
|
54988
|
-
|
|
54989
|
-
|
|
54990
|
-
|
|
54991
|
-
|
|
54992
|
-
|
|
54993
|
-
|
|
54994
|
-
|
|
54995
|
-
|
|
54996
|
-
|
|
54997
|
-
|
|
54998
|
-
|
|
54999
|
-
|
|
55000
|
-
|
|
55001
|
-
|
|
55002
|
-
|
|
55003
|
-
|
|
55004
|
-
|
|
55005
|
-
|
|
55006
|
-
|
|
55007
|
-
|
|
55008
|
-
|
|
55009
|
-
|
|
55010
|
-
|
|
55011
|
-
|
|
55012
|
-
|
|
55013
|
-
|
|
55014
|
-
|
|
55015
|
-
|
|
55016
|
-
|
|
55017
|
-
|
|
55018
|
-
|
|
55019
|
-
|
|
55020
|
-
|
|
55021
|
-
|
|
55022
|
-
|
|
55023
|
-
|
|
55024
|
-
|
|
55025
|
-
|
|
55026
|
-
|
|
55027
|
-
|
|
55028
|
-
|
|
55029
|
-
|
|
55030
|
-
|
|
55031
|
-
|
|
55032
|
-
|
|
55033
|
-
|
|
55034
|
-
|
|
55035
|
-
|
|
55036
|
-
|
|
55037
|
-
|
|
55000
|
+
// src/execution/story-orchestrator/types.ts
|
|
55001
|
+
var EXHAUSTED_EXIT_REASONS, TDD_OP_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY, STRATEGY_TO_REVALIDATION_PHASES, STRICT_VERDICT_PHASE_NAMES;
|
|
55002
|
+
var init_types9 = __esm(() => {
|
|
55003
|
+
EXHAUSTED_EXIT_REASONS = new Set([
|
|
55004
|
+
"max-attempts-total",
|
|
55005
|
+
"max-attempts-per-strategy",
|
|
55006
|
+
"bail-when",
|
|
55007
|
+
"no-strategy",
|
|
55008
|
+
"agent-gave-up",
|
|
55009
|
+
"validate-short-circuit"
|
|
55010
|
+
]);
|
|
55011
|
+
TDD_OP_NAMES = new Set(["test-writer", "implementer", "verifier"]);
|
|
55012
|
+
CANONICAL_ORDER = [
|
|
55013
|
+
"test-writer",
|
|
55014
|
+
"greenfield-gate",
|
|
55015
|
+
"implementer",
|
|
55016
|
+
"full-suite-gate",
|
|
55017
|
+
"verifier",
|
|
55018
|
+
"verify-scoped",
|
|
55019
|
+
"lint-check",
|
|
55020
|
+
"typecheck-check",
|
|
55021
|
+
"semantic-review",
|
|
55022
|
+
"adversarial-review"
|
|
55023
|
+
];
|
|
55024
|
+
PHASE_KIND_TO_STATE_KEY = {
|
|
55025
|
+
"test-writer": "testWriter",
|
|
55026
|
+
"greenfield-gate": "greenfieldGate",
|
|
55027
|
+
implementer: "implementer",
|
|
55028
|
+
"full-suite-gate": "fullSuiteGate",
|
|
55029
|
+
verifier: "verifier",
|
|
55030
|
+
"verify-scoped": "verifyScoped",
|
|
55031
|
+
"lint-check": "lintCheck",
|
|
55032
|
+
"typecheck-check": "typecheckCheck",
|
|
55033
|
+
"semantic-review": "semanticReview",
|
|
55034
|
+
"adversarial-review": "adversarialReview"
|
|
55035
|
+
};
|
|
55036
|
+
STRATEGY_TO_REVALIDATION_PHASES = {
|
|
55037
|
+
"mechanical-lintfix": ["lint-check"],
|
|
55038
|
+
"mechanical-formatfix": ["lint-check"],
|
|
55039
|
+
"autofix-implementer": ["lint-check", "typecheck-check", "full-suite-gate", "semantic-review", "adversarial-review"],
|
|
55040
|
+
"autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "adversarial-review"],
|
|
55041
|
+
"full-suite-rectify": [
|
|
55042
|
+
"lint-check",
|
|
55043
|
+
"typecheck-check",
|
|
55044
|
+
"full-suite-gate",
|
|
55045
|
+
"verifier",
|
|
55046
|
+
"verify-scoped",
|
|
55047
|
+
"semantic-review"
|
|
55048
|
+
]
|
|
55049
|
+
};
|
|
55050
|
+
STRICT_VERDICT_PHASE_NAMES = new Set([
|
|
55051
|
+
"full-suite-gate",
|
|
55052
|
+
"verify-scoped",
|
|
55053
|
+
"lint-check",
|
|
55054
|
+
"typecheck-check",
|
|
55055
|
+
"verifier"
|
|
55056
|
+
]);
|
|
55038
55057
|
});
|
|
55039
55058
|
|
|
55040
|
-
// src/execution/story-orchestrator.ts
|
|
55041
|
-
async function refreshReviewInputForDispatch(opName, input) {
|
|
55042
|
-
if (opName !== "semantic-review" && opName !== "adversarial-review")
|
|
55043
|
-
return input;
|
|
55044
|
-
const i = input;
|
|
55045
|
-
const { _refresh } = i;
|
|
55046
|
-
if (!_refresh || !i.workdir)
|
|
55047
|
-
return input;
|
|
55048
|
-
try {
|
|
55049
|
-
if (opName === "semantic-review") {
|
|
55050
|
-
const { _refresh: _, ...semInput } = input;
|
|
55051
|
-
const fresh2 = await _storyOrchestratorDeps.prepareSemanticReviewInput({
|
|
55052
|
-
workdir: semInput.workdir,
|
|
55053
|
-
projectDir: _refresh.projectDir,
|
|
55054
|
-
storyId: _refresh.storyId,
|
|
55055
|
-
storyGitRef: _refresh.storyGitRef,
|
|
55056
|
-
config: _refresh.config,
|
|
55057
|
-
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55058
|
-
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55059
|
-
semanticConfig: semInput.semanticConfig
|
|
55060
|
-
});
|
|
55061
|
-
return {
|
|
55062
|
-
...semInput,
|
|
55063
|
-
stat: fresh2.stat,
|
|
55064
|
-
diff: fresh2.diff,
|
|
55065
|
-
excludePatterns: fresh2.excludePatterns,
|
|
55066
|
-
storyGitRef: fresh2.effectiveRef ?? semInput.storyGitRef
|
|
55067
|
-
};
|
|
55068
|
-
}
|
|
55069
|
-
const { _refresh: __, ...advInput } = input;
|
|
55070
|
-
const fresh = await _storyOrchestratorDeps.prepareAdversarialReviewInput({
|
|
55071
|
-
workdir: advInput.workdir,
|
|
55072
|
-
projectDir: _refresh.projectDir,
|
|
55073
|
-
storyId: _refresh.storyId,
|
|
55074
|
-
storyGitRef: _refresh.storyGitRef,
|
|
55075
|
-
config: _refresh.config,
|
|
55076
|
-
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55077
|
-
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55078
|
-
adversarialConfig: advInput.adversarialConfig
|
|
55079
|
-
});
|
|
55080
|
-
return {
|
|
55081
|
-
...advInput,
|
|
55082
|
-
stat: fresh.stat,
|
|
55083
|
-
diff: fresh.diff,
|
|
55084
|
-
testInventory: fresh.testInventory,
|
|
55085
|
-
excludePatterns: fresh.excludePatterns,
|
|
55086
|
-
testGlobs: fresh.testGlobs,
|
|
55087
|
-
refExcludePatterns: fresh.refExcludePatterns,
|
|
55088
|
-
storyGitRef: fresh.effectiveRef ?? advInput.storyGitRef
|
|
55089
|
-
};
|
|
55090
|
-
} catch (err) {
|
|
55091
|
-
getSafeLogger()?.warn("story-orchestrator", "review input refresh failed \u2014 dispatching with stale input", {
|
|
55092
|
-
storyId: _refresh.storyId,
|
|
55093
|
-
phase: opName,
|
|
55094
|
-
error: errorMessage(err)
|
|
55095
|
-
});
|
|
55096
|
-
const { _refresh: _stripped, ...fallback } = input;
|
|
55097
|
-
return fallback;
|
|
55098
|
-
}
|
|
55099
|
-
}
|
|
55100
|
-
function isSlot(value) {
|
|
55101
|
-
return value !== null && typeof value === "object" && "op" in value && "input" in value && typeof value.op?.kind === "string";
|
|
55102
|
-
}
|
|
55103
|
-
function setPhase(state, kind, slot) {
|
|
55104
|
-
const key = PHASE_KIND_TO_STATE_KEY[kind];
|
|
55105
|
-
if (state[key] !== undefined) {
|
|
55106
|
-
throw new NaxError(`StoryOrchestratorBuilder: addX was called twice for phase "${kind}"`, "ORCHESTRATOR_PHASE_DUPLICATE", { stage: "execution", kind });
|
|
55107
|
-
}
|
|
55108
|
-
state[key] = { kind, slot };
|
|
55109
|
-
}
|
|
55110
|
-
function collectOrderedPhases(state) {
|
|
55111
|
-
return CANONICAL_ORDER.flatMap((kind) => {
|
|
55112
|
-
if (kind === "test-writer" && state.testWriter)
|
|
55113
|
-
return [state.testWriter];
|
|
55114
|
-
if (kind === "greenfield-gate" && state.greenfieldGate)
|
|
55115
|
-
return [state.greenfieldGate];
|
|
55116
|
-
if (kind === "implementer" && state.implementer)
|
|
55117
|
-
return [state.implementer];
|
|
55118
|
-
if (kind === "full-suite-gate" && state.fullSuiteGate)
|
|
55119
|
-
return [state.fullSuiteGate];
|
|
55120
|
-
if (kind === "verifier" && state.verifier)
|
|
55121
|
-
return [state.verifier];
|
|
55122
|
-
if (kind === "verify-scoped" && state.verifyScoped)
|
|
55123
|
-
return [state.verifyScoped];
|
|
55124
|
-
if (kind === "lint-check" && state.lintCheck)
|
|
55125
|
-
return [state.lintCheck];
|
|
55126
|
-
if (kind === "typecheck-check" && state.typecheckCheck)
|
|
55127
|
-
return [state.typecheckCheck];
|
|
55128
|
-
if (kind === "semantic-review" && state.semanticReview)
|
|
55129
|
-
return [state.semanticReview];
|
|
55130
|
-
if (kind === "adversarial-review" && state.adversarialReview)
|
|
55131
|
-
return [state.adversarialReview];
|
|
55132
|
-
return [];
|
|
55133
|
-
});
|
|
55134
|
-
}
|
|
55059
|
+
// src/execution/story-orchestrator/phase-eval.ts
|
|
55135
55060
|
function phaseExplicitlyPassed(output) {
|
|
55136
55061
|
if (output === null || output === undefined || typeof output !== "object")
|
|
55137
55062
|
return false;
|
|
@@ -55189,34 +55114,6 @@ function gateFailureKeys(gateOutput) {
|
|
|
55189
55114
|
}
|
|
55190
55115
|
return keys;
|
|
55191
55116
|
}
|
|
55192
|
-
function shouldSkipPhaseForRectification(phase, state, phaseOutputs) {
|
|
55193
|
-
if (phase.kind !== "full-suite-gate")
|
|
55194
|
-
return false;
|
|
55195
|
-
const verifierName = state.verifier?.slot.op.name;
|
|
55196
|
-
if (!verifierName)
|
|
55197
|
-
return false;
|
|
55198
|
-
return phaseExplicitlyPassed(phaseOutputs[verifierName]);
|
|
55199
|
-
}
|
|
55200
|
-
function gatherRectificationFindings(phaseOutputs, phases, state) {
|
|
55201
|
-
const findings = [];
|
|
55202
|
-
for (const phase of phases) {
|
|
55203
|
-
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
55204
|
-
continue;
|
|
55205
|
-
findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
|
|
55206
|
-
}
|
|
55207
|
-
return findings;
|
|
55208
|
-
}
|
|
55209
|
-
function collectRectificationPhases(state) {
|
|
55210
|
-
return [
|
|
55211
|
-
state.fullSuiteGate,
|
|
55212
|
-
state.verifier,
|
|
55213
|
-
state.verifyScoped,
|
|
55214
|
-
state.lintCheck,
|
|
55215
|
-
state.typecheckCheck,
|
|
55216
|
-
state.semanticReview,
|
|
55217
|
-
state.adversarialReview
|
|
55218
|
-
].filter((phase) => phase !== undefined);
|
|
55219
|
-
}
|
|
55220
55117
|
function phasesToRevalidate(strategiesRun, allPhases) {
|
|
55221
55118
|
if (!strategiesRun || strategiesRun.length === 0)
|
|
55222
55119
|
return allPhases;
|
|
@@ -55236,6 +55133,111 @@ function orderGateLast(phases) {
|
|
|
55236
55133
|
const gates = phases.filter((p) => p.kind === "full-suite-gate");
|
|
55237
55134
|
return [...rest, ...gates];
|
|
55238
55135
|
}
|
|
55136
|
+
var init_phase_eval = __esm(() => {
|
|
55137
|
+
init_logger2();
|
|
55138
|
+
init_types9();
|
|
55139
|
+
});
|
|
55140
|
+
|
|
55141
|
+
// src/execution/story-orchestrator/phase-state.ts
|
|
55142
|
+
function isSlot(value) {
|
|
55143
|
+
return value !== null && typeof value === "object" && "op" in value && "input" in value && typeof value.op?.kind === "string";
|
|
55144
|
+
}
|
|
55145
|
+
function setPhase(state, kind, slot) {
|
|
55146
|
+
const key = PHASE_KIND_TO_STATE_KEY[kind];
|
|
55147
|
+
if (state[key] !== undefined) {
|
|
55148
|
+
throw new NaxError(`StoryOrchestratorBuilder: addX was called twice for phase "${kind}"`, "ORCHESTRATOR_PHASE_DUPLICATE", { stage: "execution", kind });
|
|
55149
|
+
}
|
|
55150
|
+
state[key] = { kind, slot };
|
|
55151
|
+
}
|
|
55152
|
+
function collectOrderedPhases(state) {
|
|
55153
|
+
return CANONICAL_ORDER.flatMap((kind) => {
|
|
55154
|
+
if (kind === "test-writer" && state.testWriter)
|
|
55155
|
+
return [state.testWriter];
|
|
55156
|
+
if (kind === "greenfield-gate" && state.greenfieldGate)
|
|
55157
|
+
return [state.greenfieldGate];
|
|
55158
|
+
if (kind === "implementer" && state.implementer)
|
|
55159
|
+
return [state.implementer];
|
|
55160
|
+
if (kind === "full-suite-gate" && state.fullSuiteGate)
|
|
55161
|
+
return [state.fullSuiteGate];
|
|
55162
|
+
if (kind === "verifier" && state.verifier)
|
|
55163
|
+
return [state.verifier];
|
|
55164
|
+
if (kind === "verify-scoped" && state.verifyScoped)
|
|
55165
|
+
return [state.verifyScoped];
|
|
55166
|
+
if (kind === "lint-check" && state.lintCheck)
|
|
55167
|
+
return [state.lintCheck];
|
|
55168
|
+
if (kind === "typecheck-check" && state.typecheckCheck)
|
|
55169
|
+
return [state.typecheckCheck];
|
|
55170
|
+
if (kind === "semantic-review" && state.semanticReview)
|
|
55171
|
+
return [state.semanticReview];
|
|
55172
|
+
if (kind === "adversarial-review" && state.adversarialReview)
|
|
55173
|
+
return [state.adversarialReview];
|
|
55174
|
+
return [];
|
|
55175
|
+
});
|
|
55176
|
+
}
|
|
55177
|
+
var init_phase_state = __esm(() => {
|
|
55178
|
+
init_errors();
|
|
55179
|
+
init_types9();
|
|
55180
|
+
});
|
|
55181
|
+
|
|
55182
|
+
// src/execution/story-orchestrator-logging.ts
|
|
55183
|
+
function formatPhaseResultMessage(opName, success2, stage, status) {
|
|
55184
|
+
if (opName === "greenfield-gate") {
|
|
55185
|
+
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";
|
|
55186
|
+
}
|
|
55187
|
+
if (status === "skipped") {
|
|
55188
|
+
return `Phase skipped: ${opName}`;
|
|
55189
|
+
}
|
|
55190
|
+
if (stage === "rectification") {
|
|
55191
|
+
return `Rectification strategy completed: ${opName}`;
|
|
55192
|
+
}
|
|
55193
|
+
return success2 ? `Phase passed: ${opName}` : `Phase failed: ${opName}`;
|
|
55194
|
+
}
|
|
55195
|
+
function buildPhaseOutcomeLogData(storyId, opName, output, durationMs) {
|
|
55196
|
+
if (output === null || output === undefined || typeof output !== "object")
|
|
55197
|
+
return null;
|
|
55198
|
+
const r = output;
|
|
55199
|
+
const success2 = r.success === true || r.passed === true;
|
|
55200
|
+
const findingsCount = Array.isArray(r.normalizedFindings) ? r.normalizedFindings.length : Array.isArray(r.findings) ? r.findings.length : undefined;
|
|
55201
|
+
const status = typeof r.status === "string" ? r.status : undefined;
|
|
55202
|
+
const data = { storyId, phase: opName, durationMs };
|
|
55203
|
+
if (findingsCount !== undefined)
|
|
55204
|
+
data.findingsCount = findingsCount;
|
|
55205
|
+
if (status !== undefined)
|
|
55206
|
+
data.status = status;
|
|
55207
|
+
if (typeof r.failureCategory === "string")
|
|
55208
|
+
data.failureCategory = r.failureCategory;
|
|
55209
|
+
if (typeof r.reviewReason === "string")
|
|
55210
|
+
data.reviewReason = r.reviewReason;
|
|
55211
|
+
return { success: success2, data };
|
|
55212
|
+
}
|
|
55213
|
+
function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTddPhase, stage, progressData = {}) {
|
|
55214
|
+
if (isTddPhase)
|
|
55215
|
+
return;
|
|
55216
|
+
if (opName === "semantic-review" || opName === "adversarial-review")
|
|
55217
|
+
return;
|
|
55218
|
+
const built = buildPhaseOutcomeLogData(storyId, opName, output, durationMs);
|
|
55219
|
+
if (!built)
|
|
55220
|
+
return;
|
|
55221
|
+
const { success: success2 } = built;
|
|
55222
|
+
const data = { ...built.data, ...progressData };
|
|
55223
|
+
const status = typeof built.data.status === "string" ? built.data.status : undefined;
|
|
55224
|
+
const logger = getSafeLogger();
|
|
55225
|
+
const message = formatPhaseResultMessage(opName, success2, stage, status);
|
|
55226
|
+
if (stage === "rectification") {
|
|
55227
|
+
logger?.info("story-orchestrator", message, data);
|
|
55228
|
+
return;
|
|
55229
|
+
}
|
|
55230
|
+
if (success2) {
|
|
55231
|
+
logger?.info("story-orchestrator", message, data);
|
|
55232
|
+
} else {
|
|
55233
|
+
logger?.warn("story-orchestrator", message, data);
|
|
55234
|
+
}
|
|
55235
|
+
}
|
|
55236
|
+
var init_story_orchestrator_logging = __esm(() => {
|
|
55237
|
+
init_logger2();
|
|
55238
|
+
});
|
|
55239
|
+
|
|
55240
|
+
// src/execution/story-orchestrator/review-decision.ts
|
|
55239
55241
|
function toReviewDecisionPayload(opName, output) {
|
|
55240
55242
|
if (output === null || output === undefined || typeof output !== "object")
|
|
55241
55243
|
return null;
|
|
@@ -55351,6 +55353,70 @@ function logUnifiedReviewPhaseResult(storyId, opName, output) {
|
|
|
55351
55353
|
truncated: findingsCount > findingsSummary.length
|
|
55352
55354
|
});
|
|
55353
55355
|
}
|
|
55356
|
+
var init_review_decision = __esm(() => {
|
|
55357
|
+
init_logger2();
|
|
55358
|
+
});
|
|
55359
|
+
|
|
55360
|
+
// src/execution/story-orchestrator/run-phase.ts
|
|
55361
|
+
async function refreshReviewInputForDispatch(opName, input) {
|
|
55362
|
+
if (opName !== "semantic-review" && opName !== "adversarial-review")
|
|
55363
|
+
return input;
|
|
55364
|
+
const i = input;
|
|
55365
|
+
const { _refresh } = i;
|
|
55366
|
+
if (!_refresh || !i.workdir)
|
|
55367
|
+
return input;
|
|
55368
|
+
try {
|
|
55369
|
+
if (opName === "semantic-review") {
|
|
55370
|
+
const { _refresh: _, ...semInput } = input;
|
|
55371
|
+
const fresh2 = await _storyOrchestratorDeps.prepareSemanticReviewInput({
|
|
55372
|
+
workdir: semInput.workdir,
|
|
55373
|
+
projectDir: _refresh.projectDir,
|
|
55374
|
+
storyId: _refresh.storyId,
|
|
55375
|
+
storyGitRef: _refresh.storyGitRef,
|
|
55376
|
+
config: _refresh.config,
|
|
55377
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55378
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55379
|
+
semanticConfig: semInput.semanticConfig
|
|
55380
|
+
});
|
|
55381
|
+
return {
|
|
55382
|
+
...semInput,
|
|
55383
|
+
stat: fresh2.stat,
|
|
55384
|
+
diff: fresh2.diff,
|
|
55385
|
+
excludePatterns: fresh2.excludePatterns,
|
|
55386
|
+
storyGitRef: fresh2.effectiveRef ?? semInput.storyGitRef
|
|
55387
|
+
};
|
|
55388
|
+
}
|
|
55389
|
+
const { _refresh: __, ...advInput } = input;
|
|
55390
|
+
const fresh = await _storyOrchestratorDeps.prepareAdversarialReviewInput({
|
|
55391
|
+
workdir: advInput.workdir,
|
|
55392
|
+
projectDir: _refresh.projectDir,
|
|
55393
|
+
storyId: _refresh.storyId,
|
|
55394
|
+
storyGitRef: _refresh.storyGitRef,
|
|
55395
|
+
config: _refresh.config,
|
|
55396
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55397
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55398
|
+
adversarialConfig: advInput.adversarialConfig
|
|
55399
|
+
});
|
|
55400
|
+
return {
|
|
55401
|
+
...advInput,
|
|
55402
|
+
stat: fresh.stat,
|
|
55403
|
+
diff: fresh.diff,
|
|
55404
|
+
testInventory: fresh.testInventory,
|
|
55405
|
+
excludePatterns: fresh.excludePatterns,
|
|
55406
|
+
testGlobs: fresh.testGlobs,
|
|
55407
|
+
refExcludePatterns: fresh.refExcludePatterns,
|
|
55408
|
+
storyGitRef: fresh.effectiveRef ?? advInput.storyGitRef
|
|
55409
|
+
};
|
|
55410
|
+
} catch (err) {
|
|
55411
|
+
getSafeLogger()?.warn("story-orchestrator", "review input refresh failed \u2014 dispatching with stale input", {
|
|
55412
|
+
storyId: _refresh.storyId,
|
|
55413
|
+
phase: opName,
|
|
55414
|
+
error: errorMessage(err)
|
|
55415
|
+
});
|
|
55416
|
+
const { _refresh: _stripped, ...fallback } = input;
|
|
55417
|
+
return fallback;
|
|
55418
|
+
}
|
|
55419
|
+
}
|
|
55354
55420
|
async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = false, progress) {
|
|
55355
55421
|
const logger = getSafeLogger();
|
|
55356
55422
|
const opName = slot.op.name;
|
|
@@ -55436,6 +55502,57 @@ function withIncreasingFailuresBail(strategies, enabled, consecutiveIncreases) {
|
|
|
55436
55502
|
}
|
|
55437
55503
|
}));
|
|
55438
55504
|
}
|
|
55505
|
+
var _storyOrchestratorDeps;
|
|
55506
|
+
var init_run_phase = __esm(() => {
|
|
55507
|
+
init_findings();
|
|
55508
|
+
init_logger2();
|
|
55509
|
+
init_operations();
|
|
55510
|
+
init_pipeline();
|
|
55511
|
+
init_review();
|
|
55512
|
+
init_git();
|
|
55513
|
+
init_non_blocking_fix();
|
|
55514
|
+
init_story_orchestrator_logging();
|
|
55515
|
+
init_review_decision();
|
|
55516
|
+
init_types9();
|
|
55517
|
+
_storyOrchestratorDeps = {
|
|
55518
|
+
callOp,
|
|
55519
|
+
runFixCycle,
|
|
55520
|
+
captureGitRef,
|
|
55521
|
+
prepareSemanticReviewInput,
|
|
55522
|
+
prepareAdversarialReviewInput,
|
|
55523
|
+
runNonBlockingFix
|
|
55524
|
+
};
|
|
55525
|
+
});
|
|
55526
|
+
|
|
55527
|
+
// src/execution/story-orchestrator/rectification.ts
|
|
55528
|
+
function shouldSkipPhaseForRectification(phase, state, phaseOutputs) {
|
|
55529
|
+
if (phase.kind !== "full-suite-gate")
|
|
55530
|
+
return false;
|
|
55531
|
+
const verifierName = state.verifier?.slot.op.name;
|
|
55532
|
+
if (!verifierName)
|
|
55533
|
+
return false;
|
|
55534
|
+
return phaseExplicitlyPassed(phaseOutputs[verifierName]);
|
|
55535
|
+
}
|
|
55536
|
+
function gatherRectificationFindings(phaseOutputs, phases, state) {
|
|
55537
|
+
const findings = [];
|
|
55538
|
+
for (const phase of phases) {
|
|
55539
|
+
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
55540
|
+
continue;
|
|
55541
|
+
findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
|
|
55542
|
+
}
|
|
55543
|
+
return findings;
|
|
55544
|
+
}
|
|
55545
|
+
function collectRectificationPhases(state) {
|
|
55546
|
+
return [
|
|
55547
|
+
state.fullSuiteGate,
|
|
55548
|
+
state.verifier,
|
|
55549
|
+
state.verifyScoped,
|
|
55550
|
+
state.lintCheck,
|
|
55551
|
+
state.typecheckCheck,
|
|
55552
|
+
state.semanticReview,
|
|
55553
|
+
state.adversarialReview
|
|
55554
|
+
].filter((phase) => phase !== undefined);
|
|
55555
|
+
}
|
|
55439
55556
|
async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides) {
|
|
55440
55557
|
const rectification = state.rectification;
|
|
55441
55558
|
const baseValidationPhases = collectRectificationPhases(state);
|
|
@@ -55533,7 +55650,15 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides)
|
|
|
55533
55650
|
}
|
|
55534
55651
|
return {};
|
|
55535
55652
|
}
|
|
55653
|
+
var init_rectification = __esm(() => {
|
|
55654
|
+
init_logger2();
|
|
55655
|
+
init_phase_eval();
|
|
55656
|
+
init_phase_eval();
|
|
55657
|
+
init_run_phase();
|
|
55658
|
+
init_types9();
|
|
55659
|
+
});
|
|
55536
55660
|
|
|
55661
|
+
// src/execution/story-orchestrator/execution-plan.ts
|
|
55537
55662
|
class ExecutionPlan {
|
|
55538
55663
|
ctx;
|
|
55539
55664
|
state;
|
|
@@ -55687,18 +55812,29 @@ class ExecutionPlan {
|
|
|
55687
55812
|
} else if (verifierPassedSsot && gateName !== undefined && !phasePassed(gateName, phaseOutputs[gateName], this.ctx.storyId)) {
|
|
55688
55813
|
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 });
|
|
55689
55814
|
}
|
|
55690
|
-
const
|
|
55815
|
+
const requiredReviewPhaseNames = [
|
|
55816
|
+
this.state.semanticReview?.slot.op.name,
|
|
55817
|
+
this.state.adversarialReview?.slot.op.name
|
|
55818
|
+
].filter((name) => name !== undefined);
|
|
55819
|
+
const missingRequiredReviewPhases = requiredReviewPhaseNames.filter((name) => !(name in phaseOutputs));
|
|
55820
|
+
if (missingRequiredReviewPhases.length > 0) {
|
|
55821
|
+
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 });
|
|
55822
|
+
}
|
|
55823
|
+
const success2 = missingRequiredReviewPhases.length === 0 && Object.entries(phaseOutputs).every(([name, output]) => {
|
|
55691
55824
|
if (verifierPassedSsot && name === gateName)
|
|
55692
55825
|
return true;
|
|
55693
55826
|
return phasePassed(name, output, this.ctx.storyId);
|
|
55694
55827
|
});
|
|
55695
55828
|
const totalCostUsd = Object.values(phaseCosts).reduce((sum, cost) => sum + cost, 0);
|
|
55696
55829
|
const durationMs = Date.now() - startedAt;
|
|
55697
|
-
const failedPhases =
|
|
55698
|
-
|
|
55699
|
-
|
|
55700
|
-
|
|
55701
|
-
|
|
55830
|
+
const failedPhases = [
|
|
55831
|
+
...Object.entries(phaseOutputs).filter(([name, output]) => {
|
|
55832
|
+
if (verifierPassedSsot && name === gateName)
|
|
55833
|
+
return false;
|
|
55834
|
+
return !phasePassed(name, output, this.ctx.storyId);
|
|
55835
|
+
}).map(([name]) => name),
|
|
55836
|
+
...missingRequiredReviewPhases.map((name) => `${name} (never ran)`)
|
|
55837
|
+
];
|
|
55702
55838
|
const summary = {
|
|
55703
55839
|
storyId: this.ctx.storyId,
|
|
55704
55840
|
success: success2,
|
|
@@ -55711,6 +55847,8 @@ class ExecutionPlan {
|
|
|
55711
55847
|
summary.rectificationExhausted = true;
|
|
55712
55848
|
if (rectResult.unfixedFindings)
|
|
55713
55849
|
summary.unfixedFindingsCount = rectResult.unfixedFindings.length;
|
|
55850
|
+
if (missingRequiredReviewPhases.length > 0)
|
|
55851
|
+
summary.missingRequiredReviewPhases = missingRequiredReviewPhases;
|
|
55714
55852
|
if (success2) {
|
|
55715
55853
|
logger?.info("story-orchestrator", "Story orchestration complete", summary);
|
|
55716
55854
|
} else {
|
|
@@ -55723,11 +55861,21 @@ class ExecutionPlan {
|
|
|
55723
55861
|
durationMs,
|
|
55724
55862
|
phaseOutputs,
|
|
55725
55863
|
...rectResult,
|
|
55726
|
-
gateRegressedDuringRect
|
|
55864
|
+
gateRegressedDuringRect,
|
|
55865
|
+
missingRequiredReviewPhases: missingRequiredReviewPhases.length > 0 ? missingRequiredReviewPhases : undefined
|
|
55727
55866
|
};
|
|
55728
55867
|
}
|
|
55729
55868
|
}
|
|
55869
|
+
var init_execution_plan = __esm(() => {
|
|
55870
|
+
init_logger2();
|
|
55871
|
+
init_non_blocking_fix();
|
|
55872
|
+
init_phase_eval();
|
|
55873
|
+
init_phase_state();
|
|
55874
|
+
init_rectification();
|
|
55875
|
+
init_run_phase();
|
|
55876
|
+
});
|
|
55730
55877
|
|
|
55878
|
+
// src/execution/story-orchestrator/builder.ts
|
|
55731
55879
|
class StoryOrchestratorBuilder {
|
|
55732
55880
|
state = {};
|
|
55733
55881
|
addImplementer(value) {
|
|
@@ -55787,80 +55935,21 @@ class StoryOrchestratorBuilder {
|
|
|
55787
55935
|
return new ExecutionPlan(ctx, { ...this.state }, opts.isThreeSession ?? false);
|
|
55788
55936
|
}
|
|
55789
55937
|
}
|
|
55790
|
-
var
|
|
55791
|
-
var init_story_orchestrator = __esm(() => {
|
|
55938
|
+
var init_builder2 = __esm(() => {
|
|
55792
55939
|
init_errors();
|
|
55793
|
-
init_findings();
|
|
55794
|
-
init_logger2();
|
|
55795
55940
|
init_operations();
|
|
55796
|
-
|
|
55797
|
-
|
|
55798
|
-
|
|
55799
|
-
|
|
55800
|
-
|
|
55801
|
-
|
|
55802
|
-
|
|
55803
|
-
|
|
55804
|
-
|
|
55805
|
-
|
|
55806
|
-
|
|
55807
|
-
|
|
55808
|
-
runNonBlockingFix
|
|
55809
|
-
};
|
|
55810
|
-
EXHAUSTED_EXIT_REASONS = new Set([
|
|
55811
|
-
"max-attempts-total",
|
|
55812
|
-
"max-attempts-per-strategy",
|
|
55813
|
-
"bail-when",
|
|
55814
|
-
"no-strategy",
|
|
55815
|
-
"agent-gave-up",
|
|
55816
|
-
"validate-short-circuit"
|
|
55817
|
-
]);
|
|
55818
|
-
TDD_OP_NAMES = new Set(["test-writer", "implementer", "verifier"]);
|
|
55819
|
-
STRICT_VERDICT_PHASE_NAMES = new Set([
|
|
55820
|
-
fullSuiteGateOp.name,
|
|
55821
|
-
verifyScopedOp.name,
|
|
55822
|
-
lintCheckOp.name,
|
|
55823
|
-
typecheckCheckOp.name,
|
|
55824
|
-
verifierOp.name
|
|
55825
|
-
]);
|
|
55826
|
-
CANONICAL_ORDER = [
|
|
55827
|
-
"test-writer",
|
|
55828
|
-
"greenfield-gate",
|
|
55829
|
-
"implementer",
|
|
55830
|
-
"full-suite-gate",
|
|
55831
|
-
"verifier",
|
|
55832
|
-
"verify-scoped",
|
|
55833
|
-
"lint-check",
|
|
55834
|
-
"typecheck-check",
|
|
55835
|
-
"semantic-review",
|
|
55836
|
-
"adversarial-review"
|
|
55837
|
-
];
|
|
55838
|
-
PHASE_KIND_TO_STATE_KEY = {
|
|
55839
|
-
"test-writer": "testWriter",
|
|
55840
|
-
"greenfield-gate": "greenfieldGate",
|
|
55841
|
-
implementer: "implementer",
|
|
55842
|
-
"full-suite-gate": "fullSuiteGate",
|
|
55843
|
-
verifier: "verifier",
|
|
55844
|
-
"verify-scoped": "verifyScoped",
|
|
55845
|
-
"lint-check": "lintCheck",
|
|
55846
|
-
"typecheck-check": "typecheckCheck",
|
|
55847
|
-
"semantic-review": "semanticReview",
|
|
55848
|
-
"adversarial-review": "adversarialReview"
|
|
55849
|
-
};
|
|
55850
|
-
STRATEGY_TO_REVALIDATION_PHASES = {
|
|
55851
|
-
"mechanical-lintfix": ["lint-check"],
|
|
55852
|
-
"mechanical-formatfix": ["lint-check"],
|
|
55853
|
-
"autofix-implementer": ["lint-check", "typecheck-check", "full-suite-gate", "semantic-review", "adversarial-review"],
|
|
55854
|
-
"autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "adversarial-review"],
|
|
55855
|
-
"full-suite-rectify": [
|
|
55856
|
-
"lint-check",
|
|
55857
|
-
"typecheck-check",
|
|
55858
|
-
"full-suite-gate",
|
|
55859
|
-
"verifier",
|
|
55860
|
-
"verify-scoped",
|
|
55861
|
-
"semantic-review"
|
|
55862
|
-
]
|
|
55863
|
-
};
|
|
55941
|
+
init_execution_plan();
|
|
55942
|
+
init_phase_state();
|
|
55943
|
+
});
|
|
55944
|
+
|
|
55945
|
+
// src/execution/story-orchestrator/index.ts
|
|
55946
|
+
var init_story_orchestrator = __esm(() => {
|
|
55947
|
+
init_builder2();
|
|
55948
|
+
init_execution_plan();
|
|
55949
|
+
init_phase_eval();
|
|
55950
|
+
init_rectification();
|
|
55951
|
+
init_run_phase();
|
|
55952
|
+
init_types9();
|
|
55864
55953
|
});
|
|
55865
55954
|
|
|
55866
55955
|
// src/execution/build-plan-for-strategy.ts
|
|
@@ -55961,18 +56050,24 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55961
56050
|
const nbSink = makeDeclarationSink();
|
|
55962
56051
|
if (nbf.scope === "source") {
|
|
55963
56052
|
nbStrategies.push(makeAutofixImplementerStrategy(story, config2, nbSink, {
|
|
55964
|
-
includeAdversarialReview: true
|
|
56053
|
+
includeAdversarialReview: true,
|
|
56054
|
+
promptSeverityFloor: "info"
|
|
55965
56055
|
}));
|
|
55966
56056
|
} else if (nbf.scope === "triage") {
|
|
55967
56057
|
nbStrategies.push(makeAutofixImplementerStrategy(story, config2, nbSink, {
|
|
55968
|
-
adversarialReviewByFixTarget: "source"
|
|
56058
|
+
adversarialReviewByFixTarget: "source",
|
|
56059
|
+
promptSeverityFloor: "info"
|
|
55969
56060
|
}), makeAutofixTestWriterStrategy(story, config2, nbSink, {
|
|
55970
|
-
includeAdversarialReview: false
|
|
56061
|
+
includeAdversarialReview: false,
|
|
56062
|
+
promptSeverityFloor: "info"
|
|
55971
56063
|
}));
|
|
55972
56064
|
} else {
|
|
55973
56065
|
nbStrategies.push(makeAutofixImplementerStrategy(story, config2, nbSink, {
|
|
55974
|
-
includeAdversarialReview: false
|
|
55975
|
-
|
|
56066
|
+
includeAdversarialReview: false,
|
|
56067
|
+
promptSeverityFloor: "info"
|
|
56068
|
+
}), makeAutofixTestWriterStrategy(story, config2, nbSink, {
|
|
56069
|
+
promptSeverityFloor: "info"
|
|
56070
|
+
}));
|
|
55976
56071
|
}
|
|
55977
56072
|
nbStrategies.push(makeFullSuiteRectifyStrategy(story, config2, nbSink));
|
|
55978
56073
|
const nbPostValidate = async (findings, _validateCtx) => {
|
|
@@ -56247,7 +56342,7 @@ function routeTddFailure(failureCategory, isLiteMode, ctx, reviewReason, failure
|
|
|
56247
56342
|
}
|
|
56248
56343
|
return { action: "escalate", reason: buildReason("isolation-violation") };
|
|
56249
56344
|
}
|
|
56250
|
-
if (failureCategory === "session-failure" || failureCategory === "tests-failing" || failureCategory === "full-suite-gate-exhausted" || failureCategory === "verifier-rejected" || failureCategory === "runtime-crash") {
|
|
56345
|
+
if (failureCategory === "session-failure" || failureCategory === "tests-failing" || failureCategory === "full-suite-gate-exhausted" || failureCategory === "verifier-rejected" || failureCategory === "runtime-crash" || failureCategory === "review-incomplete") {
|
|
56251
56346
|
return { action: "escalate", reason: buildReason(failureCategory) };
|
|
56252
56347
|
}
|
|
56253
56348
|
if (failureCategory === "greenfield-no-tests") {
|
|
@@ -56346,22 +56441,8 @@ async function closeAllRunSessions(sessionManager, agentGetFn, opts) {
|
|
|
56346
56441
|
return totalClosed;
|
|
56347
56442
|
}
|
|
56348
56443
|
|
|
56349
|
-
// src/execution/
|
|
56350
|
-
function
|
|
56351
|
-
return tddMode?.rollbackEnabled === true && failureCategory === "isolation-violation";
|
|
56352
|
-
}
|
|
56353
|
-
function extractPauseReason(phaseOutputs) {
|
|
56354
|
-
for (const output of Object.values(phaseOutputs)) {
|
|
56355
|
-
if (output !== null && typeof output === "object") {
|
|
56356
|
-
const record2 = output;
|
|
56357
|
-
if (typeof record2.pauseReason === "string" && record2.pauseReason) {
|
|
56358
|
-
return record2.pauseReason;
|
|
56359
|
-
}
|
|
56360
|
-
}
|
|
56361
|
-
}
|
|
56362
|
-
return;
|
|
56363
|
-
}
|
|
56364
|
-
function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDuringRect) {
|
|
56444
|
+
// src/execution/tdd-failure-category.ts
|
|
56445
|
+
function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDuringRect, missingRequiredReviewPhases) {
|
|
56365
56446
|
const testWriterOutput = phaseOutputs[testWriterOp.name];
|
|
56366
56447
|
if (testWriterOutput?.success === false) {
|
|
56367
56448
|
return "session-failure";
|
|
@@ -56400,6 +56481,29 @@ function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDu
|
|
|
56400
56481
|
if (implOutput?.success === false) {
|
|
56401
56482
|
return "session-failure";
|
|
56402
56483
|
}
|
|
56484
|
+
if (missingRequiredReviewPhases && missingRequiredReviewPhases.length > 0) {
|
|
56485
|
+
return "review-incomplete";
|
|
56486
|
+
}
|
|
56487
|
+
return;
|
|
56488
|
+
}
|
|
56489
|
+
var init_tdd_failure_category = __esm(() => {
|
|
56490
|
+
init_operations();
|
|
56491
|
+
init_story_orchestrator();
|
|
56492
|
+
});
|
|
56493
|
+
|
|
56494
|
+
// src/execution/post-run.ts
|
|
56495
|
+
function shouldRollbackTddFailure(tddMode, failureCategory) {
|
|
56496
|
+
return tddMode?.rollbackEnabled === true && failureCategory === "isolation-violation";
|
|
56497
|
+
}
|
|
56498
|
+
function extractPauseReason(phaseOutputs) {
|
|
56499
|
+
for (const output of Object.values(phaseOutputs)) {
|
|
56500
|
+
if (output !== null && typeof output === "object") {
|
|
56501
|
+
const record2 = output;
|
|
56502
|
+
if (typeof record2.pauseReason === "string" && record2.pauseReason) {
|
|
56503
|
+
return record2.pauseReason;
|
|
56504
|
+
}
|
|
56505
|
+
}
|
|
56506
|
+
}
|
|
56403
56507
|
return;
|
|
56404
56508
|
}
|
|
56405
56509
|
async function cleanupSessionOnFailure(ctx) {
|
|
@@ -56497,7 +56601,7 @@ async function applyPostRunInspection(ctx, planResult, opts) {
|
|
|
56497
56601
|
}
|
|
56498
56602
|
}
|
|
56499
56603
|
const pauseReason = extractPauseReason(planResult.phaseOutputs);
|
|
56500
|
-
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs, planResult.unfixedFindings, planResult.gateRegressedDuringRect) : undefined;
|
|
56604
|
+
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs, planResult.unfixedFindings, planResult.gateRegressedDuringRect, planResult.missingRequiredReviewPhases) : undefined;
|
|
56501
56605
|
if (isTdd && !planResult.success && !failureCategory) {
|
|
56502
56606
|
const phaseSignals = {};
|
|
56503
56607
|
for (const [name, output] of Object.entries(planResult.phaseOutputs)) {
|
|
@@ -56716,7 +56820,7 @@ var init_post_run = __esm(() => {
|
|
|
56716
56820
|
init_scratch_writer();
|
|
56717
56821
|
init_rollback();
|
|
56718
56822
|
init_git();
|
|
56719
|
-
|
|
56823
|
+
init_tdd_failure_category();
|
|
56720
56824
|
_postRunDeps = {
|
|
56721
56825
|
detectMergeConflict,
|
|
56722
56826
|
checkMergeConflict,
|
|
@@ -58853,17 +58957,46 @@ var init_setup_verify = __esm(() => {
|
|
|
58853
58957
|
};
|
|
58854
58958
|
});
|
|
58855
58959
|
|
|
58960
|
+
// src/cli/setup-write.ts
|
|
58961
|
+
import { join as join57 } from "path";
|
|
58962
|
+
async function writeSetupConfig(workdir, config2, monoConfigs, _opts, deps = _writeSetupDeps) {
|
|
58963
|
+
const naxDir = join57(workdir, ".nax");
|
|
58964
|
+
const naxConfigPath = join57(naxDir, "config.json");
|
|
58965
|
+
const written = [];
|
|
58966
|
+
await deps.mkdir(naxDir);
|
|
58967
|
+
await deps.writeFile(naxConfigPath, JSON.stringify(config2, null, 2));
|
|
58968
|
+
written.push(naxConfigPath);
|
|
58969
|
+
for (const mc of monoConfigs) {
|
|
58970
|
+
const monoDir = join57(naxDir, "mono", mc.relativeDir);
|
|
58971
|
+
const monoConfigPath = join57(monoDir, "config.json");
|
|
58972
|
+
await deps.mkdir(monoDir);
|
|
58973
|
+
await deps.writeFile(monoConfigPath, JSON.stringify(mc.config, null, 2));
|
|
58974
|
+
written.push(monoConfigPath);
|
|
58975
|
+
}
|
|
58976
|
+
return { written };
|
|
58977
|
+
}
|
|
58978
|
+
var _writeSetupDeps;
|
|
58979
|
+
var init_setup_write = __esm(() => {
|
|
58980
|
+
_writeSetupDeps = {
|
|
58981
|
+
writeFile: (path14, content) => Bun.write(path14, content).then(() => {}),
|
|
58982
|
+
mkdir: async (path14) => {
|
|
58983
|
+
const proc = Bun.spawn(["mkdir", "-p", path14]);
|
|
58984
|
+
await proc.exited;
|
|
58985
|
+
}
|
|
58986
|
+
};
|
|
58987
|
+
});
|
|
58988
|
+
|
|
58856
58989
|
// src/cli/setup.ts
|
|
58857
58990
|
var exports_setup = {};
|
|
58858
58991
|
__export(exports_setup, {
|
|
58859
58992
|
setupCommand: () => setupCommand,
|
|
58860
58993
|
_setupDeps: () => _setupDeps
|
|
58861
58994
|
});
|
|
58862
|
-
import { join as
|
|
58995
|
+
import { join as join58 } from "path";
|
|
58863
58996
|
async function setupCommand(options = {}) {
|
|
58864
58997
|
const workdir = options.dir ?? process.cwd();
|
|
58865
|
-
const naxDir =
|
|
58866
|
-
const naxConfigPath =
|
|
58998
|
+
const naxDir = join58(workdir, ".nax");
|
|
58999
|
+
const naxConfigPath = join58(naxDir, "config.json");
|
|
58867
59000
|
const exists = await _setupDeps.fileExists(naxConfigPath);
|
|
58868
59001
|
if (exists && !options.force) {
|
|
58869
59002
|
_setupDeps.stderr("[setup] .nax/config.json already exists. Use --force to overwrite.");
|
|
@@ -58893,13 +59026,7 @@ ${JSON.stringify(plan.config, null, 2)}`);
|
|
|
58893
59026
|
if (options.fillScripts) {
|
|
58894
59027
|
await _setupDeps.fillScripts(workdir, analysis);
|
|
58895
59028
|
}
|
|
58896
|
-
await _setupDeps.
|
|
58897
|
-
await _setupDeps.writeFile(naxConfigPath, JSON.stringify(plan.config, null, 2));
|
|
58898
|
-
for (const mc of plan.monoConfigs) {
|
|
58899
|
-
const monoDir = join57(naxDir, "mono", mc.relativeDir);
|
|
58900
|
-
await _setupDeps.mkdir(monoDir);
|
|
58901
|
-
await _setupDeps.writeFile(join57(monoDir, "config.json"), JSON.stringify(mc.config, null, 2));
|
|
58902
|
-
}
|
|
59029
|
+
await _setupDeps.writeSetupConfig(workdir, plan.config, plan.monoConfigs, { force: options.force });
|
|
58903
59030
|
const gateResult = await _setupDeps.runGate(workdir, plan.config);
|
|
58904
59031
|
if (gateResult !== 0) {
|
|
58905
59032
|
return gateResult;
|
|
@@ -58916,6 +59043,7 @@ var init_setup = __esm(() => {
|
|
|
58916
59043
|
init_setup_fill();
|
|
58917
59044
|
init_setup_llm();
|
|
58918
59045
|
init_setup_verify();
|
|
59046
|
+
init_setup_write();
|
|
58919
59047
|
_setupDeps = {
|
|
58920
59048
|
analyzeRepo,
|
|
58921
59049
|
fillScripts,
|
|
@@ -58937,11 +59065,7 @@ var init_setup = __esm(() => {
|
|
|
58937
59065
|
generateSetupPlan: (ctx, analysis) => generateSetupPlan(ctx, analysis),
|
|
58938
59066
|
runGate: (workdir, config2) => runSetupGate(workdir, config2),
|
|
58939
59067
|
fileExists: (path14) => Bun.file(path14).exists(),
|
|
58940
|
-
|
|
58941
|
-
mkdir: async (path14) => {
|
|
58942
|
-
const proc = Bun.spawn(["mkdir", "-p", path14]);
|
|
58943
|
-
await proc.exited;
|
|
58944
|
-
},
|
|
59068
|
+
writeSetupConfig: (workdir, config2, monoConfigs, opts) => writeSetupConfig(workdir, config2, monoConfigs, opts),
|
|
58945
59069
|
stdout: (msg) => {
|
|
58946
59070
|
process.stdout.write(`${msg}
|
|
58947
59071
|
`);
|
|
@@ -60380,7 +60504,7 @@ var init_command_argv = __esm(() => {
|
|
|
60380
60504
|
});
|
|
60381
60505
|
|
|
60382
60506
|
// src/hooks/runner.ts
|
|
60383
|
-
import { join as
|
|
60507
|
+
import { join as join75 } from "path";
|
|
60384
60508
|
function createDrainDeadline2(deadlineMs) {
|
|
60385
60509
|
let timeoutId;
|
|
60386
60510
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -60399,14 +60523,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
60399
60523
|
let globalHooks = { hooks: {} };
|
|
60400
60524
|
let projectHooks = { hooks: {} };
|
|
60401
60525
|
let skipGlobal = false;
|
|
60402
|
-
const projectPath =
|
|
60526
|
+
const projectPath = join75(projectDir, "hooks.json");
|
|
60403
60527
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
60404
60528
|
if (projectData) {
|
|
60405
60529
|
projectHooks = projectData;
|
|
60406
60530
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
60407
60531
|
}
|
|
60408
60532
|
if (!skipGlobal && globalDir) {
|
|
60409
|
-
const globalPath =
|
|
60533
|
+
const globalPath = join75(globalDir, "hooks.json");
|
|
60410
60534
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
60411
60535
|
if (globalData) {
|
|
60412
60536
|
globalHooks = globalData;
|
|
@@ -60576,7 +60700,7 @@ var package_default;
|
|
|
60576
60700
|
var init_package = __esm(() => {
|
|
60577
60701
|
package_default = {
|
|
60578
60702
|
name: "@nathapp/nax",
|
|
60579
|
-
version: "0.70.
|
|
60703
|
+
version: "0.70.3",
|
|
60580
60704
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
60581
60705
|
type: "module",
|
|
60582
60706
|
bin: {
|
|
@@ -60587,7 +60711,7 @@ var init_package = __esm(() => {
|
|
|
60587
60711
|
dev: "bun run bin/nax.ts",
|
|
60588
60712
|
build: 'bun build bin/nax.ts --outdir dist --target bun --define "GIT_COMMIT=\\"$(git rev-parse --short HEAD)\\""',
|
|
60589
60713
|
typecheck: "bun x tsc --noEmit && bun x tsc --noEmit -p tsconfig.contracts.json",
|
|
60590
|
-
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",
|
|
60714
|
+
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",
|
|
60591
60715
|
"lint:json": "bun x biome check src/ bin/ --reporter json && bun run check:nax-error 1>&2 && bun run check:logger-storyid 1>&2",
|
|
60592
60716
|
"lint:fix": "bun x biome check --write src/ bin/",
|
|
60593
60717
|
"check:no-real-global-nax": "bun run scripts/check-no-real-global-nax.ts",
|
|
@@ -60598,6 +60722,8 @@ var init_package = __esm(() => {
|
|
|
60598
60722
|
"check:nax-error:update": "bun run scripts/check-nax-error.ts --update-baseline",
|
|
60599
60723
|
"check:logger-storyid": "bun run scripts/check-logger-storyid.ts",
|
|
60600
60724
|
"check:logger-storyid:update": "bun run scripts/check-logger-storyid.ts --update-baseline",
|
|
60725
|
+
"check:file-sizes": "bun run scripts/check-file-sizes.ts",
|
|
60726
|
+
"check:file-sizes:update": "bun run scripts/check-file-sizes.ts --update-baseline",
|
|
60601
60727
|
release: "bun scripts/release.ts",
|
|
60602
60728
|
test: "AGENT=1 bun run scripts/run-tests.ts",
|
|
60603
60729
|
"test:verbose": "bun run scripts/run-tests.ts",
|
|
@@ -60609,6 +60735,8 @@ var init_package = __esm(() => {
|
|
|
60609
60735
|
"test:integration": "bun test ./test/integration/ --timeout=60000",
|
|
60610
60736
|
"test:ui": "bun test ./test/ui/ --timeout=60000",
|
|
60611
60737
|
"test:e2e": "timeout -k 5s 180s bun test test/e2e/ --timeout=60000",
|
|
60738
|
+
"test:coverage": "bun run scripts/check-coverage.ts",
|
|
60739
|
+
"test:coverage:report": "bun run scripts/check-coverage.ts --report",
|
|
60612
60740
|
"check-test-overlap": "bun run scripts/check-test-overlap.ts",
|
|
60613
60741
|
"check-dead-tests": "bun run scripts/check-dead-tests.ts",
|
|
60614
60742
|
"check:test-sizes": "bun run scripts/check-test-sizes.ts",
|
|
@@ -60672,8 +60800,8 @@ var init_version = __esm(() => {
|
|
|
60672
60800
|
NAX_VERSION = package_default.version;
|
|
60673
60801
|
NAX_COMMIT = (() => {
|
|
60674
60802
|
try {
|
|
60675
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
60676
|
-
return "
|
|
60803
|
+
if (/^[0-9a-f]{6,10}$/.test("c399b5b4"))
|
|
60804
|
+
return "c399b5b4";
|
|
60677
60805
|
} catch {}
|
|
60678
60806
|
try {
|
|
60679
60807
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -61551,15 +61679,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
61551
61679
|
|
|
61552
61680
|
// src/session/scratch-purge.ts
|
|
61553
61681
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
61554
|
-
import { dirname as dirname12, join as
|
|
61682
|
+
import { dirname as dirname12, join as join76 } from "path";
|
|
61555
61683
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
61556
|
-
const sessionsDir =
|
|
61684
|
+
const sessionsDir = join76(projectDir, ".nax", "features", featureName, "sessions");
|
|
61557
61685
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
61558
61686
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
61559
61687
|
let purged = 0;
|
|
61560
61688
|
for (const sessionId of sessionIds) {
|
|
61561
|
-
const sessionDir =
|
|
61562
|
-
const descriptorPath =
|
|
61689
|
+
const sessionDir = join76(sessionsDir, sessionId);
|
|
61690
|
+
const descriptorPath = join76(sessionDir, "descriptor.json");
|
|
61563
61691
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
61564
61692
|
continue;
|
|
61565
61693
|
let lastActivityAt;
|
|
@@ -61575,7 +61703,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
61575
61703
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
61576
61704
|
continue;
|
|
61577
61705
|
if (archiveInsteadOfDelete) {
|
|
61578
|
-
const archiveDest =
|
|
61706
|
+
const archiveDest = join76(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
61579
61707
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
61580
61708
|
} else {
|
|
61581
61709
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -62280,7 +62408,7 @@ function outputRunFooter(options) {
|
|
|
62280
62408
|
}
|
|
62281
62409
|
var init_headless_formatter = __esm(() => {
|
|
62282
62410
|
init_source();
|
|
62283
|
-
|
|
62411
|
+
init_log_format();
|
|
62284
62412
|
init_version();
|
|
62285
62413
|
});
|
|
62286
62414
|
|
|
@@ -62326,12 +62454,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
62326
62454
|
|
|
62327
62455
|
// src/pipeline/subscribers/events-writer.ts
|
|
62328
62456
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
62329
|
-
import { basename as basename13, join as
|
|
62457
|
+
import { basename as basename13, join as join77 } from "path";
|
|
62330
62458
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
62331
62459
|
const logger = getSafeLogger();
|
|
62332
62460
|
const project = basename13(workdir);
|
|
62333
|
-
const eventsDir =
|
|
62334
|
-
const eventsFile =
|
|
62461
|
+
const eventsDir = join77(getEventsRootDir(), project);
|
|
62462
|
+
const eventsFile = join77(eventsDir, "events.jsonl");
|
|
62335
62463
|
let dirReady = false;
|
|
62336
62464
|
const write = (line) => {
|
|
62337
62465
|
return (async () => {
|
|
@@ -62512,12 +62640,12 @@ var init_interaction2 = __esm(() => {
|
|
|
62512
62640
|
|
|
62513
62641
|
// src/pipeline/subscribers/registry.ts
|
|
62514
62642
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
62515
|
-
import { basename as basename14, join as
|
|
62643
|
+
import { basename as basename14, join as join78 } from "path";
|
|
62516
62644
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
62517
62645
|
const logger = getSafeLogger();
|
|
62518
62646
|
const project = basename14(workdir);
|
|
62519
|
-
const runDir =
|
|
62520
|
-
const metaFile =
|
|
62647
|
+
const runDir = join78(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
62648
|
+
const metaFile = join78(runDir, "meta.json");
|
|
62521
62649
|
const unsub = bus.on("run:started", (_ev) => {
|
|
62522
62650
|
return (async () => {
|
|
62523
62651
|
try {
|
|
@@ -62527,8 +62655,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
62527
62655
|
project,
|
|
62528
62656
|
feature,
|
|
62529
62657
|
workdir,
|
|
62530
|
-
statusPath:
|
|
62531
|
-
eventsDir:
|
|
62658
|
+
statusPath: join78(outputDir, "features", feature, "status.json"),
|
|
62659
|
+
eventsDir: join78(outputDir, "features", feature, "runs"),
|
|
62532
62660
|
registeredAt: new Date().toISOString()
|
|
62533
62661
|
};
|
|
62534
62662
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -62760,7 +62888,7 @@ function buildPreviewRouting(story, config2) {
|
|
|
62760
62888
|
|
|
62761
62889
|
// src/worktree/types.ts
|
|
62762
62890
|
var WorktreeDependencyPreparationError;
|
|
62763
|
-
var
|
|
62891
|
+
var init_types10 = __esm(() => {
|
|
62764
62892
|
WorktreeDependencyPreparationError = class WorktreeDependencyPreparationError extends Error {
|
|
62765
62893
|
mode;
|
|
62766
62894
|
failureCategory = "dependency-prep";
|
|
@@ -62774,7 +62902,7 @@ var init_types9 = __esm(() => {
|
|
|
62774
62902
|
|
|
62775
62903
|
// src/worktree/dependencies.ts
|
|
62776
62904
|
import { existsSync as existsSync30 } from "fs";
|
|
62777
|
-
import { join as
|
|
62905
|
+
import { join as join79 } from "path";
|
|
62778
62906
|
async function prepareWorktreeDependencies(options) {
|
|
62779
62907
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
62780
62908
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -62788,7 +62916,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
62788
62916
|
}
|
|
62789
62917
|
}
|
|
62790
62918
|
function resolveDependencyCwd(options) {
|
|
62791
|
-
return options.storyWorkdir ?
|
|
62919
|
+
return options.storyWorkdir ? join79(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
62792
62920
|
}
|
|
62793
62921
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
62794
62922
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -62798,7 +62926,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
62798
62926
|
}
|
|
62799
62927
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
62800
62928
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
62801
|
-
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(
|
|
62929
|
+
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join79(directory, filename))));
|
|
62802
62930
|
}
|
|
62803
62931
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
62804
62932
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -62830,7 +62958,7 @@ var PHASE_ONE_INHERIT_UNSUPPORTED_FILES, _worktreeDependencyDeps;
|
|
|
62830
62958
|
var init_dependencies = __esm(() => {
|
|
62831
62959
|
init_bun_deps();
|
|
62832
62960
|
init_command_argv();
|
|
62833
|
-
|
|
62961
|
+
init_types10();
|
|
62834
62962
|
PHASE_ONE_INHERIT_UNSUPPORTED_FILES = [
|
|
62835
62963
|
"package.json",
|
|
62836
62964
|
"bun.lock",
|
|
@@ -62862,13 +62990,13 @@ __export(exports_manager, {
|
|
|
62862
62990
|
});
|
|
62863
62991
|
import { existsSync as existsSync31, symlinkSync } from "fs";
|
|
62864
62992
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
62865
|
-
import { join as
|
|
62993
|
+
import { join as join80 } from "path";
|
|
62866
62994
|
|
|
62867
62995
|
class WorktreeManager {
|
|
62868
62996
|
async ensureGitExcludes(projectRoot) {
|
|
62869
62997
|
const logger = getSafeLogger();
|
|
62870
|
-
const infoDir =
|
|
62871
|
-
const excludePath =
|
|
62998
|
+
const infoDir = join80(projectRoot, ".git", "info");
|
|
62999
|
+
const excludePath = join80(infoDir, "exclude");
|
|
62872
63000
|
try {
|
|
62873
63001
|
await mkdir15(infoDir, { recursive: true });
|
|
62874
63002
|
let existing = "";
|
|
@@ -62895,7 +63023,7 @@ ${missing.join(`
|
|
|
62895
63023
|
}
|
|
62896
63024
|
async create(projectRoot, storyId) {
|
|
62897
63025
|
validateStoryId(storyId);
|
|
62898
|
-
const worktreePath =
|
|
63026
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62899
63027
|
const branchName = `nax/${storyId}`;
|
|
62900
63028
|
try {
|
|
62901
63029
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -62935,9 +63063,9 @@ ${missing.join(`
|
|
|
62935
63063
|
}
|
|
62936
63064
|
throw new Error(`Failed to create worktree: ${String(error48)}`);
|
|
62937
63065
|
}
|
|
62938
|
-
const envSource =
|
|
63066
|
+
const envSource = join80(projectRoot, ".env");
|
|
62939
63067
|
if (existsSync31(envSource)) {
|
|
62940
|
-
const envTarget =
|
|
63068
|
+
const envTarget = join80(worktreePath, ".env");
|
|
62941
63069
|
try {
|
|
62942
63070
|
symlinkSync(envSource, envTarget, "file");
|
|
62943
63071
|
} catch (error48) {
|
|
@@ -62948,7 +63076,7 @@ ${missing.join(`
|
|
|
62948
63076
|
}
|
|
62949
63077
|
async remove(projectRoot, storyId) {
|
|
62950
63078
|
validateStoryId(storyId);
|
|
62951
|
-
const worktreePath =
|
|
63079
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62952
63080
|
const branchName = `nax/${storyId}`;
|
|
62953
63081
|
try {
|
|
62954
63082
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -63532,6 +63660,8 @@ function resolveMaxAttemptsOutcome(failureCategory) {
|
|
|
63532
63660
|
return "pause";
|
|
63533
63661
|
case "runtime-crash":
|
|
63534
63662
|
return "pause";
|
|
63663
|
+
case "review-incomplete":
|
|
63664
|
+
return "pause";
|
|
63535
63665
|
case "session-failure":
|
|
63536
63666
|
case "tests-failing":
|
|
63537
63667
|
case "full-suite-gate-exhausted":
|
|
@@ -63770,10 +63900,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
63770
63900
|
});
|
|
63771
63901
|
|
|
63772
63902
|
// src/execution/pipeline-result-handler.ts
|
|
63773
|
-
import { join as
|
|
63903
|
+
import { join as join81 } from "path";
|
|
63774
63904
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
63775
63905
|
const logger = getSafeLogger();
|
|
63776
|
-
const worktreePath =
|
|
63906
|
+
const worktreePath = join81(projectRoot, ".nax-wt", storyId);
|
|
63777
63907
|
try {
|
|
63778
63908
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
63779
63909
|
cwd: projectRoot,
|
|
@@ -63990,7 +64120,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
63990
64120
|
|
|
63991
64121
|
// src/execution/iteration-runner.ts
|
|
63992
64122
|
import { existsSync as existsSync32 } from "fs";
|
|
63993
|
-
import { join as
|
|
64123
|
+
import { join as join82 } from "path";
|
|
63994
64124
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
63995
64125
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
63996
64126
|
if (ctx.dryRun) {
|
|
@@ -64015,7 +64145,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64015
64145
|
const storyStartTime = Date.now();
|
|
64016
64146
|
let effectiveWorkdir = ctx.workdir;
|
|
64017
64147
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
64018
|
-
const worktreePath =
|
|
64148
|
+
const worktreePath = join82(ctx.workdir, ".nax-wt", story.id);
|
|
64019
64149
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
64020
64150
|
if (!worktreeExists) {
|
|
64021
64151
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -64035,7 +64165,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64035
64165
|
}
|
|
64036
64166
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
64037
64167
|
const profileOverride = profileOverrideFromConfig(ctx.config);
|
|
64038
|
-
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(
|
|
64168
|
+
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join82(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
|
|
64039
64169
|
let dependencyContext;
|
|
64040
64170
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
64041
64171
|
try {
|
|
@@ -64062,7 +64192,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64062
64192
|
};
|
|
64063
64193
|
}
|
|
64064
64194
|
}
|
|
64065
|
-
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ?
|
|
64195
|
+
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;
|
|
64066
64196
|
const pipelineContext = {
|
|
64067
64197
|
config: effectiveConfig,
|
|
64068
64198
|
rootConfig: ctx.config,
|
|
@@ -64265,7 +64395,7 @@ __export(exports_parallel_worker, {
|
|
|
64265
64395
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
64266
64396
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
64267
64397
|
});
|
|
64268
|
-
import { join as
|
|
64398
|
+
import { join as join83 } from "path";
|
|
64269
64399
|
function buildWorktreePipelineContext(base, _story) {
|
|
64270
64400
|
return { ...base, prd: structuredClone(base.prd) };
|
|
64271
64401
|
}
|
|
@@ -64288,7 +64418,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
64288
64418
|
story,
|
|
64289
64419
|
stories: [story],
|
|
64290
64420
|
projectDir: context.projectDir,
|
|
64291
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
64421
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join83(worktreePath, story.workdir) : worktreePath),
|
|
64292
64422
|
worktreeDependencyContext: dependencyContext,
|
|
64293
64423
|
routing,
|
|
64294
64424
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -65188,7 +65318,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
65188
65318
|
var init_status_file = () => {};
|
|
65189
65319
|
|
|
65190
65320
|
// src/execution/status-writer.ts
|
|
65191
|
-
import { join as
|
|
65321
|
+
import { join as join84 } from "path";
|
|
65192
65322
|
|
|
65193
65323
|
class StatusWriter {
|
|
65194
65324
|
statusFile;
|
|
@@ -65307,7 +65437,7 @@ class StatusWriter {
|
|
|
65307
65437
|
if (!this._prd)
|
|
65308
65438
|
return;
|
|
65309
65439
|
const safeLogger = getSafeLogger();
|
|
65310
|
-
const featureStatusPath =
|
|
65440
|
+
const featureStatusPath = join84(featureDir, "status.json");
|
|
65311
65441
|
const write = async () => {
|
|
65312
65442
|
try {
|
|
65313
65443
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -65741,7 +65871,7 @@ __export(exports_run_initialization, {
|
|
|
65741
65871
|
initializeRun: () => initializeRun,
|
|
65742
65872
|
_reconcileDeps: () => _reconcileDeps
|
|
65743
65873
|
});
|
|
65744
|
-
import { join as
|
|
65874
|
+
import { join as join85 } from "path";
|
|
65745
65875
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
65746
65876
|
const logger = getSafeLogger();
|
|
65747
65877
|
let reconciledCount = 0;
|
|
@@ -65758,7 +65888,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
65758
65888
|
});
|
|
65759
65889
|
continue;
|
|
65760
65890
|
}
|
|
65761
|
-
const effectiveWorkdir = story.workdir ?
|
|
65891
|
+
const effectiveWorkdir = story.workdir ? join85(workdir, story.workdir) : workdir;
|
|
65762
65892
|
try {
|
|
65763
65893
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
65764
65894
|
if (!reviewResult.success) {
|
|
@@ -95589,7 +95719,7 @@ __export(exports_curator, {
|
|
|
95589
95719
|
});
|
|
95590
95720
|
import { readdirSync as readdirSync8 } from "fs";
|
|
95591
95721
|
import { unlink as unlink4 } from "fs/promises";
|
|
95592
|
-
import { basename as basename15, join as
|
|
95722
|
+
import { basename as basename15, join as join87 } from "path";
|
|
95593
95723
|
function getProjectKey(config2, projectDir) {
|
|
95594
95724
|
return config2.name?.trim() || basename15(projectDir);
|
|
95595
95725
|
}
|
|
@@ -95672,7 +95802,7 @@ async function curatorStatus(options) {
|
|
|
95672
95802
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95673
95803
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95674
95804
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95675
|
-
const runsDir =
|
|
95805
|
+
const runsDir = join87(outputDir, "runs");
|
|
95676
95806
|
const runIds = listRunIds(runsDir);
|
|
95677
95807
|
let runId;
|
|
95678
95808
|
if (options.run) {
|
|
@@ -95689,8 +95819,8 @@ async function curatorStatus(options) {
|
|
|
95689
95819
|
runId = runIds[runIds.length - 1];
|
|
95690
95820
|
}
|
|
95691
95821
|
console.log(`Run: ${runId}`);
|
|
95692
|
-
const runDir =
|
|
95693
|
-
const observationsPath =
|
|
95822
|
+
const runDir = join87(runsDir, runId);
|
|
95823
|
+
const observationsPath = join87(runDir, "observations.jsonl");
|
|
95694
95824
|
const observations = await parseObservations(observationsPath);
|
|
95695
95825
|
const counts = new Map;
|
|
95696
95826
|
for (const obs of observations) {
|
|
@@ -95700,7 +95830,7 @@ async function curatorStatus(options) {
|
|
|
95700
95830
|
for (const [kind, count] of counts.entries()) {
|
|
95701
95831
|
console.log(` ${kind}: ${count}`);
|
|
95702
95832
|
}
|
|
95703
|
-
const proposalsPath =
|
|
95833
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
95704
95834
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
95705
95835
|
if (proposalText !== null) {
|
|
95706
95836
|
console.log("");
|
|
@@ -95714,8 +95844,8 @@ async function curatorCommit(options) {
|
|
|
95714
95844
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95715
95845
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95716
95846
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95717
|
-
const runDir =
|
|
95718
|
-
const proposalsPath =
|
|
95847
|
+
const runDir = join87(outputDir, "runs", options.runId);
|
|
95848
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
95719
95849
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
95720
95850
|
if (proposalText === null) {
|
|
95721
95851
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -95731,7 +95861,7 @@ async function curatorCommit(options) {
|
|
|
95731
95861
|
const dropFileState = new Map;
|
|
95732
95862
|
const skippedDrops = new Set;
|
|
95733
95863
|
for (const drop2 of drops) {
|
|
95734
|
-
const targetPath =
|
|
95864
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
95735
95865
|
if (!dropFileState.has(targetPath)) {
|
|
95736
95866
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
95737
95867
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -95765,7 +95895,7 @@ async function curatorCommit(options) {
|
|
|
95765
95895
|
if (skippedDrops.has(drop2)) {
|
|
95766
95896
|
continue;
|
|
95767
95897
|
}
|
|
95768
|
-
const targetPath =
|
|
95898
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
95769
95899
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
95770
95900
|
const filtered = filterDropContent(existing, drop2.description);
|
|
95771
95901
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -95774,7 +95904,7 @@ async function curatorCommit(options) {
|
|
|
95774
95904
|
}
|
|
95775
95905
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
95776
95906
|
for (const add2 of adds) {
|
|
95777
|
-
const targetPath =
|
|
95907
|
+
const targetPath = join87(resolved.projectDir, add2.canonicalFile);
|
|
95778
95908
|
const content = buildAddContent(add2);
|
|
95779
95909
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
95780
95910
|
modifiedFiles.add(targetPath);
|
|
@@ -95811,7 +95941,7 @@ async function curatorDryrun(options) {
|
|
|
95811
95941
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95812
95942
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95813
95943
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95814
|
-
const runsDir =
|
|
95944
|
+
const runsDir = join87(outputDir, "runs");
|
|
95815
95945
|
const runIds = listRunIds(runsDir);
|
|
95816
95946
|
if (runIds.length === 0) {
|
|
95817
95947
|
console.log("No runs found.");
|
|
@@ -95822,7 +95952,7 @@ async function curatorDryrun(options) {
|
|
|
95822
95952
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
95823
95953
|
return;
|
|
95824
95954
|
}
|
|
95825
|
-
const observationsPath =
|
|
95955
|
+
const observationsPath = join87(runsDir, runId, "observations.jsonl");
|
|
95826
95956
|
const observations = await parseObservations(observationsPath);
|
|
95827
95957
|
const thresholds = getThresholds(config2);
|
|
95828
95958
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -95863,12 +95993,12 @@ async function curatorGc(options) {
|
|
|
95863
95993
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
95864
95994
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95865
95995
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95866
|
-
const perRunsDir =
|
|
95996
|
+
const perRunsDir = join87(outputDir, "runs");
|
|
95867
95997
|
for (const runId of uniqueRunIds) {
|
|
95868
95998
|
if (!keepSet.has(runId)) {
|
|
95869
|
-
const runDir =
|
|
95870
|
-
await _curatorCmdDeps.removeFile(
|
|
95871
|
-
await _curatorCmdDeps.removeFile(
|
|
95999
|
+
const runDir = join87(perRunsDir, runId);
|
|
96000
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "observations.jsonl"));
|
|
96001
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "curator-proposals.md"));
|
|
95872
96002
|
}
|
|
95873
96003
|
}
|
|
95874
96004
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -95913,7 +96043,7 @@ var init_curator2 = __esm(() => {
|
|
|
95913
96043
|
init_source();
|
|
95914
96044
|
import { existsSync as existsSync35, mkdirSync as mkdirSync7 } from "fs";
|
|
95915
96045
|
import { homedir as homedir3 } from "os";
|
|
95916
|
-
import { basename as basename16, join as
|
|
96046
|
+
import { basename as basename16, join as join88 } from "path";
|
|
95917
96047
|
|
|
95918
96048
|
// node_modules/commander/esm.mjs
|
|
95919
96049
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -97037,6 +97167,7 @@ async function runsShowCommand(options) {
|
|
|
97037
97167
|
init_prompts2();
|
|
97038
97168
|
init_init2();
|
|
97039
97169
|
init_setup();
|
|
97170
|
+
init_setup_write();
|
|
97040
97171
|
|
|
97041
97172
|
// src/cli/plugins.ts
|
|
97042
97173
|
init_paths();
|
|
@@ -97112,7 +97243,7 @@ init_source();
|
|
|
97112
97243
|
init_loader();
|
|
97113
97244
|
init_generator2();
|
|
97114
97245
|
import { existsSync as existsSync24 } from "fs";
|
|
97115
|
-
import { join as
|
|
97246
|
+
import { join as join63 } from "path";
|
|
97116
97247
|
var VALID_AGENTS = ["claude", "codex", "opencode", "cursor", "windsurf", "aider", "gemini"];
|
|
97117
97248
|
async function generateCommand(options) {
|
|
97118
97249
|
const workdir = options.dir ?? process.cwd();
|
|
@@ -97155,7 +97286,7 @@ async function generateCommand(options) {
|
|
|
97155
97286
|
return;
|
|
97156
97287
|
}
|
|
97157
97288
|
if (options.package) {
|
|
97158
|
-
const packageDir =
|
|
97289
|
+
const packageDir = join63(workdir, options.package);
|
|
97159
97290
|
if (dryRun) {
|
|
97160
97291
|
console.log(source_default.yellow("\u26A0 Dry run \u2014 no files will be written"));
|
|
97161
97292
|
}
|
|
@@ -97175,8 +97306,8 @@ async function generateCommand(options) {
|
|
|
97175
97306
|
process.exit(1);
|
|
97176
97307
|
return;
|
|
97177
97308
|
}
|
|
97178
|
-
const contextPath = options.context ?
|
|
97179
|
-
const outputDir = options.output ?
|
|
97309
|
+
const contextPath = options.context ? join63(workdir, options.context) : join63(workdir, ".nax/context.md");
|
|
97310
|
+
const outputDir = options.output ? join63(workdir, options.output) : workdir;
|
|
97180
97311
|
const autoInject = !options.noAutoInject;
|
|
97181
97312
|
if (!existsSync24(contextPath)) {
|
|
97182
97313
|
console.error(source_default.red(`\u2717 Context file not found: ${contextPath}`));
|
|
@@ -97282,7 +97413,7 @@ async function generateCommand(options) {
|
|
|
97282
97413
|
// src/cli/config-display.ts
|
|
97283
97414
|
init_loader();
|
|
97284
97415
|
import { existsSync as existsSync26 } from "fs";
|
|
97285
|
-
import { join as
|
|
97416
|
+
import { join as join65 } from "path";
|
|
97286
97417
|
|
|
97287
97418
|
// src/cli/config-descriptions.ts
|
|
97288
97419
|
var FIELD_DESCRIPTIONS = {
|
|
@@ -97535,7 +97666,7 @@ function deepEqual(a, b) {
|
|
|
97535
97666
|
init_defaults();
|
|
97536
97667
|
init_loader();
|
|
97537
97668
|
import { existsSync as existsSync25 } from "fs";
|
|
97538
|
-
import { join as
|
|
97669
|
+
import { join as join64 } from "path";
|
|
97539
97670
|
async function loadConfigFile(path19) {
|
|
97540
97671
|
if (!existsSync25(path19))
|
|
97541
97672
|
return null;
|
|
@@ -97557,7 +97688,7 @@ async function loadProjectConfig() {
|
|
|
97557
97688
|
const projectDir = findProjectDir();
|
|
97558
97689
|
if (!projectDir)
|
|
97559
97690
|
return null;
|
|
97560
|
-
const projectPath =
|
|
97691
|
+
const projectPath = join64(projectDir, "config.json");
|
|
97561
97692
|
return await loadConfigFile(projectPath);
|
|
97562
97693
|
}
|
|
97563
97694
|
|
|
@@ -97617,7 +97748,7 @@ async function configCommand(config2, options = {}) {
|
|
|
97617
97748
|
function determineConfigSources() {
|
|
97618
97749
|
const globalPath = globalConfigPath();
|
|
97619
97750
|
const projectDir = findProjectDir();
|
|
97620
|
-
const projectPath = projectDir ?
|
|
97751
|
+
const projectPath = projectDir ? join65(projectDir, "config.json") : null;
|
|
97621
97752
|
return {
|
|
97622
97753
|
global: fileExists(globalPath) ? globalPath : null,
|
|
97623
97754
|
project: projectPath && fileExists(projectPath) ? projectPath : null
|
|
@@ -97766,15 +97897,15 @@ init_paths();
|
|
|
97766
97897
|
init_profile();
|
|
97767
97898
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
97768
97899
|
import { readdirSync as readdirSync5 } from "fs";
|
|
97769
|
-
import { join as
|
|
97900
|
+
import { join as join66 } from "path";
|
|
97770
97901
|
var _profileCLIDeps = {
|
|
97771
97902
|
env: process.env
|
|
97772
97903
|
};
|
|
97773
97904
|
var SENSITIVE_KEY_PATTERN = /key|token|secret|password|credential/i;
|
|
97774
97905
|
var VAR_PATTERN = /\$[A-Za-z_][A-Za-z0-9_]*/;
|
|
97775
97906
|
async function profileListCommand(startDir) {
|
|
97776
|
-
const globalProfilesDir =
|
|
97777
|
-
const projectProfilesDir =
|
|
97907
|
+
const globalProfilesDir = join66(globalConfigDir(), "profiles");
|
|
97908
|
+
const projectProfilesDir = join66(projectConfigDir(startDir), "profiles");
|
|
97778
97909
|
const globalProfiles = scanProfileDir(globalProfilesDir);
|
|
97779
97910
|
const projectProfiles = scanProfileDir(projectProfilesDir);
|
|
97780
97911
|
const activeProfile = await resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
@@ -97833,7 +97964,7 @@ function maskProfileValues(obj) {
|
|
|
97833
97964
|
return result;
|
|
97834
97965
|
}
|
|
97835
97966
|
async function profileUseCommand(profileName, startDir) {
|
|
97836
|
-
const configPath =
|
|
97967
|
+
const configPath = join66(projectConfigDir(startDir), "config.json");
|
|
97837
97968
|
const configFile = Bun.file(configPath);
|
|
97838
97969
|
let existing = {};
|
|
97839
97970
|
if (await configFile.exists()) {
|
|
@@ -97852,8 +97983,8 @@ async function profileCurrentCommand(startDir) {
|
|
|
97852
97983
|
return resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
97853
97984
|
}
|
|
97854
97985
|
async function profileCreateCommand(profileName, startDir) {
|
|
97855
|
-
const profilesDir =
|
|
97856
|
-
const profilePath =
|
|
97986
|
+
const profilesDir = join66(projectConfigDir(startDir), "profiles");
|
|
97987
|
+
const profilePath = join66(profilesDir, `${profileName}.json`);
|
|
97857
97988
|
const profileFile = Bun.file(profilePath);
|
|
97858
97989
|
if (await profileFile.exists()) {
|
|
97859
97990
|
throw new Error(`Profile "${profileName}" already exists at ${profilePath}`);
|
|
@@ -97975,7 +98106,7 @@ async function contextInspectCommand(options) {
|
|
|
97975
98106
|
init_canonical_loader();
|
|
97976
98107
|
init_errors();
|
|
97977
98108
|
import { mkdir as mkdir11 } from "fs/promises";
|
|
97978
|
-
import { basename as basename12, join as
|
|
98109
|
+
import { basename as basename12, join as join67 } from "path";
|
|
97979
98110
|
var _rulesCLIDeps = {
|
|
97980
98111
|
readFile: async (path19) => Bun.file(path19).text(),
|
|
97981
98112
|
writeFile: async (path19, content) => {
|
|
@@ -97984,7 +98115,7 @@ var _rulesCLIDeps = {
|
|
|
97984
98115
|
fileExists: async (path19) => Bun.file(path19).exists(),
|
|
97985
98116
|
globInDir: (dir) => {
|
|
97986
98117
|
try {
|
|
97987
|
-
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) =>
|
|
98118
|
+
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join67(dir, f));
|
|
97988
98119
|
} catch {
|
|
97989
98120
|
return [];
|
|
97990
98121
|
}
|
|
@@ -98033,7 +98164,7 @@ ${r.content}`).join(`
|
|
|
98033
98164
|
`);
|
|
98034
98165
|
const shimContent = `${header + body}
|
|
98035
98166
|
`;
|
|
98036
|
-
const shimPath =
|
|
98167
|
+
const shimPath = join67(workdir, shimFileName);
|
|
98037
98168
|
if (options.dryRun) {
|
|
98038
98169
|
console.log(`[dry-run] Would write ${shimPath} (${shimContent.length} bytes)`);
|
|
98039
98170
|
return;
|
|
@@ -98062,14 +98193,14 @@ function neutralizeContent(content) {
|
|
|
98062
98193
|
}
|
|
98063
98194
|
async function collectMigrationSources(workdir) {
|
|
98064
98195
|
const sources = [];
|
|
98065
|
-
const claudeMdPath =
|
|
98196
|
+
const claudeMdPath = join67(workdir, "CLAUDE.md");
|
|
98066
98197
|
if (await _rulesCLIDeps.fileExists(claudeMdPath)) {
|
|
98067
98198
|
const content = await _rulesCLIDeps.readFile(claudeMdPath);
|
|
98068
98199
|
if (content.trim()) {
|
|
98069
98200
|
sources.push({ sourcePath: claudeMdPath, targetFileName: "project-conventions.md", content });
|
|
98070
98201
|
}
|
|
98071
98202
|
}
|
|
98072
|
-
const rulesDir =
|
|
98203
|
+
const rulesDir = join67(workdir, ".claude", "rules");
|
|
98073
98204
|
const ruleFiles = _rulesCLIDeps.globInDir(rulesDir);
|
|
98074
98205
|
for (const filePath of ruleFiles) {
|
|
98075
98206
|
try {
|
|
@@ -98089,7 +98220,7 @@ async function rulesMigrateCommand(options) {
|
|
|
98089
98220
|
console.log("[WARN] No source files found (checked CLAUDE.md and .claude/rules/*.md). Nothing to migrate.");
|
|
98090
98221
|
return;
|
|
98091
98222
|
}
|
|
98092
|
-
const targetDir =
|
|
98223
|
+
const targetDir = join67(workdir, CANONICAL_RULES_DIR);
|
|
98093
98224
|
if (!options.dryRun) {
|
|
98094
98225
|
try {
|
|
98095
98226
|
await _rulesCLIDeps.mkdir(targetDir);
|
|
@@ -98100,7 +98231,7 @@ async function rulesMigrateCommand(options) {
|
|
|
98100
98231
|
let written = 0;
|
|
98101
98232
|
let skipped = 0;
|
|
98102
98233
|
for (const { sourcePath, targetFileName, content } of sources) {
|
|
98103
|
-
const targetPath =
|
|
98234
|
+
const targetPath = join67(targetDir, targetFileName);
|
|
98104
98235
|
if (!force && !options.dryRun && await _rulesCLIDeps.fileExists(targetPath)) {
|
|
98105
98236
|
console.log(`[skip] ${targetFileName} already exists (use --force to overwrite)`);
|
|
98106
98237
|
skipped++;
|
|
@@ -98139,7 +98270,7 @@ function collectCanonicalRuleRoots(workdir) {
|
|
|
98139
98270
|
const packageRel = normalized.slice(0, idx);
|
|
98140
98271
|
if (!packageRel)
|
|
98141
98272
|
continue;
|
|
98142
|
-
roots.add(
|
|
98273
|
+
roots.add(join67(workdir, packageRel));
|
|
98143
98274
|
}
|
|
98144
98275
|
return [...roots].sort();
|
|
98145
98276
|
}
|
|
@@ -98191,7 +98322,7 @@ init_logger2();
|
|
|
98191
98322
|
init_detect2();
|
|
98192
98323
|
init_workspace();
|
|
98193
98324
|
init_common();
|
|
98194
|
-
import { join as
|
|
98325
|
+
import { join as join68 } from "path";
|
|
98195
98326
|
function resolveEffective(detected, configPatterns) {
|
|
98196
98327
|
if (configPatterns !== undefined)
|
|
98197
98328
|
return "config";
|
|
@@ -98276,7 +98407,7 @@ async function detectCommand(options) {
|
|
|
98276
98407
|
const rootDetected = detectionMap[""] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98277
98408
|
const pkgEntries = await Promise.all(packageDirs.map(async (dir) => {
|
|
98278
98409
|
const det = detectionMap[dir] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98279
|
-
const pkgConfigPath =
|
|
98410
|
+
const pkgConfigPath = join68(workdir, ".nax", "mono", dir, "config.json");
|
|
98280
98411
|
const pkgRaw = await loadRawConfig(pkgConfigPath);
|
|
98281
98412
|
const pkgPatterns = deepGet(pkgRaw, TEST_PATTERNS_KEY);
|
|
98282
98413
|
const effective = Array.isArray(pkgPatterns) ? pkgPatterns : undefined;
|
|
@@ -98330,13 +98461,13 @@ async function detectCommand(options) {
|
|
|
98330
98461
|
if (rootDetected.confidence === "empty") {
|
|
98331
98462
|
console.log(source_default.yellow(" root: skipped (empty detection)"));
|
|
98332
98463
|
} else {
|
|
98333
|
-
const rootConfigPath =
|
|
98464
|
+
const rootConfigPath = join68(workdir, ".nax", "config.json");
|
|
98334
98465
|
try {
|
|
98335
98466
|
const status = await applyToConfig(rootConfigPath, rootDetected.patterns, options.force ?? false);
|
|
98336
98467
|
if (status === "skipped") {
|
|
98337
98468
|
console.log(source_default.dim(" root: skipped (testFilePatterns already set; use --force to overwrite)"));
|
|
98338
98469
|
} else {
|
|
98339
|
-
console.log(source_default.green(` root: ${status} \u2192 ${
|
|
98470
|
+
console.log(source_default.green(` root: ${status} \u2192 ${join68(".nax", "config.json")}`));
|
|
98340
98471
|
}
|
|
98341
98472
|
} catch (err) {
|
|
98342
98473
|
console.error(source_default.red(` root: write failed \u2014 ${err.message}`));
|
|
@@ -98349,13 +98480,13 @@ async function detectCommand(options) {
|
|
|
98349
98480
|
console.log(source_default.dim(` ${dir}: skipped (empty detection)`));
|
|
98350
98481
|
continue;
|
|
98351
98482
|
}
|
|
98352
|
-
const pkgConfigPath =
|
|
98483
|
+
const pkgConfigPath = join68(workdir, ".nax", "mono", dir, "config.json");
|
|
98353
98484
|
try {
|
|
98354
98485
|
const status = await applyToConfig(pkgConfigPath, det.patterns, options.force ?? false);
|
|
98355
98486
|
if (status === "skipped") {
|
|
98356
98487
|
console.log(source_default.dim(` ${dir}: skipped (already set)`));
|
|
98357
98488
|
} else {
|
|
98358
|
-
console.log(source_default.green(` ${dir}: ${status} \u2192 ${
|
|
98489
|
+
console.log(source_default.green(` ${dir}: ${status} \u2192 ${join68(".nax", "mono", dir, "config.json")}`));
|
|
98359
98490
|
}
|
|
98360
98491
|
} catch (err) {
|
|
98361
98492
|
console.error(source_default.red(` ${dir}: write failed \u2014 ${err.message}`));
|
|
@@ -98373,19 +98504,19 @@ async function detectCommand(options) {
|
|
|
98373
98504
|
// src/commands/logs.ts
|
|
98374
98505
|
init_common();
|
|
98375
98506
|
import { existsSync as existsSync28 } from "fs";
|
|
98376
|
-
import { join as
|
|
98507
|
+
import { join as join71 } from "path";
|
|
98377
98508
|
|
|
98378
98509
|
// src/commands/logs-formatter.ts
|
|
98379
98510
|
init_source();
|
|
98380
98511
|
init_formatter();
|
|
98381
98512
|
import { readdirSync as readdirSync7 } from "fs";
|
|
98382
|
-
import { join as
|
|
98513
|
+
import { join as join70 } from "path";
|
|
98383
98514
|
|
|
98384
98515
|
// src/commands/logs-reader.ts
|
|
98385
98516
|
init_paths3();
|
|
98386
98517
|
import { existsSync as existsSync27, readdirSync as readdirSync6 } from "fs";
|
|
98387
98518
|
import { readdir as readdir3 } from "fs/promises";
|
|
98388
|
-
import { join as
|
|
98519
|
+
import { join as join69 } from "path";
|
|
98389
98520
|
var _logsReaderDeps = {
|
|
98390
98521
|
getRunsDir
|
|
98391
98522
|
};
|
|
@@ -98399,7 +98530,7 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
98399
98530
|
}
|
|
98400
98531
|
let matched = null;
|
|
98401
98532
|
for (const entry of entries) {
|
|
98402
|
-
const metaPath =
|
|
98533
|
+
const metaPath = join69(runsDir, entry, "meta.json");
|
|
98403
98534
|
try {
|
|
98404
98535
|
const meta3 = await Bun.file(metaPath).json();
|
|
98405
98536
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -98421,14 +98552,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
98421
98552
|
return null;
|
|
98422
98553
|
}
|
|
98423
98554
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
98424
|
-
return
|
|
98555
|
+
return join69(matched.eventsDir, specificFile ?? files[0]);
|
|
98425
98556
|
}
|
|
98426
98557
|
async function selectRunFile(runsDir) {
|
|
98427
98558
|
const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
98428
98559
|
if (files.length === 0) {
|
|
98429
98560
|
return null;
|
|
98430
98561
|
}
|
|
98431
|
-
return
|
|
98562
|
+
return join69(runsDir, files[0]);
|
|
98432
98563
|
}
|
|
98433
98564
|
async function extractRunSummary(filePath) {
|
|
98434
98565
|
const file3 = Bun.file(filePath);
|
|
@@ -98514,7 +98645,7 @@ Runs:
|
|
|
98514
98645
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
98515
98646
|
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"));
|
|
98516
98647
|
for (const file3 of files) {
|
|
98517
|
-
const filePath =
|
|
98648
|
+
const filePath = join70(runsDir, file3);
|
|
98518
98649
|
const summary = await extractRunSummary(filePath);
|
|
98519
98650
|
const timestamp = file3.replace(".jsonl", "");
|
|
98520
98651
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -98628,7 +98759,7 @@ async function logsCommand(options) {
|
|
|
98628
98759
|
return;
|
|
98629
98760
|
}
|
|
98630
98761
|
const resolved = resolveProject({ dir: options.dir });
|
|
98631
|
-
const naxDir =
|
|
98762
|
+
const naxDir = join71(resolved.projectDir, ".nax");
|
|
98632
98763
|
const configPath = resolved.configPath;
|
|
98633
98764
|
const configFile = Bun.file(configPath);
|
|
98634
98765
|
const config2 = await configFile.json();
|
|
@@ -98636,8 +98767,8 @@ async function logsCommand(options) {
|
|
|
98636
98767
|
if (!featureName) {
|
|
98637
98768
|
throw new Error("No feature specified in config.json");
|
|
98638
98769
|
}
|
|
98639
|
-
const featureDir =
|
|
98640
|
-
const runsDir =
|
|
98770
|
+
const featureDir = join71(naxDir, "features", featureName);
|
|
98771
|
+
const runsDir = join71(featureDir, "runs");
|
|
98641
98772
|
if (!existsSync28(runsDir)) {
|
|
98642
98773
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
98643
98774
|
}
|
|
@@ -98663,7 +98794,7 @@ init_prd();
|
|
|
98663
98794
|
init_precheck();
|
|
98664
98795
|
init_common();
|
|
98665
98796
|
import { existsSync as existsSync29 } from "fs";
|
|
98666
|
-
import { join as
|
|
98797
|
+
import { join as join72 } from "path";
|
|
98667
98798
|
async function precheckCommand(options) {
|
|
98668
98799
|
const resolved = resolveProject({
|
|
98669
98800
|
dir: options.dir,
|
|
@@ -98685,9 +98816,9 @@ async function precheckCommand(options) {
|
|
|
98685
98816
|
process.exit(1);
|
|
98686
98817
|
}
|
|
98687
98818
|
}
|
|
98688
|
-
const naxDir =
|
|
98689
|
-
const featureDir =
|
|
98690
|
-
const prdPath =
|
|
98819
|
+
const naxDir = join72(resolved.projectDir, ".nax");
|
|
98820
|
+
const featureDir = join72(naxDir, "features", featureName);
|
|
98821
|
+
const prdPath = join72(featureDir, "prd.json");
|
|
98691
98822
|
if (!existsSync29(featureDir)) {
|
|
98692
98823
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
98693
98824
|
process.exit(1);
|
|
@@ -98710,7 +98841,7 @@ async function precheckCommand(options) {
|
|
|
98710
98841
|
init_source();
|
|
98711
98842
|
init_paths3();
|
|
98712
98843
|
import { readdir as readdir4 } from "fs/promises";
|
|
98713
|
-
import { join as
|
|
98844
|
+
import { join as join73 } from "path";
|
|
98714
98845
|
var DEFAULT_LIMIT = 20;
|
|
98715
98846
|
var _runsCmdDeps = {
|
|
98716
98847
|
getRunsDir
|
|
@@ -98765,7 +98896,7 @@ async function runsCommand(options = {}) {
|
|
|
98765
98896
|
}
|
|
98766
98897
|
const rows = [];
|
|
98767
98898
|
for (const entry of entries) {
|
|
98768
|
-
const metaPath =
|
|
98899
|
+
const metaPath = join73(runsDir, entry, "meta.json");
|
|
98769
98900
|
let meta3;
|
|
98770
98901
|
try {
|
|
98771
98902
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -98842,7 +98973,7 @@ async function runsCommand(options = {}) {
|
|
|
98842
98973
|
|
|
98843
98974
|
// src/commands/unlock.ts
|
|
98844
98975
|
init_source();
|
|
98845
|
-
import { join as
|
|
98976
|
+
import { join as join74 } from "path";
|
|
98846
98977
|
function isProcessAlive2(pid) {
|
|
98847
98978
|
try {
|
|
98848
98979
|
process.kill(pid, 0);
|
|
@@ -98857,7 +98988,7 @@ function formatLockAge(ageMs) {
|
|
|
98857
98988
|
}
|
|
98858
98989
|
async function unlockCommand(options) {
|
|
98859
98990
|
const workdir = options.dir ?? process.cwd();
|
|
98860
|
-
const lockPath =
|
|
98991
|
+
const lockPath = join74(workdir, "nax.lock");
|
|
98861
98992
|
const lockFile = Bun.file(lockPath);
|
|
98862
98993
|
const exists = await lockFile.exists();
|
|
98863
98994
|
if (!exists) {
|
|
@@ -107295,7 +107426,7 @@ Next: nax generate --package ${options.package}`));
|
|
|
107295
107426
|
}
|
|
107296
107427
|
return;
|
|
107297
107428
|
}
|
|
107298
|
-
const naxDir =
|
|
107429
|
+
const naxDir = join88(workdir, ".nax");
|
|
107299
107430
|
if (existsSync35(naxDir) && !options.force) {
|
|
107300
107431
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
107301
107432
|
return;
|
|
@@ -107324,11 +107455,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
107324
107455
|
}
|
|
107325
107456
|
}
|
|
107326
107457
|
}
|
|
107327
|
-
mkdirSync7(
|
|
107328
|
-
mkdirSync7(
|
|
107458
|
+
mkdirSync7(join88(naxDir, "features"), { recursive: true });
|
|
107459
|
+
mkdirSync7(join88(naxDir, "hooks"), { recursive: true });
|
|
107329
107460
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
107330
|
-
await Bun.write(
|
|
107331
|
-
await Bun.write(
|
|
107461
|
+
await Bun.write(join88(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
|
|
107462
|
+
await Bun.write(join88(naxDir, "hooks.json"), JSON.stringify({
|
|
107332
107463
|
hooks: {
|
|
107333
107464
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
107334
107465
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -107336,12 +107467,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
107336
107467
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
107337
107468
|
}
|
|
107338
107469
|
}, null, 2));
|
|
107339
|
-
await Bun.write(
|
|
107470
|
+
await Bun.write(join88(naxDir, ".gitignore"), `# nax temp files
|
|
107340
107471
|
*.tmp
|
|
107341
107472
|
.paused.json
|
|
107342
107473
|
.nax-verifier-verdict.json
|
|
107343
107474
|
`);
|
|
107344
|
-
await Bun.write(
|
|
107475
|
+
await Bun.write(join88(naxDir, "context.md"), `# Project Context
|
|
107345
107476
|
|
|
107346
107477
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
107347
107478
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -107483,7 +107614,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107483
107614
|
const cliOverrides = {};
|
|
107484
107615
|
const cliProfiles = options.profile ?? [];
|
|
107485
107616
|
const profileOverride = naxDir ? await resolveRunProfileOverride({
|
|
107486
|
-
prdPath:
|
|
107617
|
+
prdPath: join88(naxDir, "features", options.feature, "prd.json"),
|
|
107487
107618
|
projectRoot: workdir,
|
|
107488
107619
|
cliProfile: cliProfiles,
|
|
107489
107620
|
envProfile: process.env.NAX_PROFILE
|
|
@@ -107496,8 +107627,8 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107496
107627
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
107497
107628
|
process.exit(1);
|
|
107498
107629
|
}
|
|
107499
|
-
const featureDir =
|
|
107500
|
-
const prdPath =
|
|
107630
|
+
const featureDir = join88(naxDir, "features", options.feature);
|
|
107631
|
+
const prdPath = join88(featureDir, "prd.json");
|
|
107501
107632
|
if (options.plan && options.from) {
|
|
107502
107633
|
if (existsSync35(prdPath) && !options.force) {
|
|
107503
107634
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
@@ -107519,10 +107650,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107519
107650
|
}
|
|
107520
107651
|
}
|
|
107521
107652
|
try {
|
|
107522
|
-
const planLogDir =
|
|
107653
|
+
const planLogDir = join88(featureDir, "plan");
|
|
107523
107654
|
mkdirSync7(planLogDir, { recursive: true });
|
|
107524
107655
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107525
|
-
const planLogPath =
|
|
107656
|
+
const planLogPath = join88(planLogDir, `${planLogId}.jsonl`);
|
|
107526
107657
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
107527
107658
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
107528
107659
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -107568,10 +107699,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107568
107699
|
resetLogger();
|
|
107569
107700
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
107570
107701
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
107571
|
-
const runsDir =
|
|
107702
|
+
const runsDir = join88(outputDir, "features", options.feature, "runs");
|
|
107572
107703
|
mkdirSync7(runsDir, { recursive: true });
|
|
107573
107704
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107574
|
-
const logFilePath =
|
|
107705
|
+
const logFilePath = join88(runsDir, `${runId}.jsonl`);
|
|
107575
107706
|
const isTTY = process.stdout.isTTY ?? false;
|
|
107576
107707
|
const headlessFlag = options.headless ?? false;
|
|
107577
107708
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -107589,7 +107720,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107589
107720
|
config2.agent.default = options.agent;
|
|
107590
107721
|
}
|
|
107591
107722
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
107592
|
-
const globalNaxDir =
|
|
107723
|
+
const globalNaxDir = join88(homedir3(), ".nax");
|
|
107593
107724
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
107594
107725
|
const eventEmitter = new PipelineEventEmitter;
|
|
107595
107726
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -107609,12 +107740,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107609
107740
|
events: eventEmitter,
|
|
107610
107741
|
ptyOptions: null,
|
|
107611
107742
|
agentStreamEvents,
|
|
107612
|
-
queueFilePath:
|
|
107743
|
+
queueFilePath: join88(workdir, ".queue.txt")
|
|
107613
107744
|
});
|
|
107614
107745
|
} else {
|
|
107615
107746
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
107616
107747
|
}
|
|
107617
|
-
const statusFilePath =
|
|
107748
|
+
const statusFilePath = join88(outputDir, "status.json");
|
|
107618
107749
|
let parallel;
|
|
107619
107750
|
if (options.parallel !== undefined) {
|
|
107620
107751
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -107641,7 +107772,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107641
107772
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
107642
107773
|
agentStreamEvents
|
|
107643
107774
|
});
|
|
107644
|
-
const latestSymlink =
|
|
107775
|
+
const latestSymlink = join88(runsDir, "latest.jsonl");
|
|
107645
107776
|
try {
|
|
107646
107777
|
if (existsSync35(latestSymlink)) {
|
|
107647
107778
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
@@ -107702,9 +107833,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
107702
107833
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
107703
107834
|
process.exit(1);
|
|
107704
107835
|
}
|
|
107705
|
-
const featureDir =
|
|
107836
|
+
const featureDir = join88(naxDir, "features", name);
|
|
107706
107837
|
mkdirSync7(featureDir, { recursive: true });
|
|
107707
|
-
await Bun.write(
|
|
107838
|
+
await Bun.write(join88(featureDir, "spec.md"), `# Feature: ${name}
|
|
107708
107839
|
|
|
107709
107840
|
## Overview
|
|
107710
107841
|
|
|
@@ -107737,7 +107868,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
107737
107868
|
|
|
107738
107869
|
<!-- What this feature explicitly does NOT cover. -->
|
|
107739
107870
|
`);
|
|
107740
|
-
await Bun.write(
|
|
107871
|
+
await Bun.write(join88(featureDir, "progress.txt"), `# Progress: ${name}
|
|
107741
107872
|
|
|
107742
107873
|
Created: ${new Date().toISOString()}
|
|
107743
107874
|
|
|
@@ -107763,7 +107894,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
107763
107894
|
console.error(source_default.red("nax not initialized."));
|
|
107764
107895
|
process.exit(1);
|
|
107765
107896
|
}
|
|
107766
|
-
const featuresDir =
|
|
107897
|
+
const featuresDir = join88(naxDir, "features");
|
|
107767
107898
|
if (!existsSync35(featuresDir)) {
|
|
107768
107899
|
console.log(source_default.dim("No features yet."));
|
|
107769
107900
|
return;
|
|
@@ -107778,7 +107909,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
107778
107909
|
Features:
|
|
107779
107910
|
`));
|
|
107780
107911
|
for (const name of entries) {
|
|
107781
|
-
const prdPath =
|
|
107912
|
+
const prdPath = join88(featuresDir, name, "prd.json");
|
|
107782
107913
|
if (existsSync35(prdPath)) {
|
|
107783
107914
|
const prd = await loadPRD(prdPath);
|
|
107784
107915
|
const c = countStories(prd);
|
|
@@ -107814,10 +107945,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
107814
107945
|
cliOverrides.profile = cliProfiles;
|
|
107815
107946
|
}
|
|
107816
107947
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
107817
|
-
const featureLogDir =
|
|
107948
|
+
const featureLogDir = join88(naxDir, "features", options.feature, "plan");
|
|
107818
107949
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
107819
107950
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107820
|
-
const planLogPath =
|
|
107951
|
+
const planLogPath = join88(featureLogDir, `${planLogId}.jsonl`);
|
|
107821
107952
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
107822
107953
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
107823
107954
|
try {
|