@nathapp/nax 0.70.0-canary.1 → 0.70.0-canary.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nax.js +298 -115
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -17028,6 +17028,7 @@ var init_schemas_infra = __esm(() => {
|
|
|
17028
17028
|
testPath: exports_external.string().min(1, "acceptance.testPath must be non-empty"),
|
|
17029
17029
|
command: exports_external.string().optional(),
|
|
17030
17030
|
model: ConfiguredModelSchema.default("fast"),
|
|
17031
|
+
generateModel: ConfiguredModelSchema.optional(),
|
|
17031
17032
|
refinement: exports_external.boolean().default(true),
|
|
17032
17033
|
refinementConcurrency: exports_external.number().int().min(1).max(10).default(3),
|
|
17033
17034
|
redGate: exports_external.boolean().default(true),
|
|
@@ -19231,7 +19232,7 @@ function reshapeSelector(name, fn) {
|
|
|
19231
19232
|
var reviewConfigSelector, planConfigSelector, decomposeConfigSelector, rectifyConfigSelector, acceptanceConfigSelector, acceptanceFixConfigSelector, acceptanceGenConfigSelector, tddConfigSelector, debateConfigSelector, routingConfigSelector, verifyConfigSelector, rectificationGateConfigSelector, agentConfigSelector, agentManagerConfigSelector, interactionConfigSelector, precheckConfigSelector, qualityConfigSelector, autofixConfigSelector, executionGatesConfigSelector, testPatternConfigSelector, contextConfigSelector, contextToolRuntimeConfigSelector, promptLoaderConfigSelector, llmRoutingConfigSelector;
|
|
19232
19233
|
var init_selectors = __esm(() => {
|
|
19233
19234
|
reviewConfigSelector = pickSelector("review", "review", "debate", "models", "execution", "project", "quality", "agent");
|
|
19234
|
-
planConfigSelector = pickSelector("plan", "plan", "debate", "agent", "project");
|
|
19235
|
+
planConfigSelector = pickSelector("plan", "plan", "debate", "agent", "project", "routing");
|
|
19235
19236
|
decomposeConfigSelector = pickSelector("decompose", "plan", "agent", "routing");
|
|
19236
19237
|
rectifyConfigSelector = pickSelector("rectify", "execution");
|
|
19237
19238
|
acceptanceConfigSelector = pickSelector("acceptance", "acceptance");
|
|
@@ -21021,6 +21022,7 @@ class AcpAgentAdapter {
|
|
|
21021
21022
|
const MAX_TURNS = opts.maxTurns ?? 10;
|
|
21022
21023
|
let totalTokenUsage = { inputTokens: 0, outputTokens: 0 };
|
|
21023
21024
|
let totalExactCostUsd;
|
|
21025
|
+
const interactions = [];
|
|
21024
21026
|
let turnCount = 0;
|
|
21025
21027
|
let lastResponse = null;
|
|
21026
21028
|
let timedOut = false;
|
|
@@ -21105,6 +21107,7 @@ class AcpAgentAdapter {
|
|
|
21105
21107
|
})
|
|
21106
21108
|
]);
|
|
21107
21109
|
if (response) {
|
|
21110
|
+
interactions.push({ turnIndex: turnCount, question, reply: response.answer });
|
|
21108
21111
|
currentPrompt = response.answer;
|
|
21109
21112
|
continue;
|
|
21110
21113
|
}
|
|
@@ -21135,7 +21138,8 @@ class AcpAgentAdapter {
|
|
|
21135
21138
|
tokenUsage,
|
|
21136
21139
|
estimatedCostUsd,
|
|
21137
21140
|
exactCostUsd,
|
|
21138
|
-
internalRoundTrips: turnCount
|
|
21141
|
+
internalRoundTrips: turnCount,
|
|
21142
|
+
...interactions.length > 0 ? { interactions } : {}
|
|
21139
21143
|
};
|
|
21140
21144
|
}
|
|
21141
21145
|
async closeSession(handle) {
|
|
@@ -22138,6 +22142,7 @@ class AgentManager {
|
|
|
22138
22142
|
sessionId: handle.protocolIds?.sessionId ?? null,
|
|
22139
22143
|
recordId: handle.protocolIds?.recordId ?? null
|
|
22140
22144
|
},
|
|
22145
|
+
...result.interactions?.length ? { interactions: result.interactions } : {},
|
|
22141
22146
|
origin: "runAsSession",
|
|
22142
22147
|
...opts.callId !== undefined ? { callId: opts.callId } : {},
|
|
22143
22148
|
...opts.scopeId !== undefined ? { scopeId: opts.scopeId } : {}
|
|
@@ -22251,6 +22256,34 @@ function resolveDefaultAgent(config2) {
|
|
|
22251
22256
|
}
|
|
22252
22257
|
var FALLBACK_DEFAULT_AGENT = "claude";
|
|
22253
22258
|
|
|
22259
|
+
// src/agents/shared/agent-profile-resolver.ts
|
|
22260
|
+
function resolveAgentAssignment(selectedProfileId, agentRouting, storyId) {
|
|
22261
|
+
if (agentRouting?.enabled !== true)
|
|
22262
|
+
return null;
|
|
22263
|
+
const profiles = agentRouting.profiles ?? [];
|
|
22264
|
+
if (profiles.length === 0)
|
|
22265
|
+
return null;
|
|
22266
|
+
const defaultProfile = agentRouting.default ? profiles.find((p) => p.id === agentRouting.default) : undefined;
|
|
22267
|
+
if (selectedProfileId) {
|
|
22268
|
+
const profile = profiles.find((p) => p.id === selectedProfileId);
|
|
22269
|
+
if (profile)
|
|
22270
|
+
return toAssignment(profile);
|
|
22271
|
+
getSafeLogger()?.warn("routing", `Story ${storyId} selected unknown agent profile "${selectedProfileId}" \u2014 falling back to ${defaultProfile ? `default profile "${defaultProfile.id}"` : "no profile"}`, { storyId, agentProfileId: selectedProfileId });
|
|
22272
|
+
}
|
|
22273
|
+
return defaultProfile ? toAssignment(defaultProfile) : null;
|
|
22274
|
+
}
|
|
22275
|
+
function toAssignment(p) {
|
|
22276
|
+
return { agent: p.target.agent, agentProfileId: p.id, profileModelTier: p.target.model };
|
|
22277
|
+
}
|
|
22278
|
+
var init_agent_profile_resolver = __esm(() => {
|
|
22279
|
+
init_logger2();
|
|
22280
|
+
});
|
|
22281
|
+
|
|
22282
|
+
// src/agents/shared/index.ts
|
|
22283
|
+
var init_shared = __esm(() => {
|
|
22284
|
+
init_agent_profile_resolver();
|
|
22285
|
+
});
|
|
22286
|
+
|
|
22254
22287
|
// src/agents/retry/types.ts
|
|
22255
22288
|
var ParseValidationError;
|
|
22256
22289
|
var init_types4 = __esm(() => {
|
|
@@ -22497,6 +22530,7 @@ var init_agents = __esm(() => {
|
|
|
22497
22530
|
init_cost();
|
|
22498
22531
|
init_version_detection();
|
|
22499
22532
|
init_manager();
|
|
22533
|
+
init_shared();
|
|
22500
22534
|
init_retry();
|
|
22501
22535
|
});
|
|
22502
22536
|
|
|
@@ -28189,7 +28223,8 @@ function validateStory(raw, index, allIds) {
|
|
|
28189
28223
|
complexity,
|
|
28190
28224
|
testStrategy,
|
|
28191
28225
|
reasoning: typeof routing.reasoning === "string" && routing.reasoning.trim().length > 0 ? routing.reasoning.trim() : "validated from LLM output",
|
|
28192
|
-
...noTestJustification !== undefined ? { noTestJustification } : {}
|
|
28226
|
+
...noTestJustification !== undefined ? { noTestJustification } : {},
|
|
28227
|
+
...typeof routing.agentProfileId === "string" && routing.agentProfileId.trim().length > 0 ? { agentProfileId: routing.agentProfileId.trim() } : {}
|
|
28193
28228
|
},
|
|
28194
28229
|
...workdir !== undefined ? { workdir } : {},
|
|
28195
28230
|
...contextFiles.length > 0 ? { contextFiles } : {},
|
|
@@ -34691,8 +34726,10 @@ var init_plan = __esm(() => {
|
|
|
34691
34726
|
truncated: () => PlanPromptBuilder.jsonRepair(0, "JSON appears truncated \u2014 please rewrite completely")
|
|
34692
34727
|
}
|
|
34693
34728
|
}),
|
|
34694
|
-
build(input,
|
|
34695
|
-
const
|
|
34729
|
+
build(input, ctx) {
|
|
34730
|
+
const agentRouting = ctx.config.routing?.agents;
|
|
34731
|
+
const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
|
|
34732
|
+
const { taskContext, outputFormat } = new PlanPromptBuilder().build(input.specContent, input.codebaseContext, input.outputPath, input.packages, input.packageDetails, input.projectProfile, undefined, profiles);
|
|
34696
34733
|
return {
|
|
34697
34734
|
role: { id: "role", content: "", overridable: false },
|
|
34698
34735
|
task: { id: "task", content: `${taskContext}
|
|
@@ -34926,8 +34963,10 @@ var init_plan_refine = __esm(() => {
|
|
|
34926
34963
|
}
|
|
34927
34964
|
}),
|
|
34928
34965
|
fileOutput: (input) => input.outputPath,
|
|
34929
|
-
build(input,
|
|
34930
|
-
const
|
|
34966
|
+
build(input, ctx) {
|
|
34967
|
+
const agentRouting = ctx.config.routing?.agents;
|
|
34968
|
+
const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
|
|
34969
|
+
const { taskContext, outputFormat } = new PlanPromptBuilder().build(input.specContent, input.codebaseContext, input.outputPath, input.packages, input.packageDetails, input.projectProfile, undefined, profiles);
|
|
34931
34970
|
return {
|
|
34932
34971
|
role: { id: "role", content: "", overridable: false },
|
|
34933
34972
|
task: {
|
|
@@ -35203,15 +35242,12 @@ Consider:
|
|
|
35203
35242
|
});
|
|
35204
35243
|
|
|
35205
35244
|
// src/operations/decompose.ts
|
|
35206
|
-
var
|
|
35245
|
+
var decomposeOp;
|
|
35207
35246
|
var init_decompose2 = __esm(() => {
|
|
35208
35247
|
init_decompose();
|
|
35209
35248
|
init_decompose_prompt();
|
|
35210
35249
|
init_config();
|
|
35211
35250
|
init_logger2();
|
|
35212
|
-
_decomposeOpDeps = {
|
|
35213
|
-
getSafeLogger
|
|
35214
|
-
};
|
|
35215
35251
|
decomposeOp = {
|
|
35216
35252
|
kind: "complete",
|
|
35217
35253
|
name: "decompose",
|
|
@@ -35236,46 +35272,8 @@ var init_decompose2 = __esm(() => {
|
|
|
35236
35272
|
task: { id: "task", content: prompt, overridable: false }
|
|
35237
35273
|
};
|
|
35238
35274
|
},
|
|
35239
|
-
parse(output, _input,
|
|
35240
|
-
|
|
35241
|
-
const agentRouting = ctx.config.routing?.agents;
|
|
35242
|
-
if (agentRouting?.enabled !== true) {
|
|
35243
|
-
return stories;
|
|
35244
|
-
}
|
|
35245
|
-
const profiles = agentRouting.profiles ?? [];
|
|
35246
|
-
if (profiles.length === 0) {
|
|
35247
|
-
return stories;
|
|
35248
|
-
}
|
|
35249
|
-
const defaultProfile = agentRouting.default ? profiles.find((p) => p.id === agentRouting.default) : undefined;
|
|
35250
|
-
return stories.map((story) => {
|
|
35251
|
-
if (story.agentProfileId) {
|
|
35252
|
-
const profile = profiles.find((p) => p.id === story.agentProfileId);
|
|
35253
|
-
if (profile) {
|
|
35254
|
-
return {
|
|
35255
|
-
...story,
|
|
35256
|
-
routing: {
|
|
35257
|
-
...story.routing,
|
|
35258
|
-
agent: profile.target.agent,
|
|
35259
|
-
agentProfileId: profile.id,
|
|
35260
|
-
profileModelTier: profile.target.model
|
|
35261
|
-
}
|
|
35262
|
-
};
|
|
35263
|
-
}
|
|
35264
|
-
_decomposeOpDeps.getSafeLogger()?.warn("decompose", `Story ${story.id} selected unknown agent profile "${story.agentProfileId}" \u2014 falling back to ${defaultProfile ? `default profile "${defaultProfile.id}"` : "no profile"}`, { storyId: story.id, agentProfileId: story.agentProfileId });
|
|
35265
|
-
}
|
|
35266
|
-
if (defaultProfile) {
|
|
35267
|
-
return {
|
|
35268
|
-
...story,
|
|
35269
|
-
routing: {
|
|
35270
|
-
...story.routing,
|
|
35271
|
-
agent: defaultProfile.target.agent,
|
|
35272
|
-
agentProfileId: defaultProfile.id,
|
|
35273
|
-
profileModelTier: defaultProfile.target.model
|
|
35274
|
-
}
|
|
35275
|
-
};
|
|
35276
|
-
}
|
|
35277
|
-
return story;
|
|
35278
|
-
});
|
|
35275
|
+
parse(output, _input, _ctx) {
|
|
35276
|
+
return parseDecomposeOutput(output);
|
|
35279
35277
|
}
|
|
35280
35278
|
};
|
|
35281
35279
|
});
|
|
@@ -36140,7 +36138,7 @@ var init_acceptance_generate = __esm(() => {
|
|
|
36140
36138
|
stage: "acceptance",
|
|
36141
36139
|
session: { role: "acceptance-gen", lifetime: "fresh" },
|
|
36142
36140
|
config: acceptanceGenConfigSelector,
|
|
36143
|
-
model: (_input, ctx) => ctx.config.acceptance.model,
|
|
36141
|
+
model: (_input, ctx) => ctx.config.acceptance.generateModel ?? ctx.config.acceptance.model,
|
|
36144
36142
|
timeoutMs: (_input, ctx) => ctx.config.execution.sessionTimeoutSeconds * 1000,
|
|
36145
36143
|
build(input, _ctx) {
|
|
36146
36144
|
const prompt = new AcceptancePromptBuilder().buildGeneratorFromPRDPrompt({
|
|
@@ -36244,6 +36242,7 @@ var init_refinement = () => {};
|
|
|
36244
36242
|
var acceptanceRefineOp;
|
|
36245
36243
|
var init_acceptance_refine = __esm(() => {
|
|
36246
36244
|
init_refinement();
|
|
36245
|
+
init_retry();
|
|
36247
36246
|
init_config();
|
|
36248
36247
|
init_logger2();
|
|
36249
36248
|
init_prompts();
|
|
@@ -36253,7 +36252,8 @@ var init_acceptance_refine = __esm(() => {
|
|
|
36253
36252
|
stage: "acceptance",
|
|
36254
36253
|
jsonMode: true,
|
|
36255
36254
|
config: acceptanceConfigSelector,
|
|
36256
|
-
|
|
36255
|
+
retry: { preset: "transient-network", maxAttempts: 2, baseDelayMs: 0 },
|
|
36256
|
+
model: (_input, ctx) => ctx.config.acceptance.generateModel ?? ctx.config.acceptance.model,
|
|
36257
36257
|
timeoutMs: (_input, ctx) => ctx.config.acceptance.timeoutMs,
|
|
36258
36258
|
build(input, _ctx) {
|
|
36259
36259
|
const prompt = new AcceptancePromptBuilder().buildRefinementPrompt(input.criteria, input.codebaseContext, {
|
|
@@ -36268,8 +36268,11 @@ var init_acceptance_refine = __esm(() => {
|
|
|
36268
36268
|
};
|
|
36269
36269
|
},
|
|
36270
36270
|
parse(output, input, _ctx) {
|
|
36271
|
+
if (!output || !output.trim()) {
|
|
36272
|
+
throw new ParseValidationError("acceptance-refine: empty output");
|
|
36273
|
+
}
|
|
36271
36274
|
if (refinementWouldFallback(output)) {
|
|
36272
|
-
getSafeLogger()?.warn("acceptance", "AC refinement returned no usable JSON \u2014 falling back to unrefined criteria", { storyId: input.storyId, criteriaCount: input.criteria.length, responseBytes: output
|
|
36275
|
+
getSafeLogger()?.warn("acceptance", "AC refinement returned no usable JSON \u2014 falling back to unrefined criteria", { storyId: input.storyId, criteriaCount: input.criteria.length, responseBytes: output.length });
|
|
36273
36276
|
}
|
|
36274
36277
|
const items = parseRefinementResponse(output, input.criteria);
|
|
36275
36278
|
return items.map((item) => ({ ...item, storyId: item.storyId || input.storyId }));
|
|
@@ -38583,8 +38586,10 @@ var init_plan_draft = __esm(() => {
|
|
|
38583
38586
|
model: (_input, ctx) => ctx.config.plan?.model ?? "fast",
|
|
38584
38587
|
timeoutMs: (_input, ctx) => (ctx.config.plan?.timeoutSeconds ?? 600) * 1000,
|
|
38585
38588
|
retry: (input) => createDraftRetryStrategy(input.citationThreshold),
|
|
38586
|
-
build(input,
|
|
38587
|
-
|
|
38589
|
+
build(input, ctx) {
|
|
38590
|
+
const agentRouting = ctx.config.routing?.agents;
|
|
38591
|
+
const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
|
|
38592
|
+
return new PlanPromptBuilder().buildDraft({ ...input, profiles });
|
|
38588
38593
|
},
|
|
38589
38594
|
parse(output, input, _ctx) {
|
|
38590
38595
|
return parsePlanDraft(output, input);
|
|
@@ -39088,11 +39093,58 @@ var init_full_suite_gate = __esm(() => {
|
|
|
39088
39093
|
};
|
|
39089
39094
|
});
|
|
39090
39095
|
|
|
39096
|
+
// src/operations/full-suite-rectify-op.ts
|
|
39097
|
+
var fullSuiteRectifyOp;
|
|
39098
|
+
var init_full_suite_rectify_op = __esm(() => {
|
|
39099
|
+
init_config();
|
|
39100
|
+
init_prompts();
|
|
39101
|
+
init_test_edit_declaration();
|
|
39102
|
+
fullSuiteRectifyOp = {
|
|
39103
|
+
kind: "run",
|
|
39104
|
+
name: "full-suite-rectify",
|
|
39105
|
+
stage: "rectification",
|
|
39106
|
+
session: { role: "implementer", lifetime: "warm" },
|
|
39107
|
+
config: autofixConfigSelector,
|
|
39108
|
+
build(input, _ctx) {
|
|
39109
|
+
const prompt = RectifierPromptBuilder.failingTestRectification(input.findings, input.story);
|
|
39110
|
+
return {
|
|
39111
|
+
role: { id: "role", content: "", overridable: false },
|
|
39112
|
+
task: { id: "task", content: prompt, overridable: false }
|
|
39113
|
+
};
|
|
39114
|
+
},
|
|
39115
|
+
parse(output, _input, _ctx) {
|
|
39116
|
+
const declarations = parseTestEditDeclarations(output);
|
|
39117
|
+
return { applied: true, testEditDeclarations: declarations };
|
|
39118
|
+
}
|
|
39119
|
+
};
|
|
39120
|
+
});
|
|
39121
|
+
|
|
39091
39122
|
// src/operations/full-suite-rectify.ts
|
|
39092
|
-
function makeFullSuiteRectifyStrategy(story, config2) {
|
|
39123
|
+
function makeFullSuiteRectifyStrategy(story, config2, sink) {
|
|
39124
|
+
const appliesTo = (finding) => finding.source === "test-runner" && (finding.category === "failed-test" || finding.category === "execution-failed");
|
|
39125
|
+
if (sink) {
|
|
39126
|
+
return {
|
|
39127
|
+
name: "full-suite-rectify",
|
|
39128
|
+
appliesTo,
|
|
39129
|
+
fixOp: fullSuiteRectifyOp,
|
|
39130
|
+
buildInput: (findings) => ({ story, findings }),
|
|
39131
|
+
extractApplied: (output) => {
|
|
39132
|
+
for (const d of output.testEditDeclarations) {
|
|
39133
|
+
if (d.reason === "mock_structure" && d.files && d.files.length > 0) {
|
|
39134
|
+
sink.mockHandoffs.push({ files: d.files, reasonDetail: d.reasonDetail ?? "" });
|
|
39135
|
+
} else if (d.reason !== "mock_structure") {
|
|
39136
|
+
sink.testEdits.push(d);
|
|
39137
|
+
}
|
|
39138
|
+
}
|
|
39139
|
+
return { targetFiles: [], summary: "Fixed failing tests" };
|
|
39140
|
+
},
|
|
39141
|
+
maxAttempts: config2.execution.rectification.maxAttemptsPerStrategy,
|
|
39142
|
+
coRun: "exclusive"
|
|
39143
|
+
};
|
|
39144
|
+
}
|
|
39093
39145
|
return {
|
|
39094
39146
|
name: "full-suite-rectify",
|
|
39095
|
-
appliesTo
|
|
39147
|
+
appliesTo,
|
|
39096
39148
|
fixOp: implementerOp,
|
|
39097
39149
|
buildInput: (findings) => ({
|
|
39098
39150
|
story,
|
|
@@ -39105,6 +39157,7 @@ function makeFullSuiteRectifyStrategy(story, config2) {
|
|
|
39105
39157
|
}
|
|
39106
39158
|
var init_full_suite_rectify = __esm(() => {
|
|
39107
39159
|
init_prompts();
|
|
39160
|
+
init_full_suite_rectify_op();
|
|
39108
39161
|
init_implement();
|
|
39109
39162
|
});
|
|
39110
39163
|
|
|
@@ -39232,7 +39285,8 @@ function applyTestEditDeclarations(findings, declarations, story, invalidMockStr
|
|
|
39232
39285
|
const valid = validatePrdQuote(prdQuote, story);
|
|
39233
39286
|
if (valid) {
|
|
39234
39287
|
result = result.map((f) => {
|
|
39235
|
-
|
|
39288
|
+
const eligible = f.file === d.file && (f.fixTarget === "source" || f.fixTarget == null && f.source === "test-runner");
|
|
39289
|
+
if (eligible) {
|
|
39236
39290
|
return {
|
|
39237
39291
|
...f,
|
|
39238
39292
|
fixTarget: "test",
|
|
@@ -40141,6 +40195,7 @@ var init_operations = __esm(() => {
|
|
|
40141
40195
|
init_greenfield_gate();
|
|
40142
40196
|
init_full_suite_gate();
|
|
40143
40197
|
init_full_suite_rectify();
|
|
40198
|
+
init_full_suite_rectify_op();
|
|
40144
40199
|
init_autofix_implementer_strategy();
|
|
40145
40200
|
init_autofix_test_writer_strategy();
|
|
40146
40201
|
init_apply_test_edit_declarations();
|
|
@@ -42247,6 +42302,23 @@ ${adversarialErrors}
|
|
|
42247
42302
|
Do NOT add new features \u2014 only fix valid issues.
|
|
42248
42303
|
Commit your fixes when done.${scopeConstraint}${noTestIsolationBlock(story)}${escapeHatchFor(story)}`;
|
|
42249
42304
|
}
|
|
42305
|
+
function formatFailingTestsList(findings) {
|
|
42306
|
+
if (findings.length === 0) {
|
|
42307
|
+
return "The full test suite has failing tests. Fix the implementation to make all tests pass.";
|
|
42308
|
+
}
|
|
42309
|
+
const lines = [`Fix the following ${findings.length} failing test${findings.length === 1 ? "" : "s"}:
|
|
42310
|
+
`];
|
|
42311
|
+
for (const f of findings) {
|
|
42312
|
+
const location = f.file ? `${f.file}` : "(unknown file)";
|
|
42313
|
+
const rule = f.rule ? ` Test: ${f.rule}
|
|
42314
|
+
` : "";
|
|
42315
|
+
lines.push(`- ${location}
|
|
42316
|
+
${rule} Error: ${f.message}
|
|
42317
|
+
`);
|
|
42318
|
+
}
|
|
42319
|
+
return lines.join(`
|
|
42320
|
+
`);
|
|
42321
|
+
}
|
|
42250
42322
|
function mechanicalRectification(checks3, story, scopeConstraint, opts) {
|
|
42251
42323
|
const errors3 = formatCheckErrors(checks3, opts);
|
|
42252
42324
|
const scopeDirective = implementerOwnsTests(story) ? `Fix all errors listed above that are within this story's scope. ${SINGLE_SESSION_PERMIT_HEADLINE}` : `Fix all errors listed above that are within this story's scope \u2014 see the ${exceptionCountWord(story)} narrow exceptions appended below for sibling-story spillover. Do NOT change test files or test behavior except via those exceptions.`;
|
|
@@ -42931,22 +43003,23 @@ Before editing, break the work into one small fix per finding above (fix -> re-r
|
|
|
42931
43003
|
`);
|
|
42932
43004
|
}
|
|
42933
43005
|
static failingTestContext(findings) {
|
|
42934
|
-
|
|
42935
|
-
|
|
42936
|
-
|
|
42937
|
-
|
|
42938
|
-
|
|
42939
|
-
|
|
42940
|
-
|
|
42941
|
-
|
|
42942
|
-
|
|
42943
|
-
|
|
42944
|
-
|
|
42945
|
-
`
|
|
42946
|
-
|
|
42947
|
-
|
|
42948
|
-
|
|
42949
|
-
|
|
43006
|
+
const listing = formatFailingTestsList(findings);
|
|
43007
|
+
if (findings.length === 0)
|
|
43008
|
+
return listing;
|
|
43009
|
+
return `${listing}
|
|
43010
|
+
Fix the implementation (not the tests) to make all failing tests pass. Run the test suite to verify after each change.`;
|
|
43011
|
+
}
|
|
43012
|
+
static failingTestRectification(findings, story) {
|
|
43013
|
+
const listing = formatFailingTestsList(findings);
|
|
43014
|
+
const exCount = exceptionCountWord(story);
|
|
43015
|
+
const prohibition = `Do NOT change test files or test behavior \u2014 see the ${exCount} narrow exceptions appended below.`;
|
|
43016
|
+
const parts = [listing];
|
|
43017
|
+
parts.push(`
|
|
43018
|
+
Fix the implementation (not the tests) to make all failing tests pass. Do not loosen assertions or weaken test expectations. Run the test suite to verify after each change.`);
|
|
43019
|
+
parts.push(`
|
|
43020
|
+
${testEditHeadline(story, prohibition)}`);
|
|
43021
|
+
parts.push(escapeHatchFor(story));
|
|
43022
|
+
return parts.join(`
|
|
42950
43023
|
`);
|
|
42951
43024
|
}
|
|
42952
43025
|
}
|
|
@@ -43218,7 +43291,13 @@ For each one:
|
|
|
43218
43291
|
Write the corrected PRD to this file path: ${outputFilePath}
|
|
43219
43292
|
Do not output the PRD in chat. After writing the file, reply with a brief text confirmation only.`;
|
|
43220
43293
|
}
|
|
43221
|
-
build(specContent, codebaseContext, outputFilePath, packages, packageDetails, projectProfile, proposers) {
|
|
43294
|
+
build(specContent, codebaseContext, outputFilePath, packages, packageDetails, projectProfile, proposers, profiles) {
|
|
43295
|
+
const cards = OneShotPromptBuilder.agentCapabilityCards(profiles ?? []);
|
|
43296
|
+
const agentProfilesSection = cards.length > 0 ? `
|
|
43297
|
+
|
|
43298
|
+
${cards}
|
|
43299
|
+
|
|
43300
|
+
${OneShotPromptBuilder.agentProfileInstruction()}` : "";
|
|
43222
43301
|
const isMonorepo = packages && packages.length > 0;
|
|
43223
43302
|
const packageDetailsSection = packageDetails && packageDetails.length > 0 ? buildPackageDetailsSection(packageDetails) : "";
|
|
43224
43303
|
const monorepoHint = isMonorepo ? `
|
|
@@ -43273,7 +43352,7 @@ ${buildSharedQualityRules(specContent, projectProfile)}
|
|
|
43273
43352
|
|
|
43274
43353
|
For each story, set "contextFiles" to the key source files the agent should read before implementing (max 5 per story). Use your Step 2 analysis to identify the most relevant files. Leave empty for greenfield stories with no existing files to reference. Set "expectedFiles" to the NEW files the story creates.
|
|
43275
43354
|
|
|
43276
|
-
${CONTEXT_VS_EXPECTED_FILES_RULE}`;
|
|
43355
|
+
${CONTEXT_VS_EXPECTED_FILES_RULE}${agentProfilesSection}`;
|
|
43277
43356
|
const suggestedCriteriaField = specContent.trim() ? `
|
|
43278
43357
|
"suggestedCriteria": ["string \u2014 optional. Behavioral edge cases or negative paths you identified that are NOT in the spec. Plain assertions only \u2014 observable outputs, return values, state changes, or error conditions. No implementation details or vague descriptions. Omit this field if empty."],` : "";
|
|
43279
43358
|
const outputDirective = outputFilePath ? `Write the PRD JSON directly to this file path: ${outputFilePath}
|
|
@@ -43305,7 +43384,8 @@ Generate a JSON object with this exact structure (no markdown, no explanation \u
|
|
|
43305
43384
|
"complexity": "simple | medium | complex | expert",
|
|
43306
43385
|
"testStrategy": "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
|
|
43307
43386
|
"noTestJustification": "string \u2014 REQUIRED when testStrategy is no-test, explains why tests are unnecessary",
|
|
43308
|
-
"reasoning": "string \u2014 brief classification rationale"
|
|
43387
|
+
"reasoning": "string \u2014 brief classification rationale"${cards.length > 0 ? `,
|
|
43388
|
+
"agentProfileId": "string \u2014 optional, the id of the best-matching profile from the Agent Profiles table above; omit if none fits"` : ""}
|
|
43309
43389
|
},
|
|
43310
43390
|
"escalations": [],
|
|
43311
43391
|
"attempts": 0
|
|
@@ -43322,6 +43402,12 @@ ${outputDirective}`;
|
|
|
43322
43402
|
content: "You are a senior software architect generating a product requirements document (PRD) as JSON. Your intent is to produce a thorough, evidence-grounded plan.",
|
|
43323
43403
|
overridable: false
|
|
43324
43404
|
};
|
|
43405
|
+
const cards = OneShotPromptBuilder.agentCapabilityCards(input.profiles ?? []);
|
|
43406
|
+
const agentProfilesSection = cards.length > 0 ? `
|
|
43407
|
+
|
|
43408
|
+
${cards}
|
|
43409
|
+
|
|
43410
|
+
${OneShotPromptBuilder.agentProfileInstruction()}` : "";
|
|
43325
43411
|
const revisionSection = input.revisionFindings && input.revisionFindings.length > 0 ? `
|
|
43326
43412
|
|
|
43327
43413
|
## Previous draft rejected for the following issues
|
|
@@ -43371,7 +43457,7 @@ ${buildSharedQualityRules(input.specContent, input.projectProfile)}
|
|
|
43371
43457
|
|
|
43372
43458
|
For each story, set "contextFiles" to the key source files the implementer should read before starting (max 5 per story). Cite manifest factIds where relevant. Set "expectedFiles" to the NEW files the story creates.
|
|
43373
43459
|
|
|
43374
|
-
${CONTEXT_VS_EXPECTED_FILES_RULE}
|
|
43460
|
+
${CONTEXT_VS_EXPECTED_FILES_RULE}${agentProfilesSection}
|
|
43375
43461
|
|
|
43376
43462
|
## Output Schema
|
|
43377
43463
|
|
|
@@ -43394,7 +43480,8 @@ Produce a JSON object with this exact structure. Field names are mandatory \u201
|
|
|
43394
43480
|
"routing": {
|
|
43395
43481
|
"complexity": "simple | medium | complex | expert",
|
|
43396
43482
|
"testStrategy": "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
|
|
43397
|
-
"reasoning": "string \u2014 brief classification rationale"
|
|
43483
|
+
"reasoning": "string \u2014 brief classification rationale"${cards.length > 0 ? `,
|
|
43484
|
+
"agentProfileId": "string \u2014 optional, the id of the best-matching profile from the Agent Profiles table above; omit if none fits"` : ""}
|
|
43398
43485
|
}
|
|
43399
43486
|
}
|
|
43400
43487
|
]
|
|
@@ -43434,6 +43521,7 @@ var CONTEXT_VS_EXPECTED_FILES_RULE = `**\`contextFiles\` rule \u2014 files reada
|
|
|
43434
43521
|
**\`expectedFiles\` rule \u2014 files THIS story CREATES.** List every NEW file this story authors (relative paths). A file this story creates belongs here, NEVER in \`contextFiles\` \u2014 these are the story's outputs, not files to read first. A file created by an upstream dependency and only read/modified here belongs in \`contextFiles\`, NOT here (this story does not author it). A single path may appear in \`contextFiles\` (an existing sibling to mirror) AND \`expectedFiles\` (the new file itself), but the same path must never be in both.`, EXPECTED_FILES_SCHEMA_FIELD = `"expectedFiles": ["string \u2014 NEW files this story creates (relative paths, omit if none)"],`;
|
|
43435
43522
|
var init_plan_builder = __esm(() => {
|
|
43436
43523
|
init_config();
|
|
43524
|
+
init_one_shot_builder();
|
|
43437
43525
|
});
|
|
43438
43526
|
|
|
43439
43527
|
// src/prompts/builders/grounder-builder.ts
|
|
@@ -44645,11 +44733,22 @@ function buildTxtContent(entry) {
|
|
|
44645
44733
|
"",
|
|
44646
44734
|
"=== RESPONSE ===",
|
|
44647
44735
|
"",
|
|
44648
|
-
entry.response
|
|
44736
|
+
entry.response,
|
|
44737
|
+
...buildInteractionLines(entry.interactions)
|
|
44649
44738
|
];
|
|
44650
44739
|
return lines.join(`
|
|
44651
44740
|
`);
|
|
44652
44741
|
}
|
|
44742
|
+
function buildInteractionLines(interactions) {
|
|
44743
|
+
if (!interactions?.length)
|
|
44744
|
+
return [];
|
|
44745
|
+
const lines = ["", "=== INTERACTIONS ===", ""];
|
|
44746
|
+
for (const ix of interactions) {
|
|
44747
|
+
lines.push(`[turn ${ix.turnIndex}] Q: ${ix.question}`, ` A: ${ix.reply}`, "");
|
|
44748
|
+
}
|
|
44749
|
+
lines.pop();
|
|
44750
|
+
return lines;
|
|
44751
|
+
}
|
|
44653
44752
|
|
|
44654
44753
|
class PromptAuditor {
|
|
44655
44754
|
_queue = Promise.resolve();
|
|
@@ -45158,7 +45257,8 @@ function attachAuditSubscriber(bus, auditor, runId) {
|
|
|
45158
45257
|
...event.kind === "session-turn" && {
|
|
45159
45258
|
sessionId: event.protocolIds.sessionId ?? null,
|
|
45160
45259
|
recordId: event.protocolIds.recordId ?? null,
|
|
45161
|
-
turn: event.turn
|
|
45260
|
+
turn: event.turn,
|
|
45261
|
+
...event.interactions?.length ? { interactions: event.interactions } : {}
|
|
45162
45262
|
}
|
|
45163
45263
|
};
|
|
45164
45264
|
auditor.record(entry);
|
|
@@ -51771,7 +51871,7 @@ var init_precheck = __esm(() => {
|
|
|
51771
51871
|
});
|
|
51772
51872
|
|
|
51773
51873
|
// src/prd/decompose-mapper.ts
|
|
51774
|
-
function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir) {
|
|
51874
|
+
function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir, parentRouting) {
|
|
51775
51875
|
return stories.map((story, entryIndex) => {
|
|
51776
51876
|
if (!story.id) {
|
|
51777
51877
|
throw new NaxError(`Entry at index ${entryIndex} is missing required field: id`, "DECOMPOSE_VALIDATION_FAILED", {
|
|
@@ -51805,10 +51905,19 @@ function mapDecomposedStoriesToUserStories(stories, parentStoryId, parentWorkdir
|
|
|
51805
51905
|
complexity: story.complexity,
|
|
51806
51906
|
testStrategy: story.testStrategy ?? "test-after",
|
|
51807
51907
|
reasoning: story.reasoning,
|
|
51808
|
-
modelTier: story.routing?.profileModelTier ?? "balanced",
|
|
51908
|
+
modelTier: parentRouting?.profileModelTier ?? story.routing?.profileModelTier ?? "balanced",
|
|
51809
51909
|
...story.routing?.agent !== undefined && { agent: story.routing.agent },
|
|
51810
51910
|
...story.routing?.agentProfileId !== undefined && { agentProfileId: story.routing.agentProfileId },
|
|
51811
|
-
...story.routing?.profileModelTier !== undefined && { profileModelTier: story.routing.profileModelTier }
|
|
51911
|
+
...story.routing?.profileModelTier !== undefined && { profileModelTier: story.routing.profileModelTier },
|
|
51912
|
+
...parentRouting?.agent !== undefined && { agent: parentRouting.agent },
|
|
51913
|
+
...parentRouting?.agentProfileId !== undefined && { agentProfileId: parentRouting.agentProfileId },
|
|
51914
|
+
...parentRouting?.profileModelTier !== undefined && { profileModelTier: parentRouting.profileModelTier },
|
|
51915
|
+
...parentRouting?.agent !== undefined && {
|
|
51916
|
+
initialAgent: parentRouting.initialAgent ?? parentRouting.agent
|
|
51917
|
+
},
|
|
51918
|
+
...parentRouting?.agentProfileId !== undefined && {
|
|
51919
|
+
initialProfileId: parentRouting.initialProfileId ?? parentRouting.agentProfileId
|
|
51920
|
+
}
|
|
51812
51921
|
}
|
|
51813
51922
|
};
|
|
51814
51923
|
});
|
|
@@ -51874,8 +51983,7 @@ async function planDecomposeCommand(workdir, config2, options) {
|
|
|
51874
51983
|
for (let attempt = 0;attempt < maxReplanAttempts; attempt++) {
|
|
51875
51984
|
if (attempt === 0 && debateDecompEnabled) {
|
|
51876
51985
|
const decomposeStageConfig = debateStages.decompose;
|
|
51877
|
-
const
|
|
51878
|
-
const profilesForDebate = agentRoutingForDebate?.enabled === true ? agentRoutingForDebate.profiles ?? [] : [];
|
|
51986
|
+
const profilesForDebate = [];
|
|
51879
51987
|
const prompt = await buildDecomposePromptAsync({
|
|
51880
51988
|
specContent: "",
|
|
51881
51989
|
codebaseContext,
|
|
@@ -51950,7 +52058,7 @@ ${repairHint}` : codebaseContext;
|
|
|
51950
52058
|
} finally {
|
|
51951
52059
|
await rt.close().catch(() => {});
|
|
51952
52060
|
}
|
|
51953
|
-
const subStoriesWithParent = mapDecomposedStoriesToUserStories(decompStories, options.storyId, targetStory.workdir);
|
|
52061
|
+
const subStoriesWithParent = mapDecomposedStoriesToUserStories(decompStories, options.storyId, targetStory.workdir, targetStory.routing);
|
|
51954
52062
|
const updatedStories = prd.userStories.map((s) => s.id === options.storyId ? { ...s, status: "decomposed" } : s);
|
|
51955
52063
|
const originalIndex = updatedStories.findIndex((s) => s.id === options.storyId);
|
|
51956
52064
|
const finalStories = [
|
|
@@ -52912,15 +53020,28 @@ async function processPackageGroup(ctx, packageDir, groupStories, language, resu
|
|
|
52912
53020
|
featureName: ctx.prd.feature,
|
|
52913
53021
|
agentName: ctx.agentManager.getDefault()
|
|
52914
53022
|
};
|
|
52915
|
-
|
|
52916
|
-
|
|
52917
|
-
|
|
52918
|
-
|
|
52919
|
-
|
|
52920
|
-
|
|
52921
|
-
|
|
52922
|
-
|
|
52923
|
-
|
|
53023
|
+
let refined;
|
|
53024
|
+
try {
|
|
53025
|
+
refined = await _hardeningDeps.callOp(callCtx, acceptanceRefineOp, {
|
|
53026
|
+
criteria: story.suggestedCriteria ?? [],
|
|
53027
|
+
codebaseContext: "",
|
|
53028
|
+
storyId: story.id,
|
|
53029
|
+
testStrategy: ctx.config.acceptance?.testStrategy,
|
|
53030
|
+
testFramework: ctx.config.acceptance?.testFramework,
|
|
53031
|
+
storyTitle: story.title,
|
|
53032
|
+
storyDescription: story.description
|
|
53033
|
+
});
|
|
53034
|
+
} catch {
|
|
53035
|
+
logger?.warn("acceptance", "AC refinement failed after retries \u2014 using unrefined criteria", {
|
|
53036
|
+
storyId: story.id
|
|
53037
|
+
});
|
|
53038
|
+
refined = (story.suggestedCriteria ?? []).map((c) => ({
|
|
53039
|
+
original: c,
|
|
53040
|
+
refined: c,
|
|
53041
|
+
testable: true,
|
|
53042
|
+
storyId: story.id
|
|
53043
|
+
}));
|
|
53044
|
+
}
|
|
52924
53045
|
groupRefined.push(...refined);
|
|
52925
53046
|
}
|
|
52926
53047
|
const suggestedTestPath = resolveSuggestedPackageFeatureTestPath(packageDir, ctx.prd.feature, ctx.config.acceptance?.suggestedTestPath, language);
|
|
@@ -53066,6 +53187,7 @@ __export(exports_acceptance, {
|
|
|
53066
53187
|
resolveSuggestedTestFile: () => resolveSuggestedTestFile,
|
|
53067
53188
|
resolveSuggestedPackageFeatureTestPath: () => resolveSuggestedPackageFeatureTestPath,
|
|
53068
53189
|
resolveAcceptanceFeatureTestPath: () => resolveAcceptanceFeatureTestPath,
|
|
53190
|
+
refinementWouldFallback: () => refinementWouldFallback,
|
|
53069
53191
|
parseRefinementResponse: () => parseRefinementResponse,
|
|
53070
53192
|
parseAcceptanceCriteria: () => parseAcceptanceCriteria,
|
|
53071
53193
|
parseACTextFromSpec: () => parseACTextFromSpec,
|
|
@@ -53480,6 +53602,16 @@ ${stderr}` };
|
|
|
53480
53602
|
storyDescription: story.description
|
|
53481
53603
|
}, story.id).then((refined) => {
|
|
53482
53604
|
results[i] = refined;
|
|
53605
|
+
}).catch(() => {
|
|
53606
|
+
getSafeLogger()?.warn("acceptance-setup", "AC refinement failed after retries \u2014 using unrefined criteria", {
|
|
53607
|
+
storyId: story.id
|
|
53608
|
+
});
|
|
53609
|
+
results[i] = story.acceptanceCriteria.map((c) => ({
|
|
53610
|
+
original: c,
|
|
53611
|
+
refined: c,
|
|
53612
|
+
testable: true,
|
|
53613
|
+
storyId: story.id
|
|
53614
|
+
}));
|
|
53483
53615
|
}).finally(() => {
|
|
53484
53616
|
executing.delete(task);
|
|
53485
53617
|
});
|
|
@@ -55039,7 +55171,8 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides)
|
|
|
55039
55171
|
break;
|
|
55040
55172
|
}
|
|
55041
55173
|
}
|
|
55042
|
-
const
|
|
55174
|
+
const postValidateFn = overrides?.postValidate ?? rectification.postValidate;
|
|
55175
|
+
const validated = postValidateFn ? await postValidateFn(findings, _validateCtx) : findings;
|
|
55043
55176
|
return { findings: validated, shortCircuited };
|
|
55044
55177
|
}
|
|
55045
55178
|
};
|
|
@@ -55209,7 +55342,8 @@ class ExecutionPlan {
|
|
|
55209
55342
|
strategies: this.state.nonBlockingFixStrategies ?? [],
|
|
55210
55343
|
excludePhaseKinds: nonBlockingExcludePhases(),
|
|
55211
55344
|
extraRevalidationKinds: nonBlockingExtraPhases(advCfg),
|
|
55212
|
-
maxAttempts
|
|
55345
|
+
maxAttempts,
|
|
55346
|
+
postValidate: this.state.nonBlockingFixPostValidate
|
|
55213
55347
|
})
|
|
55214
55348
|
});
|
|
55215
55349
|
}
|
|
@@ -55305,9 +55439,10 @@ class StoryOrchestratorBuilder {
|
|
|
55305
55439
|
this.state.rectification = opts;
|
|
55306
55440
|
return this;
|
|
55307
55441
|
}
|
|
55308
|
-
addNonBlockingFix(cfg, strategies) {
|
|
55442
|
+
addNonBlockingFix(cfg, strategies, postValidate) {
|
|
55309
55443
|
this.state.nonBlockingFix = cfg;
|
|
55310
55444
|
this.state.nonBlockingFixStrategies = strategies;
|
|
55445
|
+
this.state.nonBlockingFixPostValidate = postValidate;
|
|
55311
55446
|
return this;
|
|
55312
55447
|
}
|
|
55313
55448
|
build(ctx, opts = {}) {
|
|
@@ -55437,10 +55572,10 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55437
55572
|
if (inputs.adversarialReview) {
|
|
55438
55573
|
builder.addAdversarialReview(inputs.adversarialReview);
|
|
55439
55574
|
}
|
|
55575
|
+
const packageDir = join47(ctx.packageDir, story.workdir ?? "");
|
|
55576
|
+
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.packageDir, story.workdir);
|
|
55440
55577
|
if (shouldRunRectification(config2) && inputs.rectification) {
|
|
55441
55578
|
const sink = makeDeclarationSink();
|
|
55442
|
-
const packageDir = join47(ctx.packageDir, story.workdir ?? "");
|
|
55443
|
-
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.packageDir, story.workdir);
|
|
55444
55579
|
const strategies = [];
|
|
55445
55580
|
const pkgQuality = ctx.packageView.select(qualityConfigSelector).quality;
|
|
55446
55581
|
if (pkgQuality?.commands?.lintFix || pkgQuality?.commands?.lintFixScoped) {
|
|
@@ -55450,7 +55585,7 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55450
55585
|
strategies.push(makeMechanicalFormatFixStrategy());
|
|
55451
55586
|
}
|
|
55452
55587
|
if (inputs.fullSuiteGate && (isThreeSession || regressionMode === "per-story")) {
|
|
55453
|
-
strategies.push(makeFullSuiteRectifyStrategy(story, config2));
|
|
55588
|
+
strategies.push(makeFullSuiteRectifyStrategy(story, config2, sink));
|
|
55454
55589
|
}
|
|
55455
55590
|
if (config2.quality.autofix?.enabled !== false) {
|
|
55456
55591
|
strategies.push(makeAutofixImplementerStrategy(story, config2, sink, {
|
|
@@ -55495,8 +55630,23 @@ async function buildPlanForStrategy(ctx, story, config2, testStrategy, inputs) {
|
|
|
55495
55630
|
includeAdversarialReview: false
|
|
55496
55631
|
}), makeAutofixTestWriterStrategy(story, config2, nbSink));
|
|
55497
55632
|
}
|
|
55498
|
-
nbStrategies.push(makeFullSuiteRectifyStrategy(story, config2));
|
|
55499
|
-
|
|
55633
|
+
nbStrategies.push(makeFullSuiteRectifyStrategy(story, config2, nbSink));
|
|
55634
|
+
const nbPostValidate = async (findings, _validateCtx) => {
|
|
55635
|
+
if (nbSink.testEdits.length === 0 && nbSink.mockHandoffs.length === 0)
|
|
55636
|
+
return findings;
|
|
55637
|
+
const pendingMock = nbSink.mockHandoffs.map((h) => ({
|
|
55638
|
+
reason: "mock_structure",
|
|
55639
|
+
file: h.files[0] ?? "",
|
|
55640
|
+
files: h.files,
|
|
55641
|
+
reasonDetail: h.reasonDetail
|
|
55642
|
+
}));
|
|
55643
|
+
const { valid, invalid } = await validateMockStructureFiles(pendingMock, resolvedTestPatterns, packageDir);
|
|
55644
|
+
nbSink.mockHandoffs = valid.map((d) => ({ files: d.files ?? [], reasonDetail: d.reasonDetail ?? "" }));
|
|
55645
|
+
const allDeclarations = [...nbSink.testEdits, ...valid];
|
|
55646
|
+
nbSink.testEdits = [];
|
|
55647
|
+
return applyTestEditDeclarations(findings, allDeclarations, story, invalid);
|
|
55648
|
+
};
|
|
55649
|
+
builder.addNonBlockingFix(nbf, nbStrategies, nbPostValidate);
|
|
55500
55650
|
}
|
|
55501
55651
|
return builder.build(ctx, { isThreeSession });
|
|
55502
55652
|
}
|
|
@@ -60095,7 +60245,7 @@ var package_default;
|
|
|
60095
60245
|
var init_package = __esm(() => {
|
|
60096
60246
|
package_default = {
|
|
60097
60247
|
name: "@nathapp/nax",
|
|
60098
|
-
version: "0.70.0-canary.
|
|
60248
|
+
version: "0.70.0-canary.3",
|
|
60099
60249
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
60100
60250
|
type: "module",
|
|
60101
60251
|
bin: {
|
|
@@ -60190,8 +60340,8 @@ var init_version = __esm(() => {
|
|
|
60190
60340
|
NAX_VERSION = package_default.version;
|
|
60191
60341
|
NAX_COMMIT = (() => {
|
|
60192
60342
|
try {
|
|
60193
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
60194
|
-
return "
|
|
60343
|
+
if (/^[0-9a-f]{6,10}$/.test("905b80cf"))
|
|
60344
|
+
return "905b80cf";
|
|
60195
60345
|
} catch {}
|
|
60196
60346
|
try {
|
|
60197
60347
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -95450,6 +95600,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95450
95600
|
const branchName = options.branch ?? `feat/${options.feature}`;
|
|
95451
95601
|
const timeoutSeconds = fullConfig?.plan?.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS2;
|
|
95452
95602
|
const config2 = planConfigSelector.select(fullConfig);
|
|
95603
|
+
const profileName = typeof fullConfig?.profile === "string" && fullConfig.profile ? fullConfig.profile : undefined;
|
|
95453
95604
|
const runtime = createPlanRuntime(fullConfig, workdir, options.feature);
|
|
95454
95605
|
const interactionChain = fullConfig ? await deps.initInteractionChain(fullConfig, !process.stdin.isTTY) : null;
|
|
95455
95606
|
let configuredBridge;
|
|
@@ -95477,6 +95628,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
95477
95628
|
branchName,
|
|
95478
95629
|
timeoutSeconds,
|
|
95479
95630
|
config: config2,
|
|
95631
|
+
profileName,
|
|
95480
95632
|
options,
|
|
95481
95633
|
runtime,
|
|
95482
95634
|
interactionChain,
|
|
@@ -95525,6 +95677,28 @@ function buildPlanComposition(userStageConfig) {
|
|
|
95525
95677
|
// src/plan/strategies/write-prd.ts
|
|
95526
95678
|
init_errors();
|
|
95527
95679
|
init_prd();
|
|
95680
|
+
|
|
95681
|
+
// src/plan/strategies/finalize-routing.ts
|
|
95682
|
+
init_agents();
|
|
95683
|
+
function finalizePrdRouting(prd, agentRouting, profileName) {
|
|
95684
|
+
const userStories = prd.userStories.map((story) => {
|
|
95685
|
+
const assignment = resolveAgentAssignment(story.routing?.agentProfileId, agentRouting, story.id);
|
|
95686
|
+
if (!assignment)
|
|
95687
|
+
return story;
|
|
95688
|
+
const routing = {
|
|
95689
|
+
...story.routing,
|
|
95690
|
+
agent: assignment.agent,
|
|
95691
|
+
agentProfileId: assignment.agentProfileId,
|
|
95692
|
+
profileModelTier: assignment.profileModelTier,
|
|
95693
|
+
initialAgent: story.routing?.initialAgent ?? assignment.agent,
|
|
95694
|
+
initialProfileId: story.routing?.initialProfileId ?? assignment.agentProfileId
|
|
95695
|
+
};
|
|
95696
|
+
return { ...story, routing };
|
|
95697
|
+
});
|
|
95698
|
+
return { ...prd, userStories, routingProfile: profileName ?? "default" };
|
|
95699
|
+
}
|
|
95700
|
+
|
|
95701
|
+
// src/plan/strategies/write-prd.ts
|
|
95528
95702
|
async function writeOrRecoverPrd(ctx, prd, err) {
|
|
95529
95703
|
const tryExtractPrd = (value) => {
|
|
95530
95704
|
if (value === null || typeof value !== "object")
|
|
@@ -95543,12 +95717,14 @@ async function writeOrRecoverPrd(ctx, prd, err) {
|
|
|
95543
95717
|
};
|
|
95544
95718
|
if (prd !== null) {
|
|
95545
95719
|
if (Array.isArray(prd.userStories)) {
|
|
95546
|
-
|
|
95720
|
+
const finalized = finalizePrdRouting({ ...prd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
|
|
95721
|
+
await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
|
|
95547
95722
|
return ctx.outputPath;
|
|
95548
95723
|
}
|
|
95549
95724
|
const normalizedPrd = tryExtractPrd(prd);
|
|
95550
95725
|
if (normalizedPrd !== null) {
|
|
95551
|
-
|
|
95726
|
+
const finalized = finalizePrdRouting({ ...normalizedPrd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
|
|
95727
|
+
await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
|
|
95552
95728
|
return ctx.outputPath;
|
|
95553
95729
|
}
|
|
95554
95730
|
}
|
|
@@ -95568,7 +95744,8 @@ async function writeOrRecoverPrd(ctx, prd, err) {
|
|
|
95568
95744
|
}
|
|
95569
95745
|
}
|
|
95570
95746
|
recoveredPrd = recoveredPrd ?? validatePlanOutput(rawContent, ctx.options.feature, ctx.branchName);
|
|
95571
|
-
|
|
95747
|
+
const finalized = finalizePrdRouting({ ...recoveredPrd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
|
|
95748
|
+
await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
|
|
95572
95749
|
return ctx.outputPath;
|
|
95573
95750
|
} catch {
|
|
95574
95751
|
throw err;
|
|
@@ -95587,7 +95764,9 @@ var _debatePlanDeps = {
|
|
|
95587
95764
|
class DebatePlanStrategy {
|
|
95588
95765
|
mode = "debate";
|
|
95589
95766
|
async execute(ctx) {
|
|
95590
|
-
const
|
|
95767
|
+
const agentRouting = ctx.config.routing?.agents;
|
|
95768
|
+
const profiles = agentRouting?.enabled === true ? agentRouting.profiles ?? [] : [];
|
|
95769
|
+
const { taskContext, outputFormat } = new PlanPromptBuilder().build(ctx.specContent, ctx.codebaseContext, undefined, ctx.relativePackages, ctx.packageDetails, ctx.config.project, undefined, profiles);
|
|
95591
95770
|
const planStage = ctx.config.debate?.stages?.plan;
|
|
95592
95771
|
if (!planStage) {
|
|
95593
95772
|
throw new NaxError("[plan] debate strategy requires config.debate.stages.plan", "PLAN_DEBATE_STAGE_CONFIG_MISSING", {
|
|
@@ -95723,7 +95902,8 @@ class PipelinePlanStrategy {
|
|
|
95723
95902
|
if (verdict.outcome !== "passed") {
|
|
95724
95903
|
throw new NaxError(verdict.specDeltasPath ? `Plan pipeline failed; see ${verdict.specDeltasPath}` : "Plan pipeline failed with no spec-deltas path", "PLAN_CRITIC_BLOCKED", { stage: "plan", specDeltasPath: verdict.specDeltasPath });
|
|
95725
95904
|
}
|
|
95726
|
-
|
|
95905
|
+
const prdToWrite = finalizePrdRouting({ ...verdict.prd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
|
|
95906
|
+
await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(prdToWrite, null, 2));
|
|
95727
95907
|
return ctx.outputPath;
|
|
95728
95908
|
} finally {
|
|
95729
95909
|
await ctx.runtime.close().catch(() => {});
|
|
@@ -95804,13 +95984,15 @@ class SinglePlanStrategy {
|
|
|
95804
95984
|
projectProfile: ctx.config.project
|
|
95805
95985
|
});
|
|
95806
95986
|
assertIsValidPrd(prd);
|
|
95807
|
-
|
|
95987
|
+
const finalized = finalizePrdRouting({ ...prd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
|
|
95988
|
+
await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalized, null, 2));
|
|
95808
95989
|
return ctx.outputPath;
|
|
95809
95990
|
} catch (err) {
|
|
95810
95991
|
if (ctx.deps.existsSync(ctx.outputPath)) {
|
|
95811
95992
|
const rawContent = await ctx.deps.readFile(ctx.outputPath);
|
|
95812
95993
|
const recoveredPrd = validatePlanOutput(rawContent, ctx.options.feature, ctx.branchName);
|
|
95813
|
-
|
|
95994
|
+
const finalizedRecovered = finalizePrdRouting({ ...recoveredPrd, project: ctx.projectName }, ctx.config.routing?.agents, ctx.profileName);
|
|
95995
|
+
await ctx.deps.writeFile(ctx.outputPath, JSON.stringify(finalizedRecovered, null, 2));
|
|
95814
95996
|
return ctx.outputPath;
|
|
95815
95997
|
}
|
|
95816
95998
|
throw err;
|
|
@@ -96856,6 +97038,7 @@ var FIELD_DESCRIPTIONS = {
|
|
|
96856
97038
|
"acceptance.testPath": "Path to acceptance test file (relative to feature dir)",
|
|
96857
97039
|
"acceptance.command": "Override command to run acceptance tests. Use {{FILE}} as placeholder for the test file path (default: 'bun test {{FILE}} --timeout=60000')",
|
|
96858
97040
|
"acceptance.model": 'Model selector for acceptance generation/refinement LLM calls. Accepts a tier string such as "fast", "balanced", or "powerful", or an explicit object like { agent: "codex", model: "gpt-5.4" }. Default: "fast".',
|
|
97041
|
+
"acceptance.generateModel": 'Model selector specifically for acceptance test generation and criteria refinement LLM calls. When set, overrides acceptance.model for these two operations. Accepts a tier string such as "fast", "balanced", or "powerful", or an explicit object like { agent: "opencode", model: "opencode-go/deepseek-v4-flash" }. Defaults to acceptance.model when not set.',
|
|
96859
97042
|
"acceptance.refinement": "Enable acceptance criteria refinement step before execution (default: true). Disable to skip refinement and use generated criteria as-is.",
|
|
96860
97043
|
"acceptance.timeoutMs": "Timeout for acceptance test generation in milliseconds (default: 1800000 = 30 min)",
|
|
96861
97044
|
context: "Context injection configuration",
|