@nathapp/nax 0.82.0 → 0.82.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/README.md +78 -44
- package/dist/nax.js +1271 -658
- 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.82.
|
|
2671
|
+
version: "0.82.2",
|
|
2672
2672
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
2673
2673
|
type: "module",
|
|
2674
2674
|
bin: {
|
|
@@ -4047,6 +4047,26 @@ var init_types2 = __esm(() => {
|
|
|
4047
4047
|
};
|
|
4048
4048
|
});
|
|
4049
4049
|
|
|
4050
|
+
// src/config/agent-defaults.ts
|
|
4051
|
+
function isBuiltInModelMap(agent, entry) {
|
|
4052
|
+
if (!Object.hasOwn(DEFAULT_MODEL_MAPS, agent) || typeof entry !== "object" || entry === null)
|
|
4053
|
+
return false;
|
|
4054
|
+
const builtIn = DEFAULT_MODEL_MAPS[agent];
|
|
4055
|
+
const tiers = Object.entries(entry);
|
|
4056
|
+
return tiers.length === Object.keys(builtIn).length && tiers.every(([tier, value]) => Object.hasOwn(builtIn, tier) && builtIn[tier] === value);
|
|
4057
|
+
}
|
|
4058
|
+
var DEFAULT_AGENT_PROTOCOL = "hybrid", DEFAULT_AGENT_NAME = "native", NATIVE_AGENT_NAME = "native", DEFAULT_MODEL_MAPS;
|
|
4059
|
+
var init_agent_defaults = __esm(() => {
|
|
4060
|
+
DEFAULT_MODEL_MAPS = {
|
|
4061
|
+
claude: { fast: "haiku", balanced: "sonnet", powerful: "opus" },
|
|
4062
|
+
native: {
|
|
4063
|
+
fast: "anthropic/claude-haiku-4-5",
|
|
4064
|
+
balanced: "anthropic/claude-sonnet-5",
|
|
4065
|
+
powerful: "anthropic/claude-opus-5-5"
|
|
4066
|
+
}
|
|
4067
|
+
};
|
|
4068
|
+
});
|
|
4069
|
+
|
|
4050
4070
|
// node_modules/zod/v4/core/core.js
|
|
4051
4071
|
function $constructor(name, initializer, params) {
|
|
4052
4072
|
function init(inst, def) {
|
|
@@ -17936,7 +17956,7 @@ var init_schemas_sandbox = __esm(() => {
|
|
|
17936
17956
|
SANDBOX_GLOB_CHARS = /[*?[\]{}]/;
|
|
17937
17957
|
literalPath = exports_external.string().refine((p) => !SANDBOX_GLOB_CHARS.test(p), "sandbox paths must be literal: no * ? [ ] { } (spec F1)");
|
|
17938
17958
|
SandboxConfigSchema = exports_external.object({
|
|
17939
|
-
enabled: exports_external.boolean().default(
|
|
17959
|
+
enabled: exports_external.boolean().default(true),
|
|
17940
17960
|
backend: exports_external.enum(["srt"]).default("srt"),
|
|
17941
17961
|
filesystem: exports_external.object({
|
|
17942
17962
|
allowWrite: exports_external.array(literalPath).default([]),
|
|
@@ -18184,7 +18204,7 @@ async function runArgv(options) {
|
|
|
18184
18204
|
stdoutController.abort();
|
|
18185
18205
|
stderrController.abort();
|
|
18186
18206
|
};
|
|
18187
|
-
const timerId = setTimeout(() => {
|
|
18207
|
+
const timerId = _argvExecDeps.setTimeout(() => {
|
|
18188
18208
|
timedOut = true;
|
|
18189
18209
|
killGroup();
|
|
18190
18210
|
stopReaders();
|
|
@@ -18201,7 +18221,7 @@ async function runArgv(options) {
|
|
|
18201
18221
|
const graceMs = _argvExecDeps.drainGraceMs;
|
|
18202
18222
|
let graceTimerId;
|
|
18203
18223
|
const gracePromise = new Promise((resolve3) => {
|
|
18204
|
-
graceTimerId = setTimeout(() => resolve3("expired"), graceMs);
|
|
18224
|
+
graceTimerId = _argvExecDeps.setTimeout(() => resolve3("expired"), graceMs);
|
|
18205
18225
|
});
|
|
18206
18226
|
const stdoutSettled = await Promise.race([
|
|
18207
18227
|
stdoutPromise,
|
|
@@ -18212,7 +18232,7 @@ async function runArgv(options) {
|
|
|
18212
18232
|
gracePromise.then(() => "expired")
|
|
18213
18233
|
]);
|
|
18214
18234
|
if (graceTimerId !== undefined)
|
|
18215
|
-
clearTimeout(graceTimerId);
|
|
18235
|
+
_argvExecDeps.clearTimeout(graceTimerId);
|
|
18216
18236
|
const stdoutClosed = stdoutSettled !== "expired";
|
|
18217
18237
|
const stderrClosed = stderrSettled !== "expired";
|
|
18218
18238
|
if (!stdoutClosed || !stderrClosed) {
|
|
@@ -18225,7 +18245,7 @@ async function runArgv(options) {
|
|
|
18225
18245
|
}
|
|
18226
18246
|
const stdoutFinal = stdoutClosed ? stdoutSettled : await stdoutPromise;
|
|
18227
18247
|
const stderrFinal = stderrClosed ? stderrSettled : await stderrPromise;
|
|
18228
|
-
clearTimeout(timerId);
|
|
18248
|
+
_argvExecDeps.clearTimeout(timerId);
|
|
18229
18249
|
signal?.removeEventListener("abort", onAbort);
|
|
18230
18250
|
return {
|
|
18231
18251
|
exitCode,
|
|
@@ -18242,7 +18262,9 @@ var init_argv_exec = __esm(() => {
|
|
|
18242
18262
|
_argvExecDeps = {
|
|
18243
18263
|
spawn,
|
|
18244
18264
|
killProcessGroup,
|
|
18245
|
-
drainGraceMs: DRAIN_GRACE_MS
|
|
18265
|
+
drainGraceMs: DRAIN_GRACE_MS,
|
|
18266
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
18267
|
+
clearTimeout: (id) => clearTimeout(id)
|
|
18246
18268
|
};
|
|
18247
18269
|
});
|
|
18248
18270
|
|
|
@@ -18376,10 +18398,26 @@ function isNaxConfigFile(root, resolved) {
|
|
|
18376
18398
|
return segments.length === 2 || segments.length >= 4 && segments[1] === "mono";
|
|
18377
18399
|
}
|
|
18378
18400
|
function isNaxOwnedWritePath(rel) {
|
|
18401
|
+
return naxOwnedKind(rel) !== undefined;
|
|
18402
|
+
}
|
|
18403
|
+
function naxOwnedKind(rel) {
|
|
18379
18404
|
const segments = rel.split("/");
|
|
18380
18405
|
if (segments.length === 1 && QUEUE_CONTROL_FILES.has(segments[0] ?? ""))
|
|
18381
|
-
return
|
|
18382
|
-
|
|
18406
|
+
return "queue";
|
|
18407
|
+
if (segments[0] === ".nax" && segments[1] === "features" && segments[segments.length - 1] === "prd.json") {
|
|
18408
|
+
return "prd";
|
|
18409
|
+
}
|
|
18410
|
+
return;
|
|
18411
|
+
}
|
|
18412
|
+
function naxOwnedBashRefusal(tool, kind, hit, verb) {
|
|
18413
|
+
switch (kind) {
|
|
18414
|
+
case "prd":
|
|
18415
|
+
return `${tool} command ${verb} "${hit}", which holds this story's acceptance criteria. ` + "nax updates it itself during the run, so it shows as modified. " + "Bash commands naming it are refused, reads included -- leave it as is. " + "To view it, use the `Read` tool.";
|
|
18416
|
+
case "queue":
|
|
18417
|
+
return `${tool} command ${verb} "${hit}", which is nax's run-control queue. ` + "Bash commands naming it are refused, reads included -- change the run through the queue command.";
|
|
18418
|
+
case "config":
|
|
18419
|
+
return `${tool} command ${verb} "${hit}", which is nax configuration. ` + "Bash commands naming it are refused, reads included -- nax configuration is not changed from inside a run.";
|
|
18420
|
+
}
|
|
18383
18421
|
}
|
|
18384
18422
|
function naxOwnedWriteRefusal(tool, rel, exemptRel) {
|
|
18385
18423
|
if (!NAX_OWNED_WRITE_TOOLS.has(tool))
|
|
@@ -19544,7 +19582,7 @@ function capitalize(text) {
|
|
|
19544
19582
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
19545
19583
|
}
|
|
19546
19584
|
function escalateDescription(shell, patterns) {
|
|
19547
|
-
return `Run one shell command string under ${shell}. ${PREFER_STRUCTURED_TOOLS_SENTENCE}` + `${capitalize(describeGrants(patterns))}.
|
|
19585
|
+
return `Run one shell command string under ${shell}. ${PREFER_STRUCTURED_TOOLS_SENTENCE}` + `${capitalize(describeGrants(patterns))}. Every command, granted or not, is checked first: paths ` + "and redirect targets must stay inside the repository root, and `.git/` access, denied flags, unexpanded " + "`$VAR`, glob or brace characters, `~`, a bare `cd`, and a command matching a deny rule are " + "refused without asking. For a command using a construct that cannot be analysed (e.g. command or process " + "substitution, backticks, here-documents, subshells, `2>&1`, `#` comments, an option-shaped `cd`), these " + "checks cover the part before that construct. A command outside the granted forms, or one using a construct " + "that cannot be analysed, is not refused: it is sent to a human for approval (unless an identical command " + "was already approved and remembered) and, if they allow it, runs exactly as written; it is refused if they " + "deny it or do not answer in time, so prefer the granted forms. Each segment of a `&&`/`||`/`;`/`|` chain is " + "checked separately. " + BACKGROUND_PROCESSES_KILLED_SENTENCE;
|
|
19548
19586
|
}
|
|
19549
19587
|
function rawDescription(shell, containment = RAW_UNCONTAINED) {
|
|
19550
19588
|
return `Run one shell command string under ${shell}. ${PREFER_STRUCTURED_TOOLS_SENTENCE}` + "This stage runs under raw mode (ADR-030): pipes, redirects, command substitution ($(...), backticks), " + "process substitution, here-documents and subshells all work here -- nothing is refused for being unparseable, " + "and Bash allow/deny/ask rules configured for this stage are NOT consulted. " + containment + "The only refusal is a command the lexer CAN parse that names or redirects into one of the exact file " + "paths nax owns -- .nax/config.json, .nax/mono/*/config.json, " + ".nax/features/**/prd.json, or the root queue-control files -- change those through nax rather than by " + "writing them directly. That screen is advisory, not a boundary: it matches exact file paths only, so a " + "command using command substitution, a directory target (cp x .nax/), a glob, a nested shell (sh -c '...'), " + "tar -C or dd of=, or a symlink alias all skip it; use the sandbox for a boundary. " + BACKGROUND_PROCESSES_KILLED_SENTENCE;
|
|
@@ -19638,7 +19676,8 @@ ${launched.stderr}`;
|
|
|
19638
19676
|
isError: launched.timedOut || launched.exitCode !== 0 || launched.aborted === true,
|
|
19639
19677
|
audit: {
|
|
19640
19678
|
executed: launched.executed,
|
|
19641
|
-
...launched.sandbox !== undefined ? { sandbox: launched.sandbox } : {}
|
|
19679
|
+
...launched.sandbox !== undefined ? { sandbox: launched.sandbox } : {},
|
|
19680
|
+
...!launched.timedOut && launched.aborted !== true ? { exitCode: launched.exitCode } : {}
|
|
19642
19681
|
},
|
|
19643
19682
|
resultBytesPreTruncation: Buffer.byteLength(body, "utf8")
|
|
19644
19683
|
};
|
|
@@ -19756,6 +19795,46 @@ var init_delete = __esm(() => {
|
|
|
19756
19795
|
};
|
|
19757
19796
|
});
|
|
19758
19797
|
|
|
19798
|
+
// src/tools/edit-region.ts
|
|
19799
|
+
function countNewlines(text) {
|
|
19800
|
+
let count = 0;
|
|
19801
|
+
for (let i = 0;i < text.length; i += 1) {
|
|
19802
|
+
if (text[i] === `
|
|
19803
|
+
`)
|
|
19804
|
+
count += 1;
|
|
19805
|
+
}
|
|
19806
|
+
return count;
|
|
19807
|
+
}
|
|
19808
|
+
function composeEditRegion({ updated, matchIndex, newStringLength }) {
|
|
19809
|
+
const lines = splitModelLines(updated);
|
|
19810
|
+
const total = lines.length;
|
|
19811
|
+
if (total === 0)
|
|
19812
|
+
return "[file is now empty]";
|
|
19813
|
+
const start = Math.min(total, 1 + countNewlines(updated.slice(0, matchIndex)));
|
|
19814
|
+
const end = newStringLength > 0 ? Math.min(total, 1 + countNewlines(updated.slice(0, matchIndex + newStringLength - 1))) : start;
|
|
19815
|
+
const a = Math.max(1, start - CONTEXT_LINES);
|
|
19816
|
+
const b = Math.min(total, end + CONTEXT_LINES);
|
|
19817
|
+
const header = `[lines ${a}-${b} of ${total}]`;
|
|
19818
|
+
const selected = end - start + 1 > MAX_REGION_LINES_SHOWN ? [
|
|
19819
|
+
...lines.slice(a - 1, start + 2),
|
|
19820
|
+
`[... lines ${start + 3}-${end - 3} not shown ...]`,
|
|
19821
|
+
...lines.slice(end - 3, b)
|
|
19822
|
+
] : lines.slice(a - 1, b);
|
|
19823
|
+
let view = [header, ...selected].join(`
|
|
19824
|
+
`);
|
|
19825
|
+
while (view.endsWith(`
|
|
19826
|
+
`))
|
|
19827
|
+
view = view.slice(0, -1);
|
|
19828
|
+
return view;
|
|
19829
|
+
}
|
|
19830
|
+
function replaceUniqueLiteral(source, oldString, newString, matchIndex) {
|
|
19831
|
+
return source.slice(0, matchIndex) + newString + source.slice(matchIndex + oldString.length);
|
|
19832
|
+
}
|
|
19833
|
+
var CONTEXT_LINES = 3, MAX_REGION_LINES_SHOWN = 8;
|
|
19834
|
+
var init_edit_region = __esm(() => {
|
|
19835
|
+
init_truncate();
|
|
19836
|
+
});
|
|
19837
|
+
|
|
19759
19838
|
// src/tools/edit.ts
|
|
19760
19839
|
import { readFile, stat, writeFile } from "fs/promises";
|
|
19761
19840
|
function countOccurrences(haystack, needle) {
|
|
@@ -19769,11 +19848,17 @@ function countOccurrences(haystack, needle) {
|
|
|
19769
19848
|
}
|
|
19770
19849
|
return count;
|
|
19771
19850
|
}
|
|
19772
|
-
var editTool;
|
|
19851
|
+
var _editDeps, editTool;
|
|
19773
19852
|
var init_edit = __esm(() => {
|
|
19853
|
+
init_edit_region();
|
|
19854
|
+
_editDeps = {
|
|
19855
|
+
stat: (path) => stat(path),
|
|
19856
|
+
readFile: (path, encoding) => readFile(path, encoding),
|
|
19857
|
+
writeFile: (path, data, encoding) => writeFile(path, data, encoding)
|
|
19858
|
+
};
|
|
19774
19859
|
editTool = {
|
|
19775
19860
|
name: "Edit",
|
|
19776
|
-
description: "Replace one exact occurrence of old_string with new_string in a repository file. Fails if the match is absent or ambiguous.",
|
|
19861
|
+
description: "Replace one exact occurrence of old_string with new_string in a repository file. Fails if the match is absent or ambiguous. On success the result shows the edited lines with up to 3 lines of context and their line range, so you do not need to Read the file again to check the edit.",
|
|
19777
19862
|
inputSchema: {
|
|
19778
19863
|
type: "object",
|
|
19779
19864
|
properties: {
|
|
@@ -19794,7 +19879,7 @@ var init_edit = __esm(() => {
|
|
|
19794
19879
|
return { content: "old_string and new_string must be strings", isError: true };
|
|
19795
19880
|
}
|
|
19796
19881
|
try {
|
|
19797
|
-
const { size } = await stat(target);
|
|
19882
|
+
const { size } = await _editDeps.stat(target);
|
|
19798
19883
|
if (size > ctx.maxFileBytes) {
|
|
19799
19884
|
return {
|
|
19800
19885
|
content: `the file is ${size} bytes, which exceeds the ${ctx.maxFileBytes}-byte file ceiling -- refusing to edit ${target}`,
|
|
@@ -19806,7 +19891,7 @@ var init_edit = __esm(() => {
|
|
|
19806
19891
|
}
|
|
19807
19892
|
let source;
|
|
19808
19893
|
try {
|
|
19809
|
-
source = await readFile(target, "utf8");
|
|
19894
|
+
source = await _editDeps.readFile(target, "utf8");
|
|
19810
19895
|
} catch (err) {
|
|
19811
19896
|
return { content: err instanceof Error ? err.message : String(err), isError: true };
|
|
19812
19897
|
}
|
|
@@ -19821,8 +19906,12 @@ var init_edit = __esm(() => {
|
|
|
19821
19906
|
};
|
|
19822
19907
|
}
|
|
19823
19908
|
try {
|
|
19824
|
-
|
|
19825
|
-
|
|
19909
|
+
const matchIndex = source.indexOf(oldString);
|
|
19910
|
+
const updated = replaceUniqueLiteral(source, oldString, newString, matchIndex);
|
|
19911
|
+
await _editDeps.writeFile(target, updated, "utf8");
|
|
19912
|
+
const region = composeEditRegion({ updated, matchIndex, newStringLength: newString.length });
|
|
19913
|
+
return { content: `edited ${target}
|
|
19914
|
+
${region}` };
|
|
19826
19915
|
} catch (err) {
|
|
19827
19916
|
return { content: err instanceof Error ? err.message : String(err), isError: true };
|
|
19828
19917
|
}
|
|
@@ -20904,9 +20993,6 @@ var ASK_NO_CHANNEL_REASON = "matched an ask rule requiring human approval; no ap
|
|
|
20904
20993
|
var init_ask = () => {};
|
|
20905
20994
|
|
|
20906
20995
|
// src/permissions/bash-lex.ts
|
|
20907
|
-
function refused(construct) {
|
|
20908
|
-
return { kind: "refused", construct };
|
|
20909
|
-
}
|
|
20910
20996
|
function doubleQuoteEnd(command, from) {
|
|
20911
20997
|
for (let i = from;i < command.length; i += 1) {
|
|
20912
20998
|
const char = command[i];
|
|
@@ -20921,7 +21007,7 @@ function doubleQuoteEnd(command, from) {
|
|
|
20921
21007
|
}
|
|
20922
21008
|
function lexBashCommand(command) {
|
|
20923
21009
|
if (command.trim() === "")
|
|
20924
|
-
return refused
|
|
21010
|
+
return { kind: "refused", construct: "an empty command", prefix: [] };
|
|
20925
21011
|
const segments = [];
|
|
20926
21012
|
let tokens = [];
|
|
20927
21013
|
let redirects = [];
|
|
@@ -20929,6 +21015,10 @@ function lexBashCommand(command) {
|
|
|
20929
21015
|
let opaque = false;
|
|
20930
21016
|
let started = false;
|
|
20931
21017
|
let pendingRedirect;
|
|
21018
|
+
function refusedHere(construct) {
|
|
21019
|
+
const prefix = tokens.length === 0 && redirects.length === 0 ? [...segments] : [...segments, { tokens, redirects }];
|
|
21020
|
+
return { kind: "refused", construct, prefix };
|
|
21021
|
+
}
|
|
20932
21022
|
function flushWord() {
|
|
20933
21023
|
if (!started)
|
|
20934
21024
|
return;
|
|
@@ -20960,7 +21050,7 @@ function lexBashCommand(command) {
|
|
|
20960
21050
|
if (char === "'") {
|
|
20961
21051
|
const end = command.indexOf("'", i + 1);
|
|
20962
21052
|
if (end === -1)
|
|
20963
|
-
return
|
|
21053
|
+
return refusedHere("an unbalanced single quote");
|
|
20964
21054
|
word += command.slice(i + 1, end);
|
|
20965
21055
|
started = true;
|
|
20966
21056
|
i = end + 1;
|
|
@@ -20969,12 +21059,12 @@ function lexBashCommand(command) {
|
|
|
20969
21059
|
if (char === '"') {
|
|
20970
21060
|
const end = doubleQuoteEnd(command, i + 1);
|
|
20971
21061
|
if (end === -1)
|
|
20972
|
-
return
|
|
21062
|
+
return refusedHere("an unbalanced double quote");
|
|
20973
21063
|
const inner = command.slice(i + 1, end);
|
|
20974
21064
|
if (inner.includes("$("))
|
|
20975
|
-
return
|
|
21065
|
+
return refusedHere("a command substitution `$(...)`");
|
|
20976
21066
|
if (inner.includes("`"))
|
|
20977
|
-
return
|
|
21067
|
+
return refusedHere("a backtick command substitution");
|
|
20978
21068
|
if (inner.includes("$"))
|
|
20979
21069
|
opaque = true;
|
|
20980
21070
|
word += inner;
|
|
@@ -20984,32 +21074,32 @@ function lexBashCommand(command) {
|
|
|
20984
21074
|
}
|
|
20985
21075
|
if (char === "\\") {
|
|
20986
21076
|
if (next === undefined)
|
|
20987
|
-
return
|
|
21077
|
+
return refusedHere("a trailing backslash");
|
|
20988
21078
|
word += next;
|
|
20989
21079
|
started = true;
|
|
20990
21080
|
i += 2;
|
|
20991
21081
|
continue;
|
|
20992
21082
|
}
|
|
20993
21083
|
if (char === "(" || char === ")")
|
|
20994
|
-
return
|
|
21084
|
+
return refusedHere("a subshell `( ... )`");
|
|
20995
21085
|
if (char === "!" && !started)
|
|
20996
|
-
return
|
|
21086
|
+
return refusedHere("a `!` negation");
|
|
20997
21087
|
if (char === "#" && !started)
|
|
20998
|
-
return
|
|
21088
|
+
return refusedHere("a `#` comment");
|
|
20999
21089
|
if (char === "$" && next === "(")
|
|
21000
|
-
return
|
|
21090
|
+
return refusedHere("a command substitution `$(...)`");
|
|
21001
21091
|
if (char === "`")
|
|
21002
|
-
return
|
|
21092
|
+
return refusedHere("a backtick command substitution");
|
|
21003
21093
|
if ((char === "<" || char === ">") && next === "(") {
|
|
21004
|
-
return
|
|
21094
|
+
return refusedHere("a process substitution `<(...)` / `>(...)`");
|
|
21005
21095
|
}
|
|
21006
21096
|
if (char === "<" && next === "<")
|
|
21007
|
-
return
|
|
21097
|
+
return refusedHere("a here-document `<<`");
|
|
21008
21098
|
if ((char === "<" || char === ">") && next === "&") {
|
|
21009
|
-
return
|
|
21099
|
+
return refusedHere("file-descriptor duplication (`2>&1`)");
|
|
21010
21100
|
}
|
|
21011
21101
|
if (char === "&" && next === ">")
|
|
21012
|
-
return
|
|
21102
|
+
return refusedHere("the `&>` redirection form");
|
|
21013
21103
|
if (char === "$") {
|
|
21014
21104
|
opaque = true;
|
|
21015
21105
|
word += char;
|
|
@@ -21026,21 +21116,21 @@ function lexBashCommand(command) {
|
|
|
21026
21116
|
` || char === ";") {
|
|
21027
21117
|
const error49 = flushSegment(";");
|
|
21028
21118
|
if (error49 !== undefined)
|
|
21029
|
-
return
|
|
21119
|
+
return refusedHere(error49);
|
|
21030
21120
|
i += 1;
|
|
21031
21121
|
continue;
|
|
21032
21122
|
}
|
|
21033
21123
|
if (char === "&" && next === "&" || char === "|" && next === "|") {
|
|
21034
21124
|
const error49 = flushSegment(char === "&" ? "&&" : "||");
|
|
21035
21125
|
if (error49 !== undefined)
|
|
21036
|
-
return
|
|
21126
|
+
return refusedHere(error49);
|
|
21037
21127
|
i += 2;
|
|
21038
21128
|
continue;
|
|
21039
21129
|
}
|
|
21040
21130
|
if (char === "|" || char === "&") {
|
|
21041
21131
|
const error49 = flushSegment(char);
|
|
21042
21132
|
if (error49 !== undefined)
|
|
21043
|
-
return
|
|
21133
|
+
return refusedHere(error49);
|
|
21044
21134
|
i += 1;
|
|
21045
21135
|
continue;
|
|
21046
21136
|
}
|
|
@@ -21065,7 +21155,7 @@ function lexBashCommand(command) {
|
|
|
21065
21155
|
}
|
|
21066
21156
|
const error48 = flushSegment();
|
|
21067
21157
|
if (error48 !== undefined)
|
|
21068
|
-
return
|
|
21158
|
+
return refusedHere(error48);
|
|
21069
21159
|
return { kind: "ok", segments };
|
|
21070
21160
|
}
|
|
21071
21161
|
|
|
@@ -21196,7 +21286,9 @@ function checkPayload(args, segment, cwd) {
|
|
|
21196
21286
|
case "no-target":
|
|
21197
21287
|
return { refusal: deny("`cd` with no target is refused") };
|
|
21198
21288
|
case "option-shaped":
|
|
21199
|
-
return {
|
|
21289
|
+
return {
|
|
21290
|
+
refusal: deny(`cd target "${cdResult.text}" is option-shaped, and this gate does not model it`, false, true)
|
|
21291
|
+
};
|
|
21200
21292
|
case "opaque":
|
|
21201
21293
|
case "unresolved":
|
|
21202
21294
|
return { refusal: deny(`cd target "${cdResult.text}" is not inside the permitted root`, true) };
|
|
@@ -21233,29 +21325,30 @@ function checkBashCommand(args) {
|
|
|
21233
21325
|
if (command.trim() === "")
|
|
21234
21326
|
return deny(`"command" must not be empty`);
|
|
21235
21327
|
const lexed = lexBashCommand(command);
|
|
21236
|
-
|
|
21237
|
-
|
|
21238
|
-
}
|
|
21239
|
-
for (const segment of lexed.segments) {
|
|
21328
|
+
const segments = lexed.kind === "ok" ? lexed.segments : lexed.prefix;
|
|
21329
|
+
for (const segment of segments) {
|
|
21240
21330
|
if (args.denyEntry !== undefined && matchesSegment(args.denyEntry, segment)) {
|
|
21241
21331
|
return deny(`${tool} segment "${render(segment)}" is denied for this stage by rule ${ruleExpr(tool, args.denyEntry, segment)}`);
|
|
21242
21332
|
}
|
|
21243
21333
|
}
|
|
21244
|
-
for (const segment of lexed.segments) {
|
|
21245
|
-
if (args.grant.unconditional || matchesSegment(args.grant, segment))
|
|
21246
|
-
continue;
|
|
21247
|
-
const granted = args.grant.raw.filter((pattern) => pattern !== "*").join(", ");
|
|
21248
|
-
const alternatives = granted === "" ? "no command forms are granted for this stage" : `granted forms: ${granted}`;
|
|
21249
|
-
return deny(`${tool} is not granted "${render(segment)}" -- ${alternatives}`, false, true);
|
|
21250
|
-
}
|
|
21251
21334
|
let cwd = [args.initialPath];
|
|
21252
|
-
for (const segment of
|
|
21335
|
+
for (const segment of segments) {
|
|
21253
21336
|
const result = checkPayload(args, segment, cwd);
|
|
21254
21337
|
if (result.refusal !== undefined)
|
|
21255
21338
|
return result.refusal;
|
|
21256
21339
|
cwd = nextWorkingDirectories(segment, cwd, result.cdTargets);
|
|
21257
21340
|
}
|
|
21258
|
-
|
|
21341
|
+
if (lexed.kind === "refused") {
|
|
21342
|
+
return deny(`command contains ${lexed.construct}, which cannot be analysed and is therefore refused -- ` + "rewrite it without that construct, or use a structured tool", false, true);
|
|
21343
|
+
}
|
|
21344
|
+
for (const segment of segments) {
|
|
21345
|
+
if (args.grant.unconditional || matchesSegment(args.grant, segment))
|
|
21346
|
+
continue;
|
|
21347
|
+
const granted = args.grant.raw.filter((pattern) => pattern !== "*").join(", ");
|
|
21348
|
+
const alternatives = granted === "" ? "no command forms are granted for this stage" : `granted forms: ${granted}`;
|
|
21349
|
+
return deny(`${tool} is not granted "${render(segment)}" -- ${alternatives}`, false, true);
|
|
21350
|
+
}
|
|
21351
|
+
for (const segment of segments) {
|
|
21259
21352
|
if (args.askEntry !== undefined && matchesSegment(args.askEntry, segment)) {
|
|
21260
21353
|
return { kind: "ask", rule: ruleExpr(tool, args.askEntry, segment) };
|
|
21261
21354
|
}
|
|
@@ -21276,15 +21369,16 @@ function protectedHit(args, candidate, cwd) {
|
|
|
21276
21369
|
for (const directory of cwd) {
|
|
21277
21370
|
const lexical = realOrRaw(resolve10(directory, candidate));
|
|
21278
21371
|
if (isNaxConfigFile(args.root, lexical))
|
|
21279
|
-
return candidate;
|
|
21372
|
+
return { kind: "config", hit: candidate };
|
|
21280
21373
|
const resolved = args.resolvePath(candidate, directory);
|
|
21281
21374
|
if (resolved === null)
|
|
21282
21375
|
continue;
|
|
21283
21376
|
const rel = relative5(args.root, resolved).split(sep4).join("/");
|
|
21284
21377
|
if (rel.startsWith(".."))
|
|
21285
21378
|
continue;
|
|
21286
|
-
|
|
21287
|
-
|
|
21379
|
+
const kind = naxOwnedKind(rel);
|
|
21380
|
+
if (kind !== undefined)
|
|
21381
|
+
return { kind, hit: candidate };
|
|
21288
21382
|
}
|
|
21289
21383
|
return;
|
|
21290
21384
|
}
|
|
@@ -21304,7 +21398,7 @@ function screenRawBashCommand(args) {
|
|
|
21304
21398
|
continue;
|
|
21305
21399
|
const hit = protectedHit(args, token.text, cwd);
|
|
21306
21400
|
if (hit !== undefined) {
|
|
21307
|
-
return deny2(
|
|
21401
|
+
return deny2(naxOwnedBashRefusal(tool, hit.kind, hit.hit, "names"));
|
|
21308
21402
|
}
|
|
21309
21403
|
}
|
|
21310
21404
|
for (const redirect of segment.redirects) {
|
|
@@ -21312,7 +21406,7 @@ function screenRawBashCommand(args) {
|
|
|
21312
21406
|
continue;
|
|
21313
21407
|
const hit = protectedHit(args, redirect.target, cwd);
|
|
21314
21408
|
if (hit !== undefined) {
|
|
21315
|
-
return deny2(
|
|
21409
|
+
return deny2(naxOwnedBashRefusal(tool, hit.kind, hit.hit, "redirects into"));
|
|
21316
21410
|
}
|
|
21317
21411
|
}
|
|
21318
21412
|
const cdResult = cdTargetsFor(segment, cwd, args.resolvePath);
|
|
@@ -22570,6 +22664,47 @@ var init_provider_advertise = __esm(() => {
|
|
|
22570
22664
|
init_provider_types();
|
|
22571
22665
|
});
|
|
22572
22666
|
|
|
22667
|
+
// src/tools/read-continuation.ts
|
|
22668
|
+
function limitStopFooter(input) {
|
|
22669
|
+
const { nextOffset, totalIsFloor, endLine, totalLines } = input;
|
|
22670
|
+
const remaining = Math.max(0, totalLines - endLine);
|
|
22671
|
+
const countLabel = totalIsFloor ? `${remaining}+` : `${remaining}`;
|
|
22672
|
+
return `[${countLabel} more lines in file. Use offset=${nextOffset} to continue.]`;
|
|
22673
|
+
}
|
|
22674
|
+
function shouldAppendLimitStopFooter(hasLimit, endLine, totalLines) {
|
|
22675
|
+
return hasLimit && endLine < totalLines;
|
|
22676
|
+
}
|
|
22677
|
+
function capFooter(input) {
|
|
22678
|
+
const { firstLine: firstLine2, lastLine, totalLabel } = input;
|
|
22679
|
+
return `[Showing lines ${firstLine2}-${lastLine} of ${totalLabel}. Use offset=${lastLine + 1} to continue.]`;
|
|
22680
|
+
}
|
|
22681
|
+
function applyCapCut(input) {
|
|
22682
|
+
const { header, lines, firstLine: firstLine2, totalLabel, limitStopFooter: limitStopFooter2, unshapedBody, maxBytes, maxLines } = input;
|
|
22683
|
+
const candidate = limitStopFooter2 === "" ? unshapedBody : `${unshapedBody}
|
|
22684
|
+
${limitStopFooter2}`;
|
|
22685
|
+
if (splitModelLines(candidate).length <= maxLines && Buffer.byteLength(candidate, "utf8") <= maxBytes) {
|
|
22686
|
+
return { content: candidate };
|
|
22687
|
+
}
|
|
22688
|
+
for (let k = Math.min(lines.length, maxLines - 2);k >= 1; k -= 1) {
|
|
22689
|
+
if (1 + k + 1 > maxLines)
|
|
22690
|
+
continue;
|
|
22691
|
+
const lastLine = firstLine2 + k - 1;
|
|
22692
|
+
const footer = capFooter({ firstLine: firstLine2, lastLine, totalLabel });
|
|
22693
|
+
const bodyJoined = lines.slice(0, k).join(`
|
|
22694
|
+
`);
|
|
22695
|
+
const cut = `${header}
|
|
22696
|
+
${bodyJoined}
|
|
22697
|
+
${footer}`;
|
|
22698
|
+
if (Buffer.byteLength(cut, "utf8") <= maxBytes) {
|
|
22699
|
+
return { content: cut };
|
|
22700
|
+
}
|
|
22701
|
+
}
|
|
22702
|
+
return { content: candidate };
|
|
22703
|
+
}
|
|
22704
|
+
var init_read_continuation = __esm(() => {
|
|
22705
|
+
init_truncate();
|
|
22706
|
+
});
|
|
22707
|
+
|
|
22573
22708
|
// src/tools/read.ts
|
|
22574
22709
|
function parsePositiveInt(value, field) {
|
|
22575
22710
|
if (typeof value !== "number" || !Number.isInteger(value))
|
|
@@ -22589,11 +22724,12 @@ function countLines(prefix) {
|
|
|
22589
22724
|
var UNSUPPORTED_RANGE_ALIASES, readTool;
|
|
22590
22725
|
var init_read = __esm(() => {
|
|
22591
22726
|
init_bounded_io();
|
|
22727
|
+
init_read_continuation();
|
|
22592
22728
|
init_truncate();
|
|
22593
22729
|
UNSUPPORTED_RANGE_ALIASES = ["start_line", "end_line", "start", "end", "line", "lineEnd", "size"];
|
|
22594
22730
|
readTool = {
|
|
22595
22731
|
name: "Read",
|
|
22596
|
-
description: "Read a UTF-8 text file from the repository. Paths are relative to the repository root. " + "Optionally pass offset (1-based line number to start from) and/or limit (maximum number of " + "lines to return) to read a slice instead of the whole file.",
|
|
22732
|
+
description: "Read a UTF-8 text file from the repository. Paths are relative to the repository root. " + "Optionally pass offset (1-based line number to start from) and/or limit (maximum number of " + "lines to return) to read a slice instead of the whole file. " + "Use Read to examine files instead of cat, sed, head, tail or awk in Bash. " + "A read that stops before the end of the file ends with a line naming the offset to continue from. " + "For a large file, read the part you need with offset/limit; when you need the whole file, continue with offset until complete. " + `Output is capped at ${MODEL_MAX_LINES} lines or ${MODEL_MAX_BYTES} bytes.`,
|
|
22597
22733
|
inputSchema: {
|
|
22598
22734
|
type: "object",
|
|
22599
22735
|
properties: {
|
|
@@ -22623,9 +22759,21 @@ var init_read = __esm(() => {
|
|
|
22623
22759
|
const prefix = await readPrefix(target, readCeiling);
|
|
22624
22760
|
const bounded2 = Buffer.byteLength(prefix, "utf8") > readCeiling;
|
|
22625
22761
|
const lineCount = countLines(prefix);
|
|
22626
|
-
const
|
|
22627
|
-
|
|
22628
|
-
|
|
22762
|
+
const totalLabel2 = bounded2 ? `${lineCount}+` : `${lineCount}`;
|
|
22763
|
+
const header = `[${totalLabel2} lines]`;
|
|
22764
|
+
const unshaped = prefix === "" ? header : `${header}
|
|
22765
|
+
${prefix}`;
|
|
22766
|
+
const result2 = applyCapCut({
|
|
22767
|
+
header,
|
|
22768
|
+
lines: splitModelLines(prefix),
|
|
22769
|
+
firstLine: 1,
|
|
22770
|
+
totalLabel: totalLabel2,
|
|
22771
|
+
limitStopFooter: "",
|
|
22772
|
+
unshapedBody: unshaped,
|
|
22773
|
+
maxBytes: ctx.maxBytes,
|
|
22774
|
+
maxLines: MODEL_MAX_LINES
|
|
22775
|
+
});
|
|
22776
|
+
return { content: result2.content };
|
|
22629
22777
|
}
|
|
22630
22778
|
let offset = 1;
|
|
22631
22779
|
if (hasOffset) {
|
|
@@ -22643,25 +22791,38 @@ ${prefix}` };
|
|
|
22643
22791
|
}
|
|
22644
22792
|
const body = await readPrefix(target, ctx.maxFileBytes);
|
|
22645
22793
|
const bounded = Buffer.byteLength(body, "utf8") > ctx.maxFileBytes;
|
|
22646
|
-
const
|
|
22647
|
-
`);
|
|
22648
|
-
const lines = trailingNewline ? body.slice(0, -1).split(`
|
|
22649
|
-
`) : body.split(`
|
|
22650
|
-
`);
|
|
22651
|
-
const totalLines = lines.length;
|
|
22794
|
+
const totalLines = countLines(body);
|
|
22652
22795
|
const totalLabel = bounded ? `${totalLines}+` : `${totalLines}`;
|
|
22653
22796
|
if (offset > totalLines) {
|
|
22654
22797
|
return {
|
|
22655
22798
|
content: bounded ? `offset ${offset} is past the first ${totalLines} lines, which is all that could be read within the ${ctx.maxFileBytes}-byte ceiling` : `offset ${offset} is past the end of the file -- it has ${totalLines} lines`
|
|
22656
22799
|
};
|
|
22657
22800
|
}
|
|
22801
|
+
const lines = splitModelLines(body);
|
|
22658
22802
|
const startIndex = offset - 1;
|
|
22659
22803
|
const endLine = limit === undefined ? totalLines : Math.min(startIndex + limit, totalLines);
|
|
22660
22804
|
const selected = lines.slice(startIndex, endLine).join(`
|
|
22661
22805
|
`);
|
|
22662
|
-
const
|
|
22663
|
-
|
|
22664
|
-
|
|
22806
|
+
const headerLine = `[lines ${offset}-${endLine} of ${totalLabel}]`;
|
|
22807
|
+
const limitStop = shouldAppendLimitStopFooter(limit !== undefined, endLine, totalLines) ? limitStopFooter({
|
|
22808
|
+
nextOffset: endLine + 1,
|
|
22809
|
+
totalIsFloor: bounded,
|
|
22810
|
+
endLine,
|
|
22811
|
+
totalLines
|
|
22812
|
+
}) : "";
|
|
22813
|
+
const unshapedBody = `${headerLine}
|
|
22814
|
+
${selected}`;
|
|
22815
|
+
const result = applyCapCut({
|
|
22816
|
+
header: headerLine,
|
|
22817
|
+
lines: lines.slice(startIndex, endLine),
|
|
22818
|
+
firstLine: offset,
|
|
22819
|
+
totalLabel,
|
|
22820
|
+
limitStopFooter: limitStop,
|
|
22821
|
+
unshapedBody,
|
|
22822
|
+
maxBytes: ctx.maxBytes,
|
|
22823
|
+
maxLines: MODEL_MAX_LINES
|
|
22824
|
+
});
|
|
22825
|
+
return { content: result.content };
|
|
22665
22826
|
} catch (err) {
|
|
22666
22827
|
return { content: err instanceof Error ? err.message : String(err), isError: true };
|
|
22667
22828
|
}
|
|
@@ -23563,15 +23724,36 @@ var init_types3 = __esm(() => {
|
|
|
23563
23724
|
});
|
|
23564
23725
|
|
|
23565
23726
|
// src/command-safety/rule-scorer.ts
|
|
23566
|
-
|
|
23727
|
+
import { posix } from "path";
|
|
23728
|
+
function escapeRegExp(text) {
|
|
23729
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
23730
|
+
}
|
|
23731
|
+
function usableRoot(root) {
|
|
23732
|
+
if (root === undefined || !root.startsWith("/"))
|
|
23733
|
+
return;
|
|
23734
|
+
const normalized = posix.normalize(root).replace(/\/+$/, "");
|
|
23735
|
+
return normalized.split("/").filter(Boolean).length >= MIN_ROOT_SEGMENTS ? normalized : undefined;
|
|
23736
|
+
}
|
|
23737
|
+
function maskProjectRoot(command, root) {
|
|
23738
|
+
const usable = usableRoot(root);
|
|
23739
|
+
if (usable === undefined)
|
|
23740
|
+
return command;
|
|
23741
|
+
const underRoot = new RegExp(`(?<=^|[${PATH_END}=:])${escapeRegExp(usable)}((?:/[^${PATH_END}]*)?)(?=$|[${PATH_END}])`, "g");
|
|
23742
|
+
return command.replace(underRoot, (match, rest, offset) => {
|
|
23743
|
+
CLEAN_TAIL.lastIndex = offset + match.length;
|
|
23744
|
+
return /\.\.|\\|,/.test(rest) || !CLEAN_TAIL.test(command) ? match : `.${rest}`;
|
|
23745
|
+
});
|
|
23746
|
+
}
|
|
23747
|
+
function scoreRules(command, context = {}) {
|
|
23567
23748
|
try {
|
|
23568
|
-
const
|
|
23749
|
+
const masked = maskProjectRoot(command, context.root);
|
|
23750
|
+
const hits = Object.fromEntries(QUESTION_IDS.map((id) => [id, RULES[id].some((re) => re.test(id === "outside_project" ? masked : command))]));
|
|
23569
23751
|
return { version: RULE_SET_VERSION, hits };
|
|
23570
23752
|
} catch (err) {
|
|
23571
23753
|
return { version: RULE_SET_VERSION, hits: NO_HITS, error: errorMessage(err) };
|
|
23572
23754
|
}
|
|
23573
23755
|
}
|
|
23574
|
-
var RULE_SET_VERSION =
|
|
23756
|
+
var RULE_SET_VERSION = 2, RULES, NO_HITS, PATH_END, CLEAN_TAIL, MIN_ROOT_SEGMENTS = 2;
|
|
23575
23757
|
var init_rule_scorer = __esm(() => {
|
|
23576
23758
|
init_types3();
|
|
23577
23759
|
RULES = {
|
|
@@ -23617,6 +23799,8 @@ var init_rule_scorer = __esm(() => {
|
|
|
23617
23799
|
privilege: [/(?:^|[\s;&|(])(?:sudo|doas)\s/, /\b(?:chmod|chown|chgrp)\b/]
|
|
23618
23800
|
};
|
|
23619
23801
|
NO_HITS = Object.freeze(Object.fromEntries(QUESTION_IDS.map((id) => [id, false])));
|
|
23802
|
+
PATH_END = String.raw`\s'"\`;&|<>()`;
|
|
23803
|
+
CLEAN_TAIL = /['")]*(?=$|[\s;&|<>])/y;
|
|
23620
23804
|
});
|
|
23621
23805
|
|
|
23622
23806
|
// src/command-safety/shadow.ts
|
|
@@ -23664,6 +23848,7 @@ function createCommandShadow(opts) {
|
|
|
23664
23848
|
const { obs } = entry;
|
|
23665
23849
|
const r = model.result;
|
|
23666
23850
|
const cwd = entry.run?.cwd ?? obs.cwd;
|
|
23851
|
+
const rules = cwd !== obs.cwd ? scoreRules(obs.command, { root: cwd }) : entry.rules;
|
|
23667
23852
|
return {
|
|
23668
23853
|
at: _commandShadowDeps.now(),
|
|
23669
23854
|
runId: opts.runId,
|
|
@@ -23676,7 +23861,7 @@ function createCommandShadow(opts) {
|
|
|
23676
23861
|
...cwd !== undefined ? { cwd } : {},
|
|
23677
23862
|
mechanical: obs.mechanical,
|
|
23678
23863
|
outcome,
|
|
23679
|
-
rules
|
|
23864
|
+
rules,
|
|
23680
23865
|
...callIdentifiers(obs),
|
|
23681
23866
|
model: {
|
|
23682
23867
|
status: model.cached && r.status === "answered" ? "cached" : r.status,
|
|
@@ -23694,7 +23879,7 @@ function createCommandShadow(opts) {
|
|
|
23694
23879
|
try {
|
|
23695
23880
|
if (entries.has(key))
|
|
23696
23881
|
return;
|
|
23697
|
-
const entry = { obs, rules: scoreRules(obs.command), written: false };
|
|
23882
|
+
const entry = { obs, rules: scoreRules(obs.command, { root: obs.cwd }), written: false };
|
|
23698
23883
|
entries.set(key, entry);
|
|
23699
23884
|
const { promise: promise2, cached: cached2 } = classifyCached(obs.command);
|
|
23700
23885
|
track(inFlight2, promise2.then((result) => {
|
|
@@ -24152,7 +24337,7 @@ var init_scratchpad = __esm(() => {
|
|
|
24152
24337
|
init_truncate();
|
|
24153
24338
|
scratchpadWriteTool = {
|
|
24154
24339
|
name: "ScratchpadWrite",
|
|
24155
|
-
description: "Write a throwaway file to your scratchpad at .nax/scratchpad/. Use it for notes to yourself, command output you want to re-read, or
|
|
24340
|
+
description: "Write a throwaway file to your scratchpad at .nax/scratchpad/. Use it for notes to yourself, command output you want to re-read, intermediate lists, or a probe script to run against the project's code. It is never committed and is wiped when a run finishes (a failed run's scratchpad is retained for inspection until the next run starts and clears it). Paths are relative to the scratchpad and cannot reach the repository.",
|
|
24156
24341
|
inputSchema: {
|
|
24157
24342
|
type: "object",
|
|
24158
24343
|
properties: {
|
|
@@ -24394,33 +24579,97 @@ var init_spill = __esm(() => {
|
|
|
24394
24579
|
// src/tools/tool-audit.ts
|
|
24395
24580
|
import { mkdir as mkdir7, writeFile as writeFile5 } from "fs/promises";
|
|
24396
24581
|
import { join as join15 } from "path";
|
|
24582
|
+
function registerToolAuditSink(runId, sink) {
|
|
24583
|
+
const sinks = openToolAuditSinks.get(runId);
|
|
24584
|
+
if (sinks === undefined) {
|
|
24585
|
+
openToolAuditSinks.set(runId, new Set([sink]));
|
|
24586
|
+
return;
|
|
24587
|
+
}
|
|
24588
|
+
sinks.add(sink);
|
|
24589
|
+
}
|
|
24590
|
+
function unregisterToolAuditSink(runId, sink) {
|
|
24591
|
+
const sinks = openToolAuditSinks.get(runId);
|
|
24592
|
+
if (sinks === undefined)
|
|
24593
|
+
return;
|
|
24594
|
+
sinks.delete(sink);
|
|
24595
|
+
if (sinks.size === 0)
|
|
24596
|
+
openToolAuditSinks.delete(runId);
|
|
24597
|
+
}
|
|
24598
|
+
async function flushOpenToolAuditSinks(runId) {
|
|
24599
|
+
const sinks = openToolAuditSinks.get(runId);
|
|
24600
|
+
if (sinks === undefined)
|
|
24601
|
+
return;
|
|
24602
|
+
openToolAuditSinks.delete(runId);
|
|
24603
|
+
await Promise.all([...sinks].map(async (sink) => {
|
|
24604
|
+
try {
|
|
24605
|
+
await sink.flushPartial();
|
|
24606
|
+
} catch (error48) {
|
|
24607
|
+
getSafeLogger()?.warn("tools", "tool-audit partial flush failed", { runId, error: errorMessage(error48) });
|
|
24608
|
+
}
|
|
24609
|
+
}));
|
|
24610
|
+
}
|
|
24397
24611
|
function createNoOpToolAuditSink() {
|
|
24398
24612
|
return { record() {}, async flush() {} };
|
|
24399
24613
|
}
|
|
24614
|
+
function nextFileStamp() {
|
|
24615
|
+
const now = Date.now();
|
|
24616
|
+
lastFileStamp = now > lastFileStamp ? now : lastFileStamp + 1;
|
|
24617
|
+
return lastFileStamp;
|
|
24618
|
+
}
|
|
24400
24619
|
function createToolAuditSink(opts) {
|
|
24401
24620
|
const calls = [];
|
|
24402
|
-
|
|
24621
|
+
const runId = opts.header?.runId;
|
|
24622
|
+
let partialFlushed = false;
|
|
24623
|
+
const write = async (partial2) => {
|
|
24624
|
+
if (calls.length === 0)
|
|
24625
|
+
return;
|
|
24626
|
+
await mkdir7(opts.dir, { recursive: true });
|
|
24627
|
+
const body = JSON.stringify({
|
|
24628
|
+
schemaVersion: TOOL_AUDIT_SCHEMA_VERSION,
|
|
24629
|
+
...opts.header ?? {},
|
|
24630
|
+
sessionName: opts.sessionName,
|
|
24631
|
+
...partial2 ? { partial: true } : {},
|
|
24632
|
+
calls: redactRowStrings(calls)
|
|
24633
|
+
}, null, 2);
|
|
24634
|
+
const prefix = runId !== undefined ? `${runId}-` : "";
|
|
24635
|
+
await writeFile5(join15(opts.dir, `${prefix}${nextFileStamp()}-${opts.sessionName}.json`), body);
|
|
24636
|
+
};
|
|
24637
|
+
const sink = {
|
|
24403
24638
|
record(entry) {
|
|
24639
|
+
if (partialFlushed) {
|
|
24640
|
+
getSafeLogger()?.warn("tools", "tool-audit row recorded after the partial flush was dropped", {
|
|
24641
|
+
runId,
|
|
24642
|
+
tool: entry.tool
|
|
24643
|
+
});
|
|
24644
|
+
return;
|
|
24645
|
+
}
|
|
24404
24646
|
calls.push(entry);
|
|
24405
24647
|
},
|
|
24648
|
+
async flushPartial() {
|
|
24649
|
+
if (partialFlushed)
|
|
24650
|
+
return;
|
|
24651
|
+
await write(true);
|
|
24652
|
+
partialFlushed = true;
|
|
24653
|
+
if (runId !== undefined)
|
|
24654
|
+
unregisterToolAuditSink(runId, sink);
|
|
24655
|
+
},
|
|
24406
24656
|
async flush() {
|
|
24407
|
-
if (
|
|
24657
|
+
if (partialFlushed)
|
|
24408
24658
|
return;
|
|
24409
|
-
|
|
24410
|
-
|
|
24411
|
-
|
|
24412
|
-
...opts.header ?? {},
|
|
24413
|
-
sessionName: opts.sessionName,
|
|
24414
|
-
calls: redactRowStrings(calls)
|
|
24415
|
-
}, null, 2);
|
|
24416
|
-
const prefix = opts.header?.runId !== undefined ? `${opts.header.runId}-` : "";
|
|
24417
|
-
await writeFile5(join15(opts.dir, `${prefix}${Date.now()}-${opts.sessionName}.json`), body);
|
|
24659
|
+
if (runId !== undefined)
|
|
24660
|
+
unregisterToolAuditSink(runId, sink);
|
|
24661
|
+
await write(false);
|
|
24418
24662
|
}
|
|
24419
24663
|
};
|
|
24664
|
+
if (runId !== undefined)
|
|
24665
|
+
registerToolAuditSink(runId, sink);
|
|
24666
|
+
return sink;
|
|
24420
24667
|
}
|
|
24421
|
-
var TOOL_AUDIT_SCHEMA_VERSION = 1;
|
|
24668
|
+
var openToolAuditSinks, TOOL_AUDIT_SCHEMA_VERSION = 1, lastFileStamp = 0;
|
|
24422
24669
|
var init_tool_audit = __esm(() => {
|
|
24670
|
+
init_logger2();
|
|
24423
24671
|
init_permissions();
|
|
24672
|
+
openToolAuditSinks = new Map;
|
|
24424
24673
|
});
|
|
24425
24674
|
|
|
24426
24675
|
// src/tools/write.ts
|
|
@@ -24524,6 +24773,7 @@ function createCodingToolRuntime(opts) {
|
|
|
24524
24773
|
...audit?.target !== undefined ? { target: audit.target } : {},
|
|
24525
24774
|
...audit?.approval !== undefined ? { approval: audit.approval } : {},
|
|
24526
24775
|
...audit?.sandbox !== undefined ? { sandbox: audit.sandbox } : {},
|
|
24776
|
+
...audit?.exitCode !== undefined ? { exitCode: audit.exitCode } : {},
|
|
24527
24777
|
...provider !== undefined ? { provider } : {},
|
|
24528
24778
|
...resultBytesPreTruncation !== undefined ? { resultBytesPreTruncation } : {},
|
|
24529
24779
|
...opts.callId !== undefined ? { callId: opts.callId } : {},
|
|
@@ -24629,6 +24879,7 @@ function createCodingToolRuntime(opts) {
|
|
|
24629
24879
|
tool: policyIdentity,
|
|
24630
24880
|
stage: opts.pipelineStage ?? "unknown",
|
|
24631
24881
|
rule: verdict.rule ?? verdict.reason,
|
|
24882
|
+
...verdict.rule !== undefined ? { matchedRule: verdict.rule } : {},
|
|
24632
24883
|
summary: ask.summary,
|
|
24633
24884
|
...ask.unshowable ? { unshowable: true } : {},
|
|
24634
24885
|
...typeof input[tool.scope.commandField ?? ""] === "string" ? { command: input[tool.scope.commandField] } : {},
|
|
@@ -25557,7 +25808,9 @@ var init_config_guards = __esm(() => {
|
|
|
25557
25808
|
"review.gateLLMChecksOnMechanicalPass": "LLM review checks are sequenced by the story orchestrator; this key never had an effect after #1859",
|
|
25558
25809
|
debate: "the multi-agent debate subsystem was removed; a config that enabled debate.stages.plan without setting plan.mode was resolving to the debate plan strategy and now plans with `single` \u2014 set plan.mode explicitly to `single` or `refine`",
|
|
25559
25810
|
"plan.citationThreshold": "this key only fed the removed pipeline plan mode",
|
|
25560
|
-
"plan.criticModel": "this key only fed the removed pipeline plan mode"
|
|
25811
|
+
"plan.criticModel": "this key only fed the removed pipeline plan mode",
|
|
25812
|
+
"quality.autofix.enforceTestWriterIsolation": "the mock-structure handoff path this key guarded was removed in #1084; the key has had no effect since",
|
|
25813
|
+
"prompts.overrides.single-session": "the single-session prompt role is not used by any run since fb3cfad3e; test-after stories use the tdd-simple role, so override tdd-simple instead"
|
|
25561
25814
|
};
|
|
25562
25815
|
});
|
|
25563
25816
|
|
|
@@ -26727,12 +26980,10 @@ var init_schemas_execution = __esm(() => {
|
|
|
26727
26980
|
}).default({ format: "auto" }),
|
|
26728
26981
|
autofix: exports_external.object({
|
|
26729
26982
|
enabled: exports_external.boolean().default(true),
|
|
26730
|
-
maxAttempts: exports_external.number().int().min(1).default(3)
|
|
26731
|
-
enforceTestWriterIsolation: exports_external.boolean().default(true)
|
|
26983
|
+
maxAttempts: exports_external.number().int().min(1).default(3)
|
|
26732
26984
|
}).default({
|
|
26733
26985
|
enabled: true,
|
|
26734
|
-
maxAttempts: 3
|
|
26735
|
-
enforceTestWriterIsolation: true
|
|
26986
|
+
maxAttempts: 3
|
|
26736
26987
|
}),
|
|
26737
26988
|
forceExit: exports_external.boolean().default(false),
|
|
26738
26989
|
detectOpenHandles: exports_external.boolean().default(true),
|
|
@@ -26799,9 +27050,10 @@ var init_schemas_execution = __esm(() => {
|
|
|
26799
27050
|
});
|
|
26800
27051
|
|
|
26801
27052
|
// src/config/schemas-infra.ts
|
|
26802
|
-
var PlanConfigSchema, AcceptanceFixConfigSchema, AcceptanceConfigSchema, LlmRoutingConfigSchema, AgentRoutingProfileSchema, AgentRoutingConfigSchema, RoutingConfigSchema, OptimizerConfigSchema, PluginConfigEntrySchema, HooksConfigSchema, InteractionConfigSchema, StorySizeGateConfigSchema, PromptAuditConfigSchema, UsageAuditConfigSchema, FallbackTargetSchema, AgentFallbackConfigSchema, DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG, AgentIdleWatchdogConfigSchema, DEFAULT_AGENT_SPIN_BREAKER_CONFIG, AgentSpinBreakerConfigSchema, AgentAcpConfigSchema, AgentNativeTransportRetryConfigSchema, AgentNativeConfigSchema, AgentTimeoutRetryConfigSchema, DEFAULT_AGENT_TIMEOUT_RETRY_CONFIG, AgentConfigSchema, PrecheckConfigSchema, PromptsConfigSchema, ProjectProfileSchema, VALID_AGENT_TYPES, GenerateConfigSchema, CuratorThresholdsSchema, CuratorRetentionConfigSchema, CuratorConfigSchema;
|
|
27053
|
+
var PlanConfigSchema, AcceptanceFixConfigSchema, AcceptanceConfigSchema, LlmRoutingConfigSchema, AgentRoutingProfileSchema, AgentRoutingConfigSchema, RoutingConfigSchema, OptimizerConfigSchema, PluginConfigEntrySchema, HooksConfigSchema, InteractionConfigSchema, StorySizeGateConfigSchema, PromptAuditConfigSchema, UsageAuditConfigSchema, FallbackTargetSchema, AgentFallbackConfigSchema, DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG, AgentIdleWatchdogConfigSchema, DEFAULT_AGENT_SPIN_BREAKER_CONFIG, AgentSpinBreakerConfigSchema, AgentAcpConfigSchema, AgentNativeTransportRetryConfigSchema, AgentNativeConfigSchema, AgentTimeoutRetryConfigSchema, DEFAULT_AGENT_TIMEOUT_RETRY_CONFIG, AgentConfigSchema, PrecheckConfigSchema, PROMPT_OVERRIDE_ROLES, PromptsConfigSchema, ProjectProfileSchema, VALID_AGENT_TYPES, GenerateConfigSchema, CuratorThresholdsSchema, CuratorRetentionConfigSchema, CuratorConfigSchema;
|
|
26803
27054
|
var init_schemas_infra = __esm(() => {
|
|
26804
27055
|
init_zod();
|
|
27056
|
+
init_agent_defaults();
|
|
26805
27057
|
init_schemas_model();
|
|
26806
27058
|
PlanConfigSchema = exports_external.object({
|
|
26807
27059
|
model: ConfiguredModelSchema,
|
|
@@ -27021,8 +27273,8 @@ var init_schemas_infra = __esm(() => {
|
|
|
27021
27273
|
budgetMultiplier: 0.5
|
|
27022
27274
|
};
|
|
27023
27275
|
AgentConfigSchema = exports_external.object({
|
|
27024
|
-
protocol: exports_external.enum(["acp", "native", "hybrid"]).default(
|
|
27025
|
-
default: exports_external.string().trim().min(1, "agent.default must be non-empty").default(
|
|
27276
|
+
protocol: exports_external.enum(["acp", "native", "hybrid"]).default(DEFAULT_AGENT_PROTOCOL),
|
|
27277
|
+
default: exports_external.string().trim().min(1, "agent.default must be non-empty").default(DEFAULT_AGENT_NAME),
|
|
27026
27278
|
maxInteractionTurns: exports_external.number().int().min(1).max(100).default(20),
|
|
27027
27279
|
promptAudit: PromptAuditConfigSchema.default({ enabled: false }),
|
|
27028
27280
|
usageAudit: UsageAuditConfigSchema.default({ enabled: false }),
|
|
@@ -27049,10 +27301,19 @@ var init_schemas_infra = __esm(() => {
|
|
|
27049
27301
|
PrecheckConfigSchema = exports_external.object({
|
|
27050
27302
|
storySizeGate: StorySizeGateConfigSchema
|
|
27051
27303
|
});
|
|
27304
|
+
PROMPT_OVERRIDE_ROLES = ["no-test", "test-writer", "implementer", "verifier", "tdd-simple"];
|
|
27052
27305
|
PromptsConfigSchema = exports_external.object({
|
|
27053
|
-
overrides: exports_external.record(exports_external.string().
|
|
27054
|
-
|
|
27055
|
-
|
|
27306
|
+
overrides: exports_external.record(exports_external.string(), exports_external.string().min(1, "Override path must be non-empty")).superRefine((overrides, ctx) => {
|
|
27307
|
+
for (const key of Object.keys(overrides)) {
|
|
27308
|
+
if (!PROMPT_OVERRIDE_ROLES.includes(key)) {
|
|
27309
|
+
ctx.addIssue({
|
|
27310
|
+
code: "custom",
|
|
27311
|
+
message: `Role must be one of: ${PROMPT_OVERRIDE_ROLES.join(", ")}`,
|
|
27312
|
+
path: [key]
|
|
27313
|
+
});
|
|
27314
|
+
}
|
|
27315
|
+
}
|
|
27316
|
+
}).optional(),
|
|
27056
27317
|
behavioralGuardrails: exports_external.enum(["off", "lite", "strict"]).default("lite")
|
|
27057
27318
|
});
|
|
27058
27319
|
ProjectProfileSchema = exports_external.object({
|
|
@@ -27101,19 +27362,29 @@ var init_schemas_infra = __esm(() => {
|
|
|
27101
27362
|
function asModelDef(entry) {
|
|
27102
27363
|
return typeof entry === "object" && entry !== null ? entry : null;
|
|
27103
27364
|
}
|
|
27365
|
+
function declaredModelAgents(models) {
|
|
27366
|
+
return Object.entries(models ?? {}).filter(([agent, entry]) => !isBuiltInModelMap(agent, entry)).map(([agent]) => agent);
|
|
27367
|
+
}
|
|
27104
27368
|
function validateProtocolGate(data, ctx) {
|
|
27105
|
-
const protocol = data.agent?.protocol ??
|
|
27106
|
-
const modelAgents =
|
|
27107
|
-
if (protocol ===
|
|
27369
|
+
const protocol = data.agent?.protocol ?? DEFAULT_AGENT_PROTOCOL;
|
|
27370
|
+
const modelAgents = declaredModelAgents(data.models);
|
|
27371
|
+
if (protocol === "acp" && (data.agent?.default ?? DEFAULT_AGENT_NAME) === NATIVE_AGENT_NAME) {
|
|
27108
27372
|
ctx.addIssue({
|
|
27109
27373
|
code: "custom",
|
|
27110
|
-
path: ["
|
|
27374
|
+
path: ["agent", "default"],
|
|
27375
|
+
message: 'agent.protocol "acp" cannot reach agent.default "native", which is also the built-in default when agent.default is unset. Set agent.default to an acpx agent such as "claude", or use agent.protocol "hybrid".'
|
|
27376
|
+
});
|
|
27377
|
+
}
|
|
27378
|
+
if (protocol === "acp" && modelAgents.includes(NATIVE_AGENT_NAME)) {
|
|
27379
|
+
ctx.addIssue({
|
|
27380
|
+
code: "custom",
|
|
27381
|
+
path: ["models", NATIVE_AGENT_NAME],
|
|
27111
27382
|
message: 'models.native requires agent.protocol "hybrid" or "native" (it is "acp"). Set agent.protocol, or remove the native entry.'
|
|
27112
27383
|
});
|
|
27113
27384
|
}
|
|
27114
|
-
if (protocol ===
|
|
27385
|
+
if (protocol === NATIVE_AGENT_NAME) {
|
|
27115
27386
|
for (const agent of modelAgents) {
|
|
27116
|
-
if (agent ===
|
|
27387
|
+
if (agent === NATIVE_AGENT_NAME)
|
|
27117
27388
|
continue;
|
|
27118
27389
|
ctx.addIssue({
|
|
27119
27390
|
code: "custom",
|
|
@@ -27121,7 +27392,7 @@ function validateProtocolGate(data, ctx) {
|
|
|
27121
27392
|
message: `agent.protocol "native" permits only models.native; "${agent}" is an acpx agent. Use "hybrid" to run both.`
|
|
27122
27393
|
});
|
|
27123
27394
|
}
|
|
27124
|
-
if ((data.agent?.default ??
|
|
27395
|
+
if ((data.agent?.default ?? DEFAULT_AGENT_NAME) !== NATIVE_AGENT_NAME) {
|
|
27125
27396
|
ctx.addIssue({
|
|
27126
27397
|
code: "custom",
|
|
27127
27398
|
path: ["agent", "default"],
|
|
@@ -27133,7 +27404,7 @@ function validateProtocolGate(data, ctx) {
|
|
|
27133
27404
|
validateFallbackLadderAgents(data, ctx);
|
|
27134
27405
|
}
|
|
27135
27406
|
function validateNativeModelIds(data, ctx) {
|
|
27136
|
-
for (const [tier, entry] of Object.entries(data.models?.[
|
|
27407
|
+
for (const [tier, entry] of Object.entries(data.models?.[NATIVE_AGENT_NAME] ?? {})) {
|
|
27137
27408
|
if (entry === undefined)
|
|
27138
27409
|
continue;
|
|
27139
27410
|
const def = asModelDef(entry);
|
|
@@ -27145,8 +27416,8 @@ function validateNativeModelIds(data, ctx) {
|
|
|
27145
27416
|
const sibling = def && typeof def.provider === "string" ? def.provider.trim() : "";
|
|
27146
27417
|
ctx.addIssue({
|
|
27147
27418
|
code: "custom",
|
|
27148
|
-
path: ["models",
|
|
27149
|
-
message: sibling.length > 0 ? `models.${
|
|
27419
|
+
path: ["models", NATIVE_AGENT_NAME, tier, ...def ? ["model"] : []],
|
|
27420
|
+
message: sibling.length > 0 ? `models.${NATIVE_AGENT_NAME}.${tier}.model "${modelId}" must be written "provider/model". The sibling "provider" field is not used on the native path \u2014 put it in the model id: "${sibling}/${modelId}".` : `models.${NATIVE_AGENT_NAME}.${tier} "${modelId}" must be written "provider/model" (e.g. "openai/gpt-5.4-mini"). There is no default provider.`
|
|
27150
27421
|
});
|
|
27151
27422
|
}
|
|
27152
27423
|
}
|
|
@@ -27161,12 +27432,12 @@ function rungAgent(value) {
|
|
|
27161
27432
|
return;
|
|
27162
27433
|
}
|
|
27163
27434
|
function validateFallbackLadderAgents(data, ctx) {
|
|
27164
|
-
const protocol = data.agent?.protocol ??
|
|
27435
|
+
const protocol = data.agent?.protocol ?? DEFAULT_AGENT_PROTOCOL;
|
|
27165
27436
|
if (protocol === "hybrid")
|
|
27166
27437
|
return;
|
|
27167
27438
|
const map2 = data.agent?.fallback?.map ?? {};
|
|
27168
27439
|
const reject = (agent, path) => {
|
|
27169
|
-
const permitted = protocol ===
|
|
27440
|
+
const permitted = protocol === NATIVE_AGENT_NAME ? `only "${NATIVE_AGENT_NAME}"` : `no native agent`;
|
|
27170
27441
|
ctx.addIssue({
|
|
27171
27442
|
code: "custom",
|
|
27172
27443
|
path,
|
|
@@ -27174,7 +27445,7 @@ function validateFallbackLadderAgents(data, ctx) {
|
|
|
27174
27445
|
});
|
|
27175
27446
|
};
|
|
27176
27447
|
for (const [from, rungs] of Object.entries(map2)) {
|
|
27177
|
-
const offending = (agent) => protocol ===
|
|
27448
|
+
const offending = (agent) => protocol === NATIVE_AGENT_NAME ? agent !== NATIVE_AGENT_NAME : agent === NATIVE_AGENT_NAME;
|
|
27178
27449
|
if (offending(from))
|
|
27179
27450
|
reject(from, ["agent", "fallback", "map", from]);
|
|
27180
27451
|
(rungs ?? []).forEach((rung, index) => {
|
|
@@ -27184,9 +27455,9 @@ function validateFallbackLadderAgents(data, ctx) {
|
|
|
27184
27455
|
});
|
|
27185
27456
|
}
|
|
27186
27457
|
}
|
|
27187
|
-
var NATIVE = "native", DEFAULT_PROTOCOL = "acp", DEFAULT_AGENT = "claude";
|
|
27188
27458
|
var init_schemas_protocol_gate = __esm(() => {
|
|
27189
27459
|
init_model_spec();
|
|
27460
|
+
init_agent_defaults();
|
|
27190
27461
|
});
|
|
27191
27462
|
|
|
27192
27463
|
// src/config/schemas-reporters.ts
|
|
@@ -27350,6 +27621,7 @@ var init_schemas_review = __esm(() => {
|
|
|
27350
27621
|
var NaxConfigSchema;
|
|
27351
27622
|
var init_schemas3 = __esm(() => {
|
|
27352
27623
|
init_zod();
|
|
27624
|
+
init_agent_defaults();
|
|
27353
27625
|
init_bash_approval();
|
|
27354
27626
|
init_schema_types();
|
|
27355
27627
|
init_schemas_context();
|
|
@@ -27379,13 +27651,7 @@ var init_schemas3 = __esm(() => {
|
|
|
27379
27651
|
message: "outputDir must be absolute or start with ~/"
|
|
27380
27652
|
}),
|
|
27381
27653
|
version: exports_external.number().default(1),
|
|
27382
|
-
models: ModelMapSchema.default(
|
|
27383
|
-
claude: {
|
|
27384
|
-
fast: "haiku",
|
|
27385
|
-
balanced: "sonnet",
|
|
27386
|
-
powerful: "opus"
|
|
27387
|
-
}
|
|
27388
|
-
}),
|
|
27654
|
+
models: ModelMapSchema.default(structuredClone(DEFAULT_MODEL_MAPS)),
|
|
27389
27655
|
autoMode: AutoModeConfigSchema.default({
|
|
27390
27656
|
enabled: true,
|
|
27391
27657
|
complexityRouting: {
|
|
@@ -27423,7 +27689,7 @@ var init_schemas3 = __esm(() => {
|
|
|
27423
27689
|
agents: { enabled: true, strategy: "off", profiles: [] }
|
|
27424
27690
|
}),
|
|
27425
27691
|
execution: ExecutionConfigSchema.default({
|
|
27426
|
-
maxIterations:
|
|
27692
|
+
maxIterations: 20,
|
|
27427
27693
|
iterationDelayMs: 2000,
|
|
27428
27694
|
costLimit: 30,
|
|
27429
27695
|
sessionTimeoutSeconds: 3600,
|
|
@@ -27468,8 +27734,7 @@ var init_schemas3 = __esm(() => {
|
|
|
27468
27734
|
},
|
|
27469
27735
|
autofix: {
|
|
27470
27736
|
enabled: true,
|
|
27471
|
-
maxAttempts: 3
|
|
27472
|
-
enforceTestWriterIsolation: true
|
|
27737
|
+
maxAttempts: 3
|
|
27473
27738
|
},
|
|
27474
27739
|
forceExit: false,
|
|
27475
27740
|
detectOpenHandles: true,
|
|
@@ -27596,8 +27861,8 @@ var init_schemas3 = __esm(() => {
|
|
|
27596
27861
|
}
|
|
27597
27862
|
}),
|
|
27598
27863
|
agent: AgentConfigSchema.optional().default({
|
|
27599
|
-
protocol:
|
|
27600
|
-
default:
|
|
27864
|
+
protocol: DEFAULT_AGENT_PROTOCOL,
|
|
27865
|
+
default: DEFAULT_AGENT_NAME,
|
|
27601
27866
|
maxInteractionTurns: 20,
|
|
27602
27867
|
promptAudit: { enabled: false },
|
|
27603
27868
|
usageAudit: { enabled: false },
|
|
@@ -27699,7 +27964,7 @@ var init_schemas3 = __esm(() => {
|
|
|
27699
27964
|
for (const [pi, profile] of profiles.entries()) {
|
|
27700
27965
|
const { agent: pAgent, model: pModel } = profile.target;
|
|
27701
27966
|
const targetTier = MODEL_SHORTHAND_TIERS[pModel.toLowerCase()] ?? pModel;
|
|
27702
|
-
const namesTier = resolveTierMembership(data.models ?? {}, pAgent, targetTier, data.agent?.default ??
|
|
27967
|
+
const namesTier = resolveTierMembership(data.models ?? {}, pAgent, targetTier, data.agent?.default ?? DEFAULT_AGENT_NAME).isTier;
|
|
27703
27968
|
const hasMatchingRung = tierOrder.some((r) => r.tier === targetTier && r.agent === pAgent);
|
|
27704
27969
|
if (namesTier && !hasMatchingRung) {
|
|
27705
27970
|
ctx.addIssue({
|
|
@@ -28312,6 +28577,57 @@ function trackedSpawnDeadlines(config2) {
|
|
|
28312
28577
|
};
|
|
28313
28578
|
}
|
|
28314
28579
|
|
|
28580
|
+
// src/config/unreferenced-agent-models.ts
|
|
28581
|
+
function isPin(value) {
|
|
28582
|
+
return typeof value.agent === "string" && (("model" in value) || ("tier" in value));
|
|
28583
|
+
}
|
|
28584
|
+
function pinAgents(value, found) {
|
|
28585
|
+
if (Array.isArray(value)) {
|
|
28586
|
+
for (const item of value)
|
|
28587
|
+
pinAgents(item, found);
|
|
28588
|
+
return;
|
|
28589
|
+
}
|
|
28590
|
+
if (typeof value !== "object" || value === null)
|
|
28591
|
+
return;
|
|
28592
|
+
const record3 = value;
|
|
28593
|
+
if (isPin(record3))
|
|
28594
|
+
found.add(record3.agent);
|
|
28595
|
+
for (const child of Object.values(record3))
|
|
28596
|
+
pinAgents(child, found);
|
|
28597
|
+
}
|
|
28598
|
+
function fallbackAgents(config2) {
|
|
28599
|
+
const fallback = config2.agent?.fallback;
|
|
28600
|
+
if (fallback?.enabled !== true)
|
|
28601
|
+
return [];
|
|
28602
|
+
return Object.values(fallback.map ?? {}).flatMap((rungs) => (rungs ?? []).map((rung) => typeof rung === "string" ? rung : rung.agent));
|
|
28603
|
+
}
|
|
28604
|
+
function findUnreferencedAgentModels(config2, storyAgents = []) {
|
|
28605
|
+
const reached = new Set([
|
|
28606
|
+
config2.agent?.default ?? DEFAULT_AGENT_NAME,
|
|
28607
|
+
...fallbackAgents(config2),
|
|
28608
|
+
...storyAgents
|
|
28609
|
+
]);
|
|
28610
|
+
for (const [key, value] of Object.entries(config2)) {
|
|
28611
|
+
if (!SKIPPED_ROOT_KEYS.has(key))
|
|
28612
|
+
pinAgents(value, reached);
|
|
28613
|
+
}
|
|
28614
|
+
return Object.entries(config2.models ?? {}).filter(([agent, map2]) => agent !== NATIVE_AGENT_NAME && !isBuiltInModelMap(agent, map2) && !reached.has(agent)).map(([agent]) => agent);
|
|
28615
|
+
}
|
|
28616
|
+
function describeUnreferencedAgentModels(agents, config2) {
|
|
28617
|
+
const maps = agents.map((agent) => `models.${agent}`).join(", ");
|
|
28618
|
+
const head = `${maps} is declared but nothing dispatches to it: no agent.default, enabled fallback rung, pin, escalation rung, ` + `complexity route, routing profile or PRD story names ${agents.join(", ")}.`;
|
|
28619
|
+
if (config2.agent?.protocol === "native") {
|
|
28620
|
+
return `${head} Under agent.protocol "native" acpx agents cannot run; remove the map or use protocol "hybrid".`;
|
|
28621
|
+
}
|
|
28622
|
+
const defaultAgent = config2.agent?.default ?? DEFAULT_AGENT_NAME;
|
|
28623
|
+
return `${head} Unassigned work runs on agent.default "${defaultAgent}". ` + `Set agent.default "${agents[0]}" to run it, or reference it from a pin or fallback rung.`;
|
|
28624
|
+
}
|
|
28625
|
+
var SKIPPED_ROOT_KEYS;
|
|
28626
|
+
var init_unreferenced_agent_models = __esm(() => {
|
|
28627
|
+
init_agent_defaults();
|
|
28628
|
+
SKIPPED_ROOT_KEYS = new Set(["models", "agent"]);
|
|
28629
|
+
});
|
|
28630
|
+
|
|
28315
28631
|
// src/config/validate.ts
|
|
28316
28632
|
function validateConfig(config2) {
|
|
28317
28633
|
const errors3 = [];
|
|
@@ -28322,7 +28638,7 @@ function validateConfig(config2) {
|
|
|
28322
28638
|
if (!config2.models) {
|
|
28323
28639
|
errors3.push("models mapping is required");
|
|
28324
28640
|
} else {
|
|
28325
|
-
const defaultAgent = config2.agent?.default ??
|
|
28641
|
+
const defaultAgent = config2.agent?.default ?? DEFAULT_AGENT_NAME;
|
|
28326
28642
|
const agentModels = config2.models[defaultAgent];
|
|
28327
28643
|
if (!agentModels) {
|
|
28328
28644
|
errors3.push(`models.${defaultAgent} is required (default agent has no model map)`);
|
|
@@ -28370,13 +28686,13 @@ function validateConfig(config2) {
|
|
|
28370
28686
|
}
|
|
28371
28687
|
if (config2.models && config2.agent?.fallback?.map) {
|
|
28372
28688
|
const modelKeys = Object.keys(config2.models);
|
|
28373
|
-
const
|
|
28689
|
+
const fallbackAgents2 = new Set;
|
|
28374
28690
|
for (const [primary, candidates] of Object.entries(config2.agent.fallback.map)) {
|
|
28375
|
-
|
|
28691
|
+
fallbackAgents2.add(primary);
|
|
28376
28692
|
for (const c of candidates)
|
|
28377
|
-
|
|
28693
|
+
fallbackAgents2.add(typeof c === "string" ? c : c.agent);
|
|
28378
28694
|
}
|
|
28379
|
-
for (const agent of
|
|
28695
|
+
for (const agent of fallbackAgents2) {
|
|
28380
28696
|
if (!modelKeys.includes(agent)) {
|
|
28381
28697
|
errors3.push(`agent.fallback.map: agent "${agent}" is not a key in models (available: ${modelKeys.join(", ")})`);
|
|
28382
28698
|
} else {
|
|
@@ -28395,7 +28711,7 @@ function validateConfig(config2) {
|
|
|
28395
28711
|
errors3.push(`autoMode.escalation.tierOrder: tier "${tc.tier}" agent "${tc.agent}" is not a key in models (available: ${modelKeys.join(", ")})`);
|
|
28396
28712
|
}
|
|
28397
28713
|
if (tc.agent === undefined) {
|
|
28398
|
-
const owner = config2.agent?.default ??
|
|
28714
|
+
const owner = config2.agent?.default ?? DEFAULT_AGENT_NAME;
|
|
28399
28715
|
const ownerMap = config2.models[owner];
|
|
28400
28716
|
if (ownerMap && ownerMap[tc.tier] === undefined) {
|
|
28401
28717
|
errors3.push(`autoMode.escalation.tierOrder: tier "${tc.tier}" does not resolve under agent "${owner}" (the default agent)`);
|
|
@@ -28403,7 +28719,7 @@ function validateConfig(config2) {
|
|
|
28403
28719
|
}
|
|
28404
28720
|
}
|
|
28405
28721
|
}
|
|
28406
|
-
const defaultAgentKey = config2.agent?.default ??
|
|
28722
|
+
const defaultAgentKey = config2.agent?.default ?? DEFAULT_AGENT_NAME;
|
|
28407
28723
|
const complexities = ["simple", "medium", "complex", "expert"];
|
|
28408
28724
|
for (const complexity of complexities) {
|
|
28409
28725
|
const entry = config2.autoMode.complexityRouting[complexity];
|
|
@@ -28430,6 +28746,9 @@ function validateConfig(config2) {
|
|
|
28430
28746
|
errors: errors3
|
|
28431
28747
|
};
|
|
28432
28748
|
}
|
|
28749
|
+
var init_validate = __esm(() => {
|
|
28750
|
+
init_agent_defaults();
|
|
28751
|
+
});
|
|
28433
28752
|
|
|
28434
28753
|
// src/config/index.ts
|
|
28435
28754
|
var exports_config = {};
|
|
@@ -28448,6 +28767,8 @@ __export(exports_config, {
|
|
|
28448
28767
|
ContextV2ConfigSchema: () => ContextV2ConfigSchema,
|
|
28449
28768
|
CuratorRetentionConfigSchema: () => CuratorRetentionConfigSchema,
|
|
28450
28769
|
DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG: () => DEFAULT_AGENT_IDLE_WATCHDOG_CONFIG,
|
|
28770
|
+
DEFAULT_AGENT_NAME: () => DEFAULT_AGENT_NAME,
|
|
28771
|
+
DEFAULT_AGENT_PROTOCOL: () => DEFAULT_AGENT_PROTOCOL,
|
|
28451
28772
|
DEFAULT_AGENT_SPIN_BREAKER_CONFIG: () => DEFAULT_AGENT_SPIN_BREAKER_CONFIG,
|
|
28452
28773
|
DEFAULT_AGENT_TIMEOUT_RETRY_CONFIG: () => DEFAULT_AGENT_TIMEOUT_RETRY_CONFIG,
|
|
28453
28774
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
@@ -28460,6 +28781,7 @@ __export(exports_config, {
|
|
|
28460
28781
|
MODEL_SHORTHAND_TIERS: () => MODEL_SHORTHAND_TIERS,
|
|
28461
28782
|
McpConfigSchema: () => McpConfigSchema,
|
|
28462
28783
|
ModelTierSchema: () => ModelTierSchema,
|
|
28784
|
+
NATIVE_AGENT_NAME: () => NATIVE_AGENT_NAME,
|
|
28463
28785
|
NaxConfigSchema: () => NaxConfigSchema,
|
|
28464
28786
|
PROJECT_FEATURES_DIR: () => PROJECT_FEATURES_DIR,
|
|
28465
28787
|
PROJECT_NAX_DIR: () => PROJECT_NAX_DIR,
|
|
@@ -28489,17 +28811,20 @@ __export(exports_config, {
|
|
|
28489
28811
|
createConfigLoader: () => createConfigLoader,
|
|
28490
28812
|
decomposeConfigSelector: () => decomposeConfigSelector,
|
|
28491
28813
|
deepMergeConfig: () => deepMergeConfig,
|
|
28814
|
+
describeUnreferencedAgentModels: () => describeUnreferencedAgentModels,
|
|
28492
28815
|
executionGatesConfigSelector: () => executionGatesConfigSelector,
|
|
28493
28816
|
featureDir: () => featureDir,
|
|
28494
28817
|
featuresDir: () => featuresDir,
|
|
28495
28818
|
findInertBashStages: () => findInertBashStages,
|
|
28496
28819
|
findProjectDir: () => findProjectDir,
|
|
28820
|
+
findUnreferencedAgentModels: () => findUnreferencedAgentModels,
|
|
28497
28821
|
finishConfigSelector: () => finishConfigSelector,
|
|
28498
28822
|
getAcQualityRules: () => getAcQualityRules,
|
|
28499
28823
|
getProjectKey: () => getProjectKey,
|
|
28500
28824
|
globalConfigDir: () => globalConfigDir,
|
|
28501
28825
|
globalConfigPath: () => globalConfigPath,
|
|
28502
28826
|
interactionConfigSelector: () => interactionConfigSelector,
|
|
28827
|
+
isBuiltInModelMap: () => isBuiltInModelMap,
|
|
28503
28828
|
isSingleSessionTestOwningStrategy: () => isSingleSessionTestOwningStrategy,
|
|
28504
28829
|
isThreeSessionStrategy: () => isThreeSessionStrategy,
|
|
28505
28830
|
isUnrecognizedLiteralModel: () => isUnrecognizedLiteralModel,
|
|
@@ -28549,6 +28874,7 @@ __export(exports_config, {
|
|
|
28549
28874
|
verifyConfigSelector: () => verifyConfigSelector
|
|
28550
28875
|
});
|
|
28551
28876
|
var init_config = __esm(() => {
|
|
28877
|
+
init_agent_defaults();
|
|
28552
28878
|
init_bash_approval();
|
|
28553
28879
|
init_inert_bash_stages();
|
|
28554
28880
|
init_loader();
|
|
@@ -28570,6 +28896,8 @@ var init_config = __esm(() => {
|
|
|
28570
28896
|
init_schemas_sandbox();
|
|
28571
28897
|
init_selectors();
|
|
28572
28898
|
init_test_strategy();
|
|
28899
|
+
init_unreferenced_agent_models();
|
|
28900
|
+
init_validate();
|
|
28573
28901
|
});
|
|
28574
28902
|
|
|
28575
28903
|
// src/agents/native/credentials.ts
|
|
@@ -28744,6 +29072,32 @@ async function ambientShadows(providerIds) {
|
|
|
28744
29072
|
}));
|
|
28745
29073
|
return checked.filter((id) => id !== undefined);
|
|
28746
29074
|
}
|
|
29075
|
+
async function providersWithoutCredentials(providerIds) {
|
|
29076
|
+
const unique = [...new Set(providerIds)];
|
|
29077
|
+
let stored;
|
|
29078
|
+
try {
|
|
29079
|
+
stored = new Set((await listStoredProviders()).map((entry) => entry.providerId));
|
|
29080
|
+
} catch {
|
|
29081
|
+
return [];
|
|
29082
|
+
}
|
|
29083
|
+
const sweep = Promise.all(unique.filter((providerId) => !stored.has(providerId)).map(async (providerId) => {
|
|
29084
|
+
try {
|
|
29085
|
+
return await _authDeps.ambientAuthAvailable(providerId) ? undefined : providerId;
|
|
29086
|
+
} catch {
|
|
29087
|
+
return;
|
|
29088
|
+
}
|
|
29089
|
+
})).then((missing) => missing.filter((id) => id !== undefined));
|
|
29090
|
+
let timer;
|
|
29091
|
+
const expiry = new Promise((resolve15) => {
|
|
29092
|
+
timer = setTimeout(() => resolve15([]), AMBIENT_PROBE_TIMEOUT_MS);
|
|
29093
|
+
});
|
|
29094
|
+
try {
|
|
29095
|
+
return await Promise.race([sweep, expiry]);
|
|
29096
|
+
} finally {
|
|
29097
|
+
if (timer !== undefined)
|
|
29098
|
+
clearTimeout(timer);
|
|
29099
|
+
}
|
|
29100
|
+
}
|
|
28747
29101
|
async function anyAmbientCredential() {
|
|
28748
29102
|
let timer;
|
|
28749
29103
|
const sweep = (async () => {
|
|
@@ -28764,13 +29118,13 @@ async function anyAmbientCredential() {
|
|
|
28764
29118
|
});
|
|
28765
29119
|
})();
|
|
28766
29120
|
const expiry = new Promise((resolve15) => {
|
|
28767
|
-
timer = setTimeout(() => resolve15(true), AMBIENT_PROBE_TIMEOUT_MS);
|
|
29121
|
+
timer = _authDeps.setTimeout(() => resolve15(true), AMBIENT_PROBE_TIMEOUT_MS);
|
|
28768
29122
|
});
|
|
28769
29123
|
try {
|
|
28770
29124
|
return await Promise.race([sweep, expiry]);
|
|
28771
29125
|
} finally {
|
|
28772
29126
|
if (timer !== undefined)
|
|
28773
|
-
clearTimeout(timer);
|
|
29127
|
+
_authDeps.clearTimeout(timer);
|
|
28774
29128
|
}
|
|
28775
29129
|
}
|
|
28776
29130
|
var AuthCancelledError, _authDeps, DEFAULT_PI_AUTH_PATH, AMBIENT_PROBE_TIMEOUT_MS = 2000;
|
|
@@ -28788,7 +29142,9 @@ var init_auth = __esm(() => {
|
|
|
28788
29142
|
_authDeps = {
|
|
28789
29143
|
login,
|
|
28790
29144
|
ambientAuthAvailable,
|
|
28791
|
-
providerIds: async () => (await defaultProviders2()).map((provider) => provider.id)
|
|
29145
|
+
providerIds: async () => (await defaultProviders2()).map((provider) => provider.id),
|
|
29146
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
29147
|
+
clearTimeout: (id) => clearTimeout(id)
|
|
28792
29148
|
};
|
|
28793
29149
|
DEFAULT_PI_AUTH_PATH = join20(homedir3(), ".pi", "agent", "auth.json");
|
|
28794
29150
|
});
|
|
@@ -28874,11 +29230,12 @@ function resolveContextWindow(override, realWindow) {
|
|
|
28874
29230
|
}
|
|
28875
29231
|
return override;
|
|
28876
29232
|
}
|
|
28877
|
-
var
|
|
29233
|
+
var THINKING_LEVELS;
|
|
28878
29234
|
var init_models = __esm(() => {
|
|
28879
29235
|
init_errors();
|
|
28880
29236
|
init_logger2();
|
|
28881
29237
|
init_model_spec();
|
|
29238
|
+
init_config();
|
|
28882
29239
|
THINKING_LEVELS = {
|
|
28883
29240
|
off: true,
|
|
28884
29241
|
minimal: true,
|
|
@@ -28892,7 +29249,7 @@ var init_models = __esm(() => {
|
|
|
28892
29249
|
|
|
28893
29250
|
// src/agents/native/client.ts
|
|
28894
29251
|
import { createClient, defaultProtocols, defaultProviders as defaultProviders3 } from "@nathapp/nax-ai";
|
|
28895
|
-
async function buildNativeClient(catalogOverrides = []) {
|
|
29252
|
+
async function buildNativeClient(catalogOverrides = [], options = {}) {
|
|
28896
29253
|
return createClient({
|
|
28897
29254
|
providers: await defaultProviders3(),
|
|
28898
29255
|
protocols: ({ providerOverrides }) => _clientDeps.defaultProtocols({
|
|
@@ -28900,7 +29257,8 @@ async function buildNativeClient(catalogOverrides = []) {
|
|
|
28900
29257
|
clientApp: NAX_CLIENT_APP,
|
|
28901
29258
|
providerOverrides
|
|
28902
29259
|
}),
|
|
28903
|
-
...catalogOverrides.length > 0 ? { providerOverrides: toProviderOverrides(catalogOverrides) } : {}
|
|
29260
|
+
...catalogOverrides.length > 0 ? { providerOverrides: toProviderOverrides(catalogOverrides) } : {},
|
|
29261
|
+
...options.transportRetries !== undefined ? { transportRetries: options.transportRetries } : {}
|
|
28904
29262
|
});
|
|
28905
29263
|
}
|
|
28906
29264
|
function canonicalise(value) {
|
|
@@ -29358,7 +29716,7 @@ async function openNativeSession(name, opts) {
|
|
|
29358
29716
|
});
|
|
29359
29717
|
return {
|
|
29360
29718
|
id: name,
|
|
29361
|
-
agentName:
|
|
29719
|
+
agentName: NATIVE_AGENT_NAME,
|
|
29362
29720
|
protocolIds: { recordId: nativeSessionId(name), sessionId: nativeSessionId(name) },
|
|
29363
29721
|
...opts.modelDef !== undefined ? { modelDef: opts.modelDef } : {},
|
|
29364
29722
|
...opts.modelTier !== undefined ? { modelTier: opts.modelTier } : {}
|
|
@@ -31030,7 +31388,7 @@ ${previousSummary}`;
|
|
|
31030
31388
|
|
|
31031
31389
|
class NativeAgentAdapter {
|
|
31032
31390
|
catalogOverrides;
|
|
31033
|
-
name =
|
|
31391
|
+
name = NATIVE_AGENT_NAME;
|
|
31034
31392
|
displayName = "Native (nax-ai)";
|
|
31035
31393
|
binary = "";
|
|
31036
31394
|
capabilities;
|
|
@@ -31064,7 +31422,7 @@ class NativeAgentAdapter {
|
|
|
31064
31422
|
const client = await getNativeClient(this.catalogOverrides);
|
|
31065
31423
|
const resolved = await client.model(provider, model);
|
|
31066
31424
|
const controller = new AbortController;
|
|
31067
|
-
const timer = options.timeoutMs !== undefined ? setTimeout(() => controller.abort(), options.timeoutMs) : undefined;
|
|
31425
|
+
const timer = options.timeoutMs !== undefined ? _adapterDeps.setTimeout(() => controller.abort(), options.timeoutMs) : undefined;
|
|
31068
31426
|
try {
|
|
31069
31427
|
const sessionId = nativeSessionId(this.oneShotKey);
|
|
31070
31428
|
const result = await client.complete(resolved, {
|
|
@@ -31098,7 +31456,7 @@ class NativeAgentAdapter {
|
|
|
31098
31456
|
throw err;
|
|
31099
31457
|
} finally {
|
|
31100
31458
|
if (timer !== undefined)
|
|
31101
|
-
clearTimeout(timer);
|
|
31459
|
+
_adapterDeps.clearTimeout(timer);
|
|
31102
31460
|
}
|
|
31103
31461
|
}
|
|
31104
31462
|
openSession(name, opts) {
|
|
@@ -31142,7 +31500,7 @@ class NativeAgentAdapter {
|
|
|
31142
31500
|
});
|
|
31143
31501
|
const deadlineController = new AbortController;
|
|
31144
31502
|
const deadlineMs = deadline.remainingMs();
|
|
31145
|
-
const deadlineTimer = deadlineMs !== undefined ? setTimeout(() => deadlineController.abort(), deadlineMs) : undefined;
|
|
31503
|
+
const deadlineTimer = deadlineMs !== undefined ? _adapterDeps.setTimeout(() => deadlineController.abort(), deadlineMs) : undefined;
|
|
31146
31504
|
const turnSignals = [turnController.signal, deadlineController.signal];
|
|
31147
31505
|
if (opts.signal !== undefined)
|
|
31148
31506
|
turnSignals.unshift(opts.signal);
|
|
@@ -31165,7 +31523,7 @@ class NativeAgentAdapter {
|
|
|
31165
31523
|
summarize: async (span, previousSummary) => {
|
|
31166
31524
|
const remainingMs = deadline.remainingMs();
|
|
31167
31525
|
const controller = new AbortController;
|
|
31168
|
-
const timer = remainingMs !== undefined ? setTimeout(() => controller.abort(), remainingMs) : undefined;
|
|
31526
|
+
const timer = remainingMs !== undefined ? _adapterDeps.setTimeout(() => controller.abort(), remainingMs) : undefined;
|
|
31169
31527
|
const signal = AbortSignal.any(opts.signal !== undefined ? [opts.signal, controller.signal, turnController.signal, deadlineController.signal] : [controller.signal, turnController.signal, deadlineController.signal]);
|
|
31170
31528
|
try {
|
|
31171
31529
|
const res = await client.complete(resolved, {
|
|
@@ -31178,13 +31536,13 @@ class NativeAgentAdapter {
|
|
|
31178
31536
|
return { text: res.text, usage: summaryUsage, costUsd, rates: resolvedRates };
|
|
31179
31537
|
} finally {
|
|
31180
31538
|
if (timer !== undefined)
|
|
31181
|
-
clearTimeout(timer);
|
|
31539
|
+
_adapterDeps.clearTimeout(timer);
|
|
31182
31540
|
}
|
|
31183
31541
|
},
|
|
31184
31542
|
complete: async (messages, tools, requestOptions) => {
|
|
31185
31543
|
const remainingMs = deadline.remainingMs();
|
|
31186
31544
|
const controller = new AbortController;
|
|
31187
|
-
const timer = remainingMs !== undefined ? setTimeout(() => controller.abort(), remainingMs) : undefined;
|
|
31545
|
+
const timer = remainingMs !== undefined ? _adapterDeps.setTimeout(() => controller.abort(), remainingMs) : undefined;
|
|
31188
31546
|
const signal = AbortSignal.any(opts.signal !== undefined ? [opts.signal, controller.signal, turnController.signal, deadlineController.signal] : [controller.signal, turnController.signal, deadlineController.signal]);
|
|
31189
31547
|
const requestThinking = requestOptions?.thinking === false ? undefined : thinking;
|
|
31190
31548
|
try {
|
|
@@ -31209,7 +31567,7 @@ class NativeAgentAdapter {
|
|
|
31209
31567
|
};
|
|
31210
31568
|
} finally {
|
|
31211
31569
|
if (timer !== undefined)
|
|
31212
|
-
clearTimeout(timer);
|
|
31570
|
+
_adapterDeps.clearTimeout(timer);
|
|
31213
31571
|
}
|
|
31214
31572
|
}
|
|
31215
31573
|
});
|
|
@@ -31229,7 +31587,7 @@ class NativeAgentAdapter {
|
|
|
31229
31587
|
throw err;
|
|
31230
31588
|
} finally {
|
|
31231
31589
|
if (deadlineTimer !== undefined)
|
|
31232
|
-
clearTimeout(deadlineTimer);
|
|
31590
|
+
_adapterDeps.clearTimeout(deadlineTimer);
|
|
31233
31591
|
}
|
|
31234
31592
|
hooks?.onStreamActivity?.({
|
|
31235
31593
|
...eventBase,
|
|
@@ -31244,7 +31602,7 @@ class NativeAgentAdapter {
|
|
|
31244
31602
|
return closeNativeSession(handle);
|
|
31245
31603
|
}
|
|
31246
31604
|
async closePhysicalSession(handle, _workdir, _options) {
|
|
31247
|
-
return closeNativeSession({ id: handle, agentName:
|
|
31605
|
+
return closeNativeSession({ id: handle, agentName: NATIVE_AGENT_NAME });
|
|
31248
31606
|
}
|
|
31249
31607
|
}
|
|
31250
31608
|
var CONSERVATIVE_CONTEXT_TOKENS = 128000, FALLBACK_TURN_TIMEOUT_SECONDS = 3600, DEFAULT_TIERS, _adapterDeps;
|
|
@@ -31262,7 +31620,12 @@ var init_adapter = __esm(() => {
|
|
|
31262
31620
|
init_turn_types();
|
|
31263
31621
|
init_session_affinity();
|
|
31264
31622
|
DEFAULT_TIERS = ["fast", "balanced", "powerful"];
|
|
31265
|
-
_adapterDeps = {
|
|
31623
|
+
_adapterDeps = {
|
|
31624
|
+
listStoredProviders,
|
|
31625
|
+
anyAmbientCredential,
|
|
31626
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
31627
|
+
clearTimeout: (id) => clearTimeout(id)
|
|
31628
|
+
};
|
|
31266
31629
|
});
|
|
31267
31630
|
|
|
31268
31631
|
// src/agents/native/model-resolver.ts
|
|
@@ -31807,7 +32170,7 @@ async function assertPrdCommitted(prdPath, projectRoot) {
|
|
|
31807
32170
|
});
|
|
31808
32171
|
}
|
|
31809
32172
|
}
|
|
31810
|
-
var
|
|
32173
|
+
var init_validate2 = __esm(() => {
|
|
31811
32174
|
init_errors();
|
|
31812
32175
|
init_git();
|
|
31813
32176
|
});
|
|
@@ -31906,7 +32269,7 @@ function validateInjectedStory(raw, existingIds) {
|
|
|
31906
32269
|
var STORY_ID_PREFIX = "US";
|
|
31907
32270
|
var init_inject = __esm(() => {
|
|
31908
32271
|
init_errors();
|
|
31909
|
-
|
|
32272
|
+
init_validate2();
|
|
31910
32273
|
});
|
|
31911
32274
|
|
|
31912
32275
|
// src/prd/modifies-extract.ts
|
|
@@ -33002,7 +33365,7 @@ var init_schema_story = __esm(() => {
|
|
|
33002
33365
|
init_test_strategy();
|
|
33003
33366
|
init_errors();
|
|
33004
33367
|
init_out_of_scope();
|
|
33005
|
-
|
|
33368
|
+
init_validate2();
|
|
33006
33369
|
VALID_COMPLEXITY = ["simple", "medium", "complex", "expert"];
|
|
33007
33370
|
WORKDIR_SOURCES = ["stated", "derived", "defaulted"];
|
|
33008
33371
|
STORY_ID_NO_SEPARATOR = /^([A-Za-z]+)(\d+)$/;
|
|
@@ -33357,7 +33720,7 @@ var init_prd = __esm(() => {
|
|
|
33357
33720
|
init_out_of_scope_extract();
|
|
33358
33721
|
init_spec_drift();
|
|
33359
33722
|
init_spec_lint();
|
|
33360
|
-
|
|
33723
|
+
init_validate2();
|
|
33361
33724
|
init_workdir_canonical();
|
|
33362
33725
|
init_schema2();
|
|
33363
33726
|
PRD_MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
@@ -40349,23 +40712,6 @@ function lintDiagnosticToFinding(d, workdir, tool) {
|
|
|
40349
40712
|
var init_lint = __esm(() => {
|
|
40350
40713
|
init_path_utils();
|
|
40351
40714
|
});
|
|
40352
|
-
// src/findings/adapters/semantic-review.ts
|
|
40353
|
-
function reviewFindingToFinding(f) {
|
|
40354
|
-
return {
|
|
40355
|
-
source: "semantic-review",
|
|
40356
|
-
severity: f.severity,
|
|
40357
|
-
category: f.category ?? "",
|
|
40358
|
-
rule: f.ruleId,
|
|
40359
|
-
file: f.file,
|
|
40360
|
-
line: f.line,
|
|
40361
|
-
column: f.column,
|
|
40362
|
-
endLine: f.endLine,
|
|
40363
|
-
endColumn: f.endColumn,
|
|
40364
|
-
message: f.message,
|
|
40365
|
-
fixTarget: "source"
|
|
40366
|
-
};
|
|
40367
|
-
}
|
|
40368
|
-
|
|
40369
40715
|
// src/findings/adapters/test-failure.ts
|
|
40370
40716
|
function testFailureToFinding(failure) {
|
|
40371
40717
|
const frames = (failure.stackTrace ?? []).slice(0, MAX_FRAMES_IN_MESSAGE);
|
|
@@ -41210,7 +41556,7 @@ function buildBehavioralGuardrailsSection(role, level, _variant, _isolation) {
|
|
|
41210
41556
|
if (role === "test-writer") {
|
|
41211
41557
|
return buildTestWriterGuardrails(level);
|
|
41212
41558
|
}
|
|
41213
|
-
if (role === "
|
|
41559
|
+
if (role === "tdd-simple" || role === "batch") {
|
|
41214
41560
|
return buildCombinedGuardrails(level);
|
|
41215
41561
|
}
|
|
41216
41562
|
return buildImplementerGuardrails(level);
|
|
@@ -41334,7 +41680,7 @@ ${body}`;
|
|
|
41334
41680
|
}
|
|
41335
41681
|
var HERMETIC_ROLES, LANGUAGE_GUIDANCE;
|
|
41336
41682
|
var init_hermetic = __esm(() => {
|
|
41337
|
-
HERMETIC_ROLES = new Set(["test-writer", "implementer", "tdd-simple", "batch"
|
|
41683
|
+
HERMETIC_ROLES = new Set(["test-writer", "implementer", "tdd-simple", "batch"]);
|
|
41338
41684
|
LANGUAGE_GUIDANCE = {
|
|
41339
41685
|
go: "Define interfaces for external dependencies. Use constructor injection. Test with interface mocks \u2014 no real I/O in tests.",
|
|
41340
41686
|
rust: "Use trait objects or generics for external deps. Mock with the mockall crate. Use #[cfg(test)] modules.",
|
|
@@ -41530,11 +41876,6 @@ isolation scope: Implement source code in src/ to make tests pass. Do not modify
|
|
|
41530
41876
|
return `${header}
|
|
41531
41877
|
|
|
41532
41878
|
isolation scope: Read-only TDD integrity inspection. Review story-scoped test results and test-file modifications. Do NOT apply source or test fixes. You MAY write only the verdict file (.nax-verifier-verdict.json).${footer}`;
|
|
41533
|
-
}
|
|
41534
|
-
if (role === "single-session") {
|
|
41535
|
-
return `${header}
|
|
41536
|
-
|
|
41537
|
-
isolation scope: Create test files in test/ directory, then implement source code in src/ to make tests pass. Both directories are in scope for this session.${footer}`;
|
|
41538
41879
|
}
|
|
41539
41880
|
return `${header}
|
|
41540
41881
|
|
|
@@ -41575,7 +41916,11 @@ freely. Every other path under \`.nax/\` stays off limits.
|
|
|
41575
41916
|
- A test under \`.nax/\` is NOT a reason to skip writing source-tree tests. \`.nax/\` is generated
|
|
41576
41917
|
scaffolding, not real coverage of the package's code.
|
|
41577
41918
|
- A source-tree test is NOT a reason to remove a test under \`.nax/\`. The two serve different
|
|
41578
|
-
purposes and must coexist
|
|
41919
|
+
purposes and must coexist.
|
|
41920
|
+
|
|
41921
|
+
nax updates \`.nax/features/<feature>/prd.json\` itself during a run, so it shows as modified in
|
|
41922
|
+
\`git status\` \u2014 do not diff or revert it: this story's criteria are already in this prompt, and if you
|
|
41923
|
+
need its contents, read it with the \`Read\` tool; shell commands that name it may be refused.`;
|
|
41579
41924
|
}
|
|
41580
41925
|
|
|
41581
41926
|
// src/prompts/sections/out-of-scope.ts
|
|
@@ -41739,25 +42084,6 @@ Instructions:
|
|
|
41739
42084
|
- Do NOT perform semantic acceptance review; semantic/adversarial review stages own acceptance criteria and broad code-quality findings
|
|
41740
42085
|
- Write a detailed verdict with reasoning
|
|
41741
42086
|
- Goal: verify story-scoped tests pass and test integrity was preserved`;
|
|
41742
|
-
}
|
|
41743
|
-
if (role === "single-session") {
|
|
41744
|
-
return `# Role: Single-Session
|
|
41745
|
-
|
|
41746
|
-
Your task: write tests AND implement the feature in one session.
|
|
41747
|
-
|
|
41748
|
-
Workflow:
|
|
41749
|
-
1. Read the acceptance criteria. For each AC, plan one success-path test and one boundary/failure test.
|
|
41750
|
-
2. Create test files in the location the project uses for tests. Cover every AC.
|
|
41751
|
-
3. Run the tests to confirm they fail with ASSERTION failures \u2014 NOT import errors or compile errors. A test that errors before reaching its assertion does not prove the behavior is missing.
|
|
41752
|
-
4. Implement source code in the package's source location to make the tests pass.
|
|
41753
|
-
5. After each meaningful change, re-run only the scoped test files \u2014 never the full suite.
|
|
41754
|
-
6. When all scoped tests pass, stage and commit ALL changed files: \`${gitCommitInstruction(commitMsg)}\`.
|
|
41755
|
-
|
|
41756
|
-
Rules:
|
|
41757
|
-
- Each test name describes ONE behavior; use AC IDs when available.
|
|
41758
|
-
- Assert on observable outputs.
|
|
41759
|
-
- ${frameworkHint}
|
|
41760
|
-
- Goal: every AC has at least one passing test; all changes committed.`;
|
|
41761
42087
|
}
|
|
41762
42088
|
if (role === "batch") {
|
|
41763
42089
|
const verifyCmdLine = testCmd ? ` - Re-run only the scoped test files after each meaningful change: ${testCmd}` : " - Re-run only the scoped test files after each meaningful change";
|
|
@@ -41817,6 +42143,11 @@ or is read by another step. A failed run's scratchpad is retained for inspection
|
|
|
41817
42143
|
before failing outlive that run, and are cleared at the next run's start. Treat every file as disposable,
|
|
41818
42144
|
and overwrite freely.
|
|
41819
42145
|
|
|
42146
|
+
To try a snippet that imports project code or dependencies, write it under \`${dir}\` with
|
|
42147
|
+
\`ScratchpadWrite\` and run it from there: relative imports resolve from \`${dir}\`, so prefer the
|
|
42148
|
+
project's package names or path aliases where it has them. A script written outside the repository,
|
|
42149
|
+
such as in \`/tmp\`, cannot resolve the project's modules, and the file tools cannot write there.
|
|
42150
|
+
|
|
41820
42151
|
\`${dir}\` is the one directory under \`.nax/\` you may write to. Every other path under \`.nax/\`
|
|
41821
42152
|
must still never be moved, renamed, or deleted.`;
|
|
41822
42153
|
}
|
|
@@ -42047,7 +42378,7 @@ An adversarial reviewer will audit your tests after implementation and BLOCK the
|
|
|
42047
42378
|
}
|
|
42048
42379
|
var AUTHORING_ROLES;
|
|
42049
42380
|
var init_test_quality = __esm(() => {
|
|
42050
|
-
AUTHORING_ROLES = new Set(["test-writer", "
|
|
42381
|
+
AUTHORING_ROLES = new Set(["test-writer", "tdd-simple", "batch"]);
|
|
42051
42382
|
});
|
|
42052
42383
|
|
|
42053
42384
|
// src/prompts/sections/verdict.ts
|
|
@@ -42247,7 +42578,7 @@ ACCEPTANCE TEST FILE: ${p.acceptanceTestPath}
|
|
|
42247
42578
|
|
|
42248
42579
|
SOURCE FILES (auto-detected from imports, up to ${p.maxFileLines} lines each):
|
|
42249
42580
|
${p.sourceFilesSection}
|
|
42250
|
-
|
|
42581
|
+
|
|
42251
42582
|
Respond with ONLY a JSON object in this exact format (no markdown, no extra text):
|
|
42252
42583
|
${responseSchema}`;
|
|
42253
42584
|
}
|
|
@@ -42326,16 +42657,10 @@ ${f.content}
|
|
|
42326
42657
|
\`\`\``).join(`
|
|
42327
42658
|
|
|
42328
42659
|
`) : "(No source files could be resolved from imports)";
|
|
42329
|
-
const verdictSection = p.semanticVerdicts && p.semanticVerdicts.length > 0 ? `
|
|
42330
|
-
SEMANTIC VERDICTS:
|
|
42331
|
-
${p.semanticVerdicts.map((v) => `- ${v.storyId}: ${v.passed ? "likely test bug (semantic review confirmed AC implementation)" : "unconfirmed"}`).join(`
|
|
42332
|
-
`)}
|
|
42333
|
-
` : "";
|
|
42334
42660
|
return this.buildDiagnosisPromptTemplate({
|
|
42335
42661
|
truncatedOutput,
|
|
42336
42662
|
acceptanceTestPath: p.acceptanceTestPath ?? "(path unavailable \u2014 inspect test output for file references)",
|
|
42337
42663
|
sourceFilesSection,
|
|
42338
|
-
verdictSection,
|
|
42339
42664
|
maxFileLines: MAX_FILE_LINES
|
|
42340
42665
|
});
|
|
42341
42666
|
}
|
|
@@ -53052,8 +53377,8 @@ var init_version = __esm(() => {
|
|
|
53052
53377
|
NAX_AI_VERSION = CATALOG_VERSION;
|
|
53053
53378
|
NAX_COMMIT = (() => {
|
|
53054
53379
|
try {
|
|
53055
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
53056
|
-
return "
|
|
53380
|
+
if (/^[0-9a-f]{6,10}$/.test("7c21771a"))
|
|
53381
|
+
return "7c21771a";
|
|
53057
53382
|
} catch {}
|
|
53058
53383
|
try {
|
|
53059
53384
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -53612,7 +53937,7 @@ function attachCostSubscriber(bus, aggregator, runId, projectKey) {
|
|
|
53612
53937
|
offCompleted();
|
|
53613
53938
|
};
|
|
53614
53939
|
}
|
|
53615
|
-
var _costSubscriberDeps, COST_ROW_SCHEMA_VERSION =
|
|
53940
|
+
var _costSubscriberDeps, COST_ROW_SCHEMA_VERSION = 7;
|
|
53616
53941
|
var init_cost2 = __esm(() => {
|
|
53617
53942
|
init_agents();
|
|
53618
53943
|
init_version();
|
|
@@ -53734,8 +54059,33 @@ function toUsageEntry(event, runId) {
|
|
|
53734
54059
|
costUsd: event.costUsd
|
|
53735
54060
|
};
|
|
53736
54061
|
}
|
|
53737
|
-
function
|
|
53738
|
-
|
|
54062
|
+
function toOneShotEntry(event, runId) {
|
|
54063
|
+
if (event.kind !== "complete")
|
|
54064
|
+
return null;
|
|
54065
|
+
const tu = event.tokenUsage;
|
|
54066
|
+
const wireExact = event.exactCostUsd;
|
|
54067
|
+
const costUsd = typeof wireExact === "number" && Number.isFinite(wireExact) ? wireExact : event.estimatedCostUsd;
|
|
54068
|
+
if (!tu && (costUsd ?? 0) === 0)
|
|
54069
|
+
return null;
|
|
54070
|
+
return {
|
|
54071
|
+
ts: event.timestamp,
|
|
54072
|
+
runId,
|
|
54073
|
+
scopeId: event.scopeId,
|
|
54074
|
+
streamCallId: event.callId ?? "one-shot",
|
|
54075
|
+
sessionName: event.sessionName,
|
|
54076
|
+
storyId: event.storyId,
|
|
54077
|
+
stage: event.stage,
|
|
54078
|
+
agentName: event.agentName,
|
|
54079
|
+
cadence: "one-shot",
|
|
54080
|
+
input: tu?.inputTokens,
|
|
54081
|
+
output: tu?.outputTokens,
|
|
54082
|
+
cacheRead: tu?.cacheReadInputTokens,
|
|
54083
|
+
cacheWrite: tu?.cacheCreationInputTokens,
|
|
54084
|
+
costUsd
|
|
54085
|
+
};
|
|
54086
|
+
}
|
|
54087
|
+
function attachUsageAuditSubscriber(bus, dispatchEvents, auditor, runId) {
|
|
54088
|
+
const offStream = bus.onAgentStream((event) => {
|
|
53739
54089
|
switch (event.kind) {
|
|
53740
54090
|
case "agent.usage_update":
|
|
53741
54091
|
auditor.record(toUsageEntry(event, runId));
|
|
@@ -53744,6 +54094,15 @@ function attachUsageAuditSubscriber(bus, auditor, runId) {
|
|
|
53744
54094
|
break;
|
|
53745
54095
|
}
|
|
53746
54096
|
});
|
|
54097
|
+
const offDispatch = dispatchEvents.onDispatch((event) => {
|
|
54098
|
+
const entry = toOneShotEntry(event, runId);
|
|
54099
|
+
if (entry)
|
|
54100
|
+
auditor.record(entry);
|
|
54101
|
+
});
|
|
54102
|
+
return () => {
|
|
54103
|
+
offStream();
|
|
54104
|
+
offDispatch();
|
|
54105
|
+
};
|
|
53747
54106
|
}
|
|
53748
54107
|
|
|
53749
54108
|
// src/runtime/middleware/index.ts
|
|
@@ -53755,15 +54114,255 @@ var init_middleware = __esm(() => {
|
|
|
53755
54114
|
init_logging();
|
|
53756
54115
|
});
|
|
53757
54116
|
|
|
54117
|
+
// src/runtime/usage-auditor.ts
|
|
54118
|
+
import { appendFileSync as appendFileSync2 } from "fs";
|
|
54119
|
+
import { mkdir as mkdir16 } from "fs/promises";
|
|
54120
|
+
import { join as join45 } from "path";
|
|
54121
|
+
function createNoOpUsageAuditor() {
|
|
54122
|
+
return {
|
|
54123
|
+
record() {},
|
|
54124
|
+
async flush() {}
|
|
54125
|
+
};
|
|
54126
|
+
}
|
|
54127
|
+
function deriveSessionRole(sessionName) {
|
|
54128
|
+
for (const role of ROLES_BY_DESCENDING_LENGTH) {
|
|
54129
|
+
if (sessionName === role || sessionName.endsWith(`-${role}`))
|
|
54130
|
+
return role;
|
|
54131
|
+
}
|
|
54132
|
+
return;
|
|
54133
|
+
}
|
|
54134
|
+
|
|
54135
|
+
class UsageAuditor {
|
|
54136
|
+
_queue = Promise.resolve();
|
|
54137
|
+
_dirCreated = false;
|
|
54138
|
+
_dir;
|
|
54139
|
+
_jsonlPath;
|
|
54140
|
+
constructor(runId, dir) {
|
|
54141
|
+
this._dir = dir;
|
|
54142
|
+
this._jsonlPath = join45(dir, `${runId}.jsonl`);
|
|
54143
|
+
}
|
|
54144
|
+
record(entry) {
|
|
54145
|
+
this._queue = this._queue.then(() => this._writeEntry(entry)).catch((err) => {
|
|
54146
|
+
const sysErr = err;
|
|
54147
|
+
getSafeLogger()?.warn("audit", "usage-audit write failed", {
|
|
54148
|
+
path: this._jsonlPath,
|
|
54149
|
+
error: errorMessage(err),
|
|
54150
|
+
code: sysErr?.code,
|
|
54151
|
+
errno: sysErr?.errno,
|
|
54152
|
+
syscall: sysErr?.syscall,
|
|
54153
|
+
ts: entry.ts,
|
|
54154
|
+
storyId: entry.storyId,
|
|
54155
|
+
sessionName: entry.sessionName,
|
|
54156
|
+
agentName: entry.agentName,
|
|
54157
|
+
stage: entry.stage,
|
|
54158
|
+
streamCallId: entry.streamCallId
|
|
54159
|
+
});
|
|
54160
|
+
});
|
|
54161
|
+
}
|
|
54162
|
+
async _writeEntry(entry) {
|
|
54163
|
+
if (!this._dirCreated) {
|
|
54164
|
+
await mkdir16(this._dir, { recursive: true });
|
|
54165
|
+
this._dirCreated = true;
|
|
54166
|
+
}
|
|
54167
|
+
const row = { ...entry, sessionRole: deriveSessionRole(entry.sessionName) };
|
|
54168
|
+
await _usageAuditorDeps.appendLine(this._jsonlPath, `${JSON.stringify(row)}
|
|
54169
|
+
`);
|
|
54170
|
+
}
|
|
54171
|
+
async flush() {
|
|
54172
|
+
await this._queue;
|
|
54173
|
+
}
|
|
54174
|
+
}
|
|
54175
|
+
var _usageAuditorDeps, ROLES_BY_DESCENDING_LENGTH;
|
|
54176
|
+
var init_usage_auditor = __esm(() => {
|
|
54177
|
+
init_logger2();
|
|
54178
|
+
init_session_role();
|
|
54179
|
+
_usageAuditorDeps = {
|
|
54180
|
+
appendLine: async (path6, data) => {
|
|
54181
|
+
appendFileSync2(path6, data, "utf8");
|
|
54182
|
+
}
|
|
54183
|
+
};
|
|
54184
|
+
ROLES_BY_DESCENDING_LENGTH = [...KNOWN_SESSION_ROLES].sort((a, b) => b.length - a.length);
|
|
54185
|
+
});
|
|
54186
|
+
|
|
54187
|
+
// src/runtime/in-flight-usage.ts
|
|
54188
|
+
function hasSpend(entry) {
|
|
54189
|
+
const { input, output, cacheRead, cacheWrite } = entry.tokens;
|
|
54190
|
+
return entry.costUsd > 0 || input + output + cacheRead + cacheWrite > 0;
|
|
54191
|
+
}
|
|
54192
|
+
function attachInFlightUsageTracker(streamBus, dispatchEvents) {
|
|
54193
|
+
const entries = new Map;
|
|
54194
|
+
const latestEndedBySession = new Map;
|
|
54195
|
+
let endedSeq = 0;
|
|
54196
|
+
const entryFor = (event) => {
|
|
54197
|
+
let entry = entries.get(event.callId);
|
|
54198
|
+
if (entry === undefined) {
|
|
54199
|
+
entry = {
|
|
54200
|
+
streamCallId: event.callId,
|
|
54201
|
+
agentName: event.agentName,
|
|
54202
|
+
model: "unknown",
|
|
54203
|
+
sessionName: event.sessionName,
|
|
54204
|
+
tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
54205
|
+
costUsd: 0,
|
|
54206
|
+
roundTrips: 0
|
|
54207
|
+
};
|
|
54208
|
+
entries.set(event.callId, entry);
|
|
54209
|
+
}
|
|
54210
|
+
entry.agentName = event.agentName;
|
|
54211
|
+
entry.sessionName = event.sessionName;
|
|
54212
|
+
if (event.storyId !== undefined)
|
|
54213
|
+
entry.storyId = event.storyId;
|
|
54214
|
+
if (event.stage !== undefined)
|
|
54215
|
+
entry.stage = event.stage;
|
|
54216
|
+
if (event.scopeId !== undefined)
|
|
54217
|
+
entry.scopeId = event.scopeId;
|
|
54218
|
+
return entry;
|
|
54219
|
+
};
|
|
54220
|
+
const onUsageUpdate = (event) => {
|
|
54221
|
+
if (event.cadence !== "round-trip")
|
|
54222
|
+
return;
|
|
54223
|
+
const entry = entryFor(event);
|
|
54224
|
+
entry.tokens.input += event.inputTokens ?? 0;
|
|
54225
|
+
entry.tokens.output += event.outputTokens ?? 0;
|
|
54226
|
+
entry.tokens.cacheRead += event.cacheRead ?? 0;
|
|
54227
|
+
entry.tokens.cacheWrite += event.cacheWrite ?? 0;
|
|
54228
|
+
entry.costUsd += event.costUsd ?? 0;
|
|
54229
|
+
if (event.roundTrip !== undefined)
|
|
54230
|
+
entry.roundTrips += 1;
|
|
54231
|
+
};
|
|
54232
|
+
const onCallStarted = (event) => {
|
|
54233
|
+
const entry = entryFor(event);
|
|
54234
|
+
entry.model = event.model === "" ? "unknown" : event.model;
|
|
54235
|
+
};
|
|
54236
|
+
const forget = (callId) => {
|
|
54237
|
+
entries.delete(callId);
|
|
54238
|
+
for (const [sessionName, remembered] of latestEndedBySession) {
|
|
54239
|
+
if (remembered === callId)
|
|
54240
|
+
latestEndedBySession.delete(sessionName);
|
|
54241
|
+
}
|
|
54242
|
+
};
|
|
54243
|
+
const onCallEnded = (event) => {
|
|
54244
|
+
latestEndedBySession.set(event.sessionName, event.callId);
|
|
54245
|
+
if (event.status === "success" || event.status === "timeout") {
|
|
54246
|
+
forget(event.callId);
|
|
54247
|
+
return;
|
|
54248
|
+
}
|
|
54249
|
+
const existing2 = entries.get(event.callId);
|
|
54250
|
+
if (existing2 === undefined)
|
|
54251
|
+
return;
|
|
54252
|
+
const entry = entryFor(event);
|
|
54253
|
+
entry.endedStatus = event.status;
|
|
54254
|
+
endedSeq += 1;
|
|
54255
|
+
entry.endedSeq = endedSeq;
|
|
54256
|
+
};
|
|
54257
|
+
const onDispatch = (event) => {
|
|
54258
|
+
if (event.kind !== "session-turn")
|
|
54259
|
+
return;
|
|
54260
|
+
const callId = latestEndedBySession.get(event.sessionName);
|
|
54261
|
+
if (callId === undefined)
|
|
54262
|
+
return;
|
|
54263
|
+
const entry = entries.get(callId);
|
|
54264
|
+
if (entry !== undefined && entry.endedStatus === "cancelled")
|
|
54265
|
+
forget(callId);
|
|
54266
|
+
};
|
|
54267
|
+
const matchesScope = (entry, event) => {
|
|
54268
|
+
if (entry.scopeId === undefined)
|
|
54269
|
+
return false;
|
|
54270
|
+
return entry.scopeId === event.scopeId || entry.scopeId === event.callId;
|
|
54271
|
+
};
|
|
54272
|
+
const onDispatchError = (event) => {
|
|
54273
|
+
const hasUsage = event.tokenUsage !== undefined;
|
|
54274
|
+
const costUsd = event.exactCostUsd ?? event.estimatedCostUsd ?? 0;
|
|
54275
|
+
if (!hasUsage && !(Number.isFinite(costUsd) && costUsd > 0))
|
|
54276
|
+
return;
|
|
54277
|
+
let target;
|
|
54278
|
+
for (const entry of entries.values()) {
|
|
54279
|
+
if (entry.endedStatus === undefined || !matchesScope(entry, event))
|
|
54280
|
+
continue;
|
|
54281
|
+
if (target === undefined || (entry.endedSeq ?? 0) > (target.endedSeq ?? 0))
|
|
54282
|
+
target = entry;
|
|
54283
|
+
}
|
|
54284
|
+
if (target !== undefined)
|
|
54285
|
+
forget(target.streamCallId);
|
|
54286
|
+
};
|
|
54287
|
+
const onStream = (event) => {
|
|
54288
|
+
if (event.kind === "agent.usage_update")
|
|
54289
|
+
onUsageUpdate(event);
|
|
54290
|
+
else if (event.kind === "agent.call_started")
|
|
54291
|
+
onCallStarted(event);
|
|
54292
|
+
else if (event.kind === "agent.call_ended")
|
|
54293
|
+
onCallEnded(event);
|
|
54294
|
+
};
|
|
54295
|
+
const residuals = () => {
|
|
54296
|
+
const out = [];
|
|
54297
|
+
for (const entry of entries.values()) {
|
|
54298
|
+
if (!hasSpend(entry))
|
|
54299
|
+
continue;
|
|
54300
|
+
out.push({
|
|
54301
|
+
streamCallId: entry.streamCallId,
|
|
54302
|
+
agentName: entry.agentName,
|
|
54303
|
+
model: entry.model,
|
|
54304
|
+
sessionName: entry.sessionName,
|
|
54305
|
+
...entry.storyId !== undefined ? { storyId: entry.storyId } : {},
|
|
54306
|
+
...entry.stage !== undefined ? { stage: entry.stage } : {},
|
|
54307
|
+
...entry.scopeId !== undefined ? { scopeId: entry.scopeId } : {},
|
|
54308
|
+
tokens: { ...entry.tokens },
|
|
54309
|
+
costUsd: entry.costUsd,
|
|
54310
|
+
roundTrips: entry.roundTrips
|
|
54311
|
+
});
|
|
54312
|
+
}
|
|
54313
|
+
return out;
|
|
54314
|
+
};
|
|
54315
|
+
const offStream = streamBus.onAgentStream(onStream);
|
|
54316
|
+
const offDispatch = dispatchEvents.onDispatch(onDispatch);
|
|
54317
|
+
const offError = dispatchEvents.onDispatchError(onDispatchError);
|
|
54318
|
+
return {
|
|
54319
|
+
tracker: { residuals },
|
|
54320
|
+
off: () => {
|
|
54321
|
+
offStream();
|
|
54322
|
+
offDispatch();
|
|
54323
|
+
offError();
|
|
54324
|
+
}
|
|
54325
|
+
};
|
|
54326
|
+
}
|
|
54327
|
+
function toPartialCostEvent(residual, runId, projectKey) {
|
|
54328
|
+
const sessionRole = deriveSessionRole(residual.sessionName);
|
|
54329
|
+
return {
|
|
54330
|
+
ts: Date.now(),
|
|
54331
|
+
runId,
|
|
54332
|
+
...projectKey !== undefined ? { projectKey } : {},
|
|
54333
|
+
schemaVersion: COST_ROW_SCHEMA_VERSION,
|
|
54334
|
+
partial: true,
|
|
54335
|
+
agentName: residual.agentName,
|
|
54336
|
+
model: residual.model,
|
|
54337
|
+
...sessionRole !== undefined ? { sessionRole } : {},
|
|
54338
|
+
...residual.stage !== undefined ? { stage: residual.stage } : {},
|
|
54339
|
+
...residual.storyId !== undefined ? { storyId: residual.storyId } : {},
|
|
54340
|
+
...residual.scopeId !== undefined ? { scopeId: residual.scopeId } : {},
|
|
54341
|
+
callId: residual.streamCallId,
|
|
54342
|
+
tokens: { ...residual.tokens },
|
|
54343
|
+
roundTrips: residual.roundTrips,
|
|
54344
|
+
roundTripUnit: "model-call",
|
|
54345
|
+
costUsd: residual.costUsd,
|
|
54346
|
+
estimatedCostUsd: residual.costUsd,
|
|
54347
|
+
exactCostUsd: residual.costUsd,
|
|
54348
|
+
confidence: "estimated",
|
|
54349
|
+
durationMs: 0
|
|
54350
|
+
};
|
|
54351
|
+
}
|
|
54352
|
+
var init_in_flight_usage = __esm(() => {
|
|
54353
|
+
init_middleware();
|
|
54354
|
+
init_usage_auditor();
|
|
54355
|
+
});
|
|
54356
|
+
|
|
53758
54357
|
// src/runtime/packages.ts
|
|
53759
|
-
import { isAbsolute as isAbsolute15, join as
|
|
54358
|
+
import { isAbsolute as isAbsolute15, join as join46, relative as relative17 } from "path";
|
|
53760
54359
|
function packageWorkdir(view) {
|
|
53761
54360
|
const { packageDir, repoRoot } = view;
|
|
53762
54361
|
if (!packageDir)
|
|
53763
54362
|
return repoRoot;
|
|
53764
54363
|
if (!repoRoot || isAbsolute15(packageDir))
|
|
53765
54364
|
return packageDir;
|
|
53766
|
-
return
|
|
54365
|
+
return join46(repoRoot, packageDir);
|
|
53767
54366
|
}
|
|
53768
54367
|
function createPackageView(config2, packageDir, repoRoot, hasOverride, overlay) {
|
|
53769
54368
|
const memo = new Map;
|
|
@@ -53876,7 +54475,7 @@ function storyExecRoot(view) {
|
|
|
53876
54475
|
const segments = packageDir.split("/");
|
|
53877
54476
|
if (segments[0] !== ".nax-wt" || segments.length < 2)
|
|
53878
54477
|
return repoRoot;
|
|
53879
|
-
return
|
|
54478
|
+
return join46(repoRoot, segments[0], segments[1]);
|
|
53880
54479
|
}
|
|
53881
54480
|
var _packagesDeps;
|
|
53882
54481
|
var init_packages = __esm(() => {
|
|
@@ -54009,9 +54608,9 @@ var init_paths2 = __esm(() => {
|
|
|
54009
54608
|
});
|
|
54010
54609
|
|
|
54011
54610
|
// src/runtime/prompt-auditor.ts
|
|
54012
|
-
import { appendFileSync as
|
|
54013
|
-
import { mkdir as
|
|
54014
|
-
import { join as
|
|
54611
|
+
import { appendFileSync as appendFileSync3 } from "fs";
|
|
54612
|
+
import { mkdir as mkdir17 } from "fs/promises";
|
|
54613
|
+
import { join as join47 } from "path";
|
|
54015
54614
|
function createNoOpPromptAuditor() {
|
|
54016
54615
|
return {
|
|
54017
54616
|
record() {},
|
|
@@ -54091,8 +54690,8 @@ class PromptAuditor {
|
|
|
54091
54690
|
_featureDir;
|
|
54092
54691
|
_turnOrdinals = new Map;
|
|
54093
54692
|
constructor(runId, flushDir, featureName) {
|
|
54094
|
-
this._featureDir =
|
|
54095
|
-
this._jsonlPath =
|
|
54693
|
+
this._featureDir = join47(flushDir, featureName);
|
|
54694
|
+
this._jsonlPath = join47(this._featureDir, `${runId}.jsonl`);
|
|
54096
54695
|
}
|
|
54097
54696
|
record(entry) {
|
|
54098
54697
|
this._enqueue(entry.callType === "run" ? { ...entry, turn: this._nextTurn(entry) } : entry);
|
|
@@ -54130,7 +54729,7 @@ class PromptAuditor {
|
|
|
54130
54729
|
async _writeEntry(entry) {
|
|
54131
54730
|
if (!this._dirCreated) {
|
|
54132
54731
|
try {
|
|
54133
|
-
await
|
|
54732
|
+
await mkdir17(this._featureDir, { recursive: true });
|
|
54134
54733
|
} catch (err) {
|
|
54135
54734
|
throw tagAuditError(err, "jsonl");
|
|
54136
54735
|
}
|
|
@@ -54147,7 +54746,7 @@ class PromptAuditor {
|
|
|
54147
54746
|
return;
|
|
54148
54747
|
const filename = deriveTxtFilename(entry);
|
|
54149
54748
|
try {
|
|
54150
|
-
await _promptAuditorDeps.write(
|
|
54749
|
+
await _promptAuditorDeps.write(join47(this._featureDir, filename), buildTxtContent(safeEntry));
|
|
54151
54750
|
} catch (err) {
|
|
54152
54751
|
throw tagAuditError(err, "txt");
|
|
54153
54752
|
}
|
|
@@ -54161,80 +54760,10 @@ var init_prompt_auditor = __esm(() => {
|
|
|
54161
54760
|
init_logger2();
|
|
54162
54761
|
_promptAuditorDeps = {
|
|
54163
54762
|
write: (path7, data) => Bun.write(path7, data),
|
|
54164
|
-
appendLine: async (path7, data) => {
|
|
54165
|
-
appendFileSync2(path7, data, "utf8");
|
|
54166
|
-
}
|
|
54167
|
-
};
|
|
54168
|
-
});
|
|
54169
|
-
|
|
54170
|
-
// src/runtime/usage-auditor.ts
|
|
54171
|
-
import { appendFileSync as appendFileSync3 } from "fs";
|
|
54172
|
-
import { mkdir as mkdir17 } from "fs/promises";
|
|
54173
|
-
import { join as join47 } from "path";
|
|
54174
|
-
function createNoOpUsageAuditor() {
|
|
54175
|
-
return {
|
|
54176
|
-
record() {},
|
|
54177
|
-
async flush() {}
|
|
54178
|
-
};
|
|
54179
|
-
}
|
|
54180
|
-
function deriveSessionRole(sessionName) {
|
|
54181
|
-
for (const role of ROLES_BY_DESCENDING_LENGTH) {
|
|
54182
|
-
if (sessionName === role || sessionName.endsWith(`-${role}`))
|
|
54183
|
-
return role;
|
|
54184
|
-
}
|
|
54185
|
-
return;
|
|
54186
|
-
}
|
|
54187
|
-
|
|
54188
|
-
class UsageAuditor {
|
|
54189
|
-
_queue = Promise.resolve();
|
|
54190
|
-
_dirCreated = false;
|
|
54191
|
-
_dir;
|
|
54192
|
-
_jsonlPath;
|
|
54193
|
-
constructor(runId, dir) {
|
|
54194
|
-
this._dir = dir;
|
|
54195
|
-
this._jsonlPath = join47(dir, `${runId}.jsonl`);
|
|
54196
|
-
}
|
|
54197
|
-
record(entry) {
|
|
54198
|
-
this._queue = this._queue.then(() => this._writeEntry(entry)).catch((err) => {
|
|
54199
|
-
const sysErr = err;
|
|
54200
|
-
getSafeLogger()?.warn("audit", "usage-audit write failed", {
|
|
54201
|
-
path: this._jsonlPath,
|
|
54202
|
-
error: errorMessage(err),
|
|
54203
|
-
code: sysErr?.code,
|
|
54204
|
-
errno: sysErr?.errno,
|
|
54205
|
-
syscall: sysErr?.syscall,
|
|
54206
|
-
ts: entry.ts,
|
|
54207
|
-
storyId: entry.storyId,
|
|
54208
|
-
sessionName: entry.sessionName,
|
|
54209
|
-
agentName: entry.agentName,
|
|
54210
|
-
stage: entry.stage,
|
|
54211
|
-
streamCallId: entry.streamCallId
|
|
54212
|
-
});
|
|
54213
|
-
});
|
|
54214
|
-
}
|
|
54215
|
-
async _writeEntry(entry) {
|
|
54216
|
-
if (!this._dirCreated) {
|
|
54217
|
-
await mkdir17(this._dir, { recursive: true });
|
|
54218
|
-
this._dirCreated = true;
|
|
54219
|
-
}
|
|
54220
|
-
const row = { ...entry, sessionRole: deriveSessionRole(entry.sessionName) };
|
|
54221
|
-
await _usageAuditorDeps.appendLine(this._jsonlPath, `${JSON.stringify(row)}
|
|
54222
|
-
`);
|
|
54223
|
-
}
|
|
54224
|
-
async flush() {
|
|
54225
|
-
await this._queue;
|
|
54226
|
-
}
|
|
54227
|
-
}
|
|
54228
|
-
var _usageAuditorDeps, ROLES_BY_DESCENDING_LENGTH;
|
|
54229
|
-
var init_usage_auditor = __esm(() => {
|
|
54230
|
-
init_logger2();
|
|
54231
|
-
init_session_role();
|
|
54232
|
-
_usageAuditorDeps = {
|
|
54233
54763
|
appendLine: async (path7, data) => {
|
|
54234
54764
|
appendFileSync3(path7, data, "utf8");
|
|
54235
54765
|
}
|
|
54236
54766
|
};
|
|
54237
|
-
ROLES_BY_DESCENDING_LENGTH = [...KNOWN_SESSION_ROLES].sort((a, b) => b.length - a.length);
|
|
54238
54767
|
});
|
|
54239
54768
|
|
|
54240
54769
|
// src/agents/factory.ts
|
|
@@ -65849,7 +66378,7 @@ var init_coding_tool_support = __esm(() => {
|
|
|
65849
66378
|
|
|
65850
66379
|
// src/agents/tool-preamble.ts
|
|
65851
66380
|
function promptWithToolPreamble(agentName, options) {
|
|
65852
|
-
const base = agentName ===
|
|
66381
|
+
const base = agentName === NATIVE_AGENT_NAME ? options.prompt : buildContextToolPreamble(options);
|
|
65853
66382
|
const scope = buildAgentScopeSection(options.codingToolRoot, options.codingToolWorkdirLabel);
|
|
65854
66383
|
return scope === undefined ? base : `${scope}
|
|
65855
66384
|
|
|
@@ -65857,7 +66386,7 @@ ${base}`;
|
|
|
65857
66386
|
}
|
|
65858
66387
|
function applyDiffAccessForAgentProtocol(agentName, prompt, advertisedTools) {
|
|
65859
66388
|
return applyProtocolRegions(prompt, {
|
|
65860
|
-
protocol: agentName ===
|
|
66389
|
+
protocol: agentName === NATIVE_AGENT_NAME ? "native" : "acp",
|
|
65861
66390
|
advertisedTools: new Set(advertisedTools)
|
|
65862
66391
|
});
|
|
65863
66392
|
}
|
|
@@ -66031,6 +66560,7 @@ __export(exports_runtime, {
|
|
|
66031
66560
|
_usageAuditorDeps: () => _usageAuditorDeps,
|
|
66032
66561
|
attachAgentIdleWatchdog: () => attachAgentIdleWatchdog,
|
|
66033
66562
|
attachAgentStreamLogging: () => attachAgentStreamLogging,
|
|
66563
|
+
attachInFlightUsageTracker: () => attachInFlightUsageTracker,
|
|
66034
66564
|
attachUsageAuditSubscriber: () => attachUsageAuditSubscriber,
|
|
66035
66565
|
claimProjectIdentity: () => claimProjectIdentity,
|
|
66036
66566
|
createNoOpCostAggregator: () => createNoOpCostAggregator,
|
|
@@ -66053,6 +66583,7 @@ __export(exports_runtime, {
|
|
|
66053
66583
|
spinTerminalNotice: () => spinTerminalNotice,
|
|
66054
66584
|
storyExecRoot: () => storyExecRoot,
|
|
66055
66585
|
storySpendUsd: () => storySpendUsd,
|
|
66586
|
+
toPartialCostEvent: () => toPartialCostEvent,
|
|
66056
66587
|
totalSpendUsd: () => totalSpendUsd,
|
|
66057
66588
|
writeProjectIdentity: () => writeProjectIdentity
|
|
66058
66589
|
});
|
|
@@ -66144,9 +66675,10 @@ function createRuntime(config2, workdir, opts) {
|
|
|
66144
66675
|
const offCost = attachCostSubscriber(dispatchEvents, costAggregator, runId, getProjectKey(config2, workdir));
|
|
66145
66676
|
const offAudit = attachAuditSubscriber(dispatchEvents, promptAuditor, runId);
|
|
66146
66677
|
const offReviewAudit = attachReviewAuditSubscriber(dispatchEvents, reviewAuditor, runId);
|
|
66147
|
-
const offUsageAudit = attachUsageAuditSubscriber(agentStreamEvents, usageAuditor, runId);
|
|
66678
|
+
const offUsageAudit = attachUsageAuditSubscriber(agentStreamEvents, dispatchEvents, usageAuditor, runId);
|
|
66148
66679
|
const offAgentStreamLogging = attachAgentStreamLogging(agentStreamEvents, runId);
|
|
66149
66680
|
const offWatchdog = attachAgentIdleWatchdog(agentStreamEvents, watchdogControllerRegistry, config2);
|
|
66681
|
+
const { tracker: inFlightTracker, off: offInFlightUsage } = attachInFlightUsageTracker(agentStreamEvents, dispatchEvents);
|
|
66150
66682
|
const packages = createPackageRegistry(configLoader, workdir);
|
|
66151
66683
|
const logger = getLogger();
|
|
66152
66684
|
const quarantineMemo = createQuarantineMemo();
|
|
@@ -66214,6 +66746,7 @@ function createRuntime(config2, workdir, opts) {
|
|
|
66214
66746
|
offUsageAudit();
|
|
66215
66747
|
offAgentStreamLogging();
|
|
66216
66748
|
offWatchdog();
|
|
66749
|
+
offInFlightUsage();
|
|
66217
66750
|
if (opts?.parentSignal && parentAbortHandler) {
|
|
66218
66751
|
opts.parentSignal.removeEventListener("abort", parentAbortHandler);
|
|
66219
66752
|
}
|
|
@@ -66223,6 +66756,10 @@ function createRuntime(config2, workdir, opts) {
|
|
|
66223
66756
|
sessionManager.close();
|
|
66224
66757
|
await mcpPool.close();
|
|
66225
66758
|
await writeMcpRollup(outputDir, buildMcpRollup({ runId, events: mcpPool.events(), withheld: mcpWithheld })).catch((error48) => logger.warn("runtime", "mcp rollup write failed", { error: String(error48) }));
|
|
66759
|
+
for (const residual of inFlightTracker.residuals()) {
|
|
66760
|
+
costAggregator.record(toPartialCostEvent(residual, runId, projectKey));
|
|
66761
|
+
}
|
|
66762
|
+
await flushOpenToolAuditSinks(runId);
|
|
66226
66763
|
const results = await Promise.allSettled([
|
|
66227
66764
|
promptAuditor.flush(),
|
|
66228
66765
|
usageAuditor.flush(),
|
|
@@ -66242,6 +66779,7 @@ var init_runtime2 = __esm(() => {
|
|
|
66242
66779
|
init_agent_stream_events();
|
|
66243
66780
|
init_cost_aggregator();
|
|
66244
66781
|
init_dispatch_events();
|
|
66782
|
+
init_in_flight_usage();
|
|
66245
66783
|
init_middleware();
|
|
66246
66784
|
init_packages();
|
|
66247
66785
|
init_paths2();
|
|
@@ -66250,6 +66788,7 @@ var init_runtime2 = __esm(() => {
|
|
|
66250
66788
|
init_session_role();
|
|
66251
66789
|
init_spin_breaker();
|
|
66252
66790
|
init_usage_auditor();
|
|
66791
|
+
init_tools();
|
|
66253
66792
|
init_factory();
|
|
66254
66793
|
init_manager2();
|
|
66255
66794
|
init_config();
|
|
@@ -66263,6 +66802,7 @@ var init_runtime2 = __esm(() => {
|
|
|
66263
66802
|
init_agent_stream_events();
|
|
66264
66803
|
init_cost_aggregator();
|
|
66265
66804
|
init_dispatch_events();
|
|
66805
|
+
init_in_flight_usage();
|
|
66266
66806
|
init_middleware();
|
|
66267
66807
|
init_packages();
|
|
66268
66808
|
init_paths2();
|
|
@@ -66674,7 +67214,6 @@ var init_feature_context_filter = __esm(() => {
|
|
|
66674
67214
|
implementer: ["all", "implementer"],
|
|
66675
67215
|
"test-writer": ["all", "test-writer"],
|
|
66676
67216
|
verifier: ["all", "verifier"],
|
|
66677
|
-
"single-session": ["all", "implementer", "test-writer"],
|
|
66678
67217
|
"tdd-simple": ["all", "implementer", "test-writer"],
|
|
66679
67218
|
"no-test": ["all", "implementer"],
|
|
66680
67219
|
batch: ["all", "implementer", "test-writer"]
|
|
@@ -67921,8 +68460,7 @@ var init_acceptance_diagnose = __esm(() => {
|
|
|
67921
68460
|
testOutput: input.testOutput,
|
|
67922
68461
|
testFileContent: input.testFileContent,
|
|
67923
68462
|
acceptanceTestPath: input.acceptanceTestPath,
|
|
67924
|
-
sourceFiles: input.sourceFiles
|
|
67925
|
-
semanticVerdicts: input.semanticVerdicts
|
|
68463
|
+
sourceFiles: input.sourceFiles
|
|
67926
68464
|
});
|
|
67927
68465
|
return {
|
|
67928
68466
|
role: { id: "role", content: "", overridable: false },
|
|
@@ -76918,7 +77456,7 @@ function buildSessionTurnEvent(input) {
|
|
|
76918
77456
|
...result.pricingSource !== undefined ? { pricingSource: result.pricingSource } : {},
|
|
76919
77457
|
...result.rates !== undefined ? { rates: result.rates } : {},
|
|
76920
77458
|
roundTrips: result.internalRoundTrips ?? 1,
|
|
76921
|
-
roundTripUnit: input.agentName ===
|
|
77459
|
+
roundTripUnit: input.agentName === NATIVE_AGENT_NAME ? "model-call" : "agent-run",
|
|
76922
77460
|
protocolIds: {
|
|
76923
77461
|
sessionId: handle.protocolIds?.sessionId ?? null,
|
|
76924
77462
|
recordId: handle.protocolIds?.recordId ?? null,
|
|
@@ -77475,7 +78013,7 @@ var init_manager_run_fallback = __esm(() => {
|
|
|
77475
78013
|
|
|
77476
78014
|
// src/agents/registry.ts
|
|
77477
78015
|
function adapterFor(name) {
|
|
77478
|
-
return name ===
|
|
78016
|
+
return name === NATIVE_AGENT_NAME ? new NativeAgentAdapter : new AcpAgentAdapter(name);
|
|
77479
78017
|
}
|
|
77480
78018
|
function buildAdapterList() {
|
|
77481
78019
|
return [...Array.from(_registryTestAdapters.values()), ...KNOWN_AGENT_NAMES.map(adapterFor)];
|
|
@@ -77491,12 +78029,12 @@ async function getInstalledAgents() {
|
|
|
77491
78029
|
function createAgentRegistry(config2) {
|
|
77492
78030
|
const logger = getLogger();
|
|
77493
78031
|
const adapterCache = new Map;
|
|
77494
|
-
const protocol = config2.agent?.protocol ??
|
|
78032
|
+
const protocol = config2.agent?.protocol ?? DEFAULT_AGENT_PROTOCOL;
|
|
77495
78033
|
logger?.info("agents", `Agent protocol: ${protocol}`, { protocol, hasConfig: !!config2.agent });
|
|
77496
78034
|
function cachedAdapter(name) {
|
|
77497
78035
|
let adapter = adapterCache.get(name);
|
|
77498
78036
|
if (adapter === undefined) {
|
|
77499
|
-
adapter = name ===
|
|
78037
|
+
adapter = name === NATIVE_AGENT_NAME ? new NativeAgentAdapter(undefined, config2.agent?.native?.catalogOverrides ?? []) : new AcpAgentAdapter(name);
|
|
77500
78038
|
adapterCache.set(name, adapter);
|
|
77501
78039
|
logger?.debug("agents", `Created ${adapter.constructor.name} for ${name}`, { name });
|
|
77502
78040
|
}
|
|
@@ -77530,10 +78068,11 @@ function createAgentRegistry(config2) {
|
|
|
77530
78068
|
}
|
|
77531
78069
|
var KNOWN_AGENT_NAMES, _registryTestAdapters;
|
|
77532
78070
|
var init_registry4 = __esm(() => {
|
|
78071
|
+
init_config();
|
|
77533
78072
|
init_logger2();
|
|
77534
78073
|
init_adapter2();
|
|
77535
78074
|
init_native();
|
|
77536
|
-
KNOWN_AGENT_NAMES = ["claude", "codex", "opencode", "gemini", "aider", "pi",
|
|
78075
|
+
KNOWN_AGENT_NAMES = ["claude", "codex", "opencode", "gemini", "aider", "pi", NATIVE_AGENT_NAME];
|
|
77537
78076
|
_registryTestAdapters = new Map;
|
|
77538
78077
|
});
|
|
77539
78078
|
|
|
@@ -77602,7 +78141,7 @@ class AgentManager {
|
|
|
77602
78141
|
const fromAgent = this._config.agent?.default;
|
|
77603
78142
|
if (typeof fromAgent === "string" && fromAgent.length > 0)
|
|
77604
78143
|
return fromAgent;
|
|
77605
|
-
return
|
|
78144
|
+
return DEFAULT_AGENT_NAME;
|
|
77606
78145
|
}
|
|
77607
78146
|
isUnavailable(agent, tier, model) {
|
|
77608
78147
|
return this._cooldowns.isCooling(agent, tier, this._fallbackIdentity.modelId(agent, tier, model));
|
|
@@ -77992,6 +78531,7 @@ class AgentManager {
|
|
|
77992
78531
|
}
|
|
77993
78532
|
var MAX_EMITTER_LISTENERS = 100, _agentManagerDeps;
|
|
77994
78533
|
var init_manager2 = __esm(() => {
|
|
78534
|
+
init_config();
|
|
77995
78535
|
init_permissions2();
|
|
77996
78536
|
init_errors();
|
|
77997
78537
|
init_logger2();
|
|
@@ -78036,7 +78576,7 @@ function toAssignment(p, models, defaultAgent) {
|
|
|
78036
78576
|
if (!membership.isTier) {
|
|
78037
78577
|
return { agent: p.target.agent, agentProfileId: p.id, profileModelPin: p.target.model };
|
|
78038
78578
|
}
|
|
78039
|
-
if (membership.viaDefaultAgentFallback && p.target.agent ===
|
|
78579
|
+
if (membership.viaDefaultAgentFallback && p.target.agent === NATIVE_AGENT !== (defaultAgent === NATIVE_AGENT)) {
|
|
78040
78580
|
getSafeLogger()?.warn("routing", "Profile tier resolves only via the default agent across a protocol boundary", {
|
|
78041
78581
|
profileId: p.id,
|
|
78042
78582
|
agent: p.target.agent,
|
|
@@ -78046,7 +78586,7 @@ function toAssignment(p, models, defaultAgent) {
|
|
|
78046
78586
|
}
|
|
78047
78587
|
return { agent: p.target.agent, agentProfileId: p.id, profileModelTier: targetModel };
|
|
78048
78588
|
}
|
|
78049
|
-
var
|
|
78589
|
+
var NATIVE_AGENT = "native";
|
|
78050
78590
|
var init_agent_profile_resolver = __esm(() => {
|
|
78051
78591
|
init_config();
|
|
78052
78592
|
init_logger2();
|
|
@@ -78146,7 +78686,11 @@ function resolveDefaultAgent(config2) {
|
|
|
78146
78686
|
return fromAgent;
|
|
78147
78687
|
return FALLBACK_DEFAULT_AGENT;
|
|
78148
78688
|
}
|
|
78149
|
-
var FALLBACK_DEFAULT_AGENT
|
|
78689
|
+
var FALLBACK_DEFAULT_AGENT;
|
|
78690
|
+
var init_utils = __esm(() => {
|
|
78691
|
+
init_config();
|
|
78692
|
+
FALLBACK_DEFAULT_AGENT = DEFAULT_AGENT_NAME;
|
|
78693
|
+
});
|
|
78150
78694
|
|
|
78151
78695
|
// src/agents/index.ts
|
|
78152
78696
|
var init_agents = __esm(() => {
|
|
@@ -78161,20 +78705,24 @@ var init_agents = __esm(() => {
|
|
|
78161
78705
|
init_shared();
|
|
78162
78706
|
init_version_detection();
|
|
78163
78707
|
init_types2();
|
|
78708
|
+
init_utils();
|
|
78164
78709
|
});
|
|
78165
78710
|
|
|
78166
78711
|
// src/cli/agents.ts
|
|
78167
78712
|
async function agentsListCommand(config2, _workdir) {
|
|
78168
|
-
const
|
|
78169
|
-
const
|
|
78713
|
+
const acpReachable = (config2.agent?.protocol ?? DEFAULT_AGENT_PROTOCOL) !== "native";
|
|
78714
|
+
const adapters = acpReachable ? Array.from(ACP_ADAPTER_NAMES).map((name) => new AcpAgentAdapter(name)) : [];
|
|
78715
|
+
const defaultAgent = resolveDefaultAgent(config2);
|
|
78716
|
+
const acpVersions = await Promise.all(adapters.map(async (agent) => ({
|
|
78170
78717
|
name: agent.name,
|
|
78171
78718
|
displayName: agent.displayName,
|
|
78172
78719
|
binary: agent.binary,
|
|
78173
78720
|
version: await _cliAgentsDeps.getAgentVersion(agent.binary),
|
|
78174
78721
|
installed: await agent.isInstalled(),
|
|
78175
78722
|
capabilities: agent.capabilities,
|
|
78176
|
-
isDefault:
|
|
78723
|
+
isDefault: defaultAgent === agent.name
|
|
78177
78724
|
})));
|
|
78725
|
+
const agentVersions = [...nativeListing(config2, defaultAgent), ...acpVersions];
|
|
78178
78726
|
const rows = agentVersions.map((info) => {
|
|
78179
78727
|
const status = info.installed ? "installed" : "unavailable";
|
|
78180
78728
|
const versionStr = info.version || "-";
|
|
@@ -78208,6 +78756,22 @@ Available Agents:
|
|
|
78208
78756
|
}
|
|
78209
78757
|
console.log();
|
|
78210
78758
|
}
|
|
78759
|
+
function nativeListing(config2, defaultAgent) {
|
|
78760
|
+
if ((config2.agent?.protocol ?? DEFAULT_AGENT_PROTOCOL) === "acp")
|
|
78761
|
+
return [];
|
|
78762
|
+
const adapter = new NativeAgentAdapter(Object.keys(config2.models[NATIVE_AGENT_NAME] ?? {}));
|
|
78763
|
+
return [
|
|
78764
|
+
{
|
|
78765
|
+
name: adapter.name,
|
|
78766
|
+
displayName: adapter.displayName,
|
|
78767
|
+
binary: "in-process",
|
|
78768
|
+
version: "",
|
|
78769
|
+
installed: true,
|
|
78770
|
+
capabilities: adapter.capabilities,
|
|
78771
|
+
isDefault: defaultAgent === adapter.name
|
|
78772
|
+
}
|
|
78773
|
+
];
|
|
78774
|
+
}
|
|
78211
78775
|
function pad(str, width) {
|
|
78212
78776
|
return str.padEnd(width);
|
|
78213
78777
|
}
|
|
@@ -78215,7 +78779,9 @@ var _cliAgentsDeps;
|
|
|
78215
78779
|
var init_agents2 = __esm(() => {
|
|
78216
78780
|
init_agents();
|
|
78217
78781
|
init_acp();
|
|
78782
|
+
init_native();
|
|
78218
78783
|
init_version_detection();
|
|
78784
|
+
init_config();
|
|
78219
78785
|
_cliAgentsDeps = { getAgentVersion };
|
|
78220
78786
|
});
|
|
78221
78787
|
|
|
@@ -78917,7 +79483,7 @@ var init_config_descriptions = __esm(() => {
|
|
|
78917
79483
|
"routing.llm.mode": "Routing mode: one-shot | per-story | hybrid",
|
|
78918
79484
|
"routing.llm.timeoutMs": "Timeout for LLM routing call in milliseconds",
|
|
78919
79485
|
execution: "Execution limits and timeouts",
|
|
78920
|
-
"execution.maxIterations": "Max iterations per feature run
|
|
79486
|
+
"execution.maxIterations": "Max iterations per feature run \u2014 each story attempt, parallel batch and the final completion pass counts one",
|
|
78921
79487
|
"execution.iterationDelayMs": "Delay between iterations in milliseconds",
|
|
78922
79488
|
"execution.costLimit": "Max cost in USD before pausing execution (override per run with `nax run --max-cost`)",
|
|
78923
79489
|
"execution.sessionTimeoutSeconds": "Timeout per agent coding session in seconds",
|
|
@@ -79073,7 +79639,6 @@ var init_config_descriptions = __esm(() => {
|
|
|
79073
79639
|
"prompts.overrides.test-writer": 'Path to custom test-writer prompt (e.g., ".nax/prompts/test-writer.md")',
|
|
79074
79640
|
"prompts.overrides.implementer": 'Path to custom implementer prompt (e.g., ".nax/prompts/implementer.md")',
|
|
79075
79641
|
"prompts.overrides.verifier": 'Path to custom verifier prompt (e.g., ".nax/prompts/verifier.md")',
|
|
79076
|
-
"prompts.overrides.single-session": 'Path to custom single-session prompt (e.g., ".nax/prompts/single-session.md")',
|
|
79077
79642
|
agent: "Agent protocol configuration (ACP-003)",
|
|
79078
79643
|
"agent.protocol": "Protocol for agent communication: 'acp' (default) | 'native' | 'hybrid'",
|
|
79079
79644
|
"agent.native.catalogOverrides": "Native only. Explicit catalog entries for model ids newer than the bundled pi-ai snapshot, plus optional provider-wide baseUrl/headers.",
|
|
@@ -79376,7 +79941,7 @@ function displayConfigWithDescriptions(obj, path10, sources, indent = 0) {
|
|
|
79376
79941
|
if (description) {
|
|
79377
79942
|
console.log(`${indentStr}# prompts.overrides: ${description}`);
|
|
79378
79943
|
}
|
|
79379
|
-
const roles = ["test-writer", "implementer", "verifier"
|
|
79944
|
+
const roles = ["test-writer", "implementer", "verifier"];
|
|
79380
79945
|
console.log(`${indentStr}overrides:`);
|
|
79381
79946
|
for (const role of roles) {
|
|
79382
79947
|
const roleDesc = FIELD_DESCRIPTIONS[`prompts.overrides.${role}`];
|
|
@@ -79421,7 +79986,7 @@ function displayConfigWithDescriptions(obj, path10, sources, indent = 0) {
|
|
|
79421
79986
|
if (description) {
|
|
79422
79987
|
console.log(`# prompts.overrides: ${description}`);
|
|
79423
79988
|
}
|
|
79424
|
-
const roles = ["test-writer", "implementer", "verifier"
|
|
79989
|
+
const roles = ["test-writer", "implementer", "verifier"];
|
|
79425
79990
|
console.log("overrides:");
|
|
79426
79991
|
for (const role of roles) {
|
|
79427
79992
|
const roleDesc = FIELD_DESCRIPTIONS[`prompts.overrides.${role}`];
|
|
@@ -80450,75 +81015,6 @@ var init_hardening = __esm(() => {
|
|
|
80450
81015
|
};
|
|
80451
81016
|
});
|
|
80452
81017
|
|
|
80453
|
-
// src/acceptance/semantic-verdict.ts
|
|
80454
|
-
import path11 from "path";
|
|
80455
|
-
async function persistSemanticVerdict(featureDir2, storyId, verdict) {
|
|
80456
|
-
const dir = path11.join(featureDir2, "semantic-verdicts");
|
|
80457
|
-
await _semanticVerdictDeps.mkdirp(dir);
|
|
80458
|
-
const filePath = path11.join(dir, `${storyId}.json`);
|
|
80459
|
-
await _semanticVerdictDeps.writeFile(filePath, JSON.stringify(verdict, null, 2));
|
|
80460
|
-
}
|
|
80461
|
-
function migrateSemanticVerdict(verdict) {
|
|
80462
|
-
if (!verdict.findings?.length)
|
|
80463
|
-
return verdict;
|
|
80464
|
-
const first = verdict.findings[0];
|
|
80465
|
-
if ("source" in first)
|
|
80466
|
-
return verdict;
|
|
80467
|
-
return {
|
|
80468
|
-
...verdict,
|
|
80469
|
-
findings: verdict.findings.map((f) => reviewFindingToFinding(f))
|
|
80470
|
-
};
|
|
80471
|
-
}
|
|
80472
|
-
async function loadSemanticVerdicts(featureDir2) {
|
|
80473
|
-
const dir = path11.join(featureDir2, "semantic-verdicts");
|
|
80474
|
-
let files;
|
|
80475
|
-
try {
|
|
80476
|
-
files = await _semanticVerdictDeps.readdir(dir);
|
|
80477
|
-
} catch (err) {
|
|
80478
|
-
if (err.code === "ENOENT")
|
|
80479
|
-
return [];
|
|
80480
|
-
throw err;
|
|
80481
|
-
}
|
|
80482
|
-
const results = [];
|
|
80483
|
-
for (const file2 of files) {
|
|
80484
|
-
if (!file2.endsWith(".json"))
|
|
80485
|
-
continue;
|
|
80486
|
-
const filePath = path11.join(dir, file2);
|
|
80487
|
-
const content = await _semanticVerdictDeps.readFile(filePath);
|
|
80488
|
-
try {
|
|
80489
|
-
const parsed = JSON.parse(content);
|
|
80490
|
-
results.push(migrateSemanticVerdict(parsed));
|
|
80491
|
-
} catch {
|
|
80492
|
-
_semanticVerdictDeps.logDebug(`Skipping invalid JSON in semantic-verdicts/${file2}`);
|
|
80493
|
-
}
|
|
80494
|
-
}
|
|
80495
|
-
return results;
|
|
80496
|
-
}
|
|
80497
|
-
var _semanticVerdictDeps;
|
|
80498
|
-
var init_semantic_verdict = __esm(() => {
|
|
80499
|
-
init_findings();
|
|
80500
|
-
init_logger2();
|
|
80501
|
-
_semanticVerdictDeps = {
|
|
80502
|
-
mkdirp: async (dir) => {
|
|
80503
|
-
const { mkdir: mkdir21 } = await import("fs/promises");
|
|
80504
|
-
await mkdir21(dir, { recursive: true });
|
|
80505
|
-
},
|
|
80506
|
-
writeFile: async (filePath, content) => {
|
|
80507
|
-
await Bun.write(filePath, content);
|
|
80508
|
-
},
|
|
80509
|
-
readdir: async (dir) => {
|
|
80510
|
-
const { readdir: readdir7 } = await import("fs/promises");
|
|
80511
|
-
return readdir7(dir);
|
|
80512
|
-
},
|
|
80513
|
-
readFile: async (filePath) => {
|
|
80514
|
-
return Bun.file(filePath).text();
|
|
80515
|
-
},
|
|
80516
|
-
logDebug: (msg) => {
|
|
80517
|
-
getLogger()?.debug("semantic-verdict", msg);
|
|
80518
|
-
}
|
|
80519
|
-
};
|
|
80520
|
-
});
|
|
80521
|
-
|
|
80522
81018
|
// src/acceptance/index.ts
|
|
80523
81019
|
var exports_acceptance = {};
|
|
80524
81020
|
__export(exports_acceptance, {
|
|
@@ -80531,11 +81027,9 @@ __export(exports_acceptance, {
|
|
|
80531
81027
|
groupStoriesByPackage: () => groupStoriesByPackage,
|
|
80532
81028
|
isStubTestContent: () => isStubTestContent,
|
|
80533
81029
|
loadAcceptanceTestContent: () => loadAcceptanceTestContent,
|
|
80534
|
-
loadSemanticVerdicts: () => loadSemanticVerdicts,
|
|
80535
81030
|
loadSourceFilesForDiagnosis: () => loadSourceFilesForDiagnosis,
|
|
80536
81031
|
parseAcceptanceCriteria: () => parseAcceptanceCriteria,
|
|
80537
81032
|
parseRefinementResponse: () => parseRefinementResponse,
|
|
80538
|
-
persistSemanticVerdict: () => persistSemanticVerdict,
|
|
80539
81033
|
refinementWouldFallback: () => refinementWouldFallback,
|
|
80540
81034
|
resolveAcceptanceFeatureTestPath: () => resolveAcceptanceFeatureTestPath,
|
|
80541
81035
|
resolveSuggestedPackageFeatureTestPath: () => resolveSuggestedPackageFeatureTestPath,
|
|
@@ -80549,7 +81043,6 @@ var init_acceptance2 = __esm(() => {
|
|
|
80549
81043
|
init_generator();
|
|
80550
81044
|
init_hardening();
|
|
80551
81045
|
init_refinement();
|
|
80552
|
-
init_semantic_verdict();
|
|
80553
81046
|
init_test_path();
|
|
80554
81047
|
});
|
|
80555
81048
|
|
|
@@ -81545,11 +82038,11 @@ var init_generate = __esm(() => {
|
|
|
81545
82038
|
// src/cli/init-context.ts
|
|
81546
82039
|
import { mkdir as mkdir21, readdir as readdir7 } from "fs/promises";
|
|
81547
82040
|
import { basename as basename11, join as join74, relative as relative23, sep as sep12 } from "path";
|
|
81548
|
-
async function bunFileExists(
|
|
81549
|
-
return Bun.file(
|
|
82041
|
+
async function bunFileExists(path11) {
|
|
82042
|
+
return Bun.file(path11).exists();
|
|
81550
82043
|
}
|
|
81551
|
-
async function mkdirp(
|
|
81552
|
-
await mkdir21(
|
|
82044
|
+
async function mkdirp(path11) {
|
|
82045
|
+
await mkdir21(path11, { recursive: true });
|
|
81553
82046
|
}
|
|
81554
82047
|
async function findFiles(dir, maxFiles = 200) {
|
|
81555
82048
|
const files = [];
|
|
@@ -81612,8 +82105,8 @@ async function detectEntryPoints(projectRoot) {
|
|
|
81612
82105
|
const candidates = ["src/index.ts", "src/main.ts", "main.go", "src/lib.rs"];
|
|
81613
82106
|
const found = [];
|
|
81614
82107
|
for (const candidate of candidates) {
|
|
81615
|
-
const
|
|
81616
|
-
if (await bunFileExists(
|
|
82108
|
+
const path11 = join74(projectRoot, candidate);
|
|
82109
|
+
if (await bunFileExists(path11)) {
|
|
81617
82110
|
found.push(candidate);
|
|
81618
82111
|
}
|
|
81619
82112
|
}
|
|
@@ -81623,8 +82116,8 @@ async function detectConfigFiles(projectRoot) {
|
|
|
81623
82116
|
const candidates = ["tsconfig.json", "biome.json", "turbo.json", ".env.example"];
|
|
81624
82117
|
const found = [];
|
|
81625
82118
|
for (const candidate of candidates) {
|
|
81626
|
-
const
|
|
81627
|
-
if (await bunFileExists(
|
|
82119
|
+
const path11 = join74(projectRoot, candidate);
|
|
82120
|
+
if (await bunFileExists(path11)) {
|
|
81628
82121
|
found.push(candidate);
|
|
81629
82122
|
}
|
|
81630
82123
|
}
|
|
@@ -82453,9 +82946,9 @@ var init_scanner = __esm(() => {
|
|
|
82453
82946
|
_scannerDeps = {
|
|
82454
82947
|
discoverWorkspacePackages: (workdir) => discoverWorkspacePackages2(workdir),
|
|
82455
82948
|
detectLanguage: (pkgDir) => detectLanguage(pkgDir),
|
|
82456
|
-
readPackageJson: async (
|
|
82949
|
+
readPackageJson: async (path11) => {
|
|
82457
82950
|
try {
|
|
82458
|
-
const file2 = Bun.file(
|
|
82951
|
+
const file2 = Bun.file(path11);
|
|
82459
82952
|
if (!await file2.exists())
|
|
82460
82953
|
return null;
|
|
82461
82954
|
return await file2.json();
|
|
@@ -82476,6 +82969,7 @@ var init_analyze = __esm(() => {
|
|
|
82476
82969
|
function createHumanAskLink(opts) {
|
|
82477
82970
|
let queue = Promise.resolve();
|
|
82478
82971
|
let activeId;
|
|
82972
|
+
const canRemember = (req) => opts.onRemember !== undefined && req.command !== undefined;
|
|
82479
82973
|
const deny3 = (decidedBy) => ({
|
|
82480
82974
|
decision: "deny",
|
|
82481
82975
|
decidedBy
|
|
@@ -82613,7 +83107,7 @@ function createHumanAskLink(opts) {
|
|
|
82613
83107
|
`stage: ${req.stage}`
|
|
82614
83108
|
].join(`
|
|
82615
83109
|
`),
|
|
82616
|
-
options:
|
|
83110
|
+
options: canRemember(req) ? [ALLOW_ONCE, ALLOW_REMEMBER, DENY] : [ALLOW_ONCE, DENY],
|
|
82617
83111
|
timeout: opts.timeoutMs,
|
|
82618
83112
|
fallback: "abort",
|
|
82619
83113
|
createdAt: Date.now(),
|
|
@@ -82631,7 +83125,7 @@ function createHumanAskLink(opts) {
|
|
|
82631
83125
|
if (!PERMITS.has(action)) {
|
|
82632
83126
|
outcome = deny3("human");
|
|
82633
83127
|
} else {
|
|
82634
|
-
if (action === "allow-remember" && opts.onRemember) {
|
|
83128
|
+
if (action === "allow-remember" && canRemember(req) && opts.onRemember) {
|
|
82635
83129
|
try {
|
|
82636
83130
|
await opts.onRemember(req);
|
|
82637
83131
|
} catch (err) {
|
|
@@ -82757,7 +83251,7 @@ function createHumanAskLink(opts) {
|
|
|
82757
83251
|
async function cancelPendingAsk(link) {
|
|
82758
83252
|
await link.cancel();
|
|
82759
83253
|
}
|
|
82760
|
-
var MAX_COMMAND_CHARS = 3500, maskedFooter = (count) => `${count} secret value(s) masked; the approved command contains them`, _askLinkDeps,
|
|
83254
|
+
var MAX_COMMAND_CHARS = 3500, maskedFooter = (count) => `${count} secret value(s) masked; the approved command contains them`, _askLinkDeps, ALLOW_ONCE, ALLOW_REMEMBER, DENY, PERMITS;
|
|
82761
83255
|
var init_ask_link = __esm(() => {
|
|
82762
83256
|
init_permissions();
|
|
82763
83257
|
init_logger2();
|
|
@@ -82766,11 +83260,9 @@ var init_ask_link = __esm(() => {
|
|
|
82766
83260
|
clearTimeout: (id) => clearTimeout(id),
|
|
82767
83261
|
ASK_KEEPALIVE_MS: 60000
|
|
82768
83262
|
};
|
|
82769
|
-
|
|
82770
|
-
|
|
82771
|
-
|
|
82772
|
-
{ key: "deny", label: "Deny" }
|
|
82773
|
-
];
|
|
83263
|
+
ALLOW_ONCE = { key: "allow", label: "Allow once" };
|
|
83264
|
+
ALLOW_REMEMBER = { key: "allow-remember", label: "Allow + remember" };
|
|
83265
|
+
DENY = { key: "deny", label: "Deny" };
|
|
82774
83266
|
PERMITS = new Set(["allow", "allow-remember"]);
|
|
82775
83267
|
});
|
|
82776
83268
|
|
|
@@ -82944,10 +83436,10 @@ async function buildDispatchAskWiring(opts, deps = _dispatchAskDeps) {
|
|
|
82944
83436
|
stage: req.stage,
|
|
82945
83437
|
command: req.command ?? "",
|
|
82946
83438
|
root: req.root ?? opts.repoRoot,
|
|
82947
|
-
origin: "escalate",
|
|
82948
|
-
matchedRule: null,
|
|
83439
|
+
origin: req.matchedRule !== undefined ? "askRule" : "escalate",
|
|
83440
|
+
matchedRule: req.matchedRule ?? null,
|
|
82949
83441
|
approvedAt: new Date().toISOString(),
|
|
82950
|
-
approvedBy: "
|
|
83442
|
+
approvedBy: opts.config.interaction?.plugin ?? "unknown",
|
|
82951
83443
|
naxCommit: NAX_COMMIT
|
|
82952
83444
|
})
|
|
82953
83445
|
});
|
|
@@ -83025,6 +83517,25 @@ async function collectEffectiveRunStageModes(opts, deps = _dispatchAskDeps) {
|
|
|
83025
83517
|
})));
|
|
83026
83518
|
return collectRunStageModes([opts.rootConfig, ...opts.extraConfigs ?? [], ...packageConfigs]);
|
|
83027
83519
|
}
|
|
83520
|
+
async function buildApprovalsSeal(opts, deps = _dispatchAskDeps) {
|
|
83521
|
+
const stageModes = await collectEffectiveRunStageModes({ projectDir: opts.projectDir, rootConfig: opts.rootConfig, packageDirs: opts.packageDirs }, deps);
|
|
83522
|
+
const forgeCapable = isForgeCapable(stageModes, opts.rootConfig.execution?.sandbox?.enabled === true);
|
|
83523
|
+
if (!forgeCapable)
|
|
83524
|
+
return async () => {};
|
|
83525
|
+
const approvalsFile = approvalsPath(opts.outputDir);
|
|
83526
|
+
const runId = opts.runId;
|
|
83527
|
+
return async () => {
|
|
83528
|
+
try {
|
|
83529
|
+
await deps.prepareApprovalsStore({ approvalsFile, runId, forgeCapable: true });
|
|
83530
|
+
} catch (error48) {
|
|
83531
|
+
getSafeLogger()?.warn("permissions", "[approvals] could not update the store's taint marker", {
|
|
83532
|
+
approvalsFile,
|
|
83533
|
+
forgeCapable: true,
|
|
83534
|
+
error: error48
|
|
83535
|
+
});
|
|
83536
|
+
}
|
|
83537
|
+
};
|
|
83538
|
+
}
|
|
83028
83539
|
async function buildRunDispatchAskWiring(opts, deps = _dispatchAskDeps) {
|
|
83029
83540
|
const stageModes = await collectEffectiveRunStageModes({
|
|
83030
83541
|
projectDir: opts.projectDir,
|
|
@@ -83038,6 +83549,7 @@ var DEFAULT_APPROVAL_TIMEOUT_MS = 600000, APPROVAL_AUDIT_DIR = "approval-audit",
|
|
|
83038
83549
|
var init_dispatch_ask = __esm(() => {
|
|
83039
83550
|
init_command_safety();
|
|
83040
83551
|
init_config();
|
|
83552
|
+
init_logger2();
|
|
83041
83553
|
init_permissions();
|
|
83042
83554
|
init_version();
|
|
83043
83555
|
init_ask_link();
|
|
@@ -84723,6 +85235,14 @@ async function checkClaudeCLI() {
|
|
|
84723
85235
|
}
|
|
84724
85236
|
async function checkAgentCLI(config2) {
|
|
84725
85237
|
const agent = resolveDefaultAgent(config2);
|
|
85238
|
+
if (agent === NATIVE_AGENT_NAME) {
|
|
85239
|
+
return {
|
|
85240
|
+
name: "agent-cli-available",
|
|
85241
|
+
tier: "blocker",
|
|
85242
|
+
passed: true,
|
|
85243
|
+
message: "native agent runs in-process; no CLI binary required"
|
|
85244
|
+
};
|
|
85245
|
+
}
|
|
84726
85246
|
try {
|
|
84727
85247
|
const proc = _checkCliDeps.spawn([agent, "--version"], {
|
|
84728
85248
|
stdout: "pipe",
|
|
@@ -84748,6 +85268,7 @@ async function checkAgentCLI(config2) {
|
|
|
84748
85268
|
var _checkCliDeps;
|
|
84749
85269
|
var init_checks_cli = __esm(() => {
|
|
84750
85270
|
init_agents();
|
|
85271
|
+
init_native();
|
|
84751
85272
|
init_bun_deps();
|
|
84752
85273
|
_checkCliDeps = {
|
|
84753
85274
|
spawn
|
|
@@ -88145,6 +88666,11 @@ async function performTeardown(ctx) {
|
|
|
88145
88666
|
if (ctx.pidRegistry) {
|
|
88146
88667
|
await ctx.pidRegistry.killAll();
|
|
88147
88668
|
}
|
|
88669
|
+
if (ctx.sealApprovals) {
|
|
88670
|
+
await ctx.sealApprovals().catch(() => {
|
|
88671
|
+
return;
|
|
88672
|
+
});
|
|
88673
|
+
}
|
|
88148
88674
|
}
|
|
88149
88675
|
function getSignalNumber(signal) {
|
|
88150
88676
|
const signalMap = {
|
|
@@ -88301,7 +88827,7 @@ var init_crash_recovery = __esm(() => {
|
|
|
88301
88827
|
});
|
|
88302
88828
|
|
|
88303
88829
|
// src/execution/ensure-package-dirs.ts
|
|
88304
|
-
import
|
|
88830
|
+
import path11 from "path";
|
|
88305
88831
|
async function ensureStoryPackageDirs(prd, workdir, deps = _ensurePackageDirsDeps) {
|
|
88306
88832
|
const logger = getSafeLogger();
|
|
88307
88833
|
const relToStoryId = new Map;
|
|
@@ -88314,8 +88840,8 @@ async function ensureStoryPackageDirs(prd, workdir, deps = _ensurePackageDirsDep
|
|
|
88314
88840
|
}
|
|
88315
88841
|
const created = [];
|
|
88316
88842
|
for (const [rel, storyId] of relToStoryId) {
|
|
88317
|
-
const abs =
|
|
88318
|
-
const rootWithSep = workdir.endsWith(
|
|
88843
|
+
const abs = path11.resolve(workdir, rel);
|
|
88844
|
+
const rootWithSep = workdir.endsWith(path11.sep) ? workdir : workdir + path11.sep;
|
|
88319
88845
|
if (abs !== workdir && !abs.startsWith(rootWithSep)) {
|
|
88320
88846
|
logger?.warn("execution", "Skipping story workdir outside repo root", {
|
|
88321
88847
|
storyId,
|
|
@@ -88466,8 +88992,8 @@ async function verifyQuoteTriple(triple, workdir, deps = _quoteIntegrityDeps) {
|
|
|
88466
88992
|
return false;
|
|
88467
88993
|
const lines = content.split(`
|
|
88468
88994
|
`);
|
|
88469
|
-
const start = Math.max(0, triple.line - 1 -
|
|
88470
|
-
const end = Math.min(lines.length, triple.line +
|
|
88995
|
+
const start = Math.max(0, triple.line - 1 - CONTEXT_LINES2);
|
|
88996
|
+
const end = Math.min(lines.length, triple.line + CONTEXT_LINES2);
|
|
88471
88997
|
const window2 = lines.slice(start, end).join(`
|
|
88472
88998
|
`);
|
|
88473
88999
|
return normalizeWs2(window2).toLowerCase().includes(normalizeWs2(triple.quote).toLowerCase());
|
|
@@ -88492,14 +89018,14 @@ async function verifyEscalationQuotes(reason, workdir, storyId, deps = _quoteInt
|
|
|
88492
89018
|
}
|
|
88493
89019
|
return verified;
|
|
88494
89020
|
}
|
|
88495
|
-
var _quoteIntegrityDeps,
|
|
89021
|
+
var _quoteIntegrityDeps, CONTEXT_LINES2 = 3;
|
|
88496
89022
|
var init_quote_integrity = __esm(() => {
|
|
88497
89023
|
init_logger2();
|
|
88498
89024
|
init_path_security2();
|
|
88499
89025
|
_quoteIntegrityDeps = {
|
|
88500
|
-
readFile: async (
|
|
89026
|
+
readFile: async (path12) => {
|
|
88501
89027
|
try {
|
|
88502
|
-
return await Bun.file(
|
|
89028
|
+
return await Bun.file(path12).text();
|
|
88503
89029
|
} catch {
|
|
88504
89030
|
return null;
|
|
88505
89031
|
}
|
|
@@ -88939,7 +89465,7 @@ var init_escalation = __esm(() => {
|
|
|
88939
89465
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
88940
89466
|
import { rename as rename5, unlink as unlink5 } from "fs/promises";
|
|
88941
89467
|
import { hostname as hostname3 } from "os";
|
|
88942
|
-
import
|
|
89468
|
+
import path12 from "path";
|
|
88943
89469
|
function getSafeLogger3() {
|
|
88944
89470
|
try {
|
|
88945
89471
|
return getLogger();
|
|
@@ -89019,7 +89545,7 @@ async function claimReclaimableLock(lockPath, observedContent, lockData) {
|
|
|
89019
89545
|
return { action: "discard" };
|
|
89020
89546
|
}
|
|
89021
89547
|
async function acquireLock(workdir) {
|
|
89022
|
-
const lockPath =
|
|
89548
|
+
const lockPath = path12.join(workdir, "nax.lock");
|
|
89023
89549
|
const lockFile = Bun.file(lockPath);
|
|
89024
89550
|
try {
|
|
89025
89551
|
const exists2 = await lockFile.exists();
|
|
@@ -89072,7 +89598,7 @@ async function acquireLock(workdir) {
|
|
|
89072
89598
|
}
|
|
89073
89599
|
}
|
|
89074
89600
|
async function releaseLock(workdir) {
|
|
89075
|
-
const lockPath =
|
|
89601
|
+
const lockPath = path12.join(workdir, "nax.lock");
|
|
89076
89602
|
try {
|
|
89077
89603
|
await unlink5(lockPath);
|
|
89078
89604
|
} catch (error48) {
|
|
@@ -89097,7 +89623,7 @@ var init_lock2 = __esm(() => {
|
|
|
89097
89623
|
// src/execution/feature-lock.ts
|
|
89098
89624
|
import { mkdir as mkdir24, rename as rename6, unlink as unlink6 } from "fs/promises";
|
|
89099
89625
|
import { hostname as hostname4 } from "os";
|
|
89100
|
-
import
|
|
89626
|
+
import path13 from "path";
|
|
89101
89627
|
function validateFeatureId2(featureId) {
|
|
89102
89628
|
if (!featureId || featureId.length === 0) {
|
|
89103
89629
|
throw new NaxError("Feature ID cannot be empty", "INVALID_FEATURE_ID", { stage: "feature-lock" });
|
|
@@ -89127,7 +89653,7 @@ function getSafeLogger4() {
|
|
|
89127
89653
|
}
|
|
89128
89654
|
function featureLockPath(outputDir, feature) {
|
|
89129
89655
|
validateFeatureId2(feature);
|
|
89130
|
-
return
|
|
89656
|
+
return path13.join(outputDir, "features", feature, "nax.lock");
|
|
89131
89657
|
}
|
|
89132
89658
|
function lockHost() {
|
|
89133
89659
|
return _featureLockDeps.host();
|
|
@@ -89188,7 +89714,7 @@ function emptyHolder(feature) {
|
|
|
89188
89714
|
}
|
|
89189
89715
|
async function acquireFeatureLock(args) {
|
|
89190
89716
|
const lockPath = _featureLockDeps.featureLockPath(args.outputDir, args.feature);
|
|
89191
|
-
const featureDir2 =
|
|
89717
|
+
const featureDir2 = path13.dirname(lockPath);
|
|
89192
89718
|
await mkdir24(featureDir2, { recursive: true });
|
|
89193
89719
|
const lockFile = Bun.file(lockPath);
|
|
89194
89720
|
if (await lockFile.exists()) {
|
|
@@ -90645,7 +91171,7 @@ var init_acceptance3 = __esm(() => {
|
|
|
90645
91171
|
});
|
|
90646
91172
|
|
|
90647
91173
|
// src/pipeline/stages/acceptance-setup.ts
|
|
90648
|
-
import
|
|
91174
|
+
import path14 from "path";
|
|
90649
91175
|
function computeACFingerprint(criteria) {
|
|
90650
91176
|
const sorted = [...criteria].sort().join(`
|
|
90651
91177
|
`);
|
|
@@ -90655,7 +91181,7 @@ function computeACFingerprint(criteria) {
|
|
|
90655
91181
|
}
|
|
90656
91182
|
function computeAcceptanceLayoutFingerprint(workdir, groups) {
|
|
90657
91183
|
const layout = groups.map(({ testPath, stories }) => ({
|
|
90658
|
-
testPath:
|
|
91184
|
+
testPath: path14.relative(workdir, testPath).replaceAll(path14.sep, "/"),
|
|
90659
91185
|
storyIds: stories.map((story) => story.id).sort()
|
|
90660
91186
|
})).sort((a, b) => a.testPath.localeCompare(b.testPath));
|
|
90661
91187
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -90665,14 +91191,14 @@ function computeAcceptanceLayoutFingerprint(workdir, groups) {
|
|
|
90665
91191
|
async function runAcceptanceSetup(ctx, featureDir2, phaseStartTime) {
|
|
90666
91192
|
const language = ctx.config.project?.language;
|
|
90667
91193
|
const testPathConfig = ctx.config.acceptance.testPath;
|
|
90668
|
-
const metaPath =
|
|
91194
|
+
const metaPath = path14.join(featureDir2, "acceptance-meta.json");
|
|
90669
91195
|
const allCriteria = ctx.prd.userStories.filter(isInAcceptanceScope).flatMap((s) => s.acceptanceCriteria);
|
|
90670
91196
|
const featureName = ctx.prd.feature ?? ctx.prd.featureName;
|
|
90671
91197
|
const groups = await groupStoriesByPackage(ctx.prd, ctx.workdir, featureName, testPathConfig, language);
|
|
90672
91198
|
const nonFixStories = groups.flatMap((g) => g.stories);
|
|
90673
91199
|
const groupConfigs = new Map;
|
|
90674
91200
|
for (const group of groups) {
|
|
90675
|
-
const relativeWorkdir =
|
|
91201
|
+
const relativeWorkdir = path14.relative(ctx.projectDir, group.packageDir);
|
|
90676
91202
|
let config2 = ctx.config;
|
|
90677
91203
|
if (relativeWorkdir && relativeWorkdir !== ".") {
|
|
90678
91204
|
try {
|
|
@@ -90717,7 +91243,6 @@ async function runAcceptanceSetup(ctx, featureDir2, phaseStartTime) {
|
|
|
90717
91243
|
await _acceptanceSetupDeps.deleteFile(testPath);
|
|
90718
91244
|
}
|
|
90719
91245
|
}
|
|
90720
|
-
await _acceptanceSetupDeps.deleteSemanticVerdicts(featureDir2);
|
|
90721
91246
|
shouldGenerate = true;
|
|
90722
91247
|
regenerated = true;
|
|
90723
91248
|
} else {
|
|
@@ -90825,7 +91350,7 @@ async function runAcceptanceSetup(ctx, featureDir2, phaseStartTime) {
|
|
|
90825
91350
|
testable: c.testable,
|
|
90826
91351
|
storyId: c.storyId
|
|
90827
91352
|
})), null, 2);
|
|
90828
|
-
await _acceptanceSetupDeps.writeFile(
|
|
91353
|
+
await _acceptanceSetupDeps.writeFile(path14.join(featureDir2, "acceptance-refined.json"), refinedJsonContent);
|
|
90829
91354
|
}
|
|
90830
91355
|
if (sawDispatchFailure) {
|
|
90831
91356
|
getSafeLogger()?.warn("acceptance-setup", "generation dispatch failed; not recording acceptance meta so the next run regenerates", { storyId: ctx.story?.id, metaPath });
|
|
@@ -90937,21 +91462,6 @@ var init_acceptance_setup = __esm(() => {
|
|
|
90937
91462
|
throw err;
|
|
90938
91463
|
}
|
|
90939
91464
|
},
|
|
90940
|
-
deleteSemanticVerdicts: async (featureDir2) => {
|
|
90941
|
-
const dir = `${featureDir2}/semantic-verdicts`;
|
|
90942
|
-
const { readdir: readdir8, unlink: unlink7 } = await import("fs/promises");
|
|
90943
|
-
let files;
|
|
90944
|
-
try {
|
|
90945
|
-
files = await readdir8(dir);
|
|
90946
|
-
} catch (err) {
|
|
90947
|
-
if (err.code === "ENOENT")
|
|
90948
|
-
return;
|
|
90949
|
-
throw err;
|
|
90950
|
-
}
|
|
90951
|
-
for (const file2 of files) {
|
|
90952
|
-
await unlink7(`${dir}/${file2}`);
|
|
90953
|
-
}
|
|
90954
|
-
},
|
|
90955
91465
|
readMeta: async (metaPath) => {
|
|
90956
91466
|
const f = Bun.file(metaPath);
|
|
90957
91467
|
if (!await f.exists())
|
|
@@ -91156,7 +91666,6 @@ async function getDiffFilePaths(workdir, baseRef) {
|
|
|
91156
91666
|
}
|
|
91157
91667
|
var MAX_DIFF_TEXT_CHARS = 8000, HIGH_MEMORY_TELEMETRY_BYTES, STREAM_DRAIN_DEADLINE_MS = 2000, completionStage, _completionDeps;
|
|
91158
91668
|
var init_completion = __esm(() => {
|
|
91159
|
-
init_acceptance2();
|
|
91160
91669
|
init_config();
|
|
91161
91670
|
init_engine();
|
|
91162
91671
|
init_fragments();
|
|
@@ -91276,7 +91785,6 @@ var init_completion = __esm(() => {
|
|
|
91276
91785
|
};
|
|
91277
91786
|
_completionDeps = {
|
|
91278
91787
|
checkReviewGate,
|
|
91279
|
-
persistSemanticVerdict,
|
|
91280
91788
|
savePRD,
|
|
91281
91789
|
getDiffText,
|
|
91282
91790
|
getDiffFilePaths,
|
|
@@ -92052,9 +92560,9 @@ var init_prompt2 = __esm(() => {
|
|
|
92052
92560
|
});
|
|
92053
92561
|
|
|
92054
92562
|
// src/pipeline/stages/queue-check.ts
|
|
92055
|
-
import
|
|
92563
|
+
import path15 from "path";
|
|
92056
92564
|
function resolvePrdPath(ctx) {
|
|
92057
|
-
return
|
|
92565
|
+
return path15.join(ctx.featureDir ?? featureDir(ctx.workdir, "unknown"), "prd.json");
|
|
92058
92566
|
}
|
|
92059
92567
|
function logDroppedCommands(logger, ctx, queueCommands, currentIndex) {
|
|
92060
92568
|
const dropped = queueCommands.slice(currentIndex + 1);
|
|
@@ -92105,10 +92613,10 @@ async function processQueueCommands(ctx, logger, queueCommands) {
|
|
|
92105
92613
|
}
|
|
92106
92614
|
if (cmd.type === "INJECT") {
|
|
92107
92615
|
try {
|
|
92108
|
-
if (
|
|
92616
|
+
if (path15.isAbsolute(cmd.storyFile)) {
|
|
92109
92617
|
throw new NaxError(`INJECT storyFile must be a relative path within the workspace: ${cmd.storyFile}`, "INJECT_PATH_ABSOLUTE", { stage: "queue-check", storyId: ctx.story?.id ?? "unknown", storyFile: cmd.storyFile });
|
|
92110
92618
|
}
|
|
92111
|
-
const storyFilePath = validateFilePath(
|
|
92619
|
+
const storyFilePath = validateFilePath(path15.join(ctx.workdir, cmd.storyFile), ctx.workdir);
|
|
92112
92620
|
const raw = await Bun.file(storyFilePath).json();
|
|
92113
92621
|
const existingIds = new Set(ctx.prd.userStories.map((s) => s.id));
|
|
92114
92622
|
const story = validateInjectedStory(raw, existingIds);
|
|
@@ -93486,7 +93994,7 @@ var init_hooks = __esm(() => {
|
|
|
93486
93994
|
});
|
|
93487
93995
|
|
|
93488
93996
|
// src/execution/lifecycle/acceptance-helpers.ts
|
|
93489
|
-
import
|
|
93997
|
+
import path16 from "path";
|
|
93490
93998
|
function resolveAcceptanceFixTarget(acceptanceTestPaths, failedPackage, config2) {
|
|
93491
93999
|
const matchedEntry = failedPackage ? acceptanceTestPaths?.find((entry) => entry.testPath === failedPackage.testPath || entry.packageDir === failedPackage.packageDir) : undefined;
|
|
93492
94000
|
const selectedPathEntry = matchedEntry ?? acceptanceTestPaths?.[0];
|
|
@@ -93509,10 +94017,7 @@ function resolveAcceptanceFixTarget(acceptanceTestPaths, failedPackage, config2)
|
|
|
93509
94017
|
function isStubTestFile(content) {
|
|
93510
94018
|
return isStubTestContent(content);
|
|
93511
94019
|
}
|
|
93512
|
-
function isTestLevelFailure(failedACs, totalACs
|
|
93513
|
-
if (semanticVerdicts && semanticVerdicts.length > 0 && semanticVerdicts.every((v) => v.passed)) {
|
|
93514
|
-
return true;
|
|
93515
|
-
}
|
|
94020
|
+
function isTestLevelFailure(failedACs, totalACs) {
|
|
93516
94021
|
const failedCount = typeof failedACs === "number" ? failedACs : failedACs.length;
|
|
93517
94022
|
const hasACError = Array.isArray(failedACs) && failedACs.includes("AC-ERROR");
|
|
93518
94023
|
if (hasACError)
|
|
@@ -93524,7 +94029,7 @@ function isTestLevelFailure(failedACs, totalACs, semanticVerdicts) {
|
|
|
93524
94029
|
async function loadSpecContent(featureDir2) {
|
|
93525
94030
|
if (!featureDir2)
|
|
93526
94031
|
return "";
|
|
93527
|
-
const specPath =
|
|
94032
|
+
const specPath = path16.join(featureDir2, "spec.md");
|
|
93528
94033
|
const specFile = Bun.file(specPath);
|
|
93529
94034
|
return await specFile.exists() ? await specFile.text() : "";
|
|
93530
94035
|
}
|
|
@@ -93544,7 +94049,7 @@ async function loadAcceptanceTestContent2(featureDir2, testPaths, configuredTest
|
|
|
93544
94049
|
}
|
|
93545
94050
|
if (!configuredTestPath)
|
|
93546
94051
|
return [];
|
|
93547
|
-
const resolvedPath =
|
|
94052
|
+
const resolvedPath = path16.join(featureDir2, configuredTestPath);
|
|
93548
94053
|
const testFile = Bun.file(resolvedPath);
|
|
93549
94054
|
const content = await testFile.exists() ? await testFile.text() : "";
|
|
93550
94055
|
return [{ content, path: resolvedPath }];
|
|
@@ -93574,7 +94079,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
|
|
|
93574
94079
|
const { unlink: unlink7 } = await import("fs/promises");
|
|
93575
94080
|
await unlink7(testPath);
|
|
93576
94081
|
if (acceptanceContext.featureDir) {
|
|
93577
|
-
const metaPath =
|
|
94082
|
+
const metaPath = path16.join(acceptanceContext.featureDir, "acceptance-meta.json");
|
|
93578
94083
|
try {
|
|
93579
94084
|
await unlink7(metaPath);
|
|
93580
94085
|
} catch {}
|
|
@@ -93590,7 +94095,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
|
|
|
93590
94095
|
const diffOutput = await _regenerateDeps.spawnGitDiff(repoRoot, storyGitRef, pathspec);
|
|
93591
94096
|
const changedFilesRaw = diffOutput.split(`
|
|
93592
94097
|
`).map((f) => f.trim()).filter((f) => f.length > 0);
|
|
93593
|
-
const packageDir = storyPkg && acceptanceContext.projectDir ?
|
|
94098
|
+
const packageDir = storyPkg && acceptanceContext.projectDir ? path16.join(acceptanceContext.projectDir, storyPkg) : undefined;
|
|
93594
94099
|
const ignoreMatchers = acceptanceContext.naxIgnoreIndex?.getMatchers(packageDir) ?? await resolveNaxIgnorePatterns(repoRoot, packageDir);
|
|
93595
94100
|
const changedFiles2 = filterNaxInternalPaths(changedFilesRaw, ignoreMatchers);
|
|
93596
94101
|
const MAX_BYTES = 51200;
|
|
@@ -93602,7 +94107,7 @@ async function regenerateAcceptanceTest(testPath, acceptanceContext) {
|
|
|
93602
94107
|
for (const file2 of changedFiles2) {
|
|
93603
94108
|
if (totalBytes >= MAX_BYTES)
|
|
93604
94109
|
break;
|
|
93605
|
-
const filePath =
|
|
94110
|
+
const filePath = path16.join(repoRoot, file2);
|
|
93606
94111
|
try {
|
|
93607
94112
|
const fileContent = await _regenerateDeps.readFile(filePath);
|
|
93608
94113
|
const remaining = MAX_BYTES - totalBytes;
|
|
@@ -93689,7 +94194,7 @@ function fixCallCtx(ctx, packageDir, config2) {
|
|
|
93689
94194
|
}
|
|
93690
94195
|
async function resolveAcceptanceDiagnosis(opts) {
|
|
93691
94196
|
const logger = getSafeLogger();
|
|
93692
|
-
const { ctx, failures, totalACs, strategy,
|
|
94197
|
+
const { ctx, failures, totalACs, strategy, diagnosisOpts } = opts;
|
|
93693
94198
|
const storyId = diagnosisOpts.storyId;
|
|
93694
94199
|
if (strategy === "implement-only") {
|
|
93695
94200
|
logger?.info("acceptance.diagnosis", "Fast path: implement-only strategy \u2192 source_bug", { storyId });
|
|
@@ -93699,19 +94204,6 @@ async function resolveAcceptanceDiagnosis(opts) {
|
|
|
93699
94204
|
confidence: 1
|
|
93700
94205
|
};
|
|
93701
94206
|
}
|
|
93702
|
-
const SENTINELS = ["AC-ERROR", "AC-HOOK"];
|
|
93703
|
-
const hasOnlySentinels = failures.failedACs.length > 0 && failures.failedACs.every((ac) => SENTINELS.includes(ac));
|
|
93704
|
-
if (!hasOnlySentinels && semanticVerdicts.length > 0 && semanticVerdicts.every((v) => v.passed)) {
|
|
93705
|
-
logger?.info("acceptance.diagnosis", "Fast path: all semantic verdicts passed \u2192 test_bug", {
|
|
93706
|
-
storyId,
|
|
93707
|
-
verdictCount: semanticVerdicts.length
|
|
93708
|
-
});
|
|
93709
|
-
return {
|
|
93710
|
-
verdict: "test_bug",
|
|
93711
|
-
reasoning: `Semantic review confirmed all ${semanticVerdicts.length} ACs are implemented \u2014 failure is a test generation issue`,
|
|
93712
|
-
confidence: 1
|
|
93713
|
-
};
|
|
93714
|
-
}
|
|
93715
94207
|
if (isTestLevelFailure(failures.failedACs, totalACs)) {
|
|
93716
94208
|
logger?.info("acceptance.diagnosis", "Fast path: test-level failure heuristic \u2192 test_bug", {
|
|
93717
94209
|
storyId,
|
|
@@ -93733,8 +94225,7 @@ async function resolveAcceptanceDiagnosis(opts) {
|
|
|
93733
94225
|
testOutput: diagnosisOpts.testOutput,
|
|
93734
94226
|
testFileContent: diagnosisOpts.testFileContent,
|
|
93735
94227
|
acceptanceTestPath: diagnosisOpts.acceptanceTestPath,
|
|
93736
|
-
sourceFiles
|
|
93737
|
-
semanticVerdicts
|
|
94228
|
+
sourceFiles
|
|
93738
94229
|
});
|
|
93739
94230
|
}
|
|
93740
94231
|
var _diagnosisDeps;
|
|
@@ -94022,7 +94513,6 @@ async function runAcceptanceLoop(ctx) {
|
|
|
94022
94513
|
continue;
|
|
94023
94514
|
}
|
|
94024
94515
|
}
|
|
94025
|
-
const semanticVerdicts = ctx.featureDir ? await _acceptanceLoopDeps.loadSemanticVerdicts(ctx.featureDir) : [];
|
|
94026
94516
|
const totalACs = prd.userStories.filter((s) => !isLegacyFixStory(s)).flatMap((s) => s.acceptanceCriteria).length;
|
|
94027
94517
|
if (!ctx.runtime) {
|
|
94028
94518
|
logger?.error("acceptance", "Runtime not found for diagnosis", { storyId: firstStory?.id });
|
|
@@ -94045,7 +94535,6 @@ async function runAcceptanceLoop(ctx) {
|
|
|
94045
94535
|
failures: pkgFailures,
|
|
94046
94536
|
totalACs,
|
|
94047
94537
|
strategy,
|
|
94048
|
-
semanticVerdicts,
|
|
94049
94538
|
diagnosisOpts: {
|
|
94050
94539
|
testOutput: pkg.output,
|
|
94051
94540
|
testFileContent,
|
|
@@ -94091,7 +94580,6 @@ var init_acceptance_loop = __esm(() => {
|
|
|
94091
94580
|
init_acceptance_helpers();
|
|
94092
94581
|
init_acceptance_helpers();
|
|
94093
94582
|
_acceptanceLoopDeps = {
|
|
94094
|
-
loadSemanticVerdicts,
|
|
94095
94583
|
loadAcceptanceTestContent
|
|
94096
94584
|
};
|
|
94097
94585
|
_acceptanceFixCycleDeps = {
|
|
@@ -94320,7 +94808,7 @@ var init_scratchpad_wipe = __esm(() => {
|
|
|
94320
94808
|
init_logger2();
|
|
94321
94809
|
init_tools();
|
|
94322
94810
|
_scratchpadWipeDeps = {
|
|
94323
|
-
remove: (
|
|
94811
|
+
remove: (path17) => rm7(path17, { recursive: true, force: true })
|
|
94324
94812
|
};
|
|
94325
94813
|
});
|
|
94326
94814
|
|
|
@@ -94472,6 +94960,13 @@ async function cleanupRun(options) {
|
|
|
94472
94960
|
} catch (error48) {
|
|
94473
94961
|
logger?.warn("plugins", "Plugin teardown failed", { error: error48 });
|
|
94474
94962
|
}
|
|
94963
|
+
if (options.sealApprovals) {
|
|
94964
|
+
try {
|
|
94965
|
+
await options.sealApprovals();
|
|
94966
|
+
} catch (error48) {
|
|
94967
|
+
logger?.warn("permissions", "End-of-run approvals seal failed \u2014 continuing teardown", { error: error48 });
|
|
94968
|
+
}
|
|
94969
|
+
}
|
|
94475
94970
|
if (interactionChain) {
|
|
94476
94971
|
try {
|
|
94477
94972
|
await interactionChain.destroy();
|
|
@@ -96909,8 +97404,8 @@ async function defaultRun(cmd, opts) {
|
|
|
96909
97404
|
clearTimeout(timer);
|
|
96910
97405
|
}
|
|
96911
97406
|
}
|
|
96912
|
-
async function defaultReadText(
|
|
96913
|
-
const file2 = Bun.file(
|
|
97407
|
+
async function defaultReadText(path17) {
|
|
97408
|
+
const file2 = Bun.file(path17);
|
|
96914
97409
|
if (!await file2.exists())
|
|
96915
97410
|
return null;
|
|
96916
97411
|
return file2.text();
|
|
@@ -97010,10 +97505,10 @@ var init_pr = __esm(() => {
|
|
|
97010
97505
|
});
|
|
97011
97506
|
|
|
97012
97507
|
// src/forge/template.ts
|
|
97013
|
-
import * as
|
|
97508
|
+
import * as path17 from "path";
|
|
97014
97509
|
async function firstExisting(workdir, deps, paths) {
|
|
97015
97510
|
for (const relPath of paths) {
|
|
97016
|
-
const content = await deps.readText(
|
|
97511
|
+
const content = await deps.readText(path17.join(workdir, relPath));
|
|
97017
97512
|
if (content !== null)
|
|
97018
97513
|
return content;
|
|
97019
97514
|
}
|
|
@@ -97228,7 +97723,7 @@ var init_pr_body = __esm(() => {
|
|
|
97228
97723
|
});
|
|
97229
97724
|
|
|
97230
97725
|
// src/plugins/builtin/auto-pr/index.ts
|
|
97231
|
-
import * as
|
|
97726
|
+
import * as path18 from "path";
|
|
97232
97727
|
async function defaultRun2(cmd, opts) {
|
|
97233
97728
|
const argv = cmd[0] === "git" ? hardenedGitArgv(cmd) : cmd;
|
|
97234
97729
|
const proc = Bun.spawn(argv, { cwd: opts.cwd, env: gitSpawnEnv(), stdout: "pipe", stderr: "pipe" });
|
|
@@ -97254,8 +97749,8 @@ async function defaultRun2(cmd, opts) {
|
|
|
97254
97749
|
clearTimeout(timer);
|
|
97255
97750
|
}
|
|
97256
97751
|
}
|
|
97257
|
-
async function defaultReadText2(
|
|
97258
|
-
const file2 = Bun.file(
|
|
97752
|
+
async function defaultReadText2(path19) {
|
|
97753
|
+
const file2 = Bun.file(path19);
|
|
97259
97754
|
if (!await file2.exists())
|
|
97260
97755
|
return null;
|
|
97261
97756
|
return file2.text();
|
|
@@ -97285,8 +97780,8 @@ function getStorySummary(context) {
|
|
|
97285
97780
|
function relativePrdPath(workdir, prdPath) {
|
|
97286
97781
|
if (!prdPath)
|
|
97287
97782
|
return prdPath;
|
|
97288
|
-
const rel =
|
|
97289
|
-
return rel && !rel.startsWith("..") && !
|
|
97783
|
+
const rel = path18.relative(workdir, prdPath);
|
|
97784
|
+
return rel && !rel.startsWith("..") && !path18.isAbsolute(rel) ? rel : prdPath;
|
|
97290
97785
|
}
|
|
97291
97786
|
function toPrBodyContext(context) {
|
|
97292
97787
|
const summary = getStorySummary(context);
|
|
@@ -97575,7 +98070,7 @@ var init_auto_prune = __esm(() => {
|
|
|
97575
98070
|
});
|
|
97576
98071
|
|
|
97577
98072
|
// src/plugins/builtin/curator/collect.ts
|
|
97578
|
-
import * as
|
|
98073
|
+
import * as path19 from "path";
|
|
97579
98074
|
function now() {
|
|
97580
98075
|
return new Date().toISOString();
|
|
97581
98076
|
}
|
|
@@ -97633,7 +98128,7 @@ function tokenCount(story) {
|
|
|
97633
98128
|
}
|
|
97634
98129
|
async function collectFromMetrics(context) {
|
|
97635
98130
|
const observations = [];
|
|
97636
|
-
const metricsPath =
|
|
98131
|
+
const metricsPath = path19.join(context.outputDir, "metrics.json");
|
|
97637
98132
|
try {
|
|
97638
98133
|
const data = await readJsonFile(metricsPath);
|
|
97639
98134
|
const runs = Array.isArray(data) ? data : [data];
|
|
@@ -97709,11 +98204,11 @@ function findingMessage(finding) {
|
|
|
97709
98204
|
}
|
|
97710
98205
|
async function collectFromReviewAudit(context) {
|
|
97711
98206
|
const observations = [];
|
|
97712
|
-
const auditDir =
|
|
98207
|
+
const auditDir = path19.join(context.outputDir, "review-audit");
|
|
97713
98208
|
try {
|
|
97714
98209
|
const glob = new Bun.Glob("**/*.json");
|
|
97715
98210
|
for await (const file2 of glob.scan({ cwd: auditDir, absolute: false })) {
|
|
97716
|
-
const fullPath =
|
|
98211
|
+
const fullPath = path19.join(auditDir, file2);
|
|
97717
98212
|
try {
|
|
97718
98213
|
const audit = asRecord3(await readJsonFile(fullPath));
|
|
97719
98214
|
if (!audit)
|
|
@@ -97764,7 +98259,7 @@ async function collectFromContextManifests(context) {
|
|
|
97764
98259
|
try {
|
|
97765
98260
|
const glob = new Bun.Glob("*/stories/*/context-manifest-*.json");
|
|
97766
98261
|
for await (const file2 of glob.scan({ cwd: featuresRoot, absolute: false })) {
|
|
97767
|
-
const fullPath =
|
|
98262
|
+
const fullPath = path19.join(featuresRoot, file2);
|
|
97768
98263
|
try {
|
|
97769
98264
|
const parts = file2.split("/");
|
|
97770
98265
|
const featureId = parts[0] ?? context.feature;
|
|
@@ -98371,9 +98866,9 @@ function renderProposals(proposals, runId, observationCount, provenance) {
|
|
|
98371
98866
|
|
|
98372
98867
|
// src/plugins/builtin/curator/rollup.ts
|
|
98373
98868
|
import { appendFile as appendFile7, mkdir as mkdir26, writeFile as writeFile11 } from "fs/promises";
|
|
98374
|
-
import * as
|
|
98869
|
+
import * as path20 from "path";
|
|
98375
98870
|
async function appendToRollup(observations, rollupPath) {
|
|
98376
|
-
const dir =
|
|
98871
|
+
const dir = path20.dirname(rollupPath);
|
|
98377
98872
|
await mkdir26(dir, { recursive: true }).catch(() => {});
|
|
98378
98873
|
const { withPathFileLock: withPathFileLock2 } = await Promise.resolve().then(() => (init_path_file_lock(), exports_path_file_lock));
|
|
98379
98874
|
await withPathFileLock2(rollupPath, () => appendToRollupUnlocked(observations, rollupPath)).catch(() => {});
|
|
@@ -98462,7 +98957,7 @@ var init_rollup2 = __esm(() => {
|
|
|
98462
98957
|
|
|
98463
98958
|
// src/plugins/builtin/curator/index.ts
|
|
98464
98959
|
import { mkdir as mkdir27 } from "fs/promises";
|
|
98465
|
-
import * as
|
|
98960
|
+
import * as path21 from "path";
|
|
98466
98961
|
function getCuratorEnabled(context) {
|
|
98467
98962
|
const cfg = context.config;
|
|
98468
98963
|
if (!cfg)
|
|
@@ -98538,7 +99033,7 @@ var init_curator = __esm(() => {
|
|
|
98538
99033
|
const observations = await collectObservations(curatorContext);
|
|
98539
99034
|
if (context.outputDir) {
|
|
98540
99035
|
const { observationsPath, rollupPath } = resolveCuratorOutputs(curatorContext);
|
|
98541
|
-
const runDir =
|
|
99036
|
+
const runDir = path21.dirname(observationsPath);
|
|
98542
99037
|
await mkdir27(runDir, { recursive: true });
|
|
98543
99038
|
await Bun.write(observationsPath, observations.map((o) => JSON.stringify(o)).join(`
|
|
98544
99039
|
`) + (observations.length > 0 ? `
|
|
@@ -98576,7 +99071,7 @@ var init_curator = __esm(() => {
|
|
|
98576
99071
|
const windowHasObservations = window2.observations.length > 0;
|
|
98577
99072
|
const provenance = windowHasObservations ? { runCount: window2.runIds.length, observationCount: window2.observations.length } : { runCount: 1, observationCount: observations.length };
|
|
98578
99073
|
const markdown = renderProposals(proposals, context.runId, observations.length, provenance);
|
|
98579
|
-
const proposalsMdPath =
|
|
99074
|
+
const proposalsMdPath = path21.join(runDir, "curator-proposals.md");
|
|
98580
99075
|
await Bun.write(proposalsMdPath, markdown);
|
|
98581
99076
|
}
|
|
98582
99077
|
return {
|
|
@@ -98959,14 +99454,14 @@ var init_validator = __esm(() => {
|
|
|
98959
99454
|
|
|
98960
99455
|
// src/plugins/loader.ts
|
|
98961
99456
|
import * as fs from "fs/promises";
|
|
98962
|
-
import * as
|
|
99457
|
+
import * as path22 from "path";
|
|
98963
99458
|
function getSafeLogger7() {
|
|
98964
99459
|
return getSafeLogger();
|
|
98965
99460
|
}
|
|
98966
99461
|
function extractPluginName(pluginPath) {
|
|
98967
|
-
const basename13 =
|
|
99462
|
+
const basename13 = path22.basename(pluginPath);
|
|
98968
99463
|
if (basename13 === "index.ts" || basename13 === "index.js" || basename13 === "index.mjs") {
|
|
98969
|
-
return
|
|
99464
|
+
return path22.basename(path22.dirname(pluginPath));
|
|
98970
99465
|
}
|
|
98971
99466
|
return basename13.replace(/\.(ts|js|mjs)$/, "");
|
|
98972
99467
|
}
|
|
@@ -99113,7 +99608,7 @@ async function discoverPlugins(dir, isTestFileFn) {
|
|
|
99113
99608
|
try {
|
|
99114
99609
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
99115
99610
|
for (const entry of entries) {
|
|
99116
|
-
const fullPath =
|
|
99611
|
+
const fullPath = path22.join(dir, entry.name);
|
|
99117
99612
|
if (entry.isFile()) {
|
|
99118
99613
|
if (isPluginFile(entry.name, isTestFileFn)) {
|
|
99119
99614
|
discovered.push({ path: fullPath });
|
|
@@ -99121,7 +99616,7 @@ async function discoverPlugins(dir, isTestFileFn) {
|
|
|
99121
99616
|
} else if (entry.isDirectory()) {
|
|
99122
99617
|
const indexPaths = ["index.ts", "index.js", "index.mjs"];
|
|
99123
99618
|
for (const indexFile of indexPaths) {
|
|
99124
|
-
const indexPath =
|
|
99619
|
+
const indexPath = path22.join(fullPath, indexFile);
|
|
99125
99620
|
try {
|
|
99126
99621
|
await fs.access(indexPath);
|
|
99127
99622
|
discovered.push({ path: indexPath });
|
|
@@ -99146,13 +99641,13 @@ function isPluginFile(filename, isTestFileFn) {
|
|
|
99146
99641
|
return !FALLBACK_TEST_FILE_RE.test(filename);
|
|
99147
99642
|
}
|
|
99148
99643
|
function resolveModulePath(modulePath, projectRoot) {
|
|
99149
|
-
if (
|
|
99644
|
+
if (path22.isAbsolute(modulePath) || !modulePath.startsWith("./") && !modulePath.startsWith("../")) {
|
|
99150
99645
|
return modulePath;
|
|
99151
99646
|
}
|
|
99152
99647
|
if (projectRoot) {
|
|
99153
|
-
return
|
|
99648
|
+
return path22.resolve(projectRoot, modulePath);
|
|
99154
99649
|
}
|
|
99155
|
-
return
|
|
99650
|
+
return path22.resolve(modulePath);
|
|
99156
99651
|
}
|
|
99157
99652
|
async function loadAndValidatePlugin(initialModulePath, config2, allowedRoots, originalPath) {
|
|
99158
99653
|
let attemptedPath = initialModulePath;
|
|
@@ -99298,8 +99793,26 @@ function warnInertBashStages(config2, logger) {
|
|
|
99298
99793
|
logger?.warn("permissions", `bashApproval "${resolved}" on stage "${stage}" grants no Bash (no Bash(...) allow rule) -- the agent is not offered Bash, so nothing can escalate. Add one rule: "allow": ["Bash(ls *, cat *, git status*)"]`, { storyId: "_setup", stage, bashApproval: resolved });
|
|
99299
99794
|
}
|
|
99300
99795
|
}
|
|
99796
|
+
function warnUnreferencedAgentModels(prd, config2, logger) {
|
|
99797
|
+
const storyAgents = prd.userStories.flatMap((story) => story.routing?.agent ? [story.routing.agent] : []);
|
|
99798
|
+
const agents = findUnreferencedAgentModels(config2, storyAgents);
|
|
99799
|
+
if (agents.length === 0)
|
|
99800
|
+
return;
|
|
99801
|
+
logger?.warn("config", describeUnreferencedAgentModels(agents, config2), { storyId: "_setup", agents });
|
|
99802
|
+
}
|
|
99803
|
+
async function assertDefaultNativeCredentials(config2) {
|
|
99804
|
+
const { describeMissingNativeCredentials, findMissingNativeCredentials } = await Promise.resolve().then(() => (init_precheck2(), exports_precheck));
|
|
99805
|
+
const missing = await findMissingNativeCredentials(config2);
|
|
99806
|
+
if (missing.length === 0)
|
|
99807
|
+
return;
|
|
99808
|
+
throw new NaxError(describeMissingNativeCredentials(missing), "NATIVE_CREDENTIALS_MISSING", {
|
|
99809
|
+
stage: "setup",
|
|
99810
|
+
providers: missing.map(({ provider: provider2 }) => provider2)
|
|
99811
|
+
});
|
|
99812
|
+
}
|
|
99301
99813
|
var init_run_setup_warnings = __esm(() => {
|
|
99302
99814
|
init_config();
|
|
99815
|
+
init_errors();
|
|
99303
99816
|
});
|
|
99304
99817
|
|
|
99305
99818
|
// src/execution/lifecycle/gitignore-reconcile.ts
|
|
@@ -99356,8 +99869,8 @@ var init_language_commands = __esm(() => {
|
|
|
99356
99869
|
|
|
99357
99870
|
// src/review/scoped-lint.ts
|
|
99358
99871
|
import { join as join100, relative as relative26 } from "path";
|
|
99359
|
-
function normalizePath3(
|
|
99360
|
-
return
|
|
99872
|
+
function normalizePath3(path23) {
|
|
99873
|
+
return path23.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
99361
99874
|
}
|
|
99362
99875
|
function isSupportedDerivedScopedCommand(command) {
|
|
99363
99876
|
const commands = normalizeCommandSpec(command);
|
|
@@ -99592,7 +100105,7 @@ var init_scoped_lint = __esm(() => {
|
|
|
99592
100105
|
listChangedFiles,
|
|
99593
100106
|
findPackageDir,
|
|
99594
100107
|
runLintCommand,
|
|
99595
|
-
fileExists: (
|
|
100108
|
+
fileExists: (path23) => Bun.file(path23).exists()
|
|
99596
100109
|
};
|
|
99597
100110
|
});
|
|
99598
100111
|
|
|
@@ -100053,7 +100566,7 @@ var init_paused_story_prompts = __esm(() => {
|
|
|
100053
100566
|
});
|
|
100054
100567
|
|
|
100055
100568
|
// src/execution/lifecycle/run-setup-init.ts
|
|
100056
|
-
import
|
|
100569
|
+
import path23 from "path";
|
|
100057
100570
|
async function initializeAfterLock(options) {
|
|
100058
100571
|
const logger = getSafeLogger();
|
|
100059
100572
|
const { config: config2, workdir, feature, dryRun, runtime, interactionChain, runId, agentGetFn, statusWriter, deps } = options;
|
|
@@ -100085,8 +100598,8 @@ async function initializeAfterLock(options) {
|
|
|
100085
100598
|
explicit: Object.fromEntries(explicitFields.map((f) => [f, existingProjectConfig[f]])),
|
|
100086
100599
|
detected: Object.fromEntries(autodetectedFields.map((f) => [f, detectedProfile[f]]))
|
|
100087
100600
|
});
|
|
100088
|
-
const globalPluginsDir =
|
|
100089
|
-
const projectPluginsDir =
|
|
100601
|
+
const globalPluginsDir = path23.join(globalConfigDir(), "plugins");
|
|
100602
|
+
const projectPluginsDir = path23.join(workdir, ".nax", "plugins");
|
|
100090
100603
|
const configPlugins = config2.plugins || [];
|
|
100091
100604
|
const resolvedPatterns = await resolveTestFilePatterns(config2, workdir);
|
|
100092
100605
|
const isTestFileFn = (filename) => resolvedPatterns.regex.some((re) => re.test(filename));
|
|
@@ -100116,6 +100629,7 @@ async function initializeAfterLock(options) {
|
|
|
100116
100629
|
const prd = initResult.prd;
|
|
100117
100630
|
statusWriter.setPrd(prd);
|
|
100118
100631
|
warnProfileMismatch(prd, config2, logger);
|
|
100632
|
+
warnUnreferencedAgentModels(prd, config2, logger);
|
|
100119
100633
|
let counts = initResult.storyCounts;
|
|
100120
100634
|
if (counts.paused > 0 && interactionChain !== null) {
|
|
100121
100635
|
const { promptForPausedStories: promptForPausedStories2 } = await Promise.resolve().then(() => (init_paused_story_prompts(), exports_paused_story_prompts));
|
|
@@ -101044,7 +101558,7 @@ __export(exports_migrate, {
|
|
|
101044
101558
|
});
|
|
101045
101559
|
import { existsSync as existsSync30 } from "fs";
|
|
101046
101560
|
import { mkdir as mkdir28, readdir as readdir10, rename as rename9 } from "fs/promises";
|
|
101047
|
-
import
|
|
101561
|
+
import path24 from "path";
|
|
101048
101562
|
async function detectGeneratedContent(naxDir) {
|
|
101049
101563
|
if (!existsSync30(naxDir))
|
|
101050
101564
|
return [];
|
|
@@ -101057,17 +101571,17 @@ async function detectGeneratedContent(naxDir) {
|
|
|
101057
101571
|
}
|
|
101058
101572
|
for (const entry of entries) {
|
|
101059
101573
|
if (GENERATED_NAMES.has(entry)) {
|
|
101060
|
-
candidates.push({ name: entry, srcPath:
|
|
101574
|
+
candidates.push({ name: entry, srcPath: path24.join(naxDir, entry) });
|
|
101061
101575
|
}
|
|
101062
101576
|
}
|
|
101063
|
-
const featuresDir2 =
|
|
101577
|
+
const featuresDir2 = path24.join(naxDir, "features");
|
|
101064
101578
|
if (existsSync30(featuresDir2)) {
|
|
101065
101579
|
let featureDirs = [];
|
|
101066
101580
|
try {
|
|
101067
101581
|
featureDirs = await readdir10(featuresDir2);
|
|
101068
101582
|
} catch {}
|
|
101069
101583
|
for (const fid of featureDirs) {
|
|
101070
|
-
const featureDir2 =
|
|
101584
|
+
const featureDir2 = path24.join(featuresDir2, fid);
|
|
101071
101585
|
let subEntries = [];
|
|
101072
101586
|
try {
|
|
101073
101587
|
subEntries = await readdir10(featureDir2);
|
|
@@ -101077,12 +101591,12 @@ async function detectGeneratedContent(naxDir) {
|
|
|
101077
101591
|
for (const sub of subEntries) {
|
|
101078
101592
|
if (GENERATED_FEATURE_SUBNAMES.has(sub)) {
|
|
101079
101593
|
candidates.push({
|
|
101080
|
-
name:
|
|
101081
|
-
srcPath:
|
|
101594
|
+
name: path24.join("features", fid, sub),
|
|
101595
|
+
srcPath: path24.join(featureDir2, sub)
|
|
101082
101596
|
});
|
|
101083
101597
|
}
|
|
101084
101598
|
if (sub === "stories") {
|
|
101085
|
-
const storiesDir =
|
|
101599
|
+
const storiesDir = path24.join(featureDir2, "stories");
|
|
101086
101600
|
let storyDirs = [];
|
|
101087
101601
|
try {
|
|
101088
101602
|
storyDirs = await readdir10(storiesDir);
|
|
@@ -101090,7 +101604,7 @@ async function detectGeneratedContent(naxDir) {
|
|
|
101090
101604
|
continue;
|
|
101091
101605
|
}
|
|
101092
101606
|
for (const sid of storyDirs) {
|
|
101093
|
-
const storyDir =
|
|
101607
|
+
const storyDir = path24.join(storiesDir, sid);
|
|
101094
101608
|
let storyEntries = [];
|
|
101095
101609
|
try {
|
|
101096
101610
|
storyEntries = await readdir10(storyDir);
|
|
@@ -101100,8 +101614,8 @@ async function detectGeneratedContent(naxDir) {
|
|
|
101100
101614
|
for (const se of storyEntries) {
|
|
101101
101615
|
if (se.startsWith("context-manifest-") && se.endsWith(".json")) {
|
|
101102
101616
|
candidates.push({
|
|
101103
|
-
name:
|
|
101104
|
-
srcPath:
|
|
101617
|
+
name: path24.join("features", fid, "stories", sid, se),
|
|
101618
|
+
srcPath: path24.join(storyDir, se)
|
|
101105
101619
|
});
|
|
101106
101620
|
}
|
|
101107
101621
|
}
|
|
@@ -101122,15 +101636,15 @@ async function migrateCommand(options) {
|
|
|
101122
101636
|
name: options.reclaim
|
|
101123
101637
|
});
|
|
101124
101638
|
}
|
|
101125
|
-
const src =
|
|
101639
|
+
const src = path24.join(globalConfigDir(), options.reclaim);
|
|
101126
101640
|
if (!existsSync30(src)) {
|
|
101127
101641
|
throw new NaxError(`Nothing to reclaim: ~/.nax/${options.reclaim} does not exist`, "MIGRATE_RECLAIM_NOT_FOUND", {
|
|
101128
101642
|
stage: "migrate",
|
|
101129
101643
|
name: options.reclaim
|
|
101130
101644
|
});
|
|
101131
101645
|
}
|
|
101132
|
-
const archiveBase =
|
|
101133
|
-
const archiveDest =
|
|
101646
|
+
const archiveBase = path24.join(globalConfigDir(), "_archive");
|
|
101647
|
+
const archiveDest = path24.join(archiveBase, `${options.reclaim}-${Date.now()}`);
|
|
101134
101648
|
await mkdir28(archiveBase, { recursive: true });
|
|
101135
101649
|
await rename9(src, archiveDest);
|
|
101136
101650
|
logger.info("migrate", `Reclaimed: archived to ${archiveDest}`, { storyId: "_migrate" });
|
|
@@ -101170,8 +101684,8 @@ async function migrateCommand(options) {
|
|
|
101170
101684
|
logger.info("migrate", `Merged: identity for "${options.merge}" updated`, { storyId: "_migrate" });
|
|
101171
101685
|
return;
|
|
101172
101686
|
}
|
|
101173
|
-
const naxDir =
|
|
101174
|
-
const configPath =
|
|
101687
|
+
const naxDir = path24.join(options.workdir, ".nax");
|
|
101688
|
+
const configPath = path24.join(naxDir, "config.json");
|
|
101175
101689
|
if (!existsSync30(configPath)) {
|
|
101176
101690
|
throw new NaxError("No .nax/config.json found \u2014 run nax init first", "MIGRATE_NO_CONFIG", {
|
|
101177
101691
|
stage: "migrate",
|
|
@@ -101187,7 +101701,7 @@ async function migrateCommand(options) {
|
|
|
101187
101701
|
cause: e
|
|
101188
101702
|
});
|
|
101189
101703
|
}
|
|
101190
|
-
const projectKey = config2.name?.trim() ||
|
|
101704
|
+
const projectKey = config2.name?.trim() || path24.basename(options.workdir);
|
|
101191
101705
|
const destBase = projectOutputDir(projectKey, config2.outputDir);
|
|
101192
101706
|
const candidates = await detectGeneratedContent(naxDir);
|
|
101193
101707
|
if (candidates.length === 0) {
|
|
@@ -101196,7 +101710,7 @@ async function migrateCommand(options) {
|
|
|
101196
101710
|
}
|
|
101197
101711
|
if (options.dryRun) {
|
|
101198
101712
|
for (const c of candidates) {
|
|
101199
|
-
logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${
|
|
101713
|
+
logger.info("migrate", `[dry-run] Would move: ${c.srcPath} -> ${path24.join(destBase, c.name)}`, {
|
|
101200
101714
|
storyId: "_migrate"
|
|
101201
101715
|
});
|
|
101202
101716
|
}
|
|
@@ -101205,8 +101719,8 @@ async function migrateCommand(options) {
|
|
|
101205
101719
|
await mkdir28(destBase, { recursive: true });
|
|
101206
101720
|
let moved = 0;
|
|
101207
101721
|
for (const candidate of candidates) {
|
|
101208
|
-
const dest =
|
|
101209
|
-
await mkdir28(
|
|
101722
|
+
const dest = path24.join(destBase, candidate.name);
|
|
101723
|
+
await mkdir28(path24.dirname(dest), { recursive: true });
|
|
101210
101724
|
if (existsSync30(dest)) {
|
|
101211
101725
|
throw new NaxError(`Migration conflict: destination already exists.
|
|
101212
101726
|
Source: ${candidate.srcPath}
|
|
@@ -101236,7 +101750,7 @@ async function migrateCommand(options) {
|
|
|
101236
101750
|
moved++;
|
|
101237
101751
|
logger.info("migrate", `Moved: ${candidate.name}`, { storyId: "_migrate" });
|
|
101238
101752
|
}
|
|
101239
|
-
await Bun.write(
|
|
101753
|
+
await Bun.write(path24.join(destBase, ".migrated-from"), JSON.stringify({ from: options.workdir, migratedAt: new Date().toISOString() }, null, 2));
|
|
101240
101754
|
logger.info("migrate", `Migration complete: ${moved} entries moved`, {
|
|
101241
101755
|
storyId: "_migrate",
|
|
101242
101756
|
destBase
|
|
@@ -101607,10 +102121,10 @@ function renderReport(timeline, options = {}) {
|
|
|
101607
102121
|
// src/commands/replay.ts
|
|
101608
102122
|
import { existsSync as existsSync32 } from "fs";
|
|
101609
102123
|
import { dirname as dirname20 } from "path";
|
|
101610
|
-
async function readJsonlLenient(
|
|
101611
|
-
if (!existsSync32(
|
|
102124
|
+
async function readJsonlLenient(path25) {
|
|
102125
|
+
if (!existsSync32(path25))
|
|
101612
102126
|
return [];
|
|
101613
|
-
const content = await Bun.file(
|
|
102127
|
+
const content = await Bun.file(path25).text();
|
|
101614
102128
|
const lines = content.split(`
|
|
101615
102129
|
`);
|
|
101616
102130
|
const entries = [];
|
|
@@ -101624,11 +102138,11 @@ async function readJsonlLenient(path26) {
|
|
|
101624
102138
|
}
|
|
101625
102139
|
return entries;
|
|
101626
102140
|
}
|
|
101627
|
-
async function readJsonOrUndefined(
|
|
101628
|
-
if (!existsSync32(
|
|
102141
|
+
async function readJsonOrUndefined(path25) {
|
|
102142
|
+
if (!existsSync32(path25))
|
|
101629
102143
|
return;
|
|
101630
102144
|
try {
|
|
101631
|
-
return await Bun.file(
|
|
102145
|
+
return await Bun.file(path25).json();
|
|
101632
102146
|
} catch {
|
|
101633
102147
|
return;
|
|
101634
102148
|
}
|
|
@@ -102341,7 +102855,7 @@ __export(exports_precheck_runner, {
|
|
|
102341
102855
|
runPrecheckValidation: () => runPrecheckValidation
|
|
102342
102856
|
});
|
|
102343
102857
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
102344
|
-
import
|
|
102858
|
+
import path25 from "path";
|
|
102345
102859
|
async function runPrecheckValidation(ctx) {
|
|
102346
102860
|
const logger = getSafeLogger();
|
|
102347
102861
|
if (process.env.NAX_PRECHECK !== "1") {
|
|
@@ -102350,7 +102864,7 @@ async function runPrecheckValidation(ctx) {
|
|
|
102350
102864
|
}
|
|
102351
102865
|
logger?.info("precheck", "Running precheck validations...");
|
|
102352
102866
|
const { runPrecheck: runPrecheck3 } = await Promise.resolve().then(() => (init_precheck2(), exports_precheck));
|
|
102353
|
-
const projectKey = ctx.config.name?.trim() ||
|
|
102867
|
+
const projectKey = ctx.config.name?.trim() || path25.basename(ctx.workdir);
|
|
102354
102868
|
const outputDir = projectOutputDir(projectKey, ctx.config.outputDir);
|
|
102355
102869
|
const featureLock = ctx.featureName !== undefined ? { outputDir, feature: ctx.featureName } : undefined;
|
|
102356
102870
|
const precheckResult = await runPrecheck3(ctx.config, ctx.prd, {
|
|
@@ -102360,7 +102874,7 @@ async function runPrecheckValidation(ctx) {
|
|
|
102360
102874
|
...featureLock !== undefined ? { featureLock } : {}
|
|
102361
102875
|
});
|
|
102362
102876
|
if (ctx.logFilePath) {
|
|
102363
|
-
mkdirSync5(
|
|
102877
|
+
mkdirSync5(path25.dirname(ctx.logFilePath), { recursive: true });
|
|
102364
102878
|
const precheckLog = {
|
|
102365
102879
|
type: "precheck",
|
|
102366
102880
|
timestamp: new Date().toISOString(),
|
|
@@ -102458,7 +102972,7 @@ __export(exports_run_setup, {
|
|
|
102458
102972
|
warnInertBashStages: () => warnInertBashStages,
|
|
102459
102973
|
warnProfileMismatch: () => warnProfileMismatch
|
|
102460
102974
|
});
|
|
102461
|
-
import
|
|
102975
|
+
import path26 from "path";
|
|
102462
102976
|
async function setupRun(options) {
|
|
102463
102977
|
const logger = getSafeLogger();
|
|
102464
102978
|
warnFallbackMisconfiguration(options.config, options.agentGetFn, logger);
|
|
@@ -102466,6 +102980,9 @@ async function setupRun(options) {
|
|
|
102466
102980
|
if (options.agentManager) {
|
|
102467
102981
|
await options.agentManager.validateCredentials();
|
|
102468
102982
|
}
|
|
102983
|
+
if (!options.dryRun) {
|
|
102984
|
+
await assertDefaultNativeCredentials(options.config);
|
|
102985
|
+
}
|
|
102469
102986
|
const {
|
|
102470
102987
|
prdPath,
|
|
102471
102988
|
workdir,
|
|
@@ -102520,6 +103037,7 @@ async function setupRun(options) {
|
|
|
102520
103037
|
}
|
|
102521
103038
|
await runtime.pidRegistry.cleanupStale();
|
|
102522
103039
|
let cleanupCrashHandlers;
|
|
103040
|
+
let sealApprovals;
|
|
102523
103041
|
try {
|
|
102524
103042
|
cleanupCrashHandlers = _runSetupDeps.installCrashHandlers({
|
|
102525
103043
|
statusWriter,
|
|
@@ -102537,6 +103055,9 @@ async function setupRun(options) {
|
|
|
102537
103055
|
emitError: (reason) => {
|
|
102538
103056
|
pipelineEventBus.emit({ type: "run:errored", reason, feature: options.feature });
|
|
102539
103057
|
},
|
|
103058
|
+
sealApprovals: async () => {
|
|
103059
|
+
await sealApprovals?.();
|
|
103060
|
+
},
|
|
102540
103061
|
onShutdown: async (abortSignal) => {
|
|
102541
103062
|
await closeAllRunSessions(sessionManager, options.agentGetFn, { force: true, signal: abortSignal });
|
|
102542
103063
|
await runtime.close().catch((err) => {
|
|
@@ -102549,7 +103070,7 @@ async function setupRun(options) {
|
|
|
102549
103070
|
statusWriter.setPrd(prd);
|
|
102550
103071
|
{
|
|
102551
103072
|
const { detectGeneratedContent: detectGeneratedContent2, migrateCommand: migrateCommand2 } = await Promise.resolve().then(() => (init_commands(), exports_commands));
|
|
102552
|
-
const naxDir =
|
|
103073
|
+
const naxDir = path26.join(workdir, ".nax");
|
|
102553
103074
|
const candidates = await detectGeneratedContent2(naxDir).catch(() => []);
|
|
102554
103075
|
if (candidates.length > 0) {
|
|
102555
103076
|
logger?.info("setup", "Found generated content under .nax/ \u2014 migrating to output dir", {
|
|
@@ -102576,7 +103097,7 @@ async function setupRun(options) {
|
|
|
102576
103097
|
remoteUrl = new TextDecoder().decode(gitResult.stdout).trim() || null;
|
|
102577
103098
|
}
|
|
102578
103099
|
} catch {}
|
|
102579
|
-
const projectKey = config2.name?.trim() ||
|
|
103100
|
+
const projectKey = config2.name?.trim() || path26.basename(workdir);
|
|
102580
103101
|
await claimProjectIdentity2(projectKey, workdir, remoteUrl).catch((err) => {
|
|
102581
103102
|
if (err instanceof NaxError && err.code === "RUN_NAME_COLLISION") {
|
|
102582
103103
|
throw err;
|
|
@@ -102660,6 +103181,19 @@ async function setupRun(options) {
|
|
|
102660
103181
|
sweepFeatureTranscripts: _runSetupDeps.sweepFeatureTranscripts
|
|
102661
103182
|
}
|
|
102662
103183
|
});
|
|
103184
|
+
try {
|
|
103185
|
+
sealApprovals = await _runSetupDeps.buildApprovalsSeal({
|
|
103186
|
+
projectDir: options.workdir,
|
|
103187
|
+
rootConfig: options.config,
|
|
103188
|
+
packageDirs: initResult.prd.userStories.map(storyPackageDir),
|
|
103189
|
+
outputDir: runtime.outputDir,
|
|
103190
|
+
runId: options.runId
|
|
103191
|
+
});
|
|
103192
|
+
} catch (error48) {
|
|
103193
|
+
await releaseFeatureLock({ outputDir: runtime.outputDir, feature, runId });
|
|
103194
|
+
await releaseLock(workdir);
|
|
103195
|
+
throw error48;
|
|
103196
|
+
}
|
|
102663
103197
|
return {
|
|
102664
103198
|
statusWriter,
|
|
102665
103199
|
sessionManager,
|
|
@@ -102669,7 +103203,8 @@ async function setupRun(options) {
|
|
|
102669
103203
|
storyCounts: initResult.storyCounts,
|
|
102670
103204
|
interactionChain: initResult.interactionChain,
|
|
102671
103205
|
shutdownController,
|
|
102672
|
-
runtime
|
|
103206
|
+
runtime,
|
|
103207
|
+
sealApprovals
|
|
102673
103208
|
};
|
|
102674
103209
|
} catch (error48) {
|
|
102675
103210
|
cleanupCrashHandlers?.();
|
|
@@ -102698,6 +103233,7 @@ var init_run_setup = __esm(() => {
|
|
|
102698
103233
|
init_test_runners();
|
|
102699
103234
|
init_tools();
|
|
102700
103235
|
init_git_env();
|
|
103236
|
+
init_path_frame();
|
|
102701
103237
|
init_crash_recovery();
|
|
102702
103238
|
init_feature_lock();
|
|
102703
103239
|
init_helpers();
|
|
@@ -102710,6 +103246,7 @@ var init_run_setup = __esm(() => {
|
|
|
102710
103246
|
createRuntime,
|
|
102711
103247
|
installCrashHandlers,
|
|
102712
103248
|
sweepFeatureTranscripts,
|
|
103249
|
+
buildApprovalsSeal,
|
|
102713
103250
|
acquireLock,
|
|
102714
103251
|
acquireFeatureLock
|
|
102715
103252
|
};
|
|
@@ -103966,7 +104503,7 @@ var init_queue_file_lock = __esm(() => {
|
|
|
103966
104503
|
|
|
103967
104504
|
// src/execution/queue-handler.ts
|
|
103968
104505
|
import { rename as rename10, unlink as unlink11 } from "fs/promises";
|
|
103969
|
-
import
|
|
104506
|
+
import path27 from "path";
|
|
103970
104507
|
function getSafeLogger8() {
|
|
103971
104508
|
try {
|
|
103972
104509
|
return getLogger();
|
|
@@ -103998,8 +104535,8 @@ async function claimCommandsLocked(queuePath, processingPath, logger) {
|
|
|
103998
104535
|
return result.commands;
|
|
103999
104536
|
}
|
|
104000
104537
|
async function readQueueFile(workdir) {
|
|
104001
|
-
const queuePath =
|
|
104002
|
-
const processingPath =
|
|
104538
|
+
const queuePath = path27.join(workdir, ".queue.txt");
|
|
104539
|
+
const processingPath = path27.join(workdir, ".queue.txt.processing");
|
|
104003
104540
|
const logger = getSafeLogger8();
|
|
104004
104541
|
try {
|
|
104005
104542
|
return await withQueueFileLock(queuePath, async () => {
|
|
@@ -104014,8 +104551,8 @@ async function readQueueFile(workdir) {
|
|
|
104014
104551
|
}
|
|
104015
104552
|
}
|
|
104016
104553
|
async function processQueueFile(workdir, processor) {
|
|
104017
|
-
const queuePath =
|
|
104018
|
-
const processingPath =
|
|
104554
|
+
const queuePath = path27.join(workdir, ".queue.txt");
|
|
104555
|
+
const processingPath = path27.join(workdir, ".queue.txt.processing");
|
|
104019
104556
|
const logger = getSafeLogger8();
|
|
104020
104557
|
try {
|
|
104021
104558
|
return await withQueueFileLock(queuePath, async () => {
|
|
@@ -104040,7 +104577,7 @@ async function processQueueFile(workdir, processor) {
|
|
|
104040
104577
|
}
|
|
104041
104578
|
}
|
|
104042
104579
|
async function drainQueueAtBatchBoundary(workdir, prd) {
|
|
104043
|
-
if (!await Bun.file(
|
|
104580
|
+
if (!await Bun.file(path27.join(workdir, ".queue.txt")).exists()) {
|
|
104044
104581
|
return { paused: false };
|
|
104045
104582
|
}
|
|
104046
104583
|
const logger = getSafeLogger8();
|
|
@@ -104096,10 +104633,10 @@ async function applyBatchBoundaryCommands(workdir, prd, commands, logger) {
|
|
|
104096
104633
|
}
|
|
104097
104634
|
if (cmd.type === "INJECT") {
|
|
104098
104635
|
try {
|
|
104099
|
-
if (
|
|
104636
|
+
if (path27.isAbsolute(cmd.storyFile)) {
|
|
104100
104637
|
throw new NaxError(`INJECT storyFile must be a relative path within the workspace: ${cmd.storyFile}`, "INJECT_PATH_ABSOLUTE", { stage: "queue-batch-boundary", storyFile: cmd.storyFile });
|
|
104101
104638
|
}
|
|
104102
|
-
const storyFilePath = validateFilePath(
|
|
104639
|
+
const storyFilePath = validateFilePath(path27.join(workdir, cmd.storyFile), workdir);
|
|
104103
104640
|
const raw = await Bun.file(storyFilePath).json();
|
|
104104
104641
|
const existingIds = new Set(prd.userStories.map((s) => s.id));
|
|
104105
104642
|
const story = validateInjectedStory(raw, existingIds);
|
|
@@ -104119,8 +104656,8 @@ async function applyBatchBoundaryCommands(workdir, prd, commands, logger) {
|
|
|
104119
104656
|
return { paused: false };
|
|
104120
104657
|
}
|
|
104121
104658
|
async function clearQueueFile(workdir) {
|
|
104122
|
-
const queuePath =
|
|
104123
|
-
const processingPath =
|
|
104659
|
+
const queuePath = path27.join(workdir, ".queue.txt");
|
|
104660
|
+
const processingPath = path27.join(workdir, ".queue.txt.processing");
|
|
104124
104661
|
const logger = getSafeLogger8();
|
|
104125
104662
|
try {
|
|
104126
104663
|
await withQueueFileLock(queuePath, async () => {
|
|
@@ -105539,12 +106076,12 @@ var init_body = __esm(() => {
|
|
|
105539
106076
|
// src/finish/pr/context.ts
|
|
105540
106077
|
import { readFile as readFile8 } from "fs/promises";
|
|
105541
106078
|
import { join as join113 } from "path";
|
|
105542
|
-
async function readJson(
|
|
106079
|
+
async function readJson(path28) {
|
|
105543
106080
|
let text;
|
|
105544
106081
|
try {
|
|
105545
|
-
text = await _finishPrDeps.readText(
|
|
106082
|
+
text = await _finishPrDeps.readText(path28);
|
|
105546
106083
|
} catch (error48) {
|
|
105547
|
-
_finishPrDeps.warn("[finish-pr] Failed to read PR context artifact", { path:
|
|
106084
|
+
_finishPrDeps.warn("[finish-pr] Failed to read PR context artifact", { path: path28, error: error48 });
|
|
105548
106085
|
return;
|
|
105549
106086
|
}
|
|
105550
106087
|
if (text === null)
|
|
@@ -105552,7 +106089,7 @@ async function readJson(path29) {
|
|
|
105552
106089
|
try {
|
|
105553
106090
|
return JSON.parse(text);
|
|
105554
106091
|
} catch (error48) {
|
|
105555
|
-
_finishPrDeps.warn("[finish-pr] Failed to parse PR context artifact", { path:
|
|
106092
|
+
_finishPrDeps.warn("[finish-pr] Failed to parse PR context artifact", { path: path28, error: error48 });
|
|
105556
106093
|
return;
|
|
105557
106094
|
}
|
|
105558
106095
|
}
|
|
@@ -105636,9 +106173,9 @@ var init_context5 = __esm(() => {
|
|
|
105636
106173
|
init_pr_title();
|
|
105637
106174
|
_finishPrDeps = {
|
|
105638
106175
|
run: defaultForgeDeps.run,
|
|
105639
|
-
readText: async (
|
|
106176
|
+
readText: async (path28) => {
|
|
105640
106177
|
try {
|
|
105641
|
-
return await readFile8(
|
|
106178
|
+
return await readFile8(path28, "utf8");
|
|
105642
106179
|
} catch (err) {
|
|
105643
106180
|
if (err.code === "ENOENT")
|
|
105644
106181
|
return null;
|
|
@@ -106527,7 +107064,7 @@ var init_finish = __esm(() => {
|
|
|
106527
107064
|
});
|
|
106528
107065
|
|
|
106529
107066
|
// src/execution/runner-completion.ts
|
|
106530
|
-
import
|
|
107067
|
+
import path28 from "path";
|
|
106531
107068
|
async function runCompletionPhase(options) {
|
|
106532
107069
|
const logger = getSafeLogger();
|
|
106533
107070
|
logger?.debug("execution", "Completion phase started", {
|
|
@@ -106548,7 +107085,7 @@ async function runCompletionPhase(options) {
|
|
|
106548
107085
|
const acceptanceStartTime = Date.now();
|
|
106549
107086
|
pipelineEventBus.emit({ type: "postrun:phase:started", phase: "acceptance" });
|
|
106550
107087
|
const acceptanceTestPaths = options.featureDir ? await Promise.all((await groupStoriesByPackage(options.prd, options.workdir, options.feature, options.config.acceptance.testPath, options.config.project?.language)).map(async (g) => {
|
|
106551
|
-
const relativeWorkdir =
|
|
107088
|
+
const relativeWorkdir = path28.relative(options.workdir, g.packageDir);
|
|
106552
107089
|
let groupConfig = options.config;
|
|
106553
107090
|
if (relativeWorkdir && relativeWorkdir !== ".") {
|
|
106554
107091
|
try {
|
|
@@ -106679,7 +107216,7 @@ async function runCompletionPhase(options) {
|
|
|
106679
107216
|
exitReason: options.exitReason,
|
|
106680
107217
|
runtime: options.runtime,
|
|
106681
107218
|
abortSignal: options.abortSignal,
|
|
106682
|
-
isSequential: options.parallel === undefined,
|
|
107219
|
+
isSequential: options.parallel === undefined || !(options.parallel > 1),
|
|
106683
107220
|
interactionChain: options.interactionChain
|
|
106684
107221
|
});
|
|
106685
107222
|
const { durationMs, runCompletedAt, finalCounts, reportedTotal, pluginGateFailed } = completionResult;
|
|
@@ -107285,7 +107822,7 @@ __export(exports_parallel_batch, {
|
|
|
107285
107822
|
_parallelBatchDeps: () => _parallelBatchDeps,
|
|
107286
107823
|
runParallelBatch: () => runParallelBatch
|
|
107287
107824
|
});
|
|
107288
|
-
import
|
|
107825
|
+
import path29 from "path";
|
|
107289
107826
|
async function runParallelBatch(options) {
|
|
107290
107827
|
const { stories, ctx, prd } = options;
|
|
107291
107828
|
const { workdir, config: config2, maxConcurrency, pipelineContext, eventEmitter, agentGetFn, hooks, pluginRegistry } = ctx;
|
|
@@ -107320,7 +107857,7 @@ async function runParallelBatch(options) {
|
|
|
107320
107857
|
}
|
|
107321
107858
|
worktreePaths.set(story.id, storyWorktreePath(workdir, worktreeId));
|
|
107322
107859
|
}
|
|
107323
|
-
const rootConfigPath =
|
|
107860
|
+
const rootConfigPath = path29.join(workdir, ".nax", "config.json");
|
|
107324
107861
|
const profileOverride = profileOverrideFromConfig(config2);
|
|
107325
107862
|
const storyEffectiveConfigs = new Map;
|
|
107326
107863
|
const configResults = await Promise.allSettled(stories.filter((story) => storyPackageDir(story)).map(async (story) => {
|
|
@@ -108303,7 +108840,8 @@ async function run(options) {
|
|
|
108303
108840
|
pluginRegistry,
|
|
108304
108841
|
interactionChain,
|
|
108305
108842
|
shutdownController,
|
|
108306
|
-
runtime
|
|
108843
|
+
runtime,
|
|
108844
|
+
sealApprovals
|
|
108307
108845
|
} = setupResult;
|
|
108308
108846
|
prd = setupResult.prd;
|
|
108309
108847
|
const agentManager = runtime.agentManager;
|
|
@@ -108425,7 +108963,8 @@ async function run(options) {
|
|
|
108425
108963
|
projectKey: runtime.projectKey,
|
|
108426
108964
|
curatorRollupPath: runtime.curatorRollupPath,
|
|
108427
108965
|
logFilePath,
|
|
108428
|
-
config: config2
|
|
108966
|
+
config: config2,
|
|
108967
|
+
sealApprovals
|
|
108429
108968
|
});
|
|
108430
108969
|
logger?.debug("execution", "Runner finally \u2014 cleanupRun done, run() returning");
|
|
108431
108970
|
} finally {
|
|
@@ -108890,12 +109429,12 @@ async function checkDependenciesInstalled(workdir) {
|
|
|
108890
109429
|
{ path: "vendor" }
|
|
108891
109430
|
];
|
|
108892
109431
|
const found = [];
|
|
108893
|
-
for (const { path:
|
|
108894
|
-
const fullPath = `${workdir}/${
|
|
109432
|
+
for (const { path: path30 } of depPaths) {
|
|
109433
|
+
const fullPath = `${workdir}/${path30}`;
|
|
108895
109434
|
if (existsSync36(fullPath)) {
|
|
108896
109435
|
const stats = statSync6(fullPath);
|
|
108897
109436
|
if (stats.isDirectory()) {
|
|
108898
|
-
found.push(
|
|
109437
|
+
found.push(path30);
|
|
108899
109438
|
}
|
|
108900
109439
|
}
|
|
108901
109440
|
}
|
|
@@ -109108,7 +109647,7 @@ function collectConfiguredModelPins(config2) {
|
|
|
109108
109647
|
}
|
|
109109
109648
|
}
|
|
109110
109649
|
const pins = [];
|
|
109111
|
-
const defaultAgent = cfg.agent?.default ??
|
|
109650
|
+
const defaultAgent = cfg.agent?.default ?? DEFAULT_AGENT_NAME;
|
|
109112
109651
|
if (cfg.review?.semantic !== undefined) {
|
|
109113
109652
|
const pin = pinFromConfiguredModel("review.semantic.model", cfg.review.semantic.model, defaultAgent, tierEntries);
|
|
109114
109653
|
if (pin !== undefined)
|
|
@@ -109197,7 +109736,7 @@ var init_checks_model_resolution_walk = __esm(() => {
|
|
|
109197
109736
|
|
|
109198
109737
|
// src/precheck/checks-model-resolution.ts
|
|
109199
109738
|
function isNativeAgent(agent) {
|
|
109200
|
-
return agent ===
|
|
109739
|
+
return agent === NATIVE_AGENT_NAME;
|
|
109201
109740
|
}
|
|
109202
109741
|
async function checkModelResolution(config2) {
|
|
109203
109742
|
const { pins, tierEntries, catalogOverrides } = collectConfiguredModelPins(config2);
|
|
@@ -109306,6 +109845,52 @@ var init_checks_model_resolution = __esm(() => {
|
|
|
109306
109845
|
};
|
|
109307
109846
|
});
|
|
109308
109847
|
|
|
109848
|
+
// src/precheck/checks-native-credentials.ts
|
|
109849
|
+
function providerOf(id) {
|
|
109850
|
+
const slash = id.indexOf("/");
|
|
109851
|
+
return slash > 0 ? id.slice(0, slash) : undefined;
|
|
109852
|
+
}
|
|
109853
|
+
function providerTiers(config2) {
|
|
109854
|
+
const overridden = new Set((config2.agent?.native?.catalogOverrides ?? []).map((override) => override.provider));
|
|
109855
|
+
const byProvider = new Map;
|
|
109856
|
+
for (const [tier, entry] of Object.entries(config2.models?.[NATIVE_AGENT_NAME] ?? {})) {
|
|
109857
|
+
if (entry === undefined)
|
|
109858
|
+
continue;
|
|
109859
|
+
const provider2 = providerOf(typeof entry === "string" ? entry : entry.model);
|
|
109860
|
+
if (provider2 === undefined || overridden.has(provider2))
|
|
109861
|
+
continue;
|
|
109862
|
+
byProvider.set(provider2, [...byProvider.get(provider2) ?? [], tier]);
|
|
109863
|
+
}
|
|
109864
|
+
return byProvider;
|
|
109865
|
+
}
|
|
109866
|
+
async function findMissingNativeCredentials(config2) {
|
|
109867
|
+
if (resolveDefaultAgent(config2) !== NATIVE_AGENT_NAME)
|
|
109868
|
+
return [];
|
|
109869
|
+
const byProvider = providerTiers(config2);
|
|
109870
|
+
if (byProvider.size === 0)
|
|
109871
|
+
return [];
|
|
109872
|
+
const missing = await _nativeCredentialDeps.providersWithoutCredentials([...byProvider.keys()]);
|
|
109873
|
+
return missing.map((provider2) => ({ provider: provider2, tiers: byProvider.get(provider2) ?? [] }));
|
|
109874
|
+
}
|
|
109875
|
+
function describeMissingNativeCredentials(missing) {
|
|
109876
|
+
const uses = missing.map(({ provider: provider2, tiers }) => `${provider2} (${tiers.map((tier) => `models.native.${tier}`).join(", ")})`).join("; ");
|
|
109877
|
+
const logins = missing.map(({ provider: provider2 }) => `nax auth login ${provider2}`).join(" / ");
|
|
109878
|
+
return `The default native agent needs a credential for ${uses}, but none is stored or in the environment. ` + `Run ${logins}, set the provider's API key environment variable, point models.native at a provider you have ` + `credentials for, or set agent.default "claude" to use an acpx agent.`;
|
|
109879
|
+
}
|
|
109880
|
+
async function checkNativeCredentials(config2) {
|
|
109881
|
+
const missing = await findMissingNativeCredentials(config2);
|
|
109882
|
+
if (missing.length === 0) {
|
|
109883
|
+
return { name: CHECK_NAME, tier: "blocker", passed: true, message: "native default agent credentials found" };
|
|
109884
|
+
}
|
|
109885
|
+
return { name: CHECK_NAME, tier: "blocker", passed: false, message: describeMissingNativeCredentials(missing) };
|
|
109886
|
+
}
|
|
109887
|
+
var CHECK_NAME = "native-credentials", _nativeCredentialDeps;
|
|
109888
|
+
var init_checks_native_credentials = __esm(() => {
|
|
109889
|
+
init_agents();
|
|
109890
|
+
init_native();
|
|
109891
|
+
_nativeCredentialDeps = { providersWithoutCredentials };
|
|
109892
|
+
});
|
|
109893
|
+
|
|
109309
109894
|
// src/precheck/checks-warnings.ts
|
|
109310
109895
|
import { existsSync as existsSync37 } from "fs";
|
|
109311
109896
|
import { isAbsolute as isAbsolute22 } from "path";
|
|
@@ -109614,6 +110199,7 @@ var init_checks4 = __esm(() => {
|
|
|
109614
110199
|
init_checks_agents();
|
|
109615
110200
|
init_checks_blockers();
|
|
109616
110201
|
init_checks_model_resolution();
|
|
110202
|
+
init_checks_native_credentials();
|
|
109617
110203
|
init_checks_warnings();
|
|
109618
110204
|
});
|
|
109619
110205
|
|
|
@@ -109742,6 +110328,7 @@ __export(exports_precheck, {
|
|
|
109742
110328
|
EXIT_CODES: () => EXIT_CODES,
|
|
109743
110329
|
_checkDiskSpaceDeps: () => _checkDiskSpaceDeps,
|
|
109744
110330
|
_modelResolutionDeps: () => _modelResolutionDeps,
|
|
110331
|
+
_nativeCredentialDeps: () => _nativeCredentialDeps,
|
|
109745
110332
|
_precheckDeps: () => _precheckDeps,
|
|
109746
110333
|
checkAgentCLI: () => checkAgentCLI,
|
|
109747
110334
|
checkBuildCommandInReviewChecks: () => checkBuildCommandInReviewChecks,
|
|
@@ -109758,6 +110345,7 @@ __export(exports_precheck, {
|
|
|
109758
110345
|
checkLintCommand: () => checkLintCommand,
|
|
109759
110346
|
checkModelResolution: () => checkModelResolution,
|
|
109760
110347
|
checkMultiAgentHealth: () => checkMultiAgentHealth,
|
|
110348
|
+
checkNativeCredentials: () => checkNativeCredentials,
|
|
109761
110349
|
checkOptionalCommands: () => checkOptionalCommands,
|
|
109762
110350
|
checkPRDValid: () => checkPRDValid,
|
|
109763
110351
|
checkPendingStories: () => checkPendingStories,
|
|
@@ -109766,6 +110354,8 @@ __export(exports_precheck, {
|
|
|
109766
110354
|
checkTestCommand: () => checkTestCommand,
|
|
109767
110355
|
checkTypecheckCommand: () => checkTypecheckCommand,
|
|
109768
110356
|
checkWorkingTreeClean: () => checkWorkingTreeClean,
|
|
110357
|
+
describeMissingNativeCredentials: () => describeMissingNativeCredentials,
|
|
110358
|
+
findMissingNativeCredentials: () => findMissingNativeCredentials,
|
|
109769
110359
|
parseDiskSpaceOutput: () => parseDiskSpaceOutput,
|
|
109770
110360
|
runEnvironmentPrecheck: () => runEnvironmentPrecheck,
|
|
109771
110361
|
runPrecheck: () => runPrecheck2
|
|
@@ -109781,6 +110371,7 @@ function getLateEnvironmentBlockers(config2, workdir) {
|
|
|
109781
110371
|
return [
|
|
109782
110372
|
() => checkAgentCLI(config2),
|
|
109783
110373
|
() => checkModelResolution(config2),
|
|
110374
|
+
() => checkNativeCredentials(config2),
|
|
109784
110375
|
() => checkDependenciesInstalled(workdir),
|
|
109785
110376
|
() => checkTestCommand(config2),
|
|
109786
110377
|
() => checkLintCommand(config2),
|
|
@@ -110170,7 +110761,7 @@ ${repairHint}` : codebaseContext;
|
|
|
110170
110761
|
agentRouting: config2.routing?.agents,
|
|
110171
110762
|
profileName: config2.profile,
|
|
110172
110763
|
models: config2.models,
|
|
110173
|
-
defaultAgent: config2.agent?.default ??
|
|
110764
|
+
defaultAgent: config2.agent?.default ?? DEFAULT_AGENT_NAME,
|
|
110174
110765
|
outputPath: prdPath,
|
|
110175
110766
|
repoRoot: workdir,
|
|
110176
110767
|
scope: new Set(subStoriesWithParent.map((s) => s.id)),
|
|
@@ -110272,8 +110863,8 @@ var init_plan_runtime = __esm(() => {
|
|
|
110272
110863
|
init_git_env();
|
|
110273
110864
|
init_plan_helpers();
|
|
110274
110865
|
_planDeps = {
|
|
110275
|
-
readFile: (
|
|
110276
|
-
writeFile: (
|
|
110866
|
+
readFile: (path30) => Bun.file(path30).text(),
|
|
110867
|
+
writeFile: (path30, content) => Bun.write(path30, content).then(() => {}),
|
|
110277
110868
|
scanSourceRoots: (workdir) => scanSourceRoots(workdir),
|
|
110278
110869
|
createRuntime: (cfg, wd, featureName) => createRuntime(cfg, wd, { featureName }),
|
|
110279
110870
|
claimProjectIdentity,
|
|
@@ -110282,10 +110873,10 @@ var init_plan_runtime = __esm(() => {
|
|
|
110282
110873
|
const result = Bun.spawnSync(cmd, opts ? { cwd: opts.cwd, ...opts.env ? { env: opts.env } : {} } : {});
|
|
110283
110874
|
return { stdout: result.stdout, exitCode: result.exitCode };
|
|
110284
110875
|
},
|
|
110285
|
-
mkdirp: (
|
|
110286
|
-
existsSync: (
|
|
110876
|
+
mkdirp: (path30) => Bun.spawn(["mkdir", "-p", path30]).exited.then(() => {}),
|
|
110877
|
+
existsSync: (path30) => existsSync38(path30),
|
|
110287
110878
|
discoverWorkspacePackages: (repoRoot) => discoverWorkspacePackages2(repoRoot),
|
|
110288
|
-
readPackageJsonAt: (
|
|
110879
|
+
readPackageJsonAt: (path30) => Bun.file(path30).json().catch(() => null),
|
|
110289
110880
|
createInteractionBridge: () => createCliInteractionBridge(),
|
|
110290
110881
|
initInteractionChain: (cfg, headless) => initInteractionChain(cfg, headless),
|
|
110291
110882
|
runPrecheck: async (config2, prd, opts) => {
|
|
@@ -110306,7 +110897,7 @@ function assertSpecLintClean(specContent, options) {
|
|
|
110306
110897
|
return [];
|
|
110307
110898
|
const findings = lintSpecContent(specContent, {
|
|
110308
110899
|
maxAcCount: options.maxAcCount,
|
|
110309
|
-
fileExists: (
|
|
110900
|
+
fileExists: (path30) => existsSync39(join118(options.workdir, path30))
|
|
110310
110901
|
});
|
|
110311
110902
|
const blocking = findings.filter((finding) => BLOCKING_SPEC_LINT_CODES.has(finding.code));
|
|
110312
110903
|
if (blocking.length > 0) {
|
|
@@ -110366,7 +110957,7 @@ async function buildPlanModeContext(workdir, fullConfig, options, deps) {
|
|
|
110366
110957
|
}));
|
|
110367
110958
|
const codebaseContext = buildSourceRootsSection(normalizedRoots);
|
|
110368
110959
|
const relativePackages = [
|
|
110369
|
-
...new Set(sourceRoots.map((root) => root.path).filter((
|
|
110960
|
+
...new Set(sourceRoots.map((root) => root.path).filter((path30) => path30 !== ".").map((path30) => path30.startsWith("/") ? path30.replace(`${workdir}/`, "") : path30))
|
|
110370
110961
|
];
|
|
110371
110962
|
const packageDetails = relativePackages.length === 0 ? [] : await Promise.all(relativePackages.map(async (relativePath) => {
|
|
110372
110963
|
const packageJson = await deps.readPackageJsonAt(join119(workdir, relativePath, "package.json"));
|
|
@@ -110494,7 +111085,7 @@ async function persistPrd(ctx, prd) {
|
|
|
110494
111085
|
agentRouting: ctx.config.routing?.agents,
|
|
110495
111086
|
profileName: ctx.profileName,
|
|
110496
111087
|
models: ctx.config.models,
|
|
110497
|
-
defaultAgent: ctx.config.agent?.default ??
|
|
111088
|
+
defaultAgent: ctx.config.agent?.default ?? DEFAULT_AGENT_NAME,
|
|
110498
111089
|
outputPath: ctx.outputPath,
|
|
110499
111090
|
repoRoot: ctx.workdir,
|
|
110500
111091
|
writeFile: ctx.deps.writeFile
|
|
@@ -110502,13 +111093,14 @@ async function persistPrd(ctx, prd) {
|
|
|
110502
111093
|
}
|
|
110503
111094
|
var _persistPrdDeps;
|
|
110504
111095
|
var init_persist_prd = __esm(() => {
|
|
111096
|
+
init_config();
|
|
110505
111097
|
init_generator2();
|
|
110506
111098
|
init_logger2();
|
|
110507
111099
|
init_operations();
|
|
110508
111100
|
init_prd();
|
|
110509
111101
|
init_finalize_routing();
|
|
110510
111102
|
_persistPrdDeps = {
|
|
110511
|
-
existsSync: (
|
|
111103
|
+
existsSync: (path30) => defaultExistsSync(path30),
|
|
110512
111104
|
discoverWorkspacePackages: (repoRoot) => discoverWorkspacePackages2(repoRoot)
|
|
110513
111105
|
};
|
|
110514
111106
|
});
|
|
@@ -110771,10 +111363,10 @@ var init_plan2 = __esm(() => {
|
|
|
110771
111363
|
});
|
|
110772
111364
|
|
|
110773
111365
|
// src/cli/plugins.ts
|
|
110774
|
-
import * as
|
|
111366
|
+
import * as path30 from "path";
|
|
110775
111367
|
async function pluginsListCommand(config2, workdir, overrideGlobalPluginsDir) {
|
|
110776
|
-
const globalPluginsDir = overrideGlobalPluginsDir ??
|
|
110777
|
-
const projectPluginsDir =
|
|
111368
|
+
const globalPluginsDir = overrideGlobalPluginsDir ?? path30.join(globalConfigDir(), "plugins");
|
|
111369
|
+
const projectPluginsDir = path30.join(workdir, ".nax", "plugins");
|
|
110778
111370
|
const configPlugins = config2.plugins || [];
|
|
110779
111371
|
const registry4 = await loadPlugins(globalPluginsDir, projectPluginsDir, configPlugins, workdir, config2.disabledPlugins);
|
|
110780
111372
|
const plugins = registry4.plugins;
|
|
@@ -110824,10 +111416,10 @@ function formatSource(type, sourcePath) {
|
|
|
110824
111416
|
return `built-in (${sourcePath})`;
|
|
110825
111417
|
}
|
|
110826
111418
|
if (type === "global") {
|
|
110827
|
-
return `global (${
|
|
111419
|
+
return `global (${path30.basename(sourcePath)})`;
|
|
110828
111420
|
}
|
|
110829
111421
|
if (type === "project") {
|
|
110830
|
-
return `project (${
|
|
111422
|
+
return `project (${path30.basename(sourcePath)})`;
|
|
110831
111423
|
}
|
|
110832
111424
|
return `config (${sourcePath})`;
|
|
110833
111425
|
}
|
|
@@ -110869,7 +111461,7 @@ async function exportPromptCommand(options) {
|
|
|
110869
111461
|
var VALID_EXPORT_ROLES;
|
|
110870
111462
|
var init_prompts_export = __esm(() => {
|
|
110871
111463
|
init_prompts();
|
|
110872
|
-
VALID_EXPORT_ROLES = ["test-writer", "implementer", "verifier", "
|
|
111464
|
+
VALID_EXPORT_ROLES = ["test-writer", "implementer", "verifier", "tdd-simple"];
|
|
110873
111465
|
});
|
|
110874
111466
|
|
|
110875
111467
|
// src/cli/prompts-init.ts
|
|
@@ -110911,7 +111503,6 @@ async function autoWirePromptsConfig(workdir) {
|
|
|
110911
111503
|
"test-writer": ".nax/templates/test-writer.md",
|
|
110912
111504
|
implementer: ".nax/templates/implementer.md",
|
|
110913
111505
|
verifier: ".nax/templates/verifier.md",
|
|
110914
|
-
"single-session": ".nax/templates/single-session.md",
|
|
110915
111506
|
"tdd-simple": ".nax/templates/tdd-simple.md"
|
|
110916
111507
|
}
|
|
110917
111508
|
}
|
|
@@ -110932,7 +111523,6 @@ ${exampleConfig}`);
|
|
|
110932
111523
|
"test-writer": ".nax/templates/test-writer.md",
|
|
110933
111524
|
implementer: ".nax/templates/implementer.md",
|
|
110934
111525
|
verifier: ".nax/templates/verifier.md",
|
|
110935
|
-
"single-session": ".nax/templates/single-session.md",
|
|
110936
111526
|
"tdd-simple": ".nax/templates/tdd-simple.md"
|
|
110937
111527
|
};
|
|
110938
111528
|
prompts.overrides = overrides;
|
|
@@ -110991,7 +111581,6 @@ var init_prompts_init = __esm(() => {
|
|
|
110991
111581
|
{ file: "test-writer.md", role: "test-writer" },
|
|
110992
111582
|
{ file: "implementer.md", role: "implementer", variant: "standard" },
|
|
110993
111583
|
{ file: "verifier.md", role: "verifier" },
|
|
110994
|
-
{ file: "single-session.md", role: "single-session" },
|
|
110995
111584
|
{ file: "tdd-simple.md", role: "tdd-simple" }
|
|
110996
111585
|
];
|
|
110997
111586
|
});
|
|
@@ -111229,8 +111818,8 @@ async function resolveRunProfileOverride(opts) {
|
|
|
111229
111818
|
return cliChain;
|
|
111230
111819
|
if (opts.envProfile)
|
|
111231
111820
|
return;
|
|
111232
|
-
const readJson2 = opts._readJson ?? (async (
|
|
111233
|
-
const file2 = Bun.file(
|
|
111821
|
+
const readJson2 = opts._readJson ?? (async (path31) => {
|
|
111822
|
+
const file2 = Bun.file(path31);
|
|
111234
111823
|
if (!await file2.exists())
|
|
111235
111824
|
return;
|
|
111236
111825
|
return file2.json();
|
|
@@ -111610,11 +112199,11 @@ var init_rules_cli_deps = __esm(() => {
|
|
|
111610
112199
|
init_logger2();
|
|
111611
112200
|
init_rules_lint();
|
|
111612
112201
|
_rulesCLIDeps = {
|
|
111613
|
-
readFile: async (
|
|
111614
|
-
writeFile: async (
|
|
111615
|
-
await Bun.write(
|
|
112202
|
+
readFile: async (path31) => Bun.file(path31).text(),
|
|
112203
|
+
writeFile: async (path31, content) => {
|
|
112204
|
+
await Bun.write(path31, content);
|
|
111616
112205
|
},
|
|
111617
|
-
fileExists: async (
|
|
112206
|
+
fileExists: async (path31) => Bun.file(path31).exists(),
|
|
111618
112207
|
globInDir: (dir) => {
|
|
111619
112208
|
try {
|
|
111620
112209
|
return [...new Bun.Glob("*.md").scanSync({ cwd: dir })].sort().map((f) => join127(dir, f));
|
|
@@ -111622,8 +112211,8 @@ var init_rules_cli_deps = __esm(() => {
|
|
|
111622
112211
|
return [];
|
|
111623
112212
|
}
|
|
111624
112213
|
},
|
|
111625
|
-
mkdir: async (
|
|
111626
|
-
await mkdir33(
|
|
112214
|
+
mkdir: async (path31) => {
|
|
112215
|
+
await mkdir33(path31, { recursive: true });
|
|
111627
112216
|
},
|
|
111628
112217
|
globCanonicalRuleFiles: (workdir) => _rulesLintDeps.globCanonicalRuleFiles(workdir),
|
|
111629
112218
|
globHasMatch: (pattern, cwd) => _rulesLintDeps.globHasMatch(pattern, cwd),
|
|
@@ -112140,10 +112729,10 @@ var init_setup_analyze = __esm(() => {
|
|
|
112140
112729
|
init_detect();
|
|
112141
112730
|
CANONICAL_SCRIPTS = ["build", "test", "lint", "type-check", "lint:fix"];
|
|
112142
112731
|
_analyzeRepoDeps = {
|
|
112143
|
-
fileExists: async (
|
|
112144
|
-
readJson: async (
|
|
112732
|
+
fileExists: async (path31) => Bun.file(path31).exists(),
|
|
112733
|
+
readJson: async (path31) => {
|
|
112145
112734
|
try {
|
|
112146
|
-
const f = Bun.file(
|
|
112735
|
+
const f = Bun.file(path31);
|
|
112147
112736
|
if (!await f.exists())
|
|
112148
112737
|
return null;
|
|
112149
112738
|
return JSON.parse(await f.text());
|
|
@@ -112198,9 +112787,9 @@ async function fillScripts(workdir, analysis) {
|
|
|
112198
112787
|
var TYPE_CHECK_KEY = "type-check", TYPE_CHECK_SCRIPT = "tsc --noEmit -p tsconfig.json", TYPE_CHECK_TURBO_PASSTHROUGH = "turbo run type-check", _fillScriptsDeps;
|
|
112199
112788
|
var init_setup_fill = __esm(() => {
|
|
112200
112789
|
_fillScriptsDeps = {
|
|
112201
|
-
readJson: async (
|
|
112790
|
+
readJson: async (path31) => {
|
|
112202
112791
|
try {
|
|
112203
|
-
const f = Bun.file(
|
|
112792
|
+
const f = Bun.file(path31);
|
|
112204
112793
|
if (!await f.exists())
|
|
112205
112794
|
return null;
|
|
112206
112795
|
return JSON.parse(await f.text());
|
|
@@ -112208,8 +112797,8 @@ var init_setup_fill = __esm(() => {
|
|
|
112208
112797
|
return null;
|
|
112209
112798
|
}
|
|
112210
112799
|
},
|
|
112211
|
-
writeFile: async (
|
|
112212
|
-
await Bun.write(
|
|
112800
|
+
writeFile: async (path31, content) => {
|
|
112801
|
+
await Bun.write(path31, content);
|
|
112213
112802
|
}
|
|
112214
112803
|
};
|
|
112215
112804
|
});
|
|
@@ -112267,9 +112856,9 @@ async function writeSetupConfig(workdir, config2, monoConfigs, _opts, deps = _wr
|
|
|
112267
112856
|
var _writeSetupDeps;
|
|
112268
112857
|
var init_setup_write = __esm(() => {
|
|
112269
112858
|
_writeSetupDeps = {
|
|
112270
|
-
writeFile: (
|
|
112271
|
-
mkdir: async (
|
|
112272
|
-
const proc = Bun.spawn(["mkdir", "-p",
|
|
112859
|
+
writeFile: (path31, content) => Bun.write(path31, content).then(() => {}),
|
|
112860
|
+
mkdir: async (path31) => {
|
|
112861
|
+
const proc = Bun.spawn(["mkdir", "-p", path31]);
|
|
112273
112862
|
await proc.exited;
|
|
112274
112863
|
}
|
|
112275
112864
|
};
|
|
@@ -112353,7 +112942,7 @@ var init_setup = __esm(() => {
|
|
|
112353
112942
|
},
|
|
112354
112943
|
generateSetupPlan: (ctx, analysis) => generateSetupPlan(ctx, analysis),
|
|
112355
112944
|
runGate: (workdir, config2) => runSetupGate(workdir, config2),
|
|
112356
|
-
fileExists: (
|
|
112945
|
+
fileExists: (path31) => Bun.file(path31).exists(),
|
|
112357
112946
|
writeSetupConfig: (workdir, config2, monoConfigs, opts) => writeSetupConfig(workdir, config2, monoConfigs, opts),
|
|
112358
112947
|
stdout: (msg) => {
|
|
112359
112948
|
process.stdout.write(`${msg}
|
|
@@ -112370,7 +112959,7 @@ var init_setup = __esm(() => {
|
|
|
112370
112959
|
import { existsSync as existsSync43 } from "fs";
|
|
112371
112960
|
import { join as join135 } from "path";
|
|
112372
112961
|
async function resolveSpecPaths(options, deps) {
|
|
112373
|
-
const explicit = (options.paths ?? []).filter((
|
|
112962
|
+
const explicit = (options.paths ?? []).filter((path31) => path31.trim().length > 0);
|
|
112374
112963
|
if (explicit.length > 0)
|
|
112375
112964
|
return [...explicit];
|
|
112376
112965
|
if (!options.feature)
|
|
@@ -112398,7 +112987,7 @@ async function lintOne(specPath, options, deps) {
|
|
|
112398
112987
|
}
|
|
112399
112988
|
const findings = lintSpecContent(content, {
|
|
112400
112989
|
maxAcCount: options.maxAcCount,
|
|
112401
|
-
fileExists: (
|
|
112990
|
+
fileExists: (path31) => deps.fileExists(join135(options.dir, path31))
|
|
112402
112991
|
});
|
|
112403
112992
|
return {
|
|
112404
112993
|
specPath,
|
|
@@ -112464,7 +113053,7 @@ var init_spec_lint_command = __esm(() => {
|
|
|
112464
113053
|
init_prd();
|
|
112465
113054
|
init_features_resolve();
|
|
112466
113055
|
_specLintCommandDeps = {
|
|
112467
|
-
readFile: async (
|
|
113056
|
+
readFile: async (path31) => Bun.file(path31).text(),
|
|
112468
113057
|
fileExists: existsSync43,
|
|
112469
113058
|
write: (line) => {
|
|
112470
113059
|
console.log(line);
|
|
@@ -114384,11 +114973,11 @@ var require_react_reconciler_development = __commonJS(function(exports, module)
|
|
|
114384
114973
|
fiber = fiber.next, id--;
|
|
114385
114974
|
return fiber;
|
|
114386
114975
|
}
|
|
114387
|
-
function copyWithSetImpl(obj,
|
|
114388
|
-
if (index >=
|
|
114976
|
+
function copyWithSetImpl(obj, path31, index, value) {
|
|
114977
|
+
if (index >= path31.length)
|
|
114389
114978
|
return value;
|
|
114390
|
-
var key =
|
|
114391
|
-
updated[key] = copyWithSetImpl(obj[key],
|
|
114979
|
+
var key = path31[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
|
|
114980
|
+
updated[key] = copyWithSetImpl(obj[key], path31, index + 1, value);
|
|
114392
114981
|
return updated;
|
|
114393
114982
|
}
|
|
114394
114983
|
function copyWithRename(obj, oldPath, newPath) {
|
|
@@ -114408,11 +114997,11 @@ var require_react_reconciler_development = __commonJS(function(exports, module)
|
|
|
114408
114997
|
index + 1 === oldPath.length ? (updated[newPath[index]] = updated[oldKey], isArrayImpl(updated) ? updated.splice(oldKey, 1) : delete updated[oldKey]) : updated[oldKey] = copyWithRenameImpl(obj[oldKey], oldPath, newPath, index + 1);
|
|
114409
114998
|
return updated;
|
|
114410
114999
|
}
|
|
114411
|
-
function copyWithDeleteImpl(obj,
|
|
114412
|
-
var key =
|
|
114413
|
-
if (index + 1 ===
|
|
115000
|
+
function copyWithDeleteImpl(obj, path31, index) {
|
|
115001
|
+
var key = path31[index], updated = isArrayImpl(obj) ? obj.slice() : assign2({}, obj);
|
|
115002
|
+
if (index + 1 === path31.length)
|
|
114414
115003
|
return isArrayImpl(updated) ? updated.splice(key, 1) : delete updated[key], updated;
|
|
114415
|
-
updated[key] = copyWithDeleteImpl(obj[key],
|
|
115004
|
+
updated[key] = copyWithDeleteImpl(obj[key], path31, index + 1);
|
|
114416
115005
|
return updated;
|
|
114417
115006
|
}
|
|
114418
115007
|
function shouldSuspendImpl() {
|
|
@@ -124436,29 +125025,29 @@ Check the top-level render call using <` + componentName2 + ">.");
|
|
|
124436
125025
|
var didWarnAboutNestedUpdates = false;
|
|
124437
125026
|
var didWarnAboutFindNodeInStrictMode = {};
|
|
124438
125027
|
var overrideHookState = null, overrideHookStateDeletePath = null, overrideHookStateRenamePath = null, overrideProps = null, overridePropsDeletePath = null, overridePropsRenamePath = null, scheduleUpdate = null, scheduleRetry = null, setErrorHandler = null, setSuspenseHandler = null;
|
|
124439
|
-
overrideHookState = function(fiber, id,
|
|
125028
|
+
overrideHookState = function(fiber, id, path31, value) {
|
|
124440
125029
|
id = findHook(fiber, id);
|
|
124441
|
-
id !== null && (
|
|
125030
|
+
id !== null && (path31 = copyWithSetImpl(id.memoizedState, path31, 0, value), id.memoizedState = path31, id.baseState = path31, fiber.memoizedProps = assign2({}, fiber.memoizedProps), path31 = enqueueConcurrentRenderForLane(fiber, 2), path31 !== null && scheduleUpdateOnFiber(path31, fiber, 2));
|
|
124442
125031
|
};
|
|
124443
|
-
overrideHookStateDeletePath = function(fiber, id,
|
|
125032
|
+
overrideHookStateDeletePath = function(fiber, id, path31) {
|
|
124444
125033
|
id = findHook(fiber, id);
|
|
124445
|
-
id !== null && (
|
|
125034
|
+
id !== null && (path31 = copyWithDeleteImpl(id.memoizedState, path31, 0), id.memoizedState = path31, id.baseState = path31, fiber.memoizedProps = assign2({}, fiber.memoizedProps), path31 = enqueueConcurrentRenderForLane(fiber, 2), path31 !== null && scheduleUpdateOnFiber(path31, fiber, 2));
|
|
124446
125035
|
};
|
|
124447
125036
|
overrideHookStateRenamePath = function(fiber, id, oldPath, newPath) {
|
|
124448
125037
|
id = findHook(fiber, id);
|
|
124449
125038
|
id !== null && (oldPath = copyWithRename(id.memoizedState, oldPath, newPath), id.memoizedState = oldPath, id.baseState = oldPath, fiber.memoizedProps = assign2({}, fiber.memoizedProps), oldPath = enqueueConcurrentRenderForLane(fiber, 2), oldPath !== null && scheduleUpdateOnFiber(oldPath, fiber, 2));
|
|
124450
125039
|
};
|
|
124451
|
-
overrideProps = function(fiber,
|
|
124452
|
-
fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps,
|
|
125040
|
+
overrideProps = function(fiber, path31, value) {
|
|
125041
|
+
fiber.pendingProps = copyWithSetImpl(fiber.memoizedProps, path31, 0, value);
|
|
124453
125042
|
fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
|
|
124454
|
-
|
|
124455
|
-
|
|
125043
|
+
path31 = enqueueConcurrentRenderForLane(fiber, 2);
|
|
125044
|
+
path31 !== null && scheduleUpdateOnFiber(path31, fiber, 2);
|
|
124456
125045
|
};
|
|
124457
|
-
overridePropsDeletePath = function(fiber,
|
|
124458
|
-
fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps,
|
|
125046
|
+
overridePropsDeletePath = function(fiber, path31) {
|
|
125047
|
+
fiber.pendingProps = copyWithDeleteImpl(fiber.memoizedProps, path31, 0);
|
|
124459
125048
|
fiber.alternate && (fiber.alternate.pendingProps = fiber.pendingProps);
|
|
124460
|
-
|
|
124461
|
-
|
|
125049
|
+
path31 = enqueueConcurrentRenderForLane(fiber, 2);
|
|
125050
|
+
path31 !== null && scheduleUpdateOnFiber(path31, fiber, 2);
|
|
124462
125051
|
};
|
|
124463
125052
|
overridePropsRenamePath = function(fiber, oldPath, newPath) {
|
|
124464
125053
|
fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath);
|
|
@@ -126097,11 +126686,38 @@ init_config_profile();
|
|
|
126097
126686
|
init_features_resolve();
|
|
126098
126687
|
init_generate();
|
|
126099
126688
|
|
|
126689
|
+
// src/cli/run-max-iterations.ts
|
|
126690
|
+
function parseMaxIterationsFlag(raw) {
|
|
126691
|
+
if (raw === undefined)
|
|
126692
|
+
return { ok: true, value: undefined };
|
|
126693
|
+
const value = Number.parseInt(raw, 10);
|
|
126694
|
+
if (!Number.isFinite(value) || value < 1) {
|
|
126695
|
+
return { ok: false, message: "--max-iterations must be a positive integer" };
|
|
126696
|
+
}
|
|
126697
|
+
return { ok: true, value };
|
|
126698
|
+
}
|
|
126699
|
+
function applyMaxIterationsFlag(config2, flag) {
|
|
126700
|
+
if (flag === undefined)
|
|
126701
|
+
return { ...config2, execution: { ...config2.execution } };
|
|
126702
|
+
return { ...config2, execution: { ...config2.execution, maxIterations: flag } };
|
|
126703
|
+
}
|
|
126704
|
+
|
|
126100
126705
|
// src/cli/run-mode.ts
|
|
126101
126706
|
function resolveUseHeadless(input) {
|
|
126102
126707
|
return !input.isTTY || input.headlessFlag || input.headlessEnv || input.formatterMode === "json";
|
|
126103
126708
|
}
|
|
126104
126709
|
|
|
126710
|
+
// src/cli/run-parallel.ts
|
|
126711
|
+
function parseParallelFlag(raw) {
|
|
126712
|
+
if (raw === undefined)
|
|
126713
|
+
return { ok: true, value: undefined };
|
|
126714
|
+
const value = Number.parseInt(raw, 10);
|
|
126715
|
+
if (!Number.isFinite(value) || value < 1) {
|
|
126716
|
+
return { ok: false, message: "--parallel must be a positive integer (omit it to run sequentially)" };
|
|
126717
|
+
}
|
|
126718
|
+
return { ok: true, value };
|
|
126719
|
+
}
|
|
126720
|
+
|
|
126105
126721
|
// bin/nax.ts
|
|
126106
126722
|
init_status_dispatch();
|
|
126107
126723
|
|
|
@@ -126120,14 +126736,14 @@ function resolveEffective(detected, configPatterns) {
|
|
|
126120
126736
|
return "detected";
|
|
126121
126737
|
return "none";
|
|
126122
126738
|
}
|
|
126123
|
-
async function loadRawConfig(
|
|
126124
|
-
const f = Bun.file(
|
|
126739
|
+
async function loadRawConfig(path31) {
|
|
126740
|
+
const f = Bun.file(path31);
|
|
126125
126741
|
if (!await f.exists())
|
|
126126
126742
|
return {};
|
|
126127
126743
|
return JSON.parse(await f.text());
|
|
126128
126744
|
}
|
|
126129
|
-
async function writeRawConfig(
|
|
126130
|
-
await Bun.write(
|
|
126745
|
+
async function writeRawConfig(path31, data) {
|
|
126746
|
+
await Bun.write(path31, `${JSON.stringify(data, null, 2)}
|
|
126131
126747
|
`);
|
|
126132
126748
|
}
|
|
126133
126749
|
function deepSet(obj, keyPath, value) {
|
|
@@ -131211,8 +131827,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
|
|
|
131211
131827
|
}
|
|
131212
131828
|
|
|
131213
131829
|
// node_modules/ink/build/components/ErrorOverview.js
|
|
131214
|
-
var cleanupPath = (
|
|
131215
|
-
return
|
|
131830
|
+
var cleanupPath = (path31) => {
|
|
131831
|
+
return path31?.replace(`file://${cwd()}/`, "");
|
|
131216
131832
|
};
|
|
131217
131833
|
var stackUtils = new import_stack_utils.default({
|
|
131218
131834
|
cwd: cwd(),
|
|
@@ -134253,7 +134869,7 @@ program2.command("setup").description("Analyze repo and generate .nax/config.jso
|
|
|
134253
134869
|
});
|
|
134254
134870
|
process.exit(exitCode);
|
|
134255
134871
|
});
|
|
134256
|
-
program2.command("run").description("Run the orchestration loop for a feature").requiredOption("-f, --feature <name>", "Feature name").option("-a, --agent <name>", "Force a specific agent").option("-m, --max-iterations <n>", "Max iterations"
|
|
134872
|
+
program2.command("run").description("Run the orchestration loop for a feature").requiredOption("-f, --feature <name>", "Feature name").option("-a, --agent <name>", "Force a specific agent").option("-m, --max-iterations <n>", "Max iterations").option("--max-cost <usd>", "Override cost limit (USD) for this run \u2014 aborts execution when exceeded").option("--dry-run", "Show plan without executing", false).option("--no-context", "Disable context builder (skip file context in prompts)").option("--no-batch", "Disable story batching (execute all stories individually)").option("--parallel <n>", "Max parallel sessions (omit = sequential)").option("--plan", "Run plan phase first before execution", false).option("--from <spec-path>", "Path to spec file (required when --plan is used)").option("--no-spec-lint", "Plan even when the spec declares sections that extract to nothing").option("--one-shot", "Skip interactive planning Q&A, use single LLM call (ACP only)", false).option("--force", "Force overwrite existing prd.json when using --plan", false).option("--headless", "Force headless mode (disable TUI, use pipe mode)", false).option("--verbose", "Enable verbose logging (debug level)", false).option("--quiet", "Quiet mode (warnings and errors only)", false).option("--silent", "Silent mode (errors only)", false).option("--json", "JSON mode (raw JSONL output to stdout)", false).option("-d, --dir <path>", "Working directory", process.cwd()).option("--skip-precheck", "Skip precheck validations (advanced users only)", false).option("--profile <name>", "Profile(s) to overlay (comma-separated or repeated; later overrides earlier)", collectProfile, []).option("--schedule <when>", "Defer run start until <when> (e.g. 30m, 1h30m, 17:00, 2026-07-02T02:00)").option("--compare <agents>", "Bake-off mode: comma-separated list of contestant agents (e.g. claude,codex)").option("--fresh", "Ignore any existing checkpoint.jsonl and re-run every incomplete story from scratch", false).addOption(new Option("--no-resume", "Alias for --fresh: never auto-resume from a prior checkpoint").default("__UNSET__")).action(async (options) => {
|
|
134257
134873
|
try {
|
|
134258
134874
|
validateFeatureName(options.feature);
|
|
134259
134875
|
} catch (err) {
|
|
@@ -134267,6 +134883,17 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
134267
134883
|
console.error(source_default.red(`Invalid directory: ${err.message}`));
|
|
134268
134884
|
process.exit(1);
|
|
134269
134885
|
}
|
|
134886
|
+
const maxIterationsFlag = parseMaxIterationsFlag(options.maxIterations);
|
|
134887
|
+
if (!maxIterationsFlag.ok) {
|
|
134888
|
+
console.error(source_default.red(maxIterationsFlag.message));
|
|
134889
|
+
process.exit(1);
|
|
134890
|
+
}
|
|
134891
|
+
const parallelFlag = parseParallelFlag(options.parallel);
|
|
134892
|
+
if (!parallelFlag.ok) {
|
|
134893
|
+
console.error(source_default.red(parallelFlag.message));
|
|
134894
|
+
process.exit(1);
|
|
134895
|
+
}
|
|
134896
|
+
const parallel = parallelFlag.value;
|
|
134270
134897
|
try {
|
|
134271
134898
|
const { assertCompareAgentExclusive: assertCompareAgentExclusive2 } = await Promise.resolve().then(() => (init_preflight(), exports_preflight));
|
|
134272
134899
|
assertCompareAgentExclusive2({ compare: options.compare, agent: options.agent });
|
|
@@ -134456,12 +135083,7 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
134456
135083
|
config2.agent ??= {};
|
|
134457
135084
|
config2.agent.default = options.agent;
|
|
134458
135085
|
}
|
|
134459
|
-
|
|
134460
|
-
if (!Number.isFinite(maxIterations) || maxIterations < 1) {
|
|
134461
|
-
console.error(source_default.red("--max-iterations must be a positive integer"));
|
|
134462
|
-
process.exit(1);
|
|
134463
|
-
}
|
|
134464
|
-
config2.execution.maxIterations = maxIterations;
|
|
135086
|
+
config2 = applyMaxIterationsFlag(config2, maxIterationsFlag.value);
|
|
134465
135087
|
if (options.maxCost !== undefined) {
|
|
134466
135088
|
const maxCost = Number(options.maxCost);
|
|
134467
135089
|
if (!Number.isFinite(maxCost) || maxCost <= 0) {
|
|
@@ -134501,15 +135123,6 @@ program2.command("run").description("Run the orchestration loop for a feature").
|
|
|
134501
135123
|
console.log(source_default.dim(" [Headless mode \u2014 pipe output]"));
|
|
134502
135124
|
}
|
|
134503
135125
|
const statusFilePath = join142(outputDir, "status.json");
|
|
134504
|
-
let parallel;
|
|
134505
|
-
if (options.parallel !== undefined) {
|
|
134506
|
-
parallel = Number.parseInt(options.parallel, 10);
|
|
134507
|
-
if (Number.isNaN(parallel) || parallel < 0) {
|
|
134508
|
-
tuiInstance?.unmount();
|
|
134509
|
-
console.error(source_default.red("--parallel must be a non-negative integer"));
|
|
134510
|
-
process.exit(1);
|
|
134511
|
-
}
|
|
134512
|
-
}
|
|
134513
135126
|
if (scheduleGate.target) {
|
|
134514
135127
|
const scheduleController = new AbortController;
|
|
134515
135128
|
const onSigint = () => scheduleController.abort();
|
|
@@ -134941,8 +135554,8 @@ configProfileCmd.command("current").description("Show the currently active profi
|
|
|
134941
135554
|
});
|
|
134942
135555
|
configProfileCmd.command("create <name>").description("Create a new empty profile").option("-d, --dir <path>", "Project directory", process.cwd()).action(async (name, options) => {
|
|
134943
135556
|
try {
|
|
134944
|
-
const
|
|
134945
|
-
console.log(`Created profile at: ${
|
|
135557
|
+
const path31 = await profileCreateCommand(name, options.dir);
|
|
135558
|
+
console.log(`Created profile at: ${path31}`);
|
|
134946
135559
|
} catch (err) {
|
|
134947
135560
|
console.error(source_default.red(`Error: ${err.message}`));
|
|
134948
135561
|
process.exit(1);
|