opencode-swarm 7.44.0 → 7.45.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 +64 -35
- package/dist/index.js +180 -86
- package/dist/tools/diff.d.ts +4 -0
- package/dist/tools/test-runner.d.ts +7 -0
- package/dist/utils/git-binary-missing-error.d.ts +9 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "opencode-swarm",
|
|
55
|
-
version: "7.
|
|
55
|
+
version: "7.45.0",
|
|
56
56
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
57
57
|
main: "dist/index.js",
|
|
58
58
|
types: "dist/index.d.ts",
|
|
@@ -35881,27 +35881,25 @@ function normalizeEntry(raw) {
|
|
|
35881
35881
|
ro = {};
|
|
35882
35882
|
obj.retrieval_outcomes = ro;
|
|
35883
35883
|
}
|
|
35884
|
-
{
|
|
35885
|
-
|
|
35886
|
-
|
|
35887
|
-
|
|
35888
|
-
|
|
35889
|
-
|
|
35890
|
-
|
|
35891
|
-
|
|
35892
|
-
|
|
35893
|
-
|
|
35894
|
-
|
|
35895
|
-
|
|
35896
|
-
|
|
35897
|
-
|
|
35898
|
-
|
|
35899
|
-
|
|
35900
|
-
|
|
35901
|
-
|
|
35902
|
-
|
|
35903
|
-
ro.failed_after_shown_count = typeof ro.failed_after_count === "number" ? ro.failed_after_count : 0;
|
|
35904
|
-
}
|
|
35884
|
+
if (typeof ro.shown_count !== "number") {
|
|
35885
|
+
ro.shown_count = typeof ro.applied_count === "number" ? ro.applied_count : 0;
|
|
35886
|
+
}
|
|
35887
|
+
if (typeof ro.acknowledged_count !== "number")
|
|
35888
|
+
ro.acknowledged_count = 0;
|
|
35889
|
+
if (typeof ro.applied_explicit_count !== "number") {
|
|
35890
|
+
ro.applied_explicit_count = 0;
|
|
35891
|
+
}
|
|
35892
|
+
if (typeof ro.ignored_count !== "number")
|
|
35893
|
+
ro.ignored_count = 0;
|
|
35894
|
+
if (typeof ro.violated_count !== "number")
|
|
35895
|
+
ro.violated_count = 0;
|
|
35896
|
+
if (typeof ro.contradicted_count !== "number")
|
|
35897
|
+
ro.contradicted_count = 0;
|
|
35898
|
+
if (typeof ro.succeeded_after_shown_count !== "number") {
|
|
35899
|
+
ro.succeeded_after_shown_count = typeof ro.succeeded_after_count === "number" ? ro.succeeded_after_count : 0;
|
|
35900
|
+
}
|
|
35901
|
+
if (typeof ro.failed_after_shown_count !== "number") {
|
|
35902
|
+
ro.failed_after_shown_count = typeof ro.failed_after_count === "number" ? ro.failed_after_count : 0;
|
|
35905
35903
|
}
|
|
35906
35904
|
try {
|
|
35907
35905
|
if (typeof obj.encounter_score !== "number" || Number.isNaN(obj.encounter_score)) {
|
|
@@ -51529,6 +51527,19 @@ import path41 from "path";
|
|
|
51529
51527
|
function normalizePath(p) {
|
|
51530
51528
|
return p.replace(/\\/g, "/");
|
|
51531
51529
|
}
|
|
51530
|
+
function sharedTrailingSegments(a, b) {
|
|
51531
|
+
const aParts = normalizePath(a).split("/").filter(Boolean);
|
|
51532
|
+
const bParts = normalizePath(b).split("/").filter(Boolean);
|
|
51533
|
+
let i = aParts.length - 1;
|
|
51534
|
+
let j = bParts.length - 1;
|
|
51535
|
+
let shared = 0;
|
|
51536
|
+
while (i >= 0 && j >= 0 && aParts[i] === bParts[j]) {
|
|
51537
|
+
shared++;
|
|
51538
|
+
i--;
|
|
51539
|
+
j--;
|
|
51540
|
+
}
|
|
51541
|
+
return shared;
|
|
51542
|
+
}
|
|
51532
51543
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
51533
51544
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
51534
51545
|
try {
|
|
@@ -51856,25 +51867,43 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
51856
51867
|
if (budgetExceeded)
|
|
51857
51868
|
break;
|
|
51858
51869
|
} else {
|
|
51859
|
-
|
|
51860
|
-
|
|
51870
|
+
const changedDir = normalizePath(path41.dirname(normalizedChanged));
|
|
51871
|
+
const changedInputDir = normalizePath(path41.dirname(changedFile));
|
|
51872
|
+
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
51873
|
+
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
51874
|
+
}).sort(([sourceA], [sourceB]) => {
|
|
51875
|
+
const sourceDirA = normalizePath(path41.dirname(sourceA));
|
|
51876
|
+
const sourceDirB = normalizePath(path41.dirname(sourceB));
|
|
51877
|
+
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
51878
|
+
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
51879
|
+
if (exactA !== exactB)
|
|
51880
|
+
return exactA ? -1 : 1;
|
|
51881
|
+
const sharedA = Math.max(sharedTrailingSegments(sourceDirA, changedDir), changedInputDir === "." ? 0 : sharedTrailingSegments(sourceDirA, changedInputDir));
|
|
51882
|
+
const sharedB = Math.max(sharedTrailingSegments(sourceDirB, changedDir), changedInputDir === "." ? 0 : sharedTrailingSegments(sourceDirB, changedInputDir));
|
|
51883
|
+
const nearestA = sharedA > 0;
|
|
51884
|
+
const nearestB = sharedB > 0;
|
|
51885
|
+
if (nearestA !== nearestB)
|
|
51886
|
+
return nearestA ? -1 : 1;
|
|
51887
|
+
if (sharedA !== sharedB)
|
|
51888
|
+
return sharedB - sharedA;
|
|
51889
|
+
return sourceA.localeCompare(sourceB);
|
|
51890
|
+
});
|
|
51891
|
+
const found = suffixMatches.length > 0;
|
|
51892
|
+
for (const [, tests2] of suffixMatches) {
|
|
51861
51893
|
if (budget !== undefined && visitedCount >= budget) {
|
|
51862
51894
|
budgetExceeded = true;
|
|
51863
51895
|
break;
|
|
51864
51896
|
}
|
|
51865
|
-
|
|
51866
|
-
|
|
51867
|
-
|
|
51868
|
-
budgetExceeded = true;
|
|
51869
|
-
break;
|
|
51870
|
-
}
|
|
51871
|
-
impactedTestsSet.add(test);
|
|
51872
|
-
visitedCount++;
|
|
51873
|
-
}
|
|
51874
|
-
if (budgetExceeded)
|
|
51897
|
+
for (const test of tests2) {
|
|
51898
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
51899
|
+
budgetExceeded = true;
|
|
51875
51900
|
break;
|
|
51876
|
-
|
|
51901
|
+
}
|
|
51902
|
+
impactedTestsSet.add(test);
|
|
51903
|
+
visitedCount++;
|
|
51877
51904
|
}
|
|
51905
|
+
if (budgetExceeded)
|
|
51906
|
+
break;
|
|
51878
51907
|
}
|
|
51879
51908
|
if (budgetExceeded)
|
|
51880
51909
|
break;
|
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ var package_default;
|
|
|
69
69
|
var init_package = __esm(() => {
|
|
70
70
|
package_default = {
|
|
71
71
|
name: "opencode-swarm",
|
|
72
|
-
version: "7.
|
|
72
|
+
version: "7.45.0",
|
|
73
73
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
74
74
|
main: "dist/index.js",
|
|
75
75
|
types: "dist/index.d.ts",
|
|
@@ -56168,27 +56168,25 @@ function normalizeEntry(raw) {
|
|
|
56168
56168
|
ro = {};
|
|
56169
56169
|
obj.retrieval_outcomes = ro;
|
|
56170
56170
|
}
|
|
56171
|
-
{
|
|
56172
|
-
|
|
56173
|
-
|
|
56174
|
-
|
|
56175
|
-
|
|
56176
|
-
|
|
56177
|
-
|
|
56178
|
-
|
|
56179
|
-
|
|
56180
|
-
|
|
56181
|
-
|
|
56182
|
-
|
|
56183
|
-
|
|
56184
|
-
|
|
56185
|
-
|
|
56186
|
-
|
|
56187
|
-
|
|
56188
|
-
|
|
56189
|
-
|
|
56190
|
-
ro.failed_after_shown_count = typeof ro.failed_after_count === "number" ? ro.failed_after_count : 0;
|
|
56191
|
-
}
|
|
56171
|
+
if (typeof ro.shown_count !== "number") {
|
|
56172
|
+
ro.shown_count = typeof ro.applied_count === "number" ? ro.applied_count : 0;
|
|
56173
|
+
}
|
|
56174
|
+
if (typeof ro.acknowledged_count !== "number")
|
|
56175
|
+
ro.acknowledged_count = 0;
|
|
56176
|
+
if (typeof ro.applied_explicit_count !== "number") {
|
|
56177
|
+
ro.applied_explicit_count = 0;
|
|
56178
|
+
}
|
|
56179
|
+
if (typeof ro.ignored_count !== "number")
|
|
56180
|
+
ro.ignored_count = 0;
|
|
56181
|
+
if (typeof ro.violated_count !== "number")
|
|
56182
|
+
ro.violated_count = 0;
|
|
56183
|
+
if (typeof ro.contradicted_count !== "number")
|
|
56184
|
+
ro.contradicted_count = 0;
|
|
56185
|
+
if (typeof ro.succeeded_after_shown_count !== "number") {
|
|
56186
|
+
ro.succeeded_after_shown_count = typeof ro.succeeded_after_count === "number" ? ro.succeeded_after_count : 0;
|
|
56187
|
+
}
|
|
56188
|
+
if (typeof ro.failed_after_shown_count !== "number") {
|
|
56189
|
+
ro.failed_after_shown_count = typeof ro.failed_after_count === "number" ? ro.failed_after_count : 0;
|
|
56192
56190
|
}
|
|
56193
56191
|
try {
|
|
56194
56192
|
if (typeof obj.encounter_score !== "number" || Number.isNaN(obj.encounter_score)) {
|
|
@@ -74499,6 +74497,19 @@ import path54 from "node:path";
|
|
|
74499
74497
|
function normalizePath(p) {
|
|
74500
74498
|
return p.replace(/\\/g, "/");
|
|
74501
74499
|
}
|
|
74500
|
+
function sharedTrailingSegments(a, b) {
|
|
74501
|
+
const aParts = normalizePath(a).split("/").filter(Boolean);
|
|
74502
|
+
const bParts = normalizePath(b).split("/").filter(Boolean);
|
|
74503
|
+
let i2 = aParts.length - 1;
|
|
74504
|
+
let j = bParts.length - 1;
|
|
74505
|
+
let shared = 0;
|
|
74506
|
+
while (i2 >= 0 && j >= 0 && aParts[i2] === bParts[j]) {
|
|
74507
|
+
shared++;
|
|
74508
|
+
i2--;
|
|
74509
|
+
j--;
|
|
74510
|
+
}
|
|
74511
|
+
return shared;
|
|
74512
|
+
}
|
|
74502
74513
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
74503
74514
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
74504
74515
|
try {
|
|
@@ -74826,25 +74837,43 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
74826
74837
|
if (budgetExceeded)
|
|
74827
74838
|
break;
|
|
74828
74839
|
} else {
|
|
74829
|
-
|
|
74830
|
-
|
|
74840
|
+
const changedDir = normalizePath(path54.dirname(normalizedChanged));
|
|
74841
|
+
const changedInputDir = normalizePath(path54.dirname(changedFile));
|
|
74842
|
+
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
74843
|
+
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
74844
|
+
}).sort(([sourceA], [sourceB]) => {
|
|
74845
|
+
const sourceDirA = normalizePath(path54.dirname(sourceA));
|
|
74846
|
+
const sourceDirB = normalizePath(path54.dirname(sourceB));
|
|
74847
|
+
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
74848
|
+
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
74849
|
+
if (exactA !== exactB)
|
|
74850
|
+
return exactA ? -1 : 1;
|
|
74851
|
+
const sharedA = Math.max(sharedTrailingSegments(sourceDirA, changedDir), changedInputDir === "." ? 0 : sharedTrailingSegments(sourceDirA, changedInputDir));
|
|
74852
|
+
const sharedB = Math.max(sharedTrailingSegments(sourceDirB, changedDir), changedInputDir === "." ? 0 : sharedTrailingSegments(sourceDirB, changedInputDir));
|
|
74853
|
+
const nearestA = sharedA > 0;
|
|
74854
|
+
const nearestB = sharedB > 0;
|
|
74855
|
+
if (nearestA !== nearestB)
|
|
74856
|
+
return nearestA ? -1 : 1;
|
|
74857
|
+
if (sharedA !== sharedB)
|
|
74858
|
+
return sharedB - sharedA;
|
|
74859
|
+
return sourceA.localeCompare(sourceB);
|
|
74860
|
+
});
|
|
74861
|
+
const found = suffixMatches.length > 0;
|
|
74862
|
+
for (const [, tests2] of suffixMatches) {
|
|
74831
74863
|
if (budget !== undefined && visitedCount >= budget) {
|
|
74832
74864
|
budgetExceeded = true;
|
|
74833
74865
|
break;
|
|
74834
74866
|
}
|
|
74835
|
-
|
|
74836
|
-
|
|
74837
|
-
|
|
74838
|
-
budgetExceeded = true;
|
|
74839
|
-
break;
|
|
74840
|
-
}
|
|
74841
|
-
impactedTestsSet.add(test);
|
|
74842
|
-
visitedCount++;
|
|
74843
|
-
}
|
|
74844
|
-
if (budgetExceeded)
|
|
74867
|
+
for (const test of tests2) {
|
|
74868
|
+
if (budget !== undefined && visitedCount >= budget) {
|
|
74869
|
+
budgetExceeded = true;
|
|
74845
74870
|
break;
|
|
74846
|
-
|
|
74871
|
+
}
|
|
74872
|
+
impactedTestsSet.add(test);
|
|
74873
|
+
visitedCount++;
|
|
74847
74874
|
}
|
|
74875
|
+
if (budgetExceeded)
|
|
74876
|
+
break;
|
|
74848
74877
|
}
|
|
74849
74878
|
if (budgetExceeded)
|
|
74850
74879
|
break;
|
|
@@ -97912,6 +97941,12 @@ function extractSignature(node, languageId) {
|
|
|
97912
97941
|
return paramsNode.text;
|
|
97913
97942
|
}
|
|
97914
97943
|
}
|
|
97944
|
+
if (node.type === "class_declaration" || node.type === "class_definition" || node.type === "class") {
|
|
97945
|
+
const classBodyNode = node.children.find((c) => c !== null && (c.type === "class_body" || c.type === "declaration_list"));
|
|
97946
|
+
if (classBodyNode) {
|
|
97947
|
+
return classBodyNode.text;
|
|
97948
|
+
}
|
|
97949
|
+
}
|
|
97915
97950
|
return;
|
|
97916
97951
|
}
|
|
97917
97952
|
function compareSymbols(oldSymbols, newSymbols) {
|
|
@@ -97973,7 +98008,7 @@ function compareSymbols(oldSymbols, newSymbols) {
|
|
|
97973
98008
|
return changes;
|
|
97974
98009
|
}
|
|
97975
98010
|
function findRenamedSymbol(newSymbol, oldSymbols, matchedOldSymbols) {
|
|
97976
|
-
if (newSymbol.category !== "function" && newSymbol.category !== "type") {
|
|
98011
|
+
if (newSymbol.category !== "function" && newSymbol.category !== "type" && newSymbol.category !== "class") {
|
|
97977
98012
|
return null;
|
|
97978
98013
|
}
|
|
97979
98014
|
if (!newSymbol.signature) {
|
|
@@ -98205,11 +98240,51 @@ function generateSummaryMarkdown(summary) {
|
|
|
98205
98240
|
`);
|
|
98206
98241
|
}
|
|
98207
98242
|
|
|
98243
|
+
// src/utils/git-binary-missing-error.ts
|
|
98244
|
+
class GitBinaryMissingError extends Error {
|
|
98245
|
+
name = "GitBinaryMissingError";
|
|
98246
|
+
constructor(message = "git binary is not available", options) {
|
|
98247
|
+
super(message, options);
|
|
98248
|
+
}
|
|
98249
|
+
}
|
|
98250
|
+
function isGitBinaryMissing(err2) {
|
|
98251
|
+
return typeof err2 === "object" && err2 !== null && "code" in err2 && err2.code === "ENOENT";
|
|
98252
|
+
}
|
|
98253
|
+
|
|
98208
98254
|
// src/hooks/semantic-diff-injection.ts
|
|
98255
|
+
async function execGit(directory, args2, options) {
|
|
98256
|
+
try {
|
|
98257
|
+
const stdout = await new Promise((resolve31, reject) => {
|
|
98258
|
+
const execOpts = {
|
|
98259
|
+
encoding: "utf-8",
|
|
98260
|
+
cwd: directory,
|
|
98261
|
+
timeout: options?.timeout,
|
|
98262
|
+
maxBuffer: options?.maxBuffer,
|
|
98263
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
98264
|
+
};
|
|
98265
|
+
child_process5.execFile("git", args2, execOpts, (error93, output, _stderr) => {
|
|
98266
|
+
if (error93) {
|
|
98267
|
+
reject(error93);
|
|
98268
|
+
return;
|
|
98269
|
+
}
|
|
98270
|
+
resolve31(output ?? "");
|
|
98271
|
+
});
|
|
98272
|
+
});
|
|
98273
|
+
return stdout;
|
|
98274
|
+
} catch (err2) {
|
|
98275
|
+
if (isGitBinaryMissing(err2)) {
|
|
98276
|
+
throw new GitBinaryMissingError("git binary is not available", {
|
|
98277
|
+
cause: err2
|
|
98278
|
+
});
|
|
98279
|
+
}
|
|
98280
|
+
throw err2;
|
|
98281
|
+
}
|
|
98282
|
+
}
|
|
98209
98283
|
async function buildSemanticDiffBlock(directory, changedFiles, maxFiles = 10) {
|
|
98210
98284
|
if (changedFiles.length === 0)
|
|
98211
98285
|
return null;
|
|
98212
98286
|
try {
|
|
98287
|
+
const realDirectory = fs55.realpathSync(directory);
|
|
98213
98288
|
const filesToProcess = changedFiles.slice(0, maxFiles);
|
|
98214
98289
|
const astDiffs = [];
|
|
98215
98290
|
const graph = getCachedGraph2(directory);
|
|
@@ -98229,37 +98304,40 @@ async function buildSemanticDiffBlock(directory, changedFiles, maxFiles = 10) {
|
|
|
98229
98304
|
if (relativeToDir.startsWith("..") || path92.isAbsolute(relativeToDir)) {
|
|
98230
98305
|
continue;
|
|
98231
98306
|
}
|
|
98307
|
+
let realResolvedPath;
|
|
98308
|
+
try {
|
|
98309
|
+
realResolvedPath = fs55.realpathSync(resolvedPath);
|
|
98310
|
+
} catch {
|
|
98311
|
+
continue;
|
|
98312
|
+
}
|
|
98313
|
+
const realRelativeToDir = path92.relative(realDirectory, realResolvedPath);
|
|
98314
|
+
if (realRelativeToDir.startsWith("..") || path92.isAbsolute(realRelativeToDir)) {
|
|
98315
|
+
continue;
|
|
98316
|
+
}
|
|
98232
98317
|
try {
|
|
98233
98318
|
let fileExistsInHead = false;
|
|
98234
98319
|
try {
|
|
98235
|
-
|
|
98236
|
-
|
|
98237
|
-
timeout: 3000,
|
|
98238
|
-
cwd: directory,
|
|
98239
|
-
stdio: "pipe"
|
|
98320
|
+
await execGit(directory, ["cat-file", "-e", `HEAD:${filePath}`], {
|
|
98321
|
+
timeout: 3000
|
|
98240
98322
|
});
|
|
98241
98323
|
fileExistsInHead = true;
|
|
98242
98324
|
} catch (err2) {
|
|
98243
|
-
if (err2
|
|
98244
|
-
err2._gitBinaryMissing = true;
|
|
98325
|
+
if (err2 instanceof GitBinaryMissingError) {
|
|
98245
98326
|
throw err2;
|
|
98246
98327
|
}
|
|
98247
98328
|
fileExistsInHead = false;
|
|
98248
98329
|
}
|
|
98249
|
-
const oldContent = fileExistsInHead ?
|
|
98250
|
-
encoding: "utf-8",
|
|
98330
|
+
const oldContent = fileExistsInHead ? await execGit(directory, ["show", `HEAD:${filePath}`], {
|
|
98251
98331
|
timeout: 5000,
|
|
98252
|
-
cwd: directory,
|
|
98253
|
-
stdio: "pipe",
|
|
98254
98332
|
maxBuffer: 5 * 1024 * 1024
|
|
98255
98333
|
}) : "";
|
|
98256
|
-
const newContent = fs55.
|
|
98334
|
+
const newContent = await fs55.promises.readFile(realResolvedPath, "utf-8");
|
|
98257
98335
|
const astResult = await computeASTDiff(filePath, oldContent, newContent);
|
|
98258
98336
|
if (astResult && (astResult.changes.length > 0 || astResult.error !== undefined)) {
|
|
98259
98337
|
astDiffs.push(astResult);
|
|
98260
98338
|
}
|
|
98261
98339
|
} catch (err2) {
|
|
98262
|
-
if (err2
|
|
98340
|
+
if (err2 instanceof GitBinaryMissingError) {
|
|
98263
98341
|
throw err2;
|
|
98264
98342
|
}
|
|
98265
98343
|
}
|
|
@@ -106602,8 +106680,8 @@ ${body2}`);
|
|
|
106602
106680
|
|
|
106603
106681
|
// src/council/council-evidence-writer.ts
|
|
106604
106682
|
init_task_file();
|
|
106605
|
-
import { appendFileSync as appendFileSync12, existsSync as existsSync62, mkdirSync as mkdirSync27, readFileSync as
|
|
106606
|
-
import { join as
|
|
106683
|
+
import { appendFileSync as appendFileSync12, existsSync as existsSync62, mkdirSync as mkdirSync27, readFileSync as readFileSync45 } from "node:fs";
|
|
106684
|
+
import { join as join93 } from "node:path";
|
|
106607
106685
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
106608
106686
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
106609
106687
|
var COUNCIL_GATE_NAME = "council";
|
|
@@ -106640,14 +106718,14 @@ async function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
106640
106718
|
if (!VALID_TASK_ID.test(synthesis.taskId)) {
|
|
106641
106719
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" — must match N.M or N.M.P format`);
|
|
106642
106720
|
}
|
|
106643
|
-
const dir =
|
|
106721
|
+
const dir = join93(workingDir, EVIDENCE_DIR2);
|
|
106644
106722
|
mkdirSync27(dir, { recursive: true });
|
|
106645
106723
|
const filePath = taskEvidencePath(workingDir, synthesis.taskId);
|
|
106646
106724
|
await _internals49.withTaskEvidenceLock(workingDir, synthesis.taskId, COUNCIL_AGENT_ID, async () => {
|
|
106647
106725
|
const existingRoot = Object.create(null);
|
|
106648
106726
|
if (existsSync62(filePath)) {
|
|
106649
106727
|
try {
|
|
106650
|
-
const parsed = JSON.parse(
|
|
106728
|
+
const parsed = JSON.parse(readFileSync45(filePath, "utf-8"));
|
|
106651
106729
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
106652
106730
|
safeAssignOwnProps(existingRoot, parsed);
|
|
106653
106731
|
}
|
|
@@ -106678,7 +106756,7 @@ async function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
106678
106756
|
await atomicWriteFile(filePath, JSON.stringify(updated, null, 2));
|
|
106679
106757
|
});
|
|
106680
106758
|
try {
|
|
106681
|
-
const councilDir =
|
|
106759
|
+
const councilDir = join93(workingDir, ".swarm", "council");
|
|
106682
106760
|
mkdirSync27(councilDir, { recursive: true });
|
|
106683
106761
|
const auditLine = JSON.stringify({
|
|
106684
106762
|
round: synthesis.roundNumber,
|
|
@@ -106686,7 +106764,7 @@ async function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
106686
106764
|
timestamp: synthesis.timestamp,
|
|
106687
106765
|
vetoedBy: synthesis.vetoedBy
|
|
106688
106766
|
});
|
|
106689
|
-
appendFileSync12(
|
|
106767
|
+
appendFileSync12(join93(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
106690
106768
|
`);
|
|
106691
106769
|
} catch (auditError) {
|
|
106692
106770
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -107008,25 +107086,25 @@ function buildFinalCouncilFeedback(projectSummary, verdict, vetoedBy, requiredFi
|
|
|
107008
107086
|
}
|
|
107009
107087
|
|
|
107010
107088
|
// src/council/criteria-store.ts
|
|
107011
|
-
import { existsSync as existsSync63, mkdirSync as mkdirSync28, readFileSync as
|
|
107012
|
-
import { join as
|
|
107089
|
+
import { existsSync as existsSync63, mkdirSync as mkdirSync28, readFileSync as readFileSync46, writeFileSync as writeFileSync20 } from "node:fs";
|
|
107090
|
+
import { join as join94 } from "node:path";
|
|
107013
107091
|
var COUNCIL_DIR = ".swarm/council";
|
|
107014
107092
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
107015
|
-
const dir =
|
|
107093
|
+
const dir = join94(workingDir, COUNCIL_DIR);
|
|
107016
107094
|
mkdirSync28(dir, { recursive: true });
|
|
107017
107095
|
const payload = {
|
|
107018
107096
|
taskId,
|
|
107019
107097
|
criteria,
|
|
107020
107098
|
declaredAt: new Date().toISOString()
|
|
107021
107099
|
};
|
|
107022
|
-
writeFileSync20(
|
|
107100
|
+
writeFileSync20(join94(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
|
|
107023
107101
|
}
|
|
107024
107102
|
function readCriteria(workingDir, taskId) {
|
|
107025
|
-
const filePath =
|
|
107103
|
+
const filePath = join94(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
|
|
107026
107104
|
if (!existsSync63(filePath))
|
|
107027
107105
|
return null;
|
|
107028
107106
|
try {
|
|
107029
|
-
const parsed = JSON.parse(
|
|
107107
|
+
const parsed = JSON.parse(readFileSync46(filePath, "utf-8"));
|
|
107030
107108
|
if (parsed && typeof parsed === "object" && typeof parsed.taskId === "string" && Array.isArray(parsed.criteria)) {
|
|
107031
107109
|
return parsed;
|
|
107032
107110
|
}
|
|
@@ -108288,7 +108366,6 @@ var diff = createSwarmTool({
|
|
|
108288
108366
|
const fileCount = files.length;
|
|
108289
108367
|
const astDiffs = [];
|
|
108290
108368
|
const filesForAST = files.slice(0, MAX_AST_FILES);
|
|
108291
|
-
const astSkippedCount = files.length > MAX_AST_FILES ? files.length - MAX_AST_FILES : 0;
|
|
108292
108369
|
for (const file3 of filesForAST) {
|
|
108293
108370
|
try {
|
|
108294
108371
|
let oldContent;
|
|
@@ -108347,6 +108424,7 @@ var diff = createSwarmTool({
|
|
|
108347
108424
|
markdownSummary = generateSummaryMarkdown(semanticSummary);
|
|
108348
108425
|
} catch {}
|
|
108349
108426
|
}
|
|
108427
|
+
const astSkippedCount = files.length > MAX_AST_FILES ? files.length - MAX_AST_FILES : 0;
|
|
108350
108428
|
const truncated = diffLines.length > MAX_DIFF_LINES;
|
|
108351
108429
|
const summary = truncated ? `${fileCount} files changed. Contract changes: ${hasContractChanges ? "YES" : "NO"}. (truncated to ${MAX_DIFF_LINES} lines)` : `${fileCount} files changed. Contract changes: ${hasContractChanges ? "YES" : "NO"}`;
|
|
108352
108430
|
const result = {
|
|
@@ -108378,6 +108456,34 @@ import * as fs79 from "node:fs";
|
|
|
108378
108456
|
import * as path116 from "node:path";
|
|
108379
108457
|
init_create_tool();
|
|
108380
108458
|
init_resolve_working_directory();
|
|
108459
|
+
async function execGit2(workingDir, args2, options) {
|
|
108460
|
+
try {
|
|
108461
|
+
const stdout = await new Promise((resolve40, reject) => {
|
|
108462
|
+
const execOpts = {
|
|
108463
|
+
encoding: "utf-8",
|
|
108464
|
+
cwd: workingDir,
|
|
108465
|
+
timeout: options?.timeout,
|
|
108466
|
+
maxBuffer: options?.maxBuffer,
|
|
108467
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
108468
|
+
};
|
|
108469
|
+
child_process8.execFile("git", args2, execOpts, (error93, output, _stderr) => {
|
|
108470
|
+
if (error93) {
|
|
108471
|
+
reject(error93);
|
|
108472
|
+
return;
|
|
108473
|
+
}
|
|
108474
|
+
resolve40(output ?? "");
|
|
108475
|
+
});
|
|
108476
|
+
});
|
|
108477
|
+
return stdout;
|
|
108478
|
+
} catch (err2) {
|
|
108479
|
+
if (isGitBinaryMissing(err2)) {
|
|
108480
|
+
throw new GitBinaryMissingError("git binary is not available", {
|
|
108481
|
+
cause: err2
|
|
108482
|
+
});
|
|
108483
|
+
}
|
|
108484
|
+
throw err2;
|
|
108485
|
+
}
|
|
108486
|
+
}
|
|
108381
108487
|
var diff_summary = createSwarmTool({
|
|
108382
108488
|
description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
|
|
108383
108489
|
args: {
|
|
@@ -108403,45 +108509,33 @@ var diff_summary = createSwarmTool({
|
|
|
108403
108509
|
const astDiffs = [];
|
|
108404
108510
|
for (const filePath of typedArgs.files) {
|
|
108405
108511
|
let astResult = null;
|
|
108406
|
-
let gitBinaryMissing = false;
|
|
108407
|
-
let gitError = null;
|
|
108408
108512
|
let fileExistsInHead = false;
|
|
108409
108513
|
try {
|
|
108410
|
-
|
|
108411
|
-
|
|
108412
|
-
timeout: 3000,
|
|
108413
|
-
cwd: workingDir,
|
|
108414
|
-
stdio: "pipe"
|
|
108514
|
+
await execGit2(workingDir, ["cat-file", "-e", `HEAD:${filePath}`], {
|
|
108515
|
+
timeout: 3000
|
|
108415
108516
|
});
|
|
108416
108517
|
fileExistsInHead = true;
|
|
108417
108518
|
} catch (e) {
|
|
108418
|
-
if (e
|
|
108419
|
-
|
|
108420
|
-
if (err2.code === "ENOENT") {
|
|
108421
|
-
gitBinaryMissing = true;
|
|
108422
|
-
gitError = e;
|
|
108423
|
-
}
|
|
108519
|
+
if (e instanceof GitBinaryMissingError) {
|
|
108520
|
+
throw e;
|
|
108424
108521
|
}
|
|
108425
108522
|
}
|
|
108426
|
-
if (gitBinaryMissing && gitError) {
|
|
108427
|
-
throw gitError;
|
|
108428
|
-
}
|
|
108429
108523
|
try {
|
|
108430
108524
|
let oldContent;
|
|
108431
|
-
const newContent = fs79.
|
|
108525
|
+
const newContent = await fs79.promises.readFile(path116.join(workingDir, filePath), "utf-8");
|
|
108432
108526
|
if (fileExistsInHead) {
|
|
108433
|
-
oldContent =
|
|
108434
|
-
encoding: "utf-8",
|
|
108527
|
+
oldContent = await execGit2(workingDir, ["show", `HEAD:${filePath}`], {
|
|
108435
108528
|
timeout: 5000,
|
|
108436
|
-
cwd: workingDir,
|
|
108437
|
-
stdio: "pipe",
|
|
108438
108529
|
maxBuffer: 5 * 1024 * 1024
|
|
108439
108530
|
});
|
|
108440
108531
|
} else {
|
|
108441
108532
|
oldContent = "";
|
|
108442
108533
|
}
|
|
108443
108534
|
astResult = await computeASTDiff(filePath, oldContent, newContent);
|
|
108444
|
-
} catch (
|
|
108535
|
+
} catch (e) {
|
|
108536
|
+
if (e instanceof GitBinaryMissingError) {
|
|
108537
|
+
throw e;
|
|
108538
|
+
}
|
|
108445
108539
|
astResult = null;
|
|
108446
108540
|
}
|
|
108447
108541
|
if (astResult && (astResult.changes.length > 0 || astResult.error !== undefined)) {
|
|
@@ -119836,7 +119930,7 @@ init_loader();
|
|
|
119836
119930
|
import {
|
|
119837
119931
|
existsSync as existsSync81,
|
|
119838
119932
|
mkdirSync as mkdirSync34,
|
|
119839
|
-
readFileSync as
|
|
119933
|
+
readFileSync as readFileSync63,
|
|
119840
119934
|
renameSync as renameSync21,
|
|
119841
119935
|
unlinkSync as unlinkSync18,
|
|
119842
119936
|
writeFileSync as writeFileSync27
|
|
@@ -119973,7 +120067,7 @@ var submit_phase_council_verdicts = createSwarmTool({
|
|
|
119973
120067
|
function getPhaseMutationGapFinding(phaseNumber, workingDir) {
|
|
119974
120068
|
const mutationGatePath = path138.join(workingDir, ".swarm", "evidence", String(phaseNumber), "mutation-gate.json");
|
|
119975
120069
|
try {
|
|
119976
|
-
const raw =
|
|
120070
|
+
const raw = readFileSync63(mutationGatePath, "utf-8");
|
|
119977
120071
|
const parsed = JSON.parse(raw);
|
|
119978
120072
|
const gateEntry = (parsed.entries ?? []).find((entry) => entry?.type === "mutation-gate");
|
|
119979
120073
|
if (!gateEntry) {
|
package/dist/tools/diff.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export interface DiffResult {
|
|
|
13
13
|
astDiffs?: ASTDiffResult[];
|
|
14
14
|
semanticSummary?: SemanticDiffSummary;
|
|
15
15
|
markdownSummary?: string;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated This field is no longer computed and will be removed in a future version.
|
|
18
|
+
* It is retained for backward compatibility with existing consumers.
|
|
19
|
+
*/
|
|
16
20
|
astSkippedCount?: number;
|
|
17
21
|
}
|
|
18
22
|
export interface DiffErrorResult {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { tool } from '@opencode-ai/plugin';
|
|
2
|
+
import { getAllHistory, type TestRunRecord } from '../test-impact/history-store.js';
|
|
2
3
|
export declare const MAX_OUTPUT_BYTES = 512000;
|
|
3
4
|
export declare const MAX_COMMAND_LENGTH = 500;
|
|
4
5
|
export declare const DEFAULT_TIMEOUT_MS = 60000;
|
|
@@ -127,4 +128,10 @@ export declare function isLanguageSpecificTestFile(basename: string): boolean;
|
|
|
127
128
|
*/
|
|
128
129
|
export declare function getTestFilesFromConvention(sourceFiles: string[], workingDir?: string): string[];
|
|
129
130
|
export declare function runTests(framework: TestFramework, scope: 'all' | 'convention' | 'graph' | 'impact', files: string[], coverage: boolean, timeout_ms: number, cwd: string): Promise<TestResult>;
|
|
131
|
+
declare function selectHistoryForAnalysis(history: ReturnType<typeof getAllHistory>): TestRunRecord[];
|
|
130
132
|
export declare const test_runner: ReturnType<typeof tool>;
|
|
133
|
+
export declare const _internals: {
|
|
134
|
+
readonly selectHistoryForAnalysis: typeof selectHistoryForAnalysis;
|
|
135
|
+
readonly AGGREGATE_TEST_NAME: "(aggregate)";
|
|
136
|
+
};
|
|
137
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class GitBinaryMissingError extends Error {
|
|
2
|
+
readonly name = "GitBinaryMissingError";
|
|
3
|
+
constructor(message?: string, options?: {
|
|
4
|
+
cause?: unknown;
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
export declare function isGitBinaryMissing(err: unknown): err is {
|
|
8
|
+
code?: string;
|
|
9
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.45.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",
|