@nathapp/nax 0.68.1 → 0.68.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nax.js +402 -135
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -17735,19 +17735,30 @@ function formatStoryStart(entry, c, _timestamp, mode) {
|
|
|
17735
17735
|
const complexity = typeof data.complexity === "string" ? data.complexity : "unknown";
|
|
17736
17736
|
const tier = typeof data.modelTier === "string" ? data.modelTier : "unknown";
|
|
17737
17737
|
const attempt = typeof data.attempt === "number" ? data.attempt : 1;
|
|
17738
|
+
const agent = typeof data.agent === "string" ? data.agent : undefined;
|
|
17739
|
+
const progress = typeof data.storyNumber === "number" && typeof data.storyTotal === "number" ? `${data.storyNumber}/${data.storyTotal}` : undefined;
|
|
17738
17740
|
const lines = [];
|
|
17739
17741
|
lines.push("");
|
|
17740
17742
|
lines.push(c.bold(`${EMOJI.storyStart} ${c.cyan(storyId)}: ${title}`));
|
|
17741
17743
|
if (mode === "verbose") {
|
|
17744
|
+
if (progress)
|
|
17745
|
+
lines.push(` ${c.gray("\u251C\u2500")} Story: ${c.cyan(progress)}`);
|
|
17742
17746
|
lines.push(` ${c.gray("\u251C\u2500")} Complexity: ${c.yellow(complexity)}`);
|
|
17743
17747
|
lines.push(` ${c.gray("\u251C\u2500")} Tier: ${c.magenta(tier)}`);
|
|
17748
|
+
if (agent)
|
|
17749
|
+
lines.push(` ${c.gray("\u251C\u2500")} Agent: ${c.cyan(agent)}`);
|
|
17744
17750
|
if (attempt > 1) {
|
|
17745
17751
|
lines.push(` ${c.gray("\u2514\u2500")} Attempt: ${c.yellow(`#${attempt}`)} ${EMOJI.retry}`);
|
|
17746
17752
|
} else {
|
|
17747
17753
|
lines.push(` ${c.gray("\u2514\u2500")} Status: ${c.green("starting")}`);
|
|
17748
17754
|
}
|
|
17749
17755
|
} else {
|
|
17750
|
-
const metadata = [
|
|
17756
|
+
const metadata = [];
|
|
17757
|
+
if (progress)
|
|
17758
|
+
metadata.push(progress);
|
|
17759
|
+
metadata.push(complexity, tier);
|
|
17760
|
+
if (agent)
|
|
17761
|
+
metadata.push(agent);
|
|
17751
17762
|
if (attempt > 1)
|
|
17752
17763
|
metadata.push(`attempt #${attempt} ${EMOJI.retry}`);
|
|
17753
17764
|
lines.push(` ${c.gray(metadata.join(" \u2022 "))}`);
|
|
@@ -17809,24 +17820,19 @@ function formatDefault(entry, c, timestamp, mode) {
|
|
|
17809
17820
|
if (entry.storyId) {
|
|
17810
17821
|
parts.push(c.dim(`[${entry.storyId}]`));
|
|
17811
17822
|
}
|
|
17823
|
+
if (entry.sessionRole) {
|
|
17824
|
+
parts.push(c.dim(`(${entry.sessionRole})`));
|
|
17825
|
+
}
|
|
17812
17826
|
parts.push(entry.message);
|
|
17813
17827
|
let output = parts.join(" ");
|
|
17814
17828
|
const data = entry.data;
|
|
17815
17829
|
if (data && typeof data === "object") {
|
|
17816
|
-
const meta3 =
|
|
17817
|
-
if (typeof data.cost === "number" && data.cost > 0)
|
|
17818
|
-
meta3.push(`${EMOJI.cost} ${formatCost(data.cost)}`);
|
|
17819
|
-
if (typeof data.durationMs === "number" && data.durationMs > 0)
|
|
17820
|
-
meta3.push(`${EMOJI.duration} ${formatDuration(data.durationMs)}`);
|
|
17821
|
-
if (typeof data.action === "string")
|
|
17822
|
-
meta3.push(`action: ${data.action}`);
|
|
17823
|
-
if (typeof data.reason === "string" && mode !== "quiet")
|
|
17824
|
-
meta3.push(data.reason);
|
|
17830
|
+
const meta3 = buildDefaultMeta(data, mode);
|
|
17825
17831
|
if (meta3.length > 0) {
|
|
17826
17832
|
output += ` ${c.gray(meta3.join(" "))}`;
|
|
17827
17833
|
}
|
|
17828
17834
|
if (mode === "verbose") {
|
|
17829
|
-
const
|
|
17835
|
+
const filtered = stripConsumedMetaFields(data);
|
|
17830
17836
|
if (Object.keys(filtered).length > 0) {
|
|
17831
17837
|
output += `
|
|
17832
17838
|
${c.gray(JSON.stringify(filtered, null, 2))}`;
|
|
@@ -17838,6 +17844,52 @@ ${c.gray(JSON.stringify(filtered, null, 2))}`;
|
|
|
17838
17844
|
shouldDisplay: true
|
|
17839
17845
|
};
|
|
17840
17846
|
}
|
|
17847
|
+
function buildDefaultMeta(data, mode) {
|
|
17848
|
+
const meta3 = [];
|
|
17849
|
+
const identity = [data.agentName, data.model].filter((v) => typeof v === "string" && v.length > 0);
|
|
17850
|
+
if (identity.length > 0)
|
|
17851
|
+
meta3.push(`${EMOJI.agent} ${identity.join("\xB7")}`);
|
|
17852
|
+
if (typeof data.phaseIndex === "number" && typeof data.totalPhases === "number") {
|
|
17853
|
+
meta3.push(`${data.phaseIndex}/${data.totalPhases}`);
|
|
17854
|
+
}
|
|
17855
|
+
if (typeof data.status === "string")
|
|
17856
|
+
meta3.push(`status: ${data.status}`);
|
|
17857
|
+
if (typeof data.findingsCount === "number")
|
|
17858
|
+
meta3.push(`${data.findingsCount} finding${data.findingsCount === 1 ? "" : "s"}`);
|
|
17859
|
+
const activity = buildActivityMeta(data);
|
|
17860
|
+
if (activity)
|
|
17861
|
+
meta3.push(activity);
|
|
17862
|
+
if (typeof data.cost === "number" && data.cost > 0)
|
|
17863
|
+
meta3.push(`${EMOJI.cost} ${formatCost(data.cost)}`);
|
|
17864
|
+
if (typeof data.durationMs === "number" && data.durationMs > 0)
|
|
17865
|
+
meta3.push(`${EMOJI.duration} ${formatDuration(data.durationMs)}`);
|
|
17866
|
+
if (typeof data.action === "string")
|
|
17867
|
+
meta3.push(`action: ${data.action}`);
|
|
17868
|
+
if (typeof data.reason === "string" && mode !== "quiet")
|
|
17869
|
+
meta3.push(data.reason);
|
|
17870
|
+
return meta3;
|
|
17871
|
+
}
|
|
17872
|
+
function buildActivityMeta(data) {
|
|
17873
|
+
const segments = [];
|
|
17874
|
+
if (typeof data.messageUpdates === "number" && data.messageUpdates > 0)
|
|
17875
|
+
segments.push(`msg ${data.messageUpdates}`);
|
|
17876
|
+
if (typeof data.toolCallUpdates === "number" && data.toolCallUpdates > 0)
|
|
17877
|
+
segments.push(`tools ${data.toolCallUpdates}`);
|
|
17878
|
+
if (typeof data.thinkingUpdates === "number" && data.thinkingUpdates > 0)
|
|
17879
|
+
segments.push(`think ${data.thinkingUpdates}`);
|
|
17880
|
+
if (typeof data.idleMs === "number" && data.idleMs > 0)
|
|
17881
|
+
segments.push(`idle ${formatDuration(data.idleMs)}`);
|
|
17882
|
+
return segments.length > 0 ? segments.join(" ") : null;
|
|
17883
|
+
}
|
|
17884
|
+
function stripConsumedMetaFields(data) {
|
|
17885
|
+
const filtered = {};
|
|
17886
|
+
for (const [key, value] of Object.entries(data)) {
|
|
17887
|
+
if (!CONSUMED_META_KEYS.includes(key)) {
|
|
17888
|
+
filtered[key] = value;
|
|
17889
|
+
}
|
|
17890
|
+
}
|
|
17891
|
+
return filtered;
|
|
17892
|
+
}
|
|
17841
17893
|
function formatRunSummary(summary, options) {
|
|
17842
17894
|
const { mode, useColor = true } = options;
|
|
17843
17895
|
if (mode === "json") {
|
|
@@ -17882,9 +17934,26 @@ function createNoopChalk() {
|
|
|
17882
17934
|
cyan: noop
|
|
17883
17935
|
};
|
|
17884
17936
|
}
|
|
17937
|
+
var CONSUMED_META_KEYS;
|
|
17885
17938
|
var init_formatter = __esm(() => {
|
|
17886
17939
|
init_source();
|
|
17887
17940
|
init_types2();
|
|
17941
|
+
CONSUMED_META_KEYS = [
|
|
17942
|
+
"agentName",
|
|
17943
|
+
"model",
|
|
17944
|
+
"phaseIndex",
|
|
17945
|
+
"totalPhases",
|
|
17946
|
+
"status",
|
|
17947
|
+
"findingsCount",
|
|
17948
|
+
"messageUpdates",
|
|
17949
|
+
"toolCallUpdates",
|
|
17950
|
+
"thinkingUpdates",
|
|
17951
|
+
"idleMs",
|
|
17952
|
+
"cost",
|
|
17953
|
+
"durationMs",
|
|
17954
|
+
"action",
|
|
17955
|
+
"reason"
|
|
17956
|
+
];
|
|
17888
17957
|
});
|
|
17889
17958
|
|
|
17890
17959
|
// src/logging/index.ts
|
|
@@ -17933,6 +18002,43 @@ var init_formatters = __esm(() => {
|
|
|
17933
18002
|
init_source();
|
|
17934
18003
|
});
|
|
17935
18004
|
|
|
18005
|
+
// src/logger/redact.ts
|
|
18006
|
+
function redactString(value) {
|
|
18007
|
+
let out = value;
|
|
18008
|
+
for (const re of SECRET_VALUE_PATTERNS) {
|
|
18009
|
+
re.lastIndex = 0;
|
|
18010
|
+
out = out.replace(re, REDACTED);
|
|
18011
|
+
}
|
|
18012
|
+
return out;
|
|
18013
|
+
}
|
|
18014
|
+
function redactSecrets(input) {
|
|
18015
|
+
if (typeof input === "string")
|
|
18016
|
+
return redactString(input);
|
|
18017
|
+
if (Array.isArray(input))
|
|
18018
|
+
return input.map(redactSecrets);
|
|
18019
|
+
if (input !== null && typeof input === "object") {
|
|
18020
|
+
const out = {};
|
|
18021
|
+
for (const [key, value] of Object.entries(input)) {
|
|
18022
|
+
out[key] = SECRET_KEY_PATTERN.test(key) ? REDACTED : redactSecrets(value);
|
|
18023
|
+
}
|
|
18024
|
+
return out;
|
|
18025
|
+
}
|
|
18026
|
+
return input;
|
|
18027
|
+
}
|
|
18028
|
+
var SECRET_KEY_PATTERN, SECRET_VALUE_PATTERNS, REDACTED = "[REDACTED]";
|
|
18029
|
+
var init_redact = __esm(() => {
|
|
18030
|
+
SECRET_KEY_PATTERN = /(SECRET|TOKEN|API_?KEY|PASSWORD|PRIVATE_?KEY|ACCESS_?KEY|WEBHOOK)/i;
|
|
18031
|
+
SECRET_VALUE_PATTERNS = [
|
|
18032
|
+
/sk-[A-Za-z0-9_-]{16,}/g,
|
|
18033
|
+
/ghp_[A-Za-z0-9]{16,}/g,
|
|
18034
|
+
/gh[opsu]_[A-Za-z0-9]{16,}/g,
|
|
18035
|
+
/npm_[A-Za-z0-9]{8,}/g,
|
|
18036
|
+
/AKIA[0-9A-Z]{16}/g,
|
|
18037
|
+
/xox[baprs]-[A-Za-z0-9-]{10,}/g,
|
|
18038
|
+
/(?:SECRET|TOKEN|API_?KEY|PASSWORD|PRIVATE_?KEY|ACCESS_?KEY|WEBHOOK)=[^\s"',]+/gi
|
|
18039
|
+
];
|
|
18040
|
+
});
|
|
18041
|
+
|
|
17936
18042
|
// src/logger/logger.ts
|
|
17937
18043
|
import { mkdirSync } from "fs";
|
|
17938
18044
|
import { appendFile } from "fs/promises";
|
|
@@ -18027,7 +18133,8 @@ ${JSON.stringify(entry.data, null, 2)}`;
|
|
|
18027
18133
|
writeToFile(entry) {
|
|
18028
18134
|
if (!this.filePath)
|
|
18029
18135
|
return;
|
|
18030
|
-
const
|
|
18136
|
+
const safeEntry = entry.data ? { ...entry, data: redactSecrets(entry.data) } : entry;
|
|
18137
|
+
const line = `${formatJsonl(safeEntry)}
|
|
18031
18138
|
`;
|
|
18032
18139
|
const filePath = this.filePath;
|
|
18033
18140
|
this.writeQueueTail = this.writeQueueTail.then(() => appendFile(filePath, line).catch((error48) => {
|
|
@@ -18089,6 +18196,7 @@ var LOG_LEVEL_PRIORITY, instance = null, noopLogger;
|
|
|
18089
18196
|
var init_logger = __esm(() => {
|
|
18090
18197
|
init_logging();
|
|
18091
18198
|
init_formatters();
|
|
18199
|
+
init_redact();
|
|
18092
18200
|
LOG_LEVEL_PRIORITY = {
|
|
18093
18201
|
silent: -1,
|
|
18094
18202
|
error: 0,
|
|
@@ -22551,9 +22659,16 @@ async function detectTestFramework(_workdir, language, pkg) {
|
|
|
22551
22659
|
}
|
|
22552
22660
|
return;
|
|
22553
22661
|
}
|
|
22662
|
+
function clearLanguageCache() {
|
|
22663
|
+
_languageCache.clear();
|
|
22664
|
+
}
|
|
22554
22665
|
async function detectLanguage(packageDir) {
|
|
22666
|
+
if (_languageCache.has(packageDir))
|
|
22667
|
+
return _languageCache.get(packageDir);
|
|
22555
22668
|
const pkg = await _detectorDeps.readJson(join5(packageDir, "package.json"));
|
|
22556
|
-
|
|
22669
|
+
const result = await _detectLanguageImpl(packageDir, pkg);
|
|
22670
|
+
_languageCache.set(packageDir, result);
|
|
22671
|
+
return result;
|
|
22557
22672
|
}
|
|
22558
22673
|
async function detectLintTool(workdir, language) {
|
|
22559
22674
|
if (language === "go")
|
|
@@ -22581,7 +22696,7 @@ async function detectProjectProfile(workdir, existing) {
|
|
|
22581
22696
|
const lintTool = existing.lintTool !== undefined ? existing.lintTool : await detectLintTool(workdir, language);
|
|
22582
22697
|
return { language, type, testFramework, lintTool };
|
|
22583
22698
|
}
|
|
22584
|
-
var _detectorDeps, WEB_DEPS, API_DEPS;
|
|
22699
|
+
var _detectorDeps, WEB_DEPS, API_DEPS, _languageCache;
|
|
22585
22700
|
var init_detector = __esm(() => {
|
|
22586
22701
|
_detectorDeps = {
|
|
22587
22702
|
async fileExists(path) {
|
|
@@ -22602,6 +22717,7 @@ var init_detector = __esm(() => {
|
|
|
22602
22717
|
};
|
|
22603
22718
|
WEB_DEPS = new Set(["react", "next", "vue", "nuxt"]);
|
|
22604
22719
|
API_DEPS = new Set(["express", "fastify", "hono"]);
|
|
22720
|
+
_languageCache = new Map;
|
|
22605
22721
|
});
|
|
22606
22722
|
|
|
22607
22723
|
// src/test-runners/conventions.ts
|
|
@@ -23730,7 +23846,10 @@ async function detectNaxMonoLayout(workdir) {
|
|
|
23730
23846
|
} catch {}
|
|
23731
23847
|
return dirs;
|
|
23732
23848
|
}
|
|
23733
|
-
|
|
23849
|
+
function clearWorkspaceCache() {
|
|
23850
|
+
_workspaceCache.clear();
|
|
23851
|
+
}
|
|
23852
|
+
async function discoverWorkspacePackagesUncached(workdir) {
|
|
23734
23853
|
const [fromPnpm, fromNpm, fromLerna, fromTurboNx, fromNaxMono] = await Promise.all([
|
|
23735
23854
|
detectPnpmWorkspace(workdir),
|
|
23736
23855
|
detectNpmWorkspaces(workdir),
|
|
@@ -23749,7 +23868,14 @@ async function discoverWorkspacePackages(workdir) {
|
|
|
23749
23868
|
}
|
|
23750
23869
|
return unique;
|
|
23751
23870
|
}
|
|
23752
|
-
|
|
23871
|
+
async function discoverWorkspacePackages(workdir) {
|
|
23872
|
+
if (_workspaceCache.has(workdir))
|
|
23873
|
+
return _workspaceCache.get(workdir) ?? [];
|
|
23874
|
+
const result = await discoverWorkspacePackagesUncached(workdir);
|
|
23875
|
+
_workspaceCache.set(workdir, result);
|
|
23876
|
+
return result;
|
|
23877
|
+
}
|
|
23878
|
+
var _workspaceDeps, _workspaceCache;
|
|
23753
23879
|
var init_workspace = __esm(() => {
|
|
23754
23880
|
init_logger2();
|
|
23755
23881
|
_workspaceDeps = {
|
|
@@ -23762,6 +23888,7 @@ var init_workspace = __esm(() => {
|
|
|
23762
23888
|
spawn: Bun.spawn,
|
|
23763
23889
|
glob: (pattern, cwd) => new Bun.Glob(pattern).scan({ cwd, onlyFiles: false })
|
|
23764
23890
|
};
|
|
23891
|
+
_workspaceCache = new Map;
|
|
23765
23892
|
});
|
|
23766
23893
|
|
|
23767
23894
|
// src/test-runners/detect.ts
|
|
@@ -24625,6 +24752,19 @@ var init_path_filters = __esm(() => {
|
|
|
24625
24752
|
|
|
24626
24753
|
// src/verification/smart-runner.ts
|
|
24627
24754
|
import { join as join8, relative as relative3 } from "path";
|
|
24755
|
+
function clearGitRootCache() {
|
|
24756
|
+
_gitRootCache.clear();
|
|
24757
|
+
}
|
|
24758
|
+
async function getGitRootMemo(workdir) {
|
|
24759
|
+
const cached2 = _gitRootCache.get(workdir);
|
|
24760
|
+
if (cached2 !== undefined)
|
|
24761
|
+
return cached2;
|
|
24762
|
+
const result = await _gitUtilDeps.getGitRoot(workdir);
|
|
24763
|
+
if (result !== null && result !== undefined) {
|
|
24764
|
+
_gitRootCache.set(workdir, result);
|
|
24765
|
+
}
|
|
24766
|
+
return result ?? null;
|
|
24767
|
+
}
|
|
24628
24768
|
function extractPatternSuffix(pattern) {
|
|
24629
24769
|
const lastStar = pattern.lastIndexOf("*");
|
|
24630
24770
|
if (lastStar === -1)
|
|
@@ -24644,28 +24784,28 @@ async function importGrepFallback(sourceFiles, workdir, testFilePatterns) {
|
|
|
24644
24784
|
return [];
|
|
24645
24785
|
const searchTerms = sourceFiles.flatMap(extractSearchTerms);
|
|
24646
24786
|
const testFilePaths = [];
|
|
24647
|
-
|
|
24648
|
-
const
|
|
24649
|
-
|
|
24650
|
-
|
|
24787
|
+
outer:
|
|
24788
|
+
for (const pattern of testFilePatterns) {
|
|
24789
|
+
const g = _bunDeps.glob(pattern);
|
|
24790
|
+
for await (const file3 of g.scan(workdir)) {
|
|
24791
|
+
testFilePaths.push(`${workdir}/${file3}`);
|
|
24792
|
+
if (testFilePaths.length >= MAX_GREP_TEST_FILES) {
|
|
24793
|
+
getSafeLogger()?.debug("smart-runner", "import-grep glob cap reached \u2014 results truncated", {
|
|
24794
|
+
cap: MAX_GREP_TEST_FILES
|
|
24795
|
+
});
|
|
24796
|
+
break outer;
|
|
24797
|
+
}
|
|
24798
|
+
}
|
|
24651
24799
|
}
|
|
24652
|
-
|
|
24653
|
-
const matched = [];
|
|
24654
|
-
for (const testFile of testFilePaths) {
|
|
24655
|
-
let content;
|
|
24800
|
+
const results = await Promise.all(testFilePaths.map(async (testFile) => {
|
|
24656
24801
|
try {
|
|
24657
|
-
content = await _bunDeps.file(testFile).text();
|
|
24802
|
+
const content = await _bunDeps.file(testFile).text();
|
|
24803
|
+
return searchTerms.some((t) => content.includes(t)) ? testFile : null;
|
|
24658
24804
|
} catch {
|
|
24659
|
-
|
|
24660
|
-
}
|
|
24661
|
-
for (const term of searchTerms) {
|
|
24662
|
-
if (content.includes(term)) {
|
|
24663
|
-
matched.push(testFile);
|
|
24664
|
-
break;
|
|
24665
|
-
}
|
|
24805
|
+
return null;
|
|
24666
24806
|
}
|
|
24667
|
-
}
|
|
24668
|
-
return
|
|
24807
|
+
}));
|
|
24808
|
+
return results.filter((p) => p !== null);
|
|
24669
24809
|
}
|
|
24670
24810
|
async function mapSourceToTests(sourceFiles, workdir, packagePrefix, testFilePatterns = [...DEFAULT_TEST_FILE_PATTERNS]) {
|
|
24671
24811
|
const testSuffixes = [...new Set(testFilePatterns.map(extractPatternSuffix).filter((s) => s !== null))];
|
|
@@ -24690,11 +24830,11 @@ async function mapSourceToTests(sourceFiles, workdir, packagePrefix, testFilePat
|
|
|
24690
24830
|
}
|
|
24691
24831
|
candidates.push(`${workdir}/${sourceWithoutExt}${suffix}`);
|
|
24692
24832
|
}
|
|
24693
|
-
|
|
24694
|
-
|
|
24695
|
-
|
|
24696
|
-
|
|
24697
|
-
}
|
|
24833
|
+
const existsFlags = await Promise.all(candidates.map((c) => _bunDeps.file(c).exists()));
|
|
24834
|
+
candidates.forEach((c, i) => {
|
|
24835
|
+
if (existsFlags[i])
|
|
24836
|
+
result.push(c);
|
|
24837
|
+
});
|
|
24698
24838
|
}
|
|
24699
24839
|
return result;
|
|
24700
24840
|
}
|
|
@@ -24733,7 +24873,7 @@ async function getChangedNonTestFiles(workdir, baseRef, packagePrefix, testFileR
|
|
|
24733
24873
|
const ignoreMatchers = naxIgnoreIndex?.getMatchers(packageDir) ?? await resolveNaxIgnorePatterns(effectiveRepoRoot, packageDir);
|
|
24734
24874
|
let effectivePrefix = packagePrefix;
|
|
24735
24875
|
if (packagePrefix && repoRoot) {
|
|
24736
|
-
const gitRoot = await
|
|
24876
|
+
const gitRoot = await getGitRootMemo(workdir);
|
|
24737
24877
|
const extraPrefix2 = gitRoot && gitRoot !== repoRoot ? relative3(gitRoot, repoRoot) : "";
|
|
24738
24878
|
effectivePrefix = extraPrefix2 ? `${extraPrefix2}/${packagePrefix}` : packagePrefix;
|
|
24739
24879
|
}
|
|
@@ -24760,7 +24900,7 @@ async function getChangedTestFiles(workdir, repoRoot, baseRef, packagePrefix, te
|
|
|
24760
24900
|
`).filter(Boolean);
|
|
24761
24901
|
const packageDir = packagePrefix ? join8(repoRoot, packagePrefix) : undefined;
|
|
24762
24902
|
const ignoreMatchers = naxIgnoreIndex?.getMatchers(packageDir) ?? await resolveNaxIgnorePatterns(repoRoot, packageDir);
|
|
24763
|
-
const gitRoot = await
|
|
24903
|
+
const gitRoot = await getGitRootMemo(workdir);
|
|
24764
24904
|
const extraPrefix = gitRoot && gitRoot !== repoRoot ? relative3(gitRoot, repoRoot) : "";
|
|
24765
24905
|
const effectivePrefix = packagePrefix ? extraPrefix ? `${extraPrefix}/${packagePrefix}` : packagePrefix : undefined;
|
|
24766
24906
|
const scopedRaw = effectivePrefix ? lines.filter((f) => f.startsWith(`${effectivePrefix}/`)) : lines;
|
|
@@ -24771,8 +24911,9 @@ async function getChangedTestFiles(workdir, repoRoot, baseRef, packagePrefix, te
|
|
|
24771
24911
|
return [];
|
|
24772
24912
|
}
|
|
24773
24913
|
}
|
|
24774
|
-
var _bunDeps, _gitUtilDeps, _smartRunnerDeps;
|
|
24914
|
+
var _bunDeps, MAX_GREP_TEST_FILES = 200, _gitUtilDeps, _gitRootCache, _smartRunnerDeps;
|
|
24775
24915
|
var init_smart_runner = __esm(() => {
|
|
24916
|
+
init_logger2();
|
|
24776
24917
|
init_conventions();
|
|
24777
24918
|
init_git();
|
|
24778
24919
|
init_path_filters();
|
|
@@ -24783,6 +24924,7 @@ var init_smart_runner = __esm(() => {
|
|
|
24783
24924
|
_gitUtilDeps = {
|
|
24784
24925
|
getGitRoot
|
|
24785
24926
|
};
|
|
24927
|
+
_gitRootCache = new Map;
|
|
24786
24928
|
_smartRunnerDeps = {
|
|
24787
24929
|
glob: _bunDeps.glob,
|
|
24788
24930
|
file: _bunDeps.file,
|
|
@@ -25140,31 +25282,50 @@ async function resolveSourceGlob(override, packageDir) {
|
|
|
25140
25282
|
const language = await _codeNeighborDeps.detectLanguage(packageDir);
|
|
25141
25283
|
return (language && SOURCE_GLOB_BY_LANGUAGE[language]) ?? FALLBACK_SOURCE_GLOB;
|
|
25142
25284
|
}
|
|
25143
|
-
|
|
25285
|
+
function scanDirectory(sourceGlob, workdir, ignoreMatchers, maxGlobFiles, globCtx) {
|
|
25286
|
+
const { files, truncated } = _codeNeighborDeps.glob(sourceGlob, workdir, ignoreMatchers, maxGlobFiles, globCtx);
|
|
25287
|
+
return { workdir, files, truncated };
|
|
25288
|
+
}
|
|
25289
|
+
async function readCached(absolutePath, cache) {
|
|
25290
|
+
const cached2 = cache.get(absolutePath);
|
|
25291
|
+
if (cached2 !== undefined)
|
|
25292
|
+
return cached2;
|
|
25293
|
+
try {
|
|
25294
|
+
const content = await _codeNeighborDeps.readFile(absolutePath);
|
|
25295
|
+
cache.set(absolutePath, content);
|
|
25296
|
+
return content;
|
|
25297
|
+
} catch {
|
|
25298
|
+
cache.set(absolutePath, "");
|
|
25299
|
+
return null;
|
|
25300
|
+
}
|
|
25301
|
+
}
|
|
25302
|
+
async function collectNeighbors(filePath, workdir, scannedDirs, contentCache, siblingTestContext) {
|
|
25144
25303
|
const neighbors = new Set;
|
|
25145
25304
|
let anyTruncated = false;
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25149
|
-
|
|
25150
|
-
|
|
25151
|
-
|
|
25305
|
+
const ownAbsPath = join10(workdir, filePath);
|
|
25306
|
+
if (await _codeNeighborDeps.fileExists(ownAbsPath)) {
|
|
25307
|
+
const ownContent = await readCached(ownAbsPath, contentCache);
|
|
25308
|
+
if (ownContent !== null && ownContent.length > 0) {
|
|
25309
|
+
for (const spec of parseImportSpecifiers(ownContent)) {
|
|
25310
|
+
const resolved = resolveImport(spec, filePath, workdir);
|
|
25311
|
+
if (resolved && resolved !== filePath)
|
|
25312
|
+
neighbors.add(resolved);
|
|
25313
|
+
}
|
|
25152
25314
|
}
|
|
25153
25315
|
}
|
|
25154
25316
|
const fileBaseName = (filePath.split("/").pop() ?? filePath).replace(/\.[^.]+$/, "");
|
|
25155
25317
|
const fileNoExt = filePath.replace(/\.[^.]+$/, "");
|
|
25156
|
-
|
|
25157
|
-
const { files: srcFiles, truncated }
|
|
25158
|
-
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
|
|
25162
|
-
|
|
25163
|
-
|
|
25164
|
-
|
|
25165
|
-
|
|
25166
|
-
|
|
25167
|
-
if (content.includes(fileBaseName)) {
|
|
25318
|
+
outer:
|
|
25319
|
+
for (const { workdir: scanWorkdir, files: srcFiles, truncated } of scannedDirs) {
|
|
25320
|
+
if (truncated)
|
|
25321
|
+
anyTruncated = true;
|
|
25322
|
+
for (const srcFile of srcFiles) {
|
|
25323
|
+
if (neighbors.size >= MAX_NEIGHBORS_PER_FILE)
|
|
25324
|
+
break outer;
|
|
25325
|
+
if (srcFile === filePath)
|
|
25326
|
+
continue;
|
|
25327
|
+
const content = await readCached(join10(scanWorkdir, srcFile), contentCache);
|
|
25328
|
+
if (content?.includes(fileBaseName)) {
|
|
25168
25329
|
for (const spec of parseImportSpecifiers(content)) {
|
|
25169
25330
|
const resolved = resolveImport(spec, srcFile, scanWorkdir);
|
|
25170
25331
|
if (resolved === filePath || resolved === fileNoExt) {
|
|
@@ -25173,17 +25334,8 @@ async function collectNeighbors(filePath, workdir, sourceGlob, maxGlobFiles, ext
|
|
|
25173
25334
|
}
|
|
25174
25335
|
}
|
|
25175
25336
|
}
|
|
25176
|
-
}
|
|
25177
|
-
}
|
|
25178
|
-
};
|
|
25179
|
-
await scanForReverseDeps(workdir);
|
|
25180
|
-
if (extraGlobWorkdirs) {
|
|
25181
|
-
for (const extraDir of extraGlobWorkdirs) {
|
|
25182
|
-
if (neighbors.size >= MAX_NEIGHBORS_PER_FILE)
|
|
25183
|
-
break;
|
|
25184
|
-
await scanForReverseDeps(extraDir);
|
|
25337
|
+
}
|
|
25185
25338
|
}
|
|
25186
|
-
}
|
|
25187
25339
|
if (siblingTestContext && !isTestFile2(filePath, siblingTestContext.regex)) {
|
|
25188
25340
|
const candidates = deriveSiblingTestCandidates(filePath, siblingTestContext.globs);
|
|
25189
25341
|
let chosen = null;
|
|
@@ -25246,10 +25398,17 @@ class CodeNeighborProvider {
|
|
|
25246
25398
|
const ignoreMatchers = request.naxIgnoreIndex?.getMatchers(workdir);
|
|
25247
25399
|
const sourceGlob = await resolveSourceGlob(this.sourceGlobOverride, request.packageDir);
|
|
25248
25400
|
const globCtx = { storyId: request.storyId, packageDir: request.packageDir };
|
|
25401
|
+
const scannedDirs = [scanDirectory(sourceGlob, workdir, ignoreMatchers, this.maxGlobFiles, globCtx)];
|
|
25402
|
+
if (extraGlobWorkdirs) {
|
|
25403
|
+
for (const extraDir of extraGlobWorkdirs) {
|
|
25404
|
+
scannedDirs.push(scanDirectory(sourceGlob, extraDir, ignoreMatchers, this.maxGlobFiles, globCtx));
|
|
25405
|
+
}
|
|
25406
|
+
}
|
|
25407
|
+
const contentCache = new Map;
|
|
25249
25408
|
const sections = [];
|
|
25250
25409
|
let anyTruncated = false;
|
|
25251
25410
|
for (const file3 of filesToProcess) {
|
|
25252
|
-
const { neighbors, truncated } = await collectNeighbors(file3, workdir,
|
|
25411
|
+
const { neighbors, truncated } = await collectNeighbors(file3, workdir, scannedDirs, contentCache, siblingTestContext);
|
|
25253
25412
|
if (truncated)
|
|
25254
25413
|
anyTruncated = true;
|
|
25255
25414
|
if (neighbors.length > 0) {
|
|
@@ -26167,13 +26326,25 @@ function buildPullToolDescriptors(stageToolNames, pullConfig) {
|
|
|
26167
26326
|
const allowed = pullConfig.allowedTools;
|
|
26168
26327
|
return stageToolNames.filter((name) => allowed.length === 0 || allowed.includes(name)).map((name) => PULL_TOOL_REGISTRY[name]).filter((d) => d !== undefined).map((d) => ({ ...d, maxCallsPerSession: pullConfig.maxCallsPerSession ?? d.maxCallsPerSession }));
|
|
26169
26328
|
}
|
|
26170
|
-
async function fetchWithTimeout(provider, request) {
|
|
26329
|
+
async function fetchWithTimeout(provider, request, timeoutMs = PROVIDER_FETCH_TIMEOUT_MS) {
|
|
26330
|
+
const controller = new AbortController;
|
|
26171
26331
|
let handle;
|
|
26332
|
+
let timedOut = false;
|
|
26172
26333
|
const timeout = new Promise((_, reject) => {
|
|
26173
|
-
handle = setTimeout(() =>
|
|
26334
|
+
handle = setTimeout(() => {
|
|
26335
|
+
timedOut = true;
|
|
26336
|
+
controller.abort();
|
|
26337
|
+
reject(new Error(`Provider "${provider.id}" timed out`));
|
|
26338
|
+
}, timeoutMs);
|
|
26339
|
+
});
|
|
26340
|
+
const fetchPromise = provider.fetch(request, controller.signal).then((result) => result, (err) => {
|
|
26341
|
+
if (timedOut) {
|
|
26342
|
+
return new Promise(() => {});
|
|
26343
|
+
}
|
|
26344
|
+
throw err;
|
|
26174
26345
|
});
|
|
26175
26346
|
try {
|
|
26176
|
-
return await Promise.race([
|
|
26347
|
+
return await Promise.race([fetchPromise, timeout]);
|
|
26177
26348
|
} finally {
|
|
26178
26349
|
clearTimeout(handle);
|
|
26179
26350
|
}
|
|
@@ -26812,12 +26983,7 @@ class GitHistoryProvider {
|
|
|
26812
26983
|
return { chunks: [], pullTools: [] };
|
|
26813
26984
|
}
|
|
26814
26985
|
const filesToProcess = touchedFiles.filter(isRelativeAndSafe).slice(0, MAX_FILES2);
|
|
26815
|
-
const sections =
|
|
26816
|
-
for (const file3 of filesToProcess) {
|
|
26817
|
-
const section = await fetchFileHistory(file3, workdir);
|
|
26818
|
-
if (section)
|
|
26819
|
-
sections.push(section);
|
|
26820
|
-
}
|
|
26986
|
+
const sections = (await Promise.all(filesToProcess.map((file3) => fetchFileHistory(file3, workdir)))).filter((section) => section !== null);
|
|
26821
26987
|
if (sections.length === 0) {
|
|
26822
26988
|
return { chunks: [], pullTools: [] };
|
|
26823
26989
|
}
|
|
@@ -33277,20 +33443,23 @@ function createDrainDeadline(deadlineMs) {
|
|
|
33277
33443
|
};
|
|
33278
33444
|
}
|
|
33279
33445
|
async function runQualityCommand(opts) {
|
|
33280
|
-
const { commandName, command, workdir, storyId, timeoutMs = DEFAULT_TIMEOUT_MS, env: env2 } = opts;
|
|
33446
|
+
const { commandName, command, workdir, storyId, timeoutMs = DEFAULT_TIMEOUT_MS, env: env2, stripEnvVars } = opts;
|
|
33281
33447
|
const startTime = Date.now();
|
|
33282
33448
|
const logger = getSafeLogger();
|
|
33283
33449
|
logger?.info("quality", `Running ${commandName}`, { storyId, commandName, command, workdir });
|
|
33284
33450
|
try {
|
|
33451
|
+
const baseEnv = {
|
|
33452
|
+
...process.env
|
|
33453
|
+
};
|
|
33454
|
+
for (const key of stripEnvVars ?? []) {
|
|
33455
|
+
delete baseEnv[key];
|
|
33456
|
+
}
|
|
33285
33457
|
const proc = _qualityRunnerDeps.spawn({
|
|
33286
33458
|
cmd: ["/bin/sh", "-c", command],
|
|
33287
33459
|
cwd: workdir,
|
|
33288
33460
|
stdout: "pipe",
|
|
33289
33461
|
stderr: "pipe",
|
|
33290
|
-
env: {
|
|
33291
|
-
...process.env,
|
|
33292
|
-
...env2 ?? {}
|
|
33293
|
-
}
|
|
33462
|
+
env: { ...baseEnv, ...env2 ?? {} }
|
|
33294
33463
|
});
|
|
33295
33464
|
let timedOut = false;
|
|
33296
33465
|
let exitedBeforeSigkill = false;
|
|
@@ -36870,7 +37039,7 @@ function buildVerifierFindings(verdict, categorization) {
|
|
|
36870
37039
|
return [];
|
|
36871
37040
|
}
|
|
36872
37041
|
}
|
|
36873
|
-
function parseVerdictFromStdout(output,
|
|
37042
|
+
function parseVerdictFromStdout(output, input, _ctx) {
|
|
36874
37043
|
if (!output || !output.trim()) {
|
|
36875
37044
|
throw new ParseValidationError("verifier produced no stdout");
|
|
36876
37045
|
}
|
|
@@ -36883,6 +37052,18 @@ function parseVerdictFromStdout(output, _input, _ctx) {
|
|
|
36883
37052
|
throw new ParseValidationError("verifier stdout JSON missing required VerifierVerdict fields");
|
|
36884
37053
|
}
|
|
36885
37054
|
const categorization = categorizeVerdict(verdict, verdict.tests.allPassing === true);
|
|
37055
|
+
getSafeLogger()?.info("verifier", "Verdict categorized", {
|
|
37056
|
+
storyId: input.story.id,
|
|
37057
|
+
approved: verdict.approved,
|
|
37058
|
+
success: categorization.success,
|
|
37059
|
+
advisoryOverride: verdict.approved === false && categorization.success,
|
|
37060
|
+
testsPassing: verdict.tests.allPassing,
|
|
37061
|
+
passCount: verdict.tests.passCount,
|
|
37062
|
+
failCount: verdict.tests.failCount,
|
|
37063
|
+
testModsDetected: verdict.testModifications.detected,
|
|
37064
|
+
testModsLegitimate: verdict.testModifications.legitimate,
|
|
37065
|
+
...categorization.failureCategory && { failureCategory: categorization.failureCategory }
|
|
37066
|
+
});
|
|
36886
37067
|
return {
|
|
36887
37068
|
success: categorization.success,
|
|
36888
37069
|
filesChanged: [],
|
|
@@ -38235,7 +38416,8 @@ var init_mechanical_lintfix_strategy = __esm(() => {
|
|
|
38235
38416
|
commandName: "lintFix",
|
|
38236
38417
|
command,
|
|
38237
38418
|
workdir: input.workdir,
|
|
38238
|
-
storyId: input.storyId
|
|
38419
|
+
storyId: input.storyId,
|
|
38420
|
+
stripEnvVars: ctxConfig?.quality?.stripEnvVars ?? []
|
|
38239
38421
|
});
|
|
38240
38422
|
return { applied: true, exitCode: result.exitCode };
|
|
38241
38423
|
}
|
|
@@ -38293,7 +38475,8 @@ var init_mechanical_formatfix_strategy = __esm(() => {
|
|
|
38293
38475
|
commandName: "formatFix",
|
|
38294
38476
|
command,
|
|
38295
38477
|
workdir: input.workdir,
|
|
38296
|
-
storyId: input.storyId
|
|
38478
|
+
storyId: input.storyId,
|
|
38479
|
+
stripEnvVars: ctxConfig?.quality?.stripEnvVars ?? []
|
|
38297
38480
|
});
|
|
38298
38481
|
return { applied: true, exitCode: result.exitCode };
|
|
38299
38482
|
}
|
|
@@ -38326,7 +38509,8 @@ var init_lint_check = __esm(() => {
|
|
|
38326
38509
|
commandName: "lint",
|
|
38327
38510
|
command: command ?? "",
|
|
38328
38511
|
workdir: input.workdir,
|
|
38329
|
-
storyId: input.storyId
|
|
38512
|
+
storyId: input.storyId,
|
|
38513
|
+
stripEnvVars: ctxConfig?.quality?.stripEnvVars ?? []
|
|
38330
38514
|
});
|
|
38331
38515
|
if (result.exitCode === 0) {
|
|
38332
38516
|
return { success: true, findings: [], durationMs: Date.now() - start };
|
|
@@ -38575,7 +38759,8 @@ var init_typecheck_check = __esm(() => {
|
|
|
38575
38759
|
commandName: "typecheck",
|
|
38576
38760
|
command: command ?? "",
|
|
38577
38761
|
workdir: input.workdir,
|
|
38578
|
-
storyId: input.storyId
|
|
38762
|
+
storyId: input.storyId,
|
|
38763
|
+
stripEnvVars: ctxConfig?.quality?.stripEnvVars ?? []
|
|
38579
38764
|
});
|
|
38580
38765
|
if (result.exitCode === 0) {
|
|
38581
38766
|
return { success: true, findings: [], durationMs: Date.now() - start };
|
|
@@ -39550,13 +39735,14 @@ async function resolveLintScope(args) {
|
|
|
39550
39735
|
function resolveScopedTemplate(reviewCommands, qualityCommands) {
|
|
39551
39736
|
return reviewCommands.lintScoped ?? qualityCommands?.lintScoped;
|
|
39552
39737
|
}
|
|
39553
|
-
async function runLintCommand(workdir, storyId, env2, command) {
|
|
39738
|
+
async function runLintCommand(workdir, storyId, env2, command, stripEnvVars) {
|
|
39554
39739
|
return runQualityCommand({
|
|
39555
39740
|
commandName: SCOPED_LINT_CHECK,
|
|
39556
39741
|
command,
|
|
39557
39742
|
workdir,
|
|
39558
39743
|
storyId,
|
|
39559
|
-
env: env2
|
|
39744
|
+
env: env2,
|
|
39745
|
+
stripEnvVars
|
|
39560
39746
|
});
|
|
39561
39747
|
}
|
|
39562
39748
|
function toReviewCheck(result) {
|
|
@@ -39597,7 +39783,7 @@ async function runScopedLintCheck(args) {
|
|
|
39597
39783
|
storyId: args.storyId,
|
|
39598
39784
|
reason: scope.degradedReason
|
|
39599
39785
|
});
|
|
39600
|
-
const fullResult2 = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, fullLintCommand);
|
|
39786
|
+
const fullResult2 = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, fullLintCommand, args.stripEnvVars);
|
|
39601
39787
|
return withLintScope(attachLintFindings(toReviewCheck(fullResult2), args.lintOutputFormat, args.workdir), scope, "degraded");
|
|
39602
39788
|
}
|
|
39603
39789
|
logger?.info("review", "lint_scope_empty", { storyId: args.storyId });
|
|
@@ -39622,19 +39808,19 @@ async function runScopedLintCheck(args) {
|
|
|
39622
39808
|
}
|
|
39623
39809
|
if (scopedTemplate) {
|
|
39624
39810
|
const scopedCommand = scopedTemplate.replaceAll("{{files}}", scope.files.map(shellQuotePath4).join(" "));
|
|
39625
|
-
const scopedResult = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, scopedCommand);
|
|
39811
|
+
const scopedResult = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, scopedCommand, args.stripEnvVars);
|
|
39626
39812
|
return withLintScope(attachLintFindings(toReviewCheck(scopedResult), args.lintOutputFormat, args.workdir), scope);
|
|
39627
39813
|
}
|
|
39628
39814
|
if (!scope.degradedReason && isSupportedDerivedScopedCommand(fullLintCommand)) {
|
|
39629
39815
|
const scopedCommand = appendFilesToCommand(fullLintCommand, scope.files);
|
|
39630
|
-
const scopedResult = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, scopedCommand);
|
|
39816
|
+
const scopedResult = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, scopedCommand, args.stripEnvVars);
|
|
39631
39817
|
return withLintScope(attachLintFindings(toReviewCheck(scopedResult), args.lintOutputFormat, args.workdir), scope);
|
|
39632
39818
|
}
|
|
39633
39819
|
logger?.warn("review", "lint_scope_degraded", {
|
|
39634
39820
|
storyId: args.storyId,
|
|
39635
39821
|
reason: scope.degradedReason ?? "unsupported_scoped_command_shape"
|
|
39636
39822
|
});
|
|
39637
|
-
const fullResult = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, fullLintCommand);
|
|
39823
|
+
const fullResult = await _scopedLintDeps.runLintCommand(args.workdir, args.storyId, args.env, fullLintCommand, args.stripEnvVars);
|
|
39638
39824
|
if (fullResult.exitCode === 0)
|
|
39639
39825
|
return withLintScope(toReviewCheck(fullResult), scope, "degraded");
|
|
39640
39826
|
const parsed = parseLintOutput(fullResult.output, args.lintOutputFormat ?? "auto", {
|
|
@@ -40360,8 +40546,8 @@ async function resolveCommand(check2, config2, executionConfig, workdir, quality
|
|
|
40360
40546
|
}
|
|
40361
40547
|
return null;
|
|
40362
40548
|
}
|
|
40363
|
-
async function runCheck(check2, command, workdir, storyId, env2) {
|
|
40364
|
-
const result = await runQualityCommand({ commandName: check2, command, workdir, storyId, env: env2 });
|
|
40549
|
+
async function runCheck(check2, command, workdir, storyId, env2, stripEnvVars) {
|
|
40550
|
+
const result = await runQualityCommand({ commandName: check2, command, workdir, storyId, env: env2, stripEnvVars });
|
|
40365
40551
|
return {
|
|
40366
40552
|
check: check2,
|
|
40367
40553
|
command: result.command,
|
|
@@ -40567,8 +40753,9 @@ async function runReview(opts) {
|
|
|
40567
40753
|
story,
|
|
40568
40754
|
storyGitRef,
|
|
40569
40755
|
env: env2,
|
|
40756
|
+
stripEnvVars: naxConfig?.quality?.stripEnvVars ?? [],
|
|
40570
40757
|
naxIgnoreIndex
|
|
40571
|
-
}) : normalizeMechanicalFindings(checkName, await runCheck(checkName, command, workdir, storyId, env2), workdir);
|
|
40758
|
+
}) : normalizeMechanicalFindings(checkName, await runCheck(checkName, command, workdir, storyId, env2, naxConfig?.quality?.stripEnvVars ?? []), workdir);
|
|
40572
40759
|
checks3.push(result);
|
|
40573
40760
|
if (result.success) {
|
|
40574
40761
|
logger?.info("review", `${checkName} passed`, {
|
|
@@ -43916,13 +44103,13 @@ var init_factory = __esm(() => {
|
|
|
43916
44103
|
|
|
43917
44104
|
// src/execution/pid-registry.ts
|
|
43918
44105
|
import { existsSync as existsSync7 } from "fs";
|
|
43919
|
-
import { appendFile as appendFile2 } from "fs/promises";
|
|
43920
44106
|
|
|
43921
44107
|
class PidRegistry {
|
|
43922
44108
|
workdir;
|
|
43923
44109
|
pidsFilePath;
|
|
43924
44110
|
pids = new Set;
|
|
43925
44111
|
frozen = false;
|
|
44112
|
+
writeQueueTail = Promise.resolve();
|
|
43926
44113
|
constructor(workdir, _platform) {
|
|
43927
44114
|
this.workdir = workdir;
|
|
43928
44115
|
this.pidsFilePath = `${workdir}/${PID_REGISTRY_FILE}`;
|
|
@@ -43943,15 +44130,8 @@ class PidRegistry {
|
|
|
43943
44130
|
return;
|
|
43944
44131
|
}
|
|
43945
44132
|
this.pids.add(pid);
|
|
43946
|
-
const entry = {
|
|
43947
|
-
pid,
|
|
43948
|
-
spawnedAt: new Date().toISOString(),
|
|
43949
|
-
workdir: this.workdir
|
|
43950
|
-
};
|
|
43951
44133
|
try {
|
|
43952
|
-
|
|
43953
|
-
`;
|
|
43954
|
-
await appendFile2(this.pidsFilePath, line);
|
|
44134
|
+
await this.enqueueWrite();
|
|
43955
44135
|
logger?.debug("pid-registry", `Registered PID ${pid}`, { pid });
|
|
43956
44136
|
} catch (err) {
|
|
43957
44137
|
logger?.warn("pid-registry", `Failed to write PID ${pid} to registry`, {
|
|
@@ -43963,7 +44143,7 @@ class PidRegistry {
|
|
|
43963
44143
|
const logger = getSafeLogger();
|
|
43964
44144
|
this.pids.delete(pid);
|
|
43965
44145
|
try {
|
|
43966
|
-
await this.
|
|
44146
|
+
await this.enqueueWrite();
|
|
43967
44147
|
logger?.debug("pid-registry", `Unregistered PID ${pid}`, { pid });
|
|
43968
44148
|
} catch (err) {
|
|
43969
44149
|
logger?.warn("pid-registry", `Failed to unregister PID ${pid}`, {
|
|
@@ -43982,8 +44162,8 @@ class PidRegistry {
|
|
|
43982
44162
|
const killPromises = pids.map((pid) => this.killPidTree(pid));
|
|
43983
44163
|
await Promise.allSettled(killPromises);
|
|
43984
44164
|
try {
|
|
43985
|
-
await Bun.write(this.pidsFilePath, "");
|
|
43986
44165
|
this.pids.clear();
|
|
44166
|
+
await this.enqueueWrite();
|
|
43987
44167
|
logger?.info("pid-registry", "All registered PIDs killed and registry cleared");
|
|
43988
44168
|
} catch (err) {
|
|
43989
44169
|
logger?.warn("pid-registry", "Failed to clear registry file", {
|
|
@@ -44202,6 +44382,37 @@ class PidRegistry {
|
|
|
44202
44382
|
getPids() {
|
|
44203
44383
|
return Array.from(this.pids);
|
|
44204
44384
|
}
|
|
44385
|
+
snapshot() {
|
|
44386
|
+
return Array.from(this.pids);
|
|
44387
|
+
}
|
|
44388
|
+
async flush() {
|
|
44389
|
+
await this.writeQueueTail;
|
|
44390
|
+
}
|
|
44391
|
+
async readPidsFromDisk() {
|
|
44392
|
+
try {
|
|
44393
|
+
if (!existsSync7(this.pidsFilePath))
|
|
44394
|
+
return [];
|
|
44395
|
+
const content = await Bun.file(this.pidsFilePath).text();
|
|
44396
|
+
return content.split(`
|
|
44397
|
+
`).filter((line) => line.trim()).map((line) => {
|
|
44398
|
+
try {
|
|
44399
|
+
return JSON.parse(line).pid;
|
|
44400
|
+
} catch {
|
|
44401
|
+
return null;
|
|
44402
|
+
}
|
|
44403
|
+
}).filter((pid) => pid !== null);
|
|
44404
|
+
} catch {
|
|
44405
|
+
return [];
|
|
44406
|
+
}
|
|
44407
|
+
}
|
|
44408
|
+
enqueueWrite() {
|
|
44409
|
+
this.writeQueueTail = this.writeQueueTail.then(() => this.writePidsFile().catch((err) => {
|
|
44410
|
+
getSafeLogger()?.warn("pid-registry", "Failed to flush PID file \u2014 on-disk registry may be stale", {
|
|
44411
|
+
error: errorMessage(err)
|
|
44412
|
+
});
|
|
44413
|
+
}));
|
|
44414
|
+
return this.writeQueueTail;
|
|
44415
|
+
}
|
|
44205
44416
|
}
|
|
44206
44417
|
var PID_REGISTRY_FILE = ".nax-pids", PID_TREE_KILL_GRACE_MS = 250, _pidRegistryDeps;
|
|
44207
44418
|
var init_pid_registry = __esm(() => {
|
|
@@ -52048,7 +52259,7 @@ var init_effectiveness = __esm(() => {
|
|
|
52048
52259
|
});
|
|
52049
52260
|
|
|
52050
52261
|
// src/execution/progress.ts
|
|
52051
|
-
import { appendFile as
|
|
52262
|
+
import { appendFile as appendFile2, mkdir as mkdir7 } from "fs/promises";
|
|
52052
52263
|
import { join as join44 } from "path";
|
|
52053
52264
|
async function appendProgress(featureDir, storyId, status, message) {
|
|
52054
52265
|
await mkdir7(featureDir, { recursive: true });
|
|
@@ -52056,7 +52267,7 @@ async function appendProgress(featureDir, storyId, status, message) {
|
|
|
52056
52267
|
const timestamp = new Date().toISOString();
|
|
52057
52268
|
const entry = `[${timestamp}] ${storyId} \u2014 ${status.toUpperCase()} \u2014 ${message}
|
|
52058
52269
|
`;
|
|
52059
|
-
await
|
|
52270
|
+
await appendFile2(progressPath, entry);
|
|
52060
52271
|
}
|
|
52061
52272
|
var init_progress = () => {};
|
|
52062
52273
|
|
|
@@ -52163,6 +52374,7 @@ var init_completion = __esm(() => {
|
|
|
52163
52374
|
const logger = getLogger();
|
|
52164
52375
|
const isBatch = ctx.stories.length > 1;
|
|
52165
52376
|
const sessionCost = ctx.agentResult?.estimatedCostUsd || 0;
|
|
52377
|
+
const persistPrd = ctx.skipPrdPersistence !== true;
|
|
52166
52378
|
const prdPath = ctx.prdPath ?? (ctx.featureDir ? `${ctx.featureDir}/prd.json` : `${ctx.workdir}/nax/features/unknown/prd.json`);
|
|
52167
52379
|
const storyStartTime = ctx.storyStartTime || new Date().toISOString();
|
|
52168
52380
|
if (isBatch) {
|
|
@@ -52187,7 +52399,9 @@ var init_completion = __esm(() => {
|
|
|
52187
52399
|
}
|
|
52188
52400
|
}
|
|
52189
52401
|
for (const completedStory of ctx.stories) {
|
|
52190
|
-
|
|
52402
|
+
if (persistPrd) {
|
|
52403
|
+
markStoryPassed(ctx.prd, completedStory.id);
|
|
52404
|
+
}
|
|
52191
52405
|
const costPerStory = sessionCost / ctx.stories.length;
|
|
52192
52406
|
logger.info("completion", "Story passed", {
|
|
52193
52407
|
storyId: completedStory.id,
|
|
@@ -52219,7 +52433,9 @@ var init_completion = __esm(() => {
|
|
|
52219
52433
|
}
|
|
52220
52434
|
}
|
|
52221
52435
|
}
|
|
52222
|
-
|
|
52436
|
+
if (persistPrd) {
|
|
52437
|
+
await _completionDeps.savePRD(ctx.prd, prdPath);
|
|
52438
|
+
}
|
|
52223
52439
|
const updatedCounts = countStories(ctx.prd);
|
|
52224
52440
|
logger.info("completion", "Progress update", {
|
|
52225
52441
|
storyId: ctx.story.id,
|
|
@@ -53022,7 +53238,7 @@ function buildPhaseOutcomeLogData(storyId, opName, output, durationMs) {
|
|
|
53022
53238
|
data.reviewReason = r.reviewReason;
|
|
53023
53239
|
return { success: success2, data };
|
|
53024
53240
|
}
|
|
53025
|
-
function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTddPhase, stage) {
|
|
53241
|
+
function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTddPhase, stage, progressData = {}) {
|
|
53026
53242
|
if (isTddPhase)
|
|
53027
53243
|
return;
|
|
53028
53244
|
if (opName === "semantic-review" || opName === "adversarial-review")
|
|
@@ -53030,7 +53246,8 @@ function logDeterministicPhaseOutcome(storyId, opName, output, durationMs, isTdd
|
|
|
53030
53246
|
const built = buildPhaseOutcomeLogData(storyId, opName, output, durationMs);
|
|
53031
53247
|
if (!built)
|
|
53032
53248
|
return;
|
|
53033
|
-
const { success: success2
|
|
53249
|
+
const { success: success2 } = built;
|
|
53250
|
+
const data = { ...built.data, ...progressData };
|
|
53034
53251
|
const logger = getSafeLogger();
|
|
53035
53252
|
const message = formatPhaseResultMessage(opName, success2, stage);
|
|
53036
53253
|
if (stage === "rectification") {
|
|
@@ -53093,17 +53310,21 @@ function logUnifiedReviewPhaseResult(storyId, opName, output) {
|
|
|
53093
53310
|
truncated: findingsCount > findingsSummary.length
|
|
53094
53311
|
});
|
|
53095
53312
|
}
|
|
53096
|
-
async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = false) {
|
|
53313
|
+
async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = false, progress) {
|
|
53097
53314
|
const logger = getSafeLogger();
|
|
53098
53315
|
const opName = slot.op.name;
|
|
53316
|
+
const progressData = progress ? { phaseIndex: progress.index, totalPhases: progress.total } : {};
|
|
53099
53317
|
const isTddPhase = isThreeSession && TDD_OP_NAMES.has(opName);
|
|
53100
53318
|
const beforeRef = isTddPhase ? await _storyOrchestratorDeps.captureGitRef(ctx.packageDir) : undefined;
|
|
53101
53319
|
let dispatchInput = isTddPhase && beforeRef ? { ...slot.input, beforeRef } : slot.input;
|
|
53102
53320
|
dispatchInput = await refreshReviewInputForDispatch(opName, dispatchInput);
|
|
53103
53321
|
if (isTddPhase) {
|
|
53104
|
-
logger?.info("tdd", `-> Session: ${opName}`, { storyId: ctx.storyId, role: opName });
|
|
53322
|
+
logger?.info("tdd", `-> Session: ${opName}`, { storyId: ctx.storyId, role: opName, ...progressData });
|
|
53105
53323
|
} else if (isThreeSession && opName === "full-suite-gate") {
|
|
53106
|
-
logger?.info("tdd", "-> Running full test suite gate (before Verifier)", {
|
|
53324
|
+
logger?.info("tdd", "-> Running full test suite gate (before Verifier)", {
|
|
53325
|
+
storyId: ctx.storyId,
|
|
53326
|
+
...progressData
|
|
53327
|
+
});
|
|
53107
53328
|
}
|
|
53108
53329
|
logUnifiedReviewPhaseStart(ctx.storyId, opName);
|
|
53109
53330
|
const phaseStartedAt = Date.now();
|
|
@@ -53113,7 +53334,7 @@ async function runPhase(ctx, slot, phaseCosts, phaseOutputs, isThreeSession = fa
|
|
|
53113
53334
|
phaseOutputs[opName] = output;
|
|
53114
53335
|
emitReviewDecision(ctx, opName, output);
|
|
53115
53336
|
logUnifiedReviewPhaseResult(ctx.storyId, opName, output);
|
|
53116
|
-
logDeterministicPhaseOutcome(ctx.storyId, opName, output, Date.now() - phaseStartedAt, isTddPhase, slot.op.stage);
|
|
53337
|
+
logDeterministicPhaseOutcome(ctx.storyId, opName, output, Date.now() - phaseStartedAt, isTddPhase, slot.op.stage, progressData);
|
|
53117
53338
|
if (isTddPhase) {
|
|
53118
53339
|
const durationMs = Date.now() - phaseStartedAt;
|
|
53119
53340
|
logger?.info("tdd", `Session complete: ${opName}`, {
|
|
@@ -53282,9 +53503,13 @@ class ExecutionPlan {
|
|
|
53282
53503
|
const phaseOutputs = {};
|
|
53283
53504
|
const startedAt = Date.now();
|
|
53284
53505
|
const logger = getSafeLogger();
|
|
53285
|
-
|
|
53506
|
+
const orderedPhases = collectOrderedPhases(this.state);
|
|
53507
|
+
for (const [phaseIndex, phase] of orderedPhases.entries()) {
|
|
53286
53508
|
try {
|
|
53287
|
-
await runPhase(this.ctx, phase.slot, phaseCosts, phaseOutputs, this.isThreeSession
|
|
53509
|
+
await runPhase(this.ctx, phase.slot, phaseCosts, phaseOutputs, this.isThreeSession, {
|
|
53510
|
+
index: phaseIndex + 1,
|
|
53511
|
+
total: orderedPhases.length
|
|
53512
|
+
});
|
|
53288
53513
|
} catch (error48) {
|
|
53289
53514
|
logger?.error("story-orchestrator", "Phase threw unexpected error", {
|
|
53290
53515
|
storyId: this.ctx.storyId,
|
|
@@ -56949,7 +57174,7 @@ function renderProposals(proposals, runId, observationCount) {
|
|
|
56949
57174
|
}
|
|
56950
57175
|
|
|
56951
57176
|
// src/plugins/builtin/curator/rollup.ts
|
|
56952
|
-
import { appendFile as
|
|
57177
|
+
import { appendFile as appendFile3, mkdir as mkdir10, writeFile } from "fs/promises";
|
|
56953
57178
|
import * as path14 from "path";
|
|
56954
57179
|
async function appendToRollup(observations, rollupPath) {
|
|
56955
57180
|
try {
|
|
@@ -56965,7 +57190,7 @@ async function appendToRollup(observations, rollupPath) {
|
|
|
56965
57190
|
const newLines = `${observations.map((o) => JSON.stringify(o)).join(`
|
|
56966
57191
|
`)}
|
|
56967
57192
|
`;
|
|
56968
|
-
await
|
|
57193
|
+
await appendFile3(rollupPath, newLines);
|
|
56969
57194
|
} catch {}
|
|
56970
57195
|
}
|
|
56971
57196
|
var init_rollup = () => {};
|
|
@@ -57883,7 +58108,7 @@ var package_default;
|
|
|
57883
58108
|
var init_package = __esm(() => {
|
|
57884
58109
|
package_default = {
|
|
57885
58110
|
name: "@nathapp/nax",
|
|
57886
|
-
version: "0.68.
|
|
58111
|
+
version: "0.68.2",
|
|
57887
58112
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
57888
58113
|
type: "module",
|
|
57889
58114
|
bin: {
|
|
@@ -57978,8 +58203,8 @@ var init_version = __esm(() => {
|
|
|
57978
58203
|
NAX_VERSION = package_default.version;
|
|
57979
58204
|
NAX_COMMIT = (() => {
|
|
57980
58205
|
try {
|
|
57981
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
57982
|
-
return "
|
|
58206
|
+
if (/^[0-9a-f]{6,10}$/.test("27a81a5e"))
|
|
58207
|
+
return "27a81a5e";
|
|
57983
58208
|
} catch {}
|
|
57984
58209
|
try {
|
|
57985
58210
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|
|
@@ -59395,6 +59620,9 @@ async function handleRunCompletion(options) {
|
|
|
59395
59620
|
if (options.pluginProviderCache) {
|
|
59396
59621
|
await options.pluginProviderCache.disposeAll();
|
|
59397
59622
|
}
|
|
59623
|
+
clearLanguageCache();
|
|
59624
|
+
clearWorkspaceCache();
|
|
59625
|
+
clearGitRootCache();
|
|
59398
59626
|
const finalCounts = countStories(prd);
|
|
59399
59627
|
const fallbackAggregate = deriveRunFallbackAggregates(allStoryMetrics);
|
|
59400
59628
|
pipelineEventBus.emit({
|
|
@@ -59500,7 +59728,10 @@ var init_run_completion = __esm(() => {
|
|
|
59500
59728
|
init_metrics();
|
|
59501
59729
|
init_event_bus();
|
|
59502
59730
|
init_prd();
|
|
59731
|
+
init_detector();
|
|
59503
59732
|
init_scratch_purge();
|
|
59733
|
+
init_workspace();
|
|
59734
|
+
init_smart_runner();
|
|
59504
59735
|
init_run_regression();
|
|
59505
59736
|
_runCompletionDeps = {
|
|
59506
59737
|
runDeferredRegression,
|
|
@@ -59598,7 +59829,7 @@ function precomputeBatchPlan(stories, maxBatchSize = DEFAULT_MAX_BATCH_SIZE) {
|
|
|
59598
59829
|
var DEFAULT_MAX_BATCH_SIZE = 4;
|
|
59599
59830
|
|
|
59600
59831
|
// src/pipeline/subscribers/events-writer.ts
|
|
59601
|
-
import { appendFile as
|
|
59832
|
+
import { appendFile as appendFile4, mkdir as mkdir14 } from "fs/promises";
|
|
59602
59833
|
import { basename as basename14, join as join73 } from "path";
|
|
59603
59834
|
function wireEventsWriter(bus, feature, runId, workdir) {
|
|
59604
59835
|
const logger = getSafeLogger();
|
|
@@ -59613,7 +59844,7 @@ function wireEventsWriter(bus, feature, runId, workdir) {
|
|
|
59613
59844
|
await mkdir14(eventsDir, { recursive: true });
|
|
59614
59845
|
dirReady = true;
|
|
59615
59846
|
}
|
|
59616
|
-
await
|
|
59847
|
+
await appendFile4(eventsFile, `${JSON.stringify(line)}
|
|
59617
59848
|
`);
|
|
59618
59849
|
} catch (err) {
|
|
59619
59850
|
logger?.warn("events-writer", "Failed to write event line (non-fatal)", {
|
|
@@ -61510,9 +61741,13 @@ var exports_parallel_worker = {};
|
|
|
61510
61741
|
__export(exports_parallel_worker, {
|
|
61511
61742
|
executeStoryInWorktree: () => executeStoryInWorktree,
|
|
61512
61743
|
executeParallelBatch: () => executeParallelBatch,
|
|
61744
|
+
buildWorktreePipelineContext: () => buildWorktreePipelineContext,
|
|
61513
61745
|
_parallelWorkerDeps: () => _parallelWorkerDeps
|
|
61514
61746
|
});
|
|
61515
61747
|
import { join as join79 } from "path";
|
|
61748
|
+
function buildWorktreePipelineContext(base, _story) {
|
|
61749
|
+
return { ...base, prd: structuredClone(base.prd) };
|
|
61750
|
+
}
|
|
61516
61751
|
async function executeStoryInWorktree(story, worktreePath, dependencyContext, context, routing, eventEmitter) {
|
|
61517
61752
|
const logger = getSafeLogger();
|
|
61518
61753
|
try {
|
|
@@ -61526,7 +61761,7 @@ async function executeStoryInWorktree(story, worktreePath, dependencyContext, co
|
|
|
61526
61761
|
}
|
|
61527
61762
|
}
|
|
61528
61763
|
const pipelineContext = {
|
|
61529
|
-
...context,
|
|
61764
|
+
...buildWorktreePipelineContext(context, story),
|
|
61530
61765
|
config: context.config,
|
|
61531
61766
|
rootConfig: context.rootConfig,
|
|
61532
61767
|
story,
|
|
@@ -61826,6 +62061,7 @@ var init_parallel_batch = __esm(() => {
|
|
|
61826
62061
|
// src/execution/unified-executor.ts
|
|
61827
62062
|
var exports_unified_executor = {};
|
|
61828
62063
|
__export(exports_unified_executor, {
|
|
62064
|
+
reconcileBatchOutcome: () => reconcileBatchOutcome,
|
|
61829
62065
|
executeUnified: () => executeUnified,
|
|
61830
62066
|
_unifiedExecutorDeps: () => _unifiedExecutorDeps
|
|
61831
62067
|
});
|
|
@@ -61949,7 +62185,10 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
61949
62185
|
const readyStories = getAllReadyStories(prd);
|
|
61950
62186
|
const batch = _unifiedExecutorDeps.selectIndependentBatch(readyStories, ctx.parallelCount);
|
|
61951
62187
|
if (batch.length > 1) {
|
|
61952
|
-
|
|
62188
|
+
const batchAgent = ctx.agentManager?.getDefault() ?? resolveDefaultAgent(ctx.config);
|
|
62189
|
+
const batchCounts = countStories(prd);
|
|
62190
|
+
const batchBaseDone = batchCounts.total - batchCounts.pending;
|
|
62191
|
+
for (const [batchIndex, story] of batch.entries()) {
|
|
61953
62192
|
const modelTier2 = story.routing?.modelTier ?? ctx.config.autoMode.complexityRouting?.[story.routing?.complexity ?? "medium"] ?? "balanced";
|
|
61954
62193
|
pipelineEventBus.emit({
|
|
61955
62194
|
type: "story:started",
|
|
@@ -61957,7 +62196,7 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
61957
62196
|
story: { id: story.id, title: story.title, status: story.status, attempts: story.attempts },
|
|
61958
62197
|
workdir: ctx.workdir,
|
|
61959
62198
|
modelTier: modelTier2,
|
|
61960
|
-
agent:
|
|
62199
|
+
agent: batchAgent,
|
|
61961
62200
|
iteration: iterations
|
|
61962
62201
|
});
|
|
61963
62202
|
logger?.info("story.start", `${story.title}`, {
|
|
@@ -61965,6 +62204,9 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
61965
62204
|
storyTitle: story.title,
|
|
61966
62205
|
complexity: story.routing?.complexity ?? "unknown",
|
|
61967
62206
|
modelTier: modelTier2,
|
|
62207
|
+
agent: batchAgent,
|
|
62208
|
+
storyNumber: batchBaseDone + batchIndex + 1,
|
|
62209
|
+
storyTotal: batchCounts.total,
|
|
61968
62210
|
attempt: story.attempts + 1
|
|
61969
62211
|
});
|
|
61970
62212
|
}
|
|
@@ -61984,6 +62226,7 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
61984
62226
|
config: ctx.config,
|
|
61985
62227
|
rootConfig: ctx.config,
|
|
61986
62228
|
prd,
|
|
62229
|
+
skipPrdPersistence: true,
|
|
61987
62230
|
projectDir: ctx.workdir,
|
|
61988
62231
|
naxIgnoreIndex,
|
|
61989
62232
|
hooks: ctx.hooks,
|
|
@@ -62031,6 +62274,8 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62031
62274
|
abortSignal: ctx.abortSignal
|
|
62032
62275
|
}, pipelineResult);
|
|
62033
62276
|
}
|
|
62277
|
+
reconcileBatchOutcome(prd, batchResult);
|
|
62278
|
+
await savePRD(prd, ctx.prdPath);
|
|
62034
62279
|
await pipelineEventBus.drain();
|
|
62035
62280
|
totalCost += batchResult.totalCost;
|
|
62036
62281
|
storiesCompleted += batchResult.completed.length;
|
|
@@ -62121,6 +62366,8 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62121
62366
|
}
|
|
62122
62367
|
}
|
|
62123
62368
|
const modelTier2 = singleSelection.routing.modelTier;
|
|
62369
|
+
const singleAgent = ctx.agentManager?.getDefault() ?? resolveDefaultAgent(ctx.config);
|
|
62370
|
+
const singleCounts = countStories(prd);
|
|
62124
62371
|
pipelineEventBus.emit({
|
|
62125
62372
|
type: "story:started",
|
|
62126
62373
|
storyId: singleStory.id,
|
|
@@ -62132,7 +62379,7 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62132
62379
|
},
|
|
62133
62380
|
workdir: ctx.workdir,
|
|
62134
62381
|
modelTier: modelTier2,
|
|
62135
|
-
agent:
|
|
62382
|
+
agent: singleAgent,
|
|
62136
62383
|
iteration: iterations
|
|
62137
62384
|
});
|
|
62138
62385
|
logger?.info("story.start", `${singleStory.title}`, {
|
|
@@ -62140,6 +62387,9 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62140
62387
|
storyTitle: singleStory.title,
|
|
62141
62388
|
complexity: singleSelection.routing.complexity ?? "unknown",
|
|
62142
62389
|
modelTier: modelTier2,
|
|
62390
|
+
agent: singleAgent,
|
|
62391
|
+
storyNumber: singleCounts.total - singleCounts.pending + 1,
|
|
62392
|
+
storyTotal: singleCounts.total,
|
|
62143
62393
|
attempt: singleStory.attempts + 1
|
|
62144
62394
|
});
|
|
62145
62395
|
const singleIter = await _unifiedExecutorDeps.runIteration(ctx, prd, singleSelection, iterations, totalCost, allStoryMetrics);
|
|
@@ -62191,6 +62441,8 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62191
62441
|
}
|
|
62192
62442
|
}
|
|
62193
62443
|
const modelTier = selection.routing.modelTier;
|
|
62444
|
+
const seqAgent = ctx.agentManager?.getDefault() ?? resolveDefaultAgent(ctx.config);
|
|
62445
|
+
const seqCounts = countStories(prd);
|
|
62194
62446
|
pipelineEventBus.emit({
|
|
62195
62447
|
type: "story:started",
|
|
62196
62448
|
storyId: selection.story.id,
|
|
@@ -62202,7 +62454,7 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62202
62454
|
},
|
|
62203
62455
|
workdir: ctx.workdir,
|
|
62204
62456
|
modelTier,
|
|
62205
|
-
agent:
|
|
62457
|
+
agent: seqAgent,
|
|
62206
62458
|
iteration: iterations
|
|
62207
62459
|
});
|
|
62208
62460
|
logger?.info("story.start", `${selection.story.title}`, {
|
|
@@ -62210,6 +62462,9 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62210
62462
|
storyTitle: selection.story.title,
|
|
62211
62463
|
complexity: selection.routing.complexity ?? "unknown",
|
|
62212
62464
|
modelTier,
|
|
62465
|
+
agent: seqAgent,
|
|
62466
|
+
storyNumber: seqCounts.total - seqCounts.pending + 1,
|
|
62467
|
+
storyTotal: seqCounts.total,
|
|
62213
62468
|
attempt: selection.story.attempts + 1
|
|
62214
62469
|
});
|
|
62215
62470
|
const iter = await _unifiedExecutorDeps.runIteration(ctx, prd, selection, iterations, totalCost, allStoryMetrics);
|
|
@@ -62268,6 +62523,18 @@ async function executeUnified(ctx, initialPrd) {
|
|
|
62268
62523
|
return buildResult2("max-iterations");
|
|
62269
62524
|
} finally {}
|
|
62270
62525
|
}
|
|
62526
|
+
function reconcileBatchOutcome(prd, batchResult) {
|
|
62527
|
+
for (const story of batchResult.completed) {
|
|
62528
|
+
markStoryPassed(prd, story.id);
|
|
62529
|
+
}
|
|
62530
|
+
for (const conflict of batchResult.mergeConflicts) {
|
|
62531
|
+
if (conflict.rectified) {
|
|
62532
|
+
markStoryPassed(prd, conflict.story.id);
|
|
62533
|
+
} else {
|
|
62534
|
+
markStoryFailed(prd, conflict.story.id, undefined, "merge-conflict");
|
|
62535
|
+
}
|
|
62536
|
+
}
|
|
62537
|
+
}
|
|
62271
62538
|
var TERMINAL_ACTIONS, _unifiedExecutorDeps;
|
|
62272
62539
|
var init_unified_executor = __esm(() => {
|
|
62273
62540
|
init_agents();
|