@nathapp/nax 0.69.6 → 0.69.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nax.js +130 -55
- package/package.json +1 -1
package/dist/nax.js
CHANGED
|
@@ -18041,7 +18041,7 @@ function redactSecrets(input) {
|
|
|
18041
18041
|
}
|
|
18042
18042
|
var SECRET_KEY_PATTERN, SECRET_VALUE_PATTERNS, REDACTED = "[REDACTED]";
|
|
18043
18043
|
var init_redact = __esm(() => {
|
|
18044
|
-
SECRET_KEY_PATTERN = /(SECRET|TOKEN|API_?KEY|PASSWORD|PRIVATE_?KEY|ACCESS_?KEY|WEBHOOK)/i;
|
|
18044
|
+
SECRET_KEY_PATTERN = /(SECRET|TOKEN(?!s\b)|API_?KEY|PASSWORD|PRIVATE_?KEY|ACCESS_?KEY|WEBHOOK)/i;
|
|
18045
18045
|
SECRET_VALUE_PATTERNS = [
|
|
18046
18046
|
/sk-[A-Za-z0-9_-]{16,}/g,
|
|
18047
18047
|
/ghp_[A-Za-z0-9]{16,}/g,
|
|
@@ -24993,12 +24993,15 @@ async function getGitRootMemo(workdir) {
|
|
|
24993
24993
|
}
|
|
24994
24994
|
return result ?? null;
|
|
24995
24995
|
}
|
|
24996
|
-
function
|
|
24997
|
-
const
|
|
24998
|
-
|
|
24996
|
+
function extractBasenamePattern(pattern) {
|
|
24997
|
+
const basename4 = pattern.slice(pattern.lastIndexOf("/") + 1);
|
|
24998
|
+
const parts = basename4.split("*");
|
|
24999
|
+
if (parts.length !== 2)
|
|
24999
25000
|
return null;
|
|
25000
|
-
const suffix =
|
|
25001
|
-
|
|
25001
|
+
const [prefix, suffix] = parts;
|
|
25002
|
+
if (!prefix && !suffix)
|
|
25003
|
+
return null;
|
|
25004
|
+
return { prefix, suffix };
|
|
25002
25005
|
}
|
|
25003
25006
|
function extractSearchTerms(sourceFile) {
|
|
25004
25007
|
const withoutPrefix = sourceFile.replace(/^(?:.*\/)?src\//, "");
|
|
@@ -25036,28 +25039,11 @@ async function importGrepFallback(sourceFiles, workdir, testFilePatterns) {
|
|
|
25036
25039
|
return results.filter((p) => p !== null);
|
|
25037
25040
|
}
|
|
25038
25041
|
async function mapSourceToTests(sourceFiles, workdir, packagePrefix, testFilePatterns = [...DEFAULT_TEST_FILE_PATTERNS]) {
|
|
25039
|
-
const
|
|
25042
|
+
const shapes = dedupeBasenamePatterns(testFilePatterns);
|
|
25043
|
+
const testDirs = [...new Set([...DEFAULT_SEPARATED_TEST_DIRS, ...extractTestDirs(testFilePatterns)])];
|
|
25040
25044
|
const result = [];
|
|
25041
25045
|
for (const sourceFile of sourceFiles) {
|
|
25042
|
-
const
|
|
25043
|
-
let innerRelative;
|
|
25044
|
-
let testBase;
|
|
25045
|
-
if (packagePrefix) {
|
|
25046
|
-
const srcRoot = `${packagePrefix}/src/`;
|
|
25047
|
-
const inner = sourceFile.startsWith(srcRoot) ? sourceFile.slice(srcRoot.length) : sourceFile.replace(/^.*\/src\//, "");
|
|
25048
|
-
innerRelative = inner.replace(/\.[^.]+$/, "");
|
|
25049
|
-
testBase = `${workdir}/${packagePrefix}`;
|
|
25050
|
-
} else {
|
|
25051
|
-
innerRelative = sourceFile.replace(/^src\//, "").replace(/\.[^.]+$/, "");
|
|
25052
|
-
testBase = workdir;
|
|
25053
|
-
}
|
|
25054
|
-
const candidates = [];
|
|
25055
|
-
for (const suffix of testSuffixes) {
|
|
25056
|
-
for (const testDir of DEFAULT_SEPARATED_TEST_DIRS) {
|
|
25057
|
-
candidates.push(`${testBase}/${testDir}/${innerRelative}${suffix}`);
|
|
25058
|
-
}
|
|
25059
|
-
candidates.push(`${workdir}/${sourceWithoutExt}${suffix}`);
|
|
25060
|
-
}
|
|
25046
|
+
const candidates = buildTestCandidates(sourceFile, workdir, packagePrefix, shapes, testDirs);
|
|
25061
25047
|
const existsFlags = await Promise.all(candidates.map((c) => _bunDeps.file(c).exists()));
|
|
25062
25048
|
candidates.forEach((c, i) => {
|
|
25063
25049
|
if (existsFlags[i])
|
|
@@ -25066,6 +25052,58 @@ async function mapSourceToTests(sourceFiles, workdir, packagePrefix, testFilePat
|
|
|
25066
25052
|
}
|
|
25067
25053
|
return result;
|
|
25068
25054
|
}
|
|
25055
|
+
function dedupeBasenamePatterns(testFilePatterns) {
|
|
25056
|
+
const seen = new Set;
|
|
25057
|
+
const shapes = [];
|
|
25058
|
+
for (const pattern of testFilePatterns) {
|
|
25059
|
+
const shape = extractBasenamePattern(pattern);
|
|
25060
|
+
if (!shape)
|
|
25061
|
+
continue;
|
|
25062
|
+
const key = `${shape.prefix}\x00${shape.suffix}`;
|
|
25063
|
+
if (seen.has(key))
|
|
25064
|
+
continue;
|
|
25065
|
+
seen.add(key);
|
|
25066
|
+
shapes.push(shape);
|
|
25067
|
+
}
|
|
25068
|
+
return shapes;
|
|
25069
|
+
}
|
|
25070
|
+
function buildTestCandidates(sourceFile, workdir, packagePrefix, shapes, testDirs) {
|
|
25071
|
+
const sourceWithoutExt = sourceFile.replace(/\.[^.]+$/, "");
|
|
25072
|
+
let innerRelative;
|
|
25073
|
+
let testBase;
|
|
25074
|
+
if (packagePrefix) {
|
|
25075
|
+
const srcRoot = `${packagePrefix}/src/`;
|
|
25076
|
+
const inner = sourceFile.startsWith(srcRoot) ? sourceFile.slice(srcRoot.length) : sourceFile.replace(/^.*\/src\//, "");
|
|
25077
|
+
innerRelative = inner.replace(/\.[^.]+$/, "");
|
|
25078
|
+
testBase = `${workdir}/${packagePrefix}`;
|
|
25079
|
+
} else {
|
|
25080
|
+
innerRelative = sourceFile.replace(/^src\//, "").replace(/\.[^.]+$/, "");
|
|
25081
|
+
testBase = workdir;
|
|
25082
|
+
}
|
|
25083
|
+
const lastSlash = innerRelative.lastIndexOf("/");
|
|
25084
|
+
const innerDir = lastSlash === -1 ? "" : innerRelative.slice(0, lastSlash);
|
|
25085
|
+
const baseName = lastSlash === -1 ? innerRelative : innerRelative.slice(lastSlash + 1);
|
|
25086
|
+
const sourceDirAbs = sourceWithoutExt.includes("/") ? `${workdir}/${sourceWithoutExt.slice(0, sourceWithoutExt.lastIndexOf("/"))}` : workdir;
|
|
25087
|
+
const candidates = [];
|
|
25088
|
+
for (const { prefix, suffix } of shapes) {
|
|
25089
|
+
if (prefix === "") {
|
|
25090
|
+
for (const testDir of testDirs) {
|
|
25091
|
+
candidates.push(`${testBase}/${testDir}/${innerRelative}${suffix}`);
|
|
25092
|
+
}
|
|
25093
|
+
candidates.push(`${workdir}/${sourceWithoutExt}${suffix}`);
|
|
25094
|
+
} else {
|
|
25095
|
+
const named = `${prefix}${baseName}${suffix}`;
|
|
25096
|
+
for (const testDir of testDirs) {
|
|
25097
|
+
candidates.push(`${testBase}/${testDir}/${innerDir ? `${innerDir}/` : ""}${named}`);
|
|
25098
|
+
if (innerDir)
|
|
25099
|
+
candidates.push(`${testBase}/${testDir}/${named}`);
|
|
25100
|
+
}
|
|
25101
|
+
candidates.push(`${sourceDirAbs}/${named}`);
|
|
25102
|
+
}
|
|
25103
|
+
}
|
|
25104
|
+
const sourceAbs = `${workdir}/${sourceFile}`;
|
|
25105
|
+
return [...new Set(candidates)].filter((c) => c !== sourceAbs);
|
|
25106
|
+
}
|
|
25069
25107
|
function buildSmartTestCommand(testFiles, baseCommand) {
|
|
25070
25108
|
if (testFiles.length === 0) {
|
|
25071
25109
|
return baseCommand;
|
|
@@ -39763,28 +39801,47 @@ var init_verify_scoped = __esm(() => {
|
|
|
39763
39801
|
timeoutSeconds: scopedTimeout,
|
|
39764
39802
|
isFullSuite: selection.isFullSuite
|
|
39765
39803
|
});
|
|
39804
|
+
const runTests = async (command) => {
|
|
39805
|
+
const result2 = await deps.regression({
|
|
39806
|
+
workdir: cmdWorkdir,
|
|
39807
|
+
command,
|
|
39808
|
+
timeoutSeconds: scopedTimeout,
|
|
39809
|
+
forceExit: quality.quality?.forceExit,
|
|
39810
|
+
detectOpenHandles: quality.quality?.detectOpenHandles,
|
|
39811
|
+
detectOpenHandlesRetries: quality.quality?.detectOpenHandlesRetries,
|
|
39812
|
+
gracePeriodMs: quality.quality?.gracePeriodMs,
|
|
39813
|
+
drainTimeoutMs: quality.quality?.drainTimeoutMs,
|
|
39814
|
+
shell: quality.quality?.shell,
|
|
39815
|
+
stripEnvVars: quality.quality?.stripEnvVars
|
|
39816
|
+
});
|
|
39817
|
+
const parsed2 = result2.output ? deps.parseTestOutput(result2.output) : { passed: 0, failed: 0, failures: [] };
|
|
39818
|
+
return { result: result2, parsed: parsed2 };
|
|
39819
|
+
};
|
|
39766
39820
|
const start = Date.now();
|
|
39767
|
-
|
|
39768
|
-
|
|
39769
|
-
|
|
39770
|
-
|
|
39771
|
-
|
|
39772
|
-
|
|
39773
|
-
|
|
39774
|
-
|
|
39775
|
-
|
|
39776
|
-
|
|
39777
|
-
|
|
39778
|
-
|
|
39821
|
+
let effectiveCommand = selection.effectiveCommand;
|
|
39822
|
+
let isFullSuite = selection.isFullSuite;
|
|
39823
|
+
let scopeTestFallback = selection.scopeTestFallback;
|
|
39824
|
+
let { result, parsed } = await runTests(effectiveCommand);
|
|
39825
|
+
const ranNoTests = parsed.passed === 0 && parsed.failed === 0 && parsed.failures.length === 0;
|
|
39826
|
+
if (!result.success && result.status !== "TIMEOUT" && !isFullSuite && ranNoTests) {
|
|
39827
|
+
logger.warn("verify[scoped]", "Scoped run executed no tests \u2014 falling back to full suite", {
|
|
39828
|
+
storyId: input.storyId,
|
|
39829
|
+
command: effectiveCommand,
|
|
39830
|
+
exitCode: result.exitCode
|
|
39831
|
+
});
|
|
39832
|
+
effectiveCommand = baseCommand;
|
|
39833
|
+
isFullSuite = true;
|
|
39834
|
+
scopeTestFallback = true;
|
|
39835
|
+
({ result, parsed } = await runTests(effectiveCommand));
|
|
39836
|
+
}
|
|
39779
39837
|
const durationMs = Date.now() - start;
|
|
39780
|
-
const parsed = result.output ? deps.parseTestOutput(result.output) : { passed: 0, failed: 0, failures: [] };
|
|
39781
39838
|
if (result.success) {
|
|
39782
39839
|
logger.info("verify[scoped]", "Scoped tests passed", {
|
|
39783
39840
|
storyId: input.storyId,
|
|
39784
39841
|
passCount: parsed.passed,
|
|
39785
39842
|
durationMs,
|
|
39786
|
-
scopeTestFallback:
|
|
39787
|
-
isFullSuite
|
|
39843
|
+
scopeTestFallback: scopeTestFallback ?? false,
|
|
39844
|
+
isFullSuite
|
|
39788
39845
|
});
|
|
39789
39846
|
return {
|
|
39790
39847
|
success: true,
|
|
@@ -39792,16 +39849,16 @@ var init_verify_scoped = __esm(() => {
|
|
|
39792
39849
|
findings: [],
|
|
39793
39850
|
durationMs,
|
|
39794
39851
|
passCount: parsed.passed,
|
|
39795
|
-
isFullSuite
|
|
39796
|
-
scopeTestFallback
|
|
39852
|
+
isFullSuite,
|
|
39853
|
+
scopeTestFallback
|
|
39797
39854
|
};
|
|
39798
39855
|
}
|
|
39799
39856
|
if (result.status === "TIMEOUT") {
|
|
39800
39857
|
logger.warn("verify[scoped]", "Scoped tests timed out", {
|
|
39801
39858
|
storyId: input.storyId,
|
|
39802
39859
|
durationMs,
|
|
39803
|
-
scopeTestFallback:
|
|
39804
|
-
isFullSuite
|
|
39860
|
+
scopeTestFallback: scopeTestFallback ?? false,
|
|
39861
|
+
isFullSuite
|
|
39805
39862
|
});
|
|
39806
39863
|
return {
|
|
39807
39864
|
success: false,
|
|
@@ -39809,8 +39866,8 @@ var init_verify_scoped = __esm(() => {
|
|
|
39809
39866
|
findings: [],
|
|
39810
39867
|
durationMs,
|
|
39811
39868
|
passCount: parsed.passed,
|
|
39812
|
-
isFullSuite
|
|
39813
|
-
scopeTestFallback
|
|
39869
|
+
isFullSuite,
|
|
39870
|
+
scopeTestFallback
|
|
39814
39871
|
};
|
|
39815
39872
|
}
|
|
39816
39873
|
logger.warn("verify[scoped]", "Scoped tests failed", {
|
|
@@ -39818,17 +39875,35 @@ var init_verify_scoped = __esm(() => {
|
|
|
39818
39875
|
passCount: parsed.passed,
|
|
39819
39876
|
failCount: parsed.failed,
|
|
39820
39877
|
durationMs,
|
|
39821
|
-
scopeTestFallback:
|
|
39822
|
-
isFullSuite
|
|
39878
|
+
scopeTestFallback: scopeTestFallback ?? false,
|
|
39879
|
+
isFullSuite
|
|
39823
39880
|
});
|
|
39881
|
+
let findings = deps.testSummaryToFindings(parsed);
|
|
39882
|
+
if (findings.length === 0) {
|
|
39883
|
+
logger.warn("verify[scoped]", "Scoped verify execution-failed \u2014 emitting synth finding", {
|
|
39884
|
+
storyId: input.storyId,
|
|
39885
|
+
command: effectiveCommand,
|
|
39886
|
+
exitCode: result.exitCode,
|
|
39887
|
+
cwd: cmdWorkdir
|
|
39888
|
+
});
|
|
39889
|
+
findings = [
|
|
39890
|
+
executionFailureToFinding({
|
|
39891
|
+
command: result.command ?? effectiveCommand,
|
|
39892
|
+
exitCode: result.exitCode,
|
|
39893
|
+
output: result.output ?? "",
|
|
39894
|
+
packageDir: input.packagePrefix,
|
|
39895
|
+
cwd: cmdWorkdir
|
|
39896
|
+
})
|
|
39897
|
+
];
|
|
39898
|
+
}
|
|
39824
39899
|
return {
|
|
39825
39900
|
success: false,
|
|
39826
39901
|
status: "failed",
|
|
39827
|
-
findings
|
|
39902
|
+
findings,
|
|
39828
39903
|
durationMs,
|
|
39829
39904
|
passCount: parsed.passed,
|
|
39830
|
-
isFullSuite
|
|
39831
|
-
scopeTestFallback
|
|
39905
|
+
isFullSuite,
|
|
39906
|
+
scopeTestFallback
|
|
39832
39907
|
};
|
|
39833
39908
|
}
|
|
39834
39909
|
};
|
|
@@ -59695,7 +59770,7 @@ var package_default;
|
|
|
59695
59770
|
var init_package = __esm(() => {
|
|
59696
59771
|
package_default = {
|
|
59697
59772
|
name: "@nathapp/nax",
|
|
59698
|
-
version: "0.69.
|
|
59773
|
+
version: "0.69.7",
|
|
59699
59774
|
description: "AI Coding Agent Orchestrator \u2014 loops until done",
|
|
59700
59775
|
type: "module",
|
|
59701
59776
|
bin: {
|
|
@@ -59790,8 +59865,8 @@ var init_version = __esm(() => {
|
|
|
59790
59865
|
NAX_VERSION = package_default.version;
|
|
59791
59866
|
NAX_COMMIT = (() => {
|
|
59792
59867
|
try {
|
|
59793
|
-
if (/^[0-9a-f]{6,10}$/.test("
|
|
59794
|
-
return "
|
|
59868
|
+
if (/^[0-9a-f]{6,10}$/.test("d524317e"))
|
|
59869
|
+
return "d524317e";
|
|
59795
59870
|
} catch {}
|
|
59796
59871
|
try {
|
|
59797
59872
|
const result = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"], {
|