@nathapp/nax 0.83.6 → 0.83.7
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 +522 -322
- package/package.json +2 -2
package/dist/nax.js
CHANGED
|
@@ -322,6 +322,31 @@ var init_approval_audit = __esm(() => {
|
|
|
322
322
|
init_secret_spans();
|
|
323
323
|
});
|
|
324
324
|
|
|
325
|
+
// ../nax-agent/src/internal/atomic-write.ts
|
|
326
|
+
import { randomUUID } from "crypto";
|
|
327
|
+
import { rename, rm, writeFile } from "fs/promises";
|
|
328
|
+
async function writeFileAtomic(path, content, options = {}) {
|
|
329
|
+
const staged = `${path}.${randomUUID()}.tmp`;
|
|
330
|
+
try {
|
|
331
|
+
await _atomicWriteDeps.writeFile(staged, content, {
|
|
332
|
+
encoding: "utf8",
|
|
333
|
+
...options.mode !== undefined ? { mode: options.mode } : {}
|
|
334
|
+
});
|
|
335
|
+
await _atomicWriteDeps.rename(staged, path);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
await _atomicWriteDeps.rm(staged, { force: true });
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
var _atomicWriteDeps;
|
|
342
|
+
var init_atomic_write = __esm(() => {
|
|
343
|
+
_atomicWriteDeps = {
|
|
344
|
+
writeFile: (path, content, options) => writeFile(path, content, options),
|
|
345
|
+
rename,
|
|
346
|
+
rm
|
|
347
|
+
};
|
|
348
|
+
});
|
|
349
|
+
|
|
325
350
|
// ../nax-agent/src/internal/process-alive.ts
|
|
326
351
|
function isProcessAlive(pid) {
|
|
327
352
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
@@ -335,7 +360,7 @@ function isProcessAlive(pid) {
|
|
|
335
360
|
}
|
|
336
361
|
|
|
337
362
|
// ../nax-agent/src/internal/file-lock.ts
|
|
338
|
-
import { readFile, stat, unlink, writeFile } from "fs/promises";
|
|
363
|
+
import { readFile, stat, unlink, writeFile as writeFile2 } from "fs/promises";
|
|
339
364
|
function unlinkQuiet(path) {
|
|
340
365
|
return _fileLockDeps.unlink(path).catch(() => {});
|
|
341
366
|
}
|
|
@@ -428,7 +453,7 @@ var DEFAULT_RETRY_MS = 10, DEFAULT_TIMEOUT_MS = 5000, EMPTY_LOCK_EVICT_AGE_MS =
|
|
|
428
453
|
var init_file_lock = __esm(() => {
|
|
429
454
|
init_infra();
|
|
430
455
|
_fileLockDeps = {
|
|
431
|
-
writeFile,
|
|
456
|
+
writeFile: writeFile2,
|
|
432
457
|
readFile,
|
|
433
458
|
stat,
|
|
434
459
|
unlink,
|
|
@@ -453,7 +478,7 @@ var init_path_file_lock = __esm(() => {
|
|
|
453
478
|
|
|
454
479
|
// ../nax-agent/src/permissions/approvals-store.ts
|
|
455
480
|
import { createHash } from "crypto";
|
|
456
|
-
import { mkdir as mkdir2, readFile as readFile2, stat as stat2
|
|
481
|
+
import { mkdir as mkdir2, readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
457
482
|
import { dirname, isAbsolute, join as join2, relative, resolve } from "path";
|
|
458
483
|
function approvalsPath(outputDir) {
|
|
459
484
|
return join2(outputDir, "approvals.json");
|
|
@@ -529,14 +554,20 @@ async function readApprovals(path) {
|
|
|
529
554
|
async function writeApprovalsFile(path, file) {
|
|
530
555
|
const body = file.taint === undefined ? { entries: file.entries } : { taint: file.taint, entries: file.entries };
|
|
531
556
|
await mkdir2(dirname(path), { recursive: true });
|
|
532
|
-
await
|
|
533
|
-
|
|
557
|
+
await writeFileAtomic(path, `${JSON.stringify(body, null, 2)}
|
|
558
|
+
`);
|
|
534
559
|
}
|
|
535
560
|
async function appendApproval(path, entry) {
|
|
536
561
|
await mkdir2(dirname(path), { recursive: true });
|
|
537
562
|
await withPathFileLock(path, async () => {
|
|
538
|
-
const
|
|
539
|
-
|
|
563
|
+
const read = await readApprovalsFileDetailed(path);
|
|
564
|
+
if (read.state === "unparseable") {
|
|
565
|
+
throw new NaxError("approvals.json could not be parsed; not rewriting it", "APPROVALS_STORE_UNPARSEABLE", {
|
|
566
|
+
stage: "permissions",
|
|
567
|
+
path
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
await writeApprovalsFile(path, { taint: read.file.taint, entries: [...read.file.entries, entry] });
|
|
540
571
|
});
|
|
541
572
|
}
|
|
542
573
|
async function applyRemoval(path, decide) {
|
|
@@ -587,6 +618,8 @@ function isWithin(projectRoot, root) {
|
|
|
587
618
|
}
|
|
588
619
|
var EMPTY_FILE;
|
|
589
620
|
var init_approvals_store = __esm(() => {
|
|
621
|
+
init_infra();
|
|
622
|
+
init_atomic_write();
|
|
590
623
|
init_path_file_lock();
|
|
591
624
|
EMPTY_FILE = { entries: [], taint: undefined };
|
|
592
625
|
});
|
|
@@ -2212,8 +2245,8 @@ var init_chained_store = __esm(() => {
|
|
|
2212
2245
|
});
|
|
2213
2246
|
|
|
2214
2247
|
// ../nax-agent/src/native/credentials/fingerprint.ts
|
|
2215
|
-
import { createHmac, randomBytes, randomUUID } from "crypto";
|
|
2216
|
-
import { link, mkdir as mkdir4, readFile as readFile3, rm, writeFile as writeFile3 } from "fs/promises";
|
|
2248
|
+
import { createHmac, randomBytes, randomUUID as randomUUID2 } from "crypto";
|
|
2249
|
+
import { link, mkdir as mkdir4, readFile as readFile3, rm as rm2, writeFile as writeFile3 } from "fs/promises";
|
|
2217
2250
|
import { dirname as dirname2, join as join5 } from "path";
|
|
2218
2251
|
function _resetFingerprintSalt() {
|
|
2219
2252
|
memoPath = undefined;
|
|
@@ -2235,7 +2268,7 @@ async function readSaltFile(path) {
|
|
|
2235
2268
|
async function createSaltFile(path) {
|
|
2236
2269
|
await mkdir4(dirname2(path), { recursive: true });
|
|
2237
2270
|
const candidate = randomBytes(SALT_BYTES);
|
|
2238
|
-
const staged = `${path}.${
|
|
2271
|
+
const staged = `${path}.${randomUUID2()}.staged`;
|
|
2239
2272
|
try {
|
|
2240
2273
|
await writeFile3(staged, candidate, { mode: 384 });
|
|
2241
2274
|
try {
|
|
@@ -2247,7 +2280,7 @@ async function createSaltFile(path) {
|
|
|
2247
2280
|
}
|
|
2248
2281
|
return candidate;
|
|
2249
2282
|
} finally {
|
|
2250
|
-
await
|
|
2283
|
+
await rm2(staged, { force: true });
|
|
2251
2284
|
}
|
|
2252
2285
|
}
|
|
2253
2286
|
async function loadSalt(path) {
|
|
@@ -3170,11 +3203,16 @@ async function importPiCredentials(options) {
|
|
|
3170
3203
|
cause: error
|
|
3171
3204
|
});
|
|
3172
3205
|
}
|
|
3206
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
3207
|
+
throw new NaxError(`The file at ${path} is not a provider credential map.`, "AUTH_IMPORT_SOURCE_UNREADABLE", {
|
|
3208
|
+
path
|
|
3209
|
+
});
|
|
3210
|
+
}
|
|
3173
3211
|
const store = naxCredentialStore();
|
|
3174
3212
|
const outcomes = [];
|
|
3175
3213
|
for (const providerId of Object.keys(parsed).sort()) {
|
|
3176
3214
|
const entry = parsed[providerId];
|
|
3177
|
-
const credential = entry ===
|
|
3215
|
+
const credential = typeof entry === "object" && entry !== null ? fromPiEntry(entry) : undefined;
|
|
3178
3216
|
if (credential === undefined) {
|
|
3179
3217
|
outcomes.push({ providerId, status: "unsupported" });
|
|
3180
3218
|
continue;
|
|
@@ -3543,12 +3581,12 @@ var init_errors = __esm(() => {
|
|
|
3543
3581
|
});
|
|
3544
3582
|
|
|
3545
3583
|
// ../nax-agent/src/native/session-affinity.ts
|
|
3546
|
-
import { createHash as createHash3, randomUUID as
|
|
3584
|
+
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
3547
3585
|
function nativeSessionId(sessionKey) {
|
|
3548
3586
|
return createHash3("sha256").update(sessionKey).digest("hex").slice(0, ID_LENGTH);
|
|
3549
3587
|
}
|
|
3550
3588
|
function newSessionKey() {
|
|
3551
|
-
return
|
|
3589
|
+
return randomUUID3();
|
|
3552
3590
|
}
|
|
3553
3591
|
var ID_LENGTH = 32;
|
|
3554
3592
|
var init_session_affinity = () => {};
|
|
@@ -3728,7 +3766,7 @@ __export(exports_transcript_store, {
|
|
|
3728
3766
|
transcriptModelIdentity: () => transcriptModelIdentity,
|
|
3729
3767
|
transcriptPath: () => transcriptPath
|
|
3730
3768
|
});
|
|
3731
|
-
import { mkdir as mkdir5, readdir, readFile as readFile6, rename, rm as
|
|
3769
|
+
import { mkdir as mkdir5, readdir, readFile as readFile6, rename as rename2, rm as rm3, stat as stat3 } from "fs/promises";
|
|
3732
3770
|
import { join as join9 } from "path";
|
|
3733
3771
|
function transcriptPath(dir, sessionName) {
|
|
3734
3772
|
return join9(dir, `${sessionName}.transcript.json`);
|
|
@@ -3762,7 +3800,7 @@ async function readTranscriptDoc(dir, sessionName) {
|
|
|
3762
3800
|
}
|
|
3763
3801
|
async function writeTranscriptDoc(dir, sessionName, doc) {
|
|
3764
3802
|
await mkdir5(dir, { recursive: true });
|
|
3765
|
-
await
|
|
3803
|
+
await writeFileAtomic(transcriptPath(dir, sessionName), JSON.stringify(doc, null, 2));
|
|
3766
3804
|
}
|
|
3767
3805
|
function createFileTranscriptStore(dir) {
|
|
3768
3806
|
return {
|
|
@@ -3789,7 +3827,7 @@ async function saveTranscript(dir, sessionName, messages, identity = {}) {
|
|
|
3789
3827
|
async function retainTranscript(dir, sessionName) {
|
|
3790
3828
|
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
3791
3829
|
try {
|
|
3792
|
-
await
|
|
3830
|
+
await rename2(transcriptPath(dir, sessionName), join9(dir, `${sessionName}.transcript.failed-${stamp}.json`));
|
|
3793
3831
|
} catch (err) {
|
|
3794
3832
|
if (err.code === "ENOENT")
|
|
3795
3833
|
return;
|
|
@@ -3797,7 +3835,7 @@ async function retainTranscript(dir, sessionName) {
|
|
|
3797
3835
|
}
|
|
3798
3836
|
}
|
|
3799
3837
|
async function deleteTranscript(dir, sessionName) {
|
|
3800
|
-
await
|
|
3838
|
+
await rm3(transcriptPath(dir, sessionName), { force: true });
|
|
3801
3839
|
}
|
|
3802
3840
|
function _resetTranscriptTruncationWarningForTests() {
|
|
3803
3841
|
hasWarnedAboutTranscriptTruncation = false;
|
|
@@ -3821,7 +3859,7 @@ async function pruneRetainedTranscripts(dir, maxRetained = MAX_RETAINED_TRANSCRI
|
|
|
3821
3859
|
}));
|
|
3822
3860
|
withMtimes.sort((a, b) => a.mtimeMs - b.mtimeMs);
|
|
3823
3861
|
const toDelete = withMtimes.slice(0, withMtimes.length - maxRetained);
|
|
3824
|
-
await Promise.all(toDelete.map((f) =>
|
|
3862
|
+
await Promise.all(toDelete.map((f) => rm3(f.path, { force: true })));
|
|
3825
3863
|
if (!hasWarnedAboutTranscriptTruncation) {
|
|
3826
3864
|
hasWarnedAboutTranscriptTruncation = true;
|
|
3827
3865
|
getLogger().warn("native-session", "Transcript retention cap reached \u2014 oldest kept-on-failure transcripts pruned", {
|
|
@@ -3835,6 +3873,7 @@ async function pruneRetainedTranscripts(dir, maxRetained = MAX_RETAINED_TRANSCRI
|
|
|
3835
3873
|
var LEGACY_SAVED_AT, MAX_RETAINED_TRANSCRIPTS = 50, hasWarnedAboutTranscriptTruncation = false;
|
|
3836
3874
|
var init_transcript_store = __esm(() => {
|
|
3837
3875
|
init_infra();
|
|
3876
|
+
init_atomic_write();
|
|
3838
3877
|
init_transcript_identity();
|
|
3839
3878
|
init_transcript_identity();
|
|
3840
3879
|
LEGACY_SAVED_AT = new Date(0).toISOString();
|
|
@@ -19554,7 +19593,7 @@ var init_schemas_sandbox = __esm(() => {
|
|
|
19554
19593
|
});
|
|
19555
19594
|
|
|
19556
19595
|
// ../nax-agent/src/sandbox/git-guards.ts
|
|
19557
|
-
import { lstat, readdir as readdir2, readFile as readFile7, rm as
|
|
19596
|
+
import { lstat, readdir as readdir2, readFile as readFile7, rm as rm4 } from "fs/promises";
|
|
19558
19597
|
import { basename as basename2, dirname as dirname7, isAbsolute as isAbsolute3, join as join11, resolve as resolve8 } from "path";
|
|
19559
19598
|
function commonDirOf(git) {
|
|
19560
19599
|
if (git.kind === "none")
|
|
@@ -19640,7 +19679,7 @@ var init_git_guards = __esm(() => {
|
|
|
19640
19679
|
}
|
|
19641
19680
|
},
|
|
19642
19681
|
readText: (p) => readFile7(p, "utf8"),
|
|
19643
|
-
remove: (p) =>
|
|
19682
|
+
remove: (p) => rm4(p, { recursive: true, force: true })
|
|
19644
19683
|
};
|
|
19645
19684
|
});
|
|
19646
19685
|
|
|
@@ -19671,7 +19710,7 @@ var init_messages = __esm(() => {
|
|
|
19671
19710
|
});
|
|
19672
19711
|
|
|
19673
19712
|
// ../nax-agent/src/sandbox/launcher.ts
|
|
19674
|
-
import { randomUUID as
|
|
19713
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
19675
19714
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
19676
19715
|
function logicalArgv(req) {
|
|
19677
19716
|
return req.spec.kind === "shell" ? [req.spec.shell, "-c", req.spec.command] : req.spec.argv;
|
|
@@ -19800,7 +19839,7 @@ var init_launcher = __esm(() => {
|
|
|
19800
19839
|
DISABLED_SANDBOX_STATE = { kind: "disabled" };
|
|
19801
19840
|
_launcherDeps = {
|
|
19802
19841
|
runArgv,
|
|
19803
|
-
newCommandId: () =>
|
|
19842
|
+
newCommandId: () => randomUUID4(),
|
|
19804
19843
|
mkdir: (path) => mkdir6(path, { recursive: true }).then(() => {
|
|
19805
19844
|
return;
|
|
19806
19845
|
})
|
|
@@ -19937,9 +19976,12 @@ function hardenedGitEnv(base) {
|
|
|
19937
19976
|
function gitSpawnEnv(overlay) {
|
|
19938
19977
|
return hardenedGitEnv(overlay === undefined ? process.env : { ...process.env, ...overlay });
|
|
19939
19978
|
}
|
|
19979
|
+
function isGitProgram(token) {
|
|
19980
|
+
return token === "git" || (token?.endsWith("/git") ?? false);
|
|
19981
|
+
}
|
|
19940
19982
|
function hardenedGitArgv(argv) {
|
|
19941
19983
|
const out = [...argv];
|
|
19942
|
-
let i = 1;
|
|
19984
|
+
let i = !isGitProgram(out[0]) && isGitProgram(out[1]) ? 2 : 1;
|
|
19943
19985
|
while (i < out.length && out[i].startsWith("-")) {
|
|
19944
19986
|
i += GLOBAL_OPTIONS_WITH_VALUE.has(out[i]) ? 2 : 1;
|
|
19945
19987
|
}
|
|
@@ -20282,6 +20324,8 @@ function isUsableSharedParent() {
|
|
|
20282
20324
|
const stats = _sessionTmpDeps.lstat(SHARED_TMP_PARENT);
|
|
20283
20325
|
if (!stats.isDirectory() || stats.isSymbolicLink())
|
|
20284
20326
|
return false;
|
|
20327
|
+
if (stats.uid !== _sessionTmpDeps.uid())
|
|
20328
|
+
return false;
|
|
20285
20329
|
} catch (err) {
|
|
20286
20330
|
return err.code === "ENOENT";
|
|
20287
20331
|
}
|
|
@@ -20735,7 +20779,7 @@ var init_edit_region = __esm(() => {
|
|
|
20735
20779
|
});
|
|
20736
20780
|
|
|
20737
20781
|
// ../nax-agent/src/tools/edit.ts
|
|
20738
|
-
import { readFile as readFile8, stat as stat5, writeFile as
|
|
20782
|
+
import { readFile as readFile8, stat as stat5, writeFile as writeFile4 } from "fs/promises";
|
|
20739
20783
|
function countOccurrences(haystack, needle) {
|
|
20740
20784
|
if (needle === "")
|
|
20741
20785
|
return 0;
|
|
@@ -20753,7 +20797,7 @@ var init_edit = __esm(() => {
|
|
|
20753
20797
|
_editDeps = {
|
|
20754
20798
|
stat: (path) => stat5(path),
|
|
20755
20799
|
readFile: (path, encoding) => readFile8(path, encoding),
|
|
20756
|
-
writeFile: (path, data, encoding) =>
|
|
20800
|
+
writeFile: (path, data, encoding) => writeFile4(path, data, encoding)
|
|
20757
20801
|
};
|
|
20758
20802
|
editTool = {
|
|
20759
20803
|
name: "Edit",
|
|
@@ -23713,7 +23757,7 @@ var init_denial_redirect = __esm(() => {
|
|
|
23713
23757
|
});
|
|
23714
23758
|
|
|
23715
23759
|
// ../nax-agent/src/tools/runtime-calltool.ts
|
|
23716
|
-
import { randomUUID as
|
|
23760
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
23717
23761
|
function resolvePolicyIdentity(name, tool, input) {
|
|
23718
23762
|
const argvField = tool.scope.argvField;
|
|
23719
23763
|
const hasArgv = argvField !== undefined && input[argvField] !== undefined;
|
|
@@ -23724,7 +23768,7 @@ function openCallShadowTap(p) {
|
|
|
23724
23768
|
if (p.shadow === undefined)
|
|
23725
23769
|
return;
|
|
23726
23770
|
return openShadowTap(p.shadow, {
|
|
23727
|
-
key:
|
|
23771
|
+
key: randomUUID5(),
|
|
23728
23772
|
identity: p.identity,
|
|
23729
23773
|
command: p.tool.scope.commandField === undefined ? undefined : p.input[p.tool.scope.commandField],
|
|
23730
23774
|
argv: p.hasArgv && p.argvField !== undefined ? p.input[p.argvField] : undefined,
|
|
@@ -23855,7 +23899,7 @@ var init_runtime_calltool = __esm(() => {
|
|
|
23855
23899
|
|
|
23856
23900
|
// ../nax-agent/src/tools/scratchpad.ts
|
|
23857
23901
|
import { existsSync as existsSync2 } from "fs";
|
|
23858
|
-
import { mkdir as mkdir8, writeFile as
|
|
23902
|
+
import { mkdir as mkdir8, writeFile as writeFile5 } from "fs/promises";
|
|
23859
23903
|
import { dirname as dirname8, join as join18, sep as sep10 } from "path";
|
|
23860
23904
|
var SCRATCHPAD_DIR = ".nax/scratchpad", MAX_MATCHES2 = 500, scratchpadWriteTool, scratchpadReadTool, scratchpadListTool;
|
|
23861
23905
|
var init_scratchpad = __esm(() => {
|
|
@@ -23893,7 +23937,7 @@ var init_scratchpad = __esm(() => {
|
|
|
23893
23937
|
}
|
|
23894
23938
|
try {
|
|
23895
23939
|
await mkdir8(dirname8(target), { recursive: true });
|
|
23896
|
-
await
|
|
23940
|
+
await writeFile5(target, content, "utf8");
|
|
23897
23941
|
return { content: `wrote ${size} bytes` };
|
|
23898
23942
|
} catch (err) {
|
|
23899
23943
|
return { content: err instanceof Error ? err.message : String(err), isError: true };
|
|
@@ -23985,7 +24029,7 @@ ${content}`, resultBytesPreTruncation: fullBytes };
|
|
|
23985
24029
|
});
|
|
23986
24030
|
|
|
23987
24031
|
// ../nax-agent/src/tools/spill.ts
|
|
23988
|
-
import { mkdir as mkdir9, writeFile as
|
|
24032
|
+
import { mkdir as mkdir9, writeFile as writeFile6 } from "fs/promises";
|
|
23989
24033
|
import { dirname as dirname9, join as join19 } from "path";
|
|
23990
24034
|
function fileSafe(value) {
|
|
23991
24035
|
return value.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
@@ -24111,14 +24155,14 @@ var init_spill = __esm(() => {
|
|
|
24111
24155
|
_spillDeps = {
|
|
24112
24156
|
mkdir: (path) => mkdir9(path, { recursive: true }),
|
|
24113
24157
|
writeFile: async (path, data) => {
|
|
24114
|
-
await
|
|
24158
|
+
await writeFile6(path, data, "utf8");
|
|
24115
24159
|
return Buffer.byteLength(data);
|
|
24116
24160
|
}
|
|
24117
24161
|
};
|
|
24118
24162
|
});
|
|
24119
24163
|
|
|
24120
24164
|
// ../nax-agent/src/tools/tool-audit.ts
|
|
24121
|
-
import { mkdir as mkdir10, writeFile as
|
|
24165
|
+
import { mkdir as mkdir10, writeFile as writeFile7 } from "fs/promises";
|
|
24122
24166
|
import { join as join20 } from "path";
|
|
24123
24167
|
function registerToolAuditSink(runId, sink) {
|
|
24124
24168
|
const sinks = openToolAuditSinks.get(runId);
|
|
@@ -24173,7 +24217,7 @@ function createToolAuditSink(opts) {
|
|
|
24173
24217
|
calls: redactRowStrings(calls)
|
|
24174
24218
|
}, null, 2);
|
|
24175
24219
|
const prefix = runId !== undefined ? `${runId}-` : "";
|
|
24176
|
-
await
|
|
24220
|
+
await writeFile7(join20(opts.dir, `${prefix}${nextFileStamp()}-${opts.sessionName}.json`), body);
|
|
24177
24221
|
};
|
|
24178
24222
|
const sink = {
|
|
24179
24223
|
record(entry) {
|
|
@@ -24214,7 +24258,7 @@ var init_tool_audit = __esm(() => {
|
|
|
24214
24258
|
});
|
|
24215
24259
|
|
|
24216
24260
|
// ../nax-agent/src/tools/write.ts
|
|
24217
|
-
import { mkdir as mkdir11, writeFile as
|
|
24261
|
+
import { mkdir as mkdir11, writeFile as writeFile8 } from "fs/promises";
|
|
24218
24262
|
import { dirname as dirname10 } from "path";
|
|
24219
24263
|
var writeTool;
|
|
24220
24264
|
var init_write = __esm(() => {
|
|
@@ -24246,7 +24290,7 @@ var init_write = __esm(() => {
|
|
|
24246
24290
|
}
|
|
24247
24291
|
try {
|
|
24248
24292
|
await mkdir11(dirname10(target), { recursive: true });
|
|
24249
|
-
await
|
|
24293
|
+
await writeFile8(target, content, "utf8");
|
|
24250
24294
|
return { content: `wrote ${Buffer.byteLength(content, "utf8")} bytes` };
|
|
24251
24295
|
} catch (err) {
|
|
24252
24296
|
return { content: err instanceof Error ? err.message : String(err), isError: true };
|
|
@@ -24256,7 +24300,7 @@ var init_write = __esm(() => {
|
|
|
24256
24300
|
});
|
|
24257
24301
|
|
|
24258
24302
|
// ../nax-agent/src/tools/runtime.ts
|
|
24259
|
-
import { randomUUID as
|
|
24303
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
24260
24304
|
function registerBuiltinCodingTools() {
|
|
24261
24305
|
if (builtinsRegistered)
|
|
24262
24306
|
return;
|
|
@@ -24340,7 +24384,7 @@ function createCodingToolRuntime(opts) {
|
|
|
24340
24384
|
return body;
|
|
24341
24385
|
return applyModelTruncationPolicy(body, {
|
|
24342
24386
|
toolName,
|
|
24343
|
-
callId: context?.toolCallId ??
|
|
24387
|
+
callId: context?.toolCallId ?? randomUUID6(),
|
|
24344
24388
|
root: opts.policy.root,
|
|
24345
24389
|
maxBytes
|
|
24346
24390
|
});
|
|
@@ -25516,7 +25560,6 @@ async function runModelRoundTrip(state, params, summarizeFailed) {
|
|
|
25516
25560
|
}
|
|
25517
25561
|
state.roundTrips += 1;
|
|
25518
25562
|
params.usage.add(res.usage, res.costUsd, res.rates);
|
|
25519
|
-
state.output = res.text;
|
|
25520
25563
|
const promptTokens = inputClassTokens(res.usage);
|
|
25521
25564
|
state.lastUsage = { promptTokens };
|
|
25522
25565
|
state.anchorIndex = state.messages.length - 1;
|
|
@@ -25544,6 +25587,7 @@ async function runModelRoundTrip(state, params, summarizeFailed) {
|
|
|
25544
25587
|
roundTrip: state.roundTrips
|
|
25545
25588
|
});
|
|
25546
25589
|
const assistantText = afterResponse.text ?? res.text;
|
|
25590
|
+
state.output = assistantText;
|
|
25547
25591
|
const assistantToolCalls = afterResponse.toolCalls ?? res.toolCalls;
|
|
25548
25592
|
const assistantThinking = afterResponse.thinking ?? res.thinking;
|
|
25549
25593
|
state.messages.push({
|
|
@@ -25910,7 +25954,7 @@ async function streamComplete(client, model, req, onDelta) {
|
|
|
25910
25954
|
var init_stream_complete = () => {};
|
|
25911
25955
|
|
|
25912
25956
|
// ../nax-agent/src/native/session-adapter.ts
|
|
25913
|
-
import { randomUUID as
|
|
25957
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
25914
25958
|
function summaryPrompt(previousSummary) {
|
|
25915
25959
|
const base = "Summarize the conversation above so it can be dropped from context. " + "Record what was attempted, what was rejected and why, any decisions that still bind, " + "and list the files read and the files modified. Be specific: this summary is the only " + "memory of this work that survives.";
|
|
25916
25960
|
if (previousSummary === undefined)
|
|
@@ -25998,7 +26042,7 @@ class NativeSessionAdapter {
|
|
|
25998
26042
|
const instructionInteraction = createInstructionInteraction(this.state.repositoryInstructions.get(handle.id), opts.interactionHandler);
|
|
25999
26043
|
const deadline = createTurnDeadline(timeoutSeconds);
|
|
26000
26044
|
const hooks = this.state.streamHooks.get(handle.id);
|
|
26001
|
-
const callId =
|
|
26045
|
+
const callId = randomUUID7();
|
|
26002
26046
|
const owner = this.state.transcriptOwners.get(handle.id);
|
|
26003
26047
|
const eventBase = {
|
|
26004
26048
|
callId,
|
|
@@ -26194,8 +26238,8 @@ var init_native = __esm(() => {
|
|
|
26194
26238
|
});
|
|
26195
26239
|
|
|
26196
26240
|
// ../nax-agent/src/session/agent-session-deps.ts
|
|
26197
|
-
import { randomUUID as
|
|
26198
|
-
import { mkdtemp, rm as
|
|
26241
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
26242
|
+
import { mkdtemp, rm as rm5, stat as stat6 } from "fs/promises";
|
|
26199
26243
|
import { tmpdir as tmpdir4 } from "os";
|
|
26200
26244
|
import { join as join21 } from "path";
|
|
26201
26245
|
var MAX_UNDELIVERED_CONTROL_EVENTS = 1000, _agentSessionDeps;
|
|
@@ -26204,7 +26248,7 @@ var init_agent_session_deps = __esm(() => {
|
|
|
26204
26248
|
now: () => Date.now(),
|
|
26205
26249
|
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
26206
26250
|
clearTimeout: (handle) => clearTimeout(handle),
|
|
26207
|
-
randomUUID: () =>
|
|
26251
|
+
randomUUID: () => randomUUID8(),
|
|
26208
26252
|
isDirectory: async (path) => {
|
|
26209
26253
|
try {
|
|
26210
26254
|
return (await stat6(path)).isDirectory();
|
|
@@ -26213,7 +26257,7 @@ var init_agent_session_deps = __esm(() => {
|
|
|
26213
26257
|
}
|
|
26214
26258
|
},
|
|
26215
26259
|
makeScratchRoot: () => mkdtemp(join21(tmpdir4(), "nax-agent-session-")),
|
|
26216
|
-
removeScratchRoot: (dir) =>
|
|
26260
|
+
removeScratchRoot: (dir) => rm5(dir, { recursive: true, force: true }),
|
|
26217
26261
|
controlEventCap: MAX_UNDELIVERED_CONTROL_EVENTS
|
|
26218
26262
|
};
|
|
26219
26263
|
});
|
|
@@ -29273,7 +29317,7 @@ function commandSpecIncludes(spec, fragment) {
|
|
|
29273
29317
|
return normalizeCommandSpec(spec).some((entry) => entry.includes(fragment));
|
|
29274
29318
|
}
|
|
29275
29319
|
function replaceInCommandSpec(spec, searchValue, replacement) {
|
|
29276
|
-
const replace = (command) => command.replaceAll(searchValue, replacement);
|
|
29320
|
+
const replace = (command) => command.replaceAll(searchValue, () => replacement);
|
|
29277
29321
|
return typeof spec === "string" ? replace(spec) : spec.map(replace);
|
|
29278
29322
|
}
|
|
29279
29323
|
function renderCommandSpec(spec) {
|
|
@@ -29352,6 +29396,7 @@ __export(exports_internal, {
|
|
|
29352
29396
|
_agentSessionDeps: () => _agentSessionDeps,
|
|
29353
29397
|
_approvalsTaintDeps: () => _approvalsTaintDeps,
|
|
29354
29398
|
_argvExecDeps: () => _argvExecDeps,
|
|
29399
|
+
_atomicWriteDeps: () => _atomicWriteDeps,
|
|
29355
29400
|
_authDeps: () => _authDeps,
|
|
29356
29401
|
_bashToolDeps: () => _bashToolDeps,
|
|
29357
29402
|
_clientDeps: () => _clientDeps,
|
|
@@ -29632,6 +29677,7 @@ __export(exports_internal, {
|
|
|
29632
29677
|
withPathFileLock: () => withPathFileLock,
|
|
29633
29678
|
wrapExternalHandler: () => wrapExternalHandler,
|
|
29634
29679
|
writeApprovalsFile: () => writeApprovalsFile,
|
|
29680
|
+
writeFileAtomic: () => writeFileAtomic,
|
|
29635
29681
|
writeSpill: () => writeSpill,
|
|
29636
29682
|
writeTool: () => writeTool
|
|
29637
29683
|
});
|
|
@@ -29662,6 +29708,7 @@ var init_internal = __esm(() => {
|
|
|
29662
29708
|
init_spin_breaker();
|
|
29663
29709
|
init_agent_output_env();
|
|
29664
29710
|
init_argv_exec();
|
|
29711
|
+
init_atomic_write();
|
|
29665
29712
|
init_file_lock();
|
|
29666
29713
|
init_git_env();
|
|
29667
29714
|
init_git_exec();
|
|
@@ -31022,7 +31069,7 @@ var init_inert_bash_stages = __esm(() => {
|
|
|
31022
31069
|
|
|
31023
31070
|
// src/utils/json-file.ts
|
|
31024
31071
|
import { existsSync as existsSync5 } from "fs";
|
|
31025
|
-
import { rename as
|
|
31072
|
+
import { rename as rename3, unlink as unlink3 } from "fs/promises";
|
|
31026
31073
|
async function loadJsonFile(path, context = "json-file") {
|
|
31027
31074
|
if (!existsSync5(path)) {
|
|
31028
31075
|
return null;
|
|
@@ -31057,7 +31104,7 @@ async function atomicWriteText(path, content, context = "json-file") {
|
|
|
31057
31104
|
const tmpPath = `${path}.tmp-${crypto.randomUUID()}`;
|
|
31058
31105
|
try {
|
|
31059
31106
|
await Bun.write(tmpPath, content);
|
|
31060
|
-
await
|
|
31107
|
+
await rename3(tmpPath, path);
|
|
31061
31108
|
} catch (err) {
|
|
31062
31109
|
await unlink3(tmpPath).catch(() => {});
|
|
31063
31110
|
const logger = getLogger2();
|
|
@@ -31370,6 +31417,12 @@ function _applyFinishAutoFlowShim(conf, warn = defaultConfigWarn) {
|
|
|
31370
31417
|
}
|
|
31371
31418
|
return { ...conf, finish: { ...lifted, ...explicitFinish } };
|
|
31372
31419
|
}
|
|
31420
|
+
function _applyTddStrategyAliasShim(conf) {
|
|
31421
|
+
const tdd = conf.tdd;
|
|
31422
|
+
if (!tdd || typeof tdd !== "object" || tdd.strategy !== "tdd-simple")
|
|
31423
|
+
return conf;
|
|
31424
|
+
return { ...conf, tdd: { ...tdd, strategy: "simple" } };
|
|
31425
|
+
}
|
|
31373
31426
|
function applyConfigCompatShims(conf, logger, dedupe) {
|
|
31374
31427
|
const log = dedupe.wrapLogger(logger);
|
|
31375
31428
|
const warn = dedupe.warn;
|
|
@@ -31386,6 +31439,7 @@ function applyConfigCompatShims(conf, logger, dedupe) {
|
|
|
31386
31439
|
out = _applyFinishAutoFlowShim(out, warn);
|
|
31387
31440
|
out = _applyRemovedOptimizerKeysShim(out, warn);
|
|
31388
31441
|
out = _applyRemovedCrossPackageDepthShim(out, warn);
|
|
31442
|
+
out = _applyTddStrategyAliasShim(out);
|
|
31389
31443
|
return out;
|
|
31390
31444
|
}
|
|
31391
31445
|
var SECURITY_SENSITIVE_KEY_PATHS, REMOVED_FINISH_KEYS;
|
|
@@ -32913,7 +32967,7 @@ var init_schemas_execution = __esm(() => {
|
|
|
32913
32967
|
});
|
|
32914
32968
|
TddConfigSchema = exports_external.object({
|
|
32915
32969
|
maxRetries: exports_external.number().int().nonnegative(),
|
|
32916
|
-
strategy: exports_external.enum(["auto", "strict", "lite", "off"]).default("auto"),
|
|
32970
|
+
strategy: exports_external.enum(["auto", "strict", "lite", "simple", "off"]).default("auto"),
|
|
32917
32971
|
sessionTiers: exports_external.object({
|
|
32918
32972
|
testWriter: ConfiguredModelSchema.default("fast"),
|
|
32919
32973
|
verifier: ConfiguredModelSchema.default("fast"),
|
|
@@ -36201,18 +36255,20 @@ var init_spec_structure_grammar = __esm(() => {
|
|
|
36201
36255
|
function declaredStoryIds(lines) {
|
|
36202
36256
|
const ids = new Set;
|
|
36203
36257
|
let inScope = false;
|
|
36204
|
-
let
|
|
36258
|
+
let skipLevel = 0;
|
|
36205
36259
|
for (const line of lines) {
|
|
36206
36260
|
if (/^##\s/.test(line)) {
|
|
36207
36261
|
inScope = /^##\s+(Stories|Acceptance Criteria)\b/i.test(line);
|
|
36208
|
-
|
|
36262
|
+
skipLevel = 0;
|
|
36209
36263
|
continue;
|
|
36210
36264
|
}
|
|
36211
36265
|
if (!inScope)
|
|
36212
36266
|
continue;
|
|
36213
|
-
|
|
36214
|
-
|
|
36215
|
-
|
|
36267
|
+
const level = /^(#{3,6})\s/.exec(line)?.[1]?.length;
|
|
36268
|
+
if (level !== undefined && (skipLevel === 0 || level <= skipLevel)) {
|
|
36269
|
+
skipLevel = GROUPED_PATH_SUBSECTION.test(line) ? level : 0;
|
|
36270
|
+
}
|
|
36271
|
+
if (skipLevel > 0)
|
|
36216
36272
|
continue;
|
|
36217
36273
|
const heading = /^#{1,6}\s+(US-\d+)\b/i.exec(line);
|
|
36218
36274
|
if (heading?.[1]) {
|
|
@@ -38089,11 +38145,15 @@ import path2 from "path";
|
|
|
38089
38145
|
async function acceptCommand(options) {
|
|
38090
38146
|
const logger = getLogger2();
|
|
38091
38147
|
const { feature, override, reason } = options;
|
|
38092
|
-
|
|
38093
|
-
|
|
38094
|
-
|
|
38095
|
-
|
|
38096
|
-
|
|
38148
|
+
const expected = "AC-1, or <package>::AC-1 (package path relative to the repo root)";
|
|
38149
|
+
const match = /^(?:(.+)::)?(AC-\d+)$/i.exec(override);
|
|
38150
|
+
const pkg = match?.[1];
|
|
38151
|
+
const ac = match?.[2];
|
|
38152
|
+
if (!ac || pkg === "") {
|
|
38153
|
+
logger.error("cli", "Invalid AC ID format", { override, expected });
|
|
38154
|
+
throw new NaxError("Invalid AC ID format", "INVALID_AC_ID", { override, expected });
|
|
38155
|
+
}
|
|
38156
|
+
const acId = pkg === undefined ? ac.toUpperCase() : `${pkg}::${ac.toUpperCase()}`;
|
|
38097
38157
|
const projectDirResult = findProjectDir(process.cwd());
|
|
38098
38158
|
if (!projectDirResult) {
|
|
38099
38159
|
logger.error("cli", "Not in a nax project directory", { hint: "Run 'nax init' first" });
|
|
@@ -38494,7 +38554,7 @@ var package_default;
|
|
|
38494
38554
|
var init_package = __esm(() => {
|
|
38495
38555
|
package_default = {
|
|
38496
38556
|
name: "@nathapp/nax",
|
|
38497
|
-
version: "0.83.
|
|
38557
|
+
version: "0.83.7",
|
|
38498
38558
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
38499
38559
|
type: "module",
|
|
38500
38560
|
bin: {
|
|
@@ -38552,7 +38612,7 @@ var init_package = __esm(() => {
|
|
|
38552
38612
|
"test:unit": "bun test ./test/unit/ --timeout=60000",
|
|
38553
38613
|
"test:integration": "bun test ./test/integration/ --timeout=60000",
|
|
38554
38614
|
"test:ui": "bun test ./test/ui/ --timeout=60000",
|
|
38555
|
-
"test:e2e": "
|
|
38615
|
+
"test:e2e": "bun run scripts/run-tests.ts --e2e",
|
|
38556
38616
|
"test:coverage": "bun run ../repo-tooling/scripts/check-coverage.ts --require-all-files",
|
|
38557
38617
|
"test:coverage:report": "bun run ../repo-tooling/scripts/check-coverage.ts --require-all-files --report",
|
|
38558
38618
|
"test:coverage:update": "bun run ../repo-tooling/scripts/check-coverage.ts --require-all-files --update-baseline",
|
|
@@ -39781,19 +39841,24 @@ function isTestFileByPatterns(filePath2, patterns) {
|
|
|
39781
39841
|
}
|
|
39782
39842
|
function globsToPathspec(patterns) {
|
|
39783
39843
|
const result = [];
|
|
39784
|
-
const
|
|
39844
|
+
const add = (pathspec) => {
|
|
39845
|
+
if (!result.includes(pathspec))
|
|
39846
|
+
result.push(pathspec);
|
|
39847
|
+
};
|
|
39785
39848
|
for (const pattern of patterns) {
|
|
39786
|
-
const
|
|
39787
|
-
|
|
39849
|
+
const segment = pattern.slice(pattern.lastIndexOf("/") + 1);
|
|
39850
|
+
const firstStar = segment.indexOf("*");
|
|
39851
|
+
if (firstStar === -1)
|
|
39788
39852
|
continue;
|
|
39789
|
-
|
|
39790
|
-
|
|
39853
|
+
if (firstStar > 0) {
|
|
39854
|
+
add(`:!${segment}`);
|
|
39855
|
+
add(`:!*/${segment}`);
|
|
39791
39856
|
continue;
|
|
39792
|
-
const pathspec = `:!*${suffix}`;
|
|
39793
|
-
if (!seen.has(pathspec)) {
|
|
39794
|
-
result.push(pathspec);
|
|
39795
|
-
seen.add(pathspec);
|
|
39796
39857
|
}
|
|
39858
|
+
const suffix = segment.slice(segment.lastIndexOf("*") + 1);
|
|
39859
|
+
if (suffix.length === 0 || BARE_EXTENSION.test(suffix))
|
|
39860
|
+
continue;
|
|
39861
|
+
add(`:!*${suffix}`);
|
|
39797
39862
|
}
|
|
39798
39863
|
return result;
|
|
39799
39864
|
}
|
|
@@ -39807,9 +39872,24 @@ function extractTestDirs(globs) {
|
|
|
39807
39872
|
}
|
|
39808
39873
|
return [...dirs];
|
|
39809
39874
|
}
|
|
39810
|
-
|
|
39875
|
+
function extractWholeTestDirs(globs) {
|
|
39876
|
+
const dirs = new Set;
|
|
39877
|
+
for (const glob2 of globs) {
|
|
39878
|
+
const segments = glob2.split("/");
|
|
39879
|
+
const first = segments[0];
|
|
39880
|
+
if (!first || first.includes("*") || segments.length < 2)
|
|
39881
|
+
continue;
|
|
39882
|
+
const filename = segments[segments.length - 1] ?? "";
|
|
39883
|
+
const coversEverything = filename === "*" || filename === "**" || filename.startsWith("*") && BARE_EXTENSION.test(filename.slice(1));
|
|
39884
|
+
if (coversEverything)
|
|
39885
|
+
dirs.add(first);
|
|
39886
|
+
}
|
|
39887
|
+
return [...dirs];
|
|
39888
|
+
}
|
|
39889
|
+
var DEFAULT_TEST_FILE_PATTERNS, BARE_EXTENSION, DEFAULT_SCAN_TEST_DIRS, DEFAULT_TS_DERIVE_SUFFIXES, DEFAULT_SEPARATED_TEST_DIRS;
|
|
39811
39890
|
var init_conventions = __esm(() => {
|
|
39812
39891
|
DEFAULT_TEST_FILE_PATTERNS = Object.freeze(["test/**/*.test.ts"]);
|
|
39892
|
+
BARE_EXTENSION = /^\.[A-Za-z0-9]+$/;
|
|
39813
39893
|
DEFAULT_SCAN_TEST_DIRS = Object.freeze([
|
|
39814
39894
|
"test",
|
|
39815
39895
|
"tests",
|
|
@@ -40292,29 +40372,11 @@ async function detectFromFileScan(workdir) {
|
|
|
40292
40372
|
const filtered = files.filter((f) => !isExcluded(f));
|
|
40293
40373
|
if (filtered.length === 0)
|
|
40294
40374
|
return null;
|
|
40295
|
-
const counts = {};
|
|
40296
|
-
for (const suffix of CANDIDATE_SUFFIXES) {
|
|
40297
|
-
counts[suffix] = 0;
|
|
40298
|
-
}
|
|
40299
|
-
for (const file2 of filtered) {
|
|
40300
|
-
for (const suffix of CANDIDATE_SUFFIXES) {
|
|
40301
|
-
if (file2.endsWith(suffix)) {
|
|
40302
|
-
counts[suffix] = (counts[suffix] ?? 0) + 1;
|
|
40303
|
-
}
|
|
40304
|
-
}
|
|
40305
|
-
}
|
|
40306
40375
|
const totalFiles = filtered.length;
|
|
40307
|
-
const patterns =
|
|
40308
|
-
|
|
40309
|
-
|
|
40310
|
-
|
|
40311
|
-
continue;
|
|
40312
|
-
if (count >= MIN_COUNT_THRESHOLD || count / totalFiles >= MIN_FRACTION_THRESHOLD) {
|
|
40313
|
-
const glob2 = SUFFIX_TO_GLOB[suffix];
|
|
40314
|
-
if (glob2)
|
|
40315
|
-
patterns.push(glob2);
|
|
40316
|
-
}
|
|
40317
|
-
}
|
|
40376
|
+
const patterns = CANDIDATES.filter((candidate) => {
|
|
40377
|
+
const count = filtered.filter((file2) => candidate.matches(file2)).length;
|
|
40378
|
+
return count > 0 && (count >= MIN_COUNT_THRESHOLD || count / totalFiles >= MIN_FRACTION_THRESHOLD);
|
|
40379
|
+
}).map((candidate) => candidate.glob);
|
|
40318
40380
|
if (patterns.length === 0)
|
|
40319
40381
|
return null;
|
|
40320
40382
|
return {
|
|
@@ -40323,41 +40385,35 @@ async function detectFromFileScan(workdir) {
|
|
|
40323
40385
|
patterns
|
|
40324
40386
|
};
|
|
40325
40387
|
}
|
|
40326
|
-
var DRAIN_TIMEOUT2, EXCLUDED_DIR_PREFIXES, MIN_COUNT_THRESHOLD = 5, MIN_FRACTION_THRESHOLD = 0.1, FILE_SCAN_GIT_TIMEOUT_MS = 4000, FILE_SCAN_DRAIN_TIMEOUT_MS = 2000,
|
|
40388
|
+
var DRAIN_TIMEOUT2, EXCLUDED_DIR_PREFIXES, MIN_COUNT_THRESHOLD = 5, MIN_FRACTION_THRESHOLD = 0.1, FILE_SCAN_GIT_TIMEOUT_MS = 4000, FILE_SCAN_DRAIN_TIMEOUT_MS = 2000, bySuffix = (suffix) => ({
|
|
40389
|
+
glob: `**/*${suffix}`,
|
|
40390
|
+
matches: (path3) => path3.endsWith(suffix)
|
|
40391
|
+
}), byBasenamePrefix = (prefix, extension) => ({
|
|
40392
|
+
glob: `**/${prefix}*${extension}`,
|
|
40393
|
+
matches: (path3) => {
|
|
40394
|
+
const base = path3.slice(path3.lastIndexOf("/") + 1);
|
|
40395
|
+
return base.startsWith(prefix) && base.endsWith(extension) && base.length > prefix.length + extension.length;
|
|
40396
|
+
}
|
|
40397
|
+
}), CANDIDATES, _fileScanDeps;
|
|
40327
40398
|
var init_file_scan = __esm(() => {
|
|
40328
40399
|
init_internal();
|
|
40329
40400
|
DRAIN_TIMEOUT2 = Symbol("drain-timeout");
|
|
40330
40401
|
EXCLUDED_DIR_PREFIXES = ["node_modules/", "dist/", "build/", ".nax/", "coverage/", ".git/"];
|
|
40331
|
-
|
|
40332
|
-
".test.ts",
|
|
40333
|
-
".test.tsx",
|
|
40334
|
-
".test.js",
|
|
40335
|
-
".test.jsx",
|
|
40336
|
-
".spec.ts",
|
|
40337
|
-
".spec.tsx",
|
|
40338
|
-
".spec.js",
|
|
40339
|
-
".spec.jsx",
|
|
40340
|
-
".e2e-spec.ts",
|
|
40341
|
-
".e2e-spec.js",
|
|
40342
|
-
"_test.go",
|
|
40343
|
-
"_test.py",
|
|
40344
|
-
"test_.py"
|
|
40402
|
+
CANDIDATES = [
|
|
40403
|
+
bySuffix(".test.ts"),
|
|
40404
|
+
bySuffix(".test.tsx"),
|
|
40405
|
+
bySuffix(".test.js"),
|
|
40406
|
+
bySuffix(".test.jsx"),
|
|
40407
|
+
bySuffix(".spec.ts"),
|
|
40408
|
+
bySuffix(".spec.tsx"),
|
|
40409
|
+
bySuffix(".spec.js"),
|
|
40410
|
+
bySuffix(".spec.jsx"),
|
|
40411
|
+
bySuffix(".e2e-spec.ts"),
|
|
40412
|
+
bySuffix(".e2e-spec.js"),
|
|
40413
|
+
bySuffix("_test.go"),
|
|
40414
|
+
bySuffix("_test.py"),
|
|
40415
|
+
byBasenamePrefix("test_", ".py")
|
|
40345
40416
|
];
|
|
40346
|
-
SUFFIX_TO_GLOB = {
|
|
40347
|
-
".test.ts": "**/*.test.ts",
|
|
40348
|
-
".test.tsx": "**/*.test.tsx",
|
|
40349
|
-
".test.js": "**/*.test.js",
|
|
40350
|
-
".test.jsx": "**/*.test.jsx",
|
|
40351
|
-
".spec.ts": "**/*.spec.ts",
|
|
40352
|
-
".spec.tsx": "**/*.spec.tsx",
|
|
40353
|
-
".spec.js": "**/*.spec.js",
|
|
40354
|
-
".spec.jsx": "**/*.spec.jsx",
|
|
40355
|
-
".e2e-spec.ts": "**/*.e2e-spec.ts",
|
|
40356
|
-
".e2e-spec.js": "**/*.e2e-spec.js",
|
|
40357
|
-
"_test.go": "**/*_test.go",
|
|
40358
|
-
"_test.py": "**/*_test.py",
|
|
40359
|
-
"test_.py": "**/test_*.py"
|
|
40360
|
-
};
|
|
40361
40417
|
_fileScanDeps = {
|
|
40362
40418
|
spawn: Bun.spawn,
|
|
40363
40419
|
killProcessGroup,
|
|
@@ -40839,7 +40895,7 @@ async function detectFromCargoToml(workdir) {
|
|
|
40839
40895
|
const path3 = `${workdir}/Cargo.toml`;
|
|
40840
40896
|
if (!await _frameworkDefaultsDeps.fileExists(path3))
|
|
40841
40897
|
return null;
|
|
40842
|
-
return { type: "manifest", framework: "rust", path: path3, patterns: ["tests/**/*.rs"
|
|
40898
|
+
return { type: "manifest", framework: "rust", path: path3, patterns: ["tests/**/*.rs"] };
|
|
40843
40899
|
}
|
|
40844
40900
|
async function detectFromPyprojectDeps(workdir) {
|
|
40845
40901
|
const path3 = `${workdir}/pyproject.toml`;
|
|
@@ -41751,7 +41807,7 @@ function resolveReviewExcludePatterns(userExplicit, resolved) {
|
|
|
41751
41807
|
const result = new Set;
|
|
41752
41808
|
for (const p of resolved.pathspec)
|
|
41753
41809
|
result.add(p);
|
|
41754
|
-
for (const d of resolved.
|
|
41810
|
+
for (const d of extractWholeTestDirs(resolved.globs))
|
|
41755
41811
|
result.add(`:!${d}/`);
|
|
41756
41812
|
for (const d of WELL_KNOWN_TEST_DIRS2)
|
|
41757
41813
|
result.add(`:!${d}/`);
|
|
@@ -42371,6 +42427,7 @@ __export(exports_test_runners, {
|
|
|
42371
42427
|
detectTestFilePatterns: () => detectTestFilePatterns,
|
|
42372
42428
|
discoverWorkspacePackages: () => discoverWorkspacePackages,
|
|
42373
42429
|
extractTestDirs: () => extractTestDirs,
|
|
42430
|
+
extractWholeTestDirs: () => extractWholeTestDirs,
|
|
42374
42431
|
findPackageDir: () => findPackageDir,
|
|
42375
42432
|
formatFailureSummary: () => formatFailureSummary,
|
|
42376
42433
|
globsToPathspec: () => globsToPathspec,
|
|
@@ -44648,7 +44705,7 @@ var init_hermetic = __esm(() => {
|
|
|
44648
44705
|
});
|
|
44649
44706
|
|
|
44650
44707
|
// src/prompts/sections/protocol-region.ts
|
|
44651
|
-
import { randomUUID as
|
|
44708
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
44652
44709
|
function call(tool, input) {
|
|
44653
44710
|
return `${tool} ${JSON.stringify(input)}`;
|
|
44654
44711
|
}
|
|
@@ -44765,7 +44822,7 @@ var KIND_PATTERN, NONCE, PROTOCOL_REGION_MARKER_PREFIX = "<!--nax:", REGION, OWN
|
|
|
44765
44822
|
var init_protocol_region = __esm(() => {
|
|
44766
44823
|
init_errors4();
|
|
44767
44824
|
KIND_PATTERN = /^[a-z][a-z-]*$/;
|
|
44768
|
-
NONCE =
|
|
44825
|
+
NONCE = randomUUID9().slice(0, 8);
|
|
44769
44826
|
REGION = new RegExp(`<!--nax:([a-z][a-z-]*):([a-f0-9]+) (\\{.*?\\})-->\\n` + `((?:(?!<!--nax:[a-z][a-z-]*:[a-f0-9]+ )[\\s\\S])*?)` + `<!--\\/nax:\\1-->\\n?`, "g");
|
|
44770
44827
|
OWN_OPEN = new RegExp(`<!--nax:[a-z][a-z-]*:${NONCE} `, "g");
|
|
44771
44828
|
REGISTRY = {
|
|
@@ -47324,7 +47381,7 @@ ${section}`);
|
|
|
47324
47381
|
const failingFiles = Array.from(new Set(findings.map((f) => f.file).filter((f) => !!f)));
|
|
47325
47382
|
if (failingFiles.length > 0) {
|
|
47326
47383
|
const perFileLines = failingFiles.map((file2) => {
|
|
47327
|
-
const scopedCmd = opts.testScopedTemplate ? opts.testScopedTemplate.
|
|
47384
|
+
const scopedCmd = opts.testScopedTemplate ? opts.testScopedTemplate.replaceAll("{{files}}", () => file2) : `${opts.testCommand} ${file2}`;
|
|
47328
47385
|
if (opts.testScopedTemplate && opts.fileScopeCommandName) {
|
|
47329
47386
|
return ` ${wrapAffordance("run-test", { command: opts.fileScopeCommandName, files: file2 }, scopedCmd)}`;
|
|
47330
47387
|
}
|
|
@@ -47754,7 +47811,7 @@ ${output}
|
|
|
47754
47811
|
const cmd = testCommand ?? "";
|
|
47755
47812
|
const failingFiles = Array.from(new Set(failures.map((f) => f.file)));
|
|
47756
47813
|
const testCommands = failingFiles.map((file2) => {
|
|
47757
|
-
const scopedCmd = testScopedTemplate ? testScopedTemplate.
|
|
47814
|
+
const scopedCmd = testScopedTemplate ? testScopedTemplate.replaceAll("{{files}}", () => file2) : cmd ? `${cmd} ${file2}` : file2;
|
|
47758
47815
|
return ` ${scopedCmd}`;
|
|
47759
47816
|
}).join(`
|
|
47760
47817
|
`);
|
|
@@ -49845,7 +49902,7 @@ async function loadCanonicalRules(workdir, options = {}) {
|
|
|
49845
49902
|
if (allViolations.length > 0) {
|
|
49846
49903
|
throw new NeutralityLintError(allViolations);
|
|
49847
49904
|
}
|
|
49848
|
-
rules.sort((a, b) => (a.priority ?? FRONTMATTER_PRIORITY_DEFAULT) - (b.priority ?? FRONTMATTER_PRIORITY_DEFAULT) || (a.id ?? a.fileName
|
|
49905
|
+
rules.sort((a, b) => (a.priority ?? FRONTMATTER_PRIORITY_DEFAULT) - (b.priority ?? FRONTMATTER_PRIORITY_DEFAULT) || byCodePoint(a.id ?? a.fileName, b.id ?? b.fileName));
|
|
49849
49906
|
logger.debug("canonical-loader", "Scanned canonical rules store", {
|
|
49850
49907
|
fileCount: rules.length,
|
|
49851
49908
|
files: rules.map((r) => r.path)
|
|
@@ -49879,6 +49936,7 @@ async function loadCanonicalRules(workdir, options = {}) {
|
|
|
49879
49936
|
}
|
|
49880
49937
|
var CANONICAL_RULES_DIR = ".nax/rules", _canonicalLoaderDeps, NEUTRALITY_RULES, DEFAULT_CANONICAL_RULES_BUDGET_TOKENS = 8192, RULES_BUDGET_WARNING_RATIO = 0.75, RULE_ALLOW_MARKER, NeutralityLintError, RulesFrontmatterLintError;
|
|
49881
49938
|
var init_canonical_loader = __esm(() => {
|
|
49939
|
+
init_internal();
|
|
49882
49940
|
init_errors4();
|
|
49883
49941
|
init_logger2();
|
|
49884
49942
|
init_rules_frontmatter();
|
|
@@ -50557,7 +50615,7 @@ function applySectionBudget(sections2, budgetTokens) {
|
|
|
50557
50615
|
overageTokens: totalTokens
|
|
50558
50616
|
};
|
|
50559
50617
|
}
|
|
50560
|
-
const sorted = [...sections2].sort((a, b) => (a.priority ?? FRONTMATTER_PRIORITY_DEFAULT) - (b.priority ?? FRONTMATTER_PRIORITY_DEFAULT) || ownerIdentifier(a)
|
|
50618
|
+
const sorted = [...sections2].sort((a, b) => (a.priority ?? FRONTMATTER_PRIORITY_DEFAULT) - (b.priority ?? FRONTMATTER_PRIORITY_DEFAULT) || byCodePoint(ownerIdentifier(a), ownerIdentifier(b)) || a.ordinal - b.ordinal);
|
|
50561
50619
|
const kept = [];
|
|
50562
50620
|
const droppedIds = [];
|
|
50563
50621
|
const closedOwners = new Set;
|
|
@@ -50589,6 +50647,7 @@ function applySectionBudget(sections2, budgetTokens) {
|
|
|
50589
50647
|
};
|
|
50590
50648
|
}
|
|
50591
50649
|
var init_rule_budget = __esm(() => {
|
|
50650
|
+
init_internal();
|
|
50592
50651
|
init_rules_frontmatter();
|
|
50593
50652
|
});
|
|
50594
50653
|
|
|
@@ -51687,7 +51746,7 @@ var init_loop_handler_forwarding = __esm(() => {
|
|
|
51687
51746
|
});
|
|
51688
51747
|
|
|
51689
51748
|
// src/session/manager-deps.ts
|
|
51690
|
-
import { randomUUID as
|
|
51749
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
51691
51750
|
import { mkdir as mkdir14 } from "fs/promises";
|
|
51692
51751
|
import { isAbsolute as isAbsolute13, join as join39, relative as relative18, sep as sep13 } from "path";
|
|
51693
51752
|
function resolveProjectDirFromScratchDir(scratchDir) {
|
|
@@ -51729,7 +51788,7 @@ var init_manager_deps = __esm(() => {
|
|
|
51729
51788
|
_sessionManagerDeps = {
|
|
51730
51789
|
now: () => new Date().toISOString(),
|
|
51731
51790
|
nowMs: () => Date.now(),
|
|
51732
|
-
uuid: () =>
|
|
51791
|
+
uuid: () => randomUUID10(),
|
|
51733
51792
|
sessionScratchDir: (projectDir, featureName, sessionId) => join39(featureDir(projectDir, featureName), "sessions", sessionId),
|
|
51734
51793
|
writeDescriptor: async (scratchDir, descriptor, projectDir) => {
|
|
51735
51794
|
await mkdir14(scratchDir, { recursive: true });
|
|
@@ -52220,10 +52279,9 @@ class SessionManager {
|
|
|
52220
52279
|
const reuse = decideReuse(liveHandle, this._findByName(name), opts);
|
|
52221
52280
|
if (liveHandle && reuse === "reuse")
|
|
52222
52281
|
return liveHandle;
|
|
52223
|
-
if (liveHandle && reuse === "close-then-reopen")
|
|
52224
|
-
await this.closeSession(liveHandle);
|
|
52225
|
-
|
|
52226
|
-
} else if (liveHandle)
|
|
52282
|
+
if (liveHandle && reuse === "close-then-reopen")
|
|
52283
|
+
await this.closeSession(liveHandle, true);
|
|
52284
|
+
else if (liveHandle)
|
|
52227
52285
|
this._liveHandles.delete(name);
|
|
52228
52286
|
const adapter = this._getAdapter(opts.agentName);
|
|
52229
52287
|
if (!adapter) {
|
|
@@ -52252,6 +52310,7 @@ class SessionManager {
|
|
|
52252
52310
|
this._liveHandles.set(name, handle);
|
|
52253
52311
|
const protocolIds = handle.protocolIds ?? NULL_PROTOCOL_IDS;
|
|
52254
52312
|
if (!existingDescriptor) {
|
|
52313
|
+
this._cancelledSessions.delete(name);
|
|
52255
52314
|
const created = this.create({
|
|
52256
52315
|
role: opts.role ?? "main",
|
|
52257
52316
|
agent: opts.agentName,
|
|
@@ -52287,7 +52346,7 @@ class SessionManager {
|
|
|
52287
52346
|
});
|
|
52288
52347
|
return handle;
|
|
52289
52348
|
}
|
|
52290
|
-
async closeSession(handle) {
|
|
52349
|
+
async closeSession(handle, keepOpenGuard = false) {
|
|
52291
52350
|
const desc = this._findByName(handle.id);
|
|
52292
52351
|
const adapter = this._getAdapter(handle.agentName);
|
|
52293
52352
|
this._liveHandles.delete(handle.id);
|
|
@@ -52305,7 +52364,8 @@ class SessionManager {
|
|
|
52305
52364
|
if (desc && desc.state === "RUNNING") {
|
|
52306
52365
|
this.transition(desc.id, "COMPLETED");
|
|
52307
52366
|
}
|
|
52308
|
-
|
|
52367
|
+
if (!keepOpenGuard)
|
|
52368
|
+
this._busySessions.delete(handle.id);
|
|
52309
52369
|
this._cancelledSessions.delete(handle.id);
|
|
52310
52370
|
this._watchdogCancels.clear(handle.id);
|
|
52311
52371
|
}
|
|
@@ -52414,7 +52474,7 @@ function recordAgentHandoff(sessionManager, sessionName, newAgent, reason) {
|
|
|
52414
52474
|
}
|
|
52415
52475
|
|
|
52416
52476
|
// src/session/scratch-purge.ts
|
|
52417
|
-
import { mkdir as mkdir15, rename as
|
|
52477
|
+
import { mkdir as mkdir15, rename as rename4, rm as rm6 } from "fs/promises";
|
|
52418
52478
|
import { dirname as dirname15, join as join40 } from "path";
|
|
52419
52479
|
async function purgeStaleScratch(projectDir, featureName, retentionDays, archiveInsteadOfDelete = false) {
|
|
52420
52480
|
const sessionsDir = join40(featureDir(projectDir, featureName), "sessions");
|
|
@@ -52466,10 +52526,10 @@ var init_scratch_purge = __esm(() => {
|
|
|
52466
52526
|
},
|
|
52467
52527
|
fileExists: (path5) => Bun.file(path5).exists(),
|
|
52468
52528
|
readFile: (path5) => Bun.file(path5).text(),
|
|
52469
|
-
remove: (path5) =>
|
|
52529
|
+
remove: (path5) => rm6(path5, { recursive: true, force: true }),
|
|
52470
52530
|
move: async (src, dest) => {
|
|
52471
52531
|
await mkdir15(dirname15(dest), { recursive: true });
|
|
52472
|
-
await
|
|
52532
|
+
await rename4(src, dest);
|
|
52473
52533
|
},
|
|
52474
52534
|
now: () => Date.now()
|
|
52475
52535
|
};
|
|
@@ -52557,7 +52617,7 @@ var init_session2 = __esm(() => {
|
|
|
52557
52617
|
var DEFAULT_MAX_TOKENS_PER_CALL = 2048;
|
|
52558
52618
|
|
|
52559
52619
|
// src/context/fragments/store.ts
|
|
52560
|
-
import { mkdir as mkdir17, rm as
|
|
52620
|
+
import { mkdir as mkdir17, rm as rm7, stat as stat7 } from "fs/promises";
|
|
52561
52621
|
import { dirname as dirname17, join as join41 } from "path";
|
|
52562
52622
|
function fragmentPath(projectDir, featureId, storyId) {
|
|
52563
52623
|
validatePathSegment(storyId, "storyId");
|
|
@@ -52671,7 +52731,7 @@ var init_store = __esm(() => {
|
|
|
52671
52731
|
return files.sort(byCodePoint);
|
|
52672
52732
|
},
|
|
52673
52733
|
removeFile: async (path5) => {
|
|
52674
|
-
await
|
|
52734
|
+
await rm7(path5, { force: true });
|
|
52675
52735
|
}
|
|
52676
52736
|
};
|
|
52677
52737
|
});
|
|
@@ -54335,6 +54395,27 @@ var init_manifest_purge = __esm(() => {
|
|
|
54335
54395
|
};
|
|
54336
54396
|
});
|
|
54337
54397
|
|
|
54398
|
+
// src/context/engine/digest-carrier.ts
|
|
54399
|
+
function boostedDigestChunk(request) {
|
|
54400
|
+
const digest = request.priorStageDigest?.trim();
|
|
54401
|
+
return digest && (request.planDigestBoost ?? 1) > 1 ? request.priorStageDigest : undefined;
|
|
54402
|
+
}
|
|
54403
|
+
function resolveDigestCarrier(request, boostedDigest, packed) {
|
|
54404
|
+
if (boostedDigest === undefined) {
|
|
54405
|
+
return { digestAsChunk: false, renderPriorDigest: request.priorStageDigest, manifestRequest: request };
|
|
54406
|
+
}
|
|
54407
|
+
const landed = packed.some((c) => c.providerId === PLAN_DIGEST_PROVIDER_ID);
|
|
54408
|
+
if (landed) {
|
|
54409
|
+
return {
|
|
54410
|
+
digestAsChunk: true,
|
|
54411
|
+
renderPriorDigest: undefined,
|
|
54412
|
+
manifestRequest: { ...request, priorStageDigest: undefined }
|
|
54413
|
+
};
|
|
54414
|
+
}
|
|
54415
|
+
return { digestAsChunk: false, renderPriorDigest: request.priorStageDigest, manifestRequest: request };
|
|
54416
|
+
}
|
|
54417
|
+
var PLAN_DIGEST_PROVIDER_ID = "plan-digest";
|
|
54418
|
+
|
|
54338
54419
|
// src/context/engine/orchestrator-rebuild-helpers.ts
|
|
54339
54420
|
function toContextChunk(packed) {
|
|
54340
54421
|
const providerId = packed.providerId ?? packed.id.split(":")[0] ?? "unknown";
|
|
@@ -54538,7 +54619,7 @@ var init_render = __esm(() => {
|
|
|
54538
54619
|
});
|
|
54539
54620
|
|
|
54540
54621
|
// src/context/engine/rebuild.ts
|
|
54541
|
-
import { randomUUID as
|
|
54622
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
54542
54623
|
function toPackedChunks(prior, newAgentId, targetAgentId) {
|
|
54543
54624
|
const priorAgentForNeutralize = prior.agentId ?? "";
|
|
54544
54625
|
return prior.chunks.map((c) => {
|
|
@@ -54665,7 +54746,7 @@ var init_rebuild = __esm(() => {
|
|
|
54665
54746
|
init_render();
|
|
54666
54747
|
init_scratch_neutralizer();
|
|
54667
54748
|
DEFAULT_REBUILD_DEPS = {
|
|
54668
|
-
uuid: () =>
|
|
54749
|
+
uuid: () => randomUUID11(),
|
|
54669
54750
|
getLogger: () => getLogger2()
|
|
54670
54751
|
};
|
|
54671
54752
|
});
|
|
@@ -54679,13 +54760,13 @@ function roleMultiplier(chunkRoles, callerRole) {
|
|
|
54679
54760
|
return ROLE_MISMATCH_WEIGHT;
|
|
54680
54761
|
}
|
|
54681
54762
|
function scoreChunk(chunk, callerRole, minScore = MIN_SCORE, stale = false, providerWeights) {
|
|
54682
|
-
const
|
|
54683
|
-
const roleFiltered =
|
|
54763
|
+
const rm8 = roleMultiplier(chunk.role, callerRole);
|
|
54764
|
+
const roleFiltered = rm8 === 0;
|
|
54684
54765
|
const kindWeight = KIND_WEIGHTS[chunk.kind] ?? 0.5;
|
|
54685
54766
|
const isStale = chunk.staleCandidate === true || stale;
|
|
54686
54767
|
const freshnessMultiplier = isStale ? chunk.scoreMultiplier ?? STALENESS_PENALTY : 1;
|
|
54687
54768
|
const effectivenessMultiplier = chunk.providerId !== undefined ? providerWeights?.[chunk.providerId] ?? 1 : 1;
|
|
54688
|
-
const score = chunk.rawScore *
|
|
54769
|
+
const score = chunk.rawScore * rm8 * kindWeight * freshnessMultiplier * effectivenessMultiplier;
|
|
54689
54770
|
const belowMinScore = !roleFiltered && score < minScore;
|
|
54690
54771
|
return { ...chunk, score, roleFiltered, belowMinScore };
|
|
54691
54772
|
}
|
|
@@ -54711,7 +54792,7 @@ var init_scoring = __esm(() => {
|
|
|
54711
54792
|
});
|
|
54712
54793
|
|
|
54713
54794
|
// src/context/engine/orchestrator.ts
|
|
54714
|
-
import { createHash as createHash10, randomUUID as
|
|
54795
|
+
import { createHash as createHash10, randomUUID as randomUUID12 } from "crypto";
|
|
54715
54796
|
function buildPullToolDescriptors(stageToolNames, pullConfig) {
|
|
54716
54797
|
if (!pullConfig?.enabled || stageToolNames.length === 0)
|
|
54717
54798
|
return [];
|
|
@@ -54720,6 +54801,28 @@ function buildPullToolDescriptors(stageToolNames, pullConfig) {
|
|
|
54720
54801
|
const override = configured2 !== undefined && configured2 !== DEFAULT_MAX_CALLS_PER_SESSION ? configured2 : undefined;
|
|
54721
54802
|
return stageToolNames.filter((name) => allowed.length === 0 || allowed.includes(name)).map((name) => PULL_TOOL_REGISTRY[name]).filter((d) => d !== undefined).map((d) => ({ ...d, maxCallsPerSession: override ?? d.maxCallsPerSession }));
|
|
54722
54803
|
}
|
|
54804
|
+
function appendPlanDigestChunk(raw, results, digest, boost) {
|
|
54805
|
+
const hash2 = createHash10("sha256").update(digest).digest("hex").slice(0, 8);
|
|
54806
|
+
const tokens = Math.ceil(digest.length / 4);
|
|
54807
|
+
raw.push({
|
|
54808
|
+
id: `${PLAN_DIGEST_PROVIDER_ID}:${hash2}`,
|
|
54809
|
+
providerId: PLAN_DIGEST_PROVIDER_ID,
|
|
54810
|
+
kind: "session",
|
|
54811
|
+
scope: "session",
|
|
54812
|
+
role: ["all"],
|
|
54813
|
+
content: digest,
|
|
54814
|
+
tokens,
|
|
54815
|
+
rawScore: 0.9 * boost
|
|
54816
|
+
});
|
|
54817
|
+
results.push({
|
|
54818
|
+
providerId: PLAN_DIGEST_PROVIDER_ID,
|
|
54819
|
+
status: "ok",
|
|
54820
|
+
source: undefined,
|
|
54821
|
+
chunkCount: 1,
|
|
54822
|
+
durationMs: 0,
|
|
54823
|
+
tokensProduced: tokens
|
|
54824
|
+
});
|
|
54825
|
+
}
|
|
54723
54826
|
async function fetchWithTimeout(provider, request, timeoutMs = PROVIDER_FETCH_TIMEOUT_MS) {
|
|
54724
54827
|
const controller = new AbortController;
|
|
54725
54828
|
let handle;
|
|
@@ -54731,7 +54834,7 @@ async function fetchWithTimeout(provider, request, timeoutMs = PROVIDER_FETCH_TI
|
|
|
54731
54834
|
reject(new Error(`Provider "${provider.id}" timed out`));
|
|
54732
54835
|
}, timeoutMs);
|
|
54733
54836
|
});
|
|
54734
|
-
const fetchPromise = provider.fetch(request, controller.signal).then((result) => result, (err) => {
|
|
54837
|
+
const fetchPromise = (async () => provider.fetch(request, controller.signal))().then((result) => result, (err) => {
|
|
54735
54838
|
if (timedOut) {
|
|
54736
54839
|
return new Promise(() => {});
|
|
54737
54840
|
}
|
|
@@ -54797,8 +54900,9 @@ class ContextOrchestrator {
|
|
|
54797
54900
|
}
|
|
54798
54901
|
const profileBudget = agentProfile.caps.preferredPromptTokens;
|
|
54799
54902
|
const stageCeiling = Math.min(request.budgetTokens, profileBudget, request.availableBudgetTokens ?? Number.POSITIVE_INFINITY);
|
|
54903
|
+
const boostedDigest = boostedDigestChunk(request);
|
|
54800
54904
|
const trimmedPriorDigest = request.priorStageDigest?.trim();
|
|
54801
|
-
const priorDigestTokens = trimmedPriorDigest ? Math.ceil(trimmedPriorDigest.length / 4) : 0;
|
|
54905
|
+
const priorDigestTokens = boostedDigest === undefined && trimmedPriorDigest ? Math.ceil(trimmedPriorDigest.length / 4) : 0;
|
|
54802
54906
|
let effectiveBudgetTokens = Math.max(0, stageCeiling - DIGEST_RESERVE_TOKENS - priorDigestTokens - FIXED_RENDER_OVERHEAD_TOKENS);
|
|
54803
54907
|
const providerSourceMap = request.providerIds === undefined ? buildProviderSourceMap(stageConfig.providerIds, request.extraProviderIds ?? []) : new Map;
|
|
54804
54908
|
const allowedIds = request.providerIds ?? [...providerSourceMap.keys()];
|
|
@@ -54876,28 +54980,8 @@ class ContextOrchestrator {
|
|
|
54876
54980
|
}));
|
|
54877
54981
|
const allRaw = fetchResults.flatMap(({ provider, result }) => result.chunks.map((c) => enrichRaw(c, provider.id)));
|
|
54878
54982
|
const providerResults = fetchResults.map(({ providerStatus }) => providerStatus);
|
|
54879
|
-
if (
|
|
54880
|
-
|
|
54881
|
-
const hash2 = createHash10("sha256").update(request.priorStageDigest).digest("hex").slice(0, 8);
|
|
54882
|
-
const tokens = Math.ceil(request.priorStageDigest.length / 4);
|
|
54883
|
-
allRaw.push({
|
|
54884
|
-
id: `plan-digest:${hash2}`,
|
|
54885
|
-
providerId: "plan-digest",
|
|
54886
|
-
kind: "session",
|
|
54887
|
-
scope: "session",
|
|
54888
|
-
role: ["all"],
|
|
54889
|
-
content: request.priorStageDigest,
|
|
54890
|
-
tokens,
|
|
54891
|
-
rawScore: 0.9 * boost
|
|
54892
|
-
});
|
|
54893
|
-
providerResults.push({
|
|
54894
|
-
providerId: "plan-digest",
|
|
54895
|
-
status: "ok",
|
|
54896
|
-
source: undefined,
|
|
54897
|
-
chunkCount: 1,
|
|
54898
|
-
durationMs: 0,
|
|
54899
|
-
tokensProduced: tokens
|
|
54900
|
-
});
|
|
54983
|
+
if (boostedDigest !== undefined) {
|
|
54984
|
+
appendPlanDigestChunk(allRaw, providerResults, boostedDigest, request.planDigestBoost ?? 1);
|
|
54901
54985
|
}
|
|
54902
54986
|
assertUniqueChunkIds(allRaw, request);
|
|
54903
54987
|
const allPullTools = agentProfile.caps.supportsToolCalls ? buildPullToolDescriptors(stageConfig.pullToolNames ?? [], request.pullConfig) : [];
|
|
@@ -54929,7 +55013,10 @@ class ContextOrchestrator {
|
|
|
54929
55013
|
excludedNonFloorChunkCount: budgetExcludedIds.length
|
|
54930
55014
|
});
|
|
54931
55015
|
}
|
|
54932
|
-
const
|
|
55016
|
+
const digestCarrier = resolveDigestCarrier(request, boostedDigest, packed);
|
|
55017
|
+
const renderOptions = {
|
|
55018
|
+
priorStageDigest: digestCarrier.renderPriorDigest
|
|
55019
|
+
};
|
|
54933
55020
|
const pushMarkdown = request.agentId !== undefined ? renderForAgent(packed, request.agentId, renderOptions) : renderChunks(packed, renderOptions);
|
|
54934
55021
|
const digest = buildDigest(packed);
|
|
54935
55022
|
const dTokens = digestTokens(digest);
|
|
@@ -54939,7 +55026,7 @@ class ContextOrchestrator {
|
|
|
54939
55026
|
const staleIds = new Set(scored.filter((c) => c.staleCandidate === true).map((c) => c.id));
|
|
54940
55027
|
const manifest = buildManifest({
|
|
54941
55028
|
requestId,
|
|
54942
|
-
request,
|
|
55029
|
+
request: digestCarrier.manifestRequest,
|
|
54943
55030
|
packed,
|
|
54944
55031
|
usedTokens,
|
|
54945
55032
|
digestTokens: dTokens,
|
|
@@ -55014,7 +55101,7 @@ var init_orchestrator = __esm(() => {
|
|
|
55014
55101
|
init_stage_config();
|
|
55015
55102
|
_orchestratorDeps = {
|
|
55016
55103
|
now: () => Date.now(),
|
|
55017
|
-
uuid: () =>
|
|
55104
|
+
uuid: () => randomUUID12(),
|
|
55018
55105
|
getLogger: getLogger2,
|
|
55019
55106
|
rebuild
|
|
55020
55107
|
};
|
|
@@ -55607,7 +55694,7 @@ __export(exports_tracker, {
|
|
|
55607
55694
|
saveRunMetrics: () => saveRunMetrics,
|
|
55608
55695
|
toFallbackHops: () => toFallbackHops
|
|
55609
55696
|
});
|
|
55610
|
-
import { rename as
|
|
55697
|
+
import { rename as rename5 } from "fs/promises";
|
|
55611
55698
|
import path5 from "path";
|
|
55612
55699
|
function tokensFromSnapshot(snapshot, divisor = 1) {
|
|
55613
55700
|
if (!snapshot || snapshot.tokenUsageCount !== snapshot.callCount)
|
|
@@ -55829,7 +55916,7 @@ async function loadExistingMetricsOrQuarantine(metricsPath) {
|
|
|
55829
55916
|
} catch (err) {
|
|
55830
55917
|
const quarantinePath = `${metricsPath}.corrupt-${new Date().toISOString().replace(/[:.]/g, "-")}`;
|
|
55831
55918
|
try {
|
|
55832
|
-
await
|
|
55919
|
+
await rename5(metricsPath, quarantinePath);
|
|
55833
55920
|
} catch (renameErr) {
|
|
55834
55921
|
getLogger2().warn("metrics", "Failed to quarantine corrupt metrics.json \u2014 leaving in place", {
|
|
55835
55922
|
metricsPath,
|
|
@@ -56597,8 +56684,8 @@ var init_registry4 = __esm(() => {
|
|
|
56597
56684
|
});
|
|
56598
56685
|
|
|
56599
56686
|
// src/trust/store.ts
|
|
56600
|
-
import { randomUUID as
|
|
56601
|
-
import { mkdir as mkdir18, rename as
|
|
56687
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
56688
|
+
import { mkdir as mkdir18, rename as rename6, stat as stat8, unlink as unlink4, writeFile as writeFile9 } from "fs/promises";
|
|
56602
56689
|
import { dirname as dirname20, isAbsolute as isAbsolute15, join as join48 } from "path";
|
|
56603
56690
|
function trustStorePath() {
|
|
56604
56691
|
return join48(globalConfigDir(), "trust.json");
|
|
@@ -56670,11 +56757,11 @@ async function readFoldersForWrite(storePath) {
|
|
|
56670
56757
|
return read.state === "ok" ? read.file.folders : [];
|
|
56671
56758
|
}
|
|
56672
56759
|
async function writeTrustStore(storePath, file2) {
|
|
56673
|
-
const tempPath = `${storePath}.${process.pid}.${
|
|
56760
|
+
const tempPath = `${storePath}.${process.pid}.${randomUUID13()}.tmp`;
|
|
56674
56761
|
try {
|
|
56675
|
-
await
|
|
56762
|
+
await writeFile9(tempPath, `${JSON.stringify(file2, null, 2)}
|
|
56676
56763
|
`, { mode: 384 });
|
|
56677
|
-
await
|
|
56764
|
+
await rename6(tempPath, storePath);
|
|
56678
56765
|
} finally {
|
|
56679
56766
|
await unlink4(tempPath).catch(() => {});
|
|
56680
56767
|
}
|
|
@@ -56970,8 +57057,8 @@ var init_version = __esm(() => {
|
|
|
56970
57057
|
NAX_AI_VERSION = CATALOG_VERSION;
|
|
56971
57058
|
NAX_COMMIT = (() => {
|
|
56972
57059
|
try {
|
|
56973
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
56974
|
-
return "
|
|
57060
|
+
if (/^[0-9a-f]{6,10}$/.test("cfab34e07"))
|
|
57061
|
+
return "cfab34e07";
|
|
56975
57062
|
} catch {}
|
|
56976
57063
|
try {
|
|
56977
57064
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -69061,7 +69148,7 @@ var init_client4 = __esm(() => {
|
|
|
69061
69148
|
|
|
69062
69149
|
// src/mcp/lock.ts
|
|
69063
69150
|
import { createHash as createHash17 } from "crypto";
|
|
69064
|
-
import { mkdir as mkdir22, readFile as readFile9, writeFile as
|
|
69151
|
+
import { mkdir as mkdir22, readFile as readFile9, writeFile as writeFile10 } from "fs/promises";
|
|
69065
69152
|
import { join as join55 } from "path";
|
|
69066
69153
|
function mcpLockPath(projectRoot) {
|
|
69067
69154
|
return join55(projectRoot, PROJECT_NAX_DIR, MCP_LOCK_FILENAME);
|
|
@@ -69093,7 +69180,7 @@ async function writeMcpLock(projectRoot, lock) {
|
|
|
69093
69180
|
Object.fromEntries(Object.entries(tools2).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0))
|
|
69094
69181
|
]));
|
|
69095
69182
|
await mkdir22(join55(projectRoot, PROJECT_NAX_DIR), { recursive: true });
|
|
69096
|
-
await
|
|
69183
|
+
await writeFile10(mcpLockPath(projectRoot), `${JSON.stringify({ version: 1, servers }, null, 2)}
|
|
69097
69184
|
`);
|
|
69098
69185
|
}
|
|
69099
69186
|
function applyLock(locked, discovered) {
|
|
@@ -69314,7 +69401,7 @@ var init_provider = __esm(() => {
|
|
|
69314
69401
|
});
|
|
69315
69402
|
|
|
69316
69403
|
// src/mcp/rollup.ts
|
|
69317
|
-
import { mkdir as mkdir23, writeFile as
|
|
69404
|
+
import { mkdir as mkdir23, writeFile as writeFile11 } from "fs/promises";
|
|
69318
69405
|
import { join as join56 } from "path";
|
|
69319
69406
|
function buildMcpRollup(args) {
|
|
69320
69407
|
const byServer = new Map;
|
|
@@ -69347,7 +69434,7 @@ async function writeMcpRollup(outputDir, rollup) {
|
|
|
69347
69434
|
return;
|
|
69348
69435
|
const dir = join56(outputDir, "mcp");
|
|
69349
69436
|
await mkdir23(dir, { recursive: true });
|
|
69350
|
-
await
|
|
69437
|
+
await writeFile11(join56(dir, `${rollup.runId}-servers.json`), `${JSON.stringify(rollup, null, 2)}
|
|
69351
69438
|
`);
|
|
69352
69439
|
}
|
|
69353
69440
|
var init_rollup = () => {};
|
|
@@ -73076,7 +73163,7 @@ var init_runners = __esm(() => {
|
|
|
73076
73163
|
|
|
73077
73164
|
// src/verification/test-baseline.ts
|
|
73078
73165
|
import { existsSync as existsSync10 } from "fs";
|
|
73079
|
-
import { mkdir as mkdir24, readdir as readdir6, rm as
|
|
73166
|
+
import { mkdir as mkdir24, readdir as readdir6, rm as rm8 } from "fs/promises";
|
|
73080
73167
|
import { join as join65 } from "path";
|
|
73081
73168
|
function runBaselinePath(root, featureId) {
|
|
73082
73169
|
return join65(featureDir(root, featureId), RUN_BASELINE_FILENAME);
|
|
@@ -73106,7 +73193,7 @@ async function clearStoryBaselines(root, featureId) {
|
|
|
73106
73193
|
return [];
|
|
73107
73194
|
throw err;
|
|
73108
73195
|
});
|
|
73109
|
-
await Promise.all(entries.filter((entry) => entry.isDirectory()).map((entry) =>
|
|
73196
|
+
await Promise.all(entries.filter((entry) => entry.isDirectory()).map((entry) => rm8(join65(storiesDir, entry.name, STORY_BASELINE_FILENAME), { force: true })));
|
|
73110
73197
|
}
|
|
73111
73198
|
async function resolveStoryBaseline(root, featureId, storyId, executionMode) {
|
|
73112
73199
|
if (executionMode === "parallel") {
|
|
@@ -74378,12 +74465,13 @@ async function performAdversarialReground(turn, firstParsed, drops, ctx) {
|
|
|
74378
74465
|
const secondParsed = validateAdversarialShape(tryParseLLMJson(secondTurn.output));
|
|
74379
74466
|
const costUsd = (turn.estimatedCostUsd ?? 0) + (secondTurn.estimatedCostUsd ?? 0);
|
|
74380
74467
|
const dropCount = drops.length;
|
|
74381
|
-
|
|
74382
|
-
|
|
74383
|
-
|
|
74384
|
-
|
|
74385
|
-
|
|
74386
|
-
|
|
74468
|
+
const keepFirstTurn = (outcome) => ({
|
|
74469
|
+
...turn,
|
|
74470
|
+
output: withRepromptMarker(turn.output, { dropCount, outcome, costUsd }),
|
|
74471
|
+
estimatedCostUsd: costUsd
|
|
74472
|
+
});
|
|
74473
|
+
if (!secondParsed)
|
|
74474
|
+
return keepFirstTurn("parse-failed");
|
|
74387
74475
|
const { accepted: secondAccepted } = filterByAcQuote(secondParsed.findings, acceptanceCriteria);
|
|
74388
74476
|
const secondBlocking = secondAccepted.filter((f) => isBlockingSeverity(f.severity, threshold));
|
|
74389
74477
|
if (secondBlocking.length > 0) {
|
|
@@ -74411,10 +74499,7 @@ async function performAdversarialReground(turn, firstParsed, drops, ctx) {
|
|
|
74411
74499
|
estimatedCostUsd: costUsd
|
|
74412
74500
|
};
|
|
74413
74501
|
}
|
|
74414
|
-
return
|
|
74415
|
-
...turn,
|
|
74416
|
-
output: withRepromptMarker(turn.output, { dropCount, outcome: "still-dropped", costUsd })
|
|
74417
|
-
};
|
|
74502
|
+
return keepFirstTurn("still-dropped");
|
|
74418
74503
|
}
|
|
74419
74504
|
async function maybeRepromptForInspection(turn, parsed, rawObject, ctx) {
|
|
74420
74505
|
if (ctx.input.adversarialConfig.demandInspectionTrail === false)
|
|
@@ -77943,7 +78028,7 @@ var init_scope = __esm(() => {
|
|
|
77943
78028
|
});
|
|
77944
78029
|
|
|
77945
78030
|
// src/review/fix-review/tree-snapshot/index.ts
|
|
77946
|
-
import { mkdtemp as mkdtemp2, rm as
|
|
78031
|
+
import { mkdtemp as mkdtemp2, rm as rm9 } from "fs/promises";
|
|
77947
78032
|
import { tmpdir as tmpdir6 } from "os";
|
|
77948
78033
|
import { join as join69 } from "path";
|
|
77949
78034
|
async function runGit(args, cwd, indexOverlay, timeoutMs = _treeSnapshotDeps.gitTimeoutMs) {
|
|
@@ -78030,7 +78115,7 @@ var init_tree_snapshot = __esm(() => {
|
|
|
78030
78115
|
spawn: typedSpawn,
|
|
78031
78116
|
gitTimeoutMs: TREE_SNAPSHOT_GIT_TIMEOUT_MS,
|
|
78032
78117
|
mkdtemp: mkdtemp2,
|
|
78033
|
-
rm:
|
|
78118
|
+
rm: rm9,
|
|
78034
78119
|
tmpdir: tmpdir6
|
|
78035
78120
|
};
|
|
78036
78121
|
});
|
|
@@ -79147,33 +79232,62 @@ function parseHeaderPath(rawLine, precededByMinusHeader) {
|
|
|
79147
79232
|
function isMinusHeader(rawLine) {
|
|
79148
79233
|
return rawLine.startsWith("--- ");
|
|
79149
79234
|
}
|
|
79150
|
-
function
|
|
79151
|
-
|
|
79152
|
-
|
|
79153
|
-
|
|
79154
|
-
|
|
79235
|
+
function bodyLineCost(line) {
|
|
79236
|
+
if (line === "" || line.startsWith(" "))
|
|
79237
|
+
return { old: 1, new: 1 };
|
|
79238
|
+
if (line.startsWith("-"))
|
|
79239
|
+
return { old: 1, new: 0 };
|
|
79240
|
+
if (line.startsWith("+"))
|
|
79241
|
+
return { old: 0, new: 1 };
|
|
79242
|
+
if (line.startsWith("\\"))
|
|
79243
|
+
return { old: 0, new: 0 };
|
|
79244
|
+
return null;
|
|
79245
|
+
}
|
|
79246
|
+
function* scanDiff(diff) {
|
|
79247
|
+
let oldLeft = 0;
|
|
79248
|
+
let newLeft = 0;
|
|
79155
79249
|
let prevWasMinusHeader = false;
|
|
79156
79250
|
for (const rawLine of diff.split(/\r?\n/)) {
|
|
79251
|
+
if (oldLeft > 0 || newLeft > 0) {
|
|
79252
|
+
const cost = bodyLineCost(rawLine);
|
|
79253
|
+
if (cost !== null) {
|
|
79254
|
+
oldLeft = Math.max(0, oldLeft - cost.old);
|
|
79255
|
+
newLeft = Math.max(0, newLeft - cost.new);
|
|
79256
|
+
continue;
|
|
79257
|
+
}
|
|
79258
|
+
oldLeft = 0;
|
|
79259
|
+
newLeft = 0;
|
|
79260
|
+
}
|
|
79157
79261
|
const wasMinusHeader = prevWasMinusHeader;
|
|
79158
79262
|
prevWasMinusHeader = isMinusHeader(rawLine);
|
|
79159
79263
|
if (rawLine.startsWith(HEADER_PREFIX_NOPREFIX)) {
|
|
79160
79264
|
const path9 = parseHeaderPath(rawLine, wasMinusHeader);
|
|
79161
79265
|
if (path9 !== null || rawLine.startsWith(HEADER_PREFIX) || wasMinusHeader)
|
|
79162
|
-
|
|
79266
|
+
yield { kind: "header", path: path9 };
|
|
79163
79267
|
continue;
|
|
79164
79268
|
}
|
|
79165
|
-
if (!currentPath)
|
|
79166
|
-
continue;
|
|
79167
79269
|
const match = HUNK_REGEX.exec(rawLine);
|
|
79168
79270
|
if (!match)
|
|
79169
79271
|
continue;
|
|
79170
|
-
|
|
79171
|
-
|
|
79172
|
-
|
|
79272
|
+
oldLeft = match[2] === undefined ? 1 : Number(match[2]);
|
|
79273
|
+
newLeft = match[4] === undefined ? 1 : Number(match[4]);
|
|
79274
|
+
yield { kind: "hunk", start: Number(match[3]), count: newLeft };
|
|
79275
|
+
}
|
|
79276
|
+
}
|
|
79277
|
+
function extractDiffLineRanges(diff) {
|
|
79278
|
+
const ranges = new Map;
|
|
79279
|
+
if (!diff)
|
|
79280
|
+
return ranges;
|
|
79281
|
+
let currentPath = null;
|
|
79282
|
+
for (const event of scanDiff(diff)) {
|
|
79283
|
+
if (event.kind === "header") {
|
|
79284
|
+
currentPath = event.path;
|
|
79285
|
+
continue;
|
|
79286
|
+
}
|
|
79287
|
+
if (!currentPath || event.count <= 0)
|
|
79173
79288
|
continue;
|
|
79174
79289
|
const entry = ranges.get(currentPath) ?? [];
|
|
79175
|
-
|
|
79176
|
-
ranges.set(currentPath, entry);
|
|
79290
|
+
ranges.set(currentPath, [...entry, { start: event.start, end: event.start + event.count - 1 }]);
|
|
79177
79291
|
}
|
|
79178
79292
|
return ranges;
|
|
79179
79293
|
}
|
|
@@ -80108,12 +80222,13 @@ async function performSemanticReground(turn, firstParsed, drops, ctx) {
|
|
|
80108
80222
|
const secondParsed = validateLLMShape(tryParseLLMJson(secondTurn.output));
|
|
80109
80223
|
const costUsd = (turn.estimatedCostUsd ?? 0) + (secondTurn.estimatedCostUsd ?? 0);
|
|
80110
80224
|
const dropCount = drops.length;
|
|
80111
|
-
|
|
80112
|
-
|
|
80113
|
-
|
|
80114
|
-
|
|
80115
|
-
|
|
80116
|
-
|
|
80225
|
+
const keepFirstTurn = (outcome) => ({
|
|
80226
|
+
...turn,
|
|
80227
|
+
output: withRepromptMarker2(turn.output, { dropCount, outcome, costUsd }),
|
|
80228
|
+
estimatedCostUsd: costUsd
|
|
80229
|
+
});
|
|
80230
|
+
if (!secondParsed)
|
|
80231
|
+
return keepFirstTurn("parse-failed");
|
|
80117
80232
|
const { accepted: secondAccepted } = filterByAcGroundingMinimal(secondParsed.findings, acceptanceCriteria);
|
|
80118
80233
|
const secondBlocking = secondAccepted.filter((f) => isBlockingSeverity(f.severity, threshold));
|
|
80119
80234
|
if (secondBlocking.length > 0) {
|
|
@@ -80141,10 +80256,7 @@ async function performSemanticReground(turn, firstParsed, drops, ctx) {
|
|
|
80141
80256
|
estimatedCostUsd: costUsd
|
|
80142
80257
|
};
|
|
80143
80258
|
}
|
|
80144
|
-
return
|
|
80145
|
-
...turn,
|
|
80146
|
-
output: withRepromptMarker2(turn.output, { dropCount, outcome: "still-dropped", costUsd })
|
|
80147
|
-
};
|
|
80259
|
+
return keepFirstTurn("still-dropped");
|
|
80148
80260
|
}
|
|
80149
80261
|
async function requoteBlockingFindings(findings, ctx) {
|
|
80150
80262
|
const threshold = ctx.input.blockingThreshold ?? "error";
|
|
@@ -82313,9 +82425,10 @@ function resolveHopCompleteOptions(options, currentAgent, primaryAgent, tier, mo
|
|
|
82313
82425
|
return { ...options, modelDef: resolveModel(model) };
|
|
82314
82426
|
return { ...options, modelDef: options.modelDefFor?.(currentAgent, tier) ?? options.modelDef };
|
|
82315
82427
|
}
|
|
82316
|
-
function resolveFinalDispatch(options, primaryAgent,
|
|
82428
|
+
function resolveFinalDispatch(options, primaryAgent, outcome) {
|
|
82429
|
+
const { fallbacks, finalTier, finalTarget } = outcome;
|
|
82317
82430
|
const agentName = fallbacks.at(-1)?.newAgent ?? primaryAgent;
|
|
82318
|
-
const hopOptions = resolveHopCompleteOptions(options, agentName, primaryAgent, finalTier);
|
|
82431
|
+
const hopOptions = resolveHopCompleteOptions(options, agentName, primaryAgent, finalTier, finalTarget?.model);
|
|
82319
82432
|
return { agentName, options: finalTier !== undefined ? { ...hopOptions, modelTier: finalTier } : hopOptions };
|
|
82320
82433
|
}
|
|
82321
82434
|
function buildFallbackRecord(input) {
|
|
@@ -83102,8 +83215,15 @@ function parseForm(request) {
|
|
|
83102
83215
|
const fields = entries.map(([key, property]) => fieldOf(key, property, required2.has(key)));
|
|
83103
83216
|
return fields.every((field) => field !== undefined) ? { ok: true, fields: withCompanions(fields) } : REFUSED;
|
|
83104
83217
|
}
|
|
83218
|
+
function ownAnswerHint(field) {
|
|
83219
|
+
if (field.companion === undefined)
|
|
83220
|
+
return "";
|
|
83221
|
+
if (!field.required)
|
|
83222
|
+
return ", or type your own answer";
|
|
83223
|
+
return field.kind === "multi" ? "; you may add your own after at least one choice" : "";
|
|
83224
|
+
}
|
|
83105
83225
|
function instruction(field) {
|
|
83106
|
-
const own = field
|
|
83226
|
+
const own = ownAnswerHint(field);
|
|
83107
83227
|
const skip = field.required ? "" : " Leave empty to skip.";
|
|
83108
83228
|
if (field.kind === "single")
|
|
83109
83229
|
return `Reply with one number or choice${own}.${skip}`;
|
|
@@ -92762,7 +92882,7 @@ var init_prompt_retry = __esm(() => {
|
|
|
92762
92882
|
});
|
|
92763
92883
|
|
|
92764
92884
|
// src/agents/acp/stream-bridge.ts
|
|
92765
|
-
import { randomUUID as
|
|
92885
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
92766
92886
|
function toolUpdate(toolName) {
|
|
92767
92887
|
return toolName === undefined ? { kind: "agent.tool_call_update" } : { kind: "agent.tool_call_update", toolName };
|
|
92768
92888
|
}
|
|
@@ -92815,7 +92935,7 @@ function sender(ctx) {
|
|
|
92815
92935
|
};
|
|
92816
92936
|
}
|
|
92817
92937
|
function startCall(ctx, now = Date.now) {
|
|
92818
|
-
const callId =
|
|
92938
|
+
const callId = randomUUID14();
|
|
92819
92939
|
const send = sender(ctx);
|
|
92820
92940
|
const base = {
|
|
92821
92941
|
callId,
|
|
@@ -92864,7 +92984,7 @@ var init_stream_bridge = __esm(() => {
|
|
|
92864
92984
|
});
|
|
92865
92985
|
|
|
92866
92986
|
// src/agents/acp/turn-loop.ts
|
|
92867
|
-
import { randomUUID as
|
|
92987
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
92868
92988
|
function used(state) {
|
|
92869
92989
|
return state.turnCount + state.asked;
|
|
92870
92990
|
}
|
|
@@ -92955,7 +93075,7 @@ async function runIteration(loop) {
|
|
|
92955
93075
|
}
|
|
92956
93076
|
const timer = armDeadline(controller, loop.deadline.remainingMs());
|
|
92957
93077
|
const call2 = startCall(session2.stream);
|
|
92958
|
-
const turnId = opts.turnId ??
|
|
93078
|
+
const turnId = opts.turnId ?? randomUUID15();
|
|
92959
93079
|
try {
|
|
92960
93080
|
session2.opts.onActiveCall?.(call2.callId, async () => controller.abort(new WatchdogCancel));
|
|
92961
93081
|
session2.slot.set({
|
|
@@ -93908,7 +94028,7 @@ class AgentManager {
|
|
|
93908
94028
|
sessionName,
|
|
93909
94029
|
prompt,
|
|
93910
94030
|
response: outcome.result.output,
|
|
93911
|
-
...resolveFinalDispatch(augmented, agentName, outcome
|
|
94031
|
+
...resolveFinalDispatch(augmented, agentName, outcome),
|
|
93912
94032
|
stage,
|
|
93913
94033
|
resolvedPermissions,
|
|
93914
94034
|
tokenUsage: outcome.result.tokenUsage,
|
|
@@ -95168,7 +95288,7 @@ var init_config_descriptions = __esm(() => {
|
|
|
95168
95288
|
"quality.stripEnvVars": "Environment variables to strip during verification",
|
|
95169
95289
|
tdd: "Test-driven development configuration",
|
|
95170
95290
|
"tdd.maxRetries": "Max retries per TDD session before escalating",
|
|
95171
|
-
"tdd.strategy":
|
|
95291
|
+
"tdd.strategy": 'TDD strategy: auto | strict | lite | off | simple ("tdd-simple" is accepted for simple)',
|
|
95172
95292
|
"tdd.sessionTiers": "Per-session model tier overrides",
|
|
95173
95293
|
"tdd.sessionTiers.testWriter": "Model tier for test-writer session",
|
|
95174
95294
|
"tdd.sessionTiers.implementer": "Ignored by design \u2014 implementer follows story.routing.modelTier + escalation, not this field. Kept optional so legacy configs still parse.",
|
|
@@ -98902,8 +99022,41 @@ var init_fix_diagnosis = __esm(() => {
|
|
|
98902
99022
|
init_import_resolution();
|
|
98903
99023
|
});
|
|
98904
99024
|
|
|
99025
|
+
// src/utils/drain-within.ts
|
|
99026
|
+
async function drainWithin(drain, deadlineMs) {
|
|
99027
|
+
let timer;
|
|
99028
|
+
const expired = new Promise((resolve37) => {
|
|
99029
|
+
timer = setTimeout(() => resolve37(""), deadlineMs);
|
|
99030
|
+
});
|
|
99031
|
+
try {
|
|
99032
|
+
return await Promise.race([drain, expired]);
|
|
99033
|
+
} finally {
|
|
99034
|
+
clearTimeout(timer);
|
|
99035
|
+
}
|
|
99036
|
+
}
|
|
99037
|
+
|
|
98905
99038
|
// src/acceptance/hardening.ts
|
|
98906
99039
|
import path12 from "path";
|
|
99040
|
+
async function awaitExitAndDrain(proc, timers) {
|
|
99041
|
+
const stdoutDrain = new Response(proc.stdout).text().catch(() => "");
|
|
99042
|
+
const stderrDrain = new Response(proc.stderr).text().catch(() => "");
|
|
99043
|
+
let exitCode;
|
|
99044
|
+
let output;
|
|
99045
|
+
try {
|
|
99046
|
+
exitCode = await proc.exited;
|
|
99047
|
+
const [stdout, stderr] = await Promise.all([
|
|
99048
|
+
drainWithin(stdoutDrain, _hardeningDeps.drainTimeoutMs),
|
|
99049
|
+
drainWithin(stderrDrain, _hardeningDeps.drainTimeoutMs)
|
|
99050
|
+
]);
|
|
99051
|
+
output = `${stdout}
|
|
99052
|
+
${stderr}`;
|
|
99053
|
+
} finally {
|
|
99054
|
+
clearTimeout(timers.killTimer);
|
|
99055
|
+
if (timers.sigkillTimer)
|
|
99056
|
+
clearTimeout(timers.sigkillTimer);
|
|
99057
|
+
}
|
|
99058
|
+
return { exitCode, output };
|
|
99059
|
+
}
|
|
98907
99060
|
async function processPackageGroup(ctx, packageDir, groupStories, language, result) {
|
|
98908
99061
|
await assertTrusted(packageDir, "acceptance-command");
|
|
98909
99062
|
const logger = getSafeLogger2();
|
|
@@ -98986,30 +99139,23 @@ async function processPackageGroup(ctx, packageDir, groupStories, language, resu
|
|
|
98986
99139
|
detached: true
|
|
98987
99140
|
});
|
|
98988
99141
|
let exitedBeforeSigkill = false;
|
|
98989
|
-
let sigkillTimer;
|
|
98990
99142
|
proc.exited.then(() => {
|
|
98991
99143
|
exitedBeforeSigkill = true;
|
|
98992
99144
|
}).catch(() => {});
|
|
98993
99145
|
const timeoutMs = config2.acceptance?.timeoutMs ?? DEFAULT_HARDENING_TIMEOUT_MS;
|
|
98994
|
-
const
|
|
98995
|
-
|
|
98996
|
-
|
|
98997
|
-
sigkillTimer =
|
|
98998
|
-
|
|
98999
|
-
|
|
99000
|
-
|
|
99001
|
-
|
|
99002
|
-
|
|
99003
|
-
|
|
99004
|
-
|
|
99005
|
-
|
|
99006
|
-
|
|
99007
|
-
]);
|
|
99008
|
-
clearTimeout(killTimer);
|
|
99009
|
-
if (sigkillTimer)
|
|
99010
|
-
clearTimeout(sigkillTimer);
|
|
99011
|
-
const output = `${stdout}
|
|
99012
|
-
${stderr}`;
|
|
99146
|
+
const timers = {
|
|
99147
|
+
killTimer: setTimeout(() => {
|
|
99148
|
+
killProcessGroup(proc.pid, "SIGTERM");
|
|
99149
|
+
timers.sigkillTimer = setTimeout(() => {
|
|
99150
|
+
timers.sigkillTimer = undefined;
|
|
99151
|
+
if (!exitedBeforeSigkill) {
|
|
99152
|
+
killProcessGroup(proc.pid, "SIGKILL");
|
|
99153
|
+
}
|
|
99154
|
+
}, HARDENING_SIGKILL_GRACE_PERIOD_MS);
|
|
99155
|
+
}, timeoutMs),
|
|
99156
|
+
sigkillTimer: undefined
|
|
99157
|
+
};
|
|
99158
|
+
const { exitCode, output } = await awaitExitAndDrain(proc, timers);
|
|
99013
99159
|
const failedACs = parseTestFailures(output);
|
|
99014
99160
|
const failedSet = new Set(failedACs.map((ac) => ac.toUpperCase()));
|
|
99015
99161
|
if (exitCode !== 0 && failedACs.length === 0) {
|
|
@@ -99114,19 +99260,59 @@ var init_hardening = __esm(() => {
|
|
|
99114
99260
|
writeFile: async (p, c) => {
|
|
99115
99261
|
await Bun.write(p, c);
|
|
99116
99262
|
},
|
|
99117
|
-
detectLanguage
|
|
99263
|
+
detectLanguage,
|
|
99264
|
+
drainTimeoutMs: 2000
|
|
99265
|
+
};
|
|
99266
|
+
});
|
|
99267
|
+
|
|
99268
|
+
// src/acceptance/override-keys.ts
|
|
99269
|
+
import { relative as relative26 } from "path";
|
|
99270
|
+
function scopedOverrideKey(workdir, packageDir, acId) {
|
|
99271
|
+
return `${relative26(workdir, packageDir) || "."}${OVERRIDE_SCOPE_SEPARATOR}${acId}`;
|
|
99272
|
+
}
|
|
99273
|
+
function definingPackageCount(acId, counts) {
|
|
99274
|
+
const n = Number(NUMBERED_AC.exec(acId)?.[1] ?? 0);
|
|
99275
|
+
if (n < 1)
|
|
99276
|
+
return 0;
|
|
99277
|
+
return [...counts.values()].filter((count2) => count2 >= n).length;
|
|
99278
|
+
}
|
|
99279
|
+
function createOverrideLookup(opts) {
|
|
99280
|
+
const table = opts.overrides ?? {};
|
|
99281
|
+
const reported = new Set;
|
|
99282
|
+
return {
|
|
99283
|
+
reasonFor(packageDir, acId) {
|
|
99284
|
+
const scoped2 = table[scopedOverrideKey(opts.workdir, packageDir, acId)];
|
|
99285
|
+
if (scoped2 !== undefined)
|
|
99286
|
+
return scoped2;
|
|
99287
|
+
const bare = table[acId];
|
|
99288
|
+
if (bare === undefined || !opts.multiPackage)
|
|
99289
|
+
return bare;
|
|
99290
|
+
if (definingPackageCount(acId, opts.acCountByPackageDir) === 1)
|
|
99291
|
+
return bare;
|
|
99292
|
+
if (!reported.has(acId)) {
|
|
99293
|
+
reported.add(acId);
|
|
99294
|
+
opts.onIgnoredBareKey(acId);
|
|
99295
|
+
}
|
|
99296
|
+
return;
|
|
99297
|
+
}
|
|
99118
99298
|
};
|
|
99299
|
+
}
|
|
99300
|
+
var OVERRIDE_SCOPE_SEPARATOR = "::", NUMBERED_AC;
|
|
99301
|
+
var init_override_keys = __esm(() => {
|
|
99302
|
+
NUMBERED_AC = /^AC-(\d+)$/;
|
|
99119
99303
|
});
|
|
99120
99304
|
|
|
99121
99305
|
// src/acceptance/index.ts
|
|
99122
99306
|
var exports_acceptance = {};
|
|
99123
99307
|
__export(exports_acceptance, {
|
|
99308
|
+
OVERRIDE_SCOPE_SEPARATOR: () => OVERRIDE_SCOPE_SEPARATOR,
|
|
99124
99309
|
_acceptanceExecutionDeps: () => _acceptanceExecutionDeps,
|
|
99125
99310
|
_groupDeps: () => _groupDeps,
|
|
99126
99311
|
acceptanceTestFilename: () => acceptanceTestFilename2,
|
|
99127
99312
|
buildAcceptanceRunCommand: () => buildAcceptanceRunCommand,
|
|
99128
99313
|
buildAcceptanceTestPrompt: () => buildAcceptanceTestPrompt,
|
|
99129
99314
|
checkAcceptanceCoverage: () => checkAcceptanceCoverage,
|
|
99315
|
+
createOverrideLookup: () => createOverrideLookup,
|
|
99130
99316
|
effectiveAcceptanceFramework: () => effectiveAcceptanceFramework,
|
|
99131
99317
|
findExistingAcceptanceTestPath: () => findExistingAcceptanceTestPath,
|
|
99132
99318
|
findMissingAcceptanceTestPaths: () => findMissingAcceptanceTestPaths,
|
|
@@ -99144,6 +99330,7 @@ __export(exports_acceptance, {
|
|
|
99144
99330
|
resolveSuggestedPackageFeatureTestPath: () => resolveSuggestedPackageFeatureTestPath,
|
|
99145
99331
|
resolveSuggestedTestFile: () => resolveSuggestedTestFile,
|
|
99146
99332
|
runHardeningPass: () => runHardeningPass,
|
|
99333
|
+
scopedOverrideKey: () => scopedOverrideKey,
|
|
99147
99334
|
substituteAcceptanceTestPath: () => substituteAcceptanceTestPath,
|
|
99148
99335
|
suggestedTestFilename: () => suggestedTestFilename,
|
|
99149
99336
|
warnMissingAcceptanceTests: () => warnMissingAcceptanceTests
|
|
@@ -99154,13 +99341,14 @@ var init_acceptance2 = __esm(() => {
|
|
|
99154
99341
|
init_fix_diagnosis();
|
|
99155
99342
|
init_generator();
|
|
99156
99343
|
init_hardening();
|
|
99344
|
+
init_override_keys();
|
|
99157
99345
|
init_refinement();
|
|
99158
99346
|
init_test_path();
|
|
99159
99347
|
});
|
|
99160
99348
|
|
|
99161
99349
|
// src/cli/features-acceptance.ts
|
|
99162
99350
|
import { existsSync as existsSync16 } from "fs";
|
|
99163
|
-
import { join as join79, relative as
|
|
99351
|
+
import { join as join79, relative as relative27 } from "path";
|
|
99164
99352
|
async function resolveFeatureAcceptance(featureName, workdir) {
|
|
99165
99353
|
let enabled = true;
|
|
99166
99354
|
try {
|
|
@@ -99181,11 +99369,11 @@ async function resolveFeatureAcceptance(featureName, workdir) {
|
|
|
99181
99369
|
const prd = await loadPRD(prdPath);
|
|
99182
99370
|
const testGroups = await groupStoriesByPackage(prd, repoRoot, featureName, config2.acceptance?.testPath, config2.project?.language);
|
|
99183
99371
|
const groups = await Promise.all(testGroups.map(async (g) => {
|
|
99184
|
-
const packageDir =
|
|
99372
|
+
const packageDir = relative27(repoRoot, g.packageDir);
|
|
99185
99373
|
const command2 = await resolveGroupCommand(repoRoot, packageDir, config2.acceptance?.command);
|
|
99186
99374
|
return {
|
|
99187
99375
|
packageDir,
|
|
99188
|
-
testPath:
|
|
99376
|
+
testPath: relative27(repoRoot, g.testPath),
|
|
99189
99377
|
exists: await Bun.file(g.testPath).exists(),
|
|
99190
99378
|
command: command2,
|
|
99191
99379
|
cwd: packageDir,
|
|
@@ -99240,7 +99428,7 @@ var init_feature_name = __esm(() => {
|
|
|
99240
99428
|
|
|
99241
99429
|
// src/cli/features-resolve.ts
|
|
99242
99430
|
import { existsSync as existsSync17, readdirSync as readdirSync3 } from "fs";
|
|
99243
|
-
import { join as join80, relative as
|
|
99431
|
+
import { join as join80, relative as relative28 } from "path";
|
|
99244
99432
|
async function resolveTestPatterns(workdir) {
|
|
99245
99433
|
try {
|
|
99246
99434
|
const config2 = await loadConfig(workdir);
|
|
@@ -99263,17 +99451,17 @@ async function searchSpecSource(naxDir, repoRoot, name) {
|
|
|
99263
99451
|
];
|
|
99264
99452
|
const docsSpecExact = join80(repoRoot, "docs", "specs", `SPEC-${name}.md`);
|
|
99265
99453
|
candidates.push({ abs: docsSpecExact, kind: "markdown" });
|
|
99266
|
-
const checked = candidates.map((c) =>
|
|
99454
|
+
const checked = candidates.map((c) => relative28(repoRoot, c.abs));
|
|
99267
99455
|
for (const { abs, kind } of candidates.slice(0, 2)) {
|
|
99268
99456
|
if (kind === "markdown") {
|
|
99269
99457
|
const nonEmpty2 = await isNonEmptyFile(abs);
|
|
99270
99458
|
if (nonEmpty2) {
|
|
99271
|
-
return { source: { kind, path:
|
|
99459
|
+
return { source: { kind, path: relative28(repoRoot, abs) }, checked };
|
|
99272
99460
|
}
|
|
99273
99461
|
}
|
|
99274
99462
|
}
|
|
99275
99463
|
if (await isNonEmptyFile(docsSpecExact)) {
|
|
99276
|
-
return { source: { kind: "markdown", path:
|
|
99464
|
+
return { source: { kind: "markdown", path: relative28(repoRoot, docsSpecExact) }, checked };
|
|
99277
99465
|
}
|
|
99278
99466
|
const docsSpecsDir = join80(repoRoot, "docs", "specs");
|
|
99279
99467
|
if (existsSync17(docsSpecsDir)) {
|
|
@@ -99281,7 +99469,7 @@ async function searchSpecSource(naxDir, repoRoot, name) {
|
|
|
99281
99469
|
for (const match of glob2.scanSync({ cwd: docsSpecsDir, absolute: false })) {
|
|
99282
99470
|
const abs = join80(docsSpecsDir, match);
|
|
99283
99471
|
if (await isNonEmptyFile(abs)) {
|
|
99284
|
-
const relPath =
|
|
99472
|
+
const relPath = relative28(repoRoot, abs);
|
|
99285
99473
|
if (!checked.includes(relPath))
|
|
99286
99474
|
checked.push(relPath);
|
|
99287
99475
|
return { source: { kind: "markdown", path: relPath }, checked };
|
|
@@ -99289,7 +99477,7 @@ async function searchSpecSource(naxDir, repoRoot, name) {
|
|
|
99289
99477
|
}
|
|
99290
99478
|
}
|
|
99291
99479
|
const prdAbs = join80(naxDir, "features", name, "prd.json");
|
|
99292
|
-
const prdRel =
|
|
99480
|
+
const prdRel = relative28(repoRoot, prdAbs);
|
|
99293
99481
|
if (!checked.includes(prdRel))
|
|
99294
99482
|
checked.push(prdRel);
|
|
99295
99483
|
if (existsSync17(prdAbs)) {
|
|
@@ -99341,8 +99529,8 @@ async function resolveFeatureSpec(name, workdir) {
|
|
|
99341
99529
|
return {
|
|
99342
99530
|
status: "ok",
|
|
99343
99531
|
featureName: null,
|
|
99344
|
-
specSource: { kind: "markdown", path:
|
|
99345
|
-
message: `resolved spec: ${
|
|
99532
|
+
specSource: { kind: "markdown", path: relative28(repoRoot, abs) },
|
|
99533
|
+
message: `resolved spec: ${relative28(repoRoot, abs)}`
|
|
99346
99534
|
};
|
|
99347
99535
|
}
|
|
99348
99536
|
if (name !== undefined && name.trim() !== "") {
|
|
@@ -99791,7 +99979,7 @@ var init_windsurf = __esm(() => {
|
|
|
99791
99979
|
|
|
99792
99980
|
// src/context/generator/index.ts
|
|
99793
99981
|
import { existsSync as existsSync19 } from "fs";
|
|
99794
|
-
import { join as join82, relative as
|
|
99982
|
+
import { join as join82, relative as relative29 } from "path";
|
|
99795
99983
|
async function loadContextContent(options, config2) {
|
|
99796
99984
|
if (!_generatorDeps.existsSync(options.contextPath)) {
|
|
99797
99985
|
throw new NaxError(`Context file not found: ${options.contextPath}`, "CONTEXT_FILE_NOT_FOUND", {
|
|
@@ -99922,7 +100110,7 @@ async function discoverWorkspacePackages2(repoRoot) {
|
|
|
99922
100110
|
}
|
|
99923
100111
|
async function generateForPackage(packageDir, config2, dryRun = false, repoRoot) {
|
|
99924
100112
|
const resolvedRepoRoot = repoRoot ?? packageDir;
|
|
99925
|
-
const relativePkgPath =
|
|
100113
|
+
const relativePkgPath = relative29(resolvedRepoRoot, packageDir);
|
|
99926
100114
|
const contextPath = join82(resolvedRepoRoot, ".nax", "mono", relativePkgPath, "context.md");
|
|
99927
100115
|
if (!_generatorDeps.existsSync(contextPath)) {
|
|
99928
100116
|
return [
|
|
@@ -100206,7 +100394,7 @@ var init_generate = __esm(() => {
|
|
|
100206
100394
|
|
|
100207
100395
|
// src/cli/init-context.ts
|
|
100208
100396
|
import { mkdir as mkdir25, readdir as readdir7 } from "fs/promises";
|
|
100209
|
-
import { basename as basename11, join as join84, relative as
|
|
100397
|
+
import { basename as basename11, join as join84, relative as relative30, sep as sep18 } from "path";
|
|
100210
100398
|
async function bunFileExists(path13) {
|
|
100211
100399
|
return Bun.file(path13).exists();
|
|
100212
100400
|
}
|
|
@@ -100233,7 +100421,7 @@ async function walkDir(root, current, out, maxFiles) {
|
|
|
100233
100421
|
continue;
|
|
100234
100422
|
await walkDir(root, join84(current, entry2.name), out, maxFiles);
|
|
100235
100423
|
} else if (entry2.isFile()) {
|
|
100236
|
-
out.push(
|
|
100424
|
+
out.push(relative30(root, join84(current, entry2.name)).replaceAll(sep18, "/"));
|
|
100237
100425
|
}
|
|
100238
100426
|
}
|
|
100239
100427
|
}
|
|
@@ -101437,7 +101625,7 @@ var init_resume_hydrate = __esm(() => {
|
|
|
101437
101625
|
});
|
|
101438
101626
|
|
|
101439
101627
|
// src/tdd/rollback.ts
|
|
101440
|
-
import { rm as
|
|
101628
|
+
import { rm as rm10 } from "fs/promises";
|
|
101441
101629
|
import { join as join88 } from "path";
|
|
101442
101630
|
async function runGitBounded2(args, workdir) {
|
|
101443
101631
|
if (!workdir) {
|
|
@@ -101558,18 +101746,18 @@ var init_rollback = __esm(() => {
|
|
|
101558
101746
|
autoCommitIfDirty,
|
|
101559
101747
|
getUntrackedPaths,
|
|
101560
101748
|
getGitRoot,
|
|
101561
|
-
rm:
|
|
101749
|
+
rm: rm10,
|
|
101562
101750
|
timeoutMs: ROLLBACK_GIT_TIMEOUT_MS,
|
|
101563
101751
|
drainTimeoutMs: ROLLBACK_DRAIN_TIMEOUT_MS
|
|
101564
101752
|
};
|
|
101565
101753
|
});
|
|
101566
101754
|
|
|
101567
101755
|
// src/utils/paths.ts
|
|
101568
|
-
import { join as join89, relative as
|
|
101756
|
+
import { join as join89, relative as relative31, sep as sep19 } from "path";
|
|
101569
101757
|
function packageDirRelative(projectDir, workdir) {
|
|
101570
101758
|
if (!projectDir || !workdir || workdir === projectDir)
|
|
101571
101759
|
return;
|
|
101572
|
-
const rel =
|
|
101760
|
+
const rel = relative31(projectDir, workdir);
|
|
101573
101761
|
if (rel === ".." || rel.startsWith(`..${sep19}`))
|
|
101574
101762
|
return;
|
|
101575
101763
|
return rel && rel !== "." ? rel : undefined;
|
|
@@ -106166,8 +106354,8 @@ var init_escalation = __esm(() => {
|
|
|
106166
106354
|
});
|
|
106167
106355
|
|
|
106168
106356
|
// src/execution/lock.ts
|
|
106169
|
-
import { randomUUID as
|
|
106170
|
-
import { rename as
|
|
106357
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
106358
|
+
import { rename as rename7, unlink as unlink6 } from "fs/promises";
|
|
106171
106359
|
import { hostname as hostname3 } from "os";
|
|
106172
106360
|
import path14 from "path";
|
|
106173
106361
|
async function serializeLockOperation(workdir, operation) {
|
|
@@ -106210,7 +106398,7 @@ function parseHolder(raw) {
|
|
|
106210
106398
|
}
|
|
106211
106399
|
}
|
|
106212
106400
|
async function publishFileAtomically(targetPath, content) {
|
|
106213
|
-
const tempPath = `${targetPath}.${
|
|
106401
|
+
const tempPath = `${targetPath}.${randomUUID16()}.tmp`;
|
|
106214
106402
|
try {
|
|
106215
106403
|
await Bun.write(tempPath, content);
|
|
106216
106404
|
const fs = await import("fs");
|
|
@@ -106383,14 +106571,14 @@ var init_lock2 = __esm(() => {
|
|
|
106383
106571
|
init_logger2();
|
|
106384
106572
|
pendingLockOperations = new Map;
|
|
106385
106573
|
_lockDeps = {
|
|
106386
|
-
rename:
|
|
106574
|
+
rename: rename7,
|
|
106387
106575
|
host: () => hostname3(),
|
|
106388
106576
|
readLockText: (lockPath) => Bun.file(lockPath).text()
|
|
106389
106577
|
};
|
|
106390
106578
|
});
|
|
106391
106579
|
|
|
106392
106580
|
// src/execution/feature-lock.ts
|
|
106393
|
-
import { mkdir as mkdir28, rename as
|
|
106581
|
+
import { mkdir as mkdir28, rename as rename8, unlink as unlink7 } from "fs/promises";
|
|
106394
106582
|
import { hostname as hostname4 } from "os";
|
|
106395
106583
|
import path15 from "path";
|
|
106396
106584
|
function validateFeatureId2(featureId) {
|
|
@@ -106629,7 +106817,7 @@ var init_feature_lock = __esm(() => {
|
|
|
106629
106817
|
featureLockPath,
|
|
106630
106818
|
host: () => hostname4(),
|
|
106631
106819
|
isProcessAlive,
|
|
106632
|
-
rename:
|
|
106820
|
+
rename: rename8,
|
|
106633
106821
|
tryExclusiveCreate,
|
|
106634
106822
|
unlink: unlink7
|
|
106635
106823
|
};
|
|
@@ -107799,6 +107987,17 @@ var init_acceptance3 = __esm(() => {
|
|
|
107799
107987
|
storiesByPackageDir.set(pkgDir, (storiesByPackageDir.get(pkgDir) ?? 0) + 1);
|
|
107800
107988
|
acsByPackageDir.set(pkgDir, (acsByPackageDir.get(pkgDir) ?? 0) + s.acceptanceCriteria.length);
|
|
107801
107989
|
}
|
|
107990
|
+
const overrideLookup = createOverrideLookup({
|
|
107991
|
+
overrides: ctx.prd.acceptanceOverrides,
|
|
107992
|
+
workdir: ctx.workdir,
|
|
107993
|
+
acCountByPackageDir: acsByPackageDir,
|
|
107994
|
+
multiPackage: testGroups.length > 1,
|
|
107995
|
+
onIgnoredBareKey: (acId) => logger.warn("acceptance", "Bare acceptance override ignored: several packages define this AC id", {
|
|
107996
|
+
storyId: ctx.story.id,
|
|
107997
|
+
acId,
|
|
107998
|
+
hint: `scope it to one package: "<package>::${acId}"`
|
|
107999
|
+
})
|
|
108000
|
+
});
|
|
107802
108001
|
const allFailedACs = [];
|
|
107803
108002
|
const seenAcKeys = new Set;
|
|
107804
108003
|
const allFindings = [];
|
|
@@ -107856,14 +108055,14 @@ var init_acceptance3 = __esm(() => {
|
|
|
107856
108055
|
const output = execution.output ?? "";
|
|
107857
108056
|
allOutputParts.push(output);
|
|
107858
108057
|
const { failedACs, taggedFailureCount } = parseTestFailuresDetailed(output);
|
|
107859
|
-
const
|
|
107860
|
-
const actualFailures = failedACs.filter((acId) => !
|
|
107861
|
-
const overriddenFailures = failedACs.filter((acId) =>
|
|
108058
|
+
const reasonFor = (acId) => overrideLookup.reasonFor(packageDir, acId);
|
|
108059
|
+
const actualFailures = failedACs.filter((acId) => !reasonFor(acId));
|
|
108060
|
+
const overriddenFailures = failedACs.filter((acId) => reasonFor(acId));
|
|
107862
108061
|
if (overriddenFailures.length > 0) {
|
|
107863
108062
|
logger.warn("acceptance", "Skipped failures (overridden)", {
|
|
107864
108063
|
storyId: ctx.story.id,
|
|
107865
108064
|
overriddenFailures,
|
|
107866
|
-
overrides: overriddenFailures.map((acId) => ({ acId, reason:
|
|
108065
|
+
overrides: overriddenFailures.map((acId) => ({ acId, reason: reasonFor(acId) }))
|
|
107867
108066
|
});
|
|
107868
108067
|
}
|
|
107869
108068
|
if (failedACs.length === 0 && exitCode !== 0) {
|
|
@@ -108973,7 +109172,7 @@ var init_scope_files = __esm(() => {
|
|
|
108973
109172
|
});
|
|
108974
109173
|
|
|
108975
109174
|
// src/pipeline/stages/context.ts
|
|
108976
|
-
import { randomUUID as
|
|
109175
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
108977
109176
|
import { join as join99 } from "path";
|
|
108978
109177
|
async function runV2Path(ctx) {
|
|
108979
109178
|
const logger = getLogger2();
|
|
@@ -109214,7 +109413,7 @@ var init_context3 = __esm(() => {
|
|
|
109214
109413
|
createOrchestrator: createDefaultOrchestrator,
|
|
109215
109414
|
loadPlugins: loadPluginProviders,
|
|
109216
109415
|
v1FeatureProvider: () => new FeatureContextProvider,
|
|
109217
|
-
uuid: () =>
|
|
109416
|
+
uuid: () => randomUUID17(),
|
|
109218
109417
|
readDigest: readDigestFile,
|
|
109219
109418
|
writeDigest: writeDigestFile,
|
|
109220
109419
|
loadFeatureManifests,
|
|
@@ -110856,7 +111055,8 @@ async function executeHook(hookDef, ctx, workdir) {
|
|
|
110856
111055
|
stdin: new Response(contextJson),
|
|
110857
111056
|
stdout: "pipe",
|
|
110858
111057
|
stderr: "pipe",
|
|
110859
|
-
env: buildAllowedEnv({ env: env2 })
|
|
111058
|
+
env: buildAllowedEnv({ env: env2 }),
|
|
111059
|
+
detached: true
|
|
110860
111060
|
});
|
|
110861
111061
|
let timedOut = false;
|
|
110862
111062
|
let killTimeoutId;
|
|
@@ -111759,7 +111959,7 @@ var init_headless_formatter = __esm(() => {
|
|
|
111759
111959
|
|
|
111760
111960
|
// src/execution/lifecycle/run-tmp-wipe.ts
|
|
111761
111961
|
import { lstatSync as lstatSync4 } from "fs";
|
|
111762
|
-
import { rm as
|
|
111962
|
+
import { rm as rm11 } from "fs/promises";
|
|
111763
111963
|
function inspect(path19) {
|
|
111764
111964
|
try {
|
|
111765
111965
|
return _runTmpWipeDeps.exists(path19) ? { state: "present" } : { state: "absent" };
|
|
@@ -111799,7 +111999,7 @@ var init_run_tmp_wipe = __esm(() => {
|
|
|
111799
111999
|
init_internal();
|
|
111800
112000
|
init_logger2();
|
|
111801
112001
|
_runTmpWipeDeps = {
|
|
111802
|
-
remove: (path19) =>
|
|
112002
|
+
remove: (path19) => rm11(path19, { recursive: true, force: true }),
|
|
111803
112003
|
exists: (path19) => {
|
|
111804
112004
|
try {
|
|
111805
112005
|
lstatSync4(path19);
|
|
@@ -111814,7 +112014,7 @@ var init_run_tmp_wipe = __esm(() => {
|
|
|
111814
112014
|
});
|
|
111815
112015
|
|
|
111816
112016
|
// src/execution/lifecycle/scratchpad-wipe.ts
|
|
111817
|
-
import { rm as
|
|
112017
|
+
import { rm as rm12 } from "fs/promises";
|
|
111818
112018
|
import { join as join102 } from "path";
|
|
111819
112019
|
async function wipeScratchpad(workdir, opts = {}) {
|
|
111820
112020
|
if (opts.dryRun)
|
|
@@ -111837,7 +112037,7 @@ var init_scratchpad_wipe = __esm(() => {
|
|
|
111837
112037
|
init_internal();
|
|
111838
112038
|
init_logger2();
|
|
111839
112039
|
_scratchpadWipeDeps = {
|
|
111840
|
-
remove: (path19) =>
|
|
112040
|
+
remove: (path19) => rm12(path19, { recursive: true, force: true })
|
|
111841
112041
|
};
|
|
111842
112042
|
});
|
|
111843
112043
|
|
|
@@ -113220,7 +113420,7 @@ var init_rtk = __esm(() => {
|
|
|
113220
113420
|
});
|
|
113221
113421
|
|
|
113222
113422
|
// src/execution/status-file.ts
|
|
113223
|
-
import { rename as
|
|
113423
|
+
import { rename as rename9, unlink as unlink8 } from "fs/promises";
|
|
113224
113424
|
import { resolve as resolve39 } from "path";
|
|
113225
113425
|
function countProgress(prd) {
|
|
113226
113426
|
const stories = prd.userStories;
|
|
@@ -113284,7 +113484,7 @@ async function writeStatusFile(filePath2, status) {
|
|
|
113284
113484
|
await unlink8(tmpPath);
|
|
113285
113485
|
} catch {}
|
|
113286
113486
|
await Bun.write(tmpPath, JSON.stringify(status, null, 2));
|
|
113287
|
-
await
|
|
113487
|
+
await rename9(tmpPath, resolvedPath);
|
|
113288
113488
|
}
|
|
113289
113489
|
var init_status_file = __esm(() => {
|
|
113290
113490
|
init_errors4();
|
|
@@ -115160,7 +115360,7 @@ async function* streamJsonlLines(file2) {
|
|
|
115160
115360
|
}
|
|
115161
115361
|
|
|
115162
115362
|
// src/plugins/builtin/curator/rollup-prune.ts
|
|
115163
|
-
import { appendFile as appendFile6, rename as
|
|
115363
|
+
import { appendFile as appendFile6, rename as rename10, unlink as unlink9, writeFile as writeFile12 } from "fs/promises";
|
|
115164
115364
|
async function scanProjectRunIds(rollupPath, projectKey) {
|
|
115165
115365
|
const maxTsByRunId = new Map;
|
|
115166
115366
|
for await (const line of streamJsonlLines(Bun.file(rollupPath))) {
|
|
@@ -115205,7 +115405,7 @@ async function pruneRollupUnlocked(input) {
|
|
|
115205
115405
|
buffer = "";
|
|
115206
115406
|
};
|
|
115207
115407
|
try {
|
|
115208
|
-
await
|
|
115408
|
+
await writeFile12(tmpPath, "");
|
|
115209
115409
|
for await (const line of streamJsonlLines(Bun.file(rollupPath))) {
|
|
115210
115410
|
if (!line.trim())
|
|
115211
115411
|
continue;
|
|
@@ -115241,7 +115441,7 @@ async function pruneRollupUnlocked(input) {
|
|
|
115241
115441
|
await flush();
|
|
115242
115442
|
}
|
|
115243
115443
|
await flush();
|
|
115244
|
-
await
|
|
115444
|
+
await rename10(tmpPath, rollupPath);
|
|
115245
115445
|
} catch (err) {
|
|
115246
115446
|
await unlink9(tmpPath).catch(() => {});
|
|
115247
115447
|
throw err;
|
|
@@ -115640,8 +115840,8 @@ function collectRectify(context, entry2, data) {
|
|
|
115640
115840
|
ts: stringValue(entry2.timestamp ?? entry2.ts, now()),
|
|
115641
115841
|
kind: "rectify-cycle",
|
|
115642
115842
|
payload: {
|
|
115643
|
-
iteration: numberValue(data.
|
|
115644
|
-
status:
|
|
115843
|
+
iteration: numberValue(data.iterationCount, 1),
|
|
115844
|
+
status: data.exitReason === "resolved" ? "passed" : "failed"
|
|
115645
115845
|
}
|
|
115646
115846
|
};
|
|
115647
115847
|
}
|
|
@@ -115733,7 +115933,7 @@ async function collectFromRunJsonl(context) {
|
|
|
115733
115933
|
observations.push(collectPullCall(context, entry2, data));
|
|
115734
115934
|
} else if (stage === "acceptance" && message === "verdict") {
|
|
115735
115935
|
observations.push(collectAcceptanceVerdict(context, entry2, data));
|
|
115736
|
-
} else if (stage === "
|
|
115936
|
+
} else if (stage === "story-orchestrator" && typeof data.iterationCount === "number") {
|
|
115737
115937
|
observations.push(collectRectify(context, entry2, data));
|
|
115738
115938
|
} else if (stage === "escalation" && message.includes("Escalating")) {
|
|
115739
115939
|
observations.push(collectEscalation(context, entry2, data));
|
|
@@ -116098,7 +116298,7 @@ function renderProposals(proposals, runId, observationCount, provenance) {
|
|
|
116098
116298
|
}
|
|
116099
116299
|
|
|
116100
116300
|
// src/plugins/builtin/curator/rollup.ts
|
|
116101
|
-
import { appendFile as appendFile7, mkdir as mkdir30, writeFile as
|
|
116301
|
+
import { appendFile as appendFile7, mkdir as mkdir30, writeFile as writeFile13 } from "fs/promises";
|
|
116102
116302
|
import * as path22 from "path";
|
|
116103
116303
|
async function appendToRollup(observations, rollupPath) {
|
|
116104
116304
|
const dir = path22.dirname(rollupPath);
|
|
@@ -116111,7 +116311,7 @@ async function appendToRollupUnlocked(observations, rollupPath) {
|
|
|
116111
116311
|
if (observations.length === 0) {
|
|
116112
116312
|
const f = Bun.file(rollupPath);
|
|
116113
116313
|
if (!await f.exists()) {
|
|
116114
|
-
await
|
|
116314
|
+
await writeFile13(rollupPath, "");
|
|
116115
116315
|
}
|
|
116116
116316
|
return;
|
|
116117
116317
|
}
|
|
@@ -117183,7 +117383,7 @@ var init_language_commands = __esm(() => {
|
|
|
117183
117383
|
});
|
|
117184
117384
|
|
|
117185
117385
|
// src/review/scoped-lint.ts
|
|
117186
|
-
import { join as join109, relative as
|
|
117386
|
+
import { join as join109, relative as relative33 } from "path";
|
|
117187
117387
|
function normalizePath3(path25) {
|
|
117188
117388
|
return path25.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
117189
117389
|
}
|
|
@@ -117209,7 +117409,7 @@ async function listChangedFiles(workdir, baseRef) {
|
|
|
117209
117409
|
function inferActivePackageDir(workdir, projectDir) {
|
|
117210
117410
|
if (!projectDir)
|
|
117211
117411
|
return;
|
|
117212
|
-
const rel = normalizePath3(
|
|
117412
|
+
const rel = normalizePath3(relative33(projectDir, workdir));
|
|
117213
117413
|
if (!rel || rel === "." || rel.startsWith(".."))
|
|
117214
117414
|
return;
|
|
117215
117415
|
return rel;
|
|
@@ -118294,8 +118494,8 @@ function resolveCanonicalTargetPath(projectDir, canonicalFile) {
|
|
|
118294
118494
|
const root = resolve42(projectDir);
|
|
118295
118495
|
if (target !== root && !target.startsWith(root + sep21))
|
|
118296
118496
|
return null;
|
|
118297
|
-
const
|
|
118298
|
-
return CURATOR_TARGET_SHAPES.some((shape) => shape.test(
|
|
118497
|
+
const relative34 = target.slice(root.length + 1).replaceAll(sep21, "/");
|
|
118498
|
+
return CURATOR_TARGET_SHAPES.some((shape) => shape.test(relative34)) ? target : null;
|
|
118299
118499
|
}
|
|
118300
118500
|
function isWithinCanonicalRulesDir(projectDir, targetPath) {
|
|
118301
118501
|
const rulesRoot = resolve42(projectDir, CANONICAL_RULES_DIR);
|
|
@@ -118881,7 +119081,7 @@ __export(exports_migrate, {
|
|
|
118881
119081
|
partitionTrackedCandidates: () => partitionTrackedCandidates
|
|
118882
119082
|
});
|
|
118883
119083
|
import { existsSync as existsSync30 } from "fs";
|
|
118884
|
-
import { mkdir as mkdir32, readdir as readdir10, rename as
|
|
119084
|
+
import { mkdir as mkdir32, readdir as readdir10, rename as rename11 } from "fs/promises";
|
|
118885
119085
|
import path26 from "path";
|
|
118886
119086
|
async function detectGeneratedContent(naxDir) {
|
|
118887
119087
|
if (!existsSync30(naxDir))
|
|
@@ -119066,7 +119266,7 @@ async function migrateCommand(options) {
|
|
|
119066
119266
|
const archiveBase = path26.join(globalConfigDir(), "_archive");
|
|
119067
119267
|
const archiveDest = path26.join(archiveBase, `${options.reclaim}-${Date.now()}`);
|
|
119068
119268
|
await mkdir32(archiveBase, { recursive: true });
|
|
119069
|
-
await
|
|
119269
|
+
await rename11(src, archiveDest);
|
|
119070
119270
|
logger.info("migrate", `Reclaimed: archived to ${archiveDest}`, { storyId: "_migrate" });
|
|
119071
119271
|
return;
|
|
119072
119272
|
}
|
|
@@ -119165,7 +119365,7 @@ async function migrateCommand(options) {
|
|
|
119165
119365
|
Remove the destination or run nax migrate --dry-run to inspect.`, "MIGRATE_CONFLICT", { stage: "migrate", src: candidate.srcPath, dest });
|
|
119166
119366
|
}
|
|
119167
119367
|
try {
|
|
119168
|
-
await
|
|
119368
|
+
await rename11(candidate.srcPath, dest);
|
|
119169
119369
|
} catch (err) {
|
|
119170
119370
|
const isXdev = err instanceof Error && "code" in err && err.code === "EXDEV";
|
|
119171
119371
|
if (isXdev) {
|
|
@@ -122019,7 +122219,7 @@ var init_queue_file_lock = __esm(() => {
|
|
|
122019
122219
|
});
|
|
122020
122220
|
|
|
122021
122221
|
// src/execution/queue-handler.ts
|
|
122022
|
-
import { rename as
|
|
122222
|
+
import { rename as rename12, unlink as unlink12 } from "fs/promises";
|
|
122023
122223
|
import path29 from "path";
|
|
122024
122224
|
function getSafeLogger9() {
|
|
122025
122225
|
try {
|
|
@@ -122039,7 +122239,7 @@ async function claimCommandsLocked(queuePath, processingPath, logger) {
|
|
|
122039
122239
|
return null;
|
|
122040
122240
|
}
|
|
122041
122241
|
try {
|
|
122042
|
-
await
|
|
122242
|
+
await rename12(queuePath, processingPath);
|
|
122043
122243
|
} catch (error48) {
|
|
122044
122244
|
logger?.warn("queue", "Failed to rename queue file for processing", {
|
|
122045
122245
|
error: error48.message
|
|
@@ -122215,7 +122415,7 @@ var init_run_cost_reconcile = __esm(() => {
|
|
|
122215
122415
|
});
|
|
122216
122416
|
|
|
122217
122417
|
// src/finish/audit.ts
|
|
122218
|
-
import { appendFile as appendFile8, mkdir as mkdir34, readFile as readFile10, writeFile as
|
|
122418
|
+
import { appendFile as appendFile8, mkdir as mkdir34, readFile as readFile10, writeFile as writeFile14 } from "fs/promises";
|
|
122219
122419
|
import { join as join120 } from "path";
|
|
122220
122420
|
function roundsPath(t) {
|
|
122221
122421
|
return join120(t.auditDir, `${t.runId}.jsonl`);
|
|
@@ -122243,7 +122443,7 @@ async function updateLedger(t, result) {
|
|
|
122243
122443
|
};
|
|
122244
122444
|
try {
|
|
122245
122445
|
await mkdir34(t.auditDir, { recursive: true });
|
|
122246
|
-
await
|
|
122446
|
+
await writeFile14(ledgerPath(t.auditDir), `${JSON.stringify(entry2, null, 2)}
|
|
122247
122447
|
`, "utf8");
|
|
122248
122448
|
} catch {}
|
|
122249
122449
|
}
|
|
@@ -122293,7 +122493,7 @@ async function writeResult(t, result, options = {}) {
|
|
|
122293
122493
|
const rounds = await readRounds(t);
|
|
122294
122494
|
const withRounds = rounds.length > 0 ? { ...result, rounds } : result;
|
|
122295
122495
|
await mkdir34(t.auditDir, { recursive: true });
|
|
122296
|
-
await
|
|
122496
|
+
await writeFile14(resultPath(t), `${JSON.stringify(withRounds, null, 2)}
|
|
122297
122497
|
`, "utf8");
|
|
122298
122498
|
if (options.ledger === false)
|
|
122299
122499
|
return;
|
|
@@ -122826,7 +123026,7 @@ function languageRunner(language) {
|
|
|
122826
123026
|
function buildAcceptanceCommand(repoRoot, group) {
|
|
122827
123027
|
const absFile = shellQuote(`${repoRoot}/${group.testPath}`);
|
|
122828
123028
|
const template = group.command ?? `${languageRunner(group.language)} {{FILE}}`;
|
|
122829
|
-
return template.replace(/\{\{FILE\}\}|\{\{file\}\}|\{\{files\}\}/g, absFile);
|
|
123029
|
+
return template.replace(/\{\{FILE\}\}|\{\{file\}\}|\{\{files\}\}/g, () => absFile);
|
|
122830
123030
|
}
|
|
122831
123031
|
async function runAcceptanceGate(repoRoot, groups, opts = {}) {
|
|
122832
123032
|
const chunks = [];
|
|
@@ -125060,7 +125260,7 @@ var init_interaction3 = __esm(() => {
|
|
|
125060
125260
|
});
|
|
125061
125261
|
|
|
125062
125262
|
// src/pipeline/subscribers/registry.ts
|
|
125063
|
-
import { mkdir as mkdir36, writeFile as
|
|
125263
|
+
import { mkdir as mkdir36, writeFile as writeFile15 } from "fs/promises";
|
|
125064
125264
|
import { basename as basename16, join as join124 } from "path";
|
|
125065
125265
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
125066
125266
|
const logger = getSafeLogger2();
|
|
@@ -125080,7 +125280,7 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
125080
125280
|
eventsDir: join124(outputDir, "features", feature, "runs"),
|
|
125081
125281
|
registeredAt: new Date().toISOString()
|
|
125082
125282
|
};
|
|
125083
|
-
await
|
|
125283
|
+
await writeFile15(metaFile, JSON.stringify(meta3, null, 2));
|
|
125084
125284
|
} catch (err) {
|
|
125085
125285
|
logger?.warn("registry-writer", "Failed to write meta.json (non-fatal)", {
|
|
125086
125286
|
path: metaFile,
|
|
@@ -128014,7 +128214,7 @@ __export(exports_story_size_gate, {
|
|
|
128014
128214
|
function countBulletPoints(text) {
|
|
128015
128215
|
const lines2 = text.split(`
|
|
128016
128216
|
`);
|
|
128017
|
-
const bulletPattern = /^\s*[-*\u2022]|\d
|
|
128217
|
+
const bulletPattern = /^\s*(?:[-*\u2022]|\d+\.)\s/;
|
|
128018
128218
|
return lines2.filter((line) => bulletPattern.test(line)).length;
|
|
128019
128219
|
}
|
|
128020
128220
|
function analyzeStory(story, config2) {
|
|
@@ -153098,9 +153298,9 @@ function parseSchedule(input, now3) {
|
|
|
153098
153298
|
const trimmed = input.trim();
|
|
153099
153299
|
if (trimmed === "")
|
|
153100
153300
|
return { ok: false, error: `Empty schedule value. ${ACCEPTED}` };
|
|
153101
|
-
const
|
|
153102
|
-
if (
|
|
153103
|
-
return
|
|
153301
|
+
const relative34 = parseRelative(trimmed, now3);
|
|
153302
|
+
if (relative34)
|
|
153303
|
+
return relative34;
|
|
153104
153304
|
const timeOfDay = parseTimeOfDay(trimmed, now3);
|
|
153105
153305
|
if (timeOfDay)
|
|
153106
153306
|
return timeOfDay;
|