opencode-swarm 7.19.3 → 7.20.0
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/cli/index.js +109 -11
- package/dist/index.js +109 -11
- package/dist/test-impact/analyzer.d.ts +8 -2
- package/dist/tools/test-runner.d.ts +11 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.20.0",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -46785,18 +46785,36 @@ async function buildImpactMap(cwd) {
|
|
|
46785
46785
|
await _internals22.saveImpactMap(cwd, impactMap);
|
|
46786
46786
|
return impactMap;
|
|
46787
46787
|
}
|
|
46788
|
-
async function loadImpactMap(cwd) {
|
|
46788
|
+
async function loadImpactMap(cwd, options) {
|
|
46789
46789
|
const cachePath = path34.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
46790
46790
|
if (fs17.existsSync(cachePath)) {
|
|
46791
46791
|
try {
|
|
46792
46792
|
const content = fs17.readFileSync(cachePath, "utf-8");
|
|
46793
46793
|
const data = JSON.parse(content);
|
|
46794
|
-
|
|
46795
|
-
|
|
46796
|
-
|
|
46797
|
-
|
|
46794
|
+
if (data.map !== null && typeof data.map === "object" && !Array.isArray(data.map)) {
|
|
46795
|
+
const map3 = data.map;
|
|
46796
|
+
const hasValidValues = Object.values(map3).every((v) => Array.isArray(v) && v.every((item) => typeof item === "string"));
|
|
46797
|
+
if (hasValidValues) {
|
|
46798
|
+
const generatedAt = new Date(data.generatedAt).getTime();
|
|
46799
|
+
if (!_internals22.isCacheStale(map3, generatedAt)) {
|
|
46800
|
+
return map3;
|
|
46801
|
+
}
|
|
46802
|
+
if (options?.skipRebuild) {
|
|
46803
|
+
return map3;
|
|
46804
|
+
}
|
|
46805
|
+
}
|
|
46798
46806
|
}
|
|
46799
|
-
|
|
46807
|
+
if (options?.skipRebuild) {
|
|
46808
|
+
return {};
|
|
46809
|
+
}
|
|
46810
|
+
} catch {
|
|
46811
|
+
if (options?.skipRebuild) {
|
|
46812
|
+
return {};
|
|
46813
|
+
}
|
|
46814
|
+
}
|
|
46815
|
+
}
|
|
46816
|
+
if (options?.skipRebuild) {
|
|
46817
|
+
return {};
|
|
46800
46818
|
}
|
|
46801
46819
|
return _internals22.buildImpactMap(cwd);
|
|
46802
46820
|
}
|
|
@@ -46813,7 +46831,7 @@ async function saveImpactMap(cwd, impactMap) {
|
|
|
46813
46831
|
};
|
|
46814
46832
|
fs17.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
46815
46833
|
}
|
|
46816
|
-
async function analyzeImpact(changedFiles, cwd) {
|
|
46834
|
+
async function analyzeImpact(changedFiles, cwd, budget) {
|
|
46817
46835
|
if (!Array.isArray(changedFiles)) {
|
|
46818
46836
|
const emptyMap = {};
|
|
46819
46837
|
return {
|
|
@@ -46827,24 +46845,49 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
46827
46845
|
const impactMap = await _internals22.loadImpactMap(cwd);
|
|
46828
46846
|
const impactedTestsSet = new Set;
|
|
46829
46847
|
const untestedFiles = [];
|
|
46848
|
+
let visitedCount = 0;
|
|
46849
|
+
let budgetExceeded = false;
|
|
46830
46850
|
for (const changedFile of validFiles) {
|
|
46851
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
46852
|
+
budgetExceeded = true;
|
|
46853
|
+
break;
|
|
46854
|
+
}
|
|
46831
46855
|
const normalizedChanged = normalizePath(path34.resolve(changedFile));
|
|
46832
46856
|
const tests = impactMap[normalizedChanged];
|
|
46833
46857
|
if (tests && tests.length > 0) {
|
|
46834
46858
|
for (const test of tests) {
|
|
46859
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
46860
|
+
budgetExceeded = true;
|
|
46861
|
+
break;
|
|
46862
|
+
}
|
|
46835
46863
|
impactedTestsSet.add(test);
|
|
46864
|
+
visitedCount++;
|
|
46836
46865
|
}
|
|
46866
|
+
if (budgetExceeded)
|
|
46867
|
+
break;
|
|
46837
46868
|
} else {
|
|
46838
46869
|
let found = false;
|
|
46839
46870
|
for (const [sourcePath, tests2] of Object.entries(impactMap)) {
|
|
46871
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
46872
|
+
budgetExceeded = true;
|
|
46873
|
+
break;
|
|
46874
|
+
}
|
|
46840
46875
|
if (sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath)) {
|
|
46841
46876
|
for (const test of tests2) {
|
|
46877
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
46878
|
+
budgetExceeded = true;
|
|
46879
|
+
break;
|
|
46880
|
+
}
|
|
46842
46881
|
impactedTestsSet.add(test);
|
|
46882
|
+
visitedCount++;
|
|
46843
46883
|
}
|
|
46884
|
+
if (budgetExceeded)
|
|
46885
|
+
break;
|
|
46844
46886
|
found = true;
|
|
46845
|
-
break;
|
|
46846
46887
|
}
|
|
46847
46888
|
}
|
|
46889
|
+
if (budgetExceeded)
|
|
46890
|
+
break;
|
|
46848
46891
|
if (!found) {
|
|
46849
46892
|
untestedFiles.push(changedFile);
|
|
46850
46893
|
}
|
|
@@ -46862,7 +46905,8 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
46862
46905
|
impactedTests,
|
|
46863
46906
|
unrelatedTests,
|
|
46864
46907
|
untestedFiles,
|
|
46865
|
-
impactMap
|
|
46908
|
+
impactMap,
|
|
46909
|
+
budgetExceeded
|
|
46866
46910
|
};
|
|
46867
46911
|
}
|
|
46868
46912
|
var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, TS_EXTENSIONS, PYTHON_EXTENSIONS, GO_EXTENSIONS, EXTENSIONS_TO_TRY, goModuleCache, _internals22;
|
|
@@ -47724,6 +47768,25 @@ var init_dispatch = __esm(() => {
|
|
|
47724
47768
|
// src/tools/test-runner.ts
|
|
47725
47769
|
import * as fs22 from "fs";
|
|
47726
47770
|
import * as path39 from "path";
|
|
47771
|
+
async function estimateFanOut(sourceFiles, cwd) {
|
|
47772
|
+
try {
|
|
47773
|
+
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
47774
|
+
const uniqueTestFiles = new Set;
|
|
47775
|
+
for (const sourceFile of sourceFiles) {
|
|
47776
|
+
const resolvedPath = path39.resolve(cwd, sourceFile);
|
|
47777
|
+
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
47778
|
+
const testFiles = impactMap[normalizedPath];
|
|
47779
|
+
if (testFiles) {
|
|
47780
|
+
for (const testFile of testFiles) {
|
|
47781
|
+
uniqueTestFiles.add(testFile);
|
|
47782
|
+
}
|
|
47783
|
+
}
|
|
47784
|
+
}
|
|
47785
|
+
return { estimatedCount: uniqueTestFiles.size };
|
|
47786
|
+
} catch {
|
|
47787
|
+
return { estimatedCount: 0 };
|
|
47788
|
+
}
|
|
47789
|
+
}
|
|
47727
47790
|
function isAbsolutePath(str) {
|
|
47728
47791
|
if (str.startsWith("/"))
|
|
47729
47792
|
return true;
|
|
@@ -49068,6 +49131,18 @@ var init_test_runner = __esm(() => {
|
|
|
49068
49131
|
};
|
|
49069
49132
|
return JSON.stringify(errorResult, null, 2);
|
|
49070
49133
|
}
|
|
49134
|
+
const estimate = await estimateFanOut(sourceFiles, workingDir);
|
|
49135
|
+
if (estimate.estimatedCount > MAX_SAFE_TEST_FILES) {
|
|
49136
|
+
const errorResult = {
|
|
49137
|
+
success: false,
|
|
49138
|
+
framework,
|
|
49139
|
+
scope,
|
|
49140
|
+
error: "Estimated test file count exceeds safe maximum",
|
|
49141
|
+
message: `Scope "graph" resolution would produce approximately ${estimate.estimatedCount} test files, which exceeds the safe limit of ${MAX_SAFE_TEST_FILES}. Break the source files into smaller batches and retry.`,
|
|
49142
|
+
outcome: "scope_exceeded"
|
|
49143
|
+
};
|
|
49144
|
+
return JSON.stringify(errorResult, null, 2);
|
|
49145
|
+
}
|
|
49071
49146
|
const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
|
|
49072
49147
|
if (graphTestFiles.length > 0) {
|
|
49073
49148
|
testFiles = graphTestFiles;
|
|
@@ -49106,8 +49181,31 @@ var init_test_runner = __esm(() => {
|
|
|
49106
49181
|
};
|
|
49107
49182
|
return JSON.stringify(errorResult, null, 2);
|
|
49108
49183
|
}
|
|
49184
|
+
const estimate = await estimateFanOut(sourceFiles, workingDir);
|
|
49185
|
+
if (estimate.estimatedCount > MAX_SAFE_TEST_FILES) {
|
|
49186
|
+
const errorResult = {
|
|
49187
|
+
success: false,
|
|
49188
|
+
framework,
|
|
49189
|
+
scope,
|
|
49190
|
+
error: "Estimated test file count exceeds safe maximum",
|
|
49191
|
+
message: `Scope "impact" resolution would produce approximately ${estimate.estimatedCount} test files, which exceeds the safe limit of ${MAX_SAFE_TEST_FILES}. Break the source files into smaller batches and retry.`,
|
|
49192
|
+
outcome: "scope_exceeded"
|
|
49193
|
+
};
|
|
49194
|
+
return JSON.stringify(errorResult, null, 2);
|
|
49195
|
+
}
|
|
49109
49196
|
try {
|
|
49110
|
-
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
49197
|
+
const impactResult = await analyzeImpact(sourceFiles, workingDir, MAX_SAFE_TEST_FILES);
|
|
49198
|
+
if (impactResult.budgetExceeded) {
|
|
49199
|
+
const errorResult = {
|
|
49200
|
+
success: false,
|
|
49201
|
+
framework,
|
|
49202
|
+
scope,
|
|
49203
|
+
error: "Budget exceeded during impact analysis",
|
|
49204
|
+
message: `Impact analysis exceeded safe budget of ${MAX_SAFE_TEST_FILES} test files.`,
|
|
49205
|
+
outcome: "scope_exceeded"
|
|
49206
|
+
};
|
|
49207
|
+
return JSON.stringify(errorResult, null, 2);
|
|
49208
|
+
}
|
|
49111
49209
|
if (impactResult.impactedTests.length > 0) {
|
|
49112
49210
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
49113
49211
|
const relativePath = path39.relative(workingDir, absPath);
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var package_default;
|
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "opencode-swarm",
|
|
36
|
-
version: "7.
|
|
36
|
+
version: "7.20.0",
|
|
37
37
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
38
38
|
main: "dist/index.js",
|
|
39
39
|
types: "dist/index.d.ts",
|
|
@@ -55407,18 +55407,36 @@ async function buildImpactMap(cwd) {
|
|
|
55407
55407
|
await _internals28.saveImpactMap(cwd, impactMap);
|
|
55408
55408
|
return impactMap;
|
|
55409
55409
|
}
|
|
55410
|
-
async function loadImpactMap(cwd) {
|
|
55410
|
+
async function loadImpactMap(cwd, options) {
|
|
55411
55411
|
const cachePath = path41.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
55412
55412
|
if (fs24.existsSync(cachePath)) {
|
|
55413
55413
|
try {
|
|
55414
55414
|
const content = fs24.readFileSync(cachePath, "utf-8");
|
|
55415
55415
|
const data = JSON.parse(content);
|
|
55416
|
-
|
|
55417
|
-
|
|
55418
|
-
|
|
55419
|
-
|
|
55416
|
+
if (data.map !== null && typeof data.map === "object" && !Array.isArray(data.map)) {
|
|
55417
|
+
const map3 = data.map;
|
|
55418
|
+
const hasValidValues = Object.values(map3).every((v) => Array.isArray(v) && v.every((item) => typeof item === "string"));
|
|
55419
|
+
if (hasValidValues) {
|
|
55420
|
+
const generatedAt = new Date(data.generatedAt).getTime();
|
|
55421
|
+
if (!_internals28.isCacheStale(map3, generatedAt)) {
|
|
55422
|
+
return map3;
|
|
55423
|
+
}
|
|
55424
|
+
if (options?.skipRebuild) {
|
|
55425
|
+
return map3;
|
|
55426
|
+
}
|
|
55427
|
+
}
|
|
55420
55428
|
}
|
|
55421
|
-
|
|
55429
|
+
if (options?.skipRebuild) {
|
|
55430
|
+
return {};
|
|
55431
|
+
}
|
|
55432
|
+
} catch {
|
|
55433
|
+
if (options?.skipRebuild) {
|
|
55434
|
+
return {};
|
|
55435
|
+
}
|
|
55436
|
+
}
|
|
55437
|
+
}
|
|
55438
|
+
if (options?.skipRebuild) {
|
|
55439
|
+
return {};
|
|
55422
55440
|
}
|
|
55423
55441
|
return _internals28.buildImpactMap(cwd);
|
|
55424
55442
|
}
|
|
@@ -55435,7 +55453,7 @@ async function saveImpactMap(cwd, impactMap) {
|
|
|
55435
55453
|
};
|
|
55436
55454
|
fs24.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
55437
55455
|
}
|
|
55438
|
-
async function analyzeImpact(changedFiles, cwd) {
|
|
55456
|
+
async function analyzeImpact(changedFiles, cwd, budget) {
|
|
55439
55457
|
if (!Array.isArray(changedFiles)) {
|
|
55440
55458
|
const emptyMap = {};
|
|
55441
55459
|
return {
|
|
@@ -55449,24 +55467,49 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
55449
55467
|
const impactMap = await _internals28.loadImpactMap(cwd);
|
|
55450
55468
|
const impactedTestsSet = new Set;
|
|
55451
55469
|
const untestedFiles = [];
|
|
55470
|
+
let visitedCount = 0;
|
|
55471
|
+
let budgetExceeded = false;
|
|
55452
55472
|
for (const changedFile of validFiles) {
|
|
55473
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
55474
|
+
budgetExceeded = true;
|
|
55475
|
+
break;
|
|
55476
|
+
}
|
|
55453
55477
|
const normalizedChanged = normalizePath(path41.resolve(changedFile));
|
|
55454
55478
|
const tests = impactMap[normalizedChanged];
|
|
55455
55479
|
if (tests && tests.length > 0) {
|
|
55456
55480
|
for (const test of tests) {
|
|
55481
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
55482
|
+
budgetExceeded = true;
|
|
55483
|
+
break;
|
|
55484
|
+
}
|
|
55457
55485
|
impactedTestsSet.add(test);
|
|
55486
|
+
visitedCount++;
|
|
55458
55487
|
}
|
|
55488
|
+
if (budgetExceeded)
|
|
55489
|
+
break;
|
|
55459
55490
|
} else {
|
|
55460
55491
|
let found = false;
|
|
55461
55492
|
for (const [sourcePath, tests2] of Object.entries(impactMap)) {
|
|
55493
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
55494
|
+
budgetExceeded = true;
|
|
55495
|
+
break;
|
|
55496
|
+
}
|
|
55462
55497
|
if (sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath)) {
|
|
55463
55498
|
for (const test of tests2) {
|
|
55499
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
55500
|
+
budgetExceeded = true;
|
|
55501
|
+
break;
|
|
55502
|
+
}
|
|
55464
55503
|
impactedTestsSet.add(test);
|
|
55504
|
+
visitedCount++;
|
|
55465
55505
|
}
|
|
55506
|
+
if (budgetExceeded)
|
|
55507
|
+
break;
|
|
55466
55508
|
found = true;
|
|
55467
|
-
break;
|
|
55468
55509
|
}
|
|
55469
55510
|
}
|
|
55511
|
+
if (budgetExceeded)
|
|
55512
|
+
break;
|
|
55470
55513
|
if (!found) {
|
|
55471
55514
|
untestedFiles.push(changedFile);
|
|
55472
55515
|
}
|
|
@@ -55484,7 +55527,8 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
55484
55527
|
impactedTests,
|
|
55485
55528
|
unrelatedTests,
|
|
55486
55529
|
untestedFiles,
|
|
55487
|
-
impactMap
|
|
55530
|
+
impactMap,
|
|
55531
|
+
budgetExceeded
|
|
55488
55532
|
};
|
|
55489
55533
|
}
|
|
55490
55534
|
var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, TS_EXTENSIONS, PYTHON_EXTENSIONS, GO_EXTENSIONS, EXTENSIONS_TO_TRY, goModuleCache, _internals28;
|
|
@@ -56346,6 +56390,25 @@ var init_dispatch = __esm(() => {
|
|
|
56346
56390
|
// src/tools/test-runner.ts
|
|
56347
56391
|
import * as fs29 from "node:fs";
|
|
56348
56392
|
import * as path46 from "node:path";
|
|
56393
|
+
async function estimateFanOut(sourceFiles, cwd) {
|
|
56394
|
+
try {
|
|
56395
|
+
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
56396
|
+
const uniqueTestFiles = new Set;
|
|
56397
|
+
for (const sourceFile of sourceFiles) {
|
|
56398
|
+
const resolvedPath = path46.resolve(cwd, sourceFile);
|
|
56399
|
+
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
56400
|
+
const testFiles = impactMap[normalizedPath];
|
|
56401
|
+
if (testFiles) {
|
|
56402
|
+
for (const testFile of testFiles) {
|
|
56403
|
+
uniqueTestFiles.add(testFile);
|
|
56404
|
+
}
|
|
56405
|
+
}
|
|
56406
|
+
}
|
|
56407
|
+
return { estimatedCount: uniqueTestFiles.size };
|
|
56408
|
+
} catch {
|
|
56409
|
+
return { estimatedCount: 0 };
|
|
56410
|
+
}
|
|
56411
|
+
}
|
|
56349
56412
|
function isAbsolutePath(str) {
|
|
56350
56413
|
if (str.startsWith("/"))
|
|
56351
56414
|
return true;
|
|
@@ -57690,6 +57753,18 @@ var init_test_runner = __esm(() => {
|
|
|
57690
57753
|
};
|
|
57691
57754
|
return JSON.stringify(errorResult, null, 2);
|
|
57692
57755
|
}
|
|
57756
|
+
const estimate = await estimateFanOut(sourceFiles, workingDir);
|
|
57757
|
+
if (estimate.estimatedCount > MAX_SAFE_TEST_FILES) {
|
|
57758
|
+
const errorResult = {
|
|
57759
|
+
success: false,
|
|
57760
|
+
framework,
|
|
57761
|
+
scope,
|
|
57762
|
+
error: "Estimated test file count exceeds safe maximum",
|
|
57763
|
+
message: `Scope "graph" resolution would produce approximately ${estimate.estimatedCount} test files, which exceeds the safe limit of ${MAX_SAFE_TEST_FILES}. Break the source files into smaller batches and retry.`,
|
|
57764
|
+
outcome: "scope_exceeded"
|
|
57765
|
+
};
|
|
57766
|
+
return JSON.stringify(errorResult, null, 2);
|
|
57767
|
+
}
|
|
57693
57768
|
const graphTestFiles = await getTestFilesFromGraph(sourceFiles, workingDir);
|
|
57694
57769
|
if (graphTestFiles.length > 0) {
|
|
57695
57770
|
testFiles = graphTestFiles;
|
|
@@ -57728,8 +57803,31 @@ var init_test_runner = __esm(() => {
|
|
|
57728
57803
|
};
|
|
57729
57804
|
return JSON.stringify(errorResult, null, 2);
|
|
57730
57805
|
}
|
|
57806
|
+
const estimate = await estimateFanOut(sourceFiles, workingDir);
|
|
57807
|
+
if (estimate.estimatedCount > MAX_SAFE_TEST_FILES) {
|
|
57808
|
+
const errorResult = {
|
|
57809
|
+
success: false,
|
|
57810
|
+
framework,
|
|
57811
|
+
scope,
|
|
57812
|
+
error: "Estimated test file count exceeds safe maximum",
|
|
57813
|
+
message: `Scope "impact" resolution would produce approximately ${estimate.estimatedCount} test files, which exceeds the safe limit of ${MAX_SAFE_TEST_FILES}. Break the source files into smaller batches and retry.`,
|
|
57814
|
+
outcome: "scope_exceeded"
|
|
57815
|
+
};
|
|
57816
|
+
return JSON.stringify(errorResult, null, 2);
|
|
57817
|
+
}
|
|
57731
57818
|
try {
|
|
57732
|
-
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
57819
|
+
const impactResult = await analyzeImpact(sourceFiles, workingDir, MAX_SAFE_TEST_FILES);
|
|
57820
|
+
if (impactResult.budgetExceeded) {
|
|
57821
|
+
const errorResult = {
|
|
57822
|
+
success: false,
|
|
57823
|
+
framework,
|
|
57824
|
+
scope,
|
|
57825
|
+
error: "Budget exceeded during impact analysis",
|
|
57826
|
+
message: `Impact analysis exceeded safe budget of ${MAX_SAFE_TEST_FILES} test files.`,
|
|
57827
|
+
outcome: "scope_exceeded"
|
|
57828
|
+
};
|
|
57829
|
+
return JSON.stringify(errorResult, null, 2);
|
|
57830
|
+
}
|
|
57733
57831
|
if (impactResult.impactedTests.length > 0) {
|
|
57734
57832
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
57735
57833
|
const relativePath = path46.relative(workingDir, absPath);
|
|
@@ -3,6 +3,7 @@ export interface TestImpactResult {
|
|
|
3
3
|
unrelatedTests: string[];
|
|
4
4
|
untestedFiles: string[];
|
|
5
5
|
impactMap: Record<string, string[]>;
|
|
6
|
+
budgetExceeded?: boolean;
|
|
6
7
|
}
|
|
7
8
|
declare function normalizePath(p: string): string;
|
|
8
9
|
declare function isCacheStale(impactMap: Record<string, string[]>, generatedAtMs: number): boolean;
|
|
@@ -30,7 +31,12 @@ export declare const _internals: {
|
|
|
30
31
|
_clearGoModuleCache: typeof _clearGoModuleCache;
|
|
31
32
|
};
|
|
32
33
|
export declare function buildImpactMap(cwd: string): Promise<Record<string, string[]>>;
|
|
33
|
-
export
|
|
34
|
+
export interface LoadImpactMapOptions {
|
|
35
|
+
/** If true and cache is stale, return the stale map instead of rebuilding.
|
|
36
|
+
* Use for estimation-only reads where slight staleness is acceptable. */
|
|
37
|
+
skipRebuild?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare function loadImpactMap(cwd: string, options?: LoadImpactMapOptions): Promise<Record<string, string[]>>;
|
|
34
40
|
declare function saveImpactMap(cwd: string, impactMap: Record<string, string[]>): Promise<void>;
|
|
35
|
-
export declare function analyzeImpact(changedFiles: string[], cwd: string): Promise<TestImpactResult>;
|
|
41
|
+
export declare function analyzeImpact(changedFiles: string[], cwd: string, budget?: number): Promise<TestImpactResult>;
|
|
36
42
|
export {};
|
|
@@ -5,6 +5,17 @@ export declare const DEFAULT_TIMEOUT_MS = 60000;
|
|
|
5
5
|
export declare const MAX_TIMEOUT_MS = 300000;
|
|
6
6
|
export declare const MAX_SAFE_TEST_FILES = 50;
|
|
7
7
|
export declare const MAX_SAFE_SOURCE_FILES = 1;
|
|
8
|
+
/**
|
|
9
|
+
* Estimate the fan-out (number of unique test files) for given source files
|
|
10
|
+
* by reading the cached impact map without spawning a subprocess.
|
|
11
|
+
* This is a pre-resolution check to prevent session blocking.
|
|
12
|
+
*
|
|
13
|
+
* Completes in <100ms by design — reads only the cached JSON and performs
|
|
14
|
+
* in-memory Set collection.
|
|
15
|
+
*/
|
|
16
|
+
export declare function estimateFanOut(sourceFiles: string[], cwd: string): Promise<{
|
|
17
|
+
estimatedCount: number;
|
|
18
|
+
}>;
|
|
8
19
|
export declare const SUPPORTED_FRAMEWORKS: readonly ["bun", "vitest", "jest", "mocha", "pytest", "cargo", "pester", "go-test", "maven", "gradle", "dotnet-test", "ctest", "swift-test", "dart-test", "rspec", "minitest"];
|
|
9
20
|
export type TestFramework = (typeof SUPPORTED_FRAMEWORKS)[number] | 'none';
|
|
10
21
|
export interface TestRunnerArgs {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.20.0",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|