@nathapp/nax 0.70.3 → 0.70.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 +432 -287
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -18185,7 +18185,8 @@ class Logger {
|
|
|
18185
18185
|
mkdirSync(dir, { recursive: true });
|
|
18186
18186
|
}
|
|
18187
18187
|
} catch (error48) {
|
|
18188
|
-
|
|
18188
|
+
process.stderr.write(`[logger] Failed to create log directory: ${error48}
|
|
18189
|
+
`);
|
|
18189
18190
|
}
|
|
18190
18191
|
}
|
|
18191
18192
|
shouldLog(level) {
|
|
@@ -18254,7 +18255,8 @@ ${JSON.stringify(entry.data, null, 2)}`;
|
|
|
18254
18255
|
`;
|
|
18255
18256
|
const filePath = this.filePath;
|
|
18256
18257
|
this.writeQueueTail = this.writeQueueTail.then(() => appendFile(filePath, line).catch((error48) => {
|
|
18257
|
-
|
|
18258
|
+
process.stderr.write(`[logger] Failed to write to log file: ${error48}
|
|
18259
|
+
`);
|
|
18258
18260
|
}));
|
|
18259
18261
|
}
|
|
18260
18262
|
async flush() {
|
|
@@ -20898,7 +20900,7 @@ class AcpAgentAdapter {
|
|
|
20898
20900
|
session = await client.createSession({ agentName, permissionMode, sessionName: completeSessionName });
|
|
20899
20901
|
let timeoutId;
|
|
20900
20902
|
const timeoutPromise = new Promise((_, reject) => {
|
|
20901
|
-
timeoutId = setTimeout(() => reject(new
|
|
20903
|
+
timeoutId = setTimeout(() => reject(new NaxError("complete() timed out", "AGENT_TIMEOUT", { stage: "acp", timeoutMs })), timeoutMs);
|
|
20902
20904
|
});
|
|
20903
20905
|
timeoutPromise.catch(() => {});
|
|
20904
20906
|
let response;
|
|
@@ -21226,6 +21228,7 @@ class AcpAgentAdapter {
|
|
|
21226
21228
|
}
|
|
21227
21229
|
var MAX_AGENT_OUTPUT_CHARS = 5000, INTERACTION_TIMEOUT_MS, AGENT_REGISTRY, DEFAULT_ENTRY;
|
|
21228
21230
|
var init_adapter = __esm(() => {
|
|
21231
|
+
init_errors();
|
|
21229
21232
|
init_logger2();
|
|
21230
21233
|
init_cost();
|
|
21231
21234
|
init_types3();
|
|
@@ -24689,26 +24692,79 @@ function parsePytestOutput(output) {
|
|
|
24689
24692
|
});
|
|
24690
24693
|
}
|
|
24691
24694
|
}
|
|
24695
|
+
const verboseStacks = parsePytestVerboseStacks(output);
|
|
24696
|
+
for (const failure of failures) {
|
|
24697
|
+
const leafName = failure.testName.split(" > ").pop() ?? failure.testName;
|
|
24698
|
+
const stack = verboseStacks.get(leafName) ?? verboseStacks.get(failure.testName) ?? verboseStacks.get(failure.testName.replace(/ > /g, "."));
|
|
24699
|
+
if (stack && stack.length > 0) {
|
|
24700
|
+
failure.stackTrace = stack;
|
|
24701
|
+
}
|
|
24702
|
+
}
|
|
24692
24703
|
return {
|
|
24693
24704
|
passed: common.passed,
|
|
24694
24705
|
failed: common.failed,
|
|
24695
24706
|
failures: failures.length > 0 ? failures : common.failures
|
|
24696
24707
|
};
|
|
24697
24708
|
}
|
|
24709
|
+
function parsePytestVerboseStacks(output) {
|
|
24710
|
+
const result = new Map;
|
|
24711
|
+
const failuresIdx = output.indexOf("FAILURES");
|
|
24712
|
+
if (failuresIdx === -1)
|
|
24713
|
+
return result;
|
|
24714
|
+
let currentTest = null;
|
|
24715
|
+
for (const line of output.slice(failuresIdx).split(`
|
|
24716
|
+
`)) {
|
|
24717
|
+
const headerMatch = line.match(/^_{4,}\s+(.+?)\s+_{4,}$/);
|
|
24718
|
+
if (headerMatch) {
|
|
24719
|
+
currentTest = headerMatch[1].trim();
|
|
24720
|
+
continue;
|
|
24721
|
+
}
|
|
24722
|
+
if (currentTest) {
|
|
24723
|
+
const fileLineMatch = line.match(/^(\S+\.py):(\d+):/);
|
|
24724
|
+
if (fileLineMatch) {
|
|
24725
|
+
const entry = `${fileLineMatch[1]}:${fileLineMatch[2]}`;
|
|
24726
|
+
const existing = result.get(currentTest) ?? [];
|
|
24727
|
+
result.set(currentTest, [...existing, entry]);
|
|
24728
|
+
}
|
|
24729
|
+
}
|
|
24730
|
+
}
|
|
24731
|
+
return result;
|
|
24732
|
+
}
|
|
24698
24733
|
function parseGoTestOutput(output) {
|
|
24699
24734
|
const common = parseCommonOutput(output);
|
|
24700
24735
|
const failures = [];
|
|
24701
|
-
|
|
24702
|
-
`)
|
|
24703
|
-
|
|
24704
|
-
|
|
24736
|
+
const lines = output.split(`
|
|
24737
|
+
`);
|
|
24738
|
+
let i = 0;
|
|
24739
|
+
while (i < lines.length) {
|
|
24740
|
+
const failMatch = lines[i].match(/^--- FAIL:\s+(\S+)\s+\([\d.]+s\)/);
|
|
24741
|
+
if (failMatch) {
|
|
24742
|
+
const testName = failMatch[1];
|
|
24743
|
+
i++;
|
|
24744
|
+
const errorLines = [];
|
|
24745
|
+
while (i < lines.length) {
|
|
24746
|
+
const line = lines[i];
|
|
24747
|
+
if (!line.trim()) {
|
|
24748
|
+
i++;
|
|
24749
|
+
continue;
|
|
24750
|
+
}
|
|
24751
|
+
const errMatch = line.match(/^\s{4,}(\S+\.go):(\d+):\s+(.+)$/);
|
|
24752
|
+
if (errMatch) {
|
|
24753
|
+
errorLines.push({ file: errMatch[1], lineNum: errMatch[2], msg: errMatch[3] });
|
|
24754
|
+
i++;
|
|
24755
|
+
} else {
|
|
24756
|
+
break;
|
|
24757
|
+
}
|
|
24758
|
+
}
|
|
24705
24759
|
failures.push({
|
|
24706
|
-
file: "unknown",
|
|
24707
|
-
testName
|
|
24708
|
-
error: "Unknown error",
|
|
24709
|
-
stackTrace:
|
|
24760
|
+
file: errorLines[0]?.file ?? "unknown",
|
|
24761
|
+
testName,
|
|
24762
|
+
error: errorLines[0]?.msg ?? "Unknown error",
|
|
24763
|
+
stackTrace: errorLines.map((e) => `${e.file}:${e.lineNum}: ${e.msg}`)
|
|
24710
24764
|
});
|
|
24765
|
+
continue;
|
|
24711
24766
|
}
|
|
24767
|
+
i++;
|
|
24712
24768
|
}
|
|
24713
24769
|
return {
|
|
24714
24770
|
passed: common.passed,
|
|
@@ -28130,39 +28186,51 @@ function normalizeComplexity(raw) {
|
|
|
28130
28186
|
}
|
|
28131
28187
|
function validateStory(raw, index, allIds) {
|
|
28132
28188
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
28133
|
-
throw new
|
|
28189
|
+
throw new NaxError(`[schema] story[${index}] must be an object`, "SCHEMA_VALIDATION_FAILED", {
|
|
28190
|
+
stage: "schema",
|
|
28191
|
+
index
|
|
28192
|
+
});
|
|
28134
28193
|
}
|
|
28135
28194
|
const s = raw;
|
|
28136
28195
|
const rawId = s.id;
|
|
28137
28196
|
if (rawId === undefined || rawId === null || rawId === "") {
|
|
28138
|
-
throw new
|
|
28197
|
+
throw new NaxError(`[schema] story[${index}].id is required and must be non-empty`, "SCHEMA_VALIDATION_FAILED", {
|
|
28198
|
+
stage: "schema",
|
|
28199
|
+
index
|
|
28200
|
+
});
|
|
28139
28201
|
}
|
|
28140
28202
|
if (typeof rawId !== "string") {
|
|
28141
|
-
throw new
|
|
28203
|
+
throw new NaxError(`[schema] story[${index}].id must be a string`, "SCHEMA_VALIDATION_FAILED", {
|
|
28204
|
+
stage: "schema",
|
|
28205
|
+
index
|
|
28206
|
+
});
|
|
28142
28207
|
}
|
|
28143
28208
|
const id = normalizeStoryId(rawId);
|
|
28144
28209
|
validateStoryId(id);
|
|
28145
28210
|
const title = s.title;
|
|
28146
28211
|
if (!title || typeof title !== "string" || title.trim() === "") {
|
|
28147
|
-
throw new
|
|
28212
|
+
throw new NaxError(`[schema] story[${index}].title is required and must be non-empty`, "SCHEMA_VALIDATION_FAILED", {
|
|
28213
|
+
stage: "schema",
|
|
28214
|
+
index
|
|
28215
|
+
});
|
|
28148
28216
|
}
|
|
28149
28217
|
const description = s.description;
|
|
28150
28218
|
if (!description || typeof description !== "string" || description.trim() === "") {
|
|
28151
|
-
throw new
|
|
28219
|
+
throw new NaxError(`[schema] story[${index}].description is required and must be non-empty`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index });
|
|
28152
28220
|
}
|
|
28153
28221
|
const ac = s.acceptanceCriteria;
|
|
28154
28222
|
if (!Array.isArray(ac) || ac.length === 0) {
|
|
28155
|
-
throw new
|
|
28223
|
+
throw new NaxError(`[schema] story[${index}].acceptanceCriteria is required and must be a non-empty array`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index });
|
|
28156
28224
|
}
|
|
28157
28225
|
for (let i = 0;i < ac.length; i++) {
|
|
28158
28226
|
if (typeof ac[i] !== "string") {
|
|
28159
|
-
throw new
|
|
28227
|
+
throw new NaxError(`[schema] story[${index}].acceptanceCriteria[${i}] must be a string`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, acIndex: i });
|
|
28160
28228
|
}
|
|
28161
28229
|
}
|
|
28162
28230
|
let suggestedCriteria;
|
|
28163
28231
|
if (s.suggestedCriteria !== undefined && s.suggestedCriteria !== null) {
|
|
28164
28232
|
if (!Array.isArray(s.suggestedCriteria)) {
|
|
28165
|
-
throw new
|
|
28233
|
+
throw new NaxError(`[schema] story[${index}].suggestedCriteria must be an array when present`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index });
|
|
28166
28234
|
}
|
|
28167
28235
|
if (s.suggestedCriteria.length > 0) {
|
|
28168
28236
|
const coerced = [];
|
|
@@ -28173,7 +28241,7 @@ function validateStory(raw, index, allIds) {
|
|
|
28173
28241
|
} else if (item !== null && typeof item === "object" && typeof item.criterion === "string") {
|
|
28174
28242
|
coerced.push(item.criterion);
|
|
28175
28243
|
} else {
|
|
28176
|
-
throw new
|
|
28244
|
+
throw new NaxError(`[schema] story[${index}].suggestedCriteria[${i}] must be a string`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, scIndex: i });
|
|
28177
28245
|
}
|
|
28178
28246
|
}
|
|
28179
28247
|
suggestedCriteria = coerced;
|
|
@@ -28182,21 +28250,24 @@ function validateStory(raw, index, allIds) {
|
|
|
28182
28250
|
const routing = typeof s.routing === "object" && s.routing !== null ? s.routing : {};
|
|
28183
28251
|
const rawComplexity = routing.complexity ?? s.complexity;
|
|
28184
28252
|
if (rawComplexity === undefined || rawComplexity === null) {
|
|
28185
|
-
throw new
|
|
28253
|
+
throw new NaxError(`[schema] story[${index}] missing complexity. Set routing.complexity to one of: ${VALID_COMPLEXITY.join(", ")}`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index });
|
|
28186
28254
|
}
|
|
28187
28255
|
if (typeof rawComplexity !== "string") {
|
|
28188
|
-
throw new
|
|
28256
|
+
throw new NaxError(`[schema] story[${index}].routing.complexity must be a string`, "SCHEMA_VALIDATION_FAILED", {
|
|
28257
|
+
stage: "schema",
|
|
28258
|
+
index
|
|
28259
|
+
});
|
|
28189
28260
|
}
|
|
28190
28261
|
const complexity = normalizeComplexity(rawComplexity);
|
|
28191
28262
|
if (complexity === null) {
|
|
28192
|
-
throw new
|
|
28263
|
+
throw new NaxError(`[schema] story[${index}].routing.complexity "${rawComplexity}" is invalid. Valid values: ${VALID_COMPLEXITY.join(", ")}`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, rawComplexity });
|
|
28193
28264
|
}
|
|
28194
28265
|
const rawTestStrategy = routing.testStrategy ?? s.testStrategy;
|
|
28195
28266
|
let testStrategy = resolveTestStrategy(typeof rawTestStrategy === "string" ? rawTestStrategy : undefined);
|
|
28196
28267
|
const rawJustification = routing.noTestJustification ?? s.noTestJustification;
|
|
28197
28268
|
if (testStrategy === "no-test") {
|
|
28198
28269
|
if (!rawJustification || typeof rawJustification !== "string" || rawJustification.trim() === "") {
|
|
28199
|
-
throw new
|
|
28270
|
+
throw new NaxError(`[schema] story[${index}].routing.noTestJustification is required when testStrategy is "no-test"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index });
|
|
28200
28271
|
}
|
|
28201
28272
|
}
|
|
28202
28273
|
if (testStrategy !== "no-test" && typeof rawJustification === "string" && rawJustification.trim() !== "") {
|
|
@@ -28207,7 +28278,7 @@ function validateStory(raw, index, allIds) {
|
|
|
28207
28278
|
const dependencies = Array.isArray(rawDeps) ? rawDeps : [];
|
|
28208
28279
|
for (const dep of dependencies) {
|
|
28209
28280
|
if (!allIds.has(dep)) {
|
|
28210
|
-
throw new
|
|
28281
|
+
throw new NaxError(`[schema] story[${index}].dependencies references unknown story ID "${dep}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, dep });
|
|
28211
28282
|
}
|
|
28212
28283
|
}
|
|
28213
28284
|
const rawTags = s.tags;
|
|
@@ -28216,13 +28287,16 @@ function validateStory(raw, index, allIds) {
|
|
|
28216
28287
|
let workdir;
|
|
28217
28288
|
if (rawWorkdir !== undefined && rawWorkdir !== null) {
|
|
28218
28289
|
if (typeof rawWorkdir !== "string") {
|
|
28219
|
-
throw new
|
|
28290
|
+
throw new NaxError(`[schema] story[${index}].workdir must be a string`, "SCHEMA_VALIDATION_FAILED", {
|
|
28291
|
+
stage: "schema",
|
|
28292
|
+
index
|
|
28293
|
+
});
|
|
28220
28294
|
}
|
|
28221
28295
|
if (rawWorkdir.startsWith("/")) {
|
|
28222
|
-
throw new
|
|
28296
|
+
throw new NaxError(`[schema] story[${index}].workdir must be relative (no leading /): "${rawWorkdir}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, rawWorkdir });
|
|
28223
28297
|
}
|
|
28224
28298
|
if (rawWorkdir.includes("..")) {
|
|
28225
|
-
throw new
|
|
28299
|
+
throw new NaxError(`[schema] story[${index}].workdir must not contain '..': "${rawWorkdir}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, rawWorkdir });
|
|
28226
28300
|
}
|
|
28227
28301
|
workdir = rawWorkdir;
|
|
28228
28302
|
}
|
|
@@ -28234,10 +28308,10 @@ function validateStory(raw, index, allIds) {
|
|
|
28234
28308
|
if (f.trim() === "")
|
|
28235
28309
|
continue;
|
|
28236
28310
|
if (f.startsWith("/")) {
|
|
28237
|
-
throw new
|
|
28311
|
+
throw new NaxError(`[schema] story[${index}].contextFiles entry must be relative (no absolute paths): "${f}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, filePath: f });
|
|
28238
28312
|
}
|
|
28239
28313
|
if (f.includes("..")) {
|
|
28240
|
-
throw new
|
|
28314
|
+
throw new NaxError(`[schema] story[${index}].contextFiles entry must not contain '..': "${f}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, filePath: f });
|
|
28241
28315
|
}
|
|
28242
28316
|
contextFiles.push(f);
|
|
28243
28317
|
} else if (typeof f === "object" && f !== null && typeof f.path === "string") {
|
|
@@ -28246,10 +28320,10 @@ function validateStory(raw, index, allIds) {
|
|
|
28246
28320
|
if (path === "")
|
|
28247
28321
|
continue;
|
|
28248
28322
|
if (path.startsWith("/")) {
|
|
28249
|
-
throw new
|
|
28323
|
+
throw new NaxError(`[schema] story[${index}].contextFiles entry must be relative (no absolute paths): "${path}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, filePath: path });
|
|
28250
28324
|
}
|
|
28251
28325
|
if (path.includes("..")) {
|
|
28252
|
-
throw new
|
|
28326
|
+
throw new NaxError(`[schema] story[${index}].contextFiles entry must not contain '..': "${path}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, filePath: path });
|
|
28253
28327
|
}
|
|
28254
28328
|
const entry = { path };
|
|
28255
28329
|
if (typeof obj.factId === "string" && obj.factId.length > 0) {
|
|
@@ -28269,10 +28343,10 @@ function validateStory(raw, index, allIds) {
|
|
|
28269
28343
|
if (trimmed === "")
|
|
28270
28344
|
continue;
|
|
28271
28345
|
if (trimmed.startsWith("/")) {
|
|
28272
|
-
throw new
|
|
28346
|
+
throw new NaxError(`[schema] story[${index}].expectedFiles entry must be relative (no absolute paths): "${trimmed}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, filePath: trimmed });
|
|
28273
28347
|
}
|
|
28274
28348
|
if (trimmed.includes("..")) {
|
|
28275
|
-
throw new
|
|
28349
|
+
throw new NaxError(`[schema] story[${index}].expectedFiles entry must not contain '..': "${trimmed}"`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, filePath: trimmed });
|
|
28276
28350
|
}
|
|
28277
28351
|
expectedFiles.push(trimmed);
|
|
28278
28352
|
}
|
|
@@ -28282,7 +28356,7 @@ function validateStory(raw, index, allIds) {
|
|
|
28282
28356
|
if (s.verifiedBy !== undefined && s.verifiedBy !== null) {
|
|
28283
28357
|
const vb = s.verifiedBy;
|
|
28284
28358
|
if (typeof vb.kind !== "string" || !VALID_VERIFIED_BY_KINDS.includes(vb.kind)) {
|
|
28285
|
-
throw new
|
|
28359
|
+
throw new NaxError(`[schema] story[${index}].verifiedBy.kind "${vb.kind}" is invalid. Valid values: ${VALID_VERIFIED_BY_KINDS.join(", ")}`, "SCHEMA_VALIDATION_FAILED", { stage: "schema", index, kind: vb.kind });
|
|
28286
28360
|
}
|
|
28287
28361
|
verifiedBy = {
|
|
28288
28362
|
kind: vb.kind,
|
|
@@ -28337,18 +28411,23 @@ function parseRawString(text) {
|
|
|
28337
28411
|
return JSON.parse(sanitized);
|
|
28338
28412
|
} catch (err) {
|
|
28339
28413
|
const parseErr = err;
|
|
28340
|
-
throw new
|
|
28414
|
+
throw new NaxError(`[schema] Failed to parse JSON: ${parseErr.message}`, "SCHEMA_VALIDATION_FAILED", {
|
|
28415
|
+
stage: "schema",
|
|
28416
|
+
cause: parseErr
|
|
28417
|
+
});
|
|
28341
28418
|
}
|
|
28342
28419
|
}
|
|
28343
28420
|
function validatePlanOutput(raw, feature, branch) {
|
|
28344
28421
|
const parsed = typeof raw === "string" ? parseRawString(raw) : raw;
|
|
28345
28422
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
28346
|
-
throw new
|
|
28423
|
+
throw new NaxError("[schema] PRD output must be a JSON object", "SCHEMA_VALIDATION_FAILED", { stage: "schema" });
|
|
28347
28424
|
}
|
|
28348
28425
|
const obj = parsed;
|
|
28349
28426
|
const rawStories = obj.userStories;
|
|
28350
28427
|
if (!Array.isArray(rawStories) || rawStories.length === 0) {
|
|
28351
|
-
throw new
|
|
28428
|
+
throw new NaxError("[schema] userStories is required and must be a non-empty array", "SCHEMA_VALIDATION_FAILED", {
|
|
28429
|
+
stage: "schema"
|
|
28430
|
+
});
|
|
28352
28431
|
}
|
|
28353
28432
|
const allIds = new Set;
|
|
28354
28433
|
for (const story of rawStories) {
|
|
@@ -28375,6 +28454,7 @@ function validatePlanOutput(raw, feature, branch) {
|
|
|
28375
28454
|
var VALID_COMPLEXITY, STORY_ID_NO_SEPARATOR;
|
|
28376
28455
|
var init_schema2 = __esm(() => {
|
|
28377
28456
|
init_test_strategy();
|
|
28457
|
+
init_errors();
|
|
28378
28458
|
VALID_COMPLEXITY = ["simple", "medium", "complex", "expert"];
|
|
28379
28459
|
STORY_ID_NO_SEPARATOR = /^([A-Za-z]+)(\d+)$/;
|
|
28380
28460
|
});
|
|
@@ -28676,7 +28756,12 @@ async function scanTestFiles(options) {
|
|
|
28676
28756
|
describes
|
|
28677
28757
|
});
|
|
28678
28758
|
}
|
|
28679
|
-
} catch {
|
|
28759
|
+
} catch (err) {
|
|
28760
|
+
getLogger().debug("test-scanner", "Failed to read file during glob scan", {
|
|
28761
|
+
path: fullPath,
|
|
28762
|
+
error: errorMessage(err)
|
|
28763
|
+
});
|
|
28764
|
+
}
|
|
28680
28765
|
}
|
|
28681
28766
|
files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
28682
28767
|
return files;
|
|
@@ -35298,145 +35383,11 @@ var init_decompose = __esm(() => {
|
|
|
35298
35383
|
init_errors();
|
|
35299
35384
|
});
|
|
35300
35385
|
|
|
35301
|
-
// src/agents/shared/decompose-prompt.ts
|
|
35302
|
-
function buildPlanModeInstructions(targetStoryId, maxAcCount) {
|
|
35303
|
-
const acConstraint = maxAcCount != null ? `
|
|
35304
|
-
## Acceptance Criteria Constraint
|
|
35305
|
-
|
|
35306
|
-
Every sub-story must have at most ${maxAcCount} acceptance criteria. If a story would exceed this limit, split it into additional sub-stories instead of adding more ACs.` : "";
|
|
35307
|
-
return `Decompose the target story (${targetStoryId}) into smaller, implementable sub-stories.
|
|
35308
|
-
|
|
35309
|
-
${COMPLEXITY_GUIDE}
|
|
35310
|
-
|
|
35311
|
-
${TEST_STRATEGY_GUIDE}
|
|
35312
|
-
|
|
35313
|
-
${GROUPING_RULES}${acConstraint}`;
|
|
35314
|
-
}
|
|
35315
|
-
function buildDecomposePromptSync(input) {
|
|
35316
|
-
if (input.targetStory) {
|
|
35317
|
-
return buildPlanModePromptSync(input);
|
|
35318
|
-
}
|
|
35319
|
-
return buildSpecModePromptSync(input);
|
|
35320
|
-
}
|
|
35321
|
-
async function buildDecomposePromptAsync(options) {
|
|
35322
|
-
if (options.targetStory) {
|
|
35323
|
-
return buildPlanModePrompt(options);
|
|
35324
|
-
}
|
|
35325
|
-
return buildSpecModePrompt(options);
|
|
35326
|
-
}
|
|
35327
|
-
function buildPlanModePromptSync(input) {
|
|
35328
|
-
const targetStory = input.targetStory;
|
|
35329
|
-
const siblings = input.siblings ?? [];
|
|
35330
|
-
const instructions = buildPlanModeInstructions(targetStory.id, input.maxAcCount ?? null);
|
|
35331
|
-
let builder = OneShotPromptBuilder.for("decomposer").instructions(instructions).inputData("Target Story", JSON.stringify(targetStory, null, 2)).inputData("Codebase Context", input.codebaseContext);
|
|
35332
|
-
if (siblings.length > 0) {
|
|
35333
|
-
const siblingsSummary = siblings.map((s) => `- ${s.id}: ${s.title}`).join(`
|
|
35334
|
-
`);
|
|
35335
|
-
builder = builder.inputData("Sibling Stories", siblingsSummary);
|
|
35336
|
-
}
|
|
35337
|
-
return builder.agentProfiles(input.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
|
|
35338
|
-
}
|
|
35339
|
-
function buildSpecModePromptSync(input) {
|
|
35340
|
-
return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", input.codebaseContext).inputData("Feature Specification", input.specContent).agentProfiles(input.profiles ?? []).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
|
|
35341
|
-
}
|
|
35342
|
-
async function buildPlanModePrompt(options) {
|
|
35343
|
-
const targetStory = options.targetStory;
|
|
35344
|
-
const siblings = options.siblings ?? [];
|
|
35345
|
-
const maxAcCount = options.maxAcCount ?? null;
|
|
35346
|
-
const instructions = buildPlanModeInstructions(targetStory.id, maxAcCount);
|
|
35347
|
-
let builder = OneShotPromptBuilder.for("decomposer").instructions(instructions).inputData("Target Story", JSON.stringify(targetStory, null, 2)).inputData("Codebase Context", options.codebaseContext);
|
|
35348
|
-
if (siblings.length > 0) {
|
|
35349
|
-
const siblingsSummary = siblings.map((s) => `- ${s.id}: ${s.title}`).join(`
|
|
35350
|
-
`);
|
|
35351
|
-
builder = builder.inputData("Sibling Stories", siblingsSummary);
|
|
35352
|
-
}
|
|
35353
|
-
return builder.agentProfiles(options.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
|
|
35354
|
-
}
|
|
35355
|
-
async function buildSpecModePrompt(options) {
|
|
35356
|
-
return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", options.codebaseContext).inputData("Feature Specification", options.specContent).agentProfiles(options.profiles ?? []).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
|
|
35357
|
-
}
|
|
35358
|
-
var DECOMPOSE_SPEC_SCHEMA, DECOMPOSE_PLAN_SCHEMA, SPEC_DECOMPOSE_INSTRUCTIONS;
|
|
35359
|
-
var init_decompose_prompt = __esm(() => {
|
|
35360
|
-
init_test_strategy();
|
|
35361
|
-
init_prompts();
|
|
35362
|
-
DECOMPOSE_SPEC_SCHEMA = {
|
|
35363
|
-
name: "DecomposedStory[]",
|
|
35364
|
-
description: "Respond with ONLY a JSON array \u2014 no markdown code fences, no explanation text before or after.",
|
|
35365
|
-
example: [
|
|
35366
|
-
{
|
|
35367
|
-
id: "US-001",
|
|
35368
|
-
title: "Story title",
|
|
35369
|
-
description: "Story description",
|
|
35370
|
-
acceptanceCriteria: ["Criterion 1"],
|
|
35371
|
-
tags: ["tag1"],
|
|
35372
|
-
dependencies: [],
|
|
35373
|
-
complexity: "medium",
|
|
35374
|
-
contextFiles: ["src/path/to/file.ts"],
|
|
35375
|
-
reasoning: "Why this complexity level",
|
|
35376
|
-
estimatedLOC: 150,
|
|
35377
|
-
risks: ["Risk 1"],
|
|
35378
|
-
testStrategy: "test-after",
|
|
35379
|
-
agentProfileId: ""
|
|
35380
|
-
}
|
|
35381
|
-
]
|
|
35382
|
-
};
|
|
35383
|
-
DECOMPOSE_PLAN_SCHEMA = {
|
|
35384
|
-
name: "SubStory[]",
|
|
35385
|
-
description: "Return a JSON array of sub-stories \u2014 no markdown code fences, no explanation \u2014 JSON array only.",
|
|
35386
|
-
example: [
|
|
35387
|
-
{
|
|
35388
|
-
id: "US-001-A",
|
|
35389
|
-
title: "Sub-story title",
|
|
35390
|
-
description: "Description",
|
|
35391
|
-
acceptanceCriteria: ["Behavioral, testable criterion"],
|
|
35392
|
-
contextFiles: ["src/path/to/file.ts"],
|
|
35393
|
-
tags: [],
|
|
35394
|
-
dependencies: [],
|
|
35395
|
-
complexity: "simple",
|
|
35396
|
-
reasoning: "Why this complexity",
|
|
35397
|
-
estimatedLOC: 0,
|
|
35398
|
-
risks: [],
|
|
35399
|
-
testStrategy: "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
|
|
35400
|
-
agentProfileId: ""
|
|
35401
|
-
}
|
|
35402
|
-
]
|
|
35403
|
-
};
|
|
35404
|
-
SPEC_DECOMPOSE_INSTRUCTIONS = `Break down the feature specification into user stories and classify each story's complexity.
|
|
35405
|
-
|
|
35406
|
-
For each story, provide:
|
|
35407
|
-
1. id: Story ID (e.g., "US-001")
|
|
35408
|
-
2. title: Concise story title
|
|
35409
|
-
3. description: What needs to be implemented
|
|
35410
|
-
4. acceptanceCriteria: Array of testable criteria
|
|
35411
|
-
5. tags: Array of routing tags (e.g., ["security", "api"])
|
|
35412
|
-
6. dependencies: Array of story IDs this depends on (e.g., ["US-001"])
|
|
35413
|
-
7. complexity: "simple" | "medium" | "complex" | "expert"
|
|
35414
|
-
8. contextFiles: Array of file paths to inject into agent prompt before execution
|
|
35415
|
-
9. reasoning: Why this complexity level
|
|
35416
|
-
10. estimatedLOC: Estimated lines of code to change
|
|
35417
|
-
11. risks: Array of implementation risks
|
|
35418
|
-
12. testStrategy: "no-test" | "test-after" | "tdd-simple" | "three-session-tdd" | "three-session-tdd-lite"
|
|
35419
|
-
13. noTestJustification: string (REQUIRED when testStrategy is "no-test" \u2014 explain why tests are unnecessary)
|
|
35420
|
-
14. agentProfileId: (optional) profile id from the Agent Profiles table \u2014 assign the best-matching profile for each story; omit if no profiles are listed or none fits well
|
|
35421
|
-
|
|
35422
|
-
${COMPLEXITY_GUIDE}
|
|
35423
|
-
|
|
35424
|
-
${TEST_STRATEGY_GUIDE}
|
|
35425
|
-
|
|
35426
|
-
${GROUPING_RULES}
|
|
35427
|
-
|
|
35428
|
-
Consider:
|
|
35429
|
-
1. Does infrastructure exist? (e.g., "add caching" when no cache layer exists = complex)
|
|
35430
|
-
2. How many files will be touched?
|
|
35431
|
-
3. Are there cross-cutting concerns (auth, validation, error handling)?
|
|
35432
|
-
4. Does it require new dependencies or architectural decisions?`;
|
|
35433
|
-
});
|
|
35434
|
-
|
|
35435
35386
|
// src/operations/decompose.ts
|
|
35436
35387
|
var decomposeOp;
|
|
35437
35388
|
var init_decompose2 = __esm(() => {
|
|
35389
|
+
init_prompts();
|
|
35438
35390
|
init_decompose();
|
|
35439
|
-
init_decompose_prompt();
|
|
35440
35391
|
init_config();
|
|
35441
35392
|
init_logger2();
|
|
35442
35393
|
decomposeOp = {
|
|
@@ -35892,10 +35843,10 @@ var init_routing = __esm(() => {
|
|
|
35892
35843
|
});
|
|
35893
35844
|
|
|
35894
35845
|
// src/operations/classify-route.ts
|
|
35895
|
-
var
|
|
35896
|
-
Respond with JSON only \u2014 no explanation text before or after.`, classifyRouteOp, BATCH_ROUTING_SCHEMA_INLINE = `Respond with a JSON array \u2014 no explanation, no markdown.
|
|
35846
|
+
var classifyRouteOp, BATCH_ROUTING_SCHEMA_INLINE = `Respond with a JSON array \u2014 no explanation, no markdown.
|
|
35897
35847
|
Example: [{"id":"US-001","complexity":"simple","modelTier":"fast","reasoning":"<one line>"}]`, classifyRouteBatchOp;
|
|
35898
35848
|
var init_classify_route = __esm(() => {
|
|
35849
|
+
init_prompts();
|
|
35899
35850
|
init_config();
|
|
35900
35851
|
init_routing();
|
|
35901
35852
|
init_llm_parsing();
|
|
@@ -35923,7 +35874,7 @@ ${criteria}`,
|
|
|
35923
35874
|
].join(`
|
|
35924
35875
|
`);
|
|
35925
35876
|
return {
|
|
35926
|
-
role: { id: "role", content:
|
|
35877
|
+
role: { id: "role", content: OneShotPromptBuilder.classifierRoleContent(), overridable: false },
|
|
35927
35878
|
task: { id: "task", content: `${ROUTING_INSTRUCTIONS}
|
|
35928
35879
|
|
|
35929
35880
|
## Story
|
|
@@ -35970,7 +35921,7 @@ ${storyBlocks}
|
|
|
35970
35921
|
|
|
35971
35922
|
${BATCH_ROUTING_SCHEMA_INLINE}`;
|
|
35972
35923
|
return {
|
|
35973
|
-
role: { id: "role", content:
|
|
35924
|
+
role: { id: "role", content: OneShotPromptBuilder.classifierRoleContent(), overridable: false },
|
|
35974
35925
|
task: { id: "task", content: taskContent, overridable: false }
|
|
35975
35926
|
};
|
|
35976
35927
|
},
|
|
@@ -37536,7 +37487,7 @@ async function resolveOutcome(proposalOutputs, critiqueOutputs, stageConfig, con
|
|
|
37536
37487
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
37537
37488
|
const kind = pickSelectorKind(stageConfig);
|
|
37538
37489
|
if ((kind === "majority-fail-closed" || kind === "majority-fail-open") && workdir !== undefined) {
|
|
37539
|
-
logger?.warn("debate", "majority resolver does not support implementer session resumption \u2014 switch to synthesis or custom resolver for context-aware semantic review");
|
|
37490
|
+
logger?.warn("debate", "majority resolver does not support implementer session resumption \u2014 switch to synthesis or custom resolver for context-aware semantic review", { storyId });
|
|
37540
37491
|
}
|
|
37541
37492
|
const proposalList = debaters ? debaters.map((debater, i) => ({
|
|
37542
37493
|
debater,
|
|
@@ -38472,7 +38423,7 @@ Options:`);
|
|
|
38472
38423
|
const prompt = OneShotPromptBuilder.for("auto-approver").instructions(AUTO_APPROVER_INSTRUCTIONS).inputData("Interaction Request", requestLines.join(`
|
|
38473
38424
|
`)).jsonSchema(AUTO_APPROVER_SCHEMA).build();
|
|
38474
38425
|
return {
|
|
38475
|
-
role: { id: "role", content:
|
|
38426
|
+
role: { id: "role", content: OneShotPromptBuilder.autoApproverRoleContent(), overridable: false },
|
|
38476
38427
|
task: { id: "task", content: prompt, overridable: false }
|
|
38477
38428
|
};
|
|
38478
38429
|
},
|
|
@@ -39330,7 +39281,12 @@ var init_full_suite_rectify_op = __esm(() => {
|
|
|
39330
39281
|
},
|
|
39331
39282
|
parse(output, _input, _ctx) {
|
|
39332
39283
|
const declarations = parseTestEditDeclarations(output);
|
|
39333
|
-
|
|
39284
|
+
const unresolvedMatch = output.match(/^UNRESOLVED:\s*(.+)$/m);
|
|
39285
|
+
return {
|
|
39286
|
+
applied: true,
|
|
39287
|
+
testEditDeclarations: declarations,
|
|
39288
|
+
...unresolvedMatch ? { unresolvedReason: unresolvedMatch[1]?.trim() } : {}
|
|
39289
|
+
};
|
|
39334
39290
|
}
|
|
39335
39291
|
};
|
|
39336
39292
|
});
|
|
@@ -39352,7 +39308,13 @@ function makeFullSuiteRectifyStrategy(story, config2, sink) {
|
|
|
39352
39308
|
sink.testEdits.push(d);
|
|
39353
39309
|
}
|
|
39354
39310
|
}
|
|
39355
|
-
|
|
39311
|
+
const hasDeclarations = output.testEditDeclarations.length > 0;
|
|
39312
|
+
const unresolved = output.unresolvedReason && !hasDeclarations ? output.unresolvedReason : undefined;
|
|
39313
|
+
return {
|
|
39314
|
+
targetFiles: [],
|
|
39315
|
+
summary: unresolved ?? "Fixed failing tests",
|
|
39316
|
+
...unresolved ? { unresolved } : {}
|
|
39317
|
+
};
|
|
39356
39318
|
},
|
|
39357
39319
|
maxAttempts: config2.execution.rectification.maxAttemptsPerStrategy,
|
|
39358
39320
|
coRun: "exclusive"
|
|
@@ -43354,6 +43316,13 @@ ${OneShotPromptBuilder.agentProfileInstruction()}`
|
|
|
43354
43316
|
].join(`
|
|
43355
43317
|
`);
|
|
43356
43318
|
}
|
|
43319
|
+
static classifierRoleContent() {
|
|
43320
|
+
return `You are a story classifier that assigns complexity and model tier to user stories.
|
|
43321
|
+
Respond with JSON only \u2014 no explanation text before or after.`;
|
|
43322
|
+
}
|
|
43323
|
+
static autoApproverRoleContent() {
|
|
43324
|
+
return "You are an AI orchestration decision-maker.";
|
|
43325
|
+
}
|
|
43357
43326
|
static agentCapabilityCards(profiles) {
|
|
43358
43327
|
if (profiles.length === 0)
|
|
43359
43328
|
return "";
|
|
@@ -44041,6 +44010,140 @@ Please enhance the original proposal to address these runner-up criteria while m
|
|
|
44041
44010
|
}
|
|
44042
44011
|
}
|
|
44043
44012
|
|
|
44013
|
+
// src/prompts/builders/decompose-builder.ts
|
|
44014
|
+
function buildPlanModeInstructions(targetStoryId, maxAcCount) {
|
|
44015
|
+
const acConstraint = maxAcCount != null ? `
|
|
44016
|
+
## Acceptance Criteria Constraint
|
|
44017
|
+
|
|
44018
|
+
Every sub-story must have at most ${maxAcCount} acceptance criteria. If a story would exceed this limit, split it into additional sub-stories instead of adding more ACs.` : "";
|
|
44019
|
+
return `Decompose the target story (${targetStoryId}) into smaller, implementable sub-stories.
|
|
44020
|
+
|
|
44021
|
+
${COMPLEXITY_GUIDE}
|
|
44022
|
+
|
|
44023
|
+
${TEST_STRATEGY_GUIDE}
|
|
44024
|
+
|
|
44025
|
+
${GROUPING_RULES}${acConstraint}`;
|
|
44026
|
+
}
|
|
44027
|
+
function buildDecomposePromptSync(input) {
|
|
44028
|
+
if (input.targetStory) {
|
|
44029
|
+
return buildPlanModePromptSync(input);
|
|
44030
|
+
}
|
|
44031
|
+
return buildSpecModePromptSync(input);
|
|
44032
|
+
}
|
|
44033
|
+
async function buildDecomposePromptAsync(options) {
|
|
44034
|
+
if (options.targetStory) {
|
|
44035
|
+
return buildPlanModePrompt(options);
|
|
44036
|
+
}
|
|
44037
|
+
return buildSpecModePrompt(options);
|
|
44038
|
+
}
|
|
44039
|
+
function buildPlanModePromptSync(input) {
|
|
44040
|
+
const targetStory = input.targetStory;
|
|
44041
|
+
const siblings = input.siblings ?? [];
|
|
44042
|
+
const instructions = buildPlanModeInstructions(targetStory.id, input.maxAcCount ?? null);
|
|
44043
|
+
let builder = OneShotPromptBuilder.for("decomposer").instructions(instructions).inputData("Target Story", JSON.stringify(targetStory, null, 2)).inputData("Codebase Context", input.codebaseContext);
|
|
44044
|
+
if (siblings.length > 0) {
|
|
44045
|
+
const siblingsSummary = siblings.map((s) => `- ${s.id}: ${s.title}`).join(`
|
|
44046
|
+
`);
|
|
44047
|
+
builder = builder.inputData("Sibling Stories", siblingsSummary);
|
|
44048
|
+
}
|
|
44049
|
+
return builder.agentProfiles(input.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
|
|
44050
|
+
}
|
|
44051
|
+
function buildSpecModePromptSync(input) {
|
|
44052
|
+
return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", input.codebaseContext).inputData("Feature Specification", input.specContent).agentProfiles(input.profiles ?? []).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
|
|
44053
|
+
}
|
|
44054
|
+
async function buildPlanModePrompt(options) {
|
|
44055
|
+
const targetStory = options.targetStory;
|
|
44056
|
+
const siblings = options.siblings ?? [];
|
|
44057
|
+
const maxAcCount = options.maxAcCount ?? null;
|
|
44058
|
+
const instructions = buildPlanModeInstructions(targetStory.id, maxAcCount);
|
|
44059
|
+
let builder = OneShotPromptBuilder.for("decomposer").instructions(instructions).inputData("Target Story", JSON.stringify(targetStory, null, 2)).inputData("Codebase Context", options.codebaseContext);
|
|
44060
|
+
if (siblings.length > 0) {
|
|
44061
|
+
const siblingsSummary = siblings.map((s) => `- ${s.id}: ${s.title}`).join(`
|
|
44062
|
+
`);
|
|
44063
|
+
builder = builder.inputData("Sibling Stories", siblingsSummary);
|
|
44064
|
+
}
|
|
44065
|
+
return builder.agentProfiles(options.profiles ?? []).jsonSchema(DECOMPOSE_PLAN_SCHEMA).build();
|
|
44066
|
+
}
|
|
44067
|
+
async function buildSpecModePrompt(options) {
|
|
44068
|
+
return OneShotPromptBuilder.for("decomposer").instructions(SPEC_DECOMPOSE_INSTRUCTIONS).inputData("Codebase Context", options.codebaseContext).inputData("Feature Specification", options.specContent).agentProfiles(options.profiles ?? []).jsonSchema(DECOMPOSE_SPEC_SCHEMA).build();
|
|
44069
|
+
}
|
|
44070
|
+
var DECOMPOSE_SPEC_SCHEMA, DECOMPOSE_PLAN_SCHEMA, SPEC_DECOMPOSE_INSTRUCTIONS;
|
|
44071
|
+
var init_decompose_builder = __esm(() => {
|
|
44072
|
+
init_test_strategy();
|
|
44073
|
+
init_one_shot_builder();
|
|
44074
|
+
DECOMPOSE_SPEC_SCHEMA = {
|
|
44075
|
+
name: "DecomposedStory[]",
|
|
44076
|
+
description: "Respond with ONLY a JSON array \u2014 no markdown code fences, no explanation text before or after.",
|
|
44077
|
+
example: [
|
|
44078
|
+
{
|
|
44079
|
+
id: "US-001",
|
|
44080
|
+
title: "Story title",
|
|
44081
|
+
description: "Story description",
|
|
44082
|
+
acceptanceCriteria: ["Criterion 1"],
|
|
44083
|
+
tags: ["tag1"],
|
|
44084
|
+
dependencies: [],
|
|
44085
|
+
complexity: "medium",
|
|
44086
|
+
contextFiles: ["src/path/to/file.ts"],
|
|
44087
|
+
reasoning: "Why this complexity level",
|
|
44088
|
+
estimatedLOC: 150,
|
|
44089
|
+
risks: ["Risk 1"],
|
|
44090
|
+
testStrategy: "test-after",
|
|
44091
|
+
agentProfileId: ""
|
|
44092
|
+
}
|
|
44093
|
+
]
|
|
44094
|
+
};
|
|
44095
|
+
DECOMPOSE_PLAN_SCHEMA = {
|
|
44096
|
+
name: "SubStory[]",
|
|
44097
|
+
description: "Return a JSON array of sub-stories \u2014 no markdown code fences, no explanation \u2014 JSON array only.",
|
|
44098
|
+
example: [
|
|
44099
|
+
{
|
|
44100
|
+
id: "US-001-A",
|
|
44101
|
+
title: "Sub-story title",
|
|
44102
|
+
description: "Description",
|
|
44103
|
+
acceptanceCriteria: ["Behavioral, testable criterion"],
|
|
44104
|
+
contextFiles: ["src/path/to/file.ts"],
|
|
44105
|
+
tags: [],
|
|
44106
|
+
dependencies: [],
|
|
44107
|
+
complexity: "simple",
|
|
44108
|
+
reasoning: "Why this complexity",
|
|
44109
|
+
estimatedLOC: 0,
|
|
44110
|
+
risks: [],
|
|
44111
|
+
testStrategy: "no-test | tdd-simple | three-session-tdd-lite | three-session-tdd | test-after",
|
|
44112
|
+
agentProfileId: ""
|
|
44113
|
+
}
|
|
44114
|
+
]
|
|
44115
|
+
};
|
|
44116
|
+
SPEC_DECOMPOSE_INSTRUCTIONS = `Break down the feature specification into user stories and classify each story's complexity.
|
|
44117
|
+
|
|
44118
|
+
For each story, provide:
|
|
44119
|
+
1. id: Story ID (e.g., "US-001")
|
|
44120
|
+
2. title: Concise story title
|
|
44121
|
+
3. description: What needs to be implemented
|
|
44122
|
+
4. acceptanceCriteria: Array of testable criteria
|
|
44123
|
+
5. tags: Array of routing tags (e.g., ["security", "api"])
|
|
44124
|
+
6. dependencies: Array of story IDs this depends on (e.g., ["US-001"])
|
|
44125
|
+
7. complexity: "simple" | "medium" | "complex" | "expert"
|
|
44126
|
+
8. contextFiles: Array of file paths to inject into agent prompt before execution
|
|
44127
|
+
9. reasoning: Why this complexity level
|
|
44128
|
+
10. estimatedLOC: Estimated lines of code to change
|
|
44129
|
+
11. risks: Array of implementation risks
|
|
44130
|
+
12. testStrategy: "no-test" | "test-after" | "tdd-simple" | "three-session-tdd" | "three-session-tdd-lite"
|
|
44131
|
+
13. noTestJustification: string (REQUIRED when testStrategy is "no-test" \u2014 explain why tests are unnecessary)
|
|
44132
|
+
14. agentProfileId: (optional) profile id from the Agent Profiles table \u2014 assign the best-matching profile for each story; omit if no profiles are listed or none fits well
|
|
44133
|
+
|
|
44134
|
+
${COMPLEXITY_GUIDE}
|
|
44135
|
+
|
|
44136
|
+
${TEST_STRATEGY_GUIDE}
|
|
44137
|
+
|
|
44138
|
+
${GROUPING_RULES}
|
|
44139
|
+
|
|
44140
|
+
Consider:
|
|
44141
|
+
1. Does infrastructure exist? (e.g., "add caching" when no cache layer exists = complex)
|
|
44142
|
+
2. How many files will be touched?
|
|
44143
|
+
3. Are there cross-cutting concerns (auth, validation, error handling)?
|
|
44144
|
+
4. Does it require new dependencies or architectural decisions?`;
|
|
44145
|
+
});
|
|
44146
|
+
|
|
44044
44147
|
// src/prompts/index.ts
|
|
44045
44148
|
var init_prompts = __esm(() => {
|
|
44046
44149
|
init_tdd_builder();
|
|
@@ -44055,6 +44158,7 @@ var init_prompts = __esm(() => {
|
|
|
44055
44158
|
init_plan_builder();
|
|
44056
44159
|
init_types5();
|
|
44057
44160
|
init_compose2();
|
|
44161
|
+
init_decompose_builder();
|
|
44058
44162
|
});
|
|
44059
44163
|
|
|
44060
44164
|
// src/operations/build-hop-callback.ts
|
|
@@ -47966,7 +48070,7 @@ async function runHybrid(ctx, prompt) {
|
|
|
47966
48070
|
const resolved = [];
|
|
47967
48071
|
for (const debater of debaters) {
|
|
47968
48072
|
if (!agentManager.getAgent(debater.agent)) {
|
|
47969
|
-
logger?.warn("debate", `Agent '${debater.agent}' not found \u2014 skipping debater
|
|
48073
|
+
logger?.warn("debate", `Agent '${debater.agent}' not found \u2014 skipping debater`, { storyId: ctx.storyId });
|
|
47970
48074
|
continue;
|
|
47971
48075
|
}
|
|
47972
48076
|
resolved.push({ debater, agentName: debater.agent });
|
|
@@ -48915,7 +49019,7 @@ async function runStateful(ctx, prompt) {
|
|
|
48915
49019
|
const resolved = debaters.flatMap((debater) => ctx.agentManager.getAgent(debater.agent) ? [{ debater, agentName: debater.agent }] : []);
|
|
48916
49020
|
for (const debater of debaters) {
|
|
48917
49021
|
if (!ctx.agentManager.getAgent(debater.agent)) {
|
|
48918
|
-
logger?.warn("debate", `Agent '${debater.agent}' not found \u2014 skipping debater
|
|
49022
|
+
logger?.warn("debate", `Agent '${debater.agent}' not found \u2014 skipping debater`, { storyId: ctx.storyId });
|
|
48919
49023
|
}
|
|
48920
49024
|
}
|
|
48921
49025
|
logger?.info("debate", "debate:start", {
|
|
@@ -49086,7 +49190,7 @@ class DebateRunner {
|
|
|
49086
49190
|
if (sessionMode === "stateful")
|
|
49087
49191
|
return this.runSessionModeWithScopes(prompt, runHybrid);
|
|
49088
49192
|
const logger = _debateSessionDeps.getSafeLogger();
|
|
49089
|
-
logger?.warn("debate", `hybrid mode requires sessionMode: stateful, but got '${sessionMode}' \u2014 falling back to one-shot
|
|
49193
|
+
logger?.warn("debate", `hybrid mode requires sessionMode: stateful, but got '${sessionMode}' \u2014 falling back to one-shot`, { storyId: this.ctx.storyId });
|
|
49090
49194
|
return this.runPanelOneShot(prompt);
|
|
49091
49195
|
}
|
|
49092
49196
|
if (sessionMode === "stateful")
|
|
@@ -49130,7 +49234,9 @@ class DebateRunner {
|
|
|
49130
49234
|
const resolved = [];
|
|
49131
49235
|
for (const debater of debaters) {
|
|
49132
49236
|
if (!agentManager.getAgent(debater.agent)) {
|
|
49133
|
-
logger?.warn("debate", `Agent '${debater.agent}' not found \u2014 skipping debater
|
|
49237
|
+
logger?.warn("debate", `Agent '${debater.agent}' not found \u2014 skipping debater`, {
|
|
49238
|
+
storyId: this.ctx.storyId
|
|
49239
|
+
});
|
|
49134
49240
|
continue;
|
|
49135
49241
|
}
|
|
49136
49242
|
resolved.push({ debater, agentName: debater.agent });
|
|
@@ -49445,13 +49551,13 @@ class InteractionChain {
|
|
|
49445
49551
|
async send(request) {
|
|
49446
49552
|
const plugin = this.getPrimary();
|
|
49447
49553
|
if (!plugin) {
|
|
49448
|
-
throw new
|
|
49554
|
+
throw new NaxError("No interaction plugin registered", "INTERACTION_ERROR", { stage: "run" });
|
|
49449
49555
|
}
|
|
49450
49556
|
await plugin.send(request);
|
|
49451
49557
|
}
|
|
49452
49558
|
async receive(requestId, timeout) {
|
|
49453
49559
|
if (this.plugins.length === 0) {
|
|
49454
|
-
throw new
|
|
49560
|
+
throw new NaxError("No interaction plugin registered", "INTERACTION_ERROR", { stage: "run", requestId });
|
|
49455
49561
|
}
|
|
49456
49562
|
const timeoutMs = timeout ?? this.config.defaultTimeout;
|
|
49457
49563
|
const errors3 = [];
|
|
@@ -49465,7 +49571,11 @@ class InteractionChain {
|
|
|
49465
49571
|
}
|
|
49466
49572
|
}
|
|
49467
49573
|
const errorMessages = errors3.map((e) => e.message).join("; ");
|
|
49468
|
-
throw new
|
|
49574
|
+
throw new NaxError(`All interaction plugins failed: ${errorMessages}`, "INTERACTION_ERROR", {
|
|
49575
|
+
stage: "run",
|
|
49576
|
+
requestId,
|
|
49577
|
+
pluginCount: this.plugins.length
|
|
49578
|
+
});
|
|
49469
49579
|
}
|
|
49470
49580
|
async prompt(request) {
|
|
49471
49581
|
await this.send(request);
|
|
@@ -49515,19 +49625,29 @@ class InteractionChain {
|
|
|
49515
49625
|
}
|
|
49516
49626
|
}
|
|
49517
49627
|
}
|
|
49628
|
+
var init_chain = __esm(() => {
|
|
49629
|
+
init_errors();
|
|
49630
|
+
});
|
|
49518
49631
|
|
|
49519
49632
|
// src/interaction/state.ts
|
|
49520
49633
|
import * as path6 from "path";
|
|
49521
49634
|
function validateInteractionId(id) {
|
|
49522
49635
|
if (!SAFE_INTERACTION_ID_RE.test(id)) {
|
|
49523
|
-
throw new
|
|
49636
|
+
throw new NaxError(`Invalid interaction ID \u2014 must match [a-zA-Z0-9_-]{1,128}: ${id}`, "INTERACTION_ERROR", {
|
|
49637
|
+
stage: "run",
|
|
49638
|
+
id
|
|
49639
|
+
});
|
|
49524
49640
|
}
|
|
49525
49641
|
}
|
|
49526
49642
|
function assertPathWithin(filePath, baseDir) {
|
|
49527
49643
|
const resolved = path6.resolve(filePath);
|
|
49528
49644
|
const base = path6.resolve(baseDir);
|
|
49529
49645
|
if (!resolved.startsWith(base + path6.sep) && resolved !== base) {
|
|
49530
|
-
throw new
|
|
49646
|
+
throw new NaxError(`Path traversal detected: ${filePath} is outside ${baseDir}`, "INTERACTION_ERROR", {
|
|
49647
|
+
stage: "run",
|
|
49648
|
+
filePath,
|
|
49649
|
+
baseDir
|
|
49650
|
+
});
|
|
49531
49651
|
}
|
|
49532
49652
|
}
|
|
49533
49653
|
async function loadPendingInteraction(requestId, featureDir) {
|
|
@@ -49568,6 +49688,7 @@ async function listPendingInteractions(featureDir) {
|
|
|
49568
49688
|
}
|
|
49569
49689
|
var SAFE_INTERACTION_ID_RE;
|
|
49570
49690
|
var init_state = __esm(() => {
|
|
49691
|
+
init_errors();
|
|
49571
49692
|
SAFE_INTERACTION_ID_RE = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
49572
49693
|
});
|
|
49573
49694
|
|
|
@@ -50878,6 +50999,7 @@ async function initInteractionChain(config2, headless) {
|
|
|
50878
50999
|
}
|
|
50879
51000
|
var init_init = __esm(() => {
|
|
50880
51001
|
init_logger2();
|
|
51002
|
+
init_chain();
|
|
50881
51003
|
init_auto();
|
|
50882
51004
|
init_cli();
|
|
50883
51005
|
init_telegram();
|
|
@@ -50920,6 +51042,7 @@ var init_bridge_builder = __esm(() => {
|
|
|
50920
51042
|
// src/interaction/index.ts
|
|
50921
51043
|
var init_interaction = __esm(() => {
|
|
50922
51044
|
init_types8();
|
|
51045
|
+
init_chain();
|
|
50923
51046
|
init_state();
|
|
50924
51047
|
init_cli();
|
|
50925
51048
|
init_telegram();
|
|
@@ -52349,9 +52472,9 @@ async function runReplanLoop(workdir, config2, options) {
|
|
|
52349
52472
|
_planDeps.processExit(1);
|
|
52350
52473
|
}
|
|
52351
52474
|
var init_plan_decompose = __esm(() => {
|
|
52475
|
+
init_prompts();
|
|
52352
52476
|
init_agents();
|
|
52353
52477
|
init_decompose();
|
|
52354
|
-
init_decompose_prompt();
|
|
52355
52478
|
init_errors();
|
|
52356
52479
|
init_logger2();
|
|
52357
52480
|
init_operations();
|
|
@@ -54399,18 +54522,20 @@ var init_constitution2 = __esm(() => {
|
|
|
54399
54522
|
if (result) {
|
|
54400
54523
|
ctx.constitution = result;
|
|
54401
54524
|
logger.debug("constitution", "Constitution loaded", {
|
|
54525
|
+
storyId: ctx.story.id,
|
|
54402
54526
|
tokens: result.tokens,
|
|
54403
54527
|
truncated: result.truncated
|
|
54404
54528
|
});
|
|
54405
54529
|
if (result.truncated) {
|
|
54406
54530
|
logger.warn("constitution", "Constitution truncated", {
|
|
54531
|
+
storyId: ctx.story.id,
|
|
54407
54532
|
originalTokens: result.originalTokens,
|
|
54408
54533
|
tokens: result.tokens,
|
|
54409
54534
|
maxTokens: ctx.config.constitution.maxTokens
|
|
54410
54535
|
});
|
|
54411
54536
|
}
|
|
54412
54537
|
} else {
|
|
54413
|
-
logger.debug("constitution", "Constitution not found or failed to load");
|
|
54538
|
+
logger.debug("constitution", "Constitution not found or failed to load", { storyId: ctx.story.id });
|
|
54414
54539
|
}
|
|
54415
54540
|
return { action: "continue" };
|
|
54416
54541
|
}
|
|
@@ -55643,7 +55768,11 @@ async function runRectification(ctx, state, phaseCosts, phaseOutputs, overrides)
|
|
|
55643
55768
|
});
|
|
55644
55769
|
}
|
|
55645
55770
|
if (EXHAUSTED_EXIT_REASONS.has(cycleResult.exitReason) && cycleResult.finalFindings.length > 0) {
|
|
55646
|
-
return {
|
|
55771
|
+
return {
|
|
55772
|
+
rectificationExhausted: true,
|
|
55773
|
+
unfixedFindings: cycleResult.finalFindings,
|
|
55774
|
+
...cycleResult.unresolvedDetail ? { unresolvedDetail: cycleResult.unresolvedDetail } : {}
|
|
55775
|
+
};
|
|
55647
55776
|
}
|
|
55648
55777
|
if (cycleResult.exitReason === "validate-short-circuit") {
|
|
55649
55778
|
return { liteScopeIncomplete: true };
|
|
@@ -56136,15 +56265,6 @@ function toVerifyScopedMode(mode) {
|
|
|
56136
56265
|
function hasReviewEscalation(story) {
|
|
56137
56266
|
return (story.priorFailures ?? []).some((f) => f.stage === "review");
|
|
56138
56267
|
}
|
|
56139
|
-
async function buildThreeSessionPrompt(role, ctx, lite) {
|
|
56140
|
-
return TddPromptBuilder.buildForRole(role, ctx.workdir, ctx.config, ctx.story, {
|
|
56141
|
-
lite,
|
|
56142
|
-
contextMarkdown: ctx.contextMarkdown,
|
|
56143
|
-
featureContextMarkdown: ctx.featureContextMarkdown,
|
|
56144
|
-
contextBundle: ctx.contextBundle,
|
|
56145
|
-
constitution: ctx.constitution?.content
|
|
56146
|
-
});
|
|
56147
|
-
}
|
|
56148
56268
|
function buildFeatureCtxBlock(ctx, role) {
|
|
56149
56269
|
const bundleMarkdown = ctx.contextBundle?.pushMarkdown.trim();
|
|
56150
56270
|
if (bundleMarkdown) {
|
|
@@ -56176,10 +56296,17 @@ async function assemblePlanInputsFromCtx(ctx) {
|
|
|
56176
56296
|
}
|
|
56177
56297
|
const packageDirRel = packageDirRelative(ctx.projectDir, ctx.workdir);
|
|
56178
56298
|
const resolvedTestPatterns = await resolveTestFilePatterns(config2, ctx.projectDir, packageDirRel);
|
|
56299
|
+
const tddOpts = {
|
|
56300
|
+
lite: isLite,
|
|
56301
|
+
contextMarkdown: ctx.contextMarkdown,
|
|
56302
|
+
featureContextMarkdown: ctx.featureContextMarkdown,
|
|
56303
|
+
contextBundle: ctx.contextBundle,
|
|
56304
|
+
constitution: ctx.constitution?.content
|
|
56305
|
+
};
|
|
56179
56306
|
const [testWriterPrompt, implementerPrompt, verifierPrompt] = _isTdd ? await Promise.all([
|
|
56180
|
-
_isFreshRun ?
|
|
56181
|
-
|
|
56182
|
-
|
|
56307
|
+
_isFreshRun ? TddPromptBuilder.buildForRole("test-writer", ctx.workdir, ctx.config, ctx.story, tddOpts) : Promise.resolve(""),
|
|
56308
|
+
TddPromptBuilder.buildForRole("implementer", ctx.workdir, ctx.config, ctx.story, tddOpts),
|
|
56309
|
+
TddPromptBuilder.buildForRole("verifier", ctx.workdir, ctx.config, ctx.story, tddOpts)
|
|
56183
56310
|
]) : ["", ctx.prompt, ""];
|
|
56184
56311
|
const testWriterInput = _isTdd && _isFreshRun ? {
|
|
56185
56312
|
story,
|
|
@@ -56671,10 +56798,12 @@ async function decideStageAction(ctx, planResult, inspection, opts) {
|
|
|
56671
56798
|
logger.error("execution", "Rectification exhausted with unfixed findings", {
|
|
56672
56799
|
storyId: ctx.story.id,
|
|
56673
56800
|
findingsCount: planResult.unfixedFindings.length,
|
|
56674
|
-
findingSources
|
|
56801
|
+
findingSources,
|
|
56802
|
+
...planResult.unresolvedDetail ? { unresolvedDetail: planResult.unresolvedDetail } : {}
|
|
56675
56803
|
});
|
|
56676
56804
|
await cleanupSessionOnFailure(ctx);
|
|
56677
|
-
|
|
56805
|
+
const exhaustedReason = planResult.unresolvedDetail ? `Rectification exhausted: ${planResult.unresolvedDetail}` : "Rectification exhausted with unfixed findings";
|
|
56806
|
+
return { action: "escalate", reason: exhaustedReason };
|
|
56678
56807
|
}
|
|
56679
56808
|
}
|
|
56680
56809
|
if (selfVerificationFailed) {
|
|
@@ -57165,7 +57294,7 @@ var init_optimizer2 = __esm(() => {
|
|
|
57165
57294
|
async execute(ctx) {
|
|
57166
57295
|
const logger = _optimizerDeps.getLogger();
|
|
57167
57296
|
if (!ctx.prompt) {
|
|
57168
|
-
logger.debug("optimizer", "No prompt to optimize, skipping");
|
|
57297
|
+
logger.debug("optimizer", "No prompt to optimize, skipping", { storyId: ctx.story?.id ?? "unknown" });
|
|
57169
57298
|
return { action: "continue" };
|
|
57170
57299
|
}
|
|
57171
57300
|
const optimizer = resolveOptimizer(ctx.config, ctx.plugins);
|
|
@@ -57178,6 +57307,7 @@ var init_optimizer2 = __esm(() => {
|
|
|
57178
57307
|
ctx.prompt = result.prompt;
|
|
57179
57308
|
const savingsPercent = Math.round(result.savings * 100);
|
|
57180
57309
|
logger.info("optimizer", `${optimizer.name}: ${savingsPercent}% savings`, {
|
|
57310
|
+
storyId: ctx.story?.id ?? "unknown",
|
|
57181
57311
|
originalTokens: result.originalTokens,
|
|
57182
57312
|
optimizedTokens: result.optimizedTokens,
|
|
57183
57313
|
tokensSaved: result.originalTokens - result.optimizedTokens,
|
|
@@ -57250,6 +57380,7 @@ var init_prompt = __esm(() => {
|
|
|
57250
57380
|
ctx.prompt = prompt;
|
|
57251
57381
|
if (isBatch) {
|
|
57252
57382
|
logger.info("prompt", "Batch session prepared", {
|
|
57383
|
+
storyId: "batch",
|
|
57253
57384
|
storyCount: ctx.stories.length,
|
|
57254
57385
|
testStrategy: ctx.routing.testStrategy
|
|
57255
57386
|
});
|
|
@@ -57378,12 +57509,12 @@ var init_queue_check = __esm(() => {
|
|
|
57378
57509
|
}
|
|
57379
57510
|
for (const cmd of queueCommands) {
|
|
57380
57511
|
if (cmd.type === "PAUSE") {
|
|
57381
|
-
logger.warn("queue", "Paused by user", { command: "PAUSE" });
|
|
57512
|
+
logger.warn("queue", "Paused by user", { storyId: ctx.story?.id ?? "unknown", command: "PAUSE" });
|
|
57382
57513
|
await clearQueueFile(ctx.workdir);
|
|
57383
57514
|
return { action: "pause", reason: "User requested pause via .queue.txt" };
|
|
57384
57515
|
}
|
|
57385
57516
|
if (cmd.type === "ABORT") {
|
|
57386
|
-
logger.warn("queue", "Aborting: marking remaining stories as skipped");
|
|
57517
|
+
logger.warn("queue", "Aborting: marking remaining stories as skipped", { storyId: ctx.story?.id ?? "unknown" });
|
|
57387
57518
|
for (const s of ctx.prd.userStories) {
|
|
57388
57519
|
if (s.status === "pending") {
|
|
57389
57520
|
markStorySkipped(ctx.prd, s.id);
|
|
@@ -57978,8 +58109,7 @@ __export(exports_init_context, {
|
|
|
57978
58109
|
initPackage: () => initPackage,
|
|
57979
58110
|
initContext: () => initContext,
|
|
57980
58111
|
generatePackageContextTemplate: () => generatePackageContextTemplate,
|
|
57981
|
-
generateContextTemplate: () => generateContextTemplate
|
|
57982
|
-
_initContextDeps: () => _initContextDeps
|
|
58112
|
+
generateContextTemplate: () => generateContextTemplate
|
|
57983
58113
|
});
|
|
57984
58114
|
import { basename as basename9, join as join52 } from "path";
|
|
57985
58115
|
async function bunFileExists(path14) {
|
|
@@ -58168,39 +58298,6 @@ function generateContextTemplate(scan) {
|
|
|
58168
58298
|
`).trim()}
|
|
58169
58299
|
`;
|
|
58170
58300
|
}
|
|
58171
|
-
async function generateContextWithLLM(scan) {
|
|
58172
|
-
const logger = getLogger();
|
|
58173
|
-
const scanSummary = `
|
|
58174
|
-
Project: ${scan.projectName}
|
|
58175
|
-
Entry Points: ${scan.entryPoints.join(", ") || "None detected"}
|
|
58176
|
-
Config Files: ${scan.configFiles.join(", ") || "None detected"}
|
|
58177
|
-
Total Files: ${scan.fileTree.length}
|
|
58178
|
-
Description: ${scan.packageManifest?.description || "Not provided"}
|
|
58179
|
-
`;
|
|
58180
|
-
const prompt = `
|
|
58181
|
-
You are a technical documentation expert. Generate a concise, well-structured context.md file for a software project based on this scan:
|
|
58182
|
-
|
|
58183
|
-
${scanSummary}
|
|
58184
|
-
|
|
58185
|
-
The context.md should include:
|
|
58186
|
-
1. Project overview (name, purpose, key technologies)
|
|
58187
|
-
2. Entry points and main modules
|
|
58188
|
-
3. Key dependencies and why they're used
|
|
58189
|
-
4. Development setup and common commands
|
|
58190
|
-
5. Architecture overview (brief)
|
|
58191
|
-
6. Development guidelines
|
|
58192
|
-
|
|
58193
|
-
Keep it under 2000 tokens. Use markdown formatting. Be specific to the detected stack and structure.
|
|
58194
|
-
`;
|
|
58195
|
-
try {
|
|
58196
|
-
const result = await _initContextDeps.callLLM(prompt);
|
|
58197
|
-
logger.info("init", "Generated context.md with LLM", { storyId: "init-context" });
|
|
58198
|
-
return result;
|
|
58199
|
-
} catch (err) {
|
|
58200
|
-
logger.warn("init", `LLM context generation failed, falling back to template: ${err instanceof Error ? err.message : String(err)}`, { storyId: "init-context" });
|
|
58201
|
-
return generateContextTemplate(scan);
|
|
58202
|
-
}
|
|
58203
|
-
}
|
|
58204
58301
|
function generatePackageContextTemplate(packagePath) {
|
|
58205
58302
|
const packageName = packagePath.split("/").pop() ?? packagePath;
|
|
58206
58303
|
return `# ${packageName} \u2014 Context
|
|
@@ -58255,26 +58352,15 @@ async function initContext(projectRoot, options = {}) {
|
|
|
58255
58352
|
await bunMkdirp(naxDir);
|
|
58256
58353
|
}
|
|
58257
58354
|
const scan = await scanProject(projectRoot);
|
|
58258
|
-
|
|
58259
|
-
if (options.ai) {
|
|
58260
|
-
content = await generateContextWithLLM(scan);
|
|
58261
|
-
} else {
|
|
58262
|
-
content = generateContextTemplate(scan);
|
|
58263
|
-
}
|
|
58355
|
+
const content = generateContextTemplate(scan);
|
|
58264
58356
|
await Bun.write(contextPath, content);
|
|
58265
58357
|
logger.info("init", "Generated .nax/context.md template from project scan", {
|
|
58266
58358
|
storyId: "init-context",
|
|
58267
58359
|
path: contextPath
|
|
58268
58360
|
});
|
|
58269
58361
|
}
|
|
58270
|
-
var _initContextDeps;
|
|
58271
58362
|
var init_init_context = __esm(() => {
|
|
58272
58363
|
init_logger2();
|
|
58273
|
-
_initContextDeps = {
|
|
58274
|
-
callLLM: async (_prompt) => {
|
|
58275
|
-
throw new Error("callLLM not implemented");
|
|
58276
|
-
}
|
|
58277
|
-
};
|
|
58278
58364
|
});
|
|
58279
58365
|
|
|
58280
58366
|
// src/cli/init-detect.ts
|
|
@@ -58708,7 +58794,7 @@ async function initProject(projectRoot, options) {
|
|
|
58708
58794
|
} else {
|
|
58709
58795
|
logger.info("init", "Project config already exists", { path: configPath });
|
|
58710
58796
|
}
|
|
58711
|
-
await initContext(projectRoot, {
|
|
58797
|
+
await initContext(projectRoot, { force: options?.force });
|
|
58712
58798
|
const constitutionPath = join54(projectDir, "constitution.md");
|
|
58713
58799
|
if (!existsSync23(constitutionPath) || options?.force) {
|
|
58714
58800
|
await Bun.write(constitutionPath, buildConstitution(stack));
|
|
@@ -60700,7 +60786,7 @@ var package_default;
|
|
|
60700
60786
|
var init_package = __esm(() => {
|
|
60701
60787
|
package_default = {
|
|
60702
60788
|
name: "@nathapp/nax",
|
|
60703
|
-
version: "0.70.
|
|
60789
|
+
version: "0.70.4",
|
|
60704
60790
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
60705
60791
|
type: "module",
|
|
60706
60792
|
bin: {
|
|
@@ -60800,8 +60886,8 @@ var init_version = __esm(() => {
|
|
|
60800
60886
|
NAX_VERSION = package_default.version;
|
|
60801
60887
|
NAX_COMMIT = (() => {
|
|
60802
60888
|
try {
|
|
60803
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
60804
|
-
return "
|
|
60889
|
+
if (/^[0-9a-f]{6,10}$/.test("b2d5d046"))
|
|
60890
|
+
return "b2d5d046";
|
|
60805
60891
|
} catch {}
|
|
60806
60892
|
try {
|
|
60807
60893
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -63052,16 +63138,37 @@ ${missing.join(`
|
|
|
63052
63138
|
});
|
|
63053
63139
|
const [exitCode, stderr] = await Promise.all([proc.exited, new Response(proc.stderr).text()]);
|
|
63054
63140
|
if (exitCode !== 0) {
|
|
63055
|
-
throw new
|
|
63141
|
+
throw new NaxError(`Failed to create worktree: ${stderr || "unknown error"}`, "WORKTREE_ERROR", {
|
|
63142
|
+
stage: "worktree",
|
|
63143
|
+
storyId,
|
|
63144
|
+
projectRoot,
|
|
63145
|
+
stderr
|
|
63146
|
+
});
|
|
63056
63147
|
}
|
|
63057
63148
|
} catch (error48) {
|
|
63149
|
+
if (error48 instanceof NaxError) {
|
|
63150
|
+
throw error48;
|
|
63151
|
+
}
|
|
63058
63152
|
if (error48 instanceof Error) {
|
|
63059
63153
|
if (error48.message.includes("not a git repository")) {
|
|
63060
|
-
throw new
|
|
63154
|
+
throw new NaxError(`Not a git repository: ${projectRoot}`, "WORKTREE_ERROR", {
|
|
63155
|
+
stage: "worktree",
|
|
63156
|
+
storyId,
|
|
63157
|
+
projectRoot
|
|
63158
|
+
});
|
|
63061
63159
|
}
|
|
63062
|
-
throw error48
|
|
63160
|
+
throw new NaxError(error48.message, "WORKTREE_ERROR", {
|
|
63161
|
+
stage: "worktree",
|
|
63162
|
+
storyId,
|
|
63163
|
+
projectRoot,
|
|
63164
|
+
cause: error48
|
|
63165
|
+
});
|
|
63063
63166
|
}
|
|
63064
|
-
throw new
|
|
63167
|
+
throw new NaxError(`Failed to create worktree: ${String(error48)}`, "WORKTREE_ERROR", {
|
|
63168
|
+
stage: "worktree",
|
|
63169
|
+
storyId,
|
|
63170
|
+
projectRoot
|
|
63171
|
+
});
|
|
63065
63172
|
}
|
|
63066
63173
|
const envSource = join80(projectRoot, ".env");
|
|
63067
63174
|
if (existsSync31(envSource)) {
|
|
@@ -63070,7 +63177,12 @@ ${missing.join(`
|
|
|
63070
63177
|
symlinkSync(envSource, envTarget, "file");
|
|
63071
63178
|
} catch (error48) {
|
|
63072
63179
|
await this.remove(projectRoot, storyId);
|
|
63073
|
-
throw new
|
|
63180
|
+
throw new NaxError(`Failed to symlink .env: ${errorMessage(error48)}`, "WORKTREE_ERROR", {
|
|
63181
|
+
stage: "worktree",
|
|
63182
|
+
storyId,
|
|
63183
|
+
envSource,
|
|
63184
|
+
envTarget
|
|
63185
|
+
});
|
|
63074
63186
|
}
|
|
63075
63187
|
}
|
|
63076
63188
|
}
|
|
@@ -63087,15 +63199,29 @@ ${missing.join(`
|
|
|
63087
63199
|
const [exitCode, stderr] = await Promise.all([proc.exited, new Response(proc.stderr).text()]);
|
|
63088
63200
|
if (exitCode !== 0) {
|
|
63089
63201
|
if (stderr.includes("not found") || stderr.includes("does not exist") || stderr.includes("no such worktree") || stderr.includes("is not a working tree")) {
|
|
63090
|
-
throw new
|
|
63202
|
+
throw new NaxError(`Worktree not found: ${worktreePath}`, "WORKTREE_ERROR", {
|
|
63203
|
+
stage: "worktree",
|
|
63204
|
+
storyId,
|
|
63205
|
+
worktreePath
|
|
63206
|
+
});
|
|
63091
63207
|
}
|
|
63092
|
-
throw new
|
|
63208
|
+
throw new NaxError(`Failed to remove worktree: ${stderr || "unknown error"}`, "WORKTREE_ERROR", {
|
|
63209
|
+
stage: "worktree",
|
|
63210
|
+
storyId,
|
|
63211
|
+
worktreePath,
|
|
63212
|
+
stderr
|
|
63213
|
+
});
|
|
63093
63214
|
}
|
|
63094
63215
|
} catch (error48) {
|
|
63095
|
-
if (error48 instanceof
|
|
63216
|
+
if (error48 instanceof NaxError) {
|
|
63096
63217
|
throw error48;
|
|
63097
63218
|
}
|
|
63098
|
-
throw new
|
|
63219
|
+
throw new NaxError(error48 instanceof Error ? error48.message : String(error48), "WORKTREE_ERROR", {
|
|
63220
|
+
stage: "worktree",
|
|
63221
|
+
storyId,
|
|
63222
|
+
worktreePath,
|
|
63223
|
+
cause: error48 instanceof Error ? error48 : undefined
|
|
63224
|
+
});
|
|
63099
63225
|
}
|
|
63100
63226
|
try {
|
|
63101
63227
|
const proc = _managerDeps.spawn(["git", "branch", "-D", branchName], {
|
|
@@ -63130,14 +63256,22 @@ ${missing.join(`
|
|
|
63130
63256
|
new Response(proc.stdout).text()
|
|
63131
63257
|
]);
|
|
63132
63258
|
if (exitCode !== 0) {
|
|
63133
|
-
throw new
|
|
63259
|
+
throw new NaxError(`Failed to list worktrees: ${stderr || "unknown error"}`, "WORKTREE_ERROR", {
|
|
63260
|
+
stage: "worktree",
|
|
63261
|
+
projectRoot,
|
|
63262
|
+
stderr
|
|
63263
|
+
});
|
|
63134
63264
|
}
|
|
63135
63265
|
return this.parseWorktreeList(stdout);
|
|
63136
63266
|
} catch (error48) {
|
|
63137
|
-
if (error48 instanceof
|
|
63267
|
+
if (error48 instanceof NaxError) {
|
|
63138
63268
|
throw error48;
|
|
63139
63269
|
}
|
|
63140
|
-
throw new
|
|
63270
|
+
throw new NaxError(error48 instanceof Error ? error48.message : String(error48), "WORKTREE_ERROR", {
|
|
63271
|
+
stage: "worktree",
|
|
63272
|
+
projectRoot,
|
|
63273
|
+
cause: error48 instanceof Error ? error48 : undefined
|
|
63274
|
+
});
|
|
63141
63275
|
}
|
|
63142
63276
|
}
|
|
63143
63277
|
parseWorktreeList(output) {
|
|
@@ -63165,6 +63299,7 @@ ${missing.join(`
|
|
|
63165
63299
|
}
|
|
63166
63300
|
var _managerDeps;
|
|
63167
63301
|
var init_manager3 = __esm(() => {
|
|
63302
|
+
init_errors();
|
|
63168
63303
|
init_logger2();
|
|
63169
63304
|
init_bun_deps();
|
|
63170
63305
|
init_gitignore();
|
|
@@ -65811,17 +65946,24 @@ async function runPrecheckValidation(ctx) {
|
|
|
65811
65946
|
ctx.statusWriter.setRunStatus("precheck-failed");
|
|
65812
65947
|
ctx.statusWriter.setCurrentStory(null);
|
|
65813
65948
|
await ctx.statusWriter.update(0, 0);
|
|
65814
|
-
|
|
65815
|
-
|
|
65816
|
-
|
|
65949
|
+
process.stderr.write(`
|
|
65950
|
+
`);
|
|
65951
|
+
process.stderr.write(`${source_default.red("\u274C PRECHECK FAILED")}
|
|
65952
|
+
`);
|
|
65953
|
+
process.stderr.write(`${source_default.red("\u2500".repeat(60))}
|
|
65954
|
+
`);
|
|
65817
65955
|
for (const blocker of precheckResult.output.blockers) {
|
|
65818
|
-
|
|
65956
|
+
process.stderr.write(`${source_default.red(`\u2717 ${blocker.name}: ${blocker.message}`)}
|
|
65957
|
+
`);
|
|
65819
65958
|
}
|
|
65820
|
-
|
|
65821
|
-
|
|
65822
|
-
|
|
65823
|
-
|
|
65824
|
-
`)
|
|
65959
|
+
process.stderr.write(`${source_default.red("\u2500".repeat(60))}
|
|
65960
|
+
`);
|
|
65961
|
+
process.stderr.write(`${source_default.yellow(`
|
|
65962
|
+
Run 'nax precheck' for detailed information`)}
|
|
65963
|
+
`);
|
|
65964
|
+
process.stderr.write(`${source_default.dim(`Use --skip-precheck to bypass (not recommended)
|
|
65965
|
+
`)}
|
|
65966
|
+
`);
|
|
65825
65967
|
throw new Error(`Precheck failed: ${precheckResult.output.blockers.map((b) => b.name).join(", ")}`);
|
|
65826
65968
|
}
|
|
65827
65969
|
if (precheckResult.output.warnings.length > 0) {
|
|
@@ -65830,12 +65972,15 @@ Run 'nax precheck' for detailed information`));
|
|
|
65830
65972
|
issues: precheckResult.output.warnings.map((w) => w.name)
|
|
65831
65973
|
});
|
|
65832
65974
|
if (ctx.headless && ctx.formatterMode !== "json") {
|
|
65833
|
-
|
|
65834
|
-
\u26A0\uFE0F Precheck warnings:`)
|
|
65975
|
+
process.stdout.write(`${source_default.yellow(`
|
|
65976
|
+
\u26A0\uFE0F Precheck warnings:`)}
|
|
65977
|
+
`);
|
|
65835
65978
|
for (const warning of precheckResult.output.warnings) {
|
|
65836
|
-
|
|
65979
|
+
process.stdout.write(`${source_default.yellow(` \u26A0 ${warning.name}: ${warning.message}`)}
|
|
65980
|
+
`);
|
|
65837
65981
|
}
|
|
65838
|
-
|
|
65982
|
+
process.stdout.write(`
|
|
65983
|
+
`);
|
|
65839
65984
|
}
|
|
65840
65985
|
} else {
|
|
65841
65986
|
logger?.info("precheck", "All precheck validations passed");
|