@nathapp/nax 0.83.0-canary.1 → 0.83.0-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nax.js +978 -365
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -2668,7 +2668,7 @@ var package_default;
|
|
|
2668
2668
|
var init_package = __esm(() => {
|
|
2669
2669
|
package_default = {
|
|
2670
2670
|
name: "@nathapp/nax",
|
|
2671
|
-
version: "0.83.0-canary.
|
|
2671
|
+
version: "0.83.0-canary.2",
|
|
2672
2672
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
2673
2673
|
type: "module",
|
|
2674
2674
|
bin: {
|
|
@@ -17962,7 +17962,8 @@ var init_schemas_sandbox = __esm(() => {
|
|
|
17962
17962
|
backend: exports_external.enum(["srt"]).default("srt"),
|
|
17963
17963
|
filesystem: exports_external.object({
|
|
17964
17964
|
allowWrite: exports_external.array(literalPath).default([]),
|
|
17965
|
-
denyRead: exports_external.array(literalPath).default([])
|
|
17965
|
+
denyRead: exports_external.array(literalPath).default([]),
|
|
17966
|
+
allowSharedTmp: exports_external.boolean().default(false)
|
|
17966
17967
|
}).prefault({}),
|
|
17967
17968
|
network: exports_external.object({
|
|
17968
17969
|
allowedDomains: exports_external.array(exports_external.string()).optional()
|
|
@@ -18278,8 +18279,8 @@ function describeNetwork(network) {
|
|
|
18278
18279
|
return "network access is disabled";
|
|
18279
18280
|
return `network access is limited to ${network.join(", ")}`;
|
|
18280
18281
|
}
|
|
18281
|
-
function sandboxSentence(network) {
|
|
18282
|
-
return
|
|
18282
|
+
function sandboxSentence(network, sharedTmp = true) {
|
|
18283
|
+
return `inside an OS sandbox: writes are allowed only under the repository root, ${tempRootsPhrase(sharedTmp)} and ` + "package-manager caches -- and nothing under .nax/ except .nax/scratchpad/, since .nax/ is nax's own state " + "(change a feature's acceptance test with the Edit tool); credential files (~/.ssh, ~/.aws, ~/.npmrc, nax credentials and similar) are unreadable; " + `${describeNetwork(network)}. A write anywhere else fails with "Operation not permitted" or "Read-only file system" ` + "-- that is the sandbox, not a bug in your command.";
|
|
18283
18284
|
}
|
|
18284
18285
|
function unsandboxedSentence(reason) {
|
|
18285
18286
|
return `Commands are NOT sandboxed on this machine (${reason}).`;
|
|
@@ -18287,10 +18288,11 @@ function unsandboxedSentence(reason) {
|
|
|
18287
18288
|
function rawBashRefusalReason(reason) {
|
|
18288
18289
|
return `sandbox unavailable (${reason}): raw bash requires the sandbox when execution.sandbox.enabled is true -- ` + "set this stage's bashApproval to gated or escalate, or disable the sandbox.";
|
|
18289
18290
|
}
|
|
18290
|
-
function denialHintLine(writeRoots) {
|
|
18291
|
-
|
|
18291
|
+
function denialHintLine(writeRoots, sharedTmp = false) {
|
|
18292
|
+
const tempClause = sharedTmp ? "" : " For temporary files use $TMPDIR or .nax/scratchpad/, not /tmp.";
|
|
18293
|
+
return `note: this command ran in the nax sandbox; that failure may be a sandbox denial -- writable roots: ${writeRoots.join(", ")}.` + tempClause;
|
|
18292
18294
|
}
|
|
18293
|
-
var LIKELY_SANDBOX_DENIAL;
|
|
18295
|
+
var LIKELY_SANDBOX_DENIAL, tempRootsPhrase = (sharedTmp) => sharedTmp ? "the system temp directories" : "this run's temp directory ($TMPDIR)";
|
|
18294
18296
|
var init_messages = __esm(() => {
|
|
18295
18297
|
LIKELY_SANDBOX_DENIAL = /Operation not permitted|Read-only file system/;
|
|
18296
18298
|
});
|
|
@@ -18325,22 +18327,22 @@ async function ensureTmpDir(tmpDir) {
|
|
|
18325
18327
|
return false;
|
|
18326
18328
|
}
|
|
18327
18329
|
}
|
|
18328
|
-
async function runUnwrapped(req, sandbox,
|
|
18330
|
+
async function runUnwrapped(req, sandbox, env2) {
|
|
18329
18331
|
const argv = logicalArgv(req);
|
|
18330
|
-
const
|
|
18332
|
+
const overlay = env2.tmpDir !== undefined ? withTmpEnv(req, env2.tmpDir) : req.env;
|
|
18331
18333
|
const result = await _launcherDeps.runArgv({
|
|
18332
18334
|
argv,
|
|
18333
18335
|
cwd: req.cwd,
|
|
18334
18336
|
timeoutMs: req.timeoutMs,
|
|
18335
18337
|
stripEnvVars: [...req.stripEnvVars],
|
|
18336
|
-
...
|
|
18338
|
+
...overlay !== undefined ? { env: overlay } : {},
|
|
18337
18339
|
...req.signal !== undefined ? { signal: req.signal } : {}
|
|
18338
18340
|
});
|
|
18339
18341
|
return { ...result, executed: argv, sandbox };
|
|
18340
18342
|
}
|
|
18341
|
-
async function runWrapped(req, backend, policy,
|
|
18343
|
+
async function runWrapped(req, backend, policy, env2) {
|
|
18342
18344
|
const rawCommand = req.spec.kind === "shell" ? req.spec.command : quoteArgvForShell(req.spec.argv);
|
|
18343
|
-
const command = tmpDir !== undefined ? `${tmpEnvPrefix(tmpDir)}${rawCommand}` : rawCommand;
|
|
18345
|
+
const command = env2.tmpDir !== undefined ? `${tmpEnvPrefix(env2.tmpDir)}${rawCommand}` : rawCommand;
|
|
18344
18346
|
const shell = req.spec.kind === "shell" ? req.spec.shell : "/bin/sh";
|
|
18345
18347
|
const commandId = _launcherDeps.newCommandId();
|
|
18346
18348
|
let argv;
|
|
@@ -18365,7 +18367,10 @@ async function runWrapped(req, backend, policy, tmpDir) {
|
|
|
18365
18367
|
});
|
|
18366
18368
|
const denied = result.exitCode !== 0 && LIKELY_SANDBOX_DENIAL.test(result.stderr);
|
|
18367
18369
|
const violations = backend.annotate(commandId, result.stderr);
|
|
18368
|
-
const extra = [
|
|
18370
|
+
const extra = [
|
|
18371
|
+
...denied ? [denialHintLine(policy.writeRoots, env2.sharedTmp)] : [],
|
|
18372
|
+
...violations !== "" ? [violations] : []
|
|
18373
|
+
];
|
|
18369
18374
|
return {
|
|
18370
18375
|
...result,
|
|
18371
18376
|
stderr: extra.length > 0 ? `${result.stderr}
|
|
@@ -18385,14 +18390,18 @@ ${extra.join(`
|
|
|
18385
18390
|
}
|
|
18386
18391
|
function createCommandLauncher(opts) {
|
|
18387
18392
|
const { state } = opts;
|
|
18393
|
+
const env2 = {
|
|
18394
|
+
tmpDir: opts.tmpDir,
|
|
18395
|
+
sharedTmp: state.kind !== "available" || state.sharedTmp !== false
|
|
18396
|
+
};
|
|
18388
18397
|
return {
|
|
18389
18398
|
state,
|
|
18390
18399
|
async run(req) {
|
|
18391
|
-
const tmpDir =
|
|
18400
|
+
const tmpDir = env2.tmpDir !== undefined && await ensureTmpDir(env2.tmpDir) ? env2.tmpDir : undefined;
|
|
18392
18401
|
if (state.kind === "disabled")
|
|
18393
|
-
return runUnwrapped(req, { backend: "none", wrapped: false }, tmpDir);
|
|
18402
|
+
return runUnwrapped(req, { backend: "none", wrapped: false }, { ...env2, tmpDir });
|
|
18394
18403
|
if (state.kind === "unavailable") {
|
|
18395
|
-
return runUnwrapped(req, { backend: state.backend, wrapped: false, reason: state.reason }, tmpDir);
|
|
18404
|
+
return runUnwrapped(req, { backend: state.backend, wrapped: false, reason: state.reason }, { ...env2, tmpDir });
|
|
18396
18405
|
}
|
|
18397
18406
|
if (opts.backend === undefined || opts.policyFor === undefined) {
|
|
18398
18407
|
throw new NaxError("[sandbox] an available launcher needs a backend and a policy", "SANDBOX_NOT_CONFIGURED", {
|
|
@@ -18400,7 +18409,7 @@ function createCommandLauncher(opts) {
|
|
|
18400
18409
|
});
|
|
18401
18410
|
}
|
|
18402
18411
|
try {
|
|
18403
|
-
return await runWrapped(req, opts.backend, await opts.policyFor(req.root), tmpDir);
|
|
18412
|
+
return await runWrapped(req, opts.backend, await opts.policyFor(req.root), { ...env2, tmpDir });
|
|
18404
18413
|
} finally {
|
|
18405
18414
|
await opts.afterWrapped?.();
|
|
18406
18415
|
}
|
|
@@ -19239,7 +19248,11 @@ async function listCredentialFiles() {
|
|
|
19239
19248
|
function defaultTempRoots() {
|
|
19240
19249
|
return [_policyInputDeps.tmpdir(), "/tmp"];
|
|
19241
19250
|
}
|
|
19242
|
-
|
|
19251
|
+
function runTempRoots(opts) {
|
|
19252
|
+
const shared = SHARED_TMP_ROOTS.some((root) => opts.tmpdir === root || opts.tmpdir.startsWith(`${root}/`));
|
|
19253
|
+
return shared ? [opts.runTmpRoot] : [opts.tmpdir, opts.runTmpRoot];
|
|
19254
|
+
}
|
|
19255
|
+
var GIT_LAYOUT_TIMEOUT_MS = 1e4, _policyInputDeps, SHARED_TMP_ROOTS;
|
|
19243
19256
|
var init_policy_inputs = __esm(() => {
|
|
19244
19257
|
init_paths();
|
|
19245
19258
|
init_schemas_sandbox();
|
|
@@ -19252,6 +19265,7 @@ var init_policy_inputs = __esm(() => {
|
|
|
19252
19265
|
tmpdir,
|
|
19253
19266
|
platform: () => process.platform
|
|
19254
19267
|
};
|
|
19268
|
+
SHARED_TMP_ROOTS = ["/tmp", "/private/tmp"];
|
|
19255
19269
|
});
|
|
19256
19270
|
|
|
19257
19271
|
// src/sandbox/probe.ts
|
|
@@ -19442,16 +19456,45 @@ var init_registry = __esm(() => {
|
|
|
19442
19456
|
});
|
|
19443
19457
|
|
|
19444
19458
|
// src/sandbox/session-tmp.ts
|
|
19445
|
-
|
|
19446
|
-
|
|
19459
|
+
import { accessSync, constants, lstatSync } from "fs";
|
|
19460
|
+
function isUsableSharedParent() {
|
|
19461
|
+
try {
|
|
19462
|
+
const stats = _sessionTmpDeps.lstat(SHARED_TMP_PARENT);
|
|
19463
|
+
if (!stats.isDirectory() || stats.isSymbolicLink())
|
|
19464
|
+
return false;
|
|
19465
|
+
} catch (err) {
|
|
19466
|
+
return err.code === "ENOENT";
|
|
19467
|
+
}
|
|
19468
|
+
try {
|
|
19469
|
+
_sessionTmpDeps.access(SHARED_TMP_PARENT, constants.W_OK | constants.X_OK);
|
|
19470
|
+
return true;
|
|
19471
|
+
} catch {
|
|
19472
|
+
return false;
|
|
19473
|
+
}
|
|
19447
19474
|
}
|
|
19448
|
-
function
|
|
19449
|
-
return `${
|
|
19475
|
+
function tmpParent() {
|
|
19476
|
+
return isUsableSharedParent() ? SHARED_TMP_PARENT : `${TMP_ROOT}/nax-${_sessionTmpDeps.uid()}`;
|
|
19450
19477
|
}
|
|
19451
|
-
function
|
|
19452
|
-
return
|
|
19478
|
+
function sanitizePart(part) {
|
|
19479
|
+
return part.replace(/[^A-Za-z0-9_.-]/g, "_").replace(/^\.+$/, "_");
|
|
19453
19480
|
}
|
|
19454
|
-
|
|
19481
|
+
function runTmpRoot(runId) {
|
|
19482
|
+
return `${tmpParent()}/${sanitizePart(runId)}`;
|
|
19483
|
+
}
|
|
19484
|
+
function sessionTmpDirUnder(root, sessionName) {
|
|
19485
|
+
return `${root}/${sanitizePart(sessionName)}`;
|
|
19486
|
+
}
|
|
19487
|
+
var TMP_ROOT = "/tmp", SHARED_TMP_PARENT, _sessionTmpDeps;
|
|
19488
|
+
var init_session_tmp = __esm(() => {
|
|
19489
|
+
SHARED_TMP_PARENT = `${TMP_ROOT}/nax`;
|
|
19490
|
+
_sessionTmpDeps = {
|
|
19491
|
+
lstat: (path) => lstatSync(path),
|
|
19492
|
+
access: (path, mode) => {
|
|
19493
|
+
accessSync(path, mode);
|
|
19494
|
+
},
|
|
19495
|
+
uid: () => process.getuid?.() ?? 0
|
|
19496
|
+
};
|
|
19497
|
+
});
|
|
19455
19498
|
|
|
19456
19499
|
// src/sandbox/index.ts
|
|
19457
19500
|
var init_sandbox = __esm(() => {
|
|
@@ -19462,6 +19505,7 @@ var init_sandbox = __esm(() => {
|
|
|
19462
19505
|
init_policy_inputs();
|
|
19463
19506
|
init_probe();
|
|
19464
19507
|
init_registry();
|
|
19508
|
+
init_session_tmp();
|
|
19465
19509
|
init_srt_backend();
|
|
19466
19510
|
});
|
|
19467
19511
|
|
|
@@ -19645,14 +19689,14 @@ function bashToolDescription(shell, opts) {
|
|
|
19645
19689
|
const state = opts.launcher?.state ?? { kind: "disabled" };
|
|
19646
19690
|
if (opts.bashApproval === "raw") {
|
|
19647
19691
|
if (state.kind === "available")
|
|
19648
|
-
return rawDescription(shell, `The command runs from the repository root ${sandboxSentence(state.network)} `);
|
|
19692
|
+
return rawDescription(shell, `The command runs from the repository root ${sandboxSentence(state.network, state.sharedTmp !== false)} `);
|
|
19649
19693
|
if (state.kind === "unavailable")
|
|
19650
19694
|
return rawUnavailableDescription(shell, state.reason);
|
|
19651
19695
|
return rawDescription(shell);
|
|
19652
19696
|
}
|
|
19653
19697
|
const policyDescription = opts.bashApproval === "escalate" && opts.humanApproval === true ? escalateDescription(shell, opts.patterns) : gatedDescription(shell, opts.patterns);
|
|
19654
19698
|
if (state.kind === "available") {
|
|
19655
|
-
return `${policyDescription} Commands that pass run ${sandboxSentence(state.network)}`;
|
|
19699
|
+
return `${policyDescription} Commands that pass run ${sandboxSentence(state.network, state.sharedTmp !== false)}`;
|
|
19656
19700
|
}
|
|
19657
19701
|
if (state.kind === "unavailable")
|
|
19658
19702
|
return `${policyDescription} ${unsandboxedSentence(state.reason)}`;
|
|
@@ -23681,7 +23725,7 @@ function otherCommandsDeclaring(declared, key, currentCommand) {
|
|
|
23681
23725
|
function execSandboxNote(launcher) {
|
|
23682
23726
|
const state = launcher?.state;
|
|
23683
23727
|
if (state?.kind === "available")
|
|
23684
|
-
return ` An "argv" call runs ${sandboxSentence(state.network)}`;
|
|
23728
|
+
return ` An "argv" call runs ${sandboxSentence(state.network, state.sharedTmp !== false)}`;
|
|
23685
23729
|
if (state?.kind === "unavailable")
|
|
23686
23730
|
return ` ${unsandboxedSentence(state.reason)}`;
|
|
23687
23731
|
return "";
|
|
@@ -24009,11 +24053,14 @@ function resolveTarget(target, frame) {
|
|
|
24009
24053
|
return posix2.normalize(target.text);
|
|
24010
24054
|
return frame === undefined ? undefined : posix2.normalize(posix2.join(frame, target.text));
|
|
24011
24055
|
}
|
|
24056
|
+
function isNaxTempTree(path, root) {
|
|
24057
|
+
return path.startsWith(`${root}/${NAX_PARENT_SEGMENT}/`) || path.startsWith(`${root}/${NAX_FALLBACK_SEGMENT}`);
|
|
24058
|
+
}
|
|
24012
24059
|
function isTmpPath(path) {
|
|
24013
24060
|
for (const root of TEMP_ROOTS) {
|
|
24014
24061
|
if (path !== root && !path.startsWith(`${root}/`))
|
|
24015
24062
|
continue;
|
|
24016
|
-
return !path
|
|
24063
|
+
return !isNaxTempTree(path, root);
|
|
24017
24064
|
}
|
|
24018
24065
|
return false;
|
|
24019
24066
|
}
|
|
@@ -24037,7 +24084,7 @@ function detectTmpWrite(command, cwd) {
|
|
|
24037
24084
|
}
|
|
24038
24085
|
return false;
|
|
24039
24086
|
}
|
|
24040
|
-
var TEMP_ROOTS,
|
|
24087
|
+
var TEMP_ROOTS, NAX_PARENT_SEGMENT = "nax", NAX_FALLBACK_SEGMENT = "nax-", ARG_TARGET_COMMANDS, LAST_TARGET_COMMANDS;
|
|
24041
24088
|
var init_tmp_write = __esm(() => {
|
|
24042
24089
|
init_permissions();
|
|
24043
24090
|
TEMP_ROOTS = ["/tmp", "/private/tmp"];
|
|
@@ -26494,7 +26541,7 @@ var init_package_config_cache = __esm(() => {
|
|
|
26494
26541
|
});
|
|
26495
26542
|
|
|
26496
26543
|
// src/config/path-security.ts
|
|
26497
|
-
import { existsSync as existsSync4, lstatSync, realpathSync as realpathSync2 } from "fs";
|
|
26544
|
+
import { existsSync as existsSync4, lstatSync as lstatSync2, realpathSync as realpathSync2 } from "fs";
|
|
26498
26545
|
import { basename as basename3, isAbsolute as isAbsolute8, normalize, relative as relative9, resolve as resolve15 } from "path";
|
|
26499
26546
|
function validateDirectory(dirPath, baseDir) {
|
|
26500
26547
|
const resolved = resolve15(dirPath);
|
|
@@ -26516,7 +26563,7 @@ function validateDirectory(dirPath, baseDir) {
|
|
|
26516
26563
|
}
|
|
26517
26564
|
let isDirectory;
|
|
26518
26565
|
try {
|
|
26519
|
-
isDirectory =
|
|
26566
|
+
isDirectory = lstatSync2(realPath).isDirectory();
|
|
26520
26567
|
} catch (error48) {
|
|
26521
26568
|
throw new NaxError(`Failed to stat path: ${dirPath} (${errorMessage(error48)})`, "PATH_DIRECTORY_STAT_FAILED", {
|
|
26522
26569
|
stage: "config",
|
|
@@ -30479,6 +30526,14 @@ function buildToolResult(args) {
|
|
|
30479
30526
|
};
|
|
30480
30527
|
}
|
|
30481
30528
|
|
|
30529
|
+
// src/utils/thenable.ts
|
|
30530
|
+
function isThenable(value) {
|
|
30531
|
+
if (value === null)
|
|
30532
|
+
return false;
|
|
30533
|
+
const type = typeof value;
|
|
30534
|
+
return (type === "object" || type === "function") && typeof value.then === "function";
|
|
30535
|
+
}
|
|
30536
|
+
|
|
30482
30537
|
// src/agents/native/session/loop-events/payload-guard.ts
|
|
30483
30538
|
function snapshotArrays(payload) {
|
|
30484
30539
|
return Object.entries(payload).flatMap(([field, value]) => Array.isArray(value) ? [{ field, array: value, saved: [...value] }] : []);
|
|
@@ -30513,18 +30568,43 @@ function pickPatchFields(returned, fields) {
|
|
|
30513
30568
|
}
|
|
30514
30569
|
return picked;
|
|
30515
30570
|
}
|
|
30571
|
+
function isBeforeToolOutcome(value) {
|
|
30572
|
+
if (typeof value !== "object" || value === null)
|
|
30573
|
+
return false;
|
|
30574
|
+
const kind = value.kind;
|
|
30575
|
+
return typeof kind === "string" && BEFORE_TOOL_KINDS.includes(kind);
|
|
30576
|
+
}
|
|
30577
|
+
function isCompleteBeforeToolOutcome(value) {
|
|
30578
|
+
if (!isBeforeToolOutcome(value))
|
|
30579
|
+
return false;
|
|
30580
|
+
const outcome = value;
|
|
30581
|
+
if (value.kind === "block" || value.kind === "terminate")
|
|
30582
|
+
return typeof outcome.content === "string";
|
|
30583
|
+
if (value.kind === "nudge")
|
|
30584
|
+
return typeof outcome.text === "string";
|
|
30585
|
+
return true;
|
|
30586
|
+
}
|
|
30587
|
+
function asOutcome(returned, tool) {
|
|
30588
|
+
if (isBeforeToolOutcome(returned))
|
|
30589
|
+
return returned;
|
|
30590
|
+
getSafeLogger()?.warn("native-loop-events", "before_tool handler answered no valid outcome; treating it as allow", {
|
|
30591
|
+
tool
|
|
30592
|
+
});
|
|
30593
|
+
return { kind: "allow" };
|
|
30594
|
+
}
|
|
30516
30595
|
async function dispatchBeforeTool(handlers, payload) {
|
|
30517
30596
|
const { call, tools } = payload;
|
|
30518
30597
|
let input;
|
|
30519
30598
|
let nudgeText2;
|
|
30520
30599
|
for (const [index, handler] of handlers.entries()) {
|
|
30521
|
-
let
|
|
30600
|
+
let returned;
|
|
30522
30601
|
const snapshot = snapshotArrays({ tools });
|
|
30523
30602
|
try {
|
|
30524
|
-
|
|
30603
|
+
const candidate = handler({
|
|
30525
30604
|
call: { ...call, input: input ?? call.input },
|
|
30526
30605
|
tools
|
|
30527
30606
|
});
|
|
30607
|
+
returned = isThenable(candidate) ? await candidate : candidate;
|
|
30528
30608
|
} catch (err) {
|
|
30529
30609
|
getSafeLogger()?.warn("native-loop-events", "before_tool handler threw; skipping it", {
|
|
30530
30610
|
tool: call.name,
|
|
@@ -30534,6 +30614,7 @@ async function dispatchBeforeTool(handlers, payload) {
|
|
|
30534
30614
|
} finally {
|
|
30535
30615
|
restoreMutated(snapshot, "before_tool", index);
|
|
30536
30616
|
}
|
|
30617
|
+
const outcome = asOutcome(returned, call.name);
|
|
30537
30618
|
if (outcome.kind === "block" || outcome.kind === "terminate")
|
|
30538
30619
|
return outcome;
|
|
30539
30620
|
if (outcome.kind === "nudge")
|
|
@@ -30599,7 +30680,7 @@ function createLoopEventRegistry() {
|
|
|
30599
30680
|
}
|
|
30600
30681
|
};
|
|
30601
30682
|
}
|
|
30602
|
-
var PATCHABLE_FIELDS;
|
|
30683
|
+
var PATCHABLE_FIELDS, LOOP_EVENTS, BEFORE_TOOL_KINDS;
|
|
30603
30684
|
var init_registry3 = __esm(() => {
|
|
30604
30685
|
init_logger2();
|
|
30605
30686
|
init_payload_guard();
|
|
@@ -30613,10 +30694,123 @@ var init_registry3 = __esm(() => {
|
|
|
30613
30694
|
before_compaction: ["decline", "summary"],
|
|
30614
30695
|
before_turn_end: ["followUp"]
|
|
30615
30696
|
};
|
|
30697
|
+
LOOP_EVENTS = Object.freeze(Object.keys(PATCHABLE_FIELDS));
|
|
30698
|
+
BEFORE_TOOL_KINDS = ["allow", "nudge", "block", "terminate"];
|
|
30699
|
+
});
|
|
30700
|
+
|
|
30701
|
+
// src/agents/native/session/loop-events/external-handler.ts
|
|
30702
|
+
function raceSettlement(entry, payload, deps) {
|
|
30703
|
+
const timeoutMs = _externalHandlerDeps.timeoutMs;
|
|
30704
|
+
return new Promise((resolve17) => {
|
|
30705
|
+
let settled = false;
|
|
30706
|
+
let timer;
|
|
30707
|
+
const finish = (result) => {
|
|
30708
|
+
if (settled)
|
|
30709
|
+
return;
|
|
30710
|
+
settled = true;
|
|
30711
|
+
if (timer !== undefined)
|
|
30712
|
+
clearTimeout(timer);
|
|
30713
|
+
deps.signal.removeEventListener("abort", onAbort);
|
|
30714
|
+
resolve17(result);
|
|
30715
|
+
};
|
|
30716
|
+
const onAbort = () => finish({ ok: false, reason: "aborted before it settled" });
|
|
30717
|
+
timer = setTimeout(() => finish({ ok: false, reason: `did not settle within ${timeoutMs}ms` }), timeoutMs);
|
|
30718
|
+
deps.signal.addEventListener("abort", onAbort, { once: true });
|
|
30719
|
+
let ctx;
|
|
30720
|
+
try {
|
|
30721
|
+
ctx = deps.getCtx();
|
|
30722
|
+
} catch (err) {
|
|
30723
|
+
finish({ ok: false, reason: `reading the handler context failed: ${errorMessage(err)}` });
|
|
30724
|
+
return;
|
|
30725
|
+
}
|
|
30726
|
+
let returned;
|
|
30727
|
+
try {
|
|
30728
|
+
returned = entry.handler(payload, ctx);
|
|
30729
|
+
} catch (err) {
|
|
30730
|
+
finish({ ok: false, reason: errorMessage(err) });
|
|
30731
|
+
return;
|
|
30732
|
+
}
|
|
30733
|
+
Promise.resolve(returned).then((value) => finish({ ok: true, value }), (err) => finish({ ok: false, reason: errorMessage(err) }));
|
|
30734
|
+
});
|
|
30735
|
+
}
|
|
30736
|
+
function failure(entry, payload, reason) {
|
|
30737
|
+
const logger = getSafeLogger();
|
|
30738
|
+
if (entry.event === "before_tool") {
|
|
30739
|
+
const tool = payload?.call?.name;
|
|
30740
|
+
logger?.warn("native-loop-events", `plugin '${entry.plugin}' failed on before_tool; blocking the call`, {
|
|
30741
|
+
plugin: entry.plugin,
|
|
30742
|
+
event: entry.event,
|
|
30743
|
+
...tool !== undefined ? { tool } : {},
|
|
30744
|
+
error: reason
|
|
30745
|
+
});
|
|
30746
|
+
return {
|
|
30747
|
+
kind: "block",
|
|
30748
|
+
isError: true,
|
|
30749
|
+
content: `Blocked: loop handler from plugin '${entry.plugin}' failed (${reason}).`
|
|
30750
|
+
};
|
|
30751
|
+
}
|
|
30752
|
+
logger?.warn("native-loop-events", `plugin '${entry.plugin}' failed on ${entry.event}`, {
|
|
30753
|
+
plugin: entry.plugin,
|
|
30754
|
+
event: entry.event,
|
|
30755
|
+
error: reason
|
|
30756
|
+
});
|
|
30757
|
+
return {};
|
|
30758
|
+
}
|
|
30759
|
+
function tracePatch(entry, value) {
|
|
30760
|
+
if (typeof value !== "object" || value === null)
|
|
30761
|
+
return;
|
|
30762
|
+
const patch = value;
|
|
30763
|
+
const fields = TRACED_PATCH_FIELDS.filter((field) => patch[field] !== undefined);
|
|
30764
|
+
if (fields.length === 0)
|
|
30765
|
+
return;
|
|
30766
|
+
getSafeLogger()?.debug("native-loop-events", `plugin '${entry.plugin}' patched ${entry.event}`, {
|
|
30767
|
+
plugin: entry.plugin,
|
|
30768
|
+
event: entry.event,
|
|
30769
|
+
fields
|
|
30770
|
+
});
|
|
30771
|
+
}
|
|
30772
|
+
function describeValue(value) {
|
|
30773
|
+
if (value === null)
|
|
30774
|
+
return "null";
|
|
30775
|
+
if (Array.isArray(value))
|
|
30776
|
+
return "an array";
|
|
30777
|
+
if (typeof value === "object")
|
|
30778
|
+
return "an object whose kind is not a before_tool outcome";
|
|
30779
|
+
return `a ${typeof value} value`;
|
|
30780
|
+
}
|
|
30781
|
+
function settled(entry, payload, value) {
|
|
30782
|
+
if (entry.event === "before_tool") {
|
|
30783
|
+
if (value === undefined)
|
|
30784
|
+
return { kind: "allow" };
|
|
30785
|
+
if (!isCompleteBeforeToolOutcome(value))
|
|
30786
|
+
return failure(entry, payload, `returned ${describeValue(value)}`);
|
|
30787
|
+
return value;
|
|
30788
|
+
}
|
|
30789
|
+
if (value === undefined)
|
|
30790
|
+
return {};
|
|
30791
|
+
tracePatch(entry, value);
|
|
30792
|
+
return value;
|
|
30793
|
+
}
|
|
30794
|
+
function wrapExternalHandler(entry, getCtx, signal) {
|
|
30795
|
+
return async (payload) => {
|
|
30796
|
+
const settlement = await raceSettlement(entry, payload, { getCtx, signal });
|
|
30797
|
+
const answer = settlement.ok ? settled(entry, payload, settlement.value) : failure(entry, payload, settlement.reason);
|
|
30798
|
+
return answer;
|
|
30799
|
+
};
|
|
30800
|
+
}
|
|
30801
|
+
var LOOP_HANDLER_TIMEOUT_MS = 1e4, _externalHandlerDeps, TRACED_PATCH_FIELDS;
|
|
30802
|
+
var init_external_handler = __esm(() => {
|
|
30803
|
+
init_logger2();
|
|
30804
|
+
init_registry3();
|
|
30805
|
+
_externalHandlerDeps = {
|
|
30806
|
+
timeoutMs: LOOP_HANDLER_TIMEOUT_MS
|
|
30807
|
+
};
|
|
30808
|
+
TRACED_PATCH_FIELDS = ["seed", "history", "messages", "summary"];
|
|
30616
30809
|
});
|
|
30617
30810
|
|
|
30618
30811
|
// src/agents/native/session/loop-events/index.ts
|
|
30619
30812
|
var init_loop_events = __esm(() => {
|
|
30813
|
+
init_external_handler();
|
|
30620
30814
|
init_registry3();
|
|
30621
30815
|
});
|
|
30622
30816
|
|
|
@@ -30696,6 +30890,16 @@ var init_truncation_handler = __esm(() => {
|
|
|
30696
30890
|
});
|
|
30697
30891
|
|
|
30698
30892
|
// src/agents/native/session/loop-handlers.ts
|
|
30893
|
+
function contextFor(state) {
|
|
30894
|
+
return state.current.loopHandlerContext ?? { sessionName: state.current.sessionName };
|
|
30895
|
+
}
|
|
30896
|
+
function turnSignalView(state) {
|
|
30897
|
+
const current = () => state.current.signal ?? NEVER_ABORTED;
|
|
30898
|
+
return {
|
|
30899
|
+
addEventListener: (...args) => current().addEventListener(...args),
|
|
30900
|
+
removeEventListener: (...args) => current().removeEventListener(...args)
|
|
30901
|
+
};
|
|
30902
|
+
}
|
|
30699
30903
|
function registerBuiltinLoopHandlers(registry3, deps) {
|
|
30700
30904
|
const installed = turnStateByRegistry.get(registry3);
|
|
30701
30905
|
if (installed !== undefined) {
|
|
@@ -30706,6 +30910,9 @@ function registerBuiltinLoopHandlers(registry3, deps) {
|
|
|
30706
30910
|
turnStateByRegistry.set(registry3, state);
|
|
30707
30911
|
registry3.register("before_tool", ({ call, tools }) => repairInvalidCall(state, call, tools));
|
|
30708
30912
|
registry3.register("before_tool", ({ call }) => observeSpin(state, call));
|
|
30913
|
+
for (const entry of deps.loopHandlers ?? []) {
|
|
30914
|
+
registry3.register(entry.event, wrapExternalHandler(entry, () => contextFor(state), turnSignalView(state)));
|
|
30915
|
+
}
|
|
30709
30916
|
registry3.register("after_tool", (payload) => createTruncationHandler(state.current.sessionName)(payload));
|
|
30710
30917
|
}
|
|
30711
30918
|
function repairInvalidCall(state, call, tools) {
|
|
@@ -30732,11 +30939,13 @@ function observeSpin(state, call) {
|
|
|
30732
30939
|
return { kind: "nudge", text: verdict.text };
|
|
30733
30940
|
return { kind: "allow" };
|
|
30734
30941
|
}
|
|
30735
|
-
var turnStateByRegistry;
|
|
30942
|
+
var NEVER_ABORTED, turnStateByRegistry;
|
|
30736
30943
|
var init_loop_handlers = __esm(() => {
|
|
30737
30944
|
init_spin_breaker();
|
|
30738
30945
|
init_handle_invalid_tool_call();
|
|
30946
|
+
init_loop_events();
|
|
30739
30947
|
init_truncation_handler();
|
|
30948
|
+
NEVER_ABORTED = new AbortController().signal;
|
|
30740
30949
|
turnStateByRegistry = new WeakMap;
|
|
30741
30950
|
});
|
|
30742
30951
|
|
|
@@ -31704,6 +31913,9 @@ async function runNativeTurn(handle, prompt, opts, deps) {
|
|
|
31704
31913
|
sessionName: handle.id,
|
|
31705
31914
|
budget: invalidCallBudget,
|
|
31706
31915
|
...deps.spinBreaker !== undefined ? { spinBreaker: deps.spinBreaker } : {},
|
|
31916
|
+
...deps.loopHandlers !== undefined ? { loopHandlers: deps.loopHandlers } : {},
|
|
31917
|
+
...deps.loopHandlerContext !== undefined ? { loopHandlerContext: deps.loopHandlerContext } : {},
|
|
31918
|
+
...deps.signal !== undefined ? { signal: deps.signal } : {},
|
|
31707
31919
|
onSpinStop: () => {
|
|
31708
31920
|
spinFlags.warned = true;
|
|
31709
31921
|
}
|
|
@@ -31854,6 +32066,12 @@ An earlier summary of still-older history follows. Merge it into your summary `
|
|
|
31854
32066
|
|
|
31855
32067
|
${previousSummary}`;
|
|
31856
32068
|
}
|
|
32069
|
+
function loopHandlerDeps(opts) {
|
|
32070
|
+
return {
|
|
32071
|
+
...opts.loopHandlers !== undefined ? { loopHandlers: opts.loopHandlers } : {},
|
|
32072
|
+
...opts.loopHandlerContext !== undefined ? { loopHandlerContext: opts.loopHandlerContext } : {}
|
|
32073
|
+
};
|
|
32074
|
+
}
|
|
31857
32075
|
|
|
31858
32076
|
class NativeAgentAdapter {
|
|
31859
32077
|
catalogOverrides;
|
|
@@ -31983,6 +32201,7 @@ class NativeAgentAdapter {
|
|
|
31983
32201
|
...nativeSessionTransportRetry.get(handle.id) !== undefined ? { transportRetry: nativeSessionTransportRetry.get(handle.id) } : {},
|
|
31984
32202
|
...nativeSessionSpinBreaker.get(handle.id) !== undefined ? { spinBreaker: nativeSessionSpinBreaker.get(handle.id) } : {},
|
|
31985
32203
|
...opts.loopEvents !== undefined ? { loopEvents: opts.loopEvents } : {},
|
|
32204
|
+
...loopHandlerDeps(opts),
|
|
31986
32205
|
signal: turnSignal,
|
|
31987
32206
|
onWaiting: () => {},
|
|
31988
32207
|
pricingSource,
|
|
@@ -35439,7 +35658,7 @@ function killProcessTree(pid, graceMs, exited) {
|
|
|
35439
35658
|
killProcessGroup(pid, "SIGTERM");
|
|
35440
35659
|
getSafeLogger()?.debug("acp-adapter", `Sent SIGTERM to process group ${pid}`);
|
|
35441
35660
|
} catch {}
|
|
35442
|
-
let
|
|
35661
|
+
let settled2 = false;
|
|
35443
35662
|
const timer = { id: undefined };
|
|
35444
35663
|
const gracePromise = new Promise((resolve17) => {
|
|
35445
35664
|
timer.id = setTimeout(() => resolve17("grace"), graceMs);
|
|
@@ -35450,9 +35669,9 @@ function killProcessTree(pid, graceMs, exited) {
|
|
|
35450
35669
|
const raced = exitedPromise !== undefined ? Promise.race([gracePromise, exitedPromise]) : gracePromise;
|
|
35451
35670
|
raced.then((outcome) => {
|
|
35452
35671
|
clearTimeout(timer.id);
|
|
35453
|
-
if (
|
|
35672
|
+
if (settled2)
|
|
35454
35673
|
return;
|
|
35455
|
-
|
|
35674
|
+
settled2 = true;
|
|
35456
35675
|
activeKillTimers.delete(pid);
|
|
35457
35676
|
if (outcome === "exited")
|
|
35458
35677
|
return;
|
|
@@ -35464,7 +35683,7 @@ function killProcessTree(pid, graceMs, exited) {
|
|
|
35464
35683
|
});
|
|
35465
35684
|
const handle = {
|
|
35466
35685
|
cancel: () => {
|
|
35467
|
-
|
|
35686
|
+
settled2 = true;
|
|
35468
35687
|
clearTimeout(timer.id);
|
|
35469
35688
|
activeKillTimers.delete(pid);
|
|
35470
35689
|
}
|
|
@@ -37422,13 +37641,13 @@ var init_interaction_handler = __esm(() => {
|
|
|
37422
37641
|
function failurePolicyFor(outcome) {
|
|
37423
37642
|
return POLICIES[outcome];
|
|
37424
37643
|
}
|
|
37425
|
-
function resolveCooldownExpiry(
|
|
37426
|
-
const { cooldown } = failurePolicyFor(
|
|
37644
|
+
function resolveCooldownExpiry(failure2, now) {
|
|
37645
|
+
const { cooldown } = failurePolicyFor(failure2.outcome);
|
|
37427
37646
|
if (cooldown === "none")
|
|
37428
37647
|
return null;
|
|
37429
37648
|
if (cooldown === "run")
|
|
37430
37649
|
return "run";
|
|
37431
|
-
const retryAfter =
|
|
37650
|
+
const retryAfter = failure2.retryAfterSeconds;
|
|
37432
37651
|
const fromProvider = retryAfter !== undefined && Number.isFinite(retryAfter) && retryAfter >= 0 ? retryAfter * 1000 : undefined;
|
|
37433
37652
|
return now + (fromProvider ?? cooldown.ms);
|
|
37434
37653
|
}
|
|
@@ -37530,10 +37749,10 @@ var init_failure_policy = __esm(() => {
|
|
|
37530
37749
|
});
|
|
37531
37750
|
|
|
37532
37751
|
// src/agents/swap-decision.ts
|
|
37533
|
-
function decideSwap(
|
|
37534
|
-
if (!
|
|
37752
|
+
function decideSwap(failure2, hopsSoFar, fallback) {
|
|
37753
|
+
if (!failure2)
|
|
37535
37754
|
return { swap: false, reason: "no-failure" };
|
|
37536
|
-
const policy = failurePolicyFor(
|
|
37755
|
+
const policy = failurePolicyFor(failure2.outcome);
|
|
37537
37756
|
if (policy.swap === "never")
|
|
37538
37757
|
return { swap: false, reason: "outcome-refused" };
|
|
37539
37758
|
if (!fallback?.enabled)
|
|
@@ -37617,12 +37836,12 @@ var MAX_RETRIES = 3, defaultRetryStrategy;
|
|
|
37617
37836
|
var init_default_strategy = __esm(() => {
|
|
37618
37837
|
init_failure_policy();
|
|
37619
37838
|
defaultRetryStrategy = {
|
|
37620
|
-
shouldRetry(
|
|
37839
|
+
shouldRetry(failure2, attempt, _ctx) {
|
|
37621
37840
|
if (attempt >= MAX_RETRIES)
|
|
37622
37841
|
return { retry: false };
|
|
37623
|
-
if (
|
|
37842
|
+
if (failure2 instanceof Error)
|
|
37624
37843
|
return { retry: false };
|
|
37625
|
-
const af =
|
|
37844
|
+
const af = failure2;
|
|
37626
37845
|
if (af.retriable === false)
|
|
37627
37846
|
return { retry: false };
|
|
37628
37847
|
if (!failurePolicyFor(af.outcome).terminalBackoff)
|
|
@@ -38569,6 +38788,9 @@ function createTestFileClassifier(resolved) {
|
|
|
38569
38788
|
}
|
|
38570
38789
|
|
|
38571
38790
|
// src/test-runners/compile-crash.ts
|
|
38791
|
+
function isCommandNotRunnable(exitCode) {
|
|
38792
|
+
return exitCode === 126 || exitCode === 127;
|
|
38793
|
+
}
|
|
38572
38794
|
function isGoMissingSymbol(message) {
|
|
38573
38795
|
const msg = message.trim();
|
|
38574
38796
|
if (msg.startsWith("undefined: "))
|
|
@@ -38737,11 +38959,11 @@ async function listFilesInDir(workdir, dir) {
|
|
|
38737
38959
|
const stdoutPromise = new Response(proc.stdout).text().catch(() => "");
|
|
38738
38960
|
const stderrPromise = new Response(proc.stderr).text().catch(() => "");
|
|
38739
38961
|
const exitCode = await new Promise((resolve17) => {
|
|
38740
|
-
let
|
|
38962
|
+
let settled2 = false;
|
|
38741
38963
|
const finish = (code) => {
|
|
38742
|
-
if (
|
|
38964
|
+
if (settled2)
|
|
38743
38965
|
return;
|
|
38744
|
-
|
|
38966
|
+
settled2 = true;
|
|
38745
38967
|
clearTimeout(timer);
|
|
38746
38968
|
resolve17(code);
|
|
38747
38969
|
};
|
|
@@ -38853,11 +39075,11 @@ async function gitLsFiles(workdir) {
|
|
|
38853
39075
|
const stdoutPromise = new Response(proc.stdout).text().catch(() => "");
|
|
38854
39076
|
const stderrPromise = new Response(proc.stderr).text().catch(() => "");
|
|
38855
39077
|
const exitCode = await new Promise((resolve17) => {
|
|
38856
|
-
let
|
|
39078
|
+
let settled2 = false;
|
|
38857
39079
|
const finish = (code) => {
|
|
38858
|
-
if (
|
|
39080
|
+
if (settled2)
|
|
38859
39081
|
return;
|
|
38860
|
-
|
|
39082
|
+
settled2 = true;
|
|
38861
39083
|
clearTimeout(timer);
|
|
38862
39084
|
resolve17(code);
|
|
38863
39085
|
};
|
|
@@ -40114,11 +40336,11 @@ function parsePytestOutput(output) {
|
|
|
40114
40336
|
}
|
|
40115
40337
|
failures.push(...errorByFile.values());
|
|
40116
40338
|
const verboseStacks = parsePytestVerboseStacks(output);
|
|
40117
|
-
for (const
|
|
40118
|
-
const leafName =
|
|
40119
|
-
const stack = verboseStacks.get(leafName) ?? verboseStacks.get(
|
|
40339
|
+
for (const failure2 of failures) {
|
|
40340
|
+
const leafName = failure2.testName.split(" > ").pop() ?? failure2.testName;
|
|
40341
|
+
const stack = verboseStacks.get(leafName) ?? verboseStacks.get(failure2.testName) ?? verboseStacks.get(failure2.testName.replace(/ > /g, "."));
|
|
40120
40342
|
if (stack && stack.length > 0) {
|
|
40121
|
-
|
|
40343
|
+
failure2.stackTrace = stack;
|
|
40122
40344
|
}
|
|
40123
40345
|
}
|
|
40124
40346
|
return {
|
|
@@ -40229,11 +40451,11 @@ function formatFailureSummary(failures, maxChars = 2000) {
|
|
|
40229
40451
|
const lines = [];
|
|
40230
40452
|
let totalChars = 0;
|
|
40231
40453
|
for (let i = 0;i < failures.length; i++) {
|
|
40232
|
-
const
|
|
40454
|
+
const failure2 = failures[i];
|
|
40233
40455
|
const num = i + 1;
|
|
40234
|
-
const header = `${num}. ${
|
|
40235
|
-
const errorLine = ` Error: ${
|
|
40236
|
-
const stackTrace =
|
|
40456
|
+
const header = `${num}. ${failure2.file} > ${failure2.testName}`;
|
|
40457
|
+
const errorLine = ` Error: ${failure2.error}`;
|
|
40458
|
+
const stackTrace = failure2.stackTrace ?? [];
|
|
40237
40459
|
const stackLine = stackTrace.length > 0 ? ` ${stackTrace[0]}` : "";
|
|
40238
40460
|
const blockLines = [header, errorLine];
|
|
40239
40461
|
if (stackLine)
|
|
@@ -40971,6 +41193,7 @@ __export(exports_test_runners, {
|
|
|
40971
41193
|
formatFailureSummary: () => formatFailureSummary,
|
|
40972
41194
|
globsToPathspec: () => globsToPathspec,
|
|
40973
41195
|
globsToTestRegex: () => globsToTestRegex,
|
|
41196
|
+
isCommandNotRunnable: () => isCommandNotRunnable,
|
|
40974
41197
|
isMonorepoOrchestratorCommand: () => isMonorepoOrchestratorCommand,
|
|
40975
41198
|
isTestFile: () => isTestFile,
|
|
40976
41199
|
isTestFileByPatterns: () => isTestFileByPatterns,
|
|
@@ -41835,17 +42058,17 @@ var init_lint = __esm(() => {
|
|
|
41835
42058
|
init_path_utils();
|
|
41836
42059
|
});
|
|
41837
42060
|
// src/findings/adapters/test-failure.ts
|
|
41838
|
-
function testFailureToFinding(
|
|
41839
|
-
const frames = (
|
|
41840
|
-
const message = frames.length > 0 ? `${
|
|
42061
|
+
function testFailureToFinding(failure2) {
|
|
42062
|
+
const frames = (failure2.stackTrace ?? []).slice(0, MAX_FRAMES_IN_MESSAGE);
|
|
42063
|
+
const message = frames.length > 0 ? `${failure2.error}
|
|
41841
42064
|
${frames.join(`
|
|
41842
|
-
`)}` :
|
|
42065
|
+
`)}` : failure2.error;
|
|
41843
42066
|
return {
|
|
41844
42067
|
source: "test-runner",
|
|
41845
42068
|
severity: "error",
|
|
41846
42069
|
category: "failed-test",
|
|
41847
|
-
rule:
|
|
41848
|
-
file:
|
|
42070
|
+
rule: failure2.testName,
|
|
42071
|
+
file: failure2.file,
|
|
41849
42072
|
message
|
|
41850
42073
|
};
|
|
41851
42074
|
}
|
|
@@ -42747,11 +42970,15 @@ async function validateRecordAndDecide(frame, state, it) {
|
|
|
42747
42970
|
break;
|
|
42748
42971
|
} catch (err) {
|
|
42749
42972
|
if (validatorAttempt >= cycle.config.validatorRetries) {
|
|
42973
|
+
const iterationCostUsd2 = fixesApplied.reduce((sum, fa) => sum + (fa.costUsd ?? 0), 0);
|
|
42974
|
+
state.totalCostUsd += iterationCostUsd2;
|
|
42750
42975
|
logger?.error("findings.cycle", "cycle exited \u2014 validator error", {
|
|
42751
42976
|
storyId: logCtx.storyId,
|
|
42752
42977
|
packageDir: logCtx.packageDir,
|
|
42753
42978
|
cycleName: logCtx.cycleName,
|
|
42754
42979
|
reason: "validator-error",
|
|
42980
|
+
strategiesRun: group.map((s) => s.name),
|
|
42981
|
+
iterationCostUsd: iterationCostUsd2,
|
|
42755
42982
|
error: errorMessage(err)
|
|
42756
42983
|
});
|
|
42757
42984
|
return {
|
|
@@ -43662,8 +43889,12 @@ To try a snippet that imports project code or dependencies, write it under \`${d
|
|
|
43662
43889
|
project's package names or path aliases where it has them. A script written outside the repository,
|
|
43663
43890
|
such as in \`/tmp\`, cannot resolve the project's modules, and the file tools cannot write there.
|
|
43664
43891
|
|
|
43665
|
-
|
|
43666
|
-
|
|
43892
|
+
Use the scratchpad as your temp folder. Files you make while working \u2014 command output you want to
|
|
43893
|
+
re-read, generated inputs, one-off scripts \u2014 go under \`${dir}\`: the shell, the file tools
|
|
43894
|
+
and the scratchpad tools can all reach it, and it is cleared after the run. For throwaway files a
|
|
43895
|
+
command creates on its own, shell commands run with \`$TMPDIR\` set to this run's temp directory; use
|
|
43896
|
+
\`$TMPDIR\` or \`mktemp\` for those. Never write to \`/tmp\` directly: in the sandbox, \`/tmp\` outside
|
|
43897
|
+
\`$TMPDIR\` is not writable and the write fails.
|
|
43667
43898
|
|
|
43668
43899
|
\`${dir}\` is the one directory under \`.nax/\` you may write to. Every other path under \`.nax/\`
|
|
43669
43900
|
must still never be moved, renamed, or deleted.`;
|
|
@@ -47167,18 +47398,18 @@ function formatPriorFailures(failures) {
|
|
|
47167
47398
|
return "";
|
|
47168
47399
|
}
|
|
47169
47400
|
const parts = [];
|
|
47170
|
-
for (const
|
|
47171
|
-
parts.push(`### Attempt ${
|
|
47172
|
-
if (
|
|
47173
|
-
const profilePart =
|
|
47174
|
-
parts.push(`**Agent:** ${
|
|
47175
|
-
}
|
|
47176
|
-
parts.push(`**Stage:** ${
|
|
47177
|
-
parts.push(`**Summary:** ${
|
|
47178
|
-
if (
|
|
47401
|
+
for (const failure2 of failures) {
|
|
47402
|
+
parts.push(`### Attempt ${failure2.attempt} \u2014 ${failure2.modelTier}`);
|
|
47403
|
+
if (failure2.agent) {
|
|
47404
|
+
const profilePart = failure2.agentProfileId ? ` (profile: ${failure2.agentProfileId})` : "";
|
|
47405
|
+
parts.push(`**Agent:** ${failure2.agent}${profilePart}`);
|
|
47406
|
+
}
|
|
47407
|
+
parts.push(`**Stage:** ${failure2.stage}`);
|
|
47408
|
+
parts.push(`**Summary:** ${failure2.summary}`);
|
|
47409
|
+
if (failure2.testFailures && failure2.testFailures.length > 0) {
|
|
47179
47410
|
parts.push(`
|
|
47180
47411
|
**Test Failures:**`);
|
|
47181
|
-
for (const testFailure of
|
|
47412
|
+
for (const testFailure of failure2.testFailures) {
|
|
47182
47413
|
parts.push(`
|
|
47183
47414
|
- **File:** \`${testFailure.file}\``);
|
|
47184
47415
|
parts.push(` **Test:** ${testFailure.testName}`);
|
|
@@ -47188,10 +47419,10 @@ function formatPriorFailures(failures) {
|
|
|
47188
47419
|
}
|
|
47189
47420
|
}
|
|
47190
47421
|
}
|
|
47191
|
-
if (
|
|
47422
|
+
if (failure2.reviewFindings && failure2.reviewFindings.length > 0) {
|
|
47192
47423
|
parts.push(`
|
|
47193
47424
|
**Review Findings (fix these issues):**`);
|
|
47194
|
-
for (const finding of
|
|
47425
|
+
for (const finding of failure2.reviewFindings) {
|
|
47195
47426
|
const source = finding.source ? ` (${finding.source})` : "";
|
|
47196
47427
|
const loc = finding.file ? `${finding.file}:${finding.line ?? 0}` : "global";
|
|
47197
47428
|
parts.push(`
|
|
@@ -50179,6 +50410,37 @@ function decideReuse(live, descriptor, requested) {
|
|
|
50179
50410
|
return sameEndpoint(live.modelDef, requested.modelDef) ? "reuse" : "close-then-reopen";
|
|
50180
50411
|
}
|
|
50181
50412
|
|
|
50413
|
+
// src/session/loop-handler-forwarding.ts
|
|
50414
|
+
function buildLoopHandlerTurnOpts(input) {
|
|
50415
|
+
if (input.set.length === 0 || input.handle.agentName !== NATIVE_AGENT_NAME) {
|
|
50416
|
+
return {};
|
|
50417
|
+
}
|
|
50418
|
+
return {
|
|
50419
|
+
loopHandlers: input.set,
|
|
50420
|
+
loopHandlerContext: buildLoopHandlerContext(input.handle, input.descriptor)
|
|
50421
|
+
};
|
|
50422
|
+
}
|
|
50423
|
+
function buildLoopHandlerContext(handle, descriptor) {
|
|
50424
|
+
const role = descriptor ? descriptor.role : handle.role;
|
|
50425
|
+
const modelDef = handle.modelDef;
|
|
50426
|
+
return Object.freeze({
|
|
50427
|
+
sessionName: handle.id,
|
|
50428
|
+
...role !== undefined ? { role } : {},
|
|
50429
|
+
...descriptor?.storyId !== undefined ? { storyId: descriptor.storyId } : {},
|
|
50430
|
+
...descriptor?.featureName !== undefined ? { feature: descriptor.featureName } : {},
|
|
50431
|
+
...descriptor?.workdir !== undefined ? { workdir: descriptor.workdir } : {},
|
|
50432
|
+
...modelDef?.model !== undefined ? { model: modelDef.model } : {},
|
|
50433
|
+
...modelDef?.provider !== undefined ? { provider: modelDef.provider } : {}
|
|
50434
|
+
});
|
|
50435
|
+
}
|
|
50436
|
+
function shouldLogNativeOnlyScope(set2, handle, alreadyLogged) {
|
|
50437
|
+
return !alreadyLogged && set2.length > 0 && handle.agentName !== NATIVE_AGENT_NAME;
|
|
50438
|
+
}
|
|
50439
|
+
var LOOP_HANDLERS_NATIVE_ONLY_MESSAGE = "loop handlers apply to the native agent only";
|
|
50440
|
+
var init_loop_handler_forwarding = __esm(() => {
|
|
50441
|
+
init_config();
|
|
50442
|
+
});
|
|
50443
|
+
|
|
50182
50444
|
// src/session/manager-deps.ts
|
|
50183
50445
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
50184
50446
|
import { mkdir as mkdir12 } from "fs/promises";
|
|
@@ -50202,9 +50464,23 @@ function deriveNativeTranscriptDir(opts) {
|
|
|
50202
50464
|
return;
|
|
50203
50465
|
return join34(opts.transcriptRoot, "features", opts.featureName, "sessions");
|
|
50204
50466
|
}
|
|
50467
|
+
function persistDescriptor(descriptor) {
|
|
50468
|
+
if (!descriptor.scratchDir)
|
|
50469
|
+
return;
|
|
50470
|
+
const projectDir = resolveProjectDirFromScratchDir(descriptor.scratchDir);
|
|
50471
|
+
_sessionManagerDeps.writeDescriptor(descriptor.scratchDir, descriptor, projectDir).catch((err) => {
|
|
50472
|
+
getLogger().warn("session", "Failed to re-persist session descriptor", {
|
|
50473
|
+
storyId: descriptor.storyId,
|
|
50474
|
+
sessionId: descriptor.id,
|
|
50475
|
+
scratchDir: descriptor.scratchDir,
|
|
50476
|
+
error: err instanceof Error ? err.message : String(err)
|
|
50477
|
+
});
|
|
50478
|
+
});
|
|
50479
|
+
}
|
|
50205
50480
|
var _sessionManagerDeps;
|
|
50206
50481
|
var init_manager_deps = __esm(() => {
|
|
50207
50482
|
init_config();
|
|
50483
|
+
init_logger2();
|
|
50208
50484
|
_sessionManagerDeps = {
|
|
50209
50485
|
now: () => new Date().toISOString(),
|
|
50210
50486
|
nowMs: () => Date.now(),
|
|
@@ -50368,6 +50644,29 @@ var init_types6 = __esm(() => {
|
|
|
50368
50644
|
};
|
|
50369
50645
|
});
|
|
50370
50646
|
|
|
50647
|
+
// src/session/watchdog-cancel-tracker.ts
|
|
50648
|
+
class WatchdogCancelTracker {
|
|
50649
|
+
_cancelledCallsBySession = new Map;
|
|
50650
|
+
buildOnActiveCall(sessionName, registry3) {
|
|
50651
|
+
if (!registry3)
|
|
50652
|
+
return;
|
|
50653
|
+
return (callId, cancel) => {
|
|
50654
|
+
registry3.set(callId, async () => {
|
|
50655
|
+
const cancelledCalls = this._cancelledCallsBySession.get(sessionName) ?? new Set;
|
|
50656
|
+
cancelledCalls.add(callId);
|
|
50657
|
+
this._cancelledCallsBySession.set(sessionName, cancelledCalls);
|
|
50658
|
+
await cancel();
|
|
50659
|
+
});
|
|
50660
|
+
};
|
|
50661
|
+
}
|
|
50662
|
+
hasCancelled(sessionName) {
|
|
50663
|
+
return (this._cancelledCallsBySession.get(sessionName)?.size ?? 0) > 0;
|
|
50664
|
+
}
|
|
50665
|
+
clear(sessionName) {
|
|
50666
|
+
this._cancelledCallsBySession.delete(sessionName);
|
|
50667
|
+
}
|
|
50668
|
+
}
|
|
50669
|
+
|
|
50371
50670
|
// src/session/watchdog-turn-classification.ts
|
|
50372
50671
|
function isWatchdogCancelledTurn(input) {
|
|
50373
50672
|
const { watchdogFired, err, signalAborted } = input;
|
|
@@ -50395,7 +50694,9 @@ class SessionManager {
|
|
|
50395
50694
|
_watchdogControllerRegistry;
|
|
50396
50695
|
_transcriptRoot;
|
|
50397
50696
|
_onStreamActivity;
|
|
50398
|
-
|
|
50697
|
+
_loopHandlers = NO_LOOP_HANDLERS;
|
|
50698
|
+
_loopHandlerScopeLogged = false;
|
|
50699
|
+
_watchdogCancels = new WatchdogCancelTracker;
|
|
50399
50700
|
_agentStreamUnsubscribe;
|
|
50400
50701
|
constructor(opts) {
|
|
50401
50702
|
this._getAdapter = opts?.getAdapter ?? (() => {
|
|
@@ -50425,34 +50726,8 @@ class SessionManager {
|
|
|
50425
50726
|
});
|
|
50426
50727
|
}
|
|
50427
50728
|
}
|
|
50428
|
-
|
|
50429
|
-
|
|
50430
|
-
if (!registry3)
|
|
50431
|
-
return;
|
|
50432
|
-
return (callId, cancel) => {
|
|
50433
|
-
registry3.set(callId, async () => {
|
|
50434
|
-
const cancelledCalls = this._watchdogCancelledCallsBySession.get(sessionName) ?? new Set;
|
|
50435
|
-
cancelledCalls.add(callId);
|
|
50436
|
-
this._watchdogCancelledCallsBySession.set(sessionName, cancelledCalls);
|
|
50437
|
-
await cancel();
|
|
50438
|
-
});
|
|
50439
|
-
};
|
|
50440
|
-
}
|
|
50441
|
-
_clearWatchdogCancelledCalls(sessionName) {
|
|
50442
|
-
this._watchdogCancelledCallsBySession.delete(sessionName);
|
|
50443
|
-
}
|
|
50444
|
-
_persistDescriptor(descriptor) {
|
|
50445
|
-
if (!descriptor.scratchDir)
|
|
50446
|
-
return;
|
|
50447
|
-
const projectDir = resolveProjectDirFromScratchDir(descriptor.scratchDir);
|
|
50448
|
-
_sessionManagerDeps.writeDescriptor(descriptor.scratchDir, descriptor, projectDir).catch((err) => {
|
|
50449
|
-
getLogger().warn("session", "Failed to re-persist session descriptor", {
|
|
50450
|
-
storyId: descriptor.storyId,
|
|
50451
|
-
sessionId: descriptor.id,
|
|
50452
|
-
scratchDir: descriptor.scratchDir,
|
|
50453
|
-
error: err instanceof Error ? err.message : String(err)
|
|
50454
|
-
});
|
|
50455
|
-
});
|
|
50729
|
+
configureLoopHandlers(set2) {
|
|
50730
|
+
this._loopHandlers = set2;
|
|
50456
50731
|
}
|
|
50457
50732
|
create(options) {
|
|
50458
50733
|
const now = _sessionManagerDeps.now();
|
|
@@ -50523,7 +50798,7 @@ class SessionManager {
|
|
|
50523
50798
|
updated.completedStages = [...session.completedStages, options.completedStage];
|
|
50524
50799
|
}
|
|
50525
50800
|
this._sessions.set(id, updated);
|
|
50526
|
-
|
|
50801
|
+
persistDescriptor(updated);
|
|
50527
50802
|
getLogger().debug("session", "Session transitioned", {
|
|
50528
50803
|
storyId: session.storyId,
|
|
50529
50804
|
sessionId: id,
|
|
@@ -50547,7 +50822,7 @@ class SessionManager {
|
|
|
50547
50822
|
lastActivityAt: _sessionManagerDeps.now()
|
|
50548
50823
|
};
|
|
50549
50824
|
this._sessions.set(id, updated);
|
|
50550
|
-
|
|
50825
|
+
persistDescriptor(updated);
|
|
50551
50826
|
getLogger().debug("session", "Session handle bound", {
|
|
50552
50827
|
storyId: session.storyId,
|
|
50553
50828
|
sessionId: id,
|
|
@@ -50569,7 +50844,7 @@ class SessionManager {
|
|
|
50569
50844
|
lastActivityAt: _sessionManagerDeps.now()
|
|
50570
50845
|
};
|
|
50571
50846
|
this._sessions.set(id, updated);
|
|
50572
|
-
|
|
50847
|
+
persistDescriptor(updated);
|
|
50573
50848
|
getLogger().info("session", "Session handed off to fallback agent", {
|
|
50574
50849
|
storyId: session.storyId,
|
|
50575
50850
|
sessionId: id,
|
|
@@ -50604,7 +50879,7 @@ class SessionManager {
|
|
|
50604
50879
|
if (terminal.includes(session.state))
|
|
50605
50880
|
continue;
|
|
50606
50881
|
const updated = { ...session, state: "COMPLETED", lastActivityAt: now };
|
|
50607
|
-
|
|
50882
|
+
persistDescriptor(updated);
|
|
50608
50883
|
this._sessions.delete(id);
|
|
50609
50884
|
if (updated.handle)
|
|
50610
50885
|
this._liveHandles.delete(updated.handle);
|
|
@@ -50688,7 +50963,7 @@ class SessionManager {
|
|
|
50688
50963
|
onSessionEstablished: opts.onSessionEstablished,
|
|
50689
50964
|
signal: opts.signal,
|
|
50690
50965
|
resume,
|
|
50691
|
-
onActiveCall: this.
|
|
50966
|
+
onActiveCall: this._watchdogCancels.buildOnActiveCall(name, this._watchdogControllerRegistry),
|
|
50692
50967
|
onStreamActivity: this._onStreamActivity,
|
|
50693
50968
|
transcriptDir: opts.transcriptDir ?? deriveNativeTranscriptDir({ featureName: opts.featureName, transcriptRoot: this._transcriptRoot }),
|
|
50694
50969
|
...opts.transcriptOwner !== undefined ? { transcriptOwner: opts.transcriptOwner } : {},
|
|
@@ -50717,7 +50992,7 @@ class SessionManager {
|
|
|
50717
50992
|
lastActivityAt: _sessionManagerDeps.now()
|
|
50718
50993
|
};
|
|
50719
50994
|
this._sessions.set(existingDescriptor.id, updated);
|
|
50720
|
-
|
|
50995
|
+
persistDescriptor(updated);
|
|
50721
50996
|
} else {
|
|
50722
50997
|
getLogger().warn("session", "openSession called on already-RUNNING session", {
|
|
50723
50998
|
storyId: opts.storyId,
|
|
@@ -50752,7 +51027,7 @@ class SessionManager {
|
|
|
50752
51027
|
}
|
|
50753
51028
|
this._busySessions.delete(handle.id);
|
|
50754
51029
|
this._cancelledSessions.delete(handle.id);
|
|
50755
|
-
this.
|
|
51030
|
+
this._watchdogCancels.clear(handle.id);
|
|
50756
51031
|
}
|
|
50757
51032
|
async sendPrompt(handle, prompt, opts) {
|
|
50758
51033
|
if (this._cancelledSessions.has(handle.id)) {
|
|
@@ -50769,16 +51044,22 @@ class SessionManager {
|
|
|
50769
51044
|
if (!adapter) {
|
|
50770
51045
|
throw new NaxError(`SessionManager.sendPrompt: no adapter found for agent "${handle.agentName}"`, "ADAPTER_NOT_FOUND", { stage: "session", agentName: handle.agentName });
|
|
50771
51046
|
}
|
|
51047
|
+
const loopHandlerOpts = buildLoopHandlerTurnOpts({ handle, descriptor: terminalDesc, set: this._loopHandlers });
|
|
51048
|
+
if (shouldLogNativeOnlyScope(this._loopHandlers, handle, this._loopHandlerScopeLogged)) {
|
|
51049
|
+
this._loopHandlerScopeLogged = true;
|
|
51050
|
+
getLogger().info("plugins", LOOP_HANDLERS_NATIVE_ONLY_MESSAGE, { sessionName: handle.id });
|
|
51051
|
+
}
|
|
50772
51052
|
this._busySessions.add(handle.id);
|
|
50773
51053
|
try {
|
|
50774
51054
|
const result = await adapter.sendTurn(handle, prompt, {
|
|
50775
51055
|
...opts,
|
|
50776
|
-
interactionHandler: opts?.interactionHandler ?? NO_OP_INTERACTION_HANDLER
|
|
51056
|
+
interactionHandler: opts?.interactionHandler ?? NO_OP_INTERACTION_HANDLER,
|
|
51057
|
+
...loopHandlerOpts
|
|
50777
51058
|
});
|
|
50778
51059
|
return { ...result, protocolIds: result.protocolIds ?? handle.protocolIds };
|
|
50779
51060
|
} catch (err) {
|
|
50780
51061
|
if (isWatchdogCancelledTurn({
|
|
50781
|
-
watchdogFired:
|
|
51062
|
+
watchdogFired: this._watchdogCancels.hasCancelled(handle.id),
|
|
50782
51063
|
err,
|
|
50783
51064
|
signalAborted: opts?.signal?.aborted === true
|
|
50784
51065
|
})) {
|
|
@@ -50799,7 +51080,7 @@ class SessionManager {
|
|
|
50799
51080
|
}
|
|
50800
51081
|
throw err;
|
|
50801
51082
|
} finally {
|
|
50802
|
-
this.
|
|
51083
|
+
this._watchdogCancels.clear(handle.id);
|
|
50803
51084
|
this._busySessions.delete(handle.id);
|
|
50804
51085
|
}
|
|
50805
51086
|
}
|
|
@@ -50822,7 +51103,7 @@ class SessionManager {
|
|
|
50822
51103
|
this._agentStreamUnsubscribe = undefined;
|
|
50823
51104
|
}
|
|
50824
51105
|
}
|
|
50825
|
-
var NULL_PROTOCOL_IDS;
|
|
51106
|
+
var NULL_PROTOCOL_IDS, NO_LOOP_HANDLERS;
|
|
50826
51107
|
var init_manager = __esm(() => {
|
|
50827
51108
|
init_types2();
|
|
50828
51109
|
init_config();
|
|
@@ -50830,6 +51111,7 @@ var init_manager = __esm(() => {
|
|
|
50830
51111
|
init_errors();
|
|
50831
51112
|
init_logger2();
|
|
50832
51113
|
init_no_op_interaction_handler();
|
|
51114
|
+
init_loop_handler_forwarding();
|
|
50833
51115
|
init_manager_deps();
|
|
50834
51116
|
init_manager_sweep();
|
|
50835
51117
|
init_naming();
|
|
@@ -50838,6 +51120,7 @@ var init_manager = __esm(() => {
|
|
|
50838
51120
|
init_watchdog_turn_classification();
|
|
50839
51121
|
init_manager_deps();
|
|
50840
51122
|
NULL_PROTOCOL_IDS = { recordId: null, sessionId: null };
|
|
51123
|
+
NO_LOOP_HANDLERS = Object.freeze([]);
|
|
50841
51124
|
});
|
|
50842
51125
|
|
|
50843
51126
|
// src/session/reopen-handoff.ts
|
|
@@ -52782,12 +53065,12 @@ function toContextChunk(packed) {
|
|
|
52782
53065
|
...packed.staleCandidate && { staleCandidate: true }
|
|
52783
53066
|
};
|
|
52784
53067
|
}
|
|
52785
|
-
function buildFailureNoteChunk(priorAgentId, newAgentId,
|
|
53068
|
+
function buildFailureNoteChunk(priorAgentId, newAgentId, failure2) {
|
|
52786
53069
|
const lines = [
|
|
52787
53070
|
"## Agent swap (availability fallback)",
|
|
52788
53071
|
"",
|
|
52789
53072
|
`Prior agent: ${priorAgentId} became unavailable.`,
|
|
52790
|
-
`Reason: ${
|
|
53073
|
+
`Reason: ${failure2.outcome} \u2014 ${failure2.message}`,
|
|
52791
53074
|
"",
|
|
52792
53075
|
`Continuing as: ${newAgentId}`,
|
|
52793
53076
|
"",
|
|
@@ -52798,7 +53081,7 @@ function buildFailureNoteChunk(priorAgentId, newAgentId, failure) {
|
|
|
52798
53081
|
`);
|
|
52799
53082
|
const tokens = Math.ceil(content.length / 4);
|
|
52800
53083
|
return {
|
|
52801
|
-
id: `failure-note:${priorAgentId}:${newAgentId}:${
|
|
53084
|
+
id: `failure-note:${priorAgentId}:${newAgentId}:${failure2.outcome}`,
|
|
52802
53085
|
providerId: "orchestrator",
|
|
52803
53086
|
kind: "session",
|
|
52804
53087
|
scope: "session",
|
|
@@ -52977,7 +53260,7 @@ function toPackedChunks(prior, newAgentId, targetAgentId) {
|
|
|
52977
53260
|
});
|
|
52978
53261
|
}
|
|
52979
53262
|
function rebuild(prior, options = {}, deps = DEFAULT_REBUILD_DEPS) {
|
|
52980
|
-
const { newAgentId, failure, priorStageDigest, storyId } = options;
|
|
53263
|
+
const { newAgentId, failure: failure2, priorStageDigest, storyId } = options;
|
|
52981
53264
|
const targetAgentId = newAgentId ?? prior.agentId ?? DEFAULT_REBUILD_AGENT_ID;
|
|
52982
53265
|
const logger = deps.getLogger();
|
|
52983
53266
|
if (newAgentId && !AGENT_PROFILES[newAgentId]) {
|
|
@@ -52993,8 +53276,8 @@ function rebuild(prior, options = {}, deps = DEFAULT_REBUILD_DEPS) {
|
|
|
52993
53276
|
const rebuiltPullTools = targetProfile.caps.supportsToolCalls ? prior.pullTools : [];
|
|
52994
53277
|
const effectiveBudget = Math.min(prior.manifest.effectiveBudget ?? Number.POSITIVE_INFINITY, targetProfile.caps.preferredPromptTokens);
|
|
52995
53278
|
let failureNoteChunk;
|
|
52996
|
-
if (
|
|
52997
|
-
failureNoteChunk = buildFailureNoteChunk(prior.agentId || "unknown", newAgentId,
|
|
53279
|
+
if (failure2 && newAgentId && !prior.manifest.rebuildInfo) {
|
|
53280
|
+
failureNoteChunk = buildFailureNoteChunk(prior.agentId || "unknown", newAgentId, failure2);
|
|
52998
53281
|
packedChunks.push(failureNoteChunk);
|
|
52999
53282
|
}
|
|
53000
53283
|
let packResult = packChunks(packedChunks, effectiveBudget);
|
|
@@ -53021,11 +53304,11 @@ function rebuild(prior, options = {}, deps = DEFAULT_REBUILD_DEPS) {
|
|
|
53021
53304
|
const newDigestContent = priorStageDigest?.trim();
|
|
53022
53305
|
const digestContribution = newDigestContent ? Math.ceil(newDigestContent.length / 4) : 0;
|
|
53023
53306
|
const usedTokens = packResult.usedTokens + digestContribution;
|
|
53024
|
-
const rebuildInfo =
|
|
53307
|
+
const rebuildInfo = failure2 && newAgentId ? {
|
|
53025
53308
|
priorAgentId: prior.agentId ?? "unknown",
|
|
53026
53309
|
newAgentId: targetAgentId,
|
|
53027
|
-
failureCategory:
|
|
53028
|
-
failureOutcome:
|
|
53310
|
+
failureCategory: failure2.category,
|
|
53311
|
+
failureOutcome: failure2.outcome,
|
|
53029
53312
|
priorChunkIds,
|
|
53030
53313
|
newChunkIds: orderedChunks.map((c) => c.id),
|
|
53031
53314
|
chunkIdMap: [
|
|
@@ -55116,8 +55399,8 @@ var init_version = __esm(() => {
|
|
|
55116
55399
|
NAX_AI_VERSION = CATALOG_VERSION;
|
|
55117
55400
|
NAX_COMMIT = (() => {
|
|
55118
55401
|
try {
|
|
55119
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
55120
|
-
return "
|
|
55402
|
+
if (/^[0-9a-f]{6,10}$/.test("1c7aa52e"))
|
|
55403
|
+
return "1c7aa52e";
|
|
55121
55404
|
} catch {}
|
|
55122
55405
|
try {
|
|
55123
55406
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -56519,16 +56802,16 @@ var init_factory = __esm(() => {
|
|
|
56519
56802
|
import { existsSync as existsSync8 } from "fs";
|
|
56520
56803
|
function boundedProcRead(proc, timeoutMs) {
|
|
56521
56804
|
return new Promise((resolve25) => {
|
|
56522
|
-
let
|
|
56805
|
+
let settled2 = false;
|
|
56523
56806
|
const finish = (exitCode, stdout) => {
|
|
56524
|
-
if (
|
|
56807
|
+
if (settled2)
|
|
56525
56808
|
return;
|
|
56526
|
-
|
|
56809
|
+
settled2 = true;
|
|
56527
56810
|
clearTimeout(timer);
|
|
56528
56811
|
resolve25({ exitCode, stdout });
|
|
56529
56812
|
};
|
|
56530
56813
|
const timer = setTimeout(() => {
|
|
56531
|
-
if (
|
|
56814
|
+
if (settled2)
|
|
56532
56815
|
return;
|
|
56533
56816
|
try {
|
|
56534
56817
|
proc.kill("SIGKILL");
|
|
@@ -56540,26 +56823,26 @@ function boundedProcRead(proc, timeoutMs) {
|
|
|
56540
56823
|
}
|
|
56541
56824
|
function awaitProcExit(proc, timeoutMs) {
|
|
56542
56825
|
return new Promise((resolve25) => {
|
|
56543
|
-
let
|
|
56826
|
+
let settled2 = false;
|
|
56544
56827
|
const timer = setTimeout(() => {
|
|
56545
|
-
if (
|
|
56828
|
+
if (settled2)
|
|
56546
56829
|
return;
|
|
56547
|
-
|
|
56830
|
+
settled2 = true;
|
|
56548
56831
|
try {
|
|
56549
56832
|
proc.kill("SIGKILL");
|
|
56550
56833
|
} catch {}
|
|
56551
56834
|
resolve25(-1);
|
|
56552
56835
|
}, timeoutMs);
|
|
56553
56836
|
proc.exited.then((code) => {
|
|
56554
|
-
if (
|
|
56837
|
+
if (settled2)
|
|
56555
56838
|
return;
|
|
56556
|
-
|
|
56839
|
+
settled2 = true;
|
|
56557
56840
|
clearTimeout(timer);
|
|
56558
56841
|
resolve25(code);
|
|
56559
56842
|
}, () => {
|
|
56560
|
-
if (
|
|
56843
|
+
if (settled2)
|
|
56561
56844
|
return;
|
|
56562
|
-
|
|
56845
|
+
settled2 = true;
|
|
56563
56846
|
clearTimeout(timer);
|
|
56564
56847
|
resolve25(-1);
|
|
56565
56848
|
});
|
|
@@ -59302,11 +59585,11 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59302
59585
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
59303
59586
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
59304
59587
|
}
|
|
59305
|
-
optimizeNames(names,
|
|
59588
|
+
optimizeNames(names, constants2) {
|
|
59306
59589
|
if (!names[this.name.str])
|
|
59307
59590
|
return;
|
|
59308
59591
|
if (this.rhs)
|
|
59309
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
59592
|
+
this.rhs = optimizeExpr(this.rhs, names, constants2);
|
|
59310
59593
|
return this;
|
|
59311
59594
|
}
|
|
59312
59595
|
get names() {
|
|
@@ -59324,10 +59607,10 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59324
59607
|
render({ _n }) {
|
|
59325
59608
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
59326
59609
|
}
|
|
59327
|
-
optimizeNames(names,
|
|
59610
|
+
optimizeNames(names, constants2) {
|
|
59328
59611
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
59329
59612
|
return;
|
|
59330
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
59613
|
+
this.rhs = optimizeExpr(this.rhs, names, constants2);
|
|
59331
59614
|
return this;
|
|
59332
59615
|
}
|
|
59333
59616
|
get names() {
|
|
@@ -59393,8 +59676,8 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59393
59676
|
optimizeNodes() {
|
|
59394
59677
|
return `${this.code}` ? this : undefined;
|
|
59395
59678
|
}
|
|
59396
|
-
optimizeNames(names,
|
|
59397
|
-
this.code = optimizeExpr(this.code, names,
|
|
59679
|
+
optimizeNames(names, constants2) {
|
|
59680
|
+
this.code = optimizeExpr(this.code, names, constants2);
|
|
59398
59681
|
return this;
|
|
59399
59682
|
}
|
|
59400
59683
|
get names() {
|
|
@@ -59424,12 +59707,12 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59424
59707
|
}
|
|
59425
59708
|
return nodes.length > 0 ? this : undefined;
|
|
59426
59709
|
}
|
|
59427
|
-
optimizeNames(names,
|
|
59710
|
+
optimizeNames(names, constants2) {
|
|
59428
59711
|
const { nodes } = this;
|
|
59429
59712
|
let i = nodes.length;
|
|
59430
59713
|
while (i--) {
|
|
59431
59714
|
const n = nodes[i];
|
|
59432
|
-
if (n.optimizeNames(names,
|
|
59715
|
+
if (n.optimizeNames(names, constants2))
|
|
59433
59716
|
continue;
|
|
59434
59717
|
subtractNames(names, n.names);
|
|
59435
59718
|
nodes.splice(i, 1);
|
|
@@ -59486,12 +59769,12 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59486
59769
|
return;
|
|
59487
59770
|
return this;
|
|
59488
59771
|
}
|
|
59489
|
-
optimizeNames(names,
|
|
59772
|
+
optimizeNames(names, constants2) {
|
|
59490
59773
|
var _a2;
|
|
59491
|
-
this.else = (_a2 = this.else) === null || _a2 === undefined ? undefined : _a2.optimizeNames(names,
|
|
59492
|
-
if (!(super.optimizeNames(names,
|
|
59774
|
+
this.else = (_a2 = this.else) === null || _a2 === undefined ? undefined : _a2.optimizeNames(names, constants2);
|
|
59775
|
+
if (!(super.optimizeNames(names, constants2) || this.else))
|
|
59493
59776
|
return;
|
|
59494
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
59777
|
+
this.condition = optimizeExpr(this.condition, names, constants2);
|
|
59495
59778
|
return this;
|
|
59496
59779
|
}
|
|
59497
59780
|
get names() {
|
|
@@ -59516,10 +59799,10 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59516
59799
|
render(opts) {
|
|
59517
59800
|
return `for(${this.iteration})` + super.render(opts);
|
|
59518
59801
|
}
|
|
59519
|
-
optimizeNames(names,
|
|
59520
|
-
if (!super.optimizeNames(names,
|
|
59802
|
+
optimizeNames(names, constants2) {
|
|
59803
|
+
if (!super.optimizeNames(names, constants2))
|
|
59521
59804
|
return;
|
|
59522
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
59805
|
+
this.iteration = optimizeExpr(this.iteration, names, constants2);
|
|
59523
59806
|
return this;
|
|
59524
59807
|
}
|
|
59525
59808
|
get names() {
|
|
@@ -59557,10 +59840,10 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59557
59840
|
render(opts) {
|
|
59558
59841
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
59559
59842
|
}
|
|
59560
|
-
optimizeNames(names,
|
|
59561
|
-
if (!super.optimizeNames(names,
|
|
59843
|
+
optimizeNames(names, constants2) {
|
|
59844
|
+
if (!super.optimizeNames(names, constants2))
|
|
59562
59845
|
return;
|
|
59563
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
59846
|
+
this.iterable = optimizeExpr(this.iterable, names, constants2);
|
|
59564
59847
|
return this;
|
|
59565
59848
|
}
|
|
59566
59849
|
get names() {
|
|
@@ -59605,11 +59888,11 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59605
59888
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
59606
59889
|
return this;
|
|
59607
59890
|
}
|
|
59608
|
-
optimizeNames(names,
|
|
59891
|
+
optimizeNames(names, constants2) {
|
|
59609
59892
|
var _a2, _b;
|
|
59610
|
-
super.optimizeNames(names,
|
|
59611
|
-
(_a2 = this.catch) === null || _a2 === undefined || _a2.optimizeNames(names,
|
|
59612
|
-
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names,
|
|
59893
|
+
super.optimizeNames(names, constants2);
|
|
59894
|
+
(_a2 = this.catch) === null || _a2 === undefined || _a2.optimizeNames(names, constants2);
|
|
59895
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants2);
|
|
59613
59896
|
return this;
|
|
59614
59897
|
}
|
|
59615
59898
|
get names() {
|
|
@@ -59883,7 +60166,7 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59883
60166
|
function addExprNames(names, from) {
|
|
59884
60167
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
59885
60168
|
}
|
|
59886
|
-
function optimizeExpr(expr, names,
|
|
60169
|
+
function optimizeExpr(expr, names, constants2) {
|
|
59887
60170
|
if (expr instanceof code_1.Name)
|
|
59888
60171
|
return replaceName(expr);
|
|
59889
60172
|
if (!canOptimize(expr))
|
|
@@ -59898,14 +60181,14 @@ var require_codegen = __commonJS(function(exports) {
|
|
|
59898
60181
|
return items;
|
|
59899
60182
|
}, []));
|
|
59900
60183
|
function replaceName(n) {
|
|
59901
|
-
const c =
|
|
60184
|
+
const c = constants2[n.str];
|
|
59902
60185
|
if (c === undefined || names[n.str] !== 1)
|
|
59903
60186
|
return n;
|
|
59904
60187
|
delete names[n.str];
|
|
59905
60188
|
return c;
|
|
59906
60189
|
}
|
|
59907
60190
|
function canOptimize(e) {
|
|
59908
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
60191
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants2[c.str] !== undefined);
|
|
59909
60192
|
}
|
|
59910
60193
|
}
|
|
59911
60194
|
function subtractNames(names, from) {
|
|
@@ -67337,8 +67620,8 @@ function createMcpPool(opts) {
|
|
|
67337
67620
|
closed = true;
|
|
67338
67621
|
const pending = [...entries.values()];
|
|
67339
67622
|
entries.clear();
|
|
67340
|
-
const
|
|
67341
|
-
await Promise.allSettled(
|
|
67623
|
+
const settled2 = await Promise.allSettled(pending);
|
|
67624
|
+
await Promise.allSettled(settled2.map(async (result) => {
|
|
67342
67625
|
if (result.status !== "fulfilled" || result.value === undefined)
|
|
67343
67626
|
return;
|
|
67344
67627
|
const { connection } = result.value;
|
|
@@ -67478,9 +67761,9 @@ function probeRanNoTests(output) {
|
|
|
67478
67761
|
function escapeRegex2(input) {
|
|
67479
67762
|
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
67480
67763
|
}
|
|
67481
|
-
function buildIsolationCommand(baseCommand,
|
|
67482
|
-
const file2 =
|
|
67483
|
-
const name =
|
|
67764
|
+
function buildIsolationCommand(baseCommand, failure2, framework) {
|
|
67765
|
+
const file2 = failure2.file;
|
|
67766
|
+
const name = failure2.testName;
|
|
67484
67767
|
switch (framework) {
|
|
67485
67768
|
case "pytest":
|
|
67486
67769
|
return `${baseCommand} ${shellQuoteArg(`${file2}::${name}`)}`;
|
|
@@ -67498,15 +67781,15 @@ function buildIsolationCommand(baseCommand, failure, framework) {
|
|
|
67498
67781
|
}
|
|
67499
67782
|
}
|
|
67500
67783
|
async function runFlakeProbe(input) {
|
|
67501
|
-
const { framework, baseCommand, failure, cwd, probeRuns, probeTimeoutSeconds } = input;
|
|
67784
|
+
const { framework, baseCommand, failure: failure2, cwd, probeRuns, probeTimeoutSeconds } = input;
|
|
67502
67785
|
const logger = getSafeLogger();
|
|
67503
|
-
if (
|
|
67786
|
+
if (failure2.file === "unknown" || framework === "unknown") {
|
|
67504
67787
|
return {
|
|
67505
67788
|
verdict: "unprobeable",
|
|
67506
|
-
reason:
|
|
67789
|
+
reason: failure2.file === "unknown" && framework === "unknown" ? "unknown file and framework" : failure2.file === "unknown" ? "unknown file" : "unknown framework"
|
|
67507
67790
|
};
|
|
67508
67791
|
}
|
|
67509
|
-
const command = buildIsolationCommand(baseCommand,
|
|
67792
|
+
const command = buildIsolationCommand(baseCommand, failure2, framework);
|
|
67510
67793
|
let probePasses = 0;
|
|
67511
67794
|
let attributableRuns = 0;
|
|
67512
67795
|
for (let i = 0;i < probeRuns; i += 1) {
|
|
@@ -67534,8 +67817,8 @@ async function runFlakeProbe(input) {
|
|
|
67534
67817
|
if (attributableRuns === 0) {
|
|
67535
67818
|
const reason = `all ${probeRuns} probe run(s) were environmental (executor crash, timeout, or non-attributable) \u2014 no attributable pass or fail`;
|
|
67536
67819
|
logger?.warn("flake-probe", `Unprobeable \u2014 ${reason}`, {
|
|
67537
|
-
file:
|
|
67538
|
-
testName:
|
|
67820
|
+
file: failure2.file,
|
|
67821
|
+
testName: failure2.testName,
|
|
67539
67822
|
probeRuns
|
|
67540
67823
|
});
|
|
67541
67824
|
return { verdict: "unprobeable", reason };
|
|
@@ -67589,8 +67872,8 @@ var init_flake_triage_telemetry = __esm(() => {
|
|
|
67589
67872
|
});
|
|
67590
67873
|
|
|
67591
67874
|
// src/verification/flake-triage.ts
|
|
67592
|
-
function flakeMemoKey(
|
|
67593
|
-
return `${
|
|
67875
|
+
function flakeMemoKey(failure2) {
|
|
67876
|
+
return `${failure2.file ?? ""}::${failure2.rule ?? ""}`;
|
|
67594
67877
|
}
|
|
67595
67878
|
function createQuarantineMemo() {
|
|
67596
67879
|
const keys = new Set;
|
|
@@ -67651,7 +67934,7 @@ async function triageFlakyFindings(input) {
|
|
|
67651
67934
|
result.push(copy);
|
|
67652
67935
|
continue;
|
|
67653
67936
|
}
|
|
67654
|
-
const
|
|
67937
|
+
const failure2 = {
|
|
67655
67938
|
file: copy.file ?? "unknown",
|
|
67656
67939
|
testName: copy.rule ?? "",
|
|
67657
67940
|
error: copy.message,
|
|
@@ -67660,14 +67943,14 @@ async function triageFlakyFindings(input) {
|
|
|
67660
67943
|
const probeInput = {
|
|
67661
67944
|
framework,
|
|
67662
67945
|
baseCommand,
|
|
67663
|
-
failure,
|
|
67946
|
+
failure: failure2,
|
|
67664
67947
|
cwd,
|
|
67665
67948
|
probeRuns: flakeDetection.probeRuns,
|
|
67666
67949
|
probeTimeoutSeconds: flakeDetection.probeTimeoutSeconds
|
|
67667
67950
|
};
|
|
67668
67951
|
let verdict;
|
|
67669
67952
|
try {
|
|
67670
|
-
verdict = await _flakeTriageDeps.runFlakeProbe({ failure, config: flakeDetection, probeInput });
|
|
67953
|
+
verdict = await _flakeTriageDeps.runFlakeProbe({ failure: failure2, config: flakeDetection, probeInput });
|
|
67671
67954
|
} catch (err) {
|
|
67672
67955
|
logger?.warn("flake-triage", `Probe dependency threw for ${key} \u2014 keeping finding blocking`, {
|
|
67673
67956
|
file: copy.file,
|
|
@@ -67780,7 +68063,28 @@ var init_coding_tool_extras = __esm(() => {
|
|
|
67780
68063
|
});
|
|
67781
68064
|
|
|
67782
68065
|
// src/agents/coding-tool-sandbox.ts
|
|
67783
|
-
import {
|
|
68066
|
+
import { mkdir as mkdir21 } from "fs/promises";
|
|
68067
|
+
import { homedir as homedir5, tmpdir as tmpdir4 } from "os";
|
|
68068
|
+
async function sessionTempRoots(args) {
|
|
68069
|
+
const { runTmpRoot: runTmpRoot2, tmpDir } = args;
|
|
68070
|
+
const shared = () => ({ tempRoots: _sessionSandboxDeps.tempRoots(), confined: false });
|
|
68071
|
+
if (args.config.filesystem.allowSharedTmp || runTmpRoot2 === undefined || tmpDir === undefined)
|
|
68072
|
+
return shared();
|
|
68073
|
+
try {
|
|
68074
|
+
await _sessionSandboxDeps.mkdir(tmpDir);
|
|
68075
|
+
} catch (err) {
|
|
68076
|
+
getSafeLogger()?.warn("sandbox", "could not create the session temp dir \u2014 granting the shared temp roots", {
|
|
68077
|
+
storyId: args.storyId ?? "_dispatch",
|
|
68078
|
+
tmpDir,
|
|
68079
|
+
error: errorMessage(err)
|
|
68080
|
+
});
|
|
68081
|
+
return shared();
|
|
68082
|
+
}
|
|
68083
|
+
return {
|
|
68084
|
+
tempRoots: _sessionSandboxDeps.runTempRoots({ runTmpRoot: runTmpRoot2, tmpdir: _sessionSandboxDeps.tmpdir() }),
|
|
68085
|
+
confined: true
|
|
68086
|
+
};
|
|
68087
|
+
}
|
|
67784
68088
|
async function resolveSessionSandbox(args) {
|
|
67785
68089
|
const config2 = args.config;
|
|
67786
68090
|
if (config2 === undefined || !config2.enabled || !args.needsLauncher) {
|
|
@@ -67801,6 +68105,12 @@ async function resolveSessionSandbox(args) {
|
|
|
67801
68105
|
const git = await _sessionSandboxDeps.gitLayout(args.root);
|
|
67802
68106
|
const credentialFiles = await _sessionSandboxDeps.credentialFiles();
|
|
67803
68107
|
const approvalsFile = args.outputDir !== undefined ? approvalsPath(args.outputDir) : undefined;
|
|
68108
|
+
const { tempRoots, confined } = await sessionTempRoots({
|
|
68109
|
+
config: config2,
|
|
68110
|
+
storyId: args.storyId,
|
|
68111
|
+
runTmpRoot: args.runTmpRoot,
|
|
68112
|
+
tmpDir: args.tmpDir
|
|
68113
|
+
});
|
|
67804
68114
|
const policyFor = async (root) => buildSandboxPolicy({
|
|
67805
68115
|
root,
|
|
67806
68116
|
git,
|
|
@@ -67809,7 +68119,7 @@ async function resolveSessionSandbox(args) {
|
|
|
67809
68119
|
credentialFiles,
|
|
67810
68120
|
...approvalsFile !== undefined ? { approvalsFile } : {},
|
|
67811
68121
|
home: _sessionSandboxDeps.homedir(),
|
|
67812
|
-
tempRoots
|
|
68122
|
+
tempRoots,
|
|
67813
68123
|
platform: _sessionSandboxDeps.platform(),
|
|
67814
68124
|
config: config2
|
|
67815
68125
|
});
|
|
@@ -67821,7 +68131,7 @@ async function resolveSessionSandbox(args) {
|
|
|
67821
68131
|
const afterWrapped = await _sessionSandboxDeps.commonDirTripwire(git, args.storyId);
|
|
67822
68132
|
const network = config2.network.allowedDomains ?? "open";
|
|
67823
68133
|
return createCommandLauncher({
|
|
67824
|
-
state: { kind: "available", backend: backend2.name, network },
|
|
68134
|
+
state: { kind: "available", backend: backend2.name, network, ...confined ? { sharedTmp: false } : {} },
|
|
67825
68135
|
backend: backend2,
|
|
67826
68136
|
policyFor,
|
|
67827
68137
|
...afterWrapped !== undefined ? { afterWrapped } : {},
|
|
@@ -67851,6 +68161,7 @@ async function literalPolicyError(policyFor, root) {
|
|
|
67851
68161
|
var _sessionSandboxDeps;
|
|
67852
68162
|
var init_coding_tool_sandbox = __esm(() => {
|
|
67853
68163
|
init_errors();
|
|
68164
|
+
init_logger2();
|
|
67854
68165
|
init_permissions();
|
|
67855
68166
|
init_sandbox();
|
|
67856
68167
|
_sessionSandboxDeps = {
|
|
@@ -67863,7 +68174,10 @@ var init_coding_tool_sandbox = __esm(() => {
|
|
|
67863
68174
|
credentialFiles: listCredentialFiles,
|
|
67864
68175
|
tempRoots: defaultTempRoots,
|
|
67865
68176
|
homedir: homedir5,
|
|
67866
|
-
platform: () => process.platform
|
|
68177
|
+
platform: () => process.platform,
|
|
68178
|
+
mkdir: (path7) => mkdir21(path7, { recursive: true }),
|
|
68179
|
+
tmpdir: () => tmpdir4(),
|
|
68180
|
+
runTempRoots
|
|
67867
68181
|
};
|
|
67868
68182
|
});
|
|
67869
68183
|
|
|
@@ -67990,23 +68304,26 @@ function unionDeclaredTools(declared, providerResult) {
|
|
|
67990
68304
|
];
|
|
67991
68305
|
}
|
|
67992
68306
|
function warnDroppedProviders(providerResult, storyId) {
|
|
67993
|
-
for (const
|
|
68307
|
+
for (const failure2 of providerResult.failures) {
|
|
67994
68308
|
getSafeLogger()?.warn("tools", "[provider] dropped", {
|
|
67995
68309
|
storyId,
|
|
67996
|
-
providerId:
|
|
67997
|
-
reason:
|
|
68310
|
+
providerId: failure2.providerId,
|
|
68311
|
+
reason: failure2.reason
|
|
67998
68312
|
});
|
|
67999
68313
|
}
|
|
68000
68314
|
}
|
|
68001
68315
|
async function resolveDispatchLauncher(options, declared, sessionName) {
|
|
68002
|
-
|
|
68316
|
+
if (options.codingToolRoot === undefined || options.codingToolRoot.trim() === "")
|
|
68317
|
+
return;
|
|
68318
|
+
const runRoot = options.runId !== undefined ? runTmpRoot(options.runId) : undefined;
|
|
68319
|
+
return await resolveSessionSandbox({
|
|
68003
68320
|
config: options.config?.execution?.sandbox,
|
|
68004
68321
|
root: options.codingToolRoot,
|
|
68005
68322
|
...options.outputDir !== undefined ? { outputDir: options.outputDir } : {},
|
|
68006
68323
|
needsLauncher: declared.includes(BASH_TOOL_NAME) || declared.includes(EXEC_TOOL_NAME),
|
|
68007
68324
|
...options.storyId !== undefined ? { storyId: options.storyId } : {},
|
|
68008
|
-
...
|
|
68009
|
-
})
|
|
68325
|
+
...runRoot !== undefined ? { tmpDir: sessionTmpDirUnder(runRoot, sessionName), runTmpRoot: runRoot } : {}
|
|
68326
|
+
});
|
|
68010
68327
|
}
|
|
68011
68328
|
function optionalDispatchArgs(options) {
|
|
68012
68329
|
return {
|
|
@@ -69312,8 +69629,8 @@ async function mayHaveJournal(candidateRoots) {
|
|
|
69312
69629
|
return false;
|
|
69313
69630
|
}
|
|
69314
69631
|
async function recordInFlight(repoRoot, entry) {
|
|
69315
|
-
const { mkdir:
|
|
69316
|
-
await
|
|
69632
|
+
const { mkdir: mkdir22 } = await import("fs/promises");
|
|
69633
|
+
await mkdir22(journalDir(repoRoot), { recursive: true });
|
|
69317
69634
|
await Bun.write(journalPathFor(repoRoot, entry.storyId), JSON.stringify(entry));
|
|
69318
69635
|
}
|
|
69319
69636
|
async function clearInFlight(repoRoot, storyId) {
|
|
@@ -69762,7 +70079,7 @@ var init_runners = __esm(() => {
|
|
|
69762
70079
|
|
|
69763
70080
|
// src/verification/test-baseline.ts
|
|
69764
70081
|
import { existsSync as existsSync10 } from "fs";
|
|
69765
|
-
import { mkdir as
|
|
70082
|
+
import { mkdir as mkdir22, readdir as readdir6, rm as rm5 } from "fs/promises";
|
|
69766
70083
|
import { join as join57 } from "path";
|
|
69767
70084
|
function runBaselinePath(root, featureId) {
|
|
69768
70085
|
return join57(featureDir(root, featureId), RUN_BASELINE_FILENAME);
|
|
@@ -69779,7 +70096,7 @@ async function readRunBaseline(root, featureId) {
|
|
|
69779
70096
|
}
|
|
69780
70097
|
async function writeStoryBaseline(root, featureId, storyId, baseline) {
|
|
69781
70098
|
const path7 = storyBaselinePath(root, featureId, storyId);
|
|
69782
|
-
await
|
|
70099
|
+
await mkdir22(join57(featureDir(root, featureId), "stories", storyId), { recursive: true });
|
|
69783
70100
|
await saveJsonFile(path7, baseline, "test-baseline");
|
|
69784
70101
|
}
|
|
69785
70102
|
async function readStoryBaseline(root, featureId, storyId) {
|
|
@@ -70143,13 +70460,13 @@ function formatDuration2(ms) {
|
|
|
70143
70460
|
return `${minutes}m ${seconds}s`;
|
|
70144
70461
|
}
|
|
70145
70462
|
function timeoutRetry(input) {
|
|
70146
|
-
const { prompt, changedFiles, elapsedMs, attempt, failure } = input;
|
|
70147
|
-
if (
|
|
70148
|
-
return invalidToolCallRetry(input,
|
|
70149
|
-
if (
|
|
70463
|
+
const { prompt, changedFiles, elapsedMs, attempt, failure: failure2 } = input;
|
|
70464
|
+
if (failure2?.outcome === "fail-invalid-tool-call")
|
|
70465
|
+
return invalidToolCallRetry(input, failure2);
|
|
70466
|
+
if (failure2?.outcome === "fail-spin") {
|
|
70150
70467
|
return nonTimeoutRetry(input, "The previous attempt was stopped because it kept repeating the same tool calls without making progress.", "Do not repeat a call whose result you already have; if a check keeps returning the same result, change the code or the approach before running it again.");
|
|
70151
70468
|
}
|
|
70152
|
-
if (
|
|
70469
|
+
if (failure2?.outcome === "fail-incomplete") {
|
|
70153
70470
|
return nonTimeoutRetry(input, "The previous attempt ended its turn before finishing the story.", "Keep working until every acceptance criterion is met, then finish with your final answer.");
|
|
70154
70471
|
}
|
|
70155
70472
|
const duration3 = formatDuration2(elapsedMs);
|
|
@@ -70193,8 +70510,8 @@ ${state}
|
|
|
70193
70510
|
|
|
70194
70511
|
${prompt}`;
|
|
70195
70512
|
}
|
|
70196
|
-
function invalidToolCallRetry(input,
|
|
70197
|
-
const detail =
|
|
70513
|
+
function invalidToolCallRetry(input, failure2) {
|
|
70514
|
+
const detail = failure2.invalidToolCall;
|
|
70198
70515
|
const rejected = detail === undefined ? "The previous attempt was stopped because it kept repeating the same invalid tool call. The tool rejected that input every time and never ran it." : `The previous attempt was stopped because it kept repeating the same invalid \`${detail.tool}\` call: property \`${detail.property}\` expected ${detail.expected}, got ${detail.actual}. The tool rejected that input every time and never ran it.`;
|
|
70199
70516
|
const fix = detail === undefined ? "Before calling a tool, check its input schema. If an optional property has no value, leave it out entirely." : `Before calling \`${detail.tool}\` again, make \`${detail.property}\` match its schema (${detail.expected}). If it is optional and you have no value for it, leave it out entirely.`;
|
|
70200
70517
|
return nonTimeoutRetry(input, rejected, fix);
|
|
@@ -70557,26 +70874,35 @@ function resolvePytestBin(packageDir) {
|
|
|
70557
70874
|
return "pytest";
|
|
70558
70875
|
}
|
|
70559
70876
|
function substituteAcceptanceTestPath(command, testPath) {
|
|
70560
|
-
return command.replace(/\{\{files\}\}/g, testPath).replace(/\{\{file\}\}/g, testPath).replace(/\{\{FILE\}\}/g, testPath);
|
|
70877
|
+
return command.replace(/\{\{files\}\}/g, () => testPath).replace(/\{\{file\}\}/g, () => testPath).replace(/\{\{FILE\}\}/g, () => testPath);
|
|
70561
70878
|
}
|
|
70562
70879
|
function buildAcceptanceRunCommand(testPath, testFramework, commandOverride, packageDir) {
|
|
70563
|
-
|
|
70564
|
-
|
|
70880
|
+
const trimmedOverride = commandOverride?.trim();
|
|
70881
|
+
if (trimmedOverride) {
|
|
70882
|
+
return substituteAcceptanceTestPath(trimmedOverride, shellQuoteArg(testPath));
|
|
70565
70883
|
}
|
|
70884
|
+
let defaultArgv;
|
|
70566
70885
|
switch (testFramework?.toLowerCase()) {
|
|
70567
70886
|
case "vitest":
|
|
70568
|
-
|
|
70887
|
+
defaultArgv = ["npx", "vitest", "run", testPath];
|
|
70888
|
+
break;
|
|
70569
70889
|
case "jest":
|
|
70570
|
-
|
|
70890
|
+
defaultArgv = ["npx", "jest", testPath];
|
|
70891
|
+
break;
|
|
70571
70892
|
case "pytest":
|
|
70572
|
-
|
|
70893
|
+
defaultArgv = [resolvePytestBin(packageDir), testPath];
|
|
70894
|
+
break;
|
|
70573
70895
|
case "go-test":
|
|
70574
|
-
|
|
70896
|
+
defaultArgv = ["go", "test", testPath];
|
|
70897
|
+
break;
|
|
70575
70898
|
case "cargo-test":
|
|
70576
|
-
|
|
70899
|
+
defaultArgv = ["cargo", "test", "--test", "acceptance"];
|
|
70900
|
+
break;
|
|
70577
70901
|
default:
|
|
70578
|
-
|
|
70902
|
+
defaultArgv = ["bun", "test", testPath, "--timeout=60000"];
|
|
70903
|
+
break;
|
|
70579
70904
|
}
|
|
70905
|
+
return defaultArgv.map(shellQuoteArg).join(" ");
|
|
70580
70906
|
}
|
|
70581
70907
|
function parseAcceptanceCriteria(specContent) {
|
|
70582
70908
|
const criteria = [];
|
|
@@ -72005,7 +72331,7 @@ var init_build_hop_callback = __esm(() => {
|
|
|
72005
72331
|
init_build_hop_callback_hop();
|
|
72006
72332
|
init_hop_endpoint();
|
|
72007
72333
|
_buildHopCallbackDeps = {
|
|
72008
|
-
rebuildForAgent: (prior, newAgentId,
|
|
72334
|
+
rebuildForAgent: (prior, newAgentId, failure2, storyId) => new ContextOrchestrator([]).rebuildForAgent(prior, { newAgentId, failure: failure2, storyId }),
|
|
72009
72335
|
writeRebuildManifest,
|
|
72010
72336
|
createContextToolRuntime,
|
|
72011
72337
|
captureGitRef,
|
|
@@ -72161,8 +72487,8 @@ function decideCompleteRetry(args) {
|
|
|
72161
72487
|
const { ctx, op, err, attempt, retryStrategy, dispatchAgent, abortSignal } = args;
|
|
72162
72488
|
if (!retryStrategy)
|
|
72163
72489
|
return;
|
|
72164
|
-
const
|
|
72165
|
-
const decision = retryStrategy.shouldRetry(
|
|
72490
|
+
const failure2 = err;
|
|
72491
|
+
const decision = retryStrategy.shouldRetry(failure2, attempt, {
|
|
72166
72492
|
site: "complete",
|
|
72167
72493
|
agentName: dispatchAgent,
|
|
72168
72494
|
stage: op.stage,
|
|
@@ -72182,8 +72508,8 @@ function decideCompleteRetry(args) {
|
|
|
72182
72508
|
attempt,
|
|
72183
72509
|
delayMs: decision.delayMs,
|
|
72184
72510
|
promptTransformed: decision.nextPrompt !== undefined,
|
|
72185
|
-
failureKind:
|
|
72186
|
-
failureMessage: errorMessage(
|
|
72511
|
+
failureKind: failure2 instanceof Error ? "error" : failure2.outcome,
|
|
72512
|
+
failureMessage: errorMessage(failure2)
|
|
72187
72513
|
});
|
|
72188
72514
|
return { delayMs: decision.delayMs };
|
|
72189
72515
|
}
|
|
@@ -74591,7 +74917,7 @@ var init_scope = __esm(() => {
|
|
|
74591
74917
|
|
|
74592
74918
|
// src/review/fix-review/tree-snapshot/index.ts
|
|
74593
74919
|
import { mkdtemp, rm as rm6 } from "fs/promises";
|
|
74594
|
-
import { tmpdir as
|
|
74920
|
+
import { tmpdir as tmpdir5 } from "os";
|
|
74595
74921
|
import { join as join61 } from "path";
|
|
74596
74922
|
async function runGit(args, cwd, indexOverlay, timeoutMs = _treeSnapshotDeps.gitTimeoutMs) {
|
|
74597
74923
|
const proc = _treeSnapshotDeps.spawn(hardenedGitArgv(["git", ...args]), {
|
|
@@ -74678,7 +75004,7 @@ var init_tree_snapshot = __esm(() => {
|
|
|
74678
75004
|
gitTimeoutMs: TREE_SNAPSHOT_GIT_TIMEOUT_MS,
|
|
74679
75005
|
mkdtemp,
|
|
74680
75006
|
rm: rm6,
|
|
74681
|
-
tmpdir:
|
|
75007
|
+
tmpdir: tmpdir5
|
|
74682
75008
|
};
|
|
74683
75009
|
});
|
|
74684
75010
|
|
|
@@ -79220,8 +79546,8 @@ function makeParseRetryStrategy(opts) {
|
|
|
79220
79546
|
const checkTruncated = opts.looksTruncated ?? looksLikeTruncatedJson;
|
|
79221
79547
|
const maxAttempts = opts.maxAttempts ?? 2;
|
|
79222
79548
|
return {
|
|
79223
|
-
shouldRetry(
|
|
79224
|
-
if (!(
|
|
79549
|
+
shouldRetry(failure2, attempt, ctx) {
|
|
79550
|
+
if (!(failure2 instanceof ParseValidationError)) {
|
|
79225
79551
|
return { retry: false };
|
|
79226
79552
|
}
|
|
79227
79553
|
if (ctx.lastOutput && ctx.lastTurnResult?.adapterFailure) {
|
|
@@ -79282,13 +79608,13 @@ var init_parse_retry = __esm(() => {
|
|
|
79282
79608
|
// src/agents/retry/presets.ts
|
|
79283
79609
|
function resolveRetryPreset(preset) {
|
|
79284
79610
|
return {
|
|
79285
|
-
shouldRetry(
|
|
79611
|
+
shouldRetry(failure2, attempt, _ctx) {
|
|
79286
79612
|
if (attempt >= preset.maxAttempts - 1)
|
|
79287
79613
|
return { retry: false };
|
|
79288
79614
|
if (preset.preset === "transient-network") {
|
|
79289
|
-
if (
|
|
79615
|
+
if (failure2 instanceof Error)
|
|
79290
79616
|
return { retry: true, delayMs: preset.baseDelayMs };
|
|
79291
|
-
const af =
|
|
79617
|
+
const af = failure2;
|
|
79292
79618
|
if (af.retriable)
|
|
79293
79619
|
return { retry: true, delayMs: preset.baseDelayMs };
|
|
79294
79620
|
return { retry: false };
|
|
@@ -79382,11 +79708,11 @@ function recordAgentFallbacks(ctx, fallbacks) {
|
|
|
79382
79708
|
}
|
|
79383
79709
|
store.set(ctx.storyId, [...fallbacks]);
|
|
79384
79710
|
}
|
|
79385
|
-
function recordAdapterFailure(ctx,
|
|
79711
|
+
function recordAdapterFailure(ctx, failure2) {
|
|
79386
79712
|
if (!ctx.storyId)
|
|
79387
79713
|
return;
|
|
79388
|
-
if (
|
|
79389
|
-
ctx.runtime.lastAdapterFailure.set(ctx.storyId,
|
|
79714
|
+
if (failure2) {
|
|
79715
|
+
ctx.runtime.lastAdapterFailure.set(ctx.storyId, failure2);
|
|
79390
79716
|
return;
|
|
79391
79717
|
}
|
|
79392
79718
|
ctx.runtime.lastAdapterFailure.delete(ctx.storyId);
|
|
@@ -79428,12 +79754,12 @@ class CooldownStore {
|
|
|
79428
79754
|
constructor(_now) {
|
|
79429
79755
|
this._now = _now;
|
|
79430
79756
|
}
|
|
79431
|
-
mark(agent,
|
|
79432
|
-
const expiresAt = resolveCooldownExpiry(
|
|
79757
|
+
mark(agent, failure2, tier, modelId) {
|
|
79758
|
+
const expiresAt = resolveCooldownExpiry(failure2, this._now());
|
|
79433
79759
|
if (expiresAt === null)
|
|
79434
79760
|
return;
|
|
79435
|
-
const key = failurePolicyFor(
|
|
79436
|
-
this._entries.set(key, { failure, expiresAt });
|
|
79761
|
+
const key = failurePolicyFor(failure2.outcome).cooldownScope === "agent" ? agent : identityKey(agent, tier, modelId);
|
|
79762
|
+
this._entries.set(key, { failure: failure2, expiresAt });
|
|
79437
79763
|
}
|
|
79438
79764
|
isCooling(agent, tier, modelId) {
|
|
79439
79765
|
return this._live(agent, tier, modelId) !== undefined;
|
|
@@ -79731,11 +80057,11 @@ var init_manager_dispatch = __esm(() => {
|
|
|
79731
80057
|
|
|
79732
80058
|
// src/agents/retry/resolve-exhaustion.ts
|
|
79733
80059
|
async function resolveExhaustion(input) {
|
|
79734
|
-
const { failure, retryStrategy, retryCtx, signal, sleep: sleep2, onExhausted } = input;
|
|
80060
|
+
const { failure: failure2, retryStrategy, retryCtx, signal, sleep: sleep2, onExhausted } = input;
|
|
79735
80061
|
if (signal?.aborted)
|
|
79736
80062
|
return "cancelled";
|
|
79737
|
-
if (
|
|
79738
|
-
const decision = retryStrategy.shouldRetry(
|
|
80063
|
+
if (failure2 && failurePolicyFor(failure2.outcome).terminalBackoff) {
|
|
80064
|
+
const decision = retryStrategy.shouldRetry(failure2, input.attempt, retryCtx);
|
|
79739
80065
|
if (decision.retry) {
|
|
79740
80066
|
await sleep2(decision.delayMs, signal);
|
|
79741
80067
|
return signal?.aborted ? "cancelled" : "retry";
|
|
@@ -79965,13 +80291,13 @@ async function runWithFallback(input) {
|
|
|
79965
80291
|
dispatchesCompleted
|
|
79966
80292
|
};
|
|
79967
80293
|
}
|
|
79968
|
-
const
|
|
80294
|
+
const failure2 = result.adapterFailure ?? unknownFailure();
|
|
79969
80295
|
const currentTier = currentHopKind.tier;
|
|
79970
|
-
input.markUnavailable(currentAgent,
|
|
80296
|
+
input.markUnavailable(currentAgent, failure2, currentTier, dispatchedModel);
|
|
79971
80297
|
const next = input.nextCandidate(primaryAgent, hopsSoFar, currentAgent, currentTier, dispatchedModel);
|
|
79972
80298
|
if (!next) {
|
|
79973
80299
|
const outcome = await input.resolveExhaustion({
|
|
79974
|
-
failure,
|
|
80300
|
+
failure: failure2,
|
|
79975
80301
|
hopsSoFar,
|
|
79976
80302
|
attempt: rateLimitRetry,
|
|
79977
80303
|
swapWasPossible: true,
|
|
@@ -80004,7 +80330,7 @@ async function runWithFallback(input) {
|
|
|
80004
80330
|
currentBundle = updatedBundle;
|
|
80005
80331
|
currentHopKind = {
|
|
80006
80332
|
kind: "swap",
|
|
80007
|
-
failure,
|
|
80333
|
+
failure: failure2,
|
|
80008
80334
|
...next.tier ? { tier: next.tier } : {},
|
|
80009
80335
|
...next.model ? { model: next.model } : {}
|
|
80010
80336
|
};
|
|
@@ -80013,7 +80339,7 @@ async function runWithFallback(input) {
|
|
|
80013
80339
|
priorAgent: currentAgent,
|
|
80014
80340
|
newAgent: next.agent,
|
|
80015
80341
|
hop: hopsSoFar,
|
|
80016
|
-
failure,
|
|
80342
|
+
failure: failure2,
|
|
80017
80343
|
costUsd: result.estimatedCostUsd ?? 0
|
|
80018
80344
|
});
|
|
80019
80345
|
fallbacks.push(fallback);
|
|
@@ -80265,8 +80591,8 @@ class AgentManager {
|
|
|
80265
80591
|
resolveFallbackChain(agent, _failure) {
|
|
80266
80592
|
return this._fallbackIdentity.chain(agent, this._isExcluded);
|
|
80267
80593
|
}
|
|
80268
|
-
shouldSwap(
|
|
80269
|
-
return decideSwap(
|
|
80594
|
+
shouldSwap(failure2, hopsSoFar) {
|
|
80595
|
+
return decideSwap(failure2, hopsSoFar, this._config.agent?.fallback).swap;
|
|
80270
80596
|
}
|
|
80271
80597
|
nextCandidate(cur, hops, exclude, tier, model) {
|
|
80272
80598
|
return this._fallbackIdentity.nextCandidate({ cur, hops, exclude, tier, model }, this._isExcluded);
|
|
@@ -80282,7 +80608,7 @@ class AgentManager {
|
|
|
80282
80608
|
logger: this._loggerOverride ?? getSafeLogger(),
|
|
80283
80609
|
getDefault: () => this.getDefault(),
|
|
80284
80610
|
isUnavailable: (agent, tier, model) => this.isUnavailable(agent, tier, model),
|
|
80285
|
-
markUnavailable: (agent,
|
|
80611
|
+
markUnavailable: (agent, failure2, tier, model) => this.markUnavailable(agent, failure2, tier, model),
|
|
80286
80612
|
nextCandidate: (cur, hops, exclude, tier, model) => this.nextCandidate(cur, hops, exclude, tier, model),
|
|
80287
80613
|
resolveExhaustion: (options) => this._resolveExhaustion(options),
|
|
80288
80614
|
emitSwapAttempt: (fallback) => this._emitter.emit("onSwapAttempt", fallback),
|
|
@@ -80934,11 +81260,11 @@ async function promptForConfirmation(question) {
|
|
|
80934
81260
|
stdin.setRawMode(true);
|
|
80935
81261
|
stdin.resume();
|
|
80936
81262
|
stdin.setEncoding("utf8");
|
|
80937
|
-
let
|
|
81263
|
+
let settled2 = false;
|
|
80938
81264
|
const finish = (answer) => {
|
|
80939
|
-
if (
|
|
81265
|
+
if (settled2)
|
|
80940
81266
|
return;
|
|
80941
|
-
|
|
81267
|
+
settled2 = true;
|
|
80942
81268
|
stdin.setRawMode(false);
|
|
80943
81269
|
stdin.pause();
|
|
80944
81270
|
stdin.removeListener("data", onData);
|
|
@@ -81197,11 +81523,11 @@ function read(message, echo, onEmptySubmit) {
|
|
|
81197
81523
|
_authPromptDeps.write(`${source_default.cyan("?")} ${message} `);
|
|
81198
81524
|
return new Promise((resolve28, reject) => {
|
|
81199
81525
|
let buffer = "";
|
|
81200
|
-
let
|
|
81526
|
+
let settled2 = false;
|
|
81201
81527
|
const cleanup = () => {
|
|
81202
|
-
if (
|
|
81528
|
+
if (settled2)
|
|
81203
81529
|
return;
|
|
81204
|
-
|
|
81530
|
+
settled2 = true;
|
|
81205
81531
|
stdin.removeListener("data", onData);
|
|
81206
81532
|
stdin.removeListener("end", onEnd);
|
|
81207
81533
|
stdin.removeListener("error", onEnd);
|
|
@@ -81265,7 +81591,7 @@ function promptForSelect(message, choices) {
|
|
|
81265
81591
|
`);
|
|
81266
81592
|
return new Promise((resolve28, reject) => {
|
|
81267
81593
|
let index = 0;
|
|
81268
|
-
let
|
|
81594
|
+
let settled2 = false;
|
|
81269
81595
|
let drawn = false;
|
|
81270
81596
|
const render3 = () => {
|
|
81271
81597
|
if (drawn)
|
|
@@ -81280,9 +81606,9 @@ function promptForSelect(message, choices) {
|
|
|
81280
81606
|
}
|
|
81281
81607
|
};
|
|
81282
81608
|
const cleanup = () => {
|
|
81283
|
-
if (
|
|
81609
|
+
if (settled2)
|
|
81284
81610
|
return;
|
|
81285
|
-
|
|
81611
|
+
settled2 = true;
|
|
81286
81612
|
stdin.removeListener("data", onData);
|
|
81287
81613
|
stdin.removeListener("end", onEnd);
|
|
81288
81614
|
stdin.removeListener("error", onEnd);
|
|
@@ -81620,6 +81946,7 @@ var init_config_descriptions = __esm(() => {
|
|
|
81620
81946
|
"execution.sandbox.filesystem": "Filesystem policy additions for the sandbox",
|
|
81621
81947
|
"execution.sandbox.filesystem.allowWrite": "Extra literal paths the sandbox may write (no glob characters)",
|
|
81622
81948
|
"execution.sandbox.filesystem.denyRead": "Extra literal paths the sandbox may not read (no glob characters)",
|
|
81949
|
+
"execution.sandbox.filesystem.allowSharedTmp": "Also grant the shared temp directories (os.tmpdir(), /tmp) to sandboxed commands. Off by default: temp writes stay inside this run's own temp root",
|
|
81623
81950
|
"execution.sandbox.network": "Network policy for sandboxed commands",
|
|
81624
81951
|
"execution.sandbox.network.allowedDomains": "Domains sandboxed commands may reach; absent means open",
|
|
81625
81952
|
"execution.commandSafety": "Shadow command classifier; observes every command, decides nothing. Root-only (ADR-031)",
|
|
@@ -83022,7 +83349,12 @@ async function processPackageGroup(ctx, packageDir, groupStories, language, resu
|
|
|
83022
83349
|
}
|
|
83023
83350
|
await _hardeningDeps.writeFile(suggestedTestPath, testCode);
|
|
83024
83351
|
const testCmd = buildAcceptanceRunCommand(suggestedTestPath, config2.project?.testFramework, config2.acceptance?.command, packageDir);
|
|
83025
|
-
const proc = _hardeningDeps.spawn(
|
|
83352
|
+
const proc = _hardeningDeps.spawn(["/bin/sh", "-c", testCmd], {
|
|
83353
|
+
cwd: packageDir,
|
|
83354
|
+
stdout: "pipe",
|
|
83355
|
+
stderr: "pipe",
|
|
83356
|
+
detached: true
|
|
83357
|
+
});
|
|
83026
83358
|
let exitedBeforeSigkill = false;
|
|
83027
83359
|
let sigkillTimer;
|
|
83028
83360
|
proc.exited.then(() => {
|
|
@@ -84233,13 +84565,13 @@ var init_generate = __esm(() => {
|
|
|
84233
84565
|
});
|
|
84234
84566
|
|
|
84235
84567
|
// src/cli/init-context.ts
|
|
84236
|
-
import { mkdir as
|
|
84568
|
+
import { mkdir as mkdir23, readdir as readdir7 } from "fs/promises";
|
|
84237
84569
|
import { basename as basename11, join as join76, relative as relative25, sep as sep13 } from "path";
|
|
84238
84570
|
async function bunFileExists(path12) {
|
|
84239
84571
|
return Bun.file(path12).exists();
|
|
84240
84572
|
}
|
|
84241
84573
|
async function mkdirp(path12) {
|
|
84242
|
-
await
|
|
84574
|
+
await mkdir23(path12, { recursive: true });
|
|
84243
84575
|
}
|
|
84244
84576
|
async function findFiles(dir, maxFiles = 200) {
|
|
84245
84577
|
const files = [];
|
|
@@ -84726,7 +85058,7 @@ __export(exports_init, {
|
|
|
84726
85058
|
validateProjectName: () => validateProjectName
|
|
84727
85059
|
});
|
|
84728
85060
|
import { existsSync as existsSync22 } from "fs";
|
|
84729
|
-
import { mkdir as
|
|
85061
|
+
import { mkdir as mkdir24 } from "fs/promises";
|
|
84730
85062
|
import { join as join78 } from "path";
|
|
84731
85063
|
function validateProjectName(name) {
|
|
84732
85064
|
if (!name)
|
|
@@ -84854,7 +85186,7 @@ async function initGlobal() {
|
|
|
84854
85186
|
const logger = getLogger();
|
|
84855
85187
|
const globalDir = globalConfigDir();
|
|
84856
85188
|
if (!existsSync22(globalDir)) {
|
|
84857
|
-
await
|
|
85189
|
+
await mkdir24(globalDir, { recursive: true });
|
|
84858
85190
|
logger.info("init", "Created global config directory", { path: globalDir });
|
|
84859
85191
|
}
|
|
84860
85192
|
const configPath = join78(globalDir, "config.json");
|
|
@@ -84874,7 +85206,7 @@ async function initGlobal() {
|
|
|
84874
85206
|
}
|
|
84875
85207
|
const hooksDir = join78(globalDir, "hooks");
|
|
84876
85208
|
if (!existsSync22(hooksDir)) {
|
|
84877
|
-
await
|
|
85209
|
+
await mkdir24(hooksDir, { recursive: true });
|
|
84878
85210
|
logger.info("init", "Created global hooks directory", { path: hooksDir });
|
|
84879
85211
|
} else {
|
|
84880
85212
|
logger.info("init", "Global hooks directory already exists", { path: hooksDir });
|
|
@@ -84919,7 +85251,7 @@ async function initProject(projectRoot, options) {
|
|
|
84919
85251
|
}
|
|
84920
85252
|
}
|
|
84921
85253
|
if (!existsSync22(projectDir)) {
|
|
84922
|
-
await
|
|
85254
|
+
await mkdir24(projectDir, { recursive: true });
|
|
84923
85255
|
logger.info("init", "Created project config directory", { path: projectDir });
|
|
84924
85256
|
}
|
|
84925
85257
|
const stack = detectStack(projectRoot);
|
|
@@ -84954,7 +85286,7 @@ async function initProject(projectRoot, options) {
|
|
|
84954
85286
|
["features", featuresDir(projectRoot)]
|
|
84955
85287
|
]) {
|
|
84956
85288
|
if (!existsSync22(dir)) {
|
|
84957
|
-
await
|
|
85289
|
+
await mkdir24(dir, { recursive: true });
|
|
84958
85290
|
logger.info("init", `Created project ${label} directory`, { path: dir });
|
|
84959
85291
|
} else {
|
|
84960
85292
|
logger.info("init", `Project ${label} directory already exists`, { path: dir });
|
|
@@ -87696,11 +88028,11 @@ async function runGitBounded2(args, workdir) {
|
|
|
87696
88028
|
let timedOut = false;
|
|
87697
88029
|
let exitCode = -1;
|
|
87698
88030
|
await new Promise((resolve29) => {
|
|
87699
|
-
let
|
|
88031
|
+
let settled2 = false;
|
|
87700
88032
|
const finish = (code) => {
|
|
87701
|
-
if (
|
|
88033
|
+
if (settled2)
|
|
87702
88034
|
return;
|
|
87703
|
-
|
|
88035
|
+
settled2 = true;
|
|
87704
88036
|
clearTimeout(timer);
|
|
87705
88037
|
exitCode = code;
|
|
87706
88038
|
resolve29();
|
|
@@ -88441,7 +88773,35 @@ function findingFile(file2) {
|
|
|
88441
88773
|
return file2;
|
|
88442
88774
|
}
|
|
88443
88775
|
async function runFixReview(ctx, req, deps = {}) {
|
|
88444
|
-
const
|
|
88776
|
+
const verdict = await evaluateFixReview(ctx, req, { ...DEFAULT_DEPS2, ...deps });
|
|
88777
|
+
logVerdict(ctx.runtime?.logger, req.story.id, verdict);
|
|
88778
|
+
return verdict;
|
|
88779
|
+
}
|
|
88780
|
+
function logVerdict(logger, storyId, verdict) {
|
|
88781
|
+
if (verdict.kind === "pass") {
|
|
88782
|
+
if (verdict.reviewed) {
|
|
88783
|
+
logger?.info("review", "Fix review passed", { storyId, reason: verdict.reason });
|
|
88784
|
+
} else {
|
|
88785
|
+
logger?.info("review", `Fix review skipped \u2014 ${verdict.reason}`, { storyId });
|
|
88786
|
+
}
|
|
88787
|
+
return;
|
|
88788
|
+
}
|
|
88789
|
+
if (verdict.kind === "error") {
|
|
88790
|
+
logger?.warn("review", "Fix review errored", { storyId, reason: verdict.reason });
|
|
88791
|
+
return;
|
|
88792
|
+
}
|
|
88793
|
+
if (verdict.cause === "scope") {
|
|
88794
|
+
logger?.info("review", "Fix review failed (scope)", { storyId, files: verdict.files, reason: verdict.reason });
|
|
88795
|
+
return;
|
|
88796
|
+
}
|
|
88797
|
+
logger?.info("review", "Fix review failed (contradiction)", {
|
|
88798
|
+
storyId,
|
|
88799
|
+
reason: verdict.reason,
|
|
88800
|
+
acIndex: verdict.acIndex,
|
|
88801
|
+
file: verdict.file
|
|
88802
|
+
});
|
|
88803
|
+
}
|
|
88804
|
+
async function evaluateFixReview(ctx, req, d) {
|
|
88445
88805
|
const logger = ctx.runtime?.logger;
|
|
88446
88806
|
if (req.config.fixReview?.enabled === false) {
|
|
88447
88807
|
return { kind: "pass", reviewed: false, reason: "fixReview is disabled" };
|
|
@@ -88517,6 +88877,11 @@ async function runFixReview(ctx, req, deps = {}) {
|
|
|
88517
88877
|
return { kind: "error", reason: `diff failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
88518
88878
|
}
|
|
88519
88879
|
const diff = truncateDiff(rawDiff);
|
|
88880
|
+
logger?.info("review", "Running fix review", {
|
|
88881
|
+
storyId: req.story.id,
|
|
88882
|
+
fixFiles: fixFiles.length,
|
|
88883
|
+
storyFiles: storyFiles?.length
|
|
88884
|
+
});
|
|
88520
88885
|
let output;
|
|
88521
88886
|
try {
|
|
88522
88887
|
output = await d.callOp(ctx, fixReviewOp, { story: req.story, diff, findings: req.findings });
|
|
@@ -88720,6 +89085,8 @@ function logUnifiedReviewPhaseResult(storyId, opName, output) {
|
|
|
88720
89085
|
const payload = toReviewDecisionPayload(opName, output);
|
|
88721
89086
|
if (!payload)
|
|
88722
89087
|
return;
|
|
89088
|
+
if (payload.reviewer === "fix")
|
|
89089
|
+
return;
|
|
88723
89090
|
if (!payload.parsed) {
|
|
88724
89091
|
if (payload.noDispatch) {
|
|
88725
89092
|
logger?.warn("review", `${payload.reviewer} review had no dispatch \u2014 failed closed`, { storyId });
|
|
@@ -88731,7 +89098,7 @@ function logUnifiedReviewPhaseResult(storyId, opName, output) {
|
|
|
88731
89098
|
return;
|
|
88732
89099
|
}
|
|
88733
89100
|
const findingsCount = payload.result.findings.length;
|
|
88734
|
-
const title = payload.reviewer === "semantic" ? "Semantic review" :
|
|
89101
|
+
const title = payload.reviewer === "semantic" ? "Semantic review" : "Adversarial review";
|
|
88735
89102
|
if (payload.passed) {
|
|
88736
89103
|
logger?.info("review", `${title} passed`, { storyId });
|
|
88737
89104
|
return;
|
|
@@ -91782,8 +92149,8 @@ var init_ensure_package_dirs = __esm(() => {
|
|
|
91782
92149
|
}
|
|
91783
92150
|
},
|
|
91784
92151
|
mkdirp: async (p) => {
|
|
91785
|
-
const { mkdir:
|
|
91786
|
-
await
|
|
92152
|
+
const { mkdir: mkdir25 } = await import("fs/promises");
|
|
92153
|
+
await mkdir25(p, { recursive: true });
|
|
91787
92154
|
}
|
|
91788
92155
|
};
|
|
91789
92156
|
});
|
|
@@ -91940,7 +92307,7 @@ var init_quote_integrity = __esm(() => {
|
|
|
91940
92307
|
});
|
|
91941
92308
|
|
|
91942
92309
|
// src/execution/progress.ts
|
|
91943
|
-
import { appendFile as appendFile5, mkdir as
|
|
92310
|
+
import { appendFile as appendFile5, mkdir as mkdir25 } from "fs/promises";
|
|
91944
92311
|
import { join as join86 } from "path";
|
|
91945
92312
|
function getSafeLogger2() {
|
|
91946
92313
|
try {
|
|
@@ -91951,7 +92318,7 @@ function getSafeLogger2() {
|
|
|
91951
92318
|
}
|
|
91952
92319
|
async function appendProgress(featureDir2, storyId, status, message) {
|
|
91953
92320
|
try {
|
|
91954
|
-
await
|
|
92321
|
+
await mkdir25(featureDir2, { recursive: true });
|
|
91955
92322
|
const progressPath = join86(featureDir2, "progress.txt");
|
|
91956
92323
|
const timestamp = new Date().toISOString();
|
|
91957
92324
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
@@ -92527,7 +92894,7 @@ var init_lock2 = __esm(() => {
|
|
|
92527
92894
|
});
|
|
92528
92895
|
|
|
92529
92896
|
// src/execution/feature-lock.ts
|
|
92530
|
-
import { mkdir as
|
|
92897
|
+
import { mkdir as mkdir26, rename as rename6, unlink as unlink6 } from "fs/promises";
|
|
92531
92898
|
import { hostname as hostname4 } from "os";
|
|
92532
92899
|
import path14 from "path";
|
|
92533
92900
|
function validateFeatureId2(featureId) {
|
|
@@ -92621,7 +92988,7 @@ function emptyHolder(feature) {
|
|
|
92621
92988
|
async function acquireFeatureLock(args) {
|
|
92622
92989
|
const lockPath = _featureLockDeps.featureLockPath(args.outputDir, args.feature);
|
|
92623
92990
|
const featureDir2 = path14.dirname(lockPath);
|
|
92624
|
-
await
|
|
92991
|
+
await mkdir26(featureDir2, { recursive: true });
|
|
92625
92992
|
const lockFile = Bun.file(lockPath);
|
|
92626
92993
|
if (await lockFile.exists()) {
|
|
92627
92994
|
const existingContent = await lockFile.text();
|
|
@@ -93183,7 +93550,7 @@ var init_worktree_id = __esm(() => {
|
|
|
93183
93550
|
|
|
93184
93551
|
// src/worktree/manager.ts
|
|
93185
93552
|
import { existsSync as existsSync23, symlinkSync } from "fs";
|
|
93186
|
-
import { mkdir as
|
|
93553
|
+
import { mkdir as mkdir27, stat as stat7 } from "fs/promises";
|
|
93187
93554
|
import { join as join89, resolve as resolve30 } from "path";
|
|
93188
93555
|
async function resolveGitInfoDir(projectRoot) {
|
|
93189
93556
|
const dotGit = join89(projectRoot, ".git");
|
|
@@ -93218,7 +93585,7 @@ class WorktreeManager {
|
|
|
93218
93585
|
try {
|
|
93219
93586
|
const infoDir = await resolveGitInfoDir(projectRoot);
|
|
93220
93587
|
const excludePath = join89(infoDir, "exclude");
|
|
93221
|
-
await
|
|
93588
|
+
await mkdir27(infoDir, { recursive: true });
|
|
93222
93589
|
const { withPathFileLock: withPathFileLock2 } = await Promise.resolve().then(() => (init_path_file_lock(), exports_path_file_lock));
|
|
93223
93590
|
await withPathFileLock2(excludePath, async () => {
|
|
93224
93591
|
let existing2 = "";
|
|
@@ -93832,6 +94199,54 @@ function areAllStoriesComplete(ctx) {
|
|
|
93832
94199
|
const totalComplete = counts.passed + counts.failed + counts.skipped;
|
|
93833
94200
|
return totalComplete === counts.total;
|
|
93834
94201
|
}
|
|
94202
|
+
function recordPackageCrash(params) {
|
|
94203
|
+
const {
|
|
94204
|
+
logger,
|
|
94205
|
+
storyId,
|
|
94206
|
+
exitCode,
|
|
94207
|
+
packageDir,
|
|
94208
|
+
testPath,
|
|
94209
|
+
testFramework,
|
|
94210
|
+
commandOverride,
|
|
94211
|
+
testCmd,
|
|
94212
|
+
output,
|
|
94213
|
+
allFailedACs,
|
|
94214
|
+
allFindings,
|
|
94215
|
+
failedPackages,
|
|
94216
|
+
errorState
|
|
94217
|
+
} = params;
|
|
94218
|
+
const notRunnable = isCommandNotRunnable(exitCode);
|
|
94219
|
+
if (notRunnable) {
|
|
94220
|
+
logger.error("acceptance", "Acceptance command could not run \u2014 check acceptance.command", {
|
|
94221
|
+
storyId,
|
|
94222
|
+
exitCode,
|
|
94223
|
+
cmd: testCmd,
|
|
94224
|
+
packageDir
|
|
94225
|
+
});
|
|
94226
|
+
} else {
|
|
94227
|
+
logger.error("acceptance", "Tests errored with no AC failures parsed", {
|
|
94228
|
+
storyId,
|
|
94229
|
+
exitCode,
|
|
94230
|
+
packageDir
|
|
94231
|
+
});
|
|
94232
|
+
}
|
|
94233
|
+
logTestOutput(logger, "acceptance", output);
|
|
94234
|
+
errorState.anyError = true;
|
|
94235
|
+
errorState.errorExitCode = exitCode;
|
|
94236
|
+
allFailedACs.push("AC-ERROR");
|
|
94237
|
+
allFindings.push(notRunnable ? {
|
|
94238
|
+
...acSentinelToFinding("AC-ERROR", output),
|
|
94239
|
+
message: `Acceptance command could not run (exit ${exitCode}): ${testCmd}`
|
|
94240
|
+
} : acSentinelToFinding("AC-ERROR", output));
|
|
94241
|
+
failedPackages.push({
|
|
94242
|
+
testPath,
|
|
94243
|
+
packageDir,
|
|
94244
|
+
testFramework,
|
|
94245
|
+
commandOverride,
|
|
94246
|
+
output,
|
|
94247
|
+
failedACs: ["AC-ERROR"]
|
|
94248
|
+
});
|
|
94249
|
+
}
|
|
93835
94250
|
var _acceptanceStageDeps, acceptanceStage;
|
|
93836
94251
|
var init_acceptance3 = __esm(() => {
|
|
93837
94252
|
init_acceptance2();
|
|
@@ -93888,8 +94303,7 @@ var init_acceptance3 = __esm(() => {
|
|
|
93888
94303
|
const failedPackages = [];
|
|
93889
94304
|
const missingTargets = [];
|
|
93890
94305
|
const allOutputParts = [];
|
|
93891
|
-
|
|
93892
|
-
let errorExitCode = 0;
|
|
94306
|
+
const errorState = { anyError: false, errorExitCode: 0 };
|
|
93893
94307
|
let hardeningPromoted = 0;
|
|
93894
94308
|
for (const { testPath, packageDir, testFramework, commandOverride, storyCount, acceptanceEnabled } of testGroups) {
|
|
93895
94309
|
const testFile = Bun.file(testPath);
|
|
@@ -93929,13 +94343,13 @@ var init_acceptance3 = __esm(() => {
|
|
|
93929
94343
|
}
|
|
93930
94344
|
const resolvedFramework = testFramework ?? ctx.config.project?.testFramework;
|
|
93931
94345
|
const resolvedCommand = commandOverride ?? ctx.config.acceptance.command;
|
|
93932
|
-
const
|
|
94346
|
+
const testCmd = buildAcceptanceRunCommand(testPath, resolvedFramework, resolvedCommand, packageDir);
|
|
93933
94347
|
logger.info("acceptance", "Running acceptance command", {
|
|
93934
94348
|
storyId: ctx.story.id,
|
|
93935
|
-
cmd:
|
|
94349
|
+
cmd: testCmd,
|
|
93936
94350
|
packageDir
|
|
93937
94351
|
});
|
|
93938
|
-
const execution = await executeWithTimeout(
|
|
94352
|
+
const execution = await executeWithTimeout(testCmd, Math.ceil(ctx.config.acceptance.timeoutMs / 1000), undefined, { cwd: packageDir });
|
|
93939
94353
|
const exitCode = execution.exitCode ?? (execution.success ? 0 : 1);
|
|
93940
94354
|
const output = execution.output ?? "";
|
|
93941
94355
|
allOutputParts.push(output);
|
|
@@ -93951,17 +94365,21 @@ var init_acceptance3 = __esm(() => {
|
|
|
93951
94365
|
});
|
|
93952
94366
|
}
|
|
93953
94367
|
if (failedACs.length === 0 && exitCode !== 0) {
|
|
93954
|
-
|
|
94368
|
+
recordPackageCrash({
|
|
94369
|
+
logger,
|
|
93955
94370
|
storyId: ctx.story.id,
|
|
93956
94371
|
exitCode,
|
|
93957
|
-
packageDir
|
|
94372
|
+
packageDir,
|
|
94373
|
+
testPath,
|
|
94374
|
+
testFramework,
|
|
94375
|
+
commandOverride,
|
|
94376
|
+
testCmd,
|
|
94377
|
+
output,
|
|
94378
|
+
allFailedACs,
|
|
94379
|
+
allFindings,
|
|
94380
|
+
failedPackages,
|
|
94381
|
+
errorState
|
|
93958
94382
|
});
|
|
93959
|
-
logTestOutput(logger, "acceptance", output);
|
|
93960
|
-
anyError = true;
|
|
93961
|
-
errorExitCode = exitCode;
|
|
93962
|
-
allFailedACs.push("AC-ERROR");
|
|
93963
|
-
allFindings.push(acSentinelToFinding("AC-ERROR", output));
|
|
93964
|
-
failedPackages.push({ testPath, packageDir, testFramework, commandOverride, output, failedACs: ["AC-ERROR"] });
|
|
93965
94383
|
continue;
|
|
93966
94384
|
}
|
|
93967
94385
|
if (exitCode !== 0 && failedACs.length > 0 && actualFailures.length === 0) {
|
|
@@ -93976,8 +94394,8 @@ var init_acceptance3 = __esm(() => {
|
|
|
93976
94394
|
acTaggedFailures: taggedFailureCount
|
|
93977
94395
|
});
|
|
93978
94396
|
logTestOutput(logger, "acceptance", output);
|
|
93979
|
-
anyError = true;
|
|
93980
|
-
errorExitCode = exitCode;
|
|
94397
|
+
errorState.anyError = true;
|
|
94398
|
+
errorState.errorExitCode = exitCode;
|
|
93981
94399
|
allFailedACs.push("AC-ERROR");
|
|
93982
94400
|
allFindings.push(acSentinelToFinding("AC-ERROR", output));
|
|
93983
94401
|
failedPackages.push({
|
|
@@ -94097,10 +94515,10 @@ var init_acceptance3 = __esm(() => {
|
|
|
94097
94515
|
hardeningPromoted,
|
|
94098
94516
|
durationMs
|
|
94099
94517
|
});
|
|
94100
|
-
if (anyError) {
|
|
94518
|
+
if (errorState.anyError) {
|
|
94101
94519
|
return {
|
|
94102
94520
|
action: "fail",
|
|
94103
|
-
reason: `Acceptance tests errored (exit code ${errorExitCode}): syntax error, import failure, or unhandled exception`
|
|
94521
|
+
reason: `Acceptance tests errored (exit code ${errorState.errorExitCode}): syntax error, import failure, or unhandled exception`
|
|
94104
94522
|
};
|
|
94105
94523
|
}
|
|
94106
94524
|
return {
|
|
@@ -94165,12 +94583,21 @@ async function runAcceptanceRedGate(ctx, entries, deps) {
|
|
|
94165
94583
|
const runCmd = buildAcceptanceRunCommand(testPath, testFramework, commandOverride, packageDir);
|
|
94166
94584
|
logger?.info("acceptance-setup", "Running acceptance RED gate command", {
|
|
94167
94585
|
storyId: entry.storyId,
|
|
94168
|
-
cmd: runCmd
|
|
94586
|
+
cmd: runCmd,
|
|
94169
94587
|
packageDir
|
|
94170
94588
|
});
|
|
94171
94589
|
const first = await deps.runTest(testPath, packageDir, runCmd, config2.acceptance.timeoutMs);
|
|
94172
94590
|
if (first.exitCode === 0)
|
|
94173
94591
|
continue;
|
|
94592
|
+
if (isCommandNotRunnable(first.exitCode)) {
|
|
94593
|
+
logger?.error("acceptance-setup", "RED gate: acceptance command could not run \u2014 check acceptance.command", {
|
|
94594
|
+
storyId: entry.storyId,
|
|
94595
|
+
cmd: runCmd,
|
|
94596
|
+
exitCode: first.exitCode
|
|
94597
|
+
});
|
|
94598
|
+
redFailCount++;
|
|
94599
|
+
continue;
|
|
94600
|
+
}
|
|
94174
94601
|
if (isCrash(first.output, first.exitCode)) {
|
|
94175
94602
|
await handleCrash(ctx, entry, first.output, runCmd, deps);
|
|
94176
94603
|
}
|
|
@@ -94533,7 +94960,7 @@ var init_acceptance_setup = __esm(() => {
|
|
|
94533
94960
|
autoCommitIfDirty,
|
|
94534
94961
|
loadGroupConfig: loadConfigForPackage,
|
|
94535
94962
|
runTest: async (_testPath, _workdir, _cmd, timeoutMs = 1800000) => {
|
|
94536
|
-
const execution = await executeWithTimeout(_cmd
|
|
94963
|
+
const execution = await executeWithTimeout(_cmd, Math.ceil(timeoutMs / 1000), undefined, {
|
|
94537
94964
|
cwd: _workdir
|
|
94538
94965
|
});
|
|
94539
94966
|
return {
|
|
@@ -96101,11 +96528,11 @@ async function closeStaleAcpSession(worktreePath, sessionName) {
|
|
|
96101
96528
|
});
|
|
96102
96529
|
let timedOut = false;
|
|
96103
96530
|
await new Promise((resolve31) => {
|
|
96104
|
-
let
|
|
96531
|
+
let settled2 = false;
|
|
96105
96532
|
const finish = () => {
|
|
96106
|
-
if (
|
|
96533
|
+
if (settled2)
|
|
96107
96534
|
return;
|
|
96108
|
-
|
|
96535
|
+
settled2 = true;
|
|
96109
96536
|
clearTimeout(timer);
|
|
96110
96537
|
resolve31();
|
|
96111
96538
|
};
|
|
@@ -102107,11 +102534,11 @@ function renderProposals(proposals, runId, observationCount, provenance) {
|
|
|
102107
102534
|
}
|
|
102108
102535
|
|
|
102109
102536
|
// src/plugins/builtin/curator/rollup.ts
|
|
102110
|
-
import { appendFile as appendFile7, mkdir as
|
|
102537
|
+
import { appendFile as appendFile7, mkdir as mkdir28, writeFile as writeFile11 } from "fs/promises";
|
|
102111
102538
|
import * as path21 from "path";
|
|
102112
102539
|
async function appendToRollup(observations, rollupPath) {
|
|
102113
102540
|
const dir = path21.dirname(rollupPath);
|
|
102114
|
-
await
|
|
102541
|
+
await mkdir28(dir, { recursive: true }).catch(() => {});
|
|
102115
102542
|
const { withPathFileLock: withPathFileLock2 } = await Promise.resolve().then(() => (init_path_file_lock(), exports_path_file_lock));
|
|
102116
102543
|
await withPathFileLock2(rollupPath, () => appendToRollupUnlocked(observations, rollupPath)).catch(() => {});
|
|
102117
102544
|
}
|
|
@@ -102198,7 +102625,7 @@ var init_rollup2 = __esm(() => {
|
|
|
102198
102625
|
});
|
|
102199
102626
|
|
|
102200
102627
|
// src/plugins/builtin/curator/index.ts
|
|
102201
|
-
import { mkdir as
|
|
102628
|
+
import { mkdir as mkdir29 } from "fs/promises";
|
|
102202
102629
|
import * as path22 from "path";
|
|
102203
102630
|
function getCuratorEnabled(context) {
|
|
102204
102631
|
const cfg = context.config;
|
|
@@ -102276,7 +102703,7 @@ var init_curator = __esm(() => {
|
|
|
102276
102703
|
if (context.outputDir) {
|
|
102277
102704
|
const { observationsPath, rollupPath } = resolveCuratorOutputs(curatorContext);
|
|
102278
102705
|
const runDir = path22.dirname(observationsPath);
|
|
102279
|
-
await
|
|
102706
|
+
await mkdir29(runDir, { recursive: true });
|
|
102280
102707
|
await Bun.write(observationsPath, observations.map((o) => JSON.stringify(o)).join(`
|
|
102281
102708
|
`) + (observations.length > 0 ? `
|
|
102282
102709
|
` : ""));
|
|
@@ -102364,10 +102791,52 @@ var init_plugin_logger = __esm(() => {
|
|
|
102364
102791
|
});
|
|
102365
102792
|
|
|
102366
102793
|
// src/plugins/registry.ts
|
|
102794
|
+
function warnPluginRegistration(pluginName, message, data) {
|
|
102795
|
+
getSafeLogger()?.warn("plugins", `Plugin '${pluginName}' ${message}`, { plugin: pluginName, ...data });
|
|
102796
|
+
}
|
|
102797
|
+
function stagePluginHandlers(pluginName, provider2) {
|
|
102798
|
+
const staged = [];
|
|
102799
|
+
let failed = false;
|
|
102800
|
+
const on = (event, handler) => {
|
|
102801
|
+
if (!LOOP_EVENT_NAMES.has(event)) {
|
|
102802
|
+
failed = true;
|
|
102803
|
+
warnPluginRegistration(pluginName, `registered a handler for unknown loop event '${event}'`, { event });
|
|
102804
|
+
return;
|
|
102805
|
+
}
|
|
102806
|
+
if (typeof handler !== "function") {
|
|
102807
|
+
failed = true;
|
|
102808
|
+
warnPluginRegistration(pluginName, `registered a non-function handler for '${event}'`, {
|
|
102809
|
+
event,
|
|
102810
|
+
handlerType: typeof handler
|
|
102811
|
+
});
|
|
102812
|
+
return;
|
|
102813
|
+
}
|
|
102814
|
+
staged.push({ plugin: pluginName, event, handler });
|
|
102815
|
+
};
|
|
102816
|
+
let returned;
|
|
102817
|
+
try {
|
|
102818
|
+
returned = provider2.register(on);
|
|
102819
|
+
} catch (err) {
|
|
102820
|
+
failed = true;
|
|
102821
|
+
warnPluginRegistration(pluginName, "loop-handler registration failed; its handlers are skipped", {
|
|
102822
|
+
error: errorMessage(err)
|
|
102823
|
+
});
|
|
102824
|
+
}
|
|
102825
|
+
if (isThenable(returned)) {
|
|
102826
|
+
failed = true;
|
|
102827
|
+
warnPluginRegistration(pluginName, "register() returned a promise; loop-handler registration must be synchronous");
|
|
102828
|
+
returned.then(undefined, (err) => {
|
|
102829
|
+
warnPluginRegistration(pluginName, "async register() rejected", { error: errorMessage(err) });
|
|
102830
|
+
});
|
|
102831
|
+
}
|
|
102832
|
+
return failed ? [] : staged;
|
|
102833
|
+
}
|
|
102834
|
+
|
|
102367
102835
|
class PluginRegistry {
|
|
102368
102836
|
plugins;
|
|
102369
102837
|
sources;
|
|
102370
102838
|
builtinPostRunActions;
|
|
102839
|
+
loopHandlers;
|
|
102371
102840
|
constructor(loadedPlugins, builtinPostRunActions = []) {
|
|
102372
102841
|
this.builtinPostRunActions = builtinPostRunActions.map((registration) => ("action" in registration) ? registration : { pluginName: registration.name, action: registration });
|
|
102373
102842
|
if (loadedPlugins.length > 0 && "plugin" in loadedPlugins[0]) {
|
|
@@ -102417,6 +102886,25 @@ class PluginRegistry {
|
|
|
102417
102886
|
});
|
|
102418
102887
|
return [...pluginActions, ...this.builtinPostRunActions];
|
|
102419
102888
|
}
|
|
102889
|
+
getLoopHandlers() {
|
|
102890
|
+
if (this.loopHandlers !== undefined) {
|
|
102891
|
+
return this.loopHandlers;
|
|
102892
|
+
}
|
|
102893
|
+
const entries = [];
|
|
102894
|
+
for (const plugin of this.plugins) {
|
|
102895
|
+
if (!plugin.provides.includes("loop-handlers")) {
|
|
102896
|
+
continue;
|
|
102897
|
+
}
|
|
102898
|
+
const provider2 = plugin.extensions.loopHandlers;
|
|
102899
|
+
if (provider2 === undefined) {
|
|
102900
|
+
warnPluginRegistration(plugin.name, "provides 'loop-handlers' but declares no loopHandlers extension");
|
|
102901
|
+
continue;
|
|
102902
|
+
}
|
|
102903
|
+
entries.push(...stagePluginHandlers(plugin.name, provider2));
|
|
102904
|
+
}
|
|
102905
|
+
this.loopHandlers = Object.freeze(entries);
|
|
102906
|
+
return this.loopHandlers;
|
|
102907
|
+
}
|
|
102420
102908
|
async teardownAll() {
|
|
102421
102909
|
const logger = getSafeLogger();
|
|
102422
102910
|
for (const plugin of this.plugins) {
|
|
@@ -102430,8 +102918,11 @@ class PluginRegistry {
|
|
|
102430
102918
|
}
|
|
102431
102919
|
}
|
|
102432
102920
|
}
|
|
102921
|
+
var LOOP_EVENT_NAMES;
|
|
102433
102922
|
var init_registry5 = __esm(() => {
|
|
102923
|
+
init_loop_events();
|
|
102434
102924
|
init_logger2();
|
|
102925
|
+
LOOP_EVENT_NAMES = new Set(LOOP_EVENTS);
|
|
102435
102926
|
});
|
|
102436
102927
|
|
|
102437
102928
|
// src/plugins/validator.ts
|
|
@@ -102507,6 +102998,8 @@ function validateExtension(pluginName, type, extensions) {
|
|
|
102507
102998
|
return validateReporter(pluginName, extensions.reporter);
|
|
102508
102999
|
case "post-run-action":
|
|
102509
103000
|
return validatePostRunAction(pluginName, extensions.postRunAction);
|
|
103001
|
+
case "loop-handlers":
|
|
103002
|
+
return validateLoopHandlers(pluginName, extensions.loopHandlers);
|
|
102510
103003
|
default:
|
|
102511
103004
|
getSafeLogger6()?.warn("plugins", `Plugin '${pluginName}' validation failed: unknown extension type '${type}'`);
|
|
102512
103005
|
return false;
|
|
@@ -102680,6 +103173,17 @@ function validatePostRunAction(pluginName, action) {
|
|
|
102680
103173
|
}
|
|
102681
103174
|
return true;
|
|
102682
103175
|
}
|
|
103176
|
+
function validateLoopHandlers(pluginName, ext) {
|
|
103177
|
+
if (typeof ext !== "object" || ext === null) {
|
|
103178
|
+
getSafeLogger6()?.warn("plugins", `Plugin '${pluginName}' validation failed: loopHandlers extension must be an object`);
|
|
103179
|
+
return false;
|
|
103180
|
+
}
|
|
103181
|
+
if (typeof ext.register !== "function") {
|
|
103182
|
+
getSafeLogger6()?.warn("plugins", `Plugin '${pluginName}' validation failed: loopHandlers.register must be a function`);
|
|
103183
|
+
return false;
|
|
103184
|
+
}
|
|
103185
|
+
return true;
|
|
103186
|
+
}
|
|
102683
103187
|
var VALID_PLUGIN_TYPES;
|
|
102684
103188
|
var init_validator = __esm(() => {
|
|
102685
103189
|
init_logger2();
|
|
@@ -102690,7 +103194,8 @@ var init_validator = __esm(() => {
|
|
|
102690
103194
|
"reviewer",
|
|
102691
103195
|
"context-provider",
|
|
102692
103196
|
"reporter",
|
|
102693
|
-
"post-run-action"
|
|
103197
|
+
"post-run-action",
|
|
103198
|
+
"loop-handlers"
|
|
102694
103199
|
];
|
|
102695
103200
|
});
|
|
102696
103201
|
|
|
@@ -103846,6 +104351,7 @@ async function initializeAfterLock(options) {
|
|
|
103846
104351
|
const resolvedPatterns = await resolveTestFilePatterns(config2, workdir);
|
|
103847
104352
|
const isTestFileFn = (filename) => resolvedPatterns.regex.some((re) => re.test(filename));
|
|
103848
104353
|
const pluginRegistry = await loadPlugins(globalPluginsDir, projectPluginsDir, configPlugins, workdir, config2.disabledPlugins, isTestFileFn, config2.reporters);
|
|
104354
|
+
runtime.sessionManager.configureLoopHandlers(pluginRegistry.getLoopHandlers());
|
|
103849
104355
|
logger?.info("plugins", `Loaded ${pluginRegistry.plugins.length} plugins`, {
|
|
103850
104356
|
plugins: pluginRegistry.plugins.map((p) => ({ name: p.name, version: p.version, provides: p.provides }))
|
|
103851
104357
|
});
|
|
@@ -104795,11 +105301,14 @@ var init_logs2 = __esm(() => {
|
|
|
104795
105301
|
// src/commands/migrate.ts
|
|
104796
105302
|
var exports_migrate = {};
|
|
104797
105303
|
__export(exports_migrate, {
|
|
105304
|
+
_gitDeps: () => _gitDeps,
|
|
105305
|
+
autoMigrateGeneratedContent: () => autoMigrateGeneratedContent,
|
|
104798
105306
|
detectGeneratedContent: () => detectGeneratedContent,
|
|
104799
|
-
migrateCommand: () => migrateCommand
|
|
105307
|
+
migrateCommand: () => migrateCommand,
|
|
105308
|
+
partitionTrackedCandidates: () => partitionTrackedCandidates
|
|
104800
105309
|
});
|
|
104801
105310
|
import { existsSync as existsSync30 } from "fs";
|
|
104802
|
-
import { mkdir as
|
|
105311
|
+
import { mkdir as mkdir30, readdir as readdir10, rename as rename9 } from "fs/promises";
|
|
104803
105312
|
import path25 from "path";
|
|
104804
105313
|
async function detectGeneratedContent(naxDir) {
|
|
104805
105314
|
if (!existsSync30(naxDir))
|
|
@@ -104868,6 +105377,102 @@ async function detectGeneratedContent(naxDir) {
|
|
|
104868
105377
|
}
|
|
104869
105378
|
return candidates;
|
|
104870
105379
|
}
|
|
105380
|
+
async function partitionTrackedCandidates(workdir, candidates) {
|
|
105381
|
+
const logger = getSafeLogger();
|
|
105382
|
+
let stdout;
|
|
105383
|
+
try {
|
|
105384
|
+
const result = await gitWithTimeout(["ls-files", "-z", "--", ".nax"], workdir);
|
|
105385
|
+
if (result.exitCode !== 0) {
|
|
105386
|
+
logger?.debug("migrate", "partitionTrackedCandidates: git ls-files returned non-zero, treating all candidates as migratable", {
|
|
105387
|
+
storyId: "_migrate",
|
|
105388
|
+
exitCode: result.exitCode,
|
|
105389
|
+
stderr: result.stderr.trim()
|
|
105390
|
+
});
|
|
105391
|
+
return { migratable: [...candidates], tracked: [] };
|
|
105392
|
+
}
|
|
105393
|
+
stdout = result.stdout;
|
|
105394
|
+
} catch (err) {
|
|
105395
|
+
logger?.debug("migrate", "partitionTrackedCandidates: git ls-files failed, treating all candidates as migratable", {
|
|
105396
|
+
storyId: "_migrate",
|
|
105397
|
+
error: err instanceof Error ? err.message : String(err)
|
|
105398
|
+
});
|
|
105399
|
+
return { migratable: [...candidates], tracked: [] };
|
|
105400
|
+
}
|
|
105401
|
+
const listedPaths = [];
|
|
105402
|
+
for (const listed of stdout.split("\x00")) {
|
|
105403
|
+
if (!listed || listed === ".nax")
|
|
105404
|
+
continue;
|
|
105405
|
+
if (listed.startsWith(".nax/"))
|
|
105406
|
+
listedPaths.push(listed);
|
|
105407
|
+
}
|
|
105408
|
+
const migratable = [];
|
|
105409
|
+
const trackedOut = [];
|
|
105410
|
+
for (const candidate of candidates) {
|
|
105411
|
+
const normalisedName = candidate.name.split("\\").join("/");
|
|
105412
|
+
const target = `.nax/${normalisedName}`;
|
|
105413
|
+
const targetWithSlash = `${target}/`;
|
|
105414
|
+
const isTracked = listedPaths.some((listed) => listed === target || listed.startsWith(targetWithSlash));
|
|
105415
|
+
if (isTracked) {
|
|
105416
|
+
trackedOut.push(candidate);
|
|
105417
|
+
} else {
|
|
105418
|
+
migratable.push(candidate);
|
|
105419
|
+
}
|
|
105420
|
+
}
|
|
105421
|
+
return { migratable, tracked: trackedOut };
|
|
105422
|
+
}
|
|
105423
|
+
async function autoMigrateGeneratedContent(workdir) {
|
|
105424
|
+
const logger = getSafeLogger();
|
|
105425
|
+
let candidates;
|
|
105426
|
+
try {
|
|
105427
|
+
candidates = await detectGeneratedContent(path25.join(workdir, ".nax"));
|
|
105428
|
+
} catch (err) {
|
|
105429
|
+
logger?.debug("migrate", "autoMigrateGeneratedContent: detectGeneratedContent failed, skipping migration", {
|
|
105430
|
+
storyId: "_setup",
|
|
105431
|
+
error: err instanceof Error ? err.message : String(err)
|
|
105432
|
+
});
|
|
105433
|
+
return;
|
|
105434
|
+
}
|
|
105435
|
+
if (candidates.length === 0)
|
|
105436
|
+
return;
|
|
105437
|
+
let partition;
|
|
105438
|
+
try {
|
|
105439
|
+
partition = await partitionTrackedCandidates(workdir, candidates);
|
|
105440
|
+
} catch (err) {
|
|
105441
|
+
logger?.debug("migrate", "autoMigrateGeneratedContent: partitionTrackedCandidates failed, treating all candidates as migratable", {
|
|
105442
|
+
storyId: "_setup",
|
|
105443
|
+
error: err instanceof Error ? err.message : String(err)
|
|
105444
|
+
});
|
|
105445
|
+
partition = { migratable: candidates, tracked: [] };
|
|
105446
|
+
}
|
|
105447
|
+
const { migratable, tracked } = partition;
|
|
105448
|
+
if (tracked.length > 0) {
|
|
105449
|
+
const paths = tracked.map((candidate) => path25.relative(workdir, candidate.srcPath)).slice(0, 5);
|
|
105450
|
+
const firstPath = paths[0];
|
|
105451
|
+
if (firstPath !== undefined) {
|
|
105452
|
+
logger?.warn("setup", "Skipping git-tracked generated content under .nax/ \u2014 untrack it with git rm -r --cached", {
|
|
105453
|
+
storyId: "_setup",
|
|
105454
|
+
count: tracked.length,
|
|
105455
|
+
paths,
|
|
105456
|
+
fix: `git rm -r --cached ${firstPath}`
|
|
105457
|
+
});
|
|
105458
|
+
}
|
|
105459
|
+
}
|
|
105460
|
+
if (migratable.length === 0)
|
|
105461
|
+
return;
|
|
105462
|
+
logger?.info("setup", "Found generated content under .nax/ \u2014 migrating to output dir", {
|
|
105463
|
+
storyId: "_setup",
|
|
105464
|
+
count: migratable.length
|
|
105465
|
+
});
|
|
105466
|
+
try {
|
|
105467
|
+
await migrateCommand({ workdir });
|
|
105468
|
+
logger?.info("setup", "Auto-migration complete", { storyId: "_setup" });
|
|
105469
|
+
} catch (err) {
|
|
105470
|
+
logger?.warn("setup", "Auto-migration failed \u2014 continuing without migration", {
|
|
105471
|
+
storyId: "_setup",
|
|
105472
|
+
error: err instanceof Error ? err.message : String(err)
|
|
105473
|
+
});
|
|
105474
|
+
}
|
|
105475
|
+
}
|
|
104871
105476
|
async function migrateCommand(options) {
|
|
104872
105477
|
const logger = getLogger();
|
|
104873
105478
|
if (options.reclaim) {
|
|
@@ -104887,7 +105492,7 @@ async function migrateCommand(options) {
|
|
|
104887
105492
|
}
|
|
104888
105493
|
const archiveBase = path25.join(globalConfigDir(), "_archive");
|
|
104889
105494
|
const archiveDest = path25.join(archiveBase, `${options.reclaim}-${Date.now()}`);
|
|
104890
|
-
await
|
|
105495
|
+
await mkdir30(archiveBase, { recursive: true });
|
|
104891
105496
|
await rename9(src, archiveDest);
|
|
104892
105497
|
logger.info("migrate", `Reclaimed: archived to ${archiveDest}`, { storyId: "_migrate" });
|
|
104893
105498
|
return;
|
|
@@ -104950,19 +105555,36 @@ async function migrateCommand(options) {
|
|
|
104950
105555
|
logger.info("migrate", "Nothing to migrate \u2014 already up to date", { storyId: "_migrate" });
|
|
104951
105556
|
return;
|
|
104952
105557
|
}
|
|
105558
|
+
const { migratable, tracked } = await partitionTrackedCandidates(options.workdir, candidates);
|
|
105559
|
+
if (migratable.length === 0) {
|
|
105560
|
+
for (const c of tracked) {
|
|
105561
|
+
const rel = path25.relative(options.workdir, c.srcPath);
|
|
105562
|
+
const msg = options.dryRun ? `[dry-run] Skip (git-tracked): ${rel}` : `Skipping git-tracked: ${rel}`;
|
|
105563
|
+
logger.info("migrate", msg, { storyId: "_migrate" });
|
|
105564
|
+
}
|
|
105565
|
+
return;
|
|
105566
|
+
}
|
|
104953
105567
|
if (options.dryRun) {
|
|
104954
|
-
for (const c of
|
|
105568
|
+
for (const c of tracked) {
|
|
105569
|
+
const rel = path25.relative(options.workdir, c.srcPath);
|
|
105570
|
+
logger.info("migrate", `[dry-run] Skip (git-tracked): ${rel}`, { storyId: "_migrate" });
|
|
105571
|
+
}
|
|
105572
|
+
for (const c of migratable) {
|
|
104955
105573
|
logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path25.join(destBase, c.name)}`, {
|
|
104956
105574
|
storyId: "_migrate"
|
|
104957
105575
|
});
|
|
104958
105576
|
}
|
|
104959
105577
|
return;
|
|
104960
105578
|
}
|
|
104961
|
-
|
|
105579
|
+
for (const c of tracked) {
|
|
105580
|
+
const rel = path25.relative(options.workdir, c.srcPath);
|
|
105581
|
+
logger.info("migrate", `Skipping git-tracked: ${rel}`, { storyId: "_migrate" });
|
|
105582
|
+
}
|
|
105583
|
+
await mkdir30(destBase, { recursive: true });
|
|
104962
105584
|
let moved = 0;
|
|
104963
|
-
for (const candidate of
|
|
105585
|
+
for (const candidate of migratable) {
|
|
104964
105586
|
const dest = path25.join(destBase, candidate.name);
|
|
104965
|
-
await
|
|
105587
|
+
await mkdir30(path25.dirname(dest), { recursive: true });
|
|
104966
105588
|
if (existsSync30(dest)) {
|
|
104967
105589
|
throw new NaxError(`Migration conflict: destination already exists.
|
|
104968
105590
|
Source: ${candidate.srcPath}
|
|
@@ -104992,11 +105614,13 @@ async function migrateCommand(options) {
|
|
|
104992
105614
|
moved++;
|
|
104993
105615
|
logger.info("migrate", `Moved: ${candidate.name}`, { storyId: "_migrate" });
|
|
104994
105616
|
}
|
|
104995
|
-
|
|
104996
|
-
|
|
104997
|
-
|
|
104998
|
-
|
|
104999
|
-
|
|
105617
|
+
if (moved > 0) {
|
|
105618
|
+
await Bun.write(path25.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
|
|
105619
|
+
logger.info("migrate", `Migration complete: ${moved} entries moved`, {
|
|
105620
|
+
storyId: "_migrate",
|
|
105621
|
+
destBase
|
|
105622
|
+
});
|
|
105623
|
+
}
|
|
105000
105624
|
}
|
|
105001
105625
|
var GENERATED_NAMES, GENERATED_FEATURE_SUBNAMES;
|
|
105002
105626
|
var init_migrate = __esm(() => {
|
|
@@ -105005,7 +105629,9 @@ var init_migrate = __esm(() => {
|
|
|
105005
105629
|
init_errors();
|
|
105006
105630
|
init_logger2();
|
|
105007
105631
|
init_runtime2();
|
|
105632
|
+
init_git();
|
|
105008
105633
|
init_git_env();
|
|
105634
|
+
init_git();
|
|
105009
105635
|
GENERATED_NAMES = new Set([
|
|
105010
105636
|
"runs",
|
|
105011
105637
|
"prompt-audit",
|
|
@@ -105780,7 +106406,7 @@ var init_runs = __esm(() => {
|
|
|
105780
106406
|
});
|
|
105781
106407
|
|
|
105782
106408
|
// src/commands/unlock.ts
|
|
105783
|
-
import { mkdir as
|
|
106409
|
+
import { mkdir as mkdir31, unlink as unlink10 } from "fs/promises";
|
|
105784
106410
|
import { basename as basename14, join as join112 } from "path";
|
|
105785
106411
|
function logUnlockInfo(message) {
|
|
105786
106412
|
_unlockDeps.getSafeLogger()?.info(UNLOCK_LOG_STAGE, message);
|
|
@@ -105855,7 +106481,7 @@ async function unlockCommand(options) {
|
|
|
105855
106481
|
const workdir = options.dir ?? process.cwd();
|
|
105856
106482
|
if (options.feature !== undefined && options.feature.length > 0) {
|
|
105857
106483
|
const { outputDir } = await resolveOutputDir(workdir);
|
|
105858
|
-
await
|
|
106484
|
+
await mkdir31(join112(outputDir, "features"), { recursive: true });
|
|
105859
106485
|
const outcome = await tryRemoveFeatureLock(outputDir, options.feature, options.force ?? false);
|
|
105860
106486
|
if (outcome === "skipped" || outcome === "parse-error") {
|
|
105861
106487
|
process.exit(1);
|
|
@@ -105965,6 +106591,7 @@ __export(exports_commands, {
|
|
|
105965
106591
|
_curatorCmdDeps: () => _curatorCmdDeps,
|
|
105966
106592
|
_replayCmdDeps: () => _replayCmdDeps,
|
|
105967
106593
|
_resumeCmdDeps: () => _resumeCmdDeps,
|
|
106594
|
+
autoMigrateGeneratedContent: () => autoMigrateGeneratedContent,
|
|
105968
106595
|
curatorCommit: () => curatorCommit,
|
|
105969
106596
|
curatorDryrun: () => curatorDryrun,
|
|
105970
106597
|
curatorGc: () => curatorGc,
|
|
@@ -105973,6 +106600,7 @@ __export(exports_commands, {
|
|
|
105973
106600
|
followLogs: () => followLogs,
|
|
105974
106601
|
logsCommand: () => logsCommand,
|
|
105975
106602
|
migrateCommand: () => migrateCommand,
|
|
106603
|
+
partitionTrackedCandidates: () => partitionTrackedCandidates,
|
|
105976
106604
|
precheckCommand: () => precheckCommand,
|
|
105977
106605
|
registerReplayCommand: () => registerReplayCommand,
|
|
105978
106606
|
registerResumeCommand: () => registerResumeCommand,
|
|
@@ -106310,26 +106938,7 @@ async function setupRun(options) {
|
|
|
106310
106938
|
const prd = await loadPRD(prdPath);
|
|
106311
106939
|
const interactionChain = await initInteractionChain(config2, headless);
|
|
106312
106940
|
statusWriter.setPrd(prd);
|
|
106313
|
-
|
|
106314
|
-
const { detectGeneratedContent: detectGeneratedContent2, migrateCommand: migrateCommand2 } = await Promise.resolve().then(() => (init_commands(), exports_commands));
|
|
106315
|
-
const naxDir = path27.join(workdir, ".nax");
|
|
106316
|
-
const candidates = await detectGeneratedContent2(naxDir).catch(() => []);
|
|
106317
|
-
if (candidates.length > 0) {
|
|
106318
|
-
logger?.info("setup", "Found generated content under .nax/ \u2014 migrating to output dir", {
|
|
106319
|
-
storyId: "_setup",
|
|
106320
|
-
count: candidates.length
|
|
106321
|
-
});
|
|
106322
|
-
try {
|
|
106323
|
-
await migrateCommand2({ workdir });
|
|
106324
|
-
logger?.info("setup", "Auto-migration complete", { storyId: "_setup" });
|
|
106325
|
-
} catch (err) {
|
|
106326
|
-
logger?.warn("setup", "Auto-migration failed \u2014 continuing without migration", {
|
|
106327
|
-
storyId: "_setup",
|
|
106328
|
-
error: err instanceof Error ? err.message : String(err)
|
|
106329
|
-
});
|
|
106330
|
-
}
|
|
106331
|
-
}
|
|
106332
|
-
}
|
|
106941
|
+
await _runSetupDeps.autoMigrateGeneratedContent(workdir);
|
|
106333
106942
|
{
|
|
106334
106943
|
const { claimProjectIdentity: claimProjectIdentity2 } = await Promise.resolve().then(() => (init_runtime2(), exports_runtime));
|
|
106335
106944
|
let remoteUrl = null;
|
|
@@ -106490,7 +107099,11 @@ var init_run_setup = __esm(() => {
|
|
|
106490
107099
|
sweepFeatureTranscripts,
|
|
106491
107100
|
buildApprovalsSeal,
|
|
106492
107101
|
acquireLock,
|
|
106493
|
-
acquireFeatureLock
|
|
107102
|
+
acquireFeatureLock,
|
|
107103
|
+
async autoMigrateGeneratedContent(workdir) {
|
|
107104
|
+
const { autoMigrateGeneratedContent: autoMigrateGeneratedContent2 } = await Promise.resolve().then(() => (init_commands(), exports_commands));
|
|
107105
|
+
await autoMigrateGeneratedContent2(workdir);
|
|
107106
|
+
}
|
|
106494
107107
|
};
|
|
106495
107108
|
});
|
|
106496
107109
|
|
|
@@ -108017,7 +108630,7 @@ var init_run_cost_reconcile = __esm(() => {
|
|
|
108017
108630
|
});
|
|
108018
108631
|
|
|
108019
108632
|
// src/finish/audit.ts
|
|
108020
|
-
import { appendFile as appendFile8, mkdir as
|
|
108633
|
+
import { appendFile as appendFile8, mkdir as mkdir32, readFile as readFile7, writeFile as writeFile12 } from "fs/promises";
|
|
108021
108634
|
import { join as join113 } from "path";
|
|
108022
108635
|
function roundsPath(t) {
|
|
108023
108636
|
return join113(t.auditDir, `${t.runId}.jsonl`);
|
|
@@ -108044,7 +108657,7 @@ async function updateLedger(t, result) {
|
|
|
108044
108657
|
finishedAt: new Date().toISOString()
|
|
108045
108658
|
};
|
|
108046
108659
|
try {
|
|
108047
|
-
await
|
|
108660
|
+
await mkdir32(t.auditDir, { recursive: true });
|
|
108048
108661
|
await writeFile12(ledgerPath(t.auditDir), `${JSON.stringify(entry, null, 2)}
|
|
108049
108662
|
`, "utf8");
|
|
108050
108663
|
} catch {}
|
|
@@ -108068,7 +108681,7 @@ async function readLedger(auditDir) {
|
|
|
108068
108681
|
}
|
|
108069
108682
|
async function appendRound(t, round) {
|
|
108070
108683
|
try {
|
|
108071
|
-
await
|
|
108684
|
+
await mkdir32(t.auditDir, { recursive: true });
|
|
108072
108685
|
await appendFile8(roundsPath(t), `${JSON.stringify(round)}
|
|
108073
108686
|
`, "utf8");
|
|
108074
108687
|
} catch {}
|
|
@@ -108094,7 +108707,7 @@ async function readRounds(t) {
|
|
|
108094
108707
|
async function writeResult(t, result, options = {}) {
|
|
108095
108708
|
const rounds = await readRounds(t);
|
|
108096
108709
|
const withRounds = rounds.length > 0 ? { ...result, rounds } : result;
|
|
108097
|
-
await
|
|
108710
|
+
await mkdir32(t.auditDir, { recursive: true });
|
|
108098
108711
|
await writeFile12(resultPath(t), `${JSON.stringify(withRounds, null, 2)}
|
|
108099
108712
|
`, "utf8");
|
|
108100
108713
|
if (options.ledger === false)
|
|
@@ -110117,7 +110730,7 @@ async function runFinishPhase(ctx) {
|
|
|
110117
110730
|
const costBefore = _finishPhaseDeps.snapshotCost(ctx.runtime);
|
|
110118
110731
|
const { signal, dispose } = phaseSignal(ctx.abortSignal, settings.timeouts.flowMs);
|
|
110119
110732
|
let result = null;
|
|
110120
|
-
let
|
|
110733
|
+
let failure2;
|
|
110121
110734
|
let dispatchAsk;
|
|
110122
110735
|
try {
|
|
110123
110736
|
const audit = {
|
|
@@ -110189,13 +110802,13 @@ async function runFinishPhase(ctx) {
|
|
|
110189
110802
|
timeouts: { acceptanceMs: settings.timeouts.acceptanceMs, gateMs: settings.timeouts.gateMs }
|
|
110190
110803
|
});
|
|
110191
110804
|
} catch (err) {
|
|
110192
|
-
|
|
110805
|
+
failure2 = errorMessage(err);
|
|
110193
110806
|
} finally {
|
|
110194
110807
|
await dispatchAsk?.dispose();
|
|
110195
110808
|
dispose();
|
|
110196
110809
|
}
|
|
110197
110810
|
const costUsd = _finishPhaseDeps.snapshotCost(ctx.runtime) - costBefore;
|
|
110198
|
-
const passed =
|
|
110811
|
+
const passed = failure2 === undefined && result?.status !== "escalated";
|
|
110199
110812
|
if (result?.skipReason) {
|
|
110200
110813
|
getSafeLogger()?.info("finish", "Finish phase skipped", {
|
|
110201
110814
|
reason: result.skipReason,
|
|
@@ -110227,8 +110840,8 @@ async function runFinishPhase(ctx) {
|
|
|
110227
110840
|
escalationReason: result.escalationReason
|
|
110228
110841
|
});
|
|
110229
110842
|
}
|
|
110230
|
-
if (
|
|
110231
|
-
getSafeLogger()?.warn("finish", "Finish phase could not run", { storyId: "_run", error:
|
|
110843
|
+
if (failure2) {
|
|
110844
|
+
getSafeLogger()?.warn("finish", "Finish phase could not run", { storyId: "_run", error: failure2 });
|
|
110232
110845
|
}
|
|
110233
110846
|
pipelineEventBus.emit({
|
|
110234
110847
|
type: "postrun:phase:completed",
|
|
@@ -110660,7 +111273,7 @@ var init_runner_completion = __esm(() => {
|
|
|
110660
111273
|
});
|
|
110661
111274
|
|
|
110662
111275
|
// src/pipeline/subscribers/events-writer.ts
|
|
110663
|
-
import { appendFile as appendFile9, mkdir as
|
|
111276
|
+
import { appendFile as appendFile9, mkdir as mkdir33 } from "fs/promises";
|
|
110664
111277
|
import { basename as basename15, join as join116 } from "path";
|
|
110665
111278
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
110666
111279
|
const logger = getSafeLogger();
|
|
@@ -110672,7 +111285,7 @@ function wireEventsWriter(bus, feature, runId, workdir) {
|
|
|
110672
111285
|
return (async () => {
|
|
110673
111286
|
try {
|
|
110674
111287
|
if (!dirReady) {
|
|
110675
|
-
await
|
|
111288
|
+
await mkdir33(eventsDir, { recursive: true });
|
|
110676
111289
|
dirReady = true;
|
|
110677
111290
|
}
|
|
110678
111291
|
await appendFile9(eventsFile, `${JSON.stringify(line)}
|
|
@@ -110846,7 +111459,7 @@ var init_interaction2 = __esm(() => {
|
|
|
110846
111459
|
});
|
|
110847
111460
|
|
|
110848
111461
|
// src/pipeline/subscribers/registry.ts
|
|
110849
|
-
import { mkdir as
|
|
111462
|
+
import { mkdir as mkdir34, writeFile as writeFile13 } from "fs/promises";
|
|
110850
111463
|
import { basename as basename16, join as join117 } from "path";
|
|
110851
111464
|
function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
110852
111465
|
const logger = getSafeLogger();
|
|
@@ -110856,7 +111469,7 @@ function wireRegistry(bus, feature, runId, workdir, outputDir) {
|
|
|
110856
111469
|
const unsub = bus.on("run:started", (_ev) => {
|
|
110857
111470
|
return (async () => {
|
|
110858
111471
|
try {
|
|
110859
|
-
await
|
|
111472
|
+
await mkdir34(runDir, { recursive: true });
|
|
110860
111473
|
const meta3 = {
|
|
110861
111474
|
runId,
|
|
110862
111475
|
project,
|
|
@@ -115829,7 +116442,7 @@ var init_rules_lint = __esm(() => {
|
|
|
115829
116442
|
});
|
|
115830
116443
|
|
|
115831
116444
|
// src/cli/rules-cli-deps.ts
|
|
115832
|
-
import { mkdir as
|
|
116445
|
+
import { mkdir as mkdir35 } from "fs/promises";
|
|
115833
116446
|
import { join as join129 } from "path";
|
|
115834
116447
|
var _rulesCLIDeps;
|
|
115835
116448
|
var init_rules_cli_deps = __esm(() => {
|
|
@@ -115850,7 +116463,7 @@ var init_rules_cli_deps = __esm(() => {
|
|
|
115850
116463
|
}
|
|
115851
116464
|
},
|
|
115852
116465
|
mkdir: async (path32) => {
|
|
115853
|
-
await
|
|
116466
|
+
await mkdir35(path32, { recursive: true });
|
|
115854
116467
|
},
|
|
115855
116468
|
globCanonicalRuleFiles: (workdir) => _rulesLintDeps.globCanonicalRuleFiles(workdir),
|
|
115856
116469
|
globHasMatch: (pattern, cwd) => _rulesLintDeps.globHasMatch(pattern, cwd),
|
|
@@ -119955,7 +120568,7 @@ Error generating stack: ` + x.message + `
|
|
|
119955
120568
|
return p0;
|
|
119956
120569
|
});
|
|
119957
120570
|
}
|
|
119958
|
-
function
|
|
120571
|
+
function describeValue2(value, maxLength) {
|
|
119959
120572
|
switch (typeof value) {
|
|
119960
120573
|
case "string":
|
|
119961
120574
|
return value = JSON.stringify(value), value.length > maxLength ? 5 > maxLength ? '"..."' : value.slice(0, maxLength - 4) + '..."' : value;
|
|
@@ -119975,7 +120588,7 @@ Error generating stack: ` + x.message + `
|
|
|
119975
120588
|
var jsonPropName = JSON.stringify(propName);
|
|
119976
120589
|
jsonPropName !== '"' + propName + '"' && (propName = jsonPropName);
|
|
119977
120590
|
maxLength -= propName.length - 2;
|
|
119978
|
-
jsonPropName =
|
|
120591
|
+
jsonPropName = describeValue2(value[propName], 15 > maxLength ? maxLength : 15);
|
|
119979
120592
|
maxLength -= jsonPropName.length;
|
|
119980
120593
|
if (0 > maxLength) {
|
|
119981
120594
|
name += name === "" ? "..." : ", ...";
|
|
@@ -119993,7 +120606,7 @@ Error generating stack: ` + x.message + `
|
|
|
119993
120606
|
}
|
|
119994
120607
|
}
|
|
119995
120608
|
function describePropValue(value, maxLength) {
|
|
119996
|
-
return typeof value !== "string" || needsEscaping.test(value) ? "{" +
|
|
120609
|
+
return typeof value !== "string" || needsEscaping.test(value) ? "{" + describeValue2(value, maxLength - 2) + "}" : value.length > maxLength - 2 ? 5 > maxLength ? '"..."' : '"' + value.slice(0, maxLength - 5) + '..."' : '"' + value + '"';
|
|
119997
120610
|
}
|
|
119998
120611
|
function describeExpandedElement(type, props, rowPrefix) {
|
|
119999
120612
|
var remainingRowLength = 120 - rowPrefix.length - type.length, properties = [], propName;
|
|
@@ -120016,14 +120629,14 @@ Error generating stack: ` + x.message + `
|
|
|
120016
120629
|
for (propName in clientObject)
|
|
120017
120630
|
if (clientObject.hasOwnProperty(propName)) {
|
|
120018
120631
|
delete remainingServerProperties[propName];
|
|
120019
|
-
var maxLength = 120 - 2 * indent - propName.length - 2, clientPropValue =
|
|
120020
|
-
serverObject.hasOwnProperty(propName) ? (maxLength =
|
|
120632
|
+
var maxLength = 120 - 2 * indent - propName.length - 2, clientPropValue = describeValue2(clientObject[propName], maxLength);
|
|
120633
|
+
serverObject.hasOwnProperty(propName) ? (maxLength = describeValue2(serverObject[propName], maxLength), properties += added(indent) + propName + ": " + clientPropValue + `
|
|
120021
120634
|
`, properties += removed(indent) + propName + ": " + maxLength + `
|
|
120022
120635
|
`) : properties += added(indent) + propName + ": " + clientPropValue + `
|
|
120023
120636
|
`;
|
|
120024
120637
|
}
|
|
120025
120638
|
for (var _propName in remainingServerProperties)
|
|
120026
|
-
remainingServerProperties.hasOwnProperty(_propName) && (clientObject =
|
|
120639
|
+
remainingServerProperties.hasOwnProperty(_propName) && (clientObject = describeValue2(remainingServerProperties[_propName], 120 - 2 * indent - _propName.length - 2), properties += removed(indent) + _propName + ": " + clientObject + `
|
|
120027
120640
|
`);
|
|
120028
120641
|
return properties;
|
|
120029
120642
|
}
|
|
@@ -132398,7 +133011,7 @@ var Wrap = /* @__PURE__ */ function(Wrap2) {
|
|
|
132398
133011
|
Wrap2[Wrap2["WrapReverse"] = 2] = "WrapReverse";
|
|
132399
133012
|
return Wrap2;
|
|
132400
133013
|
}({});
|
|
132401
|
-
var
|
|
133014
|
+
var constants2 = {
|
|
132402
133015
|
ALIGN_AUTO: Align.Auto,
|
|
132403
133016
|
ALIGN_FLEX_START: Align.FlexStart,
|
|
132404
133017
|
ALIGN_CENTER: Align.Center,
|
|
@@ -132472,7 +133085,7 @@ var constants = {
|
|
|
132472
133085
|
WRAP_WRAP: Wrap.Wrap,
|
|
132473
133086
|
WRAP_WRAP_REVERSE: Wrap.WrapReverse
|
|
132474
133087
|
};
|
|
132475
|
-
var YGEnums_default =
|
|
133088
|
+
var YGEnums_default = constants2;
|
|
132476
133089
|
|
|
132477
133090
|
// node_modules/yoga-layout/dist/src/wrapAssembly.js
|
|
132478
133091
|
function wrapAssembly(lib) {
|
|
@@ -136740,10 +137353,10 @@ async function writeQueueCommand(queueFilePath, command) {
|
|
|
136740
137353
|
await withQueueFileLock(queueFilePath, () => appendFile10(queueFilePath, `${commandLine2}
|
|
136741
137354
|
`, "utf8"));
|
|
136742
137355
|
});
|
|
136743
|
-
const
|
|
136744
|
-
_writeChains.set(queueFilePath,
|
|
136745
|
-
|
|
136746
|
-
if (_writeChains.get(queueFilePath) ===
|
|
137356
|
+
const settled2 = next.catch(() => {});
|
|
137357
|
+
_writeChains.set(queueFilePath, settled2);
|
|
137358
|
+
settled2.then(() => {
|
|
137359
|
+
if (_writeChains.get(queueFilePath) === settled2)
|
|
136747
137360
|
_writeChains.delete(queueFilePath);
|
|
136748
137361
|
});
|
|
136749
137362
|
await next;
|