@nathapp/nax 0.70.1 → 0.70.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nax.js +554 -432
- 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) => {
|
|
@@ -45276,7 +45291,7 @@ function attachLoggingSubscriber(bus, runId) {
|
|
|
45276
45291
|
offError();
|
|
45277
45292
|
};
|
|
45278
45293
|
}
|
|
45279
|
-
var
|
|
45294
|
+
var init_logging = __esm(() => {
|
|
45280
45295
|
init_logger2();
|
|
45281
45296
|
});
|
|
45282
45297
|
|
|
@@ -45794,7 +45809,7 @@ var init_idle_watchdog = __esm(() => {
|
|
|
45794
45809
|
// src/runtime/middleware/index.ts
|
|
45795
45810
|
var init_middleware = __esm(() => {
|
|
45796
45811
|
init_cancellation();
|
|
45797
|
-
|
|
45812
|
+
init_logging();
|
|
45798
45813
|
init_agent_stream_logging();
|
|
45799
45814
|
init_idle_watchdog();
|
|
45800
45815
|
});
|
|
@@ -54979,159 +54994,66 @@ var init_non_blocking_fix = __esm(() => {
|
|
|
54979
54994
|
};
|
|
54980
54995
|
});
|
|
54981
54996
|
|
|
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
|
-
|
|
54997
|
+
// src/execution/story-orchestrator/types.ts
|
|
54998
|
+
var EXHAUSTED_EXIT_REASONS, TDD_OP_NAMES, CANONICAL_ORDER, PHASE_KIND_TO_STATE_KEY, STRATEGY_TO_REVALIDATION_PHASES, STRICT_VERDICT_PHASE_NAMES;
|
|
54999
|
+
var init_types9 = __esm(() => {
|
|
55000
|
+
EXHAUSTED_EXIT_REASONS = new Set([
|
|
55001
|
+
"max-attempts-total",
|
|
55002
|
+
"max-attempts-per-strategy",
|
|
55003
|
+
"bail-when",
|
|
55004
|
+
"no-strategy",
|
|
55005
|
+
"agent-gave-up",
|
|
55006
|
+
"validate-short-circuit"
|
|
55007
|
+
]);
|
|
55008
|
+
TDD_OP_NAMES = new Set(["test-writer", "implementer", "verifier"]);
|
|
55009
|
+
CANONICAL_ORDER = [
|
|
55010
|
+
"test-writer",
|
|
55011
|
+
"greenfield-gate",
|
|
55012
|
+
"implementer",
|
|
55013
|
+
"full-suite-gate",
|
|
55014
|
+
"verifier",
|
|
55015
|
+
"verify-scoped",
|
|
55016
|
+
"lint-check",
|
|
55017
|
+
"typecheck-check",
|
|
55018
|
+
"semantic-review",
|
|
55019
|
+
"adversarial-review"
|
|
55020
|
+
];
|
|
55021
|
+
PHASE_KIND_TO_STATE_KEY = {
|
|
55022
|
+
"test-writer": "testWriter",
|
|
55023
|
+
"greenfield-gate": "greenfieldGate",
|
|
55024
|
+
implementer: "implementer",
|
|
55025
|
+
"full-suite-gate": "fullSuiteGate",
|
|
55026
|
+
verifier: "verifier",
|
|
55027
|
+
"verify-scoped": "verifyScoped",
|
|
55028
|
+
"lint-check": "lintCheck",
|
|
55029
|
+
"typecheck-check": "typecheckCheck",
|
|
55030
|
+
"semantic-review": "semanticReview",
|
|
55031
|
+
"adversarial-review": "adversarialReview"
|
|
55032
|
+
};
|
|
55033
|
+
STRATEGY_TO_REVALIDATION_PHASES = {
|
|
55034
|
+
"mechanical-lintfix": ["lint-check"],
|
|
55035
|
+
"mechanical-formatfix": ["lint-check"],
|
|
55036
|
+
"autofix-implementer": ["lint-check", "typecheck-check", "full-suite-gate", "semantic-review", "adversarial-review"],
|
|
55037
|
+
"autofix-test-writer": ["lint-check", "typecheck-check", "full-suite-gate", "adversarial-review"],
|
|
55038
|
+
"full-suite-rectify": [
|
|
55039
|
+
"lint-check",
|
|
55040
|
+
"typecheck-check",
|
|
55041
|
+
"full-suite-gate",
|
|
55042
|
+
"verifier",
|
|
55043
|
+
"verify-scoped",
|
|
55044
|
+
"semantic-review"
|
|
55045
|
+
]
|
|
55046
|
+
};
|
|
55047
|
+
STRICT_VERDICT_PHASE_NAMES = new Set([
|
|
55048
|
+
"full-suite-gate",
|
|
55049
|
+
"verify-scoped",
|
|
55050
|
+
"lint-check",
|
|
55051
|
+
"typecheck-check",
|
|
55052
|
+
"verifier"
|
|
55053
|
+
]);
|
|
55038
55054
|
});
|
|
55039
55055
|
|
|
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
|
-
}
|
|
55056
|
+
// src/execution/story-orchestrator/phase-eval.ts
|
|
55135
55057
|
function phaseExplicitlyPassed(output) {
|
|
55136
55058
|
if (output === null || output === undefined || typeof output !== "object")
|
|
55137
55059
|
return false;
|
|
@@ -55189,34 +55111,6 @@ function gateFailureKeys(gateOutput) {
|
|
|
55189
55111
|
}
|
|
55190
55112
|
return keys;
|
|
55191
55113
|
}
|
|
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
55114
|
function phasesToRevalidate(strategiesRun, allPhases) {
|
|
55221
55115
|
if (!strategiesRun || strategiesRun.length === 0)
|
|
55222
55116
|
return allPhases;
|
|
@@ -55236,6 +55130,111 @@ function orderGateLast(phases) {
|
|
|
55236
55130
|
const gates = phases.filter((p) => p.kind === "full-suite-gate");
|
|
55237
55131
|
return [...rest, ...gates];
|
|
55238
55132
|
}
|
|
55133
|
+
var init_phase_eval = __esm(() => {
|
|
55134
|
+
init_logger2();
|
|
55135
|
+
init_types9();
|
|
55136
|
+
});
|
|
55137
|
+
|
|
55138
|
+
// src/execution/story-orchestrator/phase-state.ts
|
|
55139
|
+
function isSlot(value) {
|
|
55140
|
+
return value !== null && typeof value === "object" && "op" in value && "input" in value && typeof value.op?.kind === "string";
|
|
55141
|
+
}
|
|
55142
|
+
function setPhase(state, kind, slot) {
|
|
55143
|
+
const key = PHASE_KIND_TO_STATE_KEY[kind];
|
|
55144
|
+
if (state[key] !== undefined) {
|
|
55145
|
+
throw new NaxError(`StoryOrchestratorBuilder: addX was called twice for phase "${kind}"`, "ORCHESTRATOR_PHASE_DUPLICATE", { stage: "execution", kind });
|
|
55146
|
+
}
|
|
55147
|
+
state[key] = { kind, slot };
|
|
55148
|
+
}
|
|
55149
|
+
function collectOrderedPhases(state) {
|
|
55150
|
+
return CANONICAL_ORDER.flatMap((kind) => {
|
|
55151
|
+
if (kind === "test-writer" && state.testWriter)
|
|
55152
|
+
return [state.testWriter];
|
|
55153
|
+
if (kind === "greenfield-gate" && state.greenfieldGate)
|
|
55154
|
+
return [state.greenfieldGate];
|
|
55155
|
+
if (kind === "implementer" && state.implementer)
|
|
55156
|
+
return [state.implementer];
|
|
55157
|
+
if (kind === "full-suite-gate" && state.fullSuiteGate)
|
|
55158
|
+
return [state.fullSuiteGate];
|
|
55159
|
+
if (kind === "verifier" && state.verifier)
|
|
55160
|
+
return [state.verifier];
|
|
55161
|
+
if (kind === "verify-scoped" && state.verifyScoped)
|
|
55162
|
+
return [state.verifyScoped];
|
|
55163
|
+
if (kind === "lint-check" && state.lintCheck)
|
|
55164
|
+
return [state.lintCheck];
|
|
55165
|
+
if (kind === "typecheck-check" && state.typecheckCheck)
|
|
55166
|
+
return [state.typecheckCheck];
|
|
55167
|
+
if (kind === "semantic-review" && state.semanticReview)
|
|
55168
|
+
return [state.semanticReview];
|
|
55169
|
+
if (kind === "adversarial-review" && state.adversarialReview)
|
|
55170
|
+
return [state.adversarialReview];
|
|
55171
|
+
return [];
|
|
55172
|
+
});
|
|
55173
|
+
}
|
|
55174
|
+
var init_phase_state = __esm(() => {
|
|
55175
|
+
init_errors();
|
|
55176
|
+
init_types9();
|
|
55177
|
+
});
|
|
55178
|
+
|
|
55179
|
+
// src/execution/story-orchestrator-logging.ts
|
|
55180
|
+
function formatPhaseResultMessage(opName, success2, stage, status) {
|
|
55181
|
+
if (opName === "greenfield-gate") {
|
|
55182
|
+
return success2 ? "Greenfield-gate: pre-existing tests detected (not greenfield) \u2014 proceeding with normal TDD" : "Greenfield-gate: no pre-existing tests \u2014 greenfield run, pausing TDD test-writer";
|
|
55183
|
+
}
|
|
55184
|
+
if (status === "skipped") {
|
|
55185
|
+
return `Phase skipped: ${opName}`;
|
|
55186
|
+
}
|
|
55187
|
+
if (stage === "rectification") {
|
|
55188
|
+
return `Rectification strategy completed: ${opName}`;
|
|
55189
|
+
}
|
|
55190
|
+
return success2 ? `Phase passed: ${opName}` : `Phase failed: ${opName}`;
|
|
55191
|
+
}
|
|
55192
|
+
function buildPhaseOutcomeLogData(storyId, opName, output, durationMs) {
|
|
55193
|
+
if (output === null || output === undefined || typeof output !== "object")
|
|
55194
|
+
return null;
|
|
55195
|
+
const r = output;
|
|
55196
|
+
const success2 = r.success === true || r.passed === true;
|
|
55197
|
+
const findingsCount = Array.isArray(r.normalizedFindings) ? r.normalizedFindings.length : Array.isArray(r.findings) ? r.findings.length : undefined;
|
|
55198
|
+
const status = typeof r.status === "string" ? r.status : undefined;
|
|
55199
|
+
const data = { storyId, phase: opName, durationMs };
|
|
55200
|
+
if (findingsCount !== undefined)
|
|
55201
|
+
data.findingsCount = findingsCount;
|
|
55202
|
+
if (status !== undefined)
|
|
55203
|
+
data.status = status;
|
|
55204
|
+
if (typeof r.failureCategory === "string")
|
|
55205
|
+
data.failureCategory = r.failureCategory;
|
|
55206
|
+
if (typeof r.reviewReason === "string")
|
|
55207
|
+
data.reviewReason = r.reviewReason;
|
|
55208
|
+
return { success: success2, data };
|
|
55209
|
+
}
|
|
55210
|
+
function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTddPhase, stage, progressData = {}) {
|
|
55211
|
+
if (isTddPhase)
|
|
55212
|
+
return;
|
|
55213
|
+
if (opName === "semantic-review" || opName === "adversarial-review")
|
|
55214
|
+
return;
|
|
55215
|
+
const built = buildPhaseOutcomeLogData(storyId, opName, output, durationMs);
|
|
55216
|
+
if (!built)
|
|
55217
|
+
return;
|
|
55218
|
+
const { success: success2 } = built;
|
|
55219
|
+
const data = { ...built.data, ...progressData };
|
|
55220
|
+
const status = typeof built.data.status === "string" ? built.data.status : undefined;
|
|
55221
|
+
const logger = getSafeLogger();
|
|
55222
|
+
const message = formatPhaseResultMessage(opName, success2, stage, status);
|
|
55223
|
+
if (stage === "rectification") {
|
|
55224
|
+
logger?.info("story-orchestrator", message, data);
|
|
55225
|
+
return;
|
|
55226
|
+
}
|
|
55227
|
+
if (success2) {
|
|
55228
|
+
logger?.info("story-orchestrator", message, data);
|
|
55229
|
+
} else {
|
|
55230
|
+
logger?.warn("story-orchestrator", message, data);
|
|
55231
|
+
}
|
|
55232
|
+
}
|
|
55233
|
+
var init_story_orchestrator_logging = __esm(() => {
|
|
55234
|
+
init_logger2();
|
|
55235
|
+
});
|
|
55236
|
+
|
|
55237
|
+
// src/execution/story-orchestrator/review-decision.ts
|
|
55239
55238
|
function toReviewDecisionPayload(opName, output) {
|
|
55240
55239
|
if (output === null || output === undefined || typeof output !== "object")
|
|
55241
55240
|
return null;
|
|
@@ -55351,6 +55350,70 @@ function logUnifiedReviewPhaseResult(storyId, opName, output) {
|
|
|
55351
55350
|
truncated: findingsCount > findingsSummary.length
|
|
55352
55351
|
});
|
|
55353
55352
|
}
|
|
55353
|
+
var init_review_decision = __esm(() => {
|
|
55354
|
+
init_logger2();
|
|
55355
|
+
});
|
|
55356
|
+
|
|
55357
|
+
// src/execution/story-orchestrator/run-phase.ts
|
|
55358
|
+
async function refreshReviewInputForDispatch(opName, input) {
|
|
55359
|
+
if (opName !== "semantic-review" && opName !== "adversarial-review")
|
|
55360
|
+
return input;
|
|
55361
|
+
const i = input;
|
|
55362
|
+
const { _refresh } = i;
|
|
55363
|
+
if (!_refresh || !i.workdir)
|
|
55364
|
+
return input;
|
|
55365
|
+
try {
|
|
55366
|
+
if (opName === "semantic-review") {
|
|
55367
|
+
const { _refresh: _, ...semInput } = input;
|
|
55368
|
+
const fresh2 = await _storyOrchestratorDeps.prepareSemanticReviewInput({
|
|
55369
|
+
workdir: semInput.workdir,
|
|
55370
|
+
projectDir: _refresh.projectDir,
|
|
55371
|
+
storyId: _refresh.storyId,
|
|
55372
|
+
storyGitRef: _refresh.storyGitRef,
|
|
55373
|
+
config: _refresh.config,
|
|
55374
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55375
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55376
|
+
semanticConfig: semInput.semanticConfig
|
|
55377
|
+
});
|
|
55378
|
+
return {
|
|
55379
|
+
...semInput,
|
|
55380
|
+
stat: fresh2.stat,
|
|
55381
|
+
diff: fresh2.diff,
|
|
55382
|
+
excludePatterns: fresh2.excludePatterns,
|
|
55383
|
+
storyGitRef: fresh2.effectiveRef ?? semInput.storyGitRef
|
|
55384
|
+
};
|
|
55385
|
+
}
|
|
55386
|
+
const { _refresh: __, ...advInput } = input;
|
|
55387
|
+
const fresh = await _storyOrchestratorDeps.prepareAdversarialReviewInput({
|
|
55388
|
+
workdir: advInput.workdir,
|
|
55389
|
+
projectDir: _refresh.projectDir,
|
|
55390
|
+
storyId: _refresh.storyId,
|
|
55391
|
+
storyGitRef: _refresh.storyGitRef,
|
|
55392
|
+
config: _refresh.config,
|
|
55393
|
+
naxIgnoreIndex: _refresh.naxIgnoreIndex,
|
|
55394
|
+
resolvedTestPatterns: _refresh.resolvedTestPatterns,
|
|
55395
|
+
adversarialConfig: advInput.adversarialConfig
|
|
55396
|
+
});
|
|
55397
|
+
return {
|
|
55398
|
+
...advInput,
|
|
55399
|
+
stat: fresh.stat,
|
|
55400
|
+
diff: fresh.diff,
|
|
55401
|
+
testInventory: fresh.testInventory,
|
|
55402
|
+
excludePatterns: fresh.excludePatterns,
|
|
55403
|
+
testGlobs: fresh.testGlobs,
|
|
55404
|
+
refExcludePatterns: fresh.refExcludePatterns,
|
|
55405
|
+
storyGitRef: fresh.effectiveRef ?? advInput.storyGitRef
|
|
55406
|
+
};
|
|
55407
|
+
} catch (err) {
|
|
55408
|
+
getSafeLogger()?.warn("story-orchestrator", "review input refresh failed \u2014 dispatching with stale input", {
|
|
55409
|
+
storyId: _refresh.storyId,
|
|
55410
|
+
phase: opName,
|
|
55411
|
+
error: errorMessage(err)
|
|
55412
|
+
});
|
|
55413
|
+
const { _refresh: _stripped, ...fallback } = input;
|
|
55414
|
+
return fallback;
|
|
55415
|
+
}
|
|
55416
|
+
}
|
|
55354
55417
|
async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = false, progress) {
|
|
55355
55418
|
const logger = getSafeLogger();
|
|
55356
55419
|
const opName = slot.op.name;
|
|
@@ -55436,6 +55499,57 @@ function withIncreasingFailuresBail(strategies, enabled, consecutiveIncreases) {
|
|
|
55436
55499
|
}
|
|
55437
55500
|
}));
|
|
55438
55501
|
}
|
|
55502
|
+
var _storyOrchestratorDeps;
|
|
55503
|
+
var init_run_phase = __esm(() => {
|
|
55504
|
+
init_findings();
|
|
55505
|
+
init_logger2();
|
|
55506
|
+
init_operations();
|
|
55507
|
+
init_pipeline();
|
|
55508
|
+
init_review();
|
|
55509
|
+
init_git();
|
|
55510
|
+
init_non_blocking_fix();
|
|
55511
|
+
init_story_orchestrator_logging();
|
|
55512
|
+
init_review_decision();
|
|
55513
|
+
init_types9();
|
|
55514
|
+
_storyOrchestratorDeps = {
|
|
55515
|
+
callOp,
|
|
55516
|
+
runFixCycle,
|
|
55517
|
+
captureGitRef,
|
|
55518
|
+
prepareSemanticReviewInput,
|
|
55519
|
+
prepareAdversarialReviewInput,
|
|
55520
|
+
runNonBlockingFix
|
|
55521
|
+
};
|
|
55522
|
+
});
|
|
55523
|
+
|
|
55524
|
+
// src/execution/story-orchestrator/rectification.ts
|
|
55525
|
+
function shouldSkipPhaseForRectification(phase, state, phaseOutputs) {
|
|
55526
|
+
if (phase.kind !== "full-suite-gate")
|
|
55527
|
+
return false;
|
|
55528
|
+
const verifierName = state.verifier?.slot.op.name;
|
|
55529
|
+
if (!verifierName)
|
|
55530
|
+
return false;
|
|
55531
|
+
return phaseExplicitlyPassed(phaseOutputs[verifierName]);
|
|
55532
|
+
}
|
|
55533
|
+
function gatherRectificationFindings(phaseOutputs, phases, state) {
|
|
55534
|
+
const findings = [];
|
|
55535
|
+
for (const phase of phases) {
|
|
55536
|
+
if (shouldSkipPhaseForRectification(phase, state, phaseOutputs))
|
|
55537
|
+
continue;
|
|
55538
|
+
findings.push(...extractPhaseFindings(phaseOutputs[phase.slot.op.name]));
|
|
55539
|
+
}
|
|
55540
|
+
return findings;
|
|
55541
|
+
}
|
|
55542
|
+
function collectRectificationPhases(state) {
|
|
55543
|
+
return [
|
|
55544
|
+
state.fullSuiteGate,
|
|
55545
|
+
state.verifier,
|
|
55546
|
+
state.verifyScoped,
|
|
55547
|
+
state.lintCheck,
|
|
55548
|
+
state.typecheckCheck,
|
|
55549
|
+
state.semanticReview,
|
|
55550
|
+
state.adversarialReview
|
|
55551
|
+
].filter((phase) => phase !== undefined);
|
|
55552
|
+
}
|
|
55439
55553
|
async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides) {
|
|
55440
55554
|
const rectification = state.rectification;
|
|
55441
55555
|
const baseValidationPhases = collectRectificationPhases(state);
|
|
@@ -55533,7 +55647,15 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides)
|
|
|
55533
55647
|
}
|
|
55534
55648
|
return {};
|
|
55535
55649
|
}
|
|
55650
|
+
var init_rectification = __esm(() => {
|
|
55651
|
+
init_logger2();
|
|
55652
|
+
init_phase_eval();
|
|
55653
|
+
init_phase_eval();
|
|
55654
|
+
init_run_phase();
|
|
55655
|
+
init_types9();
|
|
55656
|
+
});
|
|
55536
55657
|
|
|
55658
|
+
// src/execution/story-orchestrator/execution-plan.ts
|
|
55537
55659
|
class ExecutionPlan {
|
|
55538
55660
|
ctx;
|
|
55539
55661
|
state;
|
|
@@ -55687,18 +55809,29 @@ class ExecutionPlan {
|
|
|
55687
55809
|
} else if (verifierPassedSsot && gateName !== undefined && !phasePassed(gateName, phaseOutputs[gateName], this.ctx.storyId)) {
|
|
55688
55810
|
logger?.warn("story-orchestrator", "Full-suite gate failed but verifier judged story OK \u2014 treating gate failures as unrelated regressions", { storyId: this.ctx.storyId, packageDir: this.ctx.packageDir });
|
|
55689
55811
|
}
|
|
55690
|
-
const
|
|
55812
|
+
const requiredReviewPhaseNames = [
|
|
55813
|
+
this.state.semanticReview?.slot.op.name,
|
|
55814
|
+
this.state.adversarialReview?.slot.op.name
|
|
55815
|
+
].filter((name) => name !== undefined);
|
|
55816
|
+
const missingRequiredReviewPhases = requiredReviewPhaseNames.filter((name) => !(name in phaseOutputs));
|
|
55817
|
+
if (missingRequiredReviewPhases.length > 0) {
|
|
55818
|
+
logger?.warn("story-orchestrator", "Configured review phase(s) never ran \u2014 story cannot pass without review judgment, failing for escalation", { storyId: this.ctx.storyId, packageDir: this.ctx.packageDir, missingRequiredReviewPhases });
|
|
55819
|
+
}
|
|
55820
|
+
const success2 = missingRequiredReviewPhases.length === 0 && Object.entries(phaseOutputs).every(([name, output]) => {
|
|
55691
55821
|
if (verifierPassedSsot && name === gateName)
|
|
55692
55822
|
return true;
|
|
55693
55823
|
return phasePassed(name, output, this.ctx.storyId);
|
|
55694
55824
|
});
|
|
55695
55825
|
const totalCostUsd = Object.values(phaseCosts).reduce((sum, cost) => sum + cost, 0);
|
|
55696
55826
|
const durationMs = Date.now() - startedAt;
|
|
55697
|
-
const failedPhases =
|
|
55698
|
-
|
|
55699
|
-
|
|
55700
|
-
|
|
55701
|
-
|
|
55827
|
+
const failedPhases = [
|
|
55828
|
+
...Object.entries(phaseOutputs).filter(([name, output]) => {
|
|
55829
|
+
if (verifierPassedSsot && name === gateName)
|
|
55830
|
+
return false;
|
|
55831
|
+
return !phasePassed(name, output, this.ctx.storyId);
|
|
55832
|
+
}).map(([name]) => name),
|
|
55833
|
+
...missingRequiredReviewPhases.map((name) => `${name} (never ran)`)
|
|
55834
|
+
];
|
|
55702
55835
|
const summary = {
|
|
55703
55836
|
storyId: this.ctx.storyId,
|
|
55704
55837
|
success: success2,
|
|
@@ -55711,6 +55844,8 @@ class ExecutionPlan {
|
|
|
55711
55844
|
summary.rectificationExhausted = true;
|
|
55712
55845
|
if (rectResult.unfixedFindings)
|
|
55713
55846
|
summary.unfixedFindingsCount = rectResult.unfixedFindings.length;
|
|
55847
|
+
if (missingRequiredReviewPhases.length > 0)
|
|
55848
|
+
summary.missingRequiredReviewPhases = missingRequiredReviewPhases;
|
|
55714
55849
|
if (success2) {
|
|
55715
55850
|
logger?.info("story-orchestrator", "Story orchestration complete", summary);
|
|
55716
55851
|
} else {
|
|
@@ -55723,11 +55858,21 @@ class ExecutionPlan {
|
|
|
55723
55858
|
durationMs,
|
|
55724
55859
|
phaseOutputs,
|
|
55725
55860
|
...rectResult,
|
|
55726
|
-
gateRegressedDuringRect
|
|
55861
|
+
gateRegressedDuringRect,
|
|
55862
|
+
missingRequiredReviewPhases: missingRequiredReviewPhases.length > 0 ? missingRequiredReviewPhases : undefined
|
|
55727
55863
|
};
|
|
55728
55864
|
}
|
|
55729
55865
|
}
|
|
55866
|
+
var init_execution_plan = __esm(() => {
|
|
55867
|
+
init_logger2();
|
|
55868
|
+
init_non_blocking_fix();
|
|
55869
|
+
init_phase_eval();
|
|
55870
|
+
init_phase_state();
|
|
55871
|
+
init_rectification();
|
|
55872
|
+
init_run_phase();
|
|
55873
|
+
});
|
|
55730
55874
|
|
|
55875
|
+
// src/execution/story-orchestrator/builder.ts
|
|
55731
55876
|
class StoryOrchestratorBuilder {
|
|
55732
55877
|
state = {};
|
|
55733
55878
|
addImplementer(value) {
|
|
@@ -55787,80 +55932,21 @@ class StoryOrchestratorBuilder {
|
|
|
55787
55932
|
return new ExecutionPlan(ctx, { ...this.state }, opts.isThreeSession ?? false);
|
|
55788
55933
|
}
|
|
55789
55934
|
}
|
|
55790
|
-
var
|
|
55791
|
-
var init_story_orchestrator = __esm(() => {
|
|
55935
|
+
var init_builder2 = __esm(() => {
|
|
55792
55936
|
init_errors();
|
|
55793
|
-
init_findings();
|
|
55794
|
-
init_logger2();
|
|
55795
55937
|
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
|
-
};
|
|
55938
|
+
init_execution_plan();
|
|
55939
|
+
init_phase_state();
|
|
55940
|
+
});
|
|
55941
|
+
|
|
55942
|
+
// src/execution/story-orchestrator/index.ts
|
|
55943
|
+
var init_story_orchestrator = __esm(() => {
|
|
55944
|
+
init_builder2();
|
|
55945
|
+
init_execution_plan();
|
|
55946
|
+
init_phase_eval();
|
|
55947
|
+
init_rectification();
|
|
55948
|
+
init_run_phase();
|
|
55949
|
+
init_types9();
|
|
55864
55950
|
});
|
|
55865
55951
|
|
|
55866
55952
|
// src/execution/build-plan-for-strategy.ts
|
|
@@ -56247,7 +56333,7 @@ function routeTddFailure(failureCategory, isLiteMode, ctx, reviewReason, failure
|
|
|
56247
56333
|
}
|
|
56248
56334
|
return { action: "escalate", reason: buildReason("isolation-violation") };
|
|
56249
56335
|
}
|
|
56250
|
-
if (failureCategory === "session-failure" || failureCategory === "tests-failing" || failureCategory === "full-suite-gate-exhausted" || failureCategory === "verifier-rejected" || failureCategory === "runtime-crash") {
|
|
56336
|
+
if (failureCategory === "session-failure" || failureCategory === "tests-failing" || failureCategory === "full-suite-gate-exhausted" || failureCategory === "verifier-rejected" || failureCategory === "runtime-crash" || failureCategory === "review-incomplete") {
|
|
56251
56337
|
return { action: "escalate", reason: buildReason(failureCategory) };
|
|
56252
56338
|
}
|
|
56253
56339
|
if (failureCategory === "greenfield-no-tests") {
|
|
@@ -56346,22 +56432,8 @@ async function closeAllRunSessions(sessionManager, agentGetFn, opts) {
|
|
|
56346
56432
|
return totalClosed;
|
|
56347
56433
|
}
|
|
56348
56434
|
|
|
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) {
|
|
56435
|
+
// src/execution/tdd-failure-category.ts
|
|
56436
|
+
function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDuringRect, missingRequiredReviewPhases) {
|
|
56365
56437
|
const testWriterOutput = phaseOutputs[testWriterOp.name];
|
|
56366
56438
|
if (testWriterOutput?.success === false) {
|
|
56367
56439
|
return "session-failure";
|
|
@@ -56400,6 +56472,29 @@ function deriveTddFailureCategory(phaseOutputs, unfixedFindings, gateRegressedDu
|
|
|
56400
56472
|
if (implOutput?.success === false) {
|
|
56401
56473
|
return "session-failure";
|
|
56402
56474
|
}
|
|
56475
|
+
if (missingRequiredReviewPhases && missingRequiredReviewPhases.length > 0) {
|
|
56476
|
+
return "review-incomplete";
|
|
56477
|
+
}
|
|
56478
|
+
return;
|
|
56479
|
+
}
|
|
56480
|
+
var init_tdd_failure_category = __esm(() => {
|
|
56481
|
+
init_operations();
|
|
56482
|
+
init_story_orchestrator();
|
|
56483
|
+
});
|
|
56484
|
+
|
|
56485
|
+
// src/execution/post-run.ts
|
|
56486
|
+
function shouldRollbackTddFailure(tddMode, failureCategory) {
|
|
56487
|
+
return tddMode?.rollbackEnabled === true && failureCategory === "isolation-violation";
|
|
56488
|
+
}
|
|
56489
|
+
function extractPauseReason(phaseOutputs) {
|
|
56490
|
+
for (const output of Object.values(phaseOutputs)) {
|
|
56491
|
+
if (output !== null && typeof output === "object") {
|
|
56492
|
+
const record2 = output;
|
|
56493
|
+
if (typeof record2.pauseReason === "string" && record2.pauseReason) {
|
|
56494
|
+
return record2.pauseReason;
|
|
56495
|
+
}
|
|
56496
|
+
}
|
|
56497
|
+
}
|
|
56403
56498
|
return;
|
|
56404
56499
|
}
|
|
56405
56500
|
async function cleanupSessionOnFailure(ctx) {
|
|
@@ -56497,7 +56592,7 @@ async function applyPostRunInspection(ctx, planResult, opts) {
|
|
|
56497
56592
|
}
|
|
56498
56593
|
}
|
|
56499
56594
|
const pauseReason = extractPauseReason(planResult.phaseOutputs);
|
|
56500
|
-
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs, planResult.unfixedFindings, planResult.gateRegressedDuringRect) : undefined;
|
|
56595
|
+
const failureCategory = isTdd && !planResult.success ? deriveTddFailureCategory(planResult.phaseOutputs, planResult.unfixedFindings, planResult.gateRegressedDuringRect, planResult.missingRequiredReviewPhases) : undefined;
|
|
56501
56596
|
if (isTdd && !planResult.success && !failureCategory) {
|
|
56502
56597
|
const phaseSignals = {};
|
|
56503
56598
|
for (const [name, output] of Object.entries(planResult.phaseOutputs)) {
|
|
@@ -56716,7 +56811,7 @@ var init_post_run = __esm(() => {
|
|
|
56716
56811
|
init_scratch_writer();
|
|
56717
56812
|
init_rollback();
|
|
56718
56813
|
init_git();
|
|
56719
|
-
|
|
56814
|
+
init_tdd_failure_category();
|
|
56720
56815
|
_postRunDeps = {
|
|
56721
56816
|
detectMergeConflict,
|
|
56722
56817
|
checkMergeConflict,
|
|
@@ -58853,17 +58948,46 @@ var init_setup_verify = __esm(() => {
|
|
|
58853
58948
|
};
|
|
58854
58949
|
});
|
|
58855
58950
|
|
|
58951
|
+
// src/cli/setup-write.ts
|
|
58952
|
+
import { join as join57 } from "path";
|
|
58953
|
+
async function writeSetupConfig(workdir, config2, monoConfigs, _opts, deps = _writeSetupDeps) {
|
|
58954
|
+
const naxDir = join57(workdir, ".nax");
|
|
58955
|
+
const naxConfigPath = join57(naxDir, "config.json");
|
|
58956
|
+
const written = [];
|
|
58957
|
+
await deps.mkdir(naxDir);
|
|
58958
|
+
await deps.writeFile(naxConfigPath, JSON.stringify(config2, null, 2));
|
|
58959
|
+
written.push(naxConfigPath);
|
|
58960
|
+
for (const mc of monoConfigs) {
|
|
58961
|
+
const monoDir = join57(naxDir, "mono", mc.relativeDir);
|
|
58962
|
+
const monoConfigPath = join57(monoDir, "config.json");
|
|
58963
|
+
await deps.mkdir(monoDir);
|
|
58964
|
+
await deps.writeFile(monoConfigPath, JSON.stringify(mc.config, null, 2));
|
|
58965
|
+
written.push(monoConfigPath);
|
|
58966
|
+
}
|
|
58967
|
+
return { written };
|
|
58968
|
+
}
|
|
58969
|
+
var _writeSetupDeps;
|
|
58970
|
+
var init_setup_write = __esm(() => {
|
|
58971
|
+
_writeSetupDeps = {
|
|
58972
|
+
writeFile: (path14, content) => Bun.write(path14, content).then(() => {}),
|
|
58973
|
+
mkdir: async (path14) => {
|
|
58974
|
+
const proc = Bun.spawn(["mkdir", "-p", path14]);
|
|
58975
|
+
await proc.exited;
|
|
58976
|
+
}
|
|
58977
|
+
};
|
|
58978
|
+
});
|
|
58979
|
+
|
|
58856
58980
|
// src/cli/setup.ts
|
|
58857
58981
|
var exports_setup = {};
|
|
58858
58982
|
__export(exports_setup, {
|
|
58859
58983
|
setupCommand: () => setupCommand,
|
|
58860
58984
|
_setupDeps: () => _setupDeps
|
|
58861
58985
|
});
|
|
58862
|
-
import { join as
|
|
58986
|
+
import { join as join58 } from "path";
|
|
58863
58987
|
async function setupCommand(options = {}) {
|
|
58864
58988
|
const workdir = options.dir ?? process.cwd();
|
|
58865
|
-
const naxDir =
|
|
58866
|
-
const naxConfigPath =
|
|
58989
|
+
const naxDir = join58(workdir, ".nax");
|
|
58990
|
+
const naxConfigPath = join58(naxDir, "config.json");
|
|
58867
58991
|
const exists = await _setupDeps.fileExists(naxConfigPath);
|
|
58868
58992
|
if (exists && !options.force) {
|
|
58869
58993
|
_setupDeps.stderr("[setup] .nax/config.json already exists. Use --force to overwrite.");
|
|
@@ -58893,13 +59017,7 @@ ${JSON.stringify(plan.config, null, 2)}`);
|
|
|
58893
59017
|
if (options.fillScripts) {
|
|
58894
59018
|
await _setupDeps.fillScripts(workdir, analysis);
|
|
58895
59019
|
}
|
|
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
|
-
}
|
|
59020
|
+
await _setupDeps.writeSetupConfig(workdir, plan.config, plan.monoConfigs, { force: options.force });
|
|
58903
59021
|
const gateResult = await _setupDeps.runGate(workdir, plan.config);
|
|
58904
59022
|
if (gateResult !== 0) {
|
|
58905
59023
|
return gateResult;
|
|
@@ -58916,6 +59034,7 @@ var init_setup = __esm(() => {
|
|
|
58916
59034
|
init_setup_fill();
|
|
58917
59035
|
init_setup_llm();
|
|
58918
59036
|
init_setup_verify();
|
|
59037
|
+
init_setup_write();
|
|
58919
59038
|
_setupDeps = {
|
|
58920
59039
|
analyzeRepo,
|
|
58921
59040
|
fillScripts,
|
|
@@ -58937,11 +59056,7 @@ var init_setup = __esm(() => {
|
|
|
58937
59056
|
generateSetupPlan: (ctx, analysis) => generateSetupPlan(ctx, analysis),
|
|
58938
59057
|
runGate: (workdir, config2) => runSetupGate(workdir, config2),
|
|
58939
59058
|
fileExists: (path14) => Bun.file(path14).exists(),
|
|
58940
|
-
|
|
58941
|
-
mkdir: async (path14) => {
|
|
58942
|
-
const proc = Bun.spawn(["mkdir", "-p", path14]);
|
|
58943
|
-
await proc.exited;
|
|
58944
|
-
},
|
|
59059
|
+
writeSetupConfig: (workdir, config2, monoConfigs, opts) => writeSetupConfig(workdir, config2, monoConfigs, opts),
|
|
58945
59060
|
stdout: (msg) => {
|
|
58946
59061
|
process.stdout.write(`${msg}
|
|
58947
59062
|
`);
|
|
@@ -60380,7 +60495,7 @@ var init_command_argv = __esm(() => {
|
|
|
60380
60495
|
});
|
|
60381
60496
|
|
|
60382
60497
|
// src/hooks/runner.ts
|
|
60383
|
-
import { join as
|
|
60498
|
+
import { join as join75 } from "path";
|
|
60384
60499
|
function createDrainDeadline2(deadlineMs) {
|
|
60385
60500
|
let timeoutId;
|
|
60386
60501
|
const promise2 = new Promise((resolve16) => {
|
|
@@ -60399,14 +60514,14 @@ async function loadHooksConfig(projectDir, globalDir) {
|
|
|
60399
60514
|
let globalHooks = { hooks: {} };
|
|
60400
60515
|
let projectHooks = { hooks: {} };
|
|
60401
60516
|
let skipGlobal = false;
|
|
60402
|
-
const projectPath =
|
|
60517
|
+
const projectPath = join75(projectDir, "hooks.json");
|
|
60403
60518
|
const projectData = await loadJsonFile(projectPath, "hooks");
|
|
60404
60519
|
if (projectData) {
|
|
60405
60520
|
projectHooks = projectData;
|
|
60406
60521
|
skipGlobal = projectData.skipGlobal ?? false;
|
|
60407
60522
|
}
|
|
60408
60523
|
if (!skipGlobal && globalDir) {
|
|
60409
|
-
const globalPath =
|
|
60524
|
+
const globalPath = join75(globalDir, "hooks.json");
|
|
60410
60525
|
const globalData = await loadJsonFile(globalPath, "hooks");
|
|
60411
60526
|
if (globalData) {
|
|
60412
60527
|
globalHooks = globalData;
|
|
@@ -60576,7 +60691,7 @@ var package_default;
|
|
|
60576
60691
|
var init_package = __esm(() => {
|
|
60577
60692
|
package_default = {
|
|
60578
60693
|
name: "@nathapp/nax",
|
|
60579
|
-
version: "0.70.
|
|
60694
|
+
version: "0.70.2",
|
|
60580
60695
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
60581
60696
|
type: "module",
|
|
60582
60697
|
bin: {
|
|
@@ -60587,7 +60702,7 @@ var init_package = __esm(() => {
|
|
|
60587
60702
|
dev: "bun run bin/nax.ts",
|
|
60588
60703
|
build: 'bun build bin/nax.ts --outdir dist --target bun --define "GIT_COMMIT=\\"$(git rev-parse --short HEAD)\\""',
|
|
60589
60704
|
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",
|
|
60705
|
+
lint: "bun x biome check src/ bin/ && bun run check:no-real-global-nax && bun run check:alias-internals && bun run check:deep-relatives && bun run check:nax-error && bun run check:logger-storyid && bun run check:file-sizes",
|
|
60591
60706
|
"lint:json": "bun x biome check src/ bin/ --reporter json && bun run check:nax-error 1>&2 && bun run check:logger-storyid 1>&2",
|
|
60592
60707
|
"lint:fix": "bun x biome check --write src/ bin/",
|
|
60593
60708
|
"check:no-real-global-nax": "bun run scripts/check-no-real-global-nax.ts",
|
|
@@ -60598,6 +60713,8 @@ var init_package = __esm(() => {
|
|
|
60598
60713
|
"check:nax-error:update": "bun run scripts/check-nax-error.ts --update-baseline",
|
|
60599
60714
|
"check:logger-storyid": "bun run scripts/check-logger-storyid.ts",
|
|
60600
60715
|
"check:logger-storyid:update": "bun run scripts/check-logger-storyid.ts --update-baseline",
|
|
60716
|
+
"check:file-sizes": "bun run scripts/check-file-sizes.ts",
|
|
60717
|
+
"check:file-sizes:update": "bun run scripts/check-file-sizes.ts --update-baseline",
|
|
60601
60718
|
release: "bun scripts/release.ts",
|
|
60602
60719
|
test: "AGENT=1 bun run scripts/run-tests.ts",
|
|
60603
60720
|
"test:verbose": "bun run scripts/run-tests.ts",
|
|
@@ -60609,6 +60726,8 @@ var init_package = __esm(() => {
|
|
|
60609
60726
|
"test:integration": "bun test ./test/integration/ --timeout=60000",
|
|
60610
60727
|
"test:ui": "bun test ./test/ui/ --timeout=60000",
|
|
60611
60728
|
"test:e2e": "timeout -k 5s 180s bun test test/e2e/ --timeout=60000",
|
|
60729
|
+
"test:coverage": "bun run scripts/check-coverage.ts",
|
|
60730
|
+
"test:coverage:report": "bun run scripts/check-coverage.ts --report",
|
|
60612
60731
|
"check-test-overlap": "bun run scripts/check-test-overlap.ts",
|
|
60613
60732
|
"check-dead-tests": "bun run scripts/check-dead-tests.ts",
|
|
60614
60733
|
"check:test-sizes": "bun run scripts/check-test-sizes.ts",
|
|
@@ -60672,8 +60791,8 @@ var init_version = __esm(() => {
|
|
|
60672
60791
|
NAX_VERSION = package_default.version;
|
|
60673
60792
|
NAX_COMMIT = (() => {
|
|
60674
60793
|
try {
|
|
60675
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
60676
|
-
return "
|
|
60794
|
+
if (/^[0-9a-f]{6,10}$/.test("0e202cfa"))
|
|
60795
|
+
return "0e202cfa";
|
|
60677
60796
|
} catch {}
|
|
60678
60797
|
try {
|
|
60679
60798
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -61551,15 +61670,15 @@ var init_acceptance_loop = __esm(() => {
|
|
|
61551
61670
|
|
|
61552
61671
|
// src/session/scratch-purge.ts
|
|
61553
61672
|
import { mkdir as mkdir12, rename, rm } from "fs/promises";
|
|
61554
|
-
import { dirname as dirname12, join as
|
|
61673
|
+
import { dirname as dirname12, join as join76 } from "path";
|
|
61555
61674
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
61556
|
-
const sessionsDir =
|
|
61675
|
+
const sessionsDir = join76(projectDir, ".nax", "features", featureName, "sessions");
|
|
61557
61676
|
const sessionIds = await _scratchPurgeDeps.listSessionDirs(sessionsDir);
|
|
61558
61677
|
const cutoffMs = _scratchPurgeDeps.now() - retentionDays * 86400000;
|
|
61559
61678
|
let purged = 0;
|
|
61560
61679
|
for (const sessionId of sessionIds) {
|
|
61561
|
-
const sessionDir =
|
|
61562
|
-
const descriptorPath =
|
|
61680
|
+
const sessionDir = join76(sessionsDir, sessionId);
|
|
61681
|
+
const descriptorPath = join76(sessionDir, "descriptor.json");
|
|
61563
61682
|
if (!await _scratchPurgeDeps.fileExists(descriptorPath))
|
|
61564
61683
|
continue;
|
|
61565
61684
|
let lastActivityAt;
|
|
@@ -61575,7 +61694,7 @@ async function purgeStaleScratch(projectDir, featureName, retentionDays, archive
|
|
|
61575
61694
|
if (new Date(lastActivityAt).getTime() >= cutoffMs)
|
|
61576
61695
|
continue;
|
|
61577
61696
|
if (archiveInsteadOfDelete) {
|
|
61578
|
-
const archiveDest =
|
|
61697
|
+
const archiveDest = join76(projectDir, ".nax", "features", featureName, "_archive", "sessions", sessionId);
|
|
61579
61698
|
await _scratchPurgeDeps.move(sessionDir, archiveDest);
|
|
61580
61699
|
} else {
|
|
61581
61700
|
await _scratchPurgeDeps.remove(sessionDir);
|
|
@@ -62280,7 +62399,7 @@ function outputRunFooter(options) {
|
|
|
62280
62399
|
}
|
|
62281
62400
|
var init_headless_formatter = __esm(() => {
|
|
62282
62401
|
init_source();
|
|
62283
|
-
|
|
62402
|
+
init_log_format();
|
|
62284
62403
|
init_version();
|
|
62285
62404
|
});
|
|
62286
62405
|
|
|
@@ -62326,12 +62445,12 @@ var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
|
62326
62445
|
|
|
62327
62446
|
// src/pipeline/subscribers/events-writer.ts
|
|
62328
62447
|
import { appendFile as appendFile4, mkdir as mkdir13 } from "fs/promises";
|
|
62329
|
-
import { basename as basename13, join as
|
|
62448
|
+
import { basename as basename13, join as join77 } from "path";
|
|
62330
62449
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
62331
62450
|
const logger = getSafeLogger();
|
|
62332
62451
|
const project = basename13(workdir);
|
|
62333
|
-
const eventsDir =
|
|
62334
|
-
const eventsFile =
|
|
62452
|
+
const eventsDir = join77(getEventsRootDir(), project);
|
|
62453
|
+
const eventsFile = join77(eventsDir, "events.jsonl");
|
|
62335
62454
|
let dirReady = false;
|
|
62336
62455
|
const write = (line) => {
|
|
62337
62456
|
return (async () => {
|
|
@@ -62512,12 +62631,12 @@ var init_interaction2 = __esm(() => {
|
|
|
62512
62631
|
|
|
62513
62632
|
// src/pipeline/subscribers/registry.ts
|
|
62514
62633
|
import { mkdir as mkdir14, writeFile as writeFile2 } from "fs/promises";
|
|
62515
|
-
import { basename as basename14, join as
|
|
62634
|
+
import { basename as basename14, join as join78 } from "path";
|
|
62516
62635
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
62517
62636
|
const logger = getSafeLogger();
|
|
62518
62637
|
const project = basename14(workdir);
|
|
62519
|
-
const runDir =
|
|
62520
|
-
const metaFile =
|
|
62638
|
+
const runDir = join78(getRunsDir(), `${project}-${feature}-${runId}`);
|
|
62639
|
+
const metaFile = join78(runDir, "meta.json");
|
|
62521
62640
|
const unsub = bus.on("run:started", (_ev) => {
|
|
62522
62641
|
return (async () => {
|
|
62523
62642
|
try {
|
|
@@ -62527,8 +62646,8 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
62527
62646
|
project,
|
|
62528
62647
|
feature,
|
|
62529
62648
|
workdir,
|
|
62530
|
-
statusPath:
|
|
62531
|
-
eventsDir:
|
|
62649
|
+
statusPath: join78(outputDir, "features", feature, "status.json"),
|
|
62650
|
+
eventsDir: join78(outputDir, "features", feature, "runs"),
|
|
62532
62651
|
registeredAt: new Date().toISOString()
|
|
62533
62652
|
};
|
|
62534
62653
|
await writeFile2(metaFile, JSON.stringify(meta3, null, 2));
|
|
@@ -62760,7 +62879,7 @@ function buildPreviewRouting(story, config2) {
|
|
|
62760
62879
|
|
|
62761
62880
|
// src/worktree/types.ts
|
|
62762
62881
|
var WorktreeDependencyPreparationError;
|
|
62763
|
-
var
|
|
62882
|
+
var init_types10 = __esm(() => {
|
|
62764
62883
|
WorktreeDependencyPreparationError = class WorktreeDependencyPreparationError extends Error {
|
|
62765
62884
|
mode;
|
|
62766
62885
|
failureCategory = "dependency-prep";
|
|
@@ -62774,7 +62893,7 @@ var init_types9 = __esm(() => {
|
|
|
62774
62893
|
|
|
62775
62894
|
// src/worktree/dependencies.ts
|
|
62776
62895
|
import { existsSync as existsSync30 } from "fs";
|
|
62777
|
-
import { join as
|
|
62896
|
+
import { join as join79 } from "path";
|
|
62778
62897
|
async function prepareWorktreeDependencies(options) {
|
|
62779
62898
|
const mode = options.config.execution.worktreeDependencies.mode;
|
|
62780
62899
|
const resolvedCwd = resolveDependencyCwd(options);
|
|
@@ -62788,7 +62907,7 @@ async function prepareWorktreeDependencies(options) {
|
|
|
62788
62907
|
}
|
|
62789
62908
|
}
|
|
62790
62909
|
function resolveDependencyCwd(options) {
|
|
62791
|
-
return options.storyWorkdir ?
|
|
62910
|
+
return options.storyWorkdir ? join79(options.worktreeRoot, options.storyWorkdir) : options.worktreeRoot;
|
|
62792
62911
|
}
|
|
62793
62912
|
function resolveInheritedDependencies(options, resolvedCwd) {
|
|
62794
62913
|
if (hasDependencyManifests(options.worktreeRoot, resolvedCwd)) {
|
|
@@ -62798,7 +62917,7 @@ function resolveInheritedDependencies(options, resolvedCwd) {
|
|
|
62798
62917
|
}
|
|
62799
62918
|
function hasDependencyManifests(worktreeRoot, resolvedCwd) {
|
|
62800
62919
|
const directories = resolvedCwd === worktreeRoot ? [worktreeRoot] : [worktreeRoot, resolvedCwd];
|
|
62801
|
-
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(
|
|
62920
|
+
return directories.some((directory) => PHASE_ONE_INHERIT_UNSUPPORTED_FILES.some((filename) => _worktreeDependencyDeps.existsSync(join79(directory, filename))));
|
|
62802
62921
|
}
|
|
62803
62922
|
async function provisionDependencies(config2, worktreeRoot, resolvedCwd) {
|
|
62804
62923
|
const setupCommand2 = config2.execution.worktreeDependencies.setupCommand;
|
|
@@ -62830,7 +62949,7 @@ var PHASE_ONE_INHERIT_UNSUPPORTED_FILES, _worktreeDependencyDeps;
|
|
|
62830
62949
|
var init_dependencies = __esm(() => {
|
|
62831
62950
|
init_bun_deps();
|
|
62832
62951
|
init_command_argv();
|
|
62833
|
-
|
|
62952
|
+
init_types10();
|
|
62834
62953
|
PHASE_ONE_INHERIT_UNSUPPORTED_FILES = [
|
|
62835
62954
|
"package.json",
|
|
62836
62955
|
"bun.lock",
|
|
@@ -62862,13 +62981,13 @@ __export(exports_manager, {
|
|
|
62862
62981
|
});
|
|
62863
62982
|
import { existsSync as existsSync31, symlinkSync } from "fs";
|
|
62864
62983
|
import { mkdir as mkdir15 } from "fs/promises";
|
|
62865
|
-
import { join as
|
|
62984
|
+
import { join as join80 } from "path";
|
|
62866
62985
|
|
|
62867
62986
|
class WorktreeManager {
|
|
62868
62987
|
async ensureGitExcludes(projectRoot) {
|
|
62869
62988
|
const logger = getSafeLogger();
|
|
62870
|
-
const infoDir =
|
|
62871
|
-
const excludePath =
|
|
62989
|
+
const infoDir = join80(projectRoot, ".git", "info");
|
|
62990
|
+
const excludePath = join80(infoDir, "exclude");
|
|
62872
62991
|
try {
|
|
62873
62992
|
await mkdir15(infoDir, { recursive: true });
|
|
62874
62993
|
let existing = "";
|
|
@@ -62895,7 +63014,7 @@ ${missing.join(`
|
|
|
62895
63014
|
}
|
|
62896
63015
|
async create(projectRoot, storyId) {
|
|
62897
63016
|
validateStoryId(storyId);
|
|
62898
|
-
const worktreePath =
|
|
63017
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62899
63018
|
const branchName = `nax/${storyId}`;
|
|
62900
63019
|
try {
|
|
62901
63020
|
const pruneProc = _managerDeps.spawn(["git", "worktree", "prune"], {
|
|
@@ -62935,9 +63054,9 @@ ${missing.join(`
|
|
|
62935
63054
|
}
|
|
62936
63055
|
throw new Error(`Failed to create worktree: ${String(error48)}`);
|
|
62937
63056
|
}
|
|
62938
|
-
const envSource =
|
|
63057
|
+
const envSource = join80(projectRoot, ".env");
|
|
62939
63058
|
if (existsSync31(envSource)) {
|
|
62940
|
-
const envTarget =
|
|
63059
|
+
const envTarget = join80(worktreePath, ".env");
|
|
62941
63060
|
try {
|
|
62942
63061
|
symlinkSync(envSource, envTarget, "file");
|
|
62943
63062
|
} catch (error48) {
|
|
@@ -62948,7 +63067,7 @@ ${missing.join(`
|
|
|
62948
63067
|
}
|
|
62949
63068
|
async remove(projectRoot, storyId) {
|
|
62950
63069
|
validateStoryId(storyId);
|
|
62951
|
-
const worktreePath =
|
|
63070
|
+
const worktreePath = join80(projectRoot, ".nax-wt", storyId);
|
|
62952
63071
|
const branchName = `nax/${storyId}`;
|
|
62953
63072
|
try {
|
|
62954
63073
|
const proc = _managerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
@@ -63532,6 +63651,8 @@ function resolveMaxAttemptsOutcome(failureCategory) {
|
|
|
63532
63651
|
return "pause";
|
|
63533
63652
|
case "runtime-crash":
|
|
63534
63653
|
return "pause";
|
|
63654
|
+
case "review-incomplete":
|
|
63655
|
+
return "pause";
|
|
63535
63656
|
case "session-failure":
|
|
63536
63657
|
case "tests-failing":
|
|
63537
63658
|
case "full-suite-gate-exhausted":
|
|
@@ -63770,10 +63891,10 @@ var init_merge_conflict_rectify = __esm(() => {
|
|
|
63770
63891
|
});
|
|
63771
63892
|
|
|
63772
63893
|
// src/execution/pipeline-result-handler.ts
|
|
63773
|
-
import { join as
|
|
63894
|
+
import { join as join81 } from "path";
|
|
63774
63895
|
async function removeWorktreeDirectory(projectRoot, storyId) {
|
|
63775
63896
|
const logger = getSafeLogger();
|
|
63776
|
-
const worktreePath =
|
|
63897
|
+
const worktreePath = join81(projectRoot, ".nax-wt", storyId);
|
|
63777
63898
|
try {
|
|
63778
63899
|
const proc = _resultHandlerDeps.spawn(["git", "worktree", "remove", worktreePath, "--force"], {
|
|
63779
63900
|
cwd: projectRoot,
|
|
@@ -63990,7 +64111,7 @@ var init_pipeline_result_handler = __esm(() => {
|
|
|
63990
64111
|
|
|
63991
64112
|
// src/execution/iteration-runner.ts
|
|
63992
64113
|
import { existsSync as existsSync32 } from "fs";
|
|
63993
|
-
import { join as
|
|
64114
|
+
import { join as join82 } from "path";
|
|
63994
64115
|
async function runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics) {
|
|
63995
64116
|
const { story, storiesToExecute, routing, isBatchExecution } = selection;
|
|
63996
64117
|
if (ctx.dryRun) {
|
|
@@ -64015,7 +64136,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64015
64136
|
const storyStartTime = Date.now();
|
|
64016
64137
|
let effectiveWorkdir = ctx.workdir;
|
|
64017
64138
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
64018
|
-
const worktreePath =
|
|
64139
|
+
const worktreePath = join82(ctx.workdir, ".nax-wt", story.id);
|
|
64019
64140
|
const worktreeExists = _iterationRunnerDeps.existsSync(worktreePath);
|
|
64020
64141
|
if (!worktreeExists) {
|
|
64021
64142
|
await _iterationRunnerDeps.worktreeManager.ensureGitExcludes(ctx.workdir);
|
|
@@ -64035,7 +64156,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64035
64156
|
}
|
|
64036
64157
|
const accumulatedAttemptCost = (story.priorFailures || []).reduce((sum, f) => sum + (f.cost || 0), 0);
|
|
64037
64158
|
const profileOverride = profileOverrideFromConfig(ctx.config);
|
|
64038
|
-
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(
|
|
64159
|
+
const effectiveConfig = story.workdir ? await _iterationRunnerDeps.loadConfigForWorkdir(join82(ctx.workdir, ".nax", "config.json"), story.workdir, profileOverride) : ctx.config;
|
|
64039
64160
|
let dependencyContext;
|
|
64040
64161
|
if (ctx.config.execution.storyIsolation === "worktree") {
|
|
64041
64162
|
try {
|
|
@@ -64062,7 +64183,7 @@ async function runIteration(ctx, prd, selection, iterations, totalCost, allStory
|
|
|
64062
64183
|
};
|
|
64063
64184
|
}
|
|
64064
64185
|
}
|
|
64065
|
-
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ?
|
|
64186
|
+
const resolvedWorkdir = dependencyContext?.cwd ? dependencyContext.cwd : ctx.config.execution.storyIsolation === "worktree" ? story.workdir ? join82(effectiveWorkdir, story.workdir) : effectiveWorkdir : story.workdir ? join82(ctx.workdir, story.workdir) : ctx.workdir;
|
|
64066
64187
|
const pipelineContext = {
|
|
64067
64188
|
config: effectiveConfig,
|
|
64068
64189
|
rootConfig: ctx.config,
|
|
@@ -64265,7 +64386,7 @@ __export(exports_parallel_worker, {
|
|
|
64265
64386
|
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
64266
64387
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
64267
64388
|
});
|
|
64268
|
-
import { join as
|
|
64389
|
+
import { join as join83 } from "path";
|
|
64269
64390
|
function buildWorktreePipelineContext(base, _story) {
|
|
64270
64391
|
return { ...base, prd: structuredClone(base.prd) };
|
|
64271
64392
|
}
|
|
@@ -64288,7 +64409,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
64288
64409
|
story,
|
|
64289
64410
|
stories: [story],
|
|
64290
64411
|
projectDir: context.projectDir,
|
|
64291
|
-
workdir: dependencyContext.cwd ?? (story.workdir ?
|
|
64412
|
+
workdir: dependencyContext.cwd ?? (story.workdir ? join83(worktreePath, story.workdir) : worktreePath),
|
|
64292
64413
|
worktreeDependencyContext: dependencyContext,
|
|
64293
64414
|
routing,
|
|
64294
64415
|
storyGitRef: storyGitRef ?? undefined
|
|
@@ -65188,7 +65309,7 @@ async function writeStatusFile(filePath, status) {
|
|
|
65188
65309
|
var init_status_file = () => {};
|
|
65189
65310
|
|
|
65190
65311
|
// src/execution/status-writer.ts
|
|
65191
|
-
import { join as
|
|
65312
|
+
import { join as join84 } from "path";
|
|
65192
65313
|
|
|
65193
65314
|
class StatusWriter {
|
|
65194
65315
|
statusFile;
|
|
@@ -65307,7 +65428,7 @@ class StatusWriter {
|
|
|
65307
65428
|
if (!this._prd)
|
|
65308
65429
|
return;
|
|
65309
65430
|
const safeLogger = getSafeLogger();
|
|
65310
|
-
const featureStatusPath =
|
|
65431
|
+
const featureStatusPath = join84(featureDir, "status.json");
|
|
65311
65432
|
const write = async () => {
|
|
65312
65433
|
try {
|
|
65313
65434
|
const base = this.getSnapshot(totalCost, iterations);
|
|
@@ -65741,7 +65862,7 @@ __export(exports_run_initialization, {
|
|
|
65741
65862
|
initializeRun: () => initializeRun,
|
|
65742
65863
|
_reconcileDeps: () => _reconcileDeps
|
|
65743
65864
|
});
|
|
65744
|
-
import { join as
|
|
65865
|
+
import { join as join85 } from "path";
|
|
65745
65866
|
async function reconcileState(prd, prdPath, workdir, config2) {
|
|
65746
65867
|
const logger = getSafeLogger();
|
|
65747
65868
|
let reconciledCount = 0;
|
|
@@ -65758,7 +65879,7 @@ async function reconcileState(prd, prdPath, workdir, config2) {
|
|
|
65758
65879
|
});
|
|
65759
65880
|
continue;
|
|
65760
65881
|
}
|
|
65761
|
-
const effectiveWorkdir = story.workdir ?
|
|
65882
|
+
const effectiveWorkdir = story.workdir ? join85(workdir, story.workdir) : workdir;
|
|
65762
65883
|
try {
|
|
65763
65884
|
const reviewResult = await _reconcileDeps.runReview(config2.review, effectiveWorkdir, config2.execution);
|
|
65764
65885
|
if (!reviewResult.success) {
|
|
@@ -95589,7 +95710,7 @@ __export(exports_curator, {
|
|
|
95589
95710
|
});
|
|
95590
95711
|
import { readdirSync as readdirSync8 } from "fs";
|
|
95591
95712
|
import { unlink as unlink4 } from "fs/promises";
|
|
95592
|
-
import { basename as basename15, join as
|
|
95713
|
+
import { basename as basename15, join as join87 } from "path";
|
|
95593
95714
|
function getProjectKey(config2, projectDir) {
|
|
95594
95715
|
return config2.name?.trim() || basename15(projectDir);
|
|
95595
95716
|
}
|
|
@@ -95672,7 +95793,7 @@ async function curatorStatus(options) {
|
|
|
95672
95793
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95673
95794
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95674
95795
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95675
|
-
const runsDir =
|
|
95796
|
+
const runsDir = join87(outputDir, "runs");
|
|
95676
95797
|
const runIds = listRunIds(runsDir);
|
|
95677
95798
|
let runId;
|
|
95678
95799
|
if (options.run) {
|
|
@@ -95689,8 +95810,8 @@ async function curatorStatus(options) {
|
|
|
95689
95810
|
runId = runIds[runIds.length - 1];
|
|
95690
95811
|
}
|
|
95691
95812
|
console.log(`Run: ${runId}`);
|
|
95692
|
-
const runDir =
|
|
95693
|
-
const observationsPath =
|
|
95813
|
+
const runDir = join87(runsDir, runId);
|
|
95814
|
+
const observationsPath = join87(runDir, "observations.jsonl");
|
|
95694
95815
|
const observations = await parseObservations(observationsPath);
|
|
95695
95816
|
const counts = new Map;
|
|
95696
95817
|
for (const obs of observations) {
|
|
@@ -95700,7 +95821,7 @@ async function curatorStatus(options) {
|
|
|
95700
95821
|
for (const [kind, count] of counts.entries()) {
|
|
95701
95822
|
console.log(` ${kind}: ${count}`);
|
|
95702
95823
|
}
|
|
95703
|
-
const proposalsPath =
|
|
95824
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
95704
95825
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
95705
95826
|
if (proposalText !== null) {
|
|
95706
95827
|
console.log("");
|
|
@@ -95714,8 +95835,8 @@ async function curatorCommit(options) {
|
|
|
95714
95835
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95715
95836
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95716
95837
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95717
|
-
const runDir =
|
|
95718
|
-
const proposalsPath =
|
|
95838
|
+
const runDir = join87(outputDir, "runs", options.runId);
|
|
95839
|
+
const proposalsPath = join87(runDir, "curator-proposals.md");
|
|
95719
95840
|
const proposalText = await _curatorCmdDeps.readFile(proposalsPath).catch(() => null);
|
|
95720
95841
|
if (proposalText === null) {
|
|
95721
95842
|
console.log(`curator-proposals.md not found for run ${options.runId}.`);
|
|
@@ -95731,7 +95852,7 @@ async function curatorCommit(options) {
|
|
|
95731
95852
|
const dropFileState = new Map;
|
|
95732
95853
|
const skippedDrops = new Set;
|
|
95733
95854
|
for (const drop2 of drops) {
|
|
95734
|
-
const targetPath =
|
|
95855
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
95735
95856
|
if (!dropFileState.has(targetPath)) {
|
|
95736
95857
|
const fileExists2 = await Bun.file(targetPath).exists();
|
|
95737
95858
|
const existing = fileExists2 ? await _curatorCmdDeps.readFile(targetPath).catch(() => "") : "";
|
|
@@ -95765,7 +95886,7 @@ async function curatorCommit(options) {
|
|
|
95765
95886
|
if (skippedDrops.has(drop2)) {
|
|
95766
95887
|
continue;
|
|
95767
95888
|
}
|
|
95768
|
-
const targetPath =
|
|
95889
|
+
const targetPath = join87(resolved.projectDir, drop2.canonicalFile);
|
|
95769
95890
|
const existing = await _curatorCmdDeps.readFile(targetPath).catch(() => "");
|
|
95770
95891
|
const filtered = filterDropContent(existing, drop2.description);
|
|
95771
95892
|
await _curatorCmdDeps.writeFile(targetPath, filtered);
|
|
@@ -95774,7 +95895,7 @@ async function curatorCommit(options) {
|
|
|
95774
95895
|
}
|
|
95775
95896
|
const adds = proposals.filter((p) => p.action === "add" || p.action === "advisory");
|
|
95776
95897
|
for (const add2 of adds) {
|
|
95777
|
-
const targetPath =
|
|
95898
|
+
const targetPath = join87(resolved.projectDir, add2.canonicalFile);
|
|
95778
95899
|
const content = buildAddContent(add2);
|
|
95779
95900
|
await _curatorCmdDeps.appendFile(targetPath, content);
|
|
95780
95901
|
modifiedFiles.add(targetPath);
|
|
@@ -95811,7 +95932,7 @@ async function curatorDryrun(options) {
|
|
|
95811
95932
|
const config2 = await _curatorCmdDeps.loadConfig(resolved.projectDir);
|
|
95812
95933
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95813
95934
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95814
|
-
const runsDir =
|
|
95935
|
+
const runsDir = join87(outputDir, "runs");
|
|
95815
95936
|
const runIds = listRunIds(runsDir);
|
|
95816
95937
|
if (runIds.length === 0) {
|
|
95817
95938
|
console.log("No runs found.");
|
|
@@ -95822,7 +95943,7 @@ async function curatorDryrun(options) {
|
|
|
95822
95943
|
console.log(`Run ${options.run} not found in ${runsDir}.`);
|
|
95823
95944
|
return;
|
|
95824
95945
|
}
|
|
95825
|
-
const observationsPath =
|
|
95946
|
+
const observationsPath = join87(runsDir, runId, "observations.jsonl");
|
|
95826
95947
|
const observations = await parseObservations(observationsPath);
|
|
95827
95948
|
const thresholds = getThresholds(config2);
|
|
95828
95949
|
const proposals = runHeuristics(observations, thresholds);
|
|
@@ -95863,12 +95984,12 @@ async function curatorGc(options) {
|
|
|
95863
95984
|
await _curatorCmdDeps.writeFile(rollupPath, newContent);
|
|
95864
95985
|
const projectKey = getProjectKey(config2, resolved.projectDir);
|
|
95865
95986
|
const outputDir = _curatorCmdDeps.projectOutputDir(projectKey, config2.outputDir);
|
|
95866
|
-
const perRunsDir =
|
|
95987
|
+
const perRunsDir = join87(outputDir, "runs");
|
|
95867
95988
|
for (const runId of uniqueRunIds) {
|
|
95868
95989
|
if (!keepSet.has(runId)) {
|
|
95869
|
-
const runDir =
|
|
95870
|
-
await _curatorCmdDeps.removeFile(
|
|
95871
|
-
await _curatorCmdDeps.removeFile(
|
|
95990
|
+
const runDir = join87(perRunsDir, runId);
|
|
95991
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "observations.jsonl"));
|
|
95992
|
+
await _curatorCmdDeps.removeFile(join87(runDir, "curator-proposals.md"));
|
|
95872
95993
|
}
|
|
95873
95994
|
}
|
|
95874
95995
|
console.log(`[gc] Pruned rollup to ${keep} most recent runs (was ${uniqueRunIds.length}).`);
|
|
@@ -95913,7 +96034,7 @@ var init_curator2 = __esm(() => {
|
|
|
95913
96034
|
init_source();
|
|
95914
96035
|
import { existsSync as existsSync35, mkdirSync as mkdirSync7 } from "fs";
|
|
95915
96036
|
import { homedir as homedir3 } from "os";
|
|
95916
|
-
import { basename as basename16, join as
|
|
96037
|
+
import { basename as basename16, join as join88 } from "path";
|
|
95917
96038
|
|
|
95918
96039
|
// node_modules/commander/esm.mjs
|
|
95919
96040
|
var import__ = __toESM(require_commander(), 1);
|
|
@@ -97037,6 +97158,7 @@ async function runsShowCommand(options) {
|
|
|
97037
97158
|
init_prompts2();
|
|
97038
97159
|
init_init2();
|
|
97039
97160
|
init_setup();
|
|
97161
|
+
init_setup_write();
|
|
97040
97162
|
|
|
97041
97163
|
// src/cli/plugins.ts
|
|
97042
97164
|
init_paths();
|
|
@@ -97112,7 +97234,7 @@ init_source();
|
|
|
97112
97234
|
init_loader();
|
|
97113
97235
|
init_generator2();
|
|
97114
97236
|
import { existsSync as existsSync24 } from "fs";
|
|
97115
|
-
import { join as
|
|
97237
|
+
import { join as join63 } from "path";
|
|
97116
97238
|
var VALID_AGENTS = ["claude", "codex", "opencode", "cursor", "windsurf", "aider", "gemini"];
|
|
97117
97239
|
async function generateCommand(options) {
|
|
97118
97240
|
const workdir = options.dir ?? process.cwd();
|
|
@@ -97155,7 +97277,7 @@ async function generateCommand(options) {
|
|
|
97155
97277
|
return;
|
|
97156
97278
|
}
|
|
97157
97279
|
if (options.package) {
|
|
97158
|
-
const packageDir =
|
|
97280
|
+
const packageDir = join63(workdir, options.package);
|
|
97159
97281
|
if (dryRun) {
|
|
97160
97282
|
console.log(source_default.yellow("\u26A0 Dry run \u2014 no files will be written"));
|
|
97161
97283
|
}
|
|
@@ -97175,8 +97297,8 @@ async function generateCommand(options) {
|
|
|
97175
97297
|
process.exit(1);
|
|
97176
97298
|
return;
|
|
97177
97299
|
}
|
|
97178
|
-
const contextPath = options.context ?
|
|
97179
|
-
const outputDir = options.output ?
|
|
97300
|
+
const contextPath = options.context ? join63(workdir, options.context) : join63(workdir, ".nax/context.md");
|
|
97301
|
+
const outputDir = options.output ? join63(workdir, options.output) : workdir;
|
|
97180
97302
|
const autoInject = !options.noAutoInject;
|
|
97181
97303
|
if (!existsSync24(contextPath)) {
|
|
97182
97304
|
console.error(source_default.red(`\u2717 Context file not found: ${contextPath}`));
|
|
@@ -97282,7 +97404,7 @@ async function generateCommand(options) {
|
|
|
97282
97404
|
// src/cli/config-display.ts
|
|
97283
97405
|
init_loader();
|
|
97284
97406
|
import { existsSync as existsSync26 } from "fs";
|
|
97285
|
-
import { join as
|
|
97407
|
+
import { join as join65 } from "path";
|
|
97286
97408
|
|
|
97287
97409
|
// src/cli/config-descriptions.ts
|
|
97288
97410
|
var FIELD_DESCRIPTIONS = {
|
|
@@ -97535,7 +97657,7 @@ function deepEqual(a, b) {
|
|
|
97535
97657
|
init_defaults();
|
|
97536
97658
|
init_loader();
|
|
97537
97659
|
import { existsSync as existsSync25 } from "fs";
|
|
97538
|
-
import { join as
|
|
97660
|
+
import { join as join64 } from "path";
|
|
97539
97661
|
async function loadConfigFile(path19) {
|
|
97540
97662
|
if (!existsSync25(path19))
|
|
97541
97663
|
return null;
|
|
@@ -97557,7 +97679,7 @@ async function loadProjectConfig() {
|
|
|
97557
97679
|
const projectDir = findProjectDir();
|
|
97558
97680
|
if (!projectDir)
|
|
97559
97681
|
return null;
|
|
97560
|
-
const projectPath =
|
|
97682
|
+
const projectPath = join64(projectDir, "config.json");
|
|
97561
97683
|
return await loadConfigFile(projectPath);
|
|
97562
97684
|
}
|
|
97563
97685
|
|
|
@@ -97617,7 +97739,7 @@ async function configCommand(config2, options = {}) {
|
|
|
97617
97739
|
function determineConfigSources() {
|
|
97618
97740
|
const globalPath = globalConfigPath();
|
|
97619
97741
|
const projectDir = findProjectDir();
|
|
97620
|
-
const projectPath = projectDir ?
|
|
97742
|
+
const projectPath = projectDir ? join65(projectDir, "config.json") : null;
|
|
97621
97743
|
return {
|
|
97622
97744
|
global: fileExists(globalPath) ? globalPath : null,
|
|
97623
97745
|
project: projectPath && fileExists(projectPath) ? projectPath : null
|
|
@@ -97766,15 +97888,15 @@ init_paths();
|
|
|
97766
97888
|
init_profile();
|
|
97767
97889
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
97768
97890
|
import { readdirSync as readdirSync5 } from "fs";
|
|
97769
|
-
import { join as
|
|
97891
|
+
import { join as join66 } from "path";
|
|
97770
97892
|
var _profileCLIDeps = {
|
|
97771
97893
|
env: process.env
|
|
97772
97894
|
};
|
|
97773
97895
|
var SENSITIVE_KEY_PATTERN = /key|token|secret|password|credential/i;
|
|
97774
97896
|
var VAR_PATTERN = /\$[A-Za-z_][A-Za-z0-9_]*/;
|
|
97775
97897
|
async function profileListCommand(startDir) {
|
|
97776
|
-
const globalProfilesDir =
|
|
97777
|
-
const projectProfilesDir =
|
|
97898
|
+
const globalProfilesDir = join66(globalConfigDir(), "profiles");
|
|
97899
|
+
const projectProfilesDir = join66(projectConfigDir(startDir), "profiles");
|
|
97778
97900
|
const globalProfiles = scanProfileDir(globalProfilesDir);
|
|
97779
97901
|
const projectProfiles = scanProfileDir(projectProfilesDir);
|
|
97780
97902
|
const activeProfile = await resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
@@ -97833,7 +97955,7 @@ function maskProfileValues(obj) {
|
|
|
97833
97955
|
return result;
|
|
97834
97956
|
}
|
|
97835
97957
|
async function profileUseCommand(profileName, startDir) {
|
|
97836
|
-
const configPath =
|
|
97958
|
+
const configPath = join66(projectConfigDir(startDir), "config.json");
|
|
97837
97959
|
const configFile = Bun.file(configPath);
|
|
97838
97960
|
let existing = {};
|
|
97839
97961
|
if (await configFile.exists()) {
|
|
@@ -97852,8 +97974,8 @@ async function profileCurrentCommand(startDir) {
|
|
|
97852
97974
|
return resolveProfileName({}, _profileCLIDeps.env, startDir);
|
|
97853
97975
|
}
|
|
97854
97976
|
async function profileCreateCommand(profileName, startDir) {
|
|
97855
|
-
const profilesDir =
|
|
97856
|
-
const profilePath =
|
|
97977
|
+
const profilesDir = join66(projectConfigDir(startDir), "profiles");
|
|
97978
|
+
const profilePath = join66(profilesDir, `${profileName}.json`);
|
|
97857
97979
|
const profileFile = Bun.file(profilePath);
|
|
97858
97980
|
if (await profileFile.exists()) {
|
|
97859
97981
|
throw new Error(`Profile "${profileName}" already exists at ${profilePath}`);
|
|
@@ -97975,7 +98097,7 @@ async function contextInspectCommand(options) {
|
|
|
97975
98097
|
init_canonical_loader();
|
|
97976
98098
|
init_errors();
|
|
97977
98099
|
import { mkdir as mkdir11 } from "fs/promises";
|
|
97978
|
-
import { basename as basename12, join as
|
|
98100
|
+
import { basename as basename12, join as join67 } from "path";
|
|
97979
98101
|
var _rulesCLIDeps = {
|
|
97980
98102
|
readFile: async (path19) => Bun.file(path19).text(),
|
|
97981
98103
|
writeFile: async (path19, content) => {
|
|
@@ -97984,7 +98106,7 @@ var _rulesCLIDeps = {
|
|
|
97984
98106
|
fileExists: async (path19) => Bun.file(path19).exists(),
|
|
97985
98107
|
globInDir: (dir) => {
|
|
97986
98108
|
try {
|
|
97987
|
-
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) =>
|
|
98109
|
+
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join67(dir, f));
|
|
97988
98110
|
} catch {
|
|
97989
98111
|
return [];
|
|
97990
98112
|
}
|
|
@@ -98033,7 +98155,7 @@ ${r.content}`).join(`
|
|
|
98033
98155
|
`);
|
|
98034
98156
|
const shimContent = `${header + body}
|
|
98035
98157
|
`;
|
|
98036
|
-
const shimPath =
|
|
98158
|
+
const shimPath = join67(workdir, shimFileName);
|
|
98037
98159
|
if (options.dryRun) {
|
|
98038
98160
|
console.log(`[dry-run] Would write ${shimPath} (${shimContent.length} bytes)`);
|
|
98039
98161
|
return;
|
|
@@ -98062,14 +98184,14 @@ function neutralizeContent(content) {
|
|
|
98062
98184
|
}
|
|
98063
98185
|
async function collectMigrationSources(workdir) {
|
|
98064
98186
|
const sources = [];
|
|
98065
|
-
const claudeMdPath =
|
|
98187
|
+
const claudeMdPath = join67(workdir, "CLAUDE.md");
|
|
98066
98188
|
if (await _rulesCLIDeps.fileExists(claudeMdPath)) {
|
|
98067
98189
|
const content = await _rulesCLIDeps.readFile(claudeMdPath);
|
|
98068
98190
|
if (content.trim()) {
|
|
98069
98191
|
sources.push({ sourcePath: claudeMdPath, targetFileName: "project-conventions.md", content });
|
|
98070
98192
|
}
|
|
98071
98193
|
}
|
|
98072
|
-
const rulesDir =
|
|
98194
|
+
const rulesDir = join67(workdir, ".claude", "rules");
|
|
98073
98195
|
const ruleFiles = _rulesCLIDeps.globInDir(rulesDir);
|
|
98074
98196
|
for (const filePath of ruleFiles) {
|
|
98075
98197
|
try {
|
|
@@ -98089,7 +98211,7 @@ async function rulesMigrateCommand(options) {
|
|
|
98089
98211
|
console.log("[WARN] No source files found (checked CLAUDE.md and .claude/rules/*.md). Nothing to migrate.");
|
|
98090
98212
|
return;
|
|
98091
98213
|
}
|
|
98092
|
-
const targetDir =
|
|
98214
|
+
const targetDir = join67(workdir, CANONICAL_RULES_DIR);
|
|
98093
98215
|
if (!options.dryRun) {
|
|
98094
98216
|
try {
|
|
98095
98217
|
await _rulesCLIDeps.mkdir(targetDir);
|
|
@@ -98100,7 +98222,7 @@ async function rulesMigrateCommand(options) {
|
|
|
98100
98222
|
let written = 0;
|
|
98101
98223
|
let skipped = 0;
|
|
98102
98224
|
for (const { sourcePath, targetFileName, content } of sources) {
|
|
98103
|
-
const targetPath =
|
|
98225
|
+
const targetPath = join67(targetDir, targetFileName);
|
|
98104
98226
|
if (!force && !options.dryRun && await _rulesCLIDeps.fileExists(targetPath)) {
|
|
98105
98227
|
console.log(`[skip] ${targetFileName} already exists (use --force to overwrite)`);
|
|
98106
98228
|
skipped++;
|
|
@@ -98139,7 +98261,7 @@ function collectCanonicalRuleRoots(workdir) {
|
|
|
98139
98261
|
const packageRel = normalized.slice(0, idx);
|
|
98140
98262
|
if (!packageRel)
|
|
98141
98263
|
continue;
|
|
98142
|
-
roots.add(
|
|
98264
|
+
roots.add(join67(workdir, packageRel));
|
|
98143
98265
|
}
|
|
98144
98266
|
return [...roots].sort();
|
|
98145
98267
|
}
|
|
@@ -98191,7 +98313,7 @@ init_logger2();
|
|
|
98191
98313
|
init_detect2();
|
|
98192
98314
|
init_workspace();
|
|
98193
98315
|
init_common();
|
|
98194
|
-
import { join as
|
|
98316
|
+
import { join as join68 } from "path";
|
|
98195
98317
|
function resolveEffective(detected, configPatterns) {
|
|
98196
98318
|
if (configPatterns !== undefined)
|
|
98197
98319
|
return "config";
|
|
@@ -98276,7 +98398,7 @@ async function detectCommand(options) {
|
|
|
98276
98398
|
const rootDetected = detectionMap[""] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98277
98399
|
const pkgEntries = await Promise.all(packageDirs.map(async (dir) => {
|
|
98278
98400
|
const det = detectionMap[dir] ?? { patterns: [], confidence: "empty", sources: [] };
|
|
98279
|
-
const pkgConfigPath =
|
|
98401
|
+
const pkgConfigPath = join68(workdir, ".nax", "mono", dir, "config.json");
|
|
98280
98402
|
const pkgRaw = await loadRawConfig(pkgConfigPath);
|
|
98281
98403
|
const pkgPatterns = deepGet(pkgRaw, TEST_PATTERNS_KEY);
|
|
98282
98404
|
const effective = Array.isArray(pkgPatterns) ? pkgPatterns : undefined;
|
|
@@ -98330,13 +98452,13 @@ async function detectCommand(options) {
|
|
|
98330
98452
|
if (rootDetected.confidence === "empty") {
|
|
98331
98453
|
console.log(source_default.yellow(" root: skipped (empty detection)"));
|
|
98332
98454
|
} else {
|
|
98333
|
-
const rootConfigPath =
|
|
98455
|
+
const rootConfigPath = join68(workdir, ".nax", "config.json");
|
|
98334
98456
|
try {
|
|
98335
98457
|
const status = await applyToConfig(rootConfigPath, rootDetected.patterns, options.force ?? false);
|
|
98336
98458
|
if (status === "skipped") {
|
|
98337
98459
|
console.log(source_default.dim(" root: skipped (testFilePatterns already set; use --force to overwrite)"));
|
|
98338
98460
|
} else {
|
|
98339
|
-
console.log(source_default.green(` root: ${status} \u2192 ${
|
|
98461
|
+
console.log(source_default.green(` root: ${status} \u2192 ${join68(".nax", "config.json")}`));
|
|
98340
98462
|
}
|
|
98341
98463
|
} catch (err) {
|
|
98342
98464
|
console.error(source_default.red(` root: write failed \u2014 ${err.message}`));
|
|
@@ -98349,13 +98471,13 @@ async function detectCommand(options) {
|
|
|
98349
98471
|
console.log(source_default.dim(` ${dir}: skipped (empty detection)`));
|
|
98350
98472
|
continue;
|
|
98351
98473
|
}
|
|
98352
|
-
const pkgConfigPath =
|
|
98474
|
+
const pkgConfigPath = join68(workdir, ".nax", "mono", dir, "config.json");
|
|
98353
98475
|
try {
|
|
98354
98476
|
const status = await applyToConfig(pkgConfigPath, det.patterns, options.force ?? false);
|
|
98355
98477
|
if (status === "skipped") {
|
|
98356
98478
|
console.log(source_default.dim(` ${dir}: skipped (already set)`));
|
|
98357
98479
|
} else {
|
|
98358
|
-
console.log(source_default.green(` ${dir}: ${status} \u2192 ${
|
|
98480
|
+
console.log(source_default.green(` ${dir}: ${status} \u2192 ${join68(".nax", "mono", dir, "config.json")}`));
|
|
98359
98481
|
}
|
|
98360
98482
|
} catch (err) {
|
|
98361
98483
|
console.error(source_default.red(` ${dir}: write failed \u2014 ${err.message}`));
|
|
@@ -98373,19 +98495,19 @@ async function detectCommand(options) {
|
|
|
98373
98495
|
// src/commands/logs.ts
|
|
98374
98496
|
init_common();
|
|
98375
98497
|
import { existsSync as existsSync28 } from "fs";
|
|
98376
|
-
import { join as
|
|
98498
|
+
import { join as join71 } from "path";
|
|
98377
98499
|
|
|
98378
98500
|
// src/commands/logs-formatter.ts
|
|
98379
98501
|
init_source();
|
|
98380
98502
|
init_formatter();
|
|
98381
98503
|
import { readdirSync as readdirSync7 } from "fs";
|
|
98382
|
-
import { join as
|
|
98504
|
+
import { join as join70 } from "path";
|
|
98383
98505
|
|
|
98384
98506
|
// src/commands/logs-reader.ts
|
|
98385
98507
|
init_paths3();
|
|
98386
98508
|
import { existsSync as existsSync27, readdirSync as readdirSync6 } from "fs";
|
|
98387
98509
|
import { readdir as readdir3 } from "fs/promises";
|
|
98388
|
-
import { join as
|
|
98510
|
+
import { join as join69 } from "path";
|
|
98389
98511
|
var _logsReaderDeps = {
|
|
98390
98512
|
getRunsDir
|
|
98391
98513
|
};
|
|
@@ -98399,7 +98521,7 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
98399
98521
|
}
|
|
98400
98522
|
let matched = null;
|
|
98401
98523
|
for (const entry of entries) {
|
|
98402
|
-
const metaPath =
|
|
98524
|
+
const metaPath = join69(runsDir, entry, "meta.json");
|
|
98403
98525
|
try {
|
|
98404
98526
|
const meta3 = await Bun.file(metaPath).json();
|
|
98405
98527
|
if (meta3.runId === runId || meta3.runId.startsWith(runId)) {
|
|
@@ -98421,14 +98543,14 @@ async function resolveRunFileFromRegistry(runId) {
|
|
|
98421
98543
|
return null;
|
|
98422
98544
|
}
|
|
98423
98545
|
const specificFile = files.find((f) => f === `${matched.runId}.jsonl`);
|
|
98424
|
-
return
|
|
98546
|
+
return join69(matched.eventsDir, specificFile ?? files[0]);
|
|
98425
98547
|
}
|
|
98426
98548
|
async function selectRunFile(runsDir) {
|
|
98427
98549
|
const files = readdirSync6(runsDir).filter((f) => f.endsWith(".jsonl") && f !== "latest.jsonl").sort().reverse();
|
|
98428
98550
|
if (files.length === 0) {
|
|
98429
98551
|
return null;
|
|
98430
98552
|
}
|
|
98431
|
-
return
|
|
98553
|
+
return join69(runsDir, files[0]);
|
|
98432
98554
|
}
|
|
98433
98555
|
async function extractRunSummary(filePath) {
|
|
98434
98556
|
const file3 = Bun.file(filePath);
|
|
@@ -98514,7 +98636,7 @@ Runs:
|
|
|
98514
98636
|
console.log(source_default.gray(" Timestamp Stories Duration Cost Status"));
|
|
98515
98637
|
console.log(source_default.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
98516
98638
|
for (const file3 of files) {
|
|
98517
|
-
const filePath =
|
|
98639
|
+
const filePath = join70(runsDir, file3);
|
|
98518
98640
|
const summary = await extractRunSummary(filePath);
|
|
98519
98641
|
const timestamp = file3.replace(".jsonl", "");
|
|
98520
98642
|
const stories = summary ? `${summary.passed}/${summary.total}` : "?/?";
|
|
@@ -98628,7 +98750,7 @@ async function logsCommand(options) {
|
|
|
98628
98750
|
return;
|
|
98629
98751
|
}
|
|
98630
98752
|
const resolved = resolveProject({ dir: options.dir });
|
|
98631
|
-
const naxDir =
|
|
98753
|
+
const naxDir = join71(resolved.projectDir, ".nax");
|
|
98632
98754
|
const configPath = resolved.configPath;
|
|
98633
98755
|
const configFile = Bun.file(configPath);
|
|
98634
98756
|
const config2 = await configFile.json();
|
|
@@ -98636,8 +98758,8 @@ async function logsCommand(options) {
|
|
|
98636
98758
|
if (!featureName) {
|
|
98637
98759
|
throw new Error("No feature specified in config.json");
|
|
98638
98760
|
}
|
|
98639
|
-
const featureDir =
|
|
98640
|
-
const runsDir =
|
|
98761
|
+
const featureDir = join71(naxDir, "features", featureName);
|
|
98762
|
+
const runsDir = join71(featureDir, "runs");
|
|
98641
98763
|
if (!existsSync28(runsDir)) {
|
|
98642
98764
|
throw new Error(`No runs directory found for feature: ${featureName}`);
|
|
98643
98765
|
}
|
|
@@ -98663,7 +98785,7 @@ init_prd();
|
|
|
98663
98785
|
init_precheck();
|
|
98664
98786
|
init_common();
|
|
98665
98787
|
import { existsSync as existsSync29 } from "fs";
|
|
98666
|
-
import { join as
|
|
98788
|
+
import { join as join72 } from "path";
|
|
98667
98789
|
async function precheckCommand(options) {
|
|
98668
98790
|
const resolved = resolveProject({
|
|
98669
98791
|
dir: options.dir,
|
|
@@ -98685,9 +98807,9 @@ async function precheckCommand(options) {
|
|
|
98685
98807
|
process.exit(1);
|
|
98686
98808
|
}
|
|
98687
98809
|
}
|
|
98688
|
-
const naxDir =
|
|
98689
|
-
const featureDir =
|
|
98690
|
-
const prdPath =
|
|
98810
|
+
const naxDir = join72(resolved.projectDir, ".nax");
|
|
98811
|
+
const featureDir = join72(naxDir, "features", featureName);
|
|
98812
|
+
const prdPath = join72(featureDir, "prd.json");
|
|
98691
98813
|
if (!existsSync29(featureDir)) {
|
|
98692
98814
|
console.error(source_default.red(`Feature not found: ${featureName}`));
|
|
98693
98815
|
process.exit(1);
|
|
@@ -98710,7 +98832,7 @@ async function precheckCommand(options) {
|
|
|
98710
98832
|
init_source();
|
|
98711
98833
|
init_paths3();
|
|
98712
98834
|
import { readdir as readdir4 } from "fs/promises";
|
|
98713
|
-
import { join as
|
|
98835
|
+
import { join as join73 } from "path";
|
|
98714
98836
|
var DEFAULT_LIMIT = 20;
|
|
98715
98837
|
var _runsCmdDeps = {
|
|
98716
98838
|
getRunsDir
|
|
@@ -98765,7 +98887,7 @@ async function runsCommand(options = {}) {
|
|
|
98765
98887
|
}
|
|
98766
98888
|
const rows = [];
|
|
98767
98889
|
for (const entry of entries) {
|
|
98768
|
-
const metaPath =
|
|
98890
|
+
const metaPath = join73(runsDir, entry, "meta.json");
|
|
98769
98891
|
let meta3;
|
|
98770
98892
|
try {
|
|
98771
98893
|
meta3 = await Bun.file(metaPath).json();
|
|
@@ -98842,7 +98964,7 @@ async function runsCommand(options = {}) {
|
|
|
98842
98964
|
|
|
98843
98965
|
// src/commands/unlock.ts
|
|
98844
98966
|
init_source();
|
|
98845
|
-
import { join as
|
|
98967
|
+
import { join as join74 } from "path";
|
|
98846
98968
|
function isProcessAlive2(pid) {
|
|
98847
98969
|
try {
|
|
98848
98970
|
process.kill(pid, 0);
|
|
@@ -98857,7 +98979,7 @@ function formatLockAge(ageMs) {
|
|
|
98857
98979
|
}
|
|
98858
98980
|
async function unlockCommand(options) {
|
|
98859
98981
|
const workdir = options.dir ?? process.cwd();
|
|
98860
|
-
const lockPath =
|
|
98982
|
+
const lockPath = join74(workdir, "nax.lock");
|
|
98861
98983
|
const lockFile = Bun.file(lockPath);
|
|
98862
98984
|
const exists = await lockFile.exists();
|
|
98863
98985
|
if (!exists) {
|
|
@@ -107295,7 +107417,7 @@ Next: nax generate --package ${options.package}`));
|
|
|
107295
107417
|
}
|
|
107296
107418
|
return;
|
|
107297
107419
|
}
|
|
107298
|
-
const naxDir =
|
|
107420
|
+
const naxDir = join88(workdir, ".nax");
|
|
107299
107421
|
if (existsSync35(naxDir) && !options.force) {
|
|
107300
107422
|
console.log(source_default.yellow("nax already initialized. Use --force to overwrite."));
|
|
107301
107423
|
return;
|
|
@@ -107324,11 +107446,11 @@ Next: nax generate --package ${options.package}`));
|
|
|
107324
107446
|
}
|
|
107325
107447
|
}
|
|
107326
107448
|
}
|
|
107327
|
-
mkdirSync7(
|
|
107328
|
-
mkdirSync7(
|
|
107449
|
+
mkdirSync7(join88(naxDir, "features"), { recursive: true });
|
|
107450
|
+
mkdirSync7(join88(naxDir, "hooks"), { recursive: true });
|
|
107329
107451
|
const initConfig = options.name ? { ...DEFAULT_CONFIG, name: options.name } : DEFAULT_CONFIG;
|
|
107330
|
-
await Bun.write(
|
|
107331
|
-
await Bun.write(
|
|
107452
|
+
await Bun.write(join88(naxDir, "config.json"), JSON.stringify(initConfig, null, 2));
|
|
107453
|
+
await Bun.write(join88(naxDir, "hooks.json"), JSON.stringify({
|
|
107332
107454
|
hooks: {
|
|
107333
107455
|
"on-start": { command: 'echo "nax started: $NAX_FEATURE"', enabled: false },
|
|
107334
107456
|
"on-complete": { command: 'echo "nax complete: $NAX_FEATURE"', enabled: false },
|
|
@@ -107336,12 +107458,12 @@ Next: nax generate --package ${options.package}`));
|
|
|
107336
107458
|
"on-error": { command: 'echo "nax error: $NAX_REASON"', enabled: false }
|
|
107337
107459
|
}
|
|
107338
107460
|
}, null, 2));
|
|
107339
|
-
await Bun.write(
|
|
107461
|
+
await Bun.write(join88(naxDir, ".gitignore"), `# nax temp files
|
|
107340
107462
|
*.tmp
|
|
107341
107463
|
.paused.json
|
|
107342
107464
|
.nax-verifier-verdict.json
|
|
107343
107465
|
`);
|
|
107344
|
-
await Bun.write(
|
|
107466
|
+
await Bun.write(join88(naxDir, "context.md"), `# Project Context
|
|
107345
107467
|
|
|
107346
107468
|
This document defines coding standards, architectural decisions, and forbidden patterns for this project.
|
|
107347
107469
|
Run \`nax generate\` to regenerate agent config files (CLAUDE.md, AGENTS.md, .cursorrules, etc.) from this file.
|
|
@@ -107483,7 +107605,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107483
107605
|
const cliOverrides = {};
|
|
107484
107606
|
const cliProfiles = options.profile ?? [];
|
|
107485
107607
|
const profileOverride = naxDir ? await resolveRunProfileOverride({
|
|
107486
|
-
prdPath:
|
|
107608
|
+
prdPath: join88(naxDir, "features", options.feature, "prd.json"),
|
|
107487
107609
|
projectRoot: workdir,
|
|
107488
107610
|
cliProfile: cliProfiles,
|
|
107489
107611
|
envProfile: process.env.NAX_PROFILE
|
|
@@ -107496,8 +107618,8 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107496
107618
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
107497
107619
|
process.exit(1);
|
|
107498
107620
|
}
|
|
107499
|
-
const featureDir =
|
|
107500
|
-
const prdPath =
|
|
107621
|
+
const featureDir = join88(naxDir, "features", options.feature);
|
|
107622
|
+
const prdPath = join88(featureDir, "prd.json");
|
|
107501
107623
|
if (options.plan && options.from) {
|
|
107502
107624
|
if (existsSync35(prdPath) && !options.force) {
|
|
107503
107625
|
console.error(source_default.red(`Error: prd.json already exists for feature "${options.feature}".`));
|
|
@@ -107519,10 +107641,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107519
107641
|
}
|
|
107520
107642
|
}
|
|
107521
107643
|
try {
|
|
107522
|
-
const planLogDir =
|
|
107644
|
+
const planLogDir = join88(featureDir, "plan");
|
|
107523
107645
|
mkdirSync7(planLogDir, { recursive: true });
|
|
107524
107646
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107525
|
-
const planLogPath =
|
|
107647
|
+
const planLogPath = join88(planLogDir, `${planLogId}.jsonl`);
|
|
107526
107648
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
107527
107649
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
107528
107650
|
console.log(source_default.dim(" [Planning phase: generating PRD from spec]"));
|
|
@@ -107568,10 +107690,10 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107568
107690
|
resetLogger();
|
|
107569
107691
|
const projectKey = config2.name?.trim() || basename16(workdir);
|
|
107570
107692
|
const outputDir = projectOutputDir(projectKey, config2.outputDir);
|
|
107571
|
-
const runsDir =
|
|
107693
|
+
const runsDir = join88(outputDir, "features", options.feature, "runs");
|
|
107572
107694
|
mkdirSync7(runsDir, { recursive: true });
|
|
107573
107695
|
const runId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107574
|
-
const logFilePath =
|
|
107696
|
+
const logFilePath = join88(runsDir, `${runId}.jsonl`);
|
|
107575
107697
|
const isTTY = process.stdout.isTTY ?? false;
|
|
107576
107698
|
const headlessFlag = options.headless ?? false;
|
|
107577
107699
|
const headlessEnv = process.env.NAX_HEADLESS === "1";
|
|
@@ -107589,7 +107711,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107589
107711
|
config2.agent.default = options.agent;
|
|
107590
107712
|
}
|
|
107591
107713
|
config2.execution.maxIterations = Number.parseInt(options.maxIterations, 10);
|
|
107592
|
-
const globalNaxDir =
|
|
107714
|
+
const globalNaxDir = join88(homedir3(), ".nax");
|
|
107593
107715
|
const hooks = await loadHooksConfig(naxDir, globalNaxDir);
|
|
107594
107716
|
const eventEmitter = new PipelineEventEmitter;
|
|
107595
107717
|
const agentStreamEvents = useHeadless ? undefined : new AgentStreamEventBus;
|
|
@@ -107609,12 +107731,12 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107609
107731
|
events: eventEmitter,
|
|
107610
107732
|
ptyOptions: null,
|
|
107611
107733
|
agentStreamEvents,
|
|
107612
|
-
queueFilePath:
|
|
107734
|
+
queueFilePath: join88(workdir, ".queue.txt")
|
|
107613
107735
|
});
|
|
107614
107736
|
} else {
|
|
107615
107737
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
107616
107738
|
}
|
|
107617
|
-
const statusFilePath =
|
|
107739
|
+
const statusFilePath = join88(outputDir, "status.json");
|
|
107618
107740
|
let parallel;
|
|
107619
107741
|
if (options.parallel !== undefined) {
|
|
107620
107742
|
parallel = Number.parseInt(options.parallel, 10);
|
|
@@ -107641,7 +107763,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
107641
107763
|
skipPrecheck: options.skipPrecheck ?? false,
|
|
107642
107764
|
agentStreamEvents
|
|
107643
107765
|
});
|
|
107644
|
-
const latestSymlink =
|
|
107766
|
+
const latestSymlink = join88(runsDir, "latest.jsonl");
|
|
107645
107767
|
try {
|
|
107646
107768
|
if (existsSync35(latestSymlink)) {
|
|
107647
107769
|
Bun.spawnSync(["rm", latestSymlink]);
|
|
@@ -107702,9 +107824,9 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
107702
107824
|
console.error(source_default.red("nax not initialized. Run: nax init"));
|
|
107703
107825
|
process.exit(1);
|
|
107704
107826
|
}
|
|
107705
|
-
const featureDir =
|
|
107827
|
+
const featureDir = join88(naxDir, "features", name);
|
|
107706
107828
|
mkdirSync7(featureDir, { recursive: true });
|
|
107707
|
-
await Bun.write(
|
|
107829
|
+
await Bun.write(join88(featureDir, "spec.md"), `# Feature: ${name}
|
|
107708
107830
|
|
|
107709
107831
|
## Overview
|
|
107710
107832
|
|
|
@@ -107737,7 +107859,7 @@ features.command("create <name>").description("Create a new feature").option("-d
|
|
|
107737
107859
|
|
|
107738
107860
|
<!-- What this feature explicitly does NOT cover. -->
|
|
107739
107861
|
`);
|
|
107740
|
-
await Bun.write(
|
|
107862
|
+
await Bun.write(join88(featureDir, "progress.txt"), `# Progress: ${name}
|
|
107741
107863
|
|
|
107742
107864
|
Created: ${new Date().toISOString()}
|
|
107743
107865
|
|
|
@@ -107763,7 +107885,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
107763
107885
|
console.error(source_default.red("nax not initialized."));
|
|
107764
107886
|
process.exit(1);
|
|
107765
107887
|
}
|
|
107766
|
-
const featuresDir =
|
|
107888
|
+
const featuresDir = join88(naxDir, "features");
|
|
107767
107889
|
if (!existsSync35(featuresDir)) {
|
|
107768
107890
|
console.log(source_default.dim("No features yet."));
|
|
107769
107891
|
return;
|
|
@@ -107778,7 +107900,7 @@ features.command("list").description("List all features").option("-d, --dir <pat
|
|
|
107778
107900
|
Features:
|
|
107779
107901
|
`));
|
|
107780
107902
|
for (const name of entries) {
|
|
107781
|
-
const prdPath =
|
|
107903
|
+
const prdPath = join88(featuresDir, name, "prd.json");
|
|
107782
107904
|
if (existsSync35(prdPath)) {
|
|
107783
107905
|
const prd = await loadPRD(prdPath);
|
|
107784
107906
|
const c = countStories(prd);
|
|
@@ -107814,10 +107936,10 @@ Use: nax plan -f <feature> --from <spec>`));
|
|
|
107814
107936
|
cliOverrides.profile = cliProfiles;
|
|
107815
107937
|
}
|
|
107816
107938
|
const config2 = await loadConfig(workdir, cliOverrides);
|
|
107817
|
-
const featureLogDir =
|
|
107939
|
+
const featureLogDir = join88(naxDir, "features", options.feature, "plan");
|
|
107818
107940
|
mkdirSync7(featureLogDir, { recursive: true });
|
|
107819
107941
|
const planLogId = new Date().toISOString().replace(/:/g, "-").replace(/\..+/, "");
|
|
107820
|
-
const planLogPath =
|
|
107942
|
+
const planLogPath = join88(featureLogDir, `${planLogId}.jsonl`);
|
|
107821
107943
|
initLogger({ level: "info", filePath: planLogPath, useChalk: false, headless: true });
|
|
107822
107944
|
console.log(source_default.dim(` [Plan log: ${planLogPath}]`));
|
|
107823
107945
|
try {
|