@nathapp/nax 0.67.0-canary.3 → 0.67.0-canary.4
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 +708 -622
- package/package.json +6 -4
package/dist/nax.js
CHANGED
|
@@ -17904,7 +17904,7 @@ function formatConsole(entry) {
|
|
|
17904
17904
|
const timestamp = new Date(entry.timestamp).toLocaleTimeString("en-US", {
|
|
17905
17905
|
hour12: false
|
|
17906
17906
|
});
|
|
17907
|
-
let levelColor;
|
|
17907
|
+
let levelColor = source_default.gray;
|
|
17908
17908
|
switch (entry.level) {
|
|
17909
17909
|
case "error":
|
|
17910
17910
|
levelColor = source_default.red;
|
|
@@ -17916,6 +17916,7 @@ function formatConsole(entry) {
|
|
|
17916
17916
|
levelColor = source_default.blue;
|
|
17917
17917
|
break;
|
|
17918
17918
|
case "debug":
|
|
17919
|
+
case "silent":
|
|
17919
17920
|
levelColor = source_default.gray;
|
|
17920
17921
|
break;
|
|
17921
17922
|
}
|
|
@@ -18064,7 +18065,7 @@ ${JSON.stringify(entry.data, null, 2)}`;
|
|
|
18064
18065
|
}
|
|
18065
18066
|
close() {}
|
|
18066
18067
|
}
|
|
18067
|
-
function initLogger(options = { level: "
|
|
18068
|
+
function initLogger(options = { level: "silent" }) {
|
|
18068
18069
|
if (instance) {
|
|
18069
18070
|
throw new Error("Logger already initialized. Call getLogger() to access existing instance.");
|
|
18070
18071
|
}
|
|
@@ -18095,12 +18096,13 @@ var init_logger = __esm(() => {
|
|
|
18095
18096
|
init_logging();
|
|
18096
18097
|
init_formatters();
|
|
18097
18098
|
LOG_LEVEL_PRIORITY = {
|
|
18099
|
+
silent: -1,
|
|
18098
18100
|
error: 0,
|
|
18099
18101
|
warn: 1,
|
|
18100
18102
|
info: 2,
|
|
18101
18103
|
debug: 3
|
|
18102
18104
|
};
|
|
18103
|
-
noopLogger = new Logger({ level: "
|
|
18105
|
+
noopLogger = new Logger({ level: "silent", useChalk: false, headless: false });
|
|
18104
18106
|
});
|
|
18105
18107
|
|
|
18106
18108
|
// src/logger/index.ts
|
|
@@ -34213,6 +34215,7 @@ var init_debate_propose = __esm(() => {
|
|
|
34213
34215
|
return "fast";
|
|
34214
34216
|
return { agent: debater.agent, model: debater.model ?? "fast" };
|
|
34215
34217
|
},
|
|
34218
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34216
34219
|
build(input, _ctx) {
|
|
34217
34220
|
const builder = new DebatePromptBuilder({ taskContext: input.taskContext, outputFormat: input.outputFormat, stage: input.stage }, { debaters: input.debaters, sessionMode: "one-shot", proposers: input.stageConfig?.proposers });
|
|
34218
34221
|
return builder.proposeSlot(input.debaterIndex);
|
|
@@ -34235,6 +34238,7 @@ var init_debate_judge = __esm(() => {
|
|
|
34235
34238
|
jsonMode: false,
|
|
34236
34239
|
config: debateConfigSelector,
|
|
34237
34240
|
model: (input) => ({ agent: input.resolverAgent, model: input.resolverModel }),
|
|
34241
|
+
timeoutMs: (input, ctx) => (input.timeoutSeconds ?? ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34238
34242
|
build(input, _ctx) {
|
|
34239
34243
|
const prompt = DebatePromptBuilder.resolverJudgePrompt(input.proposals, input.critiques, input.debaters);
|
|
34240
34244
|
return {
|
|
@@ -34260,6 +34264,7 @@ var init_debate_synthesis = __esm(() => {
|
|
|
34260
34264
|
jsonMode: false,
|
|
34261
34265
|
config: debateConfigSelector,
|
|
34262
34266
|
model: (input) => ({ agent: input.resolverAgent, model: input.resolverModel }),
|
|
34267
|
+
timeoutMs: (input, ctx) => (input.timeoutSeconds ?? ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34263
34268
|
build(input, _ctx) {
|
|
34264
34269
|
const base = DebatePromptBuilder.resolverSynthesisPrompt(input.proposals, input.critiques, input.debaters);
|
|
34265
34270
|
const content = input.promptSuffix ? `${base}
|
|
@@ -34293,6 +34298,7 @@ var init_debate_rebut = __esm(() => {
|
|
|
34293
34298
|
return "fast";
|
|
34294
34299
|
return { agent: debater.agent, model: debater.model ?? "fast" };
|
|
34295
34300
|
},
|
|
34301
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34296
34302
|
build(input, _ctx) {
|
|
34297
34303
|
const builder = new DebatePromptBuilder({ taskContext: input.taskContext, outputFormat: "", stage: input.stage }, { debaters: input.debaters, sessionMode: "one-shot" });
|
|
34298
34304
|
return builder.rebutSlot(input.debaterIndex, input.proposals);
|
|
@@ -34339,6 +34345,7 @@ var init_debate_stateful = __esm(() => {
|
|
|
34339
34345
|
session: { role: "debate-stateful", lifetime: "fresh" },
|
|
34340
34346
|
config: debateConfigSelector,
|
|
34341
34347
|
model: (input) => ({ agent: input.debater.agent, model: input.debater.model ?? "fast" }),
|
|
34348
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34342
34349
|
async hopBody(initialPrompt, ctx) {
|
|
34343
34350
|
const proposal = ctx.input.turnSemaphore ? await ctx.input.turnSemaphore.run(() => ctx.send(initialPrompt)) : await ctx.send(initialPrompt);
|
|
34344
34351
|
ctx.input.proposalBarriers[ctx.input.index].resolve(proposal.output);
|
|
@@ -34510,7 +34517,8 @@ var RESOLVER_FALLBACK_AGENT = "synthesis", RESOLVER_FALLBACK_MODEL = "fast", jud
|
|
|
34510
34517
|
critiques: ctx.critiques,
|
|
34511
34518
|
debaters: ctx.debaters,
|
|
34512
34519
|
resolverAgent,
|
|
34513
|
-
resolverModel
|
|
34520
|
+
resolverModel,
|
|
34521
|
+
timeoutSeconds: ctx.stageConfig.timeoutSeconds
|
|
34514
34522
|
});
|
|
34515
34523
|
return {
|
|
34516
34524
|
outcome: output.trim() ? "passed" : "failed",
|
|
@@ -34533,7 +34541,8 @@ var RESOLVER_FALLBACK_AGENT2 = "synthesis", RESOLVER_FALLBACK_MODEL2 = "fast", s
|
|
|
34533
34541
|
debaters: ctx.debaters,
|
|
34534
34542
|
resolverAgent,
|
|
34535
34543
|
resolverModel,
|
|
34536
|
-
promptSuffix: ctx.promptSuffix
|
|
34544
|
+
promptSuffix: ctx.promptSuffix,
|
|
34545
|
+
timeoutSeconds: ctx.stageConfig.timeoutSeconds
|
|
34537
34546
|
});
|
|
34538
34547
|
return {
|
|
34539
34548
|
outcome: output.trim() ? "passed" : "failed",
|
|
@@ -34846,6 +34855,7 @@ var init_debate_hybrid = __esm(() => {
|
|
|
34846
34855
|
session: { role: "debate-hybrid", lifetime: "fresh" },
|
|
34847
34856
|
config: debateConfigSelector,
|
|
34848
34857
|
model: (input) => ({ agent: input.debater.agent, model: input.debater.model ?? "fast" }),
|
|
34858
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.review?.timeoutSeconds ?? 600) * 1000,
|
|
34849
34859
|
async hopBody(initialPrompt, ctx) {
|
|
34850
34860
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
34851
34861
|
let totalCostUsd = 0;
|
|
@@ -34909,6 +34919,7 @@ var init_debate_plan = __esm(() => {
|
|
|
34909
34919
|
session: { role: "debate-plan", lifetime: "fresh" },
|
|
34910
34920
|
config: debateConfigSelector,
|
|
34911
34921
|
model: (input) => ({ agent: input.debater.agent, model: input.debater.model ?? "fast" }),
|
|
34922
|
+
timeoutMs: (_input, ctx) => (ctx.config.debate?.stages?.plan?.timeoutSeconds ?? 600) * 1000,
|
|
34912
34923
|
fileOutput: (input) => input.outputPath,
|
|
34913
34924
|
async hopBody(initialPrompt, ctx) {
|
|
34914
34925
|
const proposal = ctx.input.turnSemaphore ? await ctx.input.turnSemaphore.run(() => ctx.send(initialPrompt)) : await ctx.send(initialPrompt);
|
|
@@ -36848,7 +36859,7 @@ function countTotalAttempts(iterations) {
|
|
|
36848
36859
|
return iterations.reduce((sum, iter) => sum + iter.fixesApplied.length, 0);
|
|
36849
36860
|
}
|
|
36850
36861
|
async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
36851
|
-
const logger = getSafeLogger();
|
|
36862
|
+
const logger = _deps.logger !== undefined ? _deps.logger : getSafeLogger();
|
|
36852
36863
|
const doCallOp = _deps.callOp ?? _cycleDeps.callOp;
|
|
36853
36864
|
const now = _deps.now ?? _cycleDeps.now;
|
|
36854
36865
|
const storyId = ctx.storyId;
|
|
@@ -36978,29 +36989,77 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
|
36978
36989
|
costUsd: totalCostUsd
|
|
36979
36990
|
};
|
|
36980
36991
|
}
|
|
36981
|
-
const
|
|
36982
|
-
|
|
36992
|
+
const allExhausted = group.every((s) => {
|
|
36993
|
+
const prior = countStrategyAttempts(cycle.iterations, s.name);
|
|
36994
|
+
const current = fixesApplied.filter((fa) => fa.strategyName === s.name).length;
|
|
36995
|
+
return prior + current >= s.maxAttempts;
|
|
36996
|
+
});
|
|
36983
36997
|
if (allExhausted) {
|
|
36998
|
+
let liteFindingsAfter;
|
|
36999
|
+
try {
|
|
37000
|
+
liteFindingsAfter = await cycle.validate(ctx, { mode: "lite" });
|
|
37001
|
+
} catch (err) {
|
|
37002
|
+
const finishedAt3 = now();
|
|
37003
|
+
cycle.iterations.push({
|
|
37004
|
+
iterationNum: cycle.iterations.length + 1,
|
|
37005
|
+
findingsBefore,
|
|
37006
|
+
fixesApplied,
|
|
37007
|
+
findingsAfter: cycle.findings,
|
|
37008
|
+
outcome: "unchanged",
|
|
37009
|
+
startedAt,
|
|
37010
|
+
finishedAt: finishedAt3
|
|
37011
|
+
});
|
|
37012
|
+
logger?.warn("findings.cycle", "lite validate failed on terminal exhausted branch", {
|
|
37013
|
+
storyId,
|
|
37014
|
+
packageDir,
|
|
37015
|
+
cycleName,
|
|
37016
|
+
error: errorMessage(err)
|
|
37017
|
+
});
|
|
37018
|
+
return {
|
|
37019
|
+
iterations: cycle.iterations,
|
|
37020
|
+
finalFindings: cycle.findings,
|
|
37021
|
+
exitReason: "max-attempts-per-strategy",
|
|
37022
|
+
exhaustedStrategy: group[0]?.name,
|
|
37023
|
+
costUsd: totalCostUsd
|
|
37024
|
+
};
|
|
37025
|
+
}
|
|
37026
|
+
const outcome2 = classifyOutcome(findingsBefore, liteFindingsAfter);
|
|
36984
37027
|
const finishedAt2 = now();
|
|
36985
37028
|
cycle.iterations.push({
|
|
36986
37029
|
iterationNum: cycle.iterations.length + 1,
|
|
36987
37030
|
findingsBefore,
|
|
36988
37031
|
fixesApplied,
|
|
36989
|
-
findingsAfter:
|
|
36990
|
-
outcome:
|
|
37032
|
+
findingsAfter: liteFindingsAfter,
|
|
37033
|
+
outcome: outcome2,
|
|
36991
37034
|
startedAt,
|
|
36992
37035
|
finishedAt: finishedAt2
|
|
36993
37036
|
});
|
|
36994
|
-
|
|
37037
|
+
cycle.findings = liteFindingsAfter;
|
|
37038
|
+
if (liteFindingsAfter.length === 0) {
|
|
37039
|
+
logger?.info("findings.cycle", "cycle exited \u2014 resolved after terminal lite validate", {
|
|
37040
|
+
storyId,
|
|
37041
|
+
packageDir,
|
|
37042
|
+
cycleName,
|
|
37043
|
+
reason: "resolved"
|
|
37044
|
+
});
|
|
37045
|
+
return {
|
|
37046
|
+
iterations: cycle.iterations,
|
|
37047
|
+
finalFindings: [],
|
|
37048
|
+
exitReason: "resolved",
|
|
37049
|
+
costUsd: totalCostUsd
|
|
37050
|
+
};
|
|
37051
|
+
}
|
|
37052
|
+
logger?.info("findings.cycle", "cycle exited \u2014 strategy attempt cap reached (lite validate)", {
|
|
36995
37053
|
storyId,
|
|
36996
37054
|
packageDir,
|
|
36997
37055
|
cycleName,
|
|
36998
37056
|
reason: "max-attempts-per-strategy",
|
|
36999
|
-
exhaustedStrategy: group[0]?.name
|
|
37057
|
+
exhaustedStrategy: group[0]?.name,
|
|
37058
|
+
liteFindingsAfterCount: liteFindingsAfter.length
|
|
37000
37059
|
});
|
|
37001
37060
|
return {
|
|
37002
37061
|
iterations: cycle.iterations,
|
|
37003
|
-
finalFindings:
|
|
37062
|
+
finalFindings: liteFindingsAfter,
|
|
37004
37063
|
exitReason: "max-attempts-per-strategy",
|
|
37005
37064
|
exhaustedStrategy: group[0]?.name,
|
|
37006
37065
|
costUsd: totalCostUsd
|
|
@@ -37010,7 +37069,7 @@ async function runFixCycle(cycle, ctx, cycleName, _deps = {}) {
|
|
|
37010
37069
|
let validatorAttempt = 0;
|
|
37011
37070
|
for (;; ) {
|
|
37012
37071
|
try {
|
|
37013
|
-
findingsAfter = await cycle.validate(ctx);
|
|
37072
|
+
findingsAfter = await cycle.validate(ctx, { mode: "full" });
|
|
37014
37073
|
break;
|
|
37015
37074
|
} catch (err) {
|
|
37016
37075
|
if (validatorAttempt >= cycle.config.validatorRetries) {
|
|
@@ -39290,8 +39349,481 @@ async function runRetryLoop(input) {
|
|
|
39290
39349
|
return { outcome: "exhausted", attempts: input.maxAttempts, finalFailure: currentFailure };
|
|
39291
39350
|
}
|
|
39292
39351
|
|
|
39352
|
+
// src/execution/escalation/escalation.ts
|
|
39353
|
+
function escalateTier(currentTier, tierOrder) {
|
|
39354
|
+
const getName = (t) => t.tier ?? t.name ?? null;
|
|
39355
|
+
const currentIndex = tierOrder.findIndex((t) => getName(t) === currentTier);
|
|
39356
|
+
if (currentIndex === -1 || currentIndex === tierOrder.length - 1) {
|
|
39357
|
+
return null;
|
|
39358
|
+
}
|
|
39359
|
+
const next = tierOrder[currentIndex + 1];
|
|
39360
|
+
const nextName = getName(next);
|
|
39361
|
+
if (!nextName)
|
|
39362
|
+
return null;
|
|
39363
|
+
return { tier: nextName, agent: next.agent };
|
|
39364
|
+
}
|
|
39365
|
+
function calculateMaxIterations(tierOrder) {
|
|
39366
|
+
return tierOrder.reduce((sum, t) => sum + t.attempts, 0);
|
|
39367
|
+
}
|
|
39368
|
+
|
|
39369
|
+
// src/session/naming.ts
|
|
39370
|
+
var exports_naming = {};
|
|
39371
|
+
__export(exports_naming, {
|
|
39372
|
+
formatSessionName: () => formatSessionName
|
|
39373
|
+
});
|
|
39374
|
+
var init_naming = __esm(() => {
|
|
39375
|
+
init_session_name();
|
|
39376
|
+
});
|
|
39377
|
+
|
|
39378
|
+
// src/verification/failure-records.ts
|
|
39379
|
+
function truncateUnmappedFailureOutput(output) {
|
|
39380
|
+
const tailLines = output.split(`
|
|
39381
|
+
`).slice(-UNMAPPED_FAILURE_OUTPUT_MAX_LINES).join(`
|
|
39382
|
+
`);
|
|
39383
|
+
if (tailLines.length <= UNMAPPED_FAILURE_OUTPUT_MAX_CHARS) {
|
|
39384
|
+
return tailLines;
|
|
39385
|
+
}
|
|
39386
|
+
return `... (truncated)
|
|
39387
|
+
${tailLines.slice(-UNMAPPED_FAILURE_OUTPUT_MAX_CHARS)}`;
|
|
39388
|
+
}
|
|
39389
|
+
function buildFailureRecords(testSummary, rawOutput) {
|
|
39390
|
+
if (testSummary.failures.length > 0) {
|
|
39391
|
+
return testSummary.failures.map((failure) => ({
|
|
39392
|
+
test: failure.testName,
|
|
39393
|
+
file: failure.file,
|
|
39394
|
+
message: failure.error,
|
|
39395
|
+
output: failure.stackTrace.length > 0 ? failure.stackTrace.join(`
|
|
39396
|
+
`) : undefined
|
|
39397
|
+
}));
|
|
39398
|
+
}
|
|
39399
|
+
if (testSummary.failed === 0) {
|
|
39400
|
+
return [];
|
|
39401
|
+
}
|
|
39402
|
+
return [
|
|
39403
|
+
{
|
|
39404
|
+
test: `Unmapped test failures (${testSummary.failed} detected)`,
|
|
39405
|
+
message: "Structured test failure parsing returned no failure records. Diagnose the regression from the raw test output.",
|
|
39406
|
+
output: rawOutput?.trim() ? truncateUnmappedFailureOutput(rawOutput.trim()) : undefined
|
|
39407
|
+
}
|
|
39408
|
+
];
|
|
39409
|
+
}
|
|
39410
|
+
var UNMAPPED_FAILURE_OUTPUT_MAX_LINES = 200, UNMAPPED_FAILURE_OUTPUT_MAX_CHARS = 8000;
|
|
39411
|
+
|
|
39412
|
+
// src/verification/rectification-loop.ts
|
|
39413
|
+
async function _defaultRunDebate(storyId, stageConfig, prompt, config2, agentManager) {
|
|
39414
|
+
const logger = getSafeLogger();
|
|
39415
|
+
const debaters = stageConfig.debaters ?? [];
|
|
39416
|
+
const manager = agentManager;
|
|
39417
|
+
const resolved = [];
|
|
39418
|
+
for (const debater of debaters) {
|
|
39419
|
+
if (manager.getAgent(debater.agent)) {
|
|
39420
|
+
resolved.push({ debater, agentName: debater.agent });
|
|
39421
|
+
}
|
|
39422
|
+
}
|
|
39423
|
+
if (resolved.length === 0) {
|
|
39424
|
+
return { output: null, totalCostUsd: 0 };
|
|
39425
|
+
}
|
|
39426
|
+
const timeoutMs = (config2.execution?.sessionTimeoutSeconds ?? 600) * 1000;
|
|
39427
|
+
const defaultAgentName = resolveDefaultAgent(config2);
|
|
39428
|
+
const resolvedDebaters = resolved.map(({ debater, agentName }) => {
|
|
39429
|
+
let modelDef;
|
|
39430
|
+
try {
|
|
39431
|
+
modelDef = resolveConfiguredModel(config2.models, agentName, debater.model ?? "balanced", defaultAgentName).modelDef;
|
|
39432
|
+
} catch {
|
|
39433
|
+
modelDef = { provider: "unknown", model: debater.model ?? "default" };
|
|
39434
|
+
}
|
|
39435
|
+
return { debater, agentName, modelDef };
|
|
39436
|
+
});
|
|
39437
|
+
const startMs = Date.now();
|
|
39438
|
+
const proposalSettled = await Promise.allSettled(resolvedDebaters.map(({ agentName, modelDef }) => manager.completeAs(agentName, prompt, {
|
|
39439
|
+
modelDef,
|
|
39440
|
+
workdir: "",
|
|
39441
|
+
storyId,
|
|
39442
|
+
sessionRole: "debate-proposal",
|
|
39443
|
+
timeoutMs
|
|
39444
|
+
}).then((out) => typeof out === "string" ? out : out.output)));
|
|
39445
|
+
const durationMs = Date.now() - startMs;
|
|
39446
|
+
const successful = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
39447
|
+
if (successful.length === 0) {
|
|
39448
|
+
return { output: null, totalCostUsd: 0 };
|
|
39449
|
+
}
|
|
39450
|
+
const successCount = successful.length;
|
|
39451
|
+
const costPerDebater = estimateCostByDuration("balanced", durationMs / successCount);
|
|
39452
|
+
const totalCostUsd = costPerDebater.cost * successCount;
|
|
39453
|
+
logger?.debug("rectification", "debate diagnosis complete", { storyId, successCount, totalCostUsd });
|
|
39454
|
+
const output = successful.join(`
|
|
39455
|
+
|
|
39456
|
+
`);
|
|
39457
|
+
return { output, totalCostUsd };
|
|
39458
|
+
}
|
|
39459
|
+
async function runRectificationLoop(opts) {
|
|
39460
|
+
const loopStartMs = Date.now();
|
|
39461
|
+
const {
|
|
39462
|
+
config: config2,
|
|
39463
|
+
workdir,
|
|
39464
|
+
story,
|
|
39465
|
+
testCommand,
|
|
39466
|
+
timeoutSeconds,
|
|
39467
|
+
testOutput,
|
|
39468
|
+
promptPrefix,
|
|
39469
|
+
featureName,
|
|
39470
|
+
projectDir,
|
|
39471
|
+
testScopedTemplate,
|
|
39472
|
+
sessionId,
|
|
39473
|
+
runtime
|
|
39474
|
+
} = opts;
|
|
39475
|
+
const logger = getSafeLogger();
|
|
39476
|
+
const agentManager = opts.agentManager ?? _rectificationDeps.agentManager;
|
|
39477
|
+
if (!agentManager) {
|
|
39478
|
+
logger?.warn("rectification", "No agentManager threaded \u2014 skipping rectification loop", {
|
|
39479
|
+
storyId: story.id
|
|
39480
|
+
});
|
|
39481
|
+
return { succeeded: false, cost: 0, durationMs: 0 };
|
|
39482
|
+
}
|
|
39483
|
+
const rectificationConfig = config2.execution.rectification;
|
|
39484
|
+
const testSummary = parseTestOutput(testOutput);
|
|
39485
|
+
const label = promptPrefix ? "regression rectification" : "rectification";
|
|
39486
|
+
const rectificationSessionName = formatSessionName({
|
|
39487
|
+
workdir,
|
|
39488
|
+
featureName,
|
|
39489
|
+
storyId: story.id,
|
|
39490
|
+
role: "implementer"
|
|
39491
|
+
});
|
|
39492
|
+
let costAccum = 0;
|
|
39493
|
+
let currentAttempt = 0;
|
|
39494
|
+
let heldHandle;
|
|
39495
|
+
const initialFailure = {
|
|
39496
|
+
testOutput,
|
|
39497
|
+
testSummary
|
|
39498
|
+
};
|
|
39499
|
+
const outcome = await runRetryLoop({
|
|
39500
|
+
stage: "rectification",
|
|
39501
|
+
storyId: story.id,
|
|
39502
|
+
packageDir: workdir,
|
|
39503
|
+
maxAttempts: rectificationConfig.maxRetries,
|
|
39504
|
+
failure: initialFailure,
|
|
39505
|
+
previousAttempts: [],
|
|
39506
|
+
buildPrompt: (failure) => {
|
|
39507
|
+
currentAttempt++;
|
|
39508
|
+
const diagnosisPrefix = null;
|
|
39509
|
+
const debateStageConfig = config2.debate?.stages?.rectification;
|
|
39510
|
+
let debatePromise = Promise.resolve(null);
|
|
39511
|
+
if (debateStageConfig?.enabled) {
|
|
39512
|
+
const failureSummary = formatFailureSummary(failure.testSummary.failures);
|
|
39513
|
+
const diagnosisPrompt = `Analyze the following test failures and identify the root cause:
|
|
39514
|
+
|
|
39515
|
+
${failureSummary}`;
|
|
39516
|
+
debatePromise = (async () => {
|
|
39517
|
+
try {
|
|
39518
|
+
const debateResult = await _rectificationDeps.runDebate(story.id, debateStageConfig, diagnosisPrompt, config2, agentManager);
|
|
39519
|
+
if (debateResult.totalCostUsd > 0 && story.routing) {
|
|
39520
|
+
story.routing.estimatedCostUsd = (story.routing.estimatedCostUsd ?? 0) + debateResult.totalCostUsd;
|
|
39521
|
+
}
|
|
39522
|
+
if (debateResult.output !== null) {
|
|
39523
|
+
return `## Root Cause Analysis
|
|
39524
|
+
|
|
39525
|
+
${debateResult.output}`;
|
|
39526
|
+
}
|
|
39527
|
+
logger?.info("rectification", "debate diagnosis fallback \u2014 all debaters failed", {
|
|
39528
|
+
storyId: story.id,
|
|
39529
|
+
event: "fallback"
|
|
39530
|
+
});
|
|
39531
|
+
return null;
|
|
39532
|
+
} catch (_error) {
|
|
39533
|
+
logger?.info("rectification", "debate diagnosis fallback \u2014 debate threw error", {
|
|
39534
|
+
storyId: story.id,
|
|
39535
|
+
event: "fallback"
|
|
39536
|
+
});
|
|
39537
|
+
return null;
|
|
39538
|
+
}
|
|
39539
|
+
})();
|
|
39540
|
+
}
|
|
39541
|
+
const failureRecords = buildFailureRecords(failure.testSummary, failure.testOutput);
|
|
39542
|
+
const rectPrompt = RectifierPromptBuilder.regressionFailure({
|
|
39543
|
+
story,
|
|
39544
|
+
failures: failureRecords,
|
|
39545
|
+
testCommand,
|
|
39546
|
+
conventions: true
|
|
39547
|
+
});
|
|
39548
|
+
const rectPromise = Promise.resolve(rectPrompt);
|
|
39549
|
+
return (async () => {
|
|
39550
|
+
const [diagnosis, rectificationPrompt] = await Promise.all([debatePromise, rectPromise]);
|
|
39551
|
+
let finalPrompt = rectificationPrompt;
|
|
39552
|
+
if (diagnosis) {
|
|
39553
|
+
finalPrompt = `${diagnosis}
|
|
39554
|
+
|
|
39555
|
+
${finalPrompt}`;
|
|
39556
|
+
}
|
|
39557
|
+
if (promptPrefix) {
|
|
39558
|
+
finalPrompt = `${promptPrefix}
|
|
39559
|
+
|
|
39560
|
+
${finalPrompt}`;
|
|
39561
|
+
}
|
|
39562
|
+
return finalPrompt;
|
|
39563
|
+
})();
|
|
39564
|
+
},
|
|
39565
|
+
execute: async (prompt) => {
|
|
39566
|
+
const defaultAgent = agentManager.getDefault();
|
|
39567
|
+
const complexity = story.routing?.complexity ?? "medium";
|
|
39568
|
+
const modelTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
39569
|
+
const modelDef = resolveModelForAgent(config2.models, story.routing?.agent ?? defaultAgent, modelTier, defaultAgent);
|
|
39570
|
+
let agentResult;
|
|
39571
|
+
{
|
|
39572
|
+
let transportRetries = 0;
|
|
39573
|
+
const maxTransportRetries = config2.execution?.sessionErrorRetryableMaxRetries ?? 3;
|
|
39574
|
+
while (true) {
|
|
39575
|
+
if (!heldHandle) {
|
|
39576
|
+
heldHandle = await runtime.sessionManager.openSession(rectificationSessionName, {
|
|
39577
|
+
agentName: defaultAgent,
|
|
39578
|
+
role: "implementer",
|
|
39579
|
+
workdir,
|
|
39580
|
+
pipelineStage: "rectification",
|
|
39581
|
+
modelDef,
|
|
39582
|
+
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
39583
|
+
featureName,
|
|
39584
|
+
storyId: story.id,
|
|
39585
|
+
signal: runtime.signal
|
|
39586
|
+
});
|
|
39587
|
+
}
|
|
39588
|
+
try {
|
|
39589
|
+
const turn = await agentManager.runAsSession(defaultAgent, heldHandle, prompt, {
|
|
39590
|
+
storyId: story.id,
|
|
39591
|
+
featureName,
|
|
39592
|
+
workdir,
|
|
39593
|
+
projectDir,
|
|
39594
|
+
pipelineStage: "rectification",
|
|
39595
|
+
sessionRole: "implementer",
|
|
39596
|
+
signal: runtime.signal,
|
|
39597
|
+
maxTurns: config2.agent?.maxInteractionTurns
|
|
39598
|
+
});
|
|
39599
|
+
agentResult = {
|
|
39600
|
+
success: true,
|
|
39601
|
+
exitCode: 0,
|
|
39602
|
+
output: turn.output,
|
|
39603
|
+
rateLimited: false,
|
|
39604
|
+
durationMs: 0,
|
|
39605
|
+
estimatedCostUsd: turn.estimatedCostUsd,
|
|
39606
|
+
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
39607
|
+
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
39608
|
+
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
39609
|
+
};
|
|
39610
|
+
break;
|
|
39611
|
+
} catch (err) {
|
|
39612
|
+
const stale = heldHandle;
|
|
39613
|
+
heldHandle = undefined;
|
|
39614
|
+
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
39615
|
+
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
39616
|
+
transportRetries++;
|
|
39617
|
+
getSafeLogger()?.warn("rectification", "fail-adapter-error: same-agent retry with fresh session", {
|
|
39618
|
+
storyId: story.id,
|
|
39619
|
+
attempt: transportRetries,
|
|
39620
|
+
maxAttempts: maxTransportRetries,
|
|
39621
|
+
retriable: true
|
|
39622
|
+
});
|
|
39623
|
+
continue;
|
|
39624
|
+
}
|
|
39625
|
+
throw err;
|
|
39626
|
+
}
|
|
39627
|
+
}
|
|
39628
|
+
}
|
|
39629
|
+
costAccum += agentResult.estimatedCostUsd ?? 0;
|
|
39630
|
+
if (sessionId && agentResult.protocolIds) {
|
|
39631
|
+
try {
|
|
39632
|
+
runtime.sessionManager.bindHandle(sessionId, rectificationSessionName, agentResult.protocolIds);
|
|
39633
|
+
} catch {}
|
|
39634
|
+
}
|
|
39635
|
+
if (agentResult.success) {
|
|
39636
|
+
logger?.info("rectification", `Agent ${label} session complete`, {
|
|
39637
|
+
storyId: story.id,
|
|
39638
|
+
cost: agentResult.estimatedCostUsd
|
|
39639
|
+
});
|
|
39640
|
+
} else {
|
|
39641
|
+
logger?.warn("rectification", `Agent ${label} session failed`, {
|
|
39642
|
+
storyId: story.id,
|
|
39643
|
+
exitCode: agentResult.exitCode
|
|
39644
|
+
});
|
|
39645
|
+
}
|
|
39646
|
+
return {
|
|
39647
|
+
agentSuccess: agentResult.success,
|
|
39648
|
+
cost: agentResult.estimatedCostUsd ?? 0,
|
|
39649
|
+
protocolIds: agentResult.protocolIds
|
|
39650
|
+
};
|
|
39651
|
+
},
|
|
39652
|
+
shouldAbort: (failure) => {
|
|
39653
|
+
if (rectificationConfig.abortOnIncreasingFailures) {
|
|
39654
|
+
return failure.testSummary.failed > initialFailure.testSummary.failed;
|
|
39655
|
+
}
|
|
39656
|
+
return false;
|
|
39657
|
+
},
|
|
39658
|
+
verify: async (result) => {
|
|
39659
|
+
const retryVerification = await _rectificationDeps.runVerification({
|
|
39660
|
+
workdir,
|
|
39661
|
+
expectedFiles: getExpectedFiles(story),
|
|
39662
|
+
command: testCommand,
|
|
39663
|
+
timeoutSeconds,
|
|
39664
|
+
forceExit: config2.quality.forceExit,
|
|
39665
|
+
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
39666
|
+
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
39667
|
+
timeoutRetryCount: 0,
|
|
39668
|
+
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
39669
|
+
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
39670
|
+
shell: config2.quality.shell,
|
|
39671
|
+
stripEnvVars: config2.quality.stripEnvVars
|
|
39672
|
+
});
|
|
39673
|
+
if (retryVerification.success) {
|
|
39674
|
+
logger?.info("rectification", `[OK] ${label} succeeded!`, {
|
|
39675
|
+
storyId: story.id,
|
|
39676
|
+
attempt: currentAttempt,
|
|
39677
|
+
initialFailures: initialFailure.testSummary.failed
|
|
39678
|
+
});
|
|
39679
|
+
return { passed: true };
|
|
39680
|
+
}
|
|
39681
|
+
if (retryVerification.output) {
|
|
39682
|
+
const newTestSummary = parseTestOutput(retryVerification.output);
|
|
39683
|
+
if (newTestSummary.failed === 0 && retryVerification.status !== "ENVIRONMENTAL_FAILURE" && (retryVerification.status === "SUCCESS" || newTestSummary.passed > 0)) {
|
|
39684
|
+
logger?.info("rectification", `[OK] ${label} succeeded after parsing retry output`, {
|
|
39685
|
+
storyId: story.id,
|
|
39686
|
+
attempt: currentAttempt,
|
|
39687
|
+
initialFailures: initialFailure.testSummary.failed
|
|
39688
|
+
});
|
|
39689
|
+
return { passed: true };
|
|
39690
|
+
}
|
|
39691
|
+
const failingTests = newTestSummary.failures.slice(0, 10).map((failure) => failure.testName);
|
|
39692
|
+
const logData = {
|
|
39693
|
+
storyId: story.id,
|
|
39694
|
+
attempt: currentAttempt,
|
|
39695
|
+
remainingFailures: newTestSummary.failed,
|
|
39696
|
+
failingTests
|
|
39697
|
+
};
|
|
39698
|
+
if (newTestSummary.failures.length > 10 || newTestSummary.failures.length === 0 && newTestSummary.failed > 0) {
|
|
39699
|
+
logData.totalFailingTests = newTestSummary.failed;
|
|
39700
|
+
}
|
|
39701
|
+
logger?.warn("rectification", `${label} still failing after attempt`, logData);
|
|
39702
|
+
return {
|
|
39703
|
+
passed: false,
|
|
39704
|
+
newFailure: {
|
|
39705
|
+
testOutput: retryVerification.output,
|
|
39706
|
+
testSummary: newTestSummary
|
|
39707
|
+
}
|
|
39708
|
+
};
|
|
39709
|
+
}
|
|
39710
|
+
return {
|
|
39711
|
+
passed: false,
|
|
39712
|
+
newFailure: {
|
|
39713
|
+
testOutput: retryVerification.output ?? "",
|
|
39714
|
+
testSummary: initialFailure.testSummary
|
|
39715
|
+
}
|
|
39716
|
+
};
|
|
39717
|
+
}
|
|
39718
|
+
}).finally(async () => {
|
|
39719
|
+
if (heldHandle) {
|
|
39720
|
+
const stale = heldHandle;
|
|
39721
|
+
heldHandle = undefined;
|
|
39722
|
+
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
39723
|
+
}
|
|
39724
|
+
});
|
|
39725
|
+
const succeeded = outcome.outcome === "fixed";
|
|
39726
|
+
if (outcome.outcome === "exhausted") {
|
|
39727
|
+
const finalFailure = outcome.finalFailure;
|
|
39728
|
+
const shouldEscalate = rectificationConfig.escalateOnExhaustion !== false && config2.autoMode?.escalation?.enabled === true && finalFailure.testSummary.failed > 0;
|
|
39729
|
+
if (shouldEscalate) {
|
|
39730
|
+
const complexity = story.routing?.complexity ?? "medium";
|
|
39731
|
+
const currentTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
39732
|
+
const tierOrder = config2.autoMode.escalation.tierOrder;
|
|
39733
|
+
const escalationResult = _rectificationDeps.escalateTier(currentTier, tierOrder);
|
|
39734
|
+
const escalatedTier = escalationResult?.tier ?? null;
|
|
39735
|
+
const escalatedAgent = escalationResult?.agent;
|
|
39736
|
+
if (escalatedTier !== null) {
|
|
39737
|
+
const escalationManager = agentManager;
|
|
39738
|
+
const agentName = escalatedAgent ?? story.routing?.agent ?? escalationManager.getDefault();
|
|
39739
|
+
if (escalationManager.getAgent(agentName)) {
|
|
39740
|
+
const escalatedModelDef = resolveModelForAgent(config2.models, agentName, escalatedTier, escalationManager.getDefault());
|
|
39741
|
+
let escalationPrompt = RectifierPromptBuilder.escalated(finalFailure.testSummary.failures, story, outcome.attempts, currentTier, escalatedTier, rectificationConfig, testCommand, testScopedTemplate);
|
|
39742
|
+
if (promptPrefix) {
|
|
39743
|
+
escalationPrompt = `${promptPrefix}
|
|
39744
|
+
|
|
39745
|
+
${escalationPrompt}`;
|
|
39746
|
+
}
|
|
39747
|
+
const escalationRunResult = await escalationManager.runAs(agentName, {
|
|
39748
|
+
runOptions: {
|
|
39749
|
+
prompt: escalationPrompt,
|
|
39750
|
+
workdir,
|
|
39751
|
+
modelTier: escalatedTier,
|
|
39752
|
+
modelDef: escalatedModelDef,
|
|
39753
|
+
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
39754
|
+
pipelineStage: "rectification",
|
|
39755
|
+
config: config2,
|
|
39756
|
+
projectDir,
|
|
39757
|
+
maxInteractionTurns: config2.agent?.maxInteractionTurns,
|
|
39758
|
+
featureName,
|
|
39759
|
+
storyId: story.id,
|
|
39760
|
+
sessionRole: "implementer"
|
|
39761
|
+
}
|
|
39762
|
+
});
|
|
39763
|
+
costAccum += escalationRunResult.estimatedCostUsd ?? 0;
|
|
39764
|
+
logger?.info("rectification", "escalated rectification attempt cost", {
|
|
39765
|
+
storyId: story.id,
|
|
39766
|
+
escalatedTier,
|
|
39767
|
+
cost: escalationRunResult.estimatedCostUsd
|
|
39768
|
+
});
|
|
39769
|
+
const escalationVerification = await _rectificationDeps.runVerification({
|
|
39770
|
+
workdir,
|
|
39771
|
+
expectedFiles: getExpectedFiles(story),
|
|
39772
|
+
command: testCommand,
|
|
39773
|
+
timeoutSeconds,
|
|
39774
|
+
forceExit: config2.quality.forceExit,
|
|
39775
|
+
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
39776
|
+
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
39777
|
+
timeoutRetryCount: 0,
|
|
39778
|
+
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
39779
|
+
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
39780
|
+
shell: config2.quality.shell,
|
|
39781
|
+
stripEnvVars: config2.quality.stripEnvVars
|
|
39782
|
+
});
|
|
39783
|
+
if (escalationVerification.success) {
|
|
39784
|
+
logger?.info("rectification", `${label} escalated from ${currentTier} to ${escalatedTier} and succeeded`, {
|
|
39785
|
+
storyId: story.id,
|
|
39786
|
+
currentTier,
|
|
39787
|
+
escalatedTier
|
|
39788
|
+
});
|
|
39789
|
+
return { succeeded: true, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
39790
|
+
}
|
|
39791
|
+
logger?.warn("rectification", "escalated rectification also failed", { storyId: story.id, escalatedTier });
|
|
39792
|
+
}
|
|
39793
|
+
}
|
|
39794
|
+
}
|
|
39795
|
+
logger?.warn("rectification", `${label} exhausted max retries`, {
|
|
39796
|
+
storyId: story.id,
|
|
39797
|
+
attempts: outcome.attempts,
|
|
39798
|
+
remainingFailures: initialFailure.testSummary.failed
|
|
39799
|
+
});
|
|
39800
|
+
}
|
|
39801
|
+
return { succeeded, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
39802
|
+
}
|
|
39803
|
+
var _rectificationDeps;
|
|
39804
|
+
var init_rectification_loop = __esm(() => {
|
|
39805
|
+
init_agents();
|
|
39806
|
+
init_cost();
|
|
39807
|
+
init_types3();
|
|
39808
|
+
init_config();
|
|
39809
|
+
init_logger2();
|
|
39810
|
+
init_prd();
|
|
39811
|
+
init_prompts();
|
|
39812
|
+
init_naming();
|
|
39813
|
+
init_parser2();
|
|
39814
|
+
init_parser2();
|
|
39815
|
+
init_runners();
|
|
39816
|
+
_rectificationDeps = {
|
|
39817
|
+
agentManager: undefined,
|
|
39818
|
+
runVerification: fullSuite,
|
|
39819
|
+
escalateTier,
|
|
39820
|
+
runDebate: _defaultRunDebate
|
|
39821
|
+
};
|
|
39822
|
+
});
|
|
39823
|
+
|
|
39293
39824
|
// src/verification/index.ts
|
|
39294
39825
|
var init_verification = __esm(() => {
|
|
39826
|
+
init_rectification_loop();
|
|
39295
39827
|
init_executor();
|
|
39296
39828
|
init_parser2();
|
|
39297
39829
|
init_runners();
|
|
@@ -42861,15 +43393,6 @@ var init_manager_sweep = __esm(() => {
|
|
|
42861
43393
|
DEFAULT_ORPHAN_TTL_MS = 4 * 60 * 60 * 1000;
|
|
42862
43394
|
});
|
|
42863
43395
|
|
|
42864
|
-
// src/session/naming.ts
|
|
42865
|
-
var exports_naming = {};
|
|
42866
|
-
__export(exports_naming, {
|
|
42867
|
-
formatSessionName: () => formatSessionName
|
|
42868
|
-
});
|
|
42869
|
-
var init_naming = __esm(() => {
|
|
42870
|
-
init_session_name();
|
|
42871
|
-
});
|
|
42872
|
-
|
|
42873
43396
|
// src/session/types.ts
|
|
42874
43397
|
var SESSION_TRANSITIONS;
|
|
42875
43398
|
var init_types7 = __esm(() => {
|
|
@@ -45211,7 +45734,11 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
45211
45734
|
const proposalBarriers = resolved.map(() => Promise.withResolvers());
|
|
45212
45735
|
const rebutBuilder = new DebatePromptBuilder({ taskContext, outputFormat: "", stage: "plan" }, { debaters: resolved.map((e) => e.debater), sessionMode: "stateful" });
|
|
45213
45736
|
const callOpPromises = resolved.map(({ debater, agentName }, index) => {
|
|
45214
|
-
const debaterCtx = {
|
|
45737
|
+
const debaterCtx = {
|
|
45738
|
+
...ctx.callContext,
|
|
45739
|
+
agentName,
|
|
45740
|
+
sessionOverride: { role: `debate-plan-${index}` }
|
|
45741
|
+
};
|
|
45215
45742
|
return callOp(debaterCtx, planDebaterOp, {
|
|
45216
45743
|
debater,
|
|
45217
45744
|
index,
|
|
@@ -45276,7 +45803,11 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
45276
45803
|
const rebuttalBarriers = resolved.map(() => Promise.withResolvers());
|
|
45277
45804
|
const rebutBuilder = new DebatePromptBuilder({ taskContext, outputFormat: "", stage: "plan" }, { debaters: resolved.map((e) => e.debater), sessionMode: "stateful" });
|
|
45278
45805
|
const callOpPromisesB = resolved.map(({ debater, agentName }, index) => {
|
|
45279
|
-
const debaterCtx = {
|
|
45806
|
+
const debaterCtx = {
|
|
45807
|
+
...ctx.callContext,
|
|
45808
|
+
agentName,
|
|
45809
|
+
sessionOverride: { role: `debate-plan-${index}` }
|
|
45810
|
+
};
|
|
45280
45811
|
return callOp(debaterCtx, planDebaterOp, {
|
|
45281
45812
|
debater,
|
|
45282
45813
|
index,
|
|
@@ -45335,7 +45866,11 @@ async function runPlan(ctx, taskContext, outputFormat, opts) {
|
|
|
45335
45866
|
for (const barrier of rebuttalBarriersC)
|
|
45336
45867
|
barrier.resolve("");
|
|
45337
45868
|
const settled = await allSettledBounded(resolved.map(({ debater, agentName }, index) => async () => {
|
|
45338
|
-
const debaterCtx = {
|
|
45869
|
+
const debaterCtx = {
|
|
45870
|
+
...ctx.callContext,
|
|
45871
|
+
agentName,
|
|
45872
|
+
sessionOverride: { role: `debate-plan-${index}` }
|
|
45873
|
+
};
|
|
45339
45874
|
const result = await callOp(debaterCtx, planDebaterOp, {
|
|
45340
45875
|
debater,
|
|
45341
45876
|
index,
|
|
@@ -50459,42 +50994,8 @@ var init_greenfield = __esm(() => {
|
|
|
50459
50994
|
]);
|
|
50460
50995
|
});
|
|
50461
50996
|
|
|
50462
|
-
// src/verification/failure-records.ts
|
|
50463
|
-
function truncateUnmappedFailureOutput(output) {
|
|
50464
|
-
const tailLines = output.split(`
|
|
50465
|
-
`).slice(-UNMAPPED_FAILURE_OUTPUT_MAX_LINES).join(`
|
|
50466
|
-
`);
|
|
50467
|
-
if (tailLines.length <= UNMAPPED_FAILURE_OUTPUT_MAX_CHARS) {
|
|
50468
|
-
return tailLines;
|
|
50469
|
-
}
|
|
50470
|
-
return `... (truncated)
|
|
50471
|
-
${tailLines.slice(-UNMAPPED_FAILURE_OUTPUT_MAX_CHARS)}`;
|
|
50472
|
-
}
|
|
50473
|
-
function buildFailureRecords(testSummary, rawOutput) {
|
|
50474
|
-
if (testSummary.failures.length > 0) {
|
|
50475
|
-
return testSummary.failures.map((failure) => ({
|
|
50476
|
-
test: failure.testName,
|
|
50477
|
-
file: failure.file,
|
|
50478
|
-
message: failure.error,
|
|
50479
|
-
output: failure.stackTrace.length > 0 ? failure.stackTrace.join(`
|
|
50480
|
-
`) : undefined
|
|
50481
|
-
}));
|
|
50482
|
-
}
|
|
50483
|
-
if (testSummary.failed === 0) {
|
|
50484
|
-
return [];
|
|
50485
|
-
}
|
|
50486
|
-
return [
|
|
50487
|
-
{
|
|
50488
|
-
test: `Unmapped test failures (${testSummary.failed} detected)`,
|
|
50489
|
-
message: "Structured test failure parsing returned no failure records. Diagnose the regression from the raw test output.",
|
|
50490
|
-
output: rawOutput?.trim() ? truncateUnmappedFailureOutput(rawOutput.trim()) : undefined
|
|
50491
|
-
}
|
|
50492
|
-
];
|
|
50493
|
-
}
|
|
50494
|
-
var UNMAPPED_FAILURE_OUTPUT_MAX_LINES = 200, UNMAPPED_FAILURE_OUTPUT_MAX_CHARS = 8000;
|
|
50495
|
-
|
|
50496
50997
|
// src/tdd/rectification-gate.ts
|
|
50497
|
-
async function runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir,
|
|
50998
|
+
async function runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, sessionId, runtime) {
|
|
50498
50999
|
const rectificationEnabled = config2.execution.rectification?.enabled ?? false;
|
|
50499
51000
|
if (!rectificationEnabled) {
|
|
50500
51001
|
return { passed: false, cost: 0, fullSuiteGatePassed: false, status: "disabled" };
|
|
@@ -50522,16 +51023,16 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
50522
51023
|
});
|
|
50523
51024
|
return { passed: true, cost: 0, fullSuiteGatePassed: false, status: "deferred-unattributable" };
|
|
50524
51025
|
}
|
|
50525
|
-
return await
|
|
51026
|
+
return await runRectificationLoop2(story, config2, workdir, agentManager, implementerTier, lite, logger, testSummary, rectificationConfig, effectiveTestCmd, fullSuiteTimeout, fullSuiteResult.output, runtime, featureName, projectDir, sessionId);
|
|
50526
51027
|
}
|
|
50527
51028
|
if (testSummary.failures.length > 0) {
|
|
50528
|
-
logger.warn("tdd", "Full suite gate: parser counter mismatch \u2014
|
|
51029
|
+
logger.warn("tdd", "Full suite gate: parser counter mismatch \u2014 failing gate (unreliable failure count)", {
|
|
50529
51030
|
storyId: story.id,
|
|
50530
51031
|
failedCounter: testSummary.failed,
|
|
50531
51032
|
failuresLength: testSummary.failures.length,
|
|
50532
51033
|
exitCode: fullSuiteResult.exitCode
|
|
50533
51034
|
});
|
|
50534
|
-
return
|
|
51035
|
+
return { passed: false, cost: 0, fullSuiteGatePassed: false, status: "execution-failed" };
|
|
50535
51036
|
}
|
|
50536
51037
|
if (testSummary.passed > 0) {
|
|
50537
51038
|
logger.info("tdd", "Full suite gate passed (non-zero exit, 0 failures, tests detected)", {
|
|
@@ -50559,7 +51060,7 @@ async function runFullSuiteGate(story, config2, workdir, agentManager, implement
|
|
|
50559
51060
|
});
|
|
50560
51061
|
return { passed: false, cost: 0, fullSuiteGatePassed: false, status: "execution-failed" };
|
|
50561
51062
|
}
|
|
50562
|
-
async function
|
|
51063
|
+
async function runRectificationLoop2(story, config2, workdir, agentManager, implementerTier, lite, logger, testSummary, rectificationConfig, testCmd, fullSuiteTimeout, testOutput, runtime, featureName, projectDir, sessionId) {
|
|
50563
51064
|
logger.warn("tdd", "Full suite gate detected regressions", {
|
|
50564
51065
|
storyId: story.id,
|
|
50565
51066
|
failedTests: testSummary.failed,
|
|
@@ -50597,7 +51098,6 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
50597
51098
|
},
|
|
50598
51099
|
execute: async (prompt) => {
|
|
50599
51100
|
currentAttempt++;
|
|
50600
|
-
const isLastAttempt = currentAttempt >= rectificationConfig.maxRetries;
|
|
50601
51101
|
const rectifyBeforeRef = await captureGitRef(workdir) ?? "HEAD";
|
|
50602
51102
|
const defaultAgent = agentManager.getDefault();
|
|
50603
51103
|
const runOptions = {
|
|
@@ -50615,71 +51115,65 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
50615
51115
|
sessionRole: "implementer"
|
|
50616
51116
|
};
|
|
50617
51117
|
let rectifyResult;
|
|
50618
|
-
|
|
50619
|
-
|
|
50620
|
-
|
|
50621
|
-
|
|
50622
|
-
|
|
50623
|
-
|
|
50624
|
-
|
|
50625
|
-
|
|
50626
|
-
|
|
50627
|
-
|
|
50628
|
-
|
|
50629
|
-
|
|
50630
|
-
|
|
50631
|
-
|
|
50632
|
-
|
|
50633
|
-
|
|
50634
|
-
|
|
50635
|
-
|
|
50636
|
-
|
|
51118
|
+
let transportRetries = 0;
|
|
51119
|
+
const maxTransportRetries = config2.execution?.sessionErrorRetryableMaxRetries ?? 3;
|
|
51120
|
+
while (true) {
|
|
51121
|
+
if (!heldHandle) {
|
|
51122
|
+
heldHandle = await runtime.sessionManager.openSession(rectificationSessionName, {
|
|
51123
|
+
agentName: defaultAgent,
|
|
51124
|
+
role: "implementer",
|
|
51125
|
+
workdir,
|
|
51126
|
+
pipelineStage: "rectification",
|
|
51127
|
+
modelDef: runOptions.modelDef,
|
|
51128
|
+
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
51129
|
+
featureName,
|
|
51130
|
+
storyId: story.id,
|
|
51131
|
+
signal: runtime.signal
|
|
51132
|
+
});
|
|
51133
|
+
}
|
|
51134
|
+
try {
|
|
51135
|
+
const turn = await agentManager.runAsSession(defaultAgent, heldHandle, prompt, {
|
|
51136
|
+
storyId: story.id,
|
|
51137
|
+
featureName,
|
|
51138
|
+
workdir,
|
|
51139
|
+
projectDir,
|
|
51140
|
+
pipelineStage: "rectification",
|
|
51141
|
+
sessionRole: "implementer",
|
|
51142
|
+
signal: runtime.signal,
|
|
51143
|
+
maxTurns: config2.agent?.maxInteractionTurns
|
|
51144
|
+
});
|
|
51145
|
+
rectifyResult = {
|
|
51146
|
+
success: true,
|
|
51147
|
+
exitCode: 0,
|
|
51148
|
+
output: turn.output,
|
|
51149
|
+
rateLimited: false,
|
|
51150
|
+
durationMs: 0,
|
|
51151
|
+
estimatedCostUsd: turn.estimatedCostUsd,
|
|
51152
|
+
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
51153
|
+
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
51154
|
+
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
51155
|
+
};
|
|
51156
|
+
break;
|
|
51157
|
+
} catch (err) {
|
|
51158
|
+
const stale = heldHandle;
|
|
51159
|
+
heldHandle = undefined;
|
|
51160
|
+
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
51161
|
+
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
51162
|
+
transportRetries++;
|
|
51163
|
+
getSafeLogger()?.warn("tdd", "fail-adapter-error: same-agent retry with fresh session", {
|
|
50637
51164
|
storyId: story.id,
|
|
50638
|
-
|
|
50639
|
-
|
|
50640
|
-
|
|
50641
|
-
pipelineStage: "rectification",
|
|
50642
|
-
sessionRole: "implementer",
|
|
50643
|
-
signal: runtime.signal,
|
|
50644
|
-
maxTurns: config2.agent?.maxInteractionTurns
|
|
51165
|
+
attempt: transportRetries,
|
|
51166
|
+
maxAttempts: maxTransportRetries,
|
|
51167
|
+
retriable: true
|
|
50645
51168
|
});
|
|
50646
|
-
|
|
50647
|
-
success: true,
|
|
50648
|
-
exitCode: 0,
|
|
50649
|
-
output: turn.output,
|
|
50650
|
-
rateLimited: false,
|
|
50651
|
-
durationMs: 0,
|
|
50652
|
-
estimatedCostUsd: turn.estimatedCostUsd,
|
|
50653
|
-
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
50654
|
-
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
50655
|
-
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
50656
|
-
};
|
|
50657
|
-
break;
|
|
50658
|
-
} catch (err) {
|
|
50659
|
-
const stale = heldHandle;
|
|
50660
|
-
heldHandle = undefined;
|
|
50661
|
-
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
50662
|
-
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
50663
|
-
transportRetries++;
|
|
50664
|
-
getSafeLogger()?.warn("tdd", "fail-adapter-error: same-agent retry with fresh session", {
|
|
50665
|
-
storyId: story.id,
|
|
50666
|
-
attempt: transportRetries,
|
|
50667
|
-
maxAttempts: maxTransportRetries,
|
|
50668
|
-
retriable: true
|
|
50669
|
-
});
|
|
50670
|
-
continue;
|
|
50671
|
-
}
|
|
50672
|
-
throw err;
|
|
51169
|
+
continue;
|
|
50673
51170
|
}
|
|
51171
|
+
throw err;
|
|
50674
51172
|
}
|
|
50675
|
-
} else {
|
|
50676
|
-
rectifyResult = await agentManager.run({
|
|
50677
|
-
runOptions: { ...runOptions, keepOpen: !isLastAttempt }
|
|
50678
|
-
});
|
|
50679
51173
|
}
|
|
50680
|
-
if (
|
|
51174
|
+
if (sessionId && rectifyResult.protocolIds) {
|
|
50681
51175
|
try {
|
|
50682
|
-
sessionManager.bindHandle(sessionId, rectificationSessionName, rectifyResult.protocolIds);
|
|
51176
|
+
runtime.sessionManager.bindHandle(sessionId, rectificationSessionName, rectifyResult.protocolIds);
|
|
50683
51177
|
} catch {}
|
|
50684
51178
|
}
|
|
50685
51179
|
if (!rectifyResult.success && rectifyResult.pid) {
|
|
@@ -50745,7 +51239,7 @@ async function runRectificationLoop(story, config2, workdir, agentManager, imple
|
|
|
50745
51239
|
};
|
|
50746
51240
|
}
|
|
50747
51241
|
}).finally(async () => {
|
|
50748
|
-
if (heldHandle
|
|
51242
|
+
if (heldHandle) {
|
|
50749
51243
|
const stale = heldHandle;
|
|
50750
51244
|
heldHandle = undefined;
|
|
50751
51245
|
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
@@ -51236,7 +51730,7 @@ async function runThreeSessionTdd(options) {
|
|
|
51236
51730
|
};
|
|
51237
51731
|
}
|
|
51238
51732
|
const implementerBinding = getTddSessionBinding?.("implementer");
|
|
51239
|
-
const fullSuiteGate = await runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, implementerBinding?.
|
|
51733
|
+
const fullSuiteGate = await runFullSuiteGate(story, config2, workdir, agentManager, implementerTier, lite, logger, featureName, projectDir, implementerBinding?.sessionId, runtime);
|
|
51240
51734
|
const { cost: fullSuiteGateCost, fullSuiteGatePassed } = fullSuiteGate;
|
|
51241
51735
|
if (fullSuiteGate.status === "rectification-exhausted") {
|
|
51242
51736
|
const failureCategory = "full-suite-gate-exhausted";
|
|
@@ -51522,6 +52016,7 @@ var init_tdd = __esm(() => {
|
|
|
51522
52016
|
init_isolation();
|
|
51523
52017
|
init_orchestrator3();
|
|
51524
52018
|
init_orchestrator_ctx();
|
|
52019
|
+
init_rectification_gate();
|
|
51525
52020
|
init_session_op();
|
|
51526
52021
|
init_cleanup();
|
|
51527
52022
|
init_verdict();
|
|
@@ -51936,9 +52431,9 @@ async function runAgentRectificationV2(ctx, _lintFixCmd, _formatFixCmd, _effecti
|
|
|
51936
52431
|
maxAttemptsTotal: maxTotalAttempts,
|
|
51937
52432
|
validatorRetries: 1
|
|
51938
52433
|
},
|
|
51939
|
-
async validate(_cycleCtx) {
|
|
52434
|
+
async validate(_cycleCtx, _opts) {
|
|
51940
52435
|
iterationBeforeRef = await _autofixCycleGuardDeps.captureGitRef(ctx.workdir) ?? iterationBeforeRef;
|
|
51941
|
-
await _autofixDeps.recheckReview(ctx);
|
|
52436
|
+
await _autofixDeps.recheckReview(ctx, { lite: _opts.mode === "lite" });
|
|
51942
52437
|
const fresh = collectCurrentFindings(ctx);
|
|
51943
52438
|
const pending = ctx.testEditDeclarations ?? [];
|
|
51944
52439
|
if (pending.length === 0)
|
|
@@ -52734,7 +53229,7 @@ var init_review2 = __esm(() => {
|
|
|
52734
53229
|
const reviewDebateEnabled = ctx.rootConfig?.debate?.enabled && ctx.rootConfig?.debate?.stages?.review?.enabled;
|
|
52735
53230
|
const dialogueEnabled = ctx.config.review?.dialogue?.enabled ?? false;
|
|
52736
53231
|
logger.info("review", "Running review phase", { storyId: ctx.story.id });
|
|
52737
|
-
if (dialogueEnabled && !reviewDebateEnabled && ctx.reviewerSession) {
|
|
53232
|
+
if (dialogueEnabled && !reviewDebateEnabled && ctx.reviewerSession && !ctx.skipLLMReviewers) {
|
|
52738
53233
|
try {
|
|
52739
53234
|
const diff = ctx.storyGitRef ?? "";
|
|
52740
53235
|
const reReviewResult = await ctx.reviewerSession.reReview(diff);
|
|
@@ -52769,7 +53264,7 @@ var init_review2 = __esm(() => {
|
|
|
52769
53264
|
});
|
|
52770
53265
|
}
|
|
52771
53266
|
}
|
|
52772
|
-
if (dialogueEnabled && !ctx.reviewerSession && ctx.agentManager && ctx.sessionManager) {
|
|
53267
|
+
if (dialogueEnabled && !ctx.reviewerSession && ctx.agentManager && ctx.sessionManager && !ctx.skipLLMReviewers) {
|
|
52773
53268
|
ctx.reviewerSession = _reviewDeps.createReviewerSession(ctx.agentManager, ctx.sessionManager, ctx.story.id, ctx.workdir, ctx.prd.feature ?? "", ctx.config);
|
|
52774
53269
|
if (!reviewDebateEnabled) {
|
|
52775
53270
|
const semanticConfig = ctx.config.review?.semantic;
|
|
@@ -52873,16 +53368,36 @@ var init_review2 = __esm(() => {
|
|
|
52873
53368
|
});
|
|
52874
53369
|
|
|
52875
53370
|
// src/pipeline/stages/autofix.ts
|
|
52876
|
-
async function recheckReview(ctx) {
|
|
53371
|
+
async function recheckReview(ctx, opts) {
|
|
53372
|
+
const lite = opts?.lite === true;
|
|
53373
|
+
if (lite) {
|
|
53374
|
+
const origSkipChecks = ctx.retrySkipChecks;
|
|
53375
|
+
const origSkipLLMReviewers = ctx.skipLLMReviewers;
|
|
53376
|
+
ctx.retrySkipChecks = new Set([...ctx.retrySkipChecks ?? [], "adversarial", "semantic"]);
|
|
53377
|
+
ctx.skipLLMReviewers = true;
|
|
53378
|
+
try {
|
|
53379
|
+
await _autofixDeps.runReviewStage(ctx);
|
|
53380
|
+
} finally {
|
|
53381
|
+
ctx.retrySkipChecks = origSkipChecks;
|
|
53382
|
+
ctx.skipLLMReviewers = origSkipLLMReviewers;
|
|
53383
|
+
}
|
|
53384
|
+
return ctx.reviewResult?.success === true;
|
|
53385
|
+
}
|
|
52877
53386
|
const { reviewStage: reviewStage2 } = await Promise.resolve().then(() => (init_review2(), exports_review));
|
|
52878
53387
|
if (!reviewStage2.enabled(ctx))
|
|
52879
53388
|
return true;
|
|
52880
|
-
await
|
|
53389
|
+
await _autofixDeps.runReviewStage(ctx);
|
|
52881
53390
|
const hasFailOpen = (ctx.reviewResult?.checks ?? []).some((c) => c.failOpen);
|
|
52882
53391
|
if (hasFailOpen)
|
|
52883
53392
|
return false;
|
|
52884
53393
|
return ctx.reviewResult?.success === true;
|
|
52885
53394
|
}
|
|
53395
|
+
async function runReviewStage(ctx) {
|
|
53396
|
+
const { reviewStage: reviewStage2 } = await Promise.resolve().then(() => (init_review2(), exports_review));
|
|
53397
|
+
if (!reviewStage2.enabled(ctx))
|
|
53398
|
+
return;
|
|
53399
|
+
await reviewStage2.execute(ctx);
|
|
53400
|
+
}
|
|
52886
53401
|
async function runMechanicalFixes(ctx, failedCheckNames) {
|
|
52887
53402
|
const commands = resolveMechanicalFixCommands(ctx, failedCheckNames);
|
|
52888
53403
|
for (const resolved of commands) {
|
|
@@ -53146,6 +53661,7 @@ var init_autofix = __esm(() => {
|
|
|
53146
53661
|
runQualityCommand,
|
|
53147
53662
|
recheckReview,
|
|
53148
53663
|
runAgentRectification: runAgentRectificationV2,
|
|
53664
|
+
runReviewStage,
|
|
53149
53665
|
runTestWriterRectification: (ctx, testWriterChecks, story, agentManager) => runTestWriterRectification(ctx, testWriterChecks, story, agentManager)
|
|
53150
53666
|
};
|
|
53151
53667
|
});
|
|
@@ -54780,455 +55296,6 @@ var init_queue_check = __esm(() => {
|
|
|
54780
55296
|
};
|
|
54781
55297
|
});
|
|
54782
55298
|
|
|
54783
|
-
// src/execution/escalation/escalation.ts
|
|
54784
|
-
function escalateTier(currentTier, tierOrder) {
|
|
54785
|
-
const getName = (t) => t.tier ?? t.name ?? null;
|
|
54786
|
-
const currentIndex = tierOrder.findIndex((t) => getName(t) === currentTier);
|
|
54787
|
-
if (currentIndex === -1 || currentIndex === tierOrder.length - 1) {
|
|
54788
|
-
return null;
|
|
54789
|
-
}
|
|
54790
|
-
const next = tierOrder[currentIndex + 1];
|
|
54791
|
-
const nextName = getName(next);
|
|
54792
|
-
if (!nextName)
|
|
54793
|
-
return null;
|
|
54794
|
-
return { tier: nextName, agent: next.agent };
|
|
54795
|
-
}
|
|
54796
|
-
function calculateMaxIterations(tierOrder) {
|
|
54797
|
-
return tierOrder.reduce((sum, t) => sum + t.attempts, 0);
|
|
54798
|
-
}
|
|
54799
|
-
|
|
54800
|
-
// src/verification/rectification-loop.ts
|
|
54801
|
-
async function _defaultRunDebate(storyId, stageConfig, prompt, config2, agentManager) {
|
|
54802
|
-
const logger = getSafeLogger();
|
|
54803
|
-
const debaters = stageConfig.debaters ?? [];
|
|
54804
|
-
const manager = agentManager;
|
|
54805
|
-
const resolved = [];
|
|
54806
|
-
for (const debater of debaters) {
|
|
54807
|
-
if (manager.getAgent(debater.agent)) {
|
|
54808
|
-
resolved.push({ debater, agentName: debater.agent });
|
|
54809
|
-
}
|
|
54810
|
-
}
|
|
54811
|
-
if (resolved.length === 0) {
|
|
54812
|
-
return { output: null, totalCostUsd: 0 };
|
|
54813
|
-
}
|
|
54814
|
-
const timeoutMs = (config2.execution?.sessionTimeoutSeconds ?? 600) * 1000;
|
|
54815
|
-
const defaultAgentName = resolveDefaultAgent(config2);
|
|
54816
|
-
const resolvedDebaters = resolved.map(({ debater, agentName }) => {
|
|
54817
|
-
let modelDef;
|
|
54818
|
-
try {
|
|
54819
|
-
modelDef = resolveConfiguredModel(config2.models, agentName, debater.model ?? "balanced", defaultAgentName).modelDef;
|
|
54820
|
-
} catch {
|
|
54821
|
-
modelDef = { provider: "unknown", model: debater.model ?? "default" };
|
|
54822
|
-
}
|
|
54823
|
-
return { debater, agentName, modelDef };
|
|
54824
|
-
});
|
|
54825
|
-
const startMs = Date.now();
|
|
54826
|
-
const proposalSettled = await Promise.allSettled(resolvedDebaters.map(({ agentName, modelDef }) => manager.completeAs(agentName, prompt, {
|
|
54827
|
-
modelDef,
|
|
54828
|
-
workdir: "",
|
|
54829
|
-
storyId,
|
|
54830
|
-
sessionRole: "debate-proposal",
|
|
54831
|
-
timeoutMs
|
|
54832
|
-
}).then((out) => typeof out === "string" ? out : out.output)));
|
|
54833
|
-
const durationMs = Date.now() - startMs;
|
|
54834
|
-
const successful = proposalSettled.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
54835
|
-
if (successful.length === 0) {
|
|
54836
|
-
return { output: null, totalCostUsd: 0 };
|
|
54837
|
-
}
|
|
54838
|
-
const successCount = successful.length;
|
|
54839
|
-
const costPerDebater = estimateCostByDuration("balanced", durationMs / successCount);
|
|
54840
|
-
const totalCostUsd = costPerDebater.cost * successCount;
|
|
54841
|
-
logger?.debug("rectification", "debate diagnosis complete", { storyId, successCount, totalCostUsd });
|
|
54842
|
-
const output = successful.join(`
|
|
54843
|
-
|
|
54844
|
-
`);
|
|
54845
|
-
return { output, totalCostUsd };
|
|
54846
|
-
}
|
|
54847
|
-
async function runRectificationLoop2(opts) {
|
|
54848
|
-
const loopStartMs = Date.now();
|
|
54849
|
-
const {
|
|
54850
|
-
config: config2,
|
|
54851
|
-
workdir,
|
|
54852
|
-
story,
|
|
54853
|
-
testCommand,
|
|
54854
|
-
timeoutSeconds,
|
|
54855
|
-
testOutput,
|
|
54856
|
-
promptPrefix,
|
|
54857
|
-
featureName,
|
|
54858
|
-
projectDir,
|
|
54859
|
-
testScopedTemplate,
|
|
54860
|
-
sessionManager,
|
|
54861
|
-
sessionId,
|
|
54862
|
-
runtime
|
|
54863
|
-
} = opts;
|
|
54864
|
-
const logger = getSafeLogger();
|
|
54865
|
-
const agentManager = opts.agentManager ?? _rectificationDeps.agentManager;
|
|
54866
|
-
if (!agentManager) {
|
|
54867
|
-
logger?.warn("rectification", "No agentManager threaded \u2014 skipping rectification loop", {
|
|
54868
|
-
storyId: story.id
|
|
54869
|
-
});
|
|
54870
|
-
return { succeeded: false, cost: 0, durationMs: 0 };
|
|
54871
|
-
}
|
|
54872
|
-
const rectificationConfig = config2.execution.rectification;
|
|
54873
|
-
const testSummary = parseTestOutput(testOutput);
|
|
54874
|
-
const label = promptPrefix ? "regression rectification" : "rectification";
|
|
54875
|
-
const rectificationSessionName = formatSessionName({
|
|
54876
|
-
workdir,
|
|
54877
|
-
featureName,
|
|
54878
|
-
storyId: story.id,
|
|
54879
|
-
role: "implementer"
|
|
54880
|
-
});
|
|
54881
|
-
let costAccum = 0;
|
|
54882
|
-
let currentAttempt = 0;
|
|
54883
|
-
let heldHandle;
|
|
54884
|
-
const initialFailure = {
|
|
54885
|
-
testOutput,
|
|
54886
|
-
testSummary
|
|
54887
|
-
};
|
|
54888
|
-
const outcome = await runRetryLoop({
|
|
54889
|
-
stage: "rectification",
|
|
54890
|
-
storyId: story.id,
|
|
54891
|
-
packageDir: workdir,
|
|
54892
|
-
maxAttempts: rectificationConfig.maxRetries,
|
|
54893
|
-
failure: initialFailure,
|
|
54894
|
-
previousAttempts: [],
|
|
54895
|
-
buildPrompt: (failure) => {
|
|
54896
|
-
currentAttempt++;
|
|
54897
|
-
const diagnosisPrefix = null;
|
|
54898
|
-
const debateStageConfig = config2.debate?.stages?.rectification;
|
|
54899
|
-
let debatePromise = Promise.resolve(null);
|
|
54900
|
-
if (debateStageConfig?.enabled) {
|
|
54901
|
-
const failureSummary = formatFailureSummary(failure.testSummary.failures);
|
|
54902
|
-
const diagnosisPrompt = `Analyze the following test failures and identify the root cause:
|
|
54903
|
-
|
|
54904
|
-
${failureSummary}`;
|
|
54905
|
-
debatePromise = (async () => {
|
|
54906
|
-
try {
|
|
54907
|
-
const debateResult = await _rectificationDeps.runDebate(story.id, debateStageConfig, diagnosisPrompt, config2, agentManager);
|
|
54908
|
-
if (debateResult.totalCostUsd > 0 && story.routing) {
|
|
54909
|
-
story.routing.estimatedCostUsd = (story.routing.estimatedCostUsd ?? 0) + debateResult.totalCostUsd;
|
|
54910
|
-
}
|
|
54911
|
-
if (debateResult.output !== null) {
|
|
54912
|
-
return `## Root Cause Analysis
|
|
54913
|
-
|
|
54914
|
-
${debateResult.output}`;
|
|
54915
|
-
}
|
|
54916
|
-
logger?.info("rectification", "debate diagnosis fallback \u2014 all debaters failed", {
|
|
54917
|
-
storyId: story.id,
|
|
54918
|
-
event: "fallback"
|
|
54919
|
-
});
|
|
54920
|
-
return null;
|
|
54921
|
-
} catch (_error) {
|
|
54922
|
-
logger?.info("rectification", "debate diagnosis fallback \u2014 debate threw error", {
|
|
54923
|
-
storyId: story.id,
|
|
54924
|
-
event: "fallback"
|
|
54925
|
-
});
|
|
54926
|
-
return null;
|
|
54927
|
-
}
|
|
54928
|
-
})();
|
|
54929
|
-
}
|
|
54930
|
-
const failureRecords = buildFailureRecords(failure.testSummary, failure.testOutput);
|
|
54931
|
-
const rectPrompt = RectifierPromptBuilder.regressionFailure({
|
|
54932
|
-
story,
|
|
54933
|
-
failures: failureRecords,
|
|
54934
|
-
testCommand,
|
|
54935
|
-
conventions: true
|
|
54936
|
-
});
|
|
54937
|
-
const rectPromise = Promise.resolve(rectPrompt);
|
|
54938
|
-
return (async () => {
|
|
54939
|
-
const [diagnosis, rectificationPrompt] = await Promise.all([debatePromise, rectPromise]);
|
|
54940
|
-
let finalPrompt = rectificationPrompt;
|
|
54941
|
-
if (diagnosis) {
|
|
54942
|
-
finalPrompt = `${diagnosis}
|
|
54943
|
-
|
|
54944
|
-
${finalPrompt}`;
|
|
54945
|
-
}
|
|
54946
|
-
if (promptPrefix) {
|
|
54947
|
-
finalPrompt = `${promptPrefix}
|
|
54948
|
-
|
|
54949
|
-
${finalPrompt}`;
|
|
54950
|
-
}
|
|
54951
|
-
return finalPrompt;
|
|
54952
|
-
})();
|
|
54953
|
-
},
|
|
54954
|
-
execute: async (prompt) => {
|
|
54955
|
-
const defaultAgent = agentManager.getDefault();
|
|
54956
|
-
const complexity = story.routing?.complexity ?? "medium";
|
|
54957
|
-
const modelTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
54958
|
-
const modelDef = resolveModelForAgent(config2.models, story.routing?.agent ?? defaultAgent, modelTier, defaultAgent);
|
|
54959
|
-
const isLastAttempt = currentAttempt >= rectificationConfig.maxRetries;
|
|
54960
|
-
const runOptions = {
|
|
54961
|
-
prompt,
|
|
54962
|
-
workdir,
|
|
54963
|
-
modelTier,
|
|
54964
|
-
modelDef,
|
|
54965
|
-
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
54966
|
-
pipelineStage: "rectification",
|
|
54967
|
-
config: config2,
|
|
54968
|
-
projectDir,
|
|
54969
|
-
maxInteractionTurns: config2.agent?.maxInteractionTurns,
|
|
54970
|
-
featureName,
|
|
54971
|
-
storyId: story.id,
|
|
54972
|
-
sessionRole: "implementer"
|
|
54973
|
-
};
|
|
54974
|
-
let agentResult;
|
|
54975
|
-
if (runtime) {
|
|
54976
|
-
let transportRetries = 0;
|
|
54977
|
-
const maxTransportRetries = config2.execution?.sessionErrorRetryableMaxRetries ?? 3;
|
|
54978
|
-
while (true) {
|
|
54979
|
-
if (!heldHandle) {
|
|
54980
|
-
heldHandle = await runtime.sessionManager.openSession(rectificationSessionName, {
|
|
54981
|
-
agentName: defaultAgent,
|
|
54982
|
-
role: "implementer",
|
|
54983
|
-
workdir,
|
|
54984
|
-
pipelineStage: "rectification",
|
|
54985
|
-
modelDef,
|
|
54986
|
-
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
54987
|
-
featureName,
|
|
54988
|
-
storyId: story.id,
|
|
54989
|
-
signal: runtime.signal
|
|
54990
|
-
});
|
|
54991
|
-
}
|
|
54992
|
-
try {
|
|
54993
|
-
const turn = await agentManager.runAsSession(defaultAgent, heldHandle, prompt, {
|
|
54994
|
-
storyId: story.id,
|
|
54995
|
-
featureName,
|
|
54996
|
-
workdir,
|
|
54997
|
-
projectDir,
|
|
54998
|
-
pipelineStage: "rectification",
|
|
54999
|
-
sessionRole: "implementer",
|
|
55000
|
-
signal: runtime.signal,
|
|
55001
|
-
maxTurns: config2.agent?.maxInteractionTurns
|
|
55002
|
-
});
|
|
55003
|
-
agentResult = {
|
|
55004
|
-
success: true,
|
|
55005
|
-
exitCode: 0,
|
|
55006
|
-
output: turn.output,
|
|
55007
|
-
rateLimited: false,
|
|
55008
|
-
durationMs: 0,
|
|
55009
|
-
estimatedCostUsd: turn.estimatedCostUsd,
|
|
55010
|
-
...turn.exactCostUsd !== undefined && { exactCostUsd: turn.exactCostUsd },
|
|
55011
|
-
...turn.tokenUsage && { tokenUsage: turn.tokenUsage },
|
|
55012
|
-
...heldHandle.protocolIds && { protocolIds: heldHandle.protocolIds }
|
|
55013
|
-
};
|
|
55014
|
-
break;
|
|
55015
|
-
} catch (err) {
|
|
55016
|
-
const stale = heldHandle;
|
|
55017
|
-
heldHandle = undefined;
|
|
55018
|
-
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
55019
|
-
if (err instanceof SessionTurnError && err.retryable && transportRetries < maxTransportRetries) {
|
|
55020
|
-
transportRetries++;
|
|
55021
|
-
getSafeLogger()?.warn("rectification", "fail-adapter-error: same-agent retry with fresh session", {
|
|
55022
|
-
storyId: story.id,
|
|
55023
|
-
attempt: transportRetries,
|
|
55024
|
-
maxAttempts: maxTransportRetries,
|
|
55025
|
-
retriable: true
|
|
55026
|
-
});
|
|
55027
|
-
continue;
|
|
55028
|
-
}
|
|
55029
|
-
throw err;
|
|
55030
|
-
}
|
|
55031
|
-
}
|
|
55032
|
-
} else {
|
|
55033
|
-
agentResult = await agentManager.run({
|
|
55034
|
-
runOptions: { ...runOptions, keepOpen: !isLastAttempt }
|
|
55035
|
-
});
|
|
55036
|
-
}
|
|
55037
|
-
costAccum += agentResult.estimatedCostUsd ?? 0;
|
|
55038
|
-
if (sessionManager && sessionId && agentResult.protocolIds) {
|
|
55039
|
-
try {
|
|
55040
|
-
sessionManager.bindHandle(sessionId, rectificationSessionName, agentResult.protocolIds);
|
|
55041
|
-
} catch {}
|
|
55042
|
-
}
|
|
55043
|
-
if (agentResult.success) {
|
|
55044
|
-
logger?.info("rectification", `Agent ${label} session complete`, {
|
|
55045
|
-
storyId: story.id,
|
|
55046
|
-
cost: agentResult.estimatedCostUsd
|
|
55047
|
-
});
|
|
55048
|
-
} else {
|
|
55049
|
-
logger?.warn("rectification", `Agent ${label} session failed`, {
|
|
55050
|
-
storyId: story.id,
|
|
55051
|
-
exitCode: agentResult.exitCode
|
|
55052
|
-
});
|
|
55053
|
-
}
|
|
55054
|
-
return {
|
|
55055
|
-
agentSuccess: agentResult.success,
|
|
55056
|
-
cost: agentResult.estimatedCostUsd ?? 0,
|
|
55057
|
-
protocolIds: agentResult.protocolIds
|
|
55058
|
-
};
|
|
55059
|
-
},
|
|
55060
|
-
shouldAbort: (failure) => {
|
|
55061
|
-
if (rectificationConfig.abortOnIncreasingFailures) {
|
|
55062
|
-
return failure.testSummary.failed > initialFailure.testSummary.failed;
|
|
55063
|
-
}
|
|
55064
|
-
return false;
|
|
55065
|
-
},
|
|
55066
|
-
verify: async (result) => {
|
|
55067
|
-
const retryVerification = await _rectificationDeps.runVerification({
|
|
55068
|
-
workdir,
|
|
55069
|
-
expectedFiles: getExpectedFiles(story),
|
|
55070
|
-
command: testCommand,
|
|
55071
|
-
timeoutSeconds,
|
|
55072
|
-
forceExit: config2.quality.forceExit,
|
|
55073
|
-
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
55074
|
-
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
55075
|
-
timeoutRetryCount: 0,
|
|
55076
|
-
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
55077
|
-
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
55078
|
-
shell: config2.quality.shell,
|
|
55079
|
-
stripEnvVars: config2.quality.stripEnvVars
|
|
55080
|
-
});
|
|
55081
|
-
if (retryVerification.success) {
|
|
55082
|
-
logger?.info("rectification", `[OK] ${label} succeeded!`, {
|
|
55083
|
-
storyId: story.id,
|
|
55084
|
-
attempt: currentAttempt,
|
|
55085
|
-
initialFailures: initialFailure.testSummary.failed
|
|
55086
|
-
});
|
|
55087
|
-
return { passed: true };
|
|
55088
|
-
}
|
|
55089
|
-
if (retryVerification.output) {
|
|
55090
|
-
const newTestSummary = parseTestOutput(retryVerification.output);
|
|
55091
|
-
if (newTestSummary.failed === 0 && retryVerification.status !== "ENVIRONMENTAL_FAILURE" && (retryVerification.status === "SUCCESS" || newTestSummary.passed > 0)) {
|
|
55092
|
-
logger?.info("rectification", `[OK] ${label} succeeded after parsing retry output`, {
|
|
55093
|
-
storyId: story.id,
|
|
55094
|
-
attempt: currentAttempt,
|
|
55095
|
-
initialFailures: initialFailure.testSummary.failed
|
|
55096
|
-
});
|
|
55097
|
-
return { passed: true };
|
|
55098
|
-
}
|
|
55099
|
-
const failingTests = newTestSummary.failures.slice(0, 10).map((failure) => failure.testName);
|
|
55100
|
-
const logData = {
|
|
55101
|
-
storyId: story.id,
|
|
55102
|
-
attempt: currentAttempt,
|
|
55103
|
-
remainingFailures: newTestSummary.failed,
|
|
55104
|
-
failingTests
|
|
55105
|
-
};
|
|
55106
|
-
if (newTestSummary.failures.length > 10 || newTestSummary.failures.length === 0 && newTestSummary.failed > 0) {
|
|
55107
|
-
logData.totalFailingTests = newTestSummary.failed;
|
|
55108
|
-
}
|
|
55109
|
-
logger?.warn("rectification", `${label} still failing after attempt`, logData);
|
|
55110
|
-
return {
|
|
55111
|
-
passed: false,
|
|
55112
|
-
newFailure: {
|
|
55113
|
-
testOutput: retryVerification.output,
|
|
55114
|
-
testSummary: newTestSummary
|
|
55115
|
-
}
|
|
55116
|
-
};
|
|
55117
|
-
}
|
|
55118
|
-
return {
|
|
55119
|
-
passed: false,
|
|
55120
|
-
newFailure: {
|
|
55121
|
-
testOutput: retryVerification.output ?? "",
|
|
55122
|
-
testSummary: initialFailure.testSummary
|
|
55123
|
-
}
|
|
55124
|
-
};
|
|
55125
|
-
}
|
|
55126
|
-
}).finally(async () => {
|
|
55127
|
-
if (heldHandle && runtime) {
|
|
55128
|
-
const stale = heldHandle;
|
|
55129
|
-
heldHandle = undefined;
|
|
55130
|
-
await runtime.sessionManager.closeSession(stale).catch(() => {});
|
|
55131
|
-
}
|
|
55132
|
-
});
|
|
55133
|
-
const succeeded = outcome.outcome === "fixed";
|
|
55134
|
-
if (outcome.outcome === "exhausted") {
|
|
55135
|
-
const finalFailure = outcome.finalFailure;
|
|
55136
|
-
const shouldEscalate = rectificationConfig.escalateOnExhaustion !== false && config2.autoMode?.escalation?.enabled === true && finalFailure.testSummary.failed > 0;
|
|
55137
|
-
if (shouldEscalate) {
|
|
55138
|
-
const complexity = story.routing?.complexity ?? "medium";
|
|
55139
|
-
const currentTier = config2.autoMode.complexityRouting?.[complexity] || config2.autoMode.escalation.tierOrder[0]?.tier || "balanced";
|
|
55140
|
-
const tierOrder = config2.autoMode.escalation.tierOrder;
|
|
55141
|
-
const escalationResult = _rectificationDeps.escalateTier(currentTier, tierOrder);
|
|
55142
|
-
const escalatedTier = escalationResult?.tier ?? null;
|
|
55143
|
-
const escalatedAgent = escalationResult?.agent;
|
|
55144
|
-
if (escalatedTier !== null) {
|
|
55145
|
-
const escalationManager = agentManager;
|
|
55146
|
-
const agentName = escalatedAgent ?? story.routing?.agent ?? escalationManager.getDefault();
|
|
55147
|
-
if (escalationManager.getAgent(agentName)) {
|
|
55148
|
-
const escalatedModelDef = resolveModelForAgent(config2.models, agentName, escalatedTier, escalationManager.getDefault());
|
|
55149
|
-
let escalationPrompt = RectifierPromptBuilder.escalated(finalFailure.testSummary.failures, story, outcome.attempts, currentTier, escalatedTier, rectificationConfig, testCommand, testScopedTemplate);
|
|
55150
|
-
if (promptPrefix) {
|
|
55151
|
-
escalationPrompt = `${promptPrefix}
|
|
55152
|
-
|
|
55153
|
-
${escalationPrompt}`;
|
|
55154
|
-
}
|
|
55155
|
-
const escalationRunResult = await escalationManager.runAs(agentName, {
|
|
55156
|
-
runOptions: {
|
|
55157
|
-
prompt: escalationPrompt,
|
|
55158
|
-
workdir,
|
|
55159
|
-
modelTier: escalatedTier,
|
|
55160
|
-
modelDef: escalatedModelDef,
|
|
55161
|
-
timeoutSeconds: config2.execution.sessionTimeoutSeconds,
|
|
55162
|
-
pipelineStage: "rectification",
|
|
55163
|
-
config: config2,
|
|
55164
|
-
projectDir,
|
|
55165
|
-
maxInteractionTurns: config2.agent?.maxInteractionTurns,
|
|
55166
|
-
featureName,
|
|
55167
|
-
storyId: story.id,
|
|
55168
|
-
sessionRole: "implementer"
|
|
55169
|
-
}
|
|
55170
|
-
});
|
|
55171
|
-
costAccum += escalationRunResult.estimatedCostUsd ?? 0;
|
|
55172
|
-
logger?.info("rectification", "escalated rectification attempt cost", {
|
|
55173
|
-
storyId: story.id,
|
|
55174
|
-
escalatedTier,
|
|
55175
|
-
cost: escalationRunResult.estimatedCostUsd
|
|
55176
|
-
});
|
|
55177
|
-
const escalationVerification = await _rectificationDeps.runVerification({
|
|
55178
|
-
workdir,
|
|
55179
|
-
expectedFiles: getExpectedFiles(story),
|
|
55180
|
-
command: testCommand,
|
|
55181
|
-
timeoutSeconds,
|
|
55182
|
-
forceExit: config2.quality.forceExit,
|
|
55183
|
-
detectOpenHandles: config2.quality.detectOpenHandles,
|
|
55184
|
-
detectOpenHandlesRetries: config2.quality.detectOpenHandlesRetries,
|
|
55185
|
-
timeoutRetryCount: 0,
|
|
55186
|
-
gracePeriodMs: config2.quality.gracePeriodMs,
|
|
55187
|
-
drainTimeoutMs: config2.quality.drainTimeoutMs,
|
|
55188
|
-
shell: config2.quality.shell,
|
|
55189
|
-
stripEnvVars: config2.quality.stripEnvVars
|
|
55190
|
-
});
|
|
55191
|
-
if (escalationVerification.success) {
|
|
55192
|
-
logger?.info("rectification", `${label} escalated from ${currentTier} to ${escalatedTier} and succeeded`, {
|
|
55193
|
-
storyId: story.id,
|
|
55194
|
-
currentTier,
|
|
55195
|
-
escalatedTier
|
|
55196
|
-
});
|
|
55197
|
-
return { succeeded: true, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
55198
|
-
}
|
|
55199
|
-
logger?.warn("rectification", "escalated rectification also failed", { storyId: story.id, escalatedTier });
|
|
55200
|
-
}
|
|
55201
|
-
}
|
|
55202
|
-
}
|
|
55203
|
-
logger?.warn("rectification", `${label} exhausted max retries`, {
|
|
55204
|
-
storyId: story.id,
|
|
55205
|
-
attempts: outcome.attempts,
|
|
55206
|
-
remainingFailures: initialFailure.testSummary.failed
|
|
55207
|
-
});
|
|
55208
|
-
}
|
|
55209
|
-
return { succeeded, cost: costAccum, durationMs: Date.now() - loopStartMs };
|
|
55210
|
-
}
|
|
55211
|
-
var _rectificationDeps;
|
|
55212
|
-
var init_rectification_loop = __esm(() => {
|
|
55213
|
-
init_agents();
|
|
55214
|
-
init_cost();
|
|
55215
|
-
init_types3();
|
|
55216
|
-
init_config();
|
|
55217
|
-
init_logger2();
|
|
55218
|
-
init_prd();
|
|
55219
|
-
init_prompts();
|
|
55220
|
-
init_naming();
|
|
55221
|
-
init_parser2();
|
|
55222
|
-
init_parser2();
|
|
55223
|
-
init_runners();
|
|
55224
|
-
_rectificationDeps = {
|
|
55225
|
-
agentManager: undefined,
|
|
55226
|
-
runVerification: fullSuite,
|
|
55227
|
-
escalateTier,
|
|
55228
|
-
runDebate: _defaultRunDebate
|
|
55229
|
-
};
|
|
55230
|
-
});
|
|
55231
|
-
|
|
55232
55299
|
// src/pipeline/stages/rectify.ts
|
|
55233
55300
|
var rectifyStage, _rectifyDeps;
|
|
55234
55301
|
var init_rectify2 = __esm(() => {
|
|
@@ -55327,7 +55394,7 @@ var init_rectify2 = __esm(() => {
|
|
|
55327
55394
|
}
|
|
55328
55395
|
};
|
|
55329
55396
|
_rectifyDeps = {
|
|
55330
|
-
runRectificationLoop: (ctx, opts) =>
|
|
55397
|
+
runRectificationLoop: (ctx, opts) => runRectificationLoop({
|
|
55331
55398
|
config: ctx.config,
|
|
55332
55399
|
workdir: ctx.workdir,
|
|
55333
55400
|
story: ctx.story,
|
|
@@ -55339,7 +55406,7 @@ var init_rectify2 = __esm(() => {
|
|
|
55339
55406
|
agentManager: ctx.agentManager,
|
|
55340
55407
|
projectDir: ctx.projectDir,
|
|
55341
55408
|
testScopedTemplate: opts.testScopedTemplate,
|
|
55342
|
-
|
|
55409
|
+
runtime: ctx.runtime,
|
|
55343
55410
|
sessionId: ctx.sessionId
|
|
55344
55411
|
}),
|
|
55345
55412
|
resolveTestCommands: resolveQualityTestCommands,
|
|
@@ -56190,7 +56257,7 @@ async function promptsInitCommand(options) {
|
|
|
56190
56257
|
mkdirSync4(templatesDir, { recursive: true });
|
|
56191
56258
|
const existingFiles = TEMPLATE_ROLES.map((t) => t.file).filter((f) => existsSync21(join50(templatesDir, f)));
|
|
56192
56259
|
if (existingFiles.length > 0 && !force) {
|
|
56193
|
-
|
|
56260
|
+
_promptsInitDeps.warn(`[WARN] nax/templates/ already contains files: ${existingFiles.join(", ")}. No files overwritten.
|
|
56194
56261
|
Pass --force to overwrite existing templates.`);
|
|
56195
56262
|
return [];
|
|
56196
56263
|
}
|
|
@@ -56202,9 +56269,9 @@ async function promptsInitCommand(options) {
|
|
|
56202
56269
|
await Bun.write(filePath, content);
|
|
56203
56270
|
written.push(filePath);
|
|
56204
56271
|
}
|
|
56205
|
-
|
|
56272
|
+
_promptsInitDeps.log(`[OK] Written ${written.length} template files to nax/templates/:`);
|
|
56206
56273
|
for (const filePath of written) {
|
|
56207
|
-
|
|
56274
|
+
_promptsInitDeps.log(` - ${filePath.replace(`${workdir}/`, "")}`);
|
|
56208
56275
|
}
|
|
56209
56276
|
if (autoWireConfig) {
|
|
56210
56277
|
await autoWirePromptsConfig(workdir);
|
|
@@ -56225,7 +56292,7 @@ async function autoWirePromptsConfig(workdir) {
|
|
|
56225
56292
|
}
|
|
56226
56293
|
}
|
|
56227
56294
|
}, null, 2);
|
|
56228
|
-
|
|
56295
|
+
_promptsInitDeps.log(`
|
|
56229
56296
|
No nax.config.json found. To activate overrides, create nax/config.json with:
|
|
56230
56297
|
${exampleConfig}`);
|
|
56231
56298
|
return;
|
|
@@ -56234,7 +56301,7 @@ ${exampleConfig}`);
|
|
|
56234
56301
|
const configContent = await configFile.text();
|
|
56235
56302
|
const config2 = JSON.parse(configContent);
|
|
56236
56303
|
if (config2.prompts?.overrides && Object.keys(config2.prompts.overrides).length > 0) {
|
|
56237
|
-
|
|
56304
|
+
_promptsInitDeps.log(`[INFO] prompts.overrides already configured in nax.config.json. Skipping auto-wiring.
|
|
56238
56305
|
` + " To reset overrides, remove the prompts.overrides section and re-run this command.");
|
|
56239
56306
|
return;
|
|
56240
56307
|
}
|
|
@@ -56251,7 +56318,7 @@ ${exampleConfig}`);
|
|
|
56251
56318
|
config2.prompts.overrides = overrides;
|
|
56252
56319
|
const updatedConfig = formatConfigJson(config2);
|
|
56253
56320
|
await Bun.write(configPath, updatedConfig);
|
|
56254
|
-
|
|
56321
|
+
_promptsInitDeps.log("[OK] Auto-wired prompts.overrides in nax.config.json");
|
|
56255
56322
|
}
|
|
56256
56323
|
function formatConfigJson(config2) {
|
|
56257
56324
|
const lines = ["{"];
|
|
@@ -56276,7 +56343,7 @@ function formatConfigJson(config2) {
|
|
|
56276
56343
|
return lines.join(`
|
|
56277
56344
|
`);
|
|
56278
56345
|
}
|
|
56279
|
-
var TEMPLATE_ROLES, TEMPLATE_HEADER = `<!--
|
|
56346
|
+
var _promptsInitDeps, TEMPLATE_ROLES, TEMPLATE_HEADER = `<!--
|
|
56280
56347
|
This file controls the role-body section of the nax prompt for this role.
|
|
56281
56348
|
Edit the content below to customize the task instructions given to the agent.
|
|
56282
56349
|
|
|
@@ -56292,6 +56359,10 @@ var TEMPLATE_ROLES, TEMPLATE_HEADER = `<!--
|
|
|
56292
56359
|
`;
|
|
56293
56360
|
var init_prompts_init = __esm(() => {
|
|
56294
56361
|
init_role_task();
|
|
56362
|
+
_promptsInitDeps = {
|
|
56363
|
+
log: console.log.bind(console),
|
|
56364
|
+
warn: console.warn.bind(console)
|
|
56365
|
+
};
|
|
56295
56366
|
TEMPLATE_ROLES = [
|
|
56296
56367
|
{ file: "test-writer.md", role: "test-writer" },
|
|
56297
56368
|
{ file: "implementer.md", role: "implementer", variant: "standard" },
|
|
@@ -56878,7 +56949,8 @@ __export(exports_init, {
|
|
|
56878
56949
|
validateProjectName: () => validateProjectName,
|
|
56879
56950
|
initProject: () => initProject,
|
|
56880
56951
|
initCommand: () => initCommand,
|
|
56881
|
-
checkInitCollision: () => checkInitCollision
|
|
56952
|
+
checkInitCollision: () => checkInitCollision,
|
|
56953
|
+
_initDeps: () => _initDeps
|
|
56882
56954
|
});
|
|
56883
56955
|
import { existsSync as existsSync24 } from "fs";
|
|
56884
56956
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
@@ -57105,20 +57177,20 @@ async function initProject(projectRoot, options) {
|
|
|
57105
57177
|
}
|
|
57106
57178
|
await updateGitignore(projectRoot);
|
|
57107
57179
|
await promptsInitCommand({ workdir: projectRoot, force: false, autoWireConfig: false });
|
|
57108
|
-
|
|
57180
|
+
_initDeps.log(`
|
|
57109
57181
|
[OK] nax init complete. Created files:`);
|
|
57110
|
-
|
|
57111
|
-
|
|
57112
|
-
|
|
57113
|
-
|
|
57114
|
-
|
|
57115
|
-
|
|
57182
|
+
_initDeps.log(" - .nax/config.json");
|
|
57183
|
+
_initDeps.log(" - .nax/context.md");
|
|
57184
|
+
_initDeps.log(" - .nax/constitution.md");
|
|
57185
|
+
_initDeps.log(" - .nax/hooks/");
|
|
57186
|
+
_initDeps.log(" - .nax/templates/");
|
|
57187
|
+
_initDeps.log(`
|
|
57116
57188
|
Next steps:`);
|
|
57117
|
-
|
|
57118
|
-
|
|
57119
|
-
|
|
57120
|
-
|
|
57121
|
-
|
|
57189
|
+
_initDeps.log(" 1. Review .nax/context.md and fill in TODOs");
|
|
57190
|
+
_initDeps.log(" 2. Review .nax/config.json and adjust quality commands");
|
|
57191
|
+
_initDeps.log(" 3. Run: nax generate");
|
|
57192
|
+
_initDeps.log(" 4. Run: nax plan");
|
|
57193
|
+
_initDeps.log(" 5. Run: nax run");
|
|
57122
57194
|
logger.info("init", "Project config initialized successfully", { path: projectDir });
|
|
57123
57195
|
}
|
|
57124
57196
|
async function initCommand(options = {}) {
|
|
@@ -57127,19 +57199,19 @@ async function initCommand(options = {}) {
|
|
|
57127
57199
|
} else if (options.package) {
|
|
57128
57200
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
57129
57201
|
await initPackage(projectRoot, options.package);
|
|
57130
|
-
|
|
57202
|
+
_initDeps.log(`
|
|
57131
57203
|
[OK] Package scaffold created.`);
|
|
57132
|
-
|
|
57133
|
-
|
|
57204
|
+
_initDeps.log(` Created: .nax/mono/${options.package}/context.md`);
|
|
57205
|
+
_initDeps.log(`
|
|
57134
57206
|
Next steps:`);
|
|
57135
|
-
|
|
57136
|
-
|
|
57207
|
+
_initDeps.log(` 1. Review .nax/mono/${options.package}/context.md and fill in TODOs`);
|
|
57208
|
+
_initDeps.log(` 2. Run: nax generate --package ${options.package}`);
|
|
57137
57209
|
} else {
|
|
57138
57210
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
57139
57211
|
await initProject(projectRoot, { name: options.name, force: options.force });
|
|
57140
57212
|
}
|
|
57141
57213
|
}
|
|
57142
|
-
var MINIMAL_GLOBAL_CONFIG;
|
|
57214
|
+
var _initDeps, MINIMAL_GLOBAL_CONFIG;
|
|
57143
57215
|
var init_init2 = __esm(() => {
|
|
57144
57216
|
init_paths();
|
|
57145
57217
|
init_errors();
|
|
@@ -57149,6 +57221,9 @@ var init_init2 = __esm(() => {
|
|
|
57149
57221
|
init_init_context();
|
|
57150
57222
|
init_init_detect();
|
|
57151
57223
|
init_prompts2();
|
|
57224
|
+
_initDeps = {
|
|
57225
|
+
log: console.log.bind(console)
|
|
57226
|
+
};
|
|
57152
57227
|
MINIMAL_GLOBAL_CONFIG = {
|
|
57153
57228
|
version: 1
|
|
57154
57229
|
};
|
|
@@ -58789,7 +58864,7 @@ var package_default;
|
|
|
58789
58864
|
var init_package = __esm(() => {
|
|
58790
58865
|
package_default = {
|
|
58791
58866
|
name: "@nathapp/nax",
|
|
58792
|
-
version: "0.67.0-canary.
|
|
58867
|
+
version: "0.67.0-canary.4",
|
|
58793
58868
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
58794
58869
|
type: "module",
|
|
58795
58870
|
bin: {
|
|
@@ -58799,7 +58874,7 @@ var init_package = __esm(() => {
|
|
|
58799
58874
|
prepare: "git config core.hooksPath .githooks",
|
|
58800
58875
|
dev: "bun run bin/nax.ts",
|
|
58801
58876
|
build: 'bun build bin/nax.ts --outdir dist --target bun --define "GIT_COMMIT=\\"$(git rev-parse --short HEAD)\\""',
|
|
58802
|
-
typecheck: "bun x tsc --noEmit",
|
|
58877
|
+
typecheck: "bun x tsc --noEmit && bun x tsc --noEmit -p tsconfig.contracts.json",
|
|
58803
58878
|
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",
|
|
58804
58879
|
"lint:json": "bun x biome check src/ bin/ --reporter json && bun run check:nax-error 1>&2 && bun run check:logger-storyid 1>&2",
|
|
58805
58880
|
"lint:fix": "bun x biome check --write src/ bin/",
|
|
@@ -58812,8 +58887,10 @@ var init_package = __esm(() => {
|
|
|
58812
58887
|
"check:logger-storyid": "bun run scripts/check-logger-storyid.ts",
|
|
58813
58888
|
"check:logger-storyid:update": "bun run scripts/check-logger-storyid.ts --update-baseline",
|
|
58814
58889
|
release: "bun scripts/release.ts",
|
|
58815
|
-
test: "bun run scripts/run-tests.ts",
|
|
58816
|
-
"test:
|
|
58890
|
+
test: "AGENT=1 bun run scripts/run-tests.ts",
|
|
58891
|
+
"test:verbose": "bun run scripts/run-tests.ts",
|
|
58892
|
+
"test:bail": "AGENT=1 bun run scripts/run-tests.ts --bail",
|
|
58893
|
+
"test:bail-verbose": "bun run scripts/run-tests.ts --bail",
|
|
58817
58894
|
"test:no-wrap": "bun test test/unit/ --timeout=5000 && bun test test/integration/ --timeout=5000 && bun test test/ui/ --timeout=5000",
|
|
58818
58895
|
"test:watch": "bun test --watch",
|
|
58819
58896
|
"test:unit": "bun test ./test/unit/ --timeout=60000",
|
|
@@ -58882,8 +58959,8 @@ var init_version = __esm(() => {
|
|
|
58882
58959
|
NAX_VERSION = package_default.version;
|
|
58883
58960
|
NAX_COMMIT = (() => {
|
|
58884
58961
|
try {
|
|
58885
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
58886
|
-
return "
|
|
58962
|
+
if (/^[0-9a-f]{6,10}$/.test("22d1f67c"))
|
|
58963
|
+
return "22d1f67c";
|
|
58887
58964
|
} catch {}
|
|
58888
58965
|
try {
|
|
58889
58966
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -59607,7 +59684,7 @@ async function runAcceptanceFixCycle(ctx, prd, initialFailures, diagnosis, accep
|
|
|
59607
59684
|
coRun: "co-run-sequential"
|
|
59608
59685
|
}
|
|
59609
59686
|
],
|
|
59610
|
-
validate: async (_ctx) => {
|
|
59687
|
+
validate: async (_ctx, _opts) => {
|
|
59611
59688
|
const result = await runAcceptanceTestsOnce(ctx, prd);
|
|
59612
59689
|
if (result.passed)
|
|
59613
59690
|
return [];
|
|
@@ -59825,7 +59902,7 @@ async function findResponsibleStory(testFile, workdir, passedStories) {
|
|
|
59825
59902
|
}
|
|
59826
59903
|
async function runDeferredRegression(options) {
|
|
59827
59904
|
const logger = getSafeLogger();
|
|
59828
|
-
const { config: config2, prd, workdir,
|
|
59905
|
+
const { config: config2, prd, workdir, runtime } = options;
|
|
59829
59906
|
const regressionMode = config2.execution.regressionGate?.mode ?? "deferred";
|
|
59830
59907
|
if (regressionMode === "disabled") {
|
|
59831
59908
|
logger?.info("regression", "Deferred regression gate disabled");
|
|
@@ -60015,8 +60092,9 @@ async function runDeferredRegression(options) {
|
|
|
60015
60092
|
promptPrefix: `# DEFERRED REGRESSION: Full-Suite Failures
|
|
60016
60093
|
|
|
60017
60094
|
Your story ${story.id} broke tests in the full suite. Fix these regressions.`,
|
|
60018
|
-
agentManager,
|
|
60019
|
-
featureName: prd.feature
|
|
60095
|
+
agentManager: runtime.agentManager,
|
|
60096
|
+
featureName: prd.feature,
|
|
60097
|
+
runtime
|
|
60020
60098
|
});
|
|
60021
60099
|
storyCostAccum[story.id] = (storyCostAccum[story.id] ?? 0) + rectResult.cost;
|
|
60022
60100
|
storyDurationAccum[story.id] = (storyDurationAccum[story.id] ?? 0) + rectResult.durationMs;
|
|
@@ -60095,7 +60173,7 @@ var init_run_regression = __esm(() => {
|
|
|
60095
60173
|
init_runners();
|
|
60096
60174
|
_regressionDeps = {
|
|
60097
60175
|
runVerification: fullSuite,
|
|
60098
|
-
runRectificationLoop
|
|
60176
|
+
runRectificationLoop,
|
|
60099
60177
|
parseTestOutput
|
|
60100
60178
|
};
|
|
60101
60179
|
});
|
|
@@ -60149,7 +60227,7 @@ async function handleRunCompletion(options) {
|
|
|
60149
60227
|
config: config2,
|
|
60150
60228
|
prd,
|
|
60151
60229
|
workdir,
|
|
60152
|
-
|
|
60230
|
+
runtime: options.runtime
|
|
60153
60231
|
});
|
|
60154
60232
|
const lastRunAt = new Date().toISOString();
|
|
60155
60233
|
logger?.info("regression", "Deferred regression gate completed", {
|
|
@@ -98394,6 +98472,7 @@ async function extractRunSummary(filePath) {
|
|
|
98394
98472
|
|
|
98395
98473
|
// src/commands/logs-formatter.ts
|
|
98396
98474
|
var LOG_LEVEL_PRIORITY2 = {
|
|
98475
|
+
silent: -1,
|
|
98397
98476
|
debug: 0,
|
|
98398
98477
|
info: 1,
|
|
98399
98478
|
warn: 2,
|
|
@@ -99277,6 +99356,13 @@ init_helpers();
|
|
|
99277
99356
|
init_crash_recovery();
|
|
99278
99357
|
init_pid_registry();
|
|
99279
99358
|
|
|
99359
|
+
// src/execution/lifecycle/index.ts
|
|
99360
|
+
init_acceptance_loop();
|
|
99361
|
+
init_headless_formatter();
|
|
99362
|
+
init_run_completion();
|
|
99363
|
+
init_run_cleanup();
|
|
99364
|
+
init_run_setup();
|
|
99365
|
+
init_run_regression();
|
|
99280
99366
|
// bin/nax.ts
|
|
99281
99367
|
init_hooks();
|
|
99282
99368
|
init_logger2();
|