opencode-swarm 6.20.0 → 6.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli/index.js +15 -6
- package/dist/hooks/delegation-gate.d.ts +10 -1
- package/dist/index.js +131 -61
- package/dist/tools/lint.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -852,7 +852,7 @@ This release adds runtime detection hooks to catch and warn about architect work
|
|
|
852
852
|
- **Partial gate tracking**: Detects when QA gates are skipped
|
|
853
853
|
- **Self-fix detection**: Warns when an agent fixes its own gate failure (should delegate to fresh agent)
|
|
854
854
|
- **Batch detection**: Catches "implement X and add Y" batching in task requests
|
|
855
|
-
- **Zero-delegation detection**: Warns when tasks complete without any coder delegation
|
|
855
|
+
- **Zero-delegation detection**: Warns when tasks complete without any coder delegation; supports parsing delegation envelopes from JSON or KEY: VALUE text format for validation.
|
|
856
856
|
|
|
857
857
|
These hooks are advisory (warnings only) and help maintain workflow discipline during long sessions.
|
|
858
858
|
|
package/dist/cli/index.js
CHANGED
|
@@ -32646,9 +32646,9 @@ function validateArgs(args) {
|
|
|
32646
32646
|
return false;
|
|
32647
32647
|
return true;
|
|
32648
32648
|
}
|
|
32649
|
-
function getLinterCommand(linter, mode) {
|
|
32649
|
+
function getLinterCommand(linter, mode, projectDir) {
|
|
32650
32650
|
const isWindows = process.platform === "win32";
|
|
32651
|
-
const binDir = path11.join(
|
|
32651
|
+
const binDir = path11.join(projectDir, "node_modules", ".bin");
|
|
32652
32652
|
const biomeBin = isWindows ? path11.join(binDir, "biome.EXE") : path11.join(binDir, "biome");
|
|
32653
32653
|
const eslintBin = isWindows ? path11.join(binDir, "eslint.cmd") : path11.join(binDir, "eslint");
|
|
32654
32654
|
switch (linter) {
|
|
@@ -32825,8 +32825,8 @@ async function detectAvailableLinter() {
|
|
|
32825
32825
|
} catch {}
|
|
32826
32826
|
return null;
|
|
32827
32827
|
}
|
|
32828
|
-
async function runLint(linter, mode) {
|
|
32829
|
-
const command = getLinterCommand(linter, mode);
|
|
32828
|
+
async function runLint(linter, mode, directory) {
|
|
32829
|
+
const command = getLinterCommand(linter, mode, directory);
|
|
32830
32830
|
const commandStr = command.join(" ");
|
|
32831
32831
|
if (commandStr.length > MAX_COMMAND_LENGTH) {
|
|
32832
32832
|
return {
|
|
@@ -32840,7 +32840,8 @@ async function runLint(linter, mode) {
|
|
|
32840
32840
|
try {
|
|
32841
32841
|
const proc = Bun.spawn(command, {
|
|
32842
32842
|
stdout: "pipe",
|
|
32843
|
-
stderr: "pipe"
|
|
32843
|
+
stderr: "pipe",
|
|
32844
|
+
cwd: directory
|
|
32844
32845
|
});
|
|
32845
32846
|
const [stdout, stderr] = await Promise.all([
|
|
32846
32847
|
new Response(proc.stdout).text(),
|
|
@@ -32954,11 +32955,19 @@ var lint = createSwarmTool({
|
|
|
32954
32955
|
};
|
|
32955
32956
|
return JSON.stringify(errorResult2, null, 2);
|
|
32956
32957
|
}
|
|
32958
|
+
if (!directory || typeof directory !== "string" || directory.trim() === "") {
|
|
32959
|
+
const errorResult2 = {
|
|
32960
|
+
success: false,
|
|
32961
|
+
mode: "check",
|
|
32962
|
+
error: "project directory is required but was not provided"
|
|
32963
|
+
};
|
|
32964
|
+
return JSON.stringify(errorResult2, null, 2);
|
|
32965
|
+
}
|
|
32957
32966
|
const { mode } = args;
|
|
32958
32967
|
const cwd = directory;
|
|
32959
32968
|
const linter = await detectAvailableLinter();
|
|
32960
32969
|
if (linter) {
|
|
32961
|
-
const result = await runLint(linter, mode);
|
|
32970
|
+
const result = await runLint(linter, mode, directory);
|
|
32962
32971
|
return JSON.stringify(result, null, 2);
|
|
32963
32972
|
}
|
|
32964
32973
|
const additionalLinter = detectAdditionalLinter(cwd);
|
|
@@ -5,13 +5,22 @@
|
|
|
5
5
|
* Uses experimental.chat.messages.transform to provide non-blocking guidance.
|
|
6
6
|
*/
|
|
7
7
|
import type { PluginConfig } from '../config';
|
|
8
|
-
import type { DelegationEnvelope } from '../types/delegation.js';
|
|
8
|
+
import type { DelegationEnvelope, EnvelopeValidationResult } from '../types/delegation.js';
|
|
9
9
|
/**
|
|
10
10
|
* Parses a string to extract a DelegationEnvelope.
|
|
11
11
|
* Returns null if no valid envelope is found.
|
|
12
12
|
* Never throws - all errors are caught and result in null.
|
|
13
13
|
*/
|
|
14
14
|
export declare function parseDelegationEnvelope(content: string): DelegationEnvelope | null;
|
|
15
|
+
interface ValidationContext {
|
|
16
|
+
planTasks: string[];
|
|
17
|
+
validAgents: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validates a DelegationEnvelope against the current plan and agent list.
|
|
21
|
+
* Returns { valid: true } on success, or { valid: false; reason: string } on failure.
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateDelegationEnvelope(envelope: unknown, context: ValidationContext): EnvelopeValidationResult;
|
|
15
24
|
interface MessageInfo {
|
|
16
25
|
role: string;
|
|
17
26
|
agent?: string;
|
package/dist/index.js
CHANGED
|
@@ -32236,9 +32236,9 @@ function validateArgs(args2) {
|
|
|
32236
32236
|
return false;
|
|
32237
32237
|
return true;
|
|
32238
32238
|
}
|
|
32239
|
-
function getLinterCommand(linter, mode) {
|
|
32239
|
+
function getLinterCommand(linter, mode, projectDir) {
|
|
32240
32240
|
const isWindows = process.platform === "win32";
|
|
32241
|
-
const binDir = path18.join(
|
|
32241
|
+
const binDir = path18.join(projectDir, "node_modules", ".bin");
|
|
32242
32242
|
const biomeBin = isWindows ? path18.join(binDir, "biome.EXE") : path18.join(binDir, "biome");
|
|
32243
32243
|
const eslintBin = isWindows ? path18.join(binDir, "eslint.cmd") : path18.join(binDir, "eslint");
|
|
32244
32244
|
switch (linter) {
|
|
@@ -32415,8 +32415,8 @@ async function detectAvailableLinter() {
|
|
|
32415
32415
|
} catch {}
|
|
32416
32416
|
return null;
|
|
32417
32417
|
}
|
|
32418
|
-
async function runLint(linter, mode) {
|
|
32419
|
-
const command = getLinterCommand(linter, mode);
|
|
32418
|
+
async function runLint(linter, mode, directory) {
|
|
32419
|
+
const command = getLinterCommand(linter, mode, directory);
|
|
32420
32420
|
const commandStr = command.join(" ");
|
|
32421
32421
|
if (commandStr.length > MAX_COMMAND_LENGTH) {
|
|
32422
32422
|
return {
|
|
@@ -32430,7 +32430,8 @@ async function runLint(linter, mode) {
|
|
|
32430
32430
|
try {
|
|
32431
32431
|
const proc = Bun.spawn(command, {
|
|
32432
32432
|
stdout: "pipe",
|
|
32433
|
-
stderr: "pipe"
|
|
32433
|
+
stderr: "pipe",
|
|
32434
|
+
cwd: directory
|
|
32434
32435
|
});
|
|
32435
32436
|
const [stdout, stderr] = await Promise.all([
|
|
32436
32437
|
new Response(proc.stdout).text(),
|
|
@@ -32550,11 +32551,19 @@ var init_lint = __esm(() => {
|
|
|
32550
32551
|
};
|
|
32551
32552
|
return JSON.stringify(errorResult2, null, 2);
|
|
32552
32553
|
}
|
|
32554
|
+
if (!directory || typeof directory !== "string" || directory.trim() === "") {
|
|
32555
|
+
const errorResult2 = {
|
|
32556
|
+
success: false,
|
|
32557
|
+
mode: "check",
|
|
32558
|
+
error: "project directory is required but was not provided"
|
|
32559
|
+
};
|
|
32560
|
+
return JSON.stringify(errorResult2, null, 2);
|
|
32561
|
+
}
|
|
32553
32562
|
const { mode } = args2;
|
|
32554
32563
|
const cwd = directory;
|
|
32555
32564
|
const linter = await detectAvailableLinter();
|
|
32556
32565
|
if (linter) {
|
|
32557
|
-
const result = await runLint(linter, mode);
|
|
32566
|
+
const result = await runLint(linter, mode, directory);
|
|
32558
32567
|
return JSON.stringify(result, null, 2);
|
|
32559
32568
|
}
|
|
32560
32569
|
const additionalLinter = detectAdditionalLinter(cwd);
|
|
@@ -34357,10 +34366,10 @@ async function runVersionCheck(dir, _timeoutMs) {
|
|
|
34357
34366
|
};
|
|
34358
34367
|
}
|
|
34359
34368
|
}
|
|
34360
|
-
async function runLintCheck(
|
|
34369
|
+
async function runLintCheck(dir, linter, timeoutMs) {
|
|
34361
34370
|
const startTime = Date.now();
|
|
34362
34371
|
try {
|
|
34363
|
-
const lintPromise = runLint(linter, "check");
|
|
34372
|
+
const lintPromise = runLint(linter, "check", dir);
|
|
34364
34373
|
const timeoutPromise = new Promise((_, reject) => {
|
|
34365
34374
|
setTimeout(() => {
|
|
34366
34375
|
reject(new Error(`Lint check timed out after ${timeoutMs}ms`));
|
|
@@ -44993,7 +45002,7 @@ async function handleKnowledgeListCommand(directory, _args) {
|
|
|
44993
45002
|
"|------|----------|------------|---------------------|"
|
|
44994
45003
|
];
|
|
44995
45004
|
for (const entry of entries) {
|
|
44996
|
-
const truncatedLesson = entry.lesson.length > 60 ? entry.lesson.slice(0, 57)
|
|
45005
|
+
const truncatedLesson = entry.lesson.length > 60 ? `${entry.lesson.slice(0, 57)}...` : entry.lesson;
|
|
44997
45006
|
const confidencePct = Math.round(entry.confidence * 100);
|
|
44998
45007
|
lines.push(`| ${entry.id.slice(0, 8)}... | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`);
|
|
44999
45008
|
}
|
|
@@ -45605,7 +45614,7 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
45605
45614
|
`);
|
|
45606
45615
|
}
|
|
45607
45616
|
const targetPhase = parseInt(phaseArg, 10);
|
|
45608
|
-
if (isNaN(targetPhase) || targetPhase < 1) {
|
|
45617
|
+
if (Number.isNaN(targetPhase) || targetPhase < 1) {
|
|
45609
45618
|
return "Error: Phase number must be a positive integer.";
|
|
45610
45619
|
}
|
|
45611
45620
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
@@ -45650,7 +45659,7 @@ async function handleRollbackCommand(directory, args2) {
|
|
|
45650
45659
|
timestamp: new Date().toISOString()
|
|
45651
45660
|
};
|
|
45652
45661
|
try {
|
|
45653
|
-
fs12.appendFileSync(eventsPath, JSON.stringify(rollbackEvent)
|
|
45662
|
+
fs12.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
45654
45663
|
`);
|
|
45655
45664
|
} catch (error93) {
|
|
45656
45665
|
console.error("Failed to write rollback event:", error93);
|
|
@@ -51240,7 +51249,7 @@ function validateExtensions(extensions) {
|
|
|
51240
51249
|
}
|
|
51241
51250
|
return { valid: true, value: extensions, error: null };
|
|
51242
51251
|
}
|
|
51243
|
-
async function getGitChurn(days) {
|
|
51252
|
+
async function getGitChurn(days, directory) {
|
|
51244
51253
|
const churnMap = new Map;
|
|
51245
51254
|
const proc = Bun.spawn([
|
|
51246
51255
|
"git",
|
|
@@ -51250,7 +51259,8 @@ async function getGitChurn(days) {
|
|
|
51250
51259
|
"--pretty=format:"
|
|
51251
51260
|
], {
|
|
51252
51261
|
stdout: "pipe",
|
|
51253
|
-
stderr: "pipe"
|
|
51262
|
+
stderr: "pipe",
|
|
51263
|
+
cwd: directory
|
|
51254
51264
|
});
|
|
51255
51265
|
const stdout = await new Response(proc.stdout).text();
|
|
51256
51266
|
await proc.exited;
|
|
@@ -51315,8 +51325,8 @@ function getComplexityForFile(filePath) {
|
|
|
51315
51325
|
return null;
|
|
51316
51326
|
}
|
|
51317
51327
|
}
|
|
51318
|
-
async function analyzeHotspots(days, topN, extensions) {
|
|
51319
|
-
const churnMap = await getGitChurn(days);
|
|
51328
|
+
async function analyzeHotspots(days, topN, extensions, directory) {
|
|
51329
|
+
const churnMap = await getGitChurn(days, directory);
|
|
51320
51330
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
51321
51331
|
const filteredChurn = new Map;
|
|
51322
51332
|
for (const [file3, count] of churnMap) {
|
|
@@ -51326,7 +51336,7 @@ async function analyzeHotspots(days, topN, extensions) {
|
|
|
51326
51336
|
}
|
|
51327
51337
|
}
|
|
51328
51338
|
const hotspots = [];
|
|
51329
|
-
const cwd =
|
|
51339
|
+
const cwd = directory;
|
|
51330
51340
|
let analyzedFiles = 0;
|
|
51331
51341
|
for (const [file3, churnCount] of filteredChurn) {
|
|
51332
51342
|
let fullPath = file3;
|
|
@@ -51378,7 +51388,22 @@ var complexity_hotspots = createSwarmTool({
|
|
|
51378
51388
|
top_n: tool.schema.number().optional().describe("Number of top hotspots to return (default: 20, valid range: 1-100)"),
|
|
51379
51389
|
extensions: tool.schema.string().optional().describe('Comma-separated extensions to include (default: "ts,tsx,js,jsx,py,rs,ps1")')
|
|
51380
51390
|
},
|
|
51381
|
-
async execute(args2,
|
|
51391
|
+
async execute(args2, directory) {
|
|
51392
|
+
if (!directory || typeof directory !== "string" || directory.trim() === "") {
|
|
51393
|
+
const errorResult = {
|
|
51394
|
+
error: "project directory is required but was not provided",
|
|
51395
|
+
analyzedFiles: 0,
|
|
51396
|
+
period: "0 days",
|
|
51397
|
+
hotspots: [],
|
|
51398
|
+
summary: {
|
|
51399
|
+
fullGates: 0,
|
|
51400
|
+
securityReview: 0,
|
|
51401
|
+
enhancedReview: 0,
|
|
51402
|
+
standard: 0
|
|
51403
|
+
}
|
|
51404
|
+
};
|
|
51405
|
+
return JSON.stringify(errorResult, null, 2);
|
|
51406
|
+
}
|
|
51382
51407
|
let daysInput;
|
|
51383
51408
|
let topNInput;
|
|
51384
51409
|
let extensionsInput;
|
|
@@ -51442,7 +51467,7 @@ var complexity_hotspots = createSwarmTool({
|
|
|
51442
51467
|
const topN = topNValidation.value;
|
|
51443
51468
|
const extensions = extensionsValidation.value.split(",").map((e) => e.trim());
|
|
51444
51469
|
try {
|
|
51445
|
-
const result = await analyzeHotspots(days, topN, extensions);
|
|
51470
|
+
const result = await analyzeHotspots(days, topN, extensions, directory);
|
|
51446
51471
|
return JSON.stringify(result, null, 2);
|
|
51447
51472
|
} catch (e) {
|
|
51448
51473
|
const errorResult = {
|
|
@@ -51477,7 +51502,7 @@ var SAFE_REF_PATTERN = /^[a-zA-Z0-9._\-/~^@{}]+$/;
|
|
|
51477
51502
|
var MAX_REF_LENGTH = 256;
|
|
51478
51503
|
var MAX_PATH_LENGTH = 500;
|
|
51479
51504
|
var SHELL_METACHARACTERS2 = /[;|&$`(){}<>!'"]/;
|
|
51480
|
-
var CONTROL_CHAR_PATTERN2 =
|
|
51505
|
+
var CONTROL_CHAR_PATTERN2 = /[\u0000-\u001F\u007F]/;
|
|
51481
51506
|
function validateBase(base) {
|
|
51482
51507
|
if (base.length > MAX_REF_LENGTH) {
|
|
51483
51508
|
return `base ref exceeds maximum length of ${MAX_REF_LENGTH}`;
|
|
@@ -51515,8 +51540,17 @@ var diff = tool({
|
|
|
51515
51540
|
base: tool.schema.string().optional().describe('Base ref to diff against (default: HEAD). Use "staged" for staged changes, "unstaged" for working tree changes.'),
|
|
51516
51541
|
paths: tool.schema.array(tool.schema.string()).optional().describe("Optional file paths to restrict diff scope.")
|
|
51517
51542
|
},
|
|
51518
|
-
async execute(args2,
|
|
51543
|
+
async execute(args2, context) {
|
|
51519
51544
|
try {
|
|
51545
|
+
if (!context.directory || typeof context.directory !== "string" || context.directory.trim() === "") {
|
|
51546
|
+
const errorResult = {
|
|
51547
|
+
error: "project directory is required but was not provided",
|
|
51548
|
+
files: [],
|
|
51549
|
+
contractChanges: [],
|
|
51550
|
+
hasContractChanges: false
|
|
51551
|
+
};
|
|
51552
|
+
return JSON.stringify(errorResult, null, 2);
|
|
51553
|
+
}
|
|
51520
51554
|
const base = args2.base ?? "HEAD";
|
|
51521
51555
|
const baseValidationError = validateBase(base);
|
|
51522
51556
|
if (baseValidationError) {
|
|
@@ -51555,12 +51589,14 @@ var diff = tool({
|
|
|
51555
51589
|
const numstatOutput = execFileSync("git", numstatArgs, {
|
|
51556
51590
|
encoding: "utf-8",
|
|
51557
51591
|
timeout: DIFF_TIMEOUT_MS,
|
|
51558
|
-
maxBuffer: MAX_BUFFER_BYTES
|
|
51592
|
+
maxBuffer: MAX_BUFFER_BYTES,
|
|
51593
|
+
cwd: context.directory
|
|
51559
51594
|
});
|
|
51560
51595
|
const fullDiffOutput = execFileSync("git", fullDiffArgs, {
|
|
51561
51596
|
encoding: "utf-8",
|
|
51562
51597
|
timeout: DIFF_TIMEOUT_MS,
|
|
51563
|
-
maxBuffer: MAX_BUFFER_BYTES
|
|
51598
|
+
maxBuffer: MAX_BUFFER_BYTES,
|
|
51599
|
+
cwd: context.directory
|
|
51564
51600
|
});
|
|
51565
51601
|
const files = [];
|
|
51566
51602
|
const numstatLines = numstatOutput.split(`
|
|
@@ -51610,7 +51646,7 @@ var diff = tool({
|
|
|
51610
51646
|
return JSON.stringify(result, null, 2);
|
|
51611
51647
|
} catch (e) {
|
|
51612
51648
|
const errorResult = {
|
|
51613
|
-
error: e instanceof Error ? `git diff failed: ${e.
|
|
51649
|
+
error: e instanceof Error ? `git diff failed: ${e.message}` : "git diff failed: unknown error",
|
|
51614
51650
|
files: [],
|
|
51615
51651
|
contractChanges: [],
|
|
51616
51652
|
hasContractChanges: false
|
|
@@ -52906,9 +52942,9 @@ function validateArgs3(args2) {
|
|
|
52906
52942
|
}
|
|
52907
52943
|
return true;
|
|
52908
52944
|
}
|
|
52909
|
-
function detectEcosystems() {
|
|
52945
|
+
function detectEcosystems(directory) {
|
|
52910
52946
|
const ecosystems = [];
|
|
52911
|
-
const cwd =
|
|
52947
|
+
const cwd = directory;
|
|
52912
52948
|
if (fs23.existsSync(path34.join(cwd, "package.json"))) {
|
|
52913
52949
|
ecosystems.push("npm");
|
|
52914
52950
|
}
|
|
@@ -52935,13 +52971,13 @@ function detectEcosystems() {
|
|
|
52935
52971
|
}
|
|
52936
52972
|
return ecosystems;
|
|
52937
52973
|
}
|
|
52938
|
-
async function runNpmAudit() {
|
|
52974
|
+
async function runNpmAudit(directory) {
|
|
52939
52975
|
const command = ["npm", "audit", "--json"];
|
|
52940
52976
|
try {
|
|
52941
52977
|
const proc = Bun.spawn(command, {
|
|
52942
52978
|
stdout: "pipe",
|
|
52943
52979
|
stderr: "pipe",
|
|
52944
|
-
cwd:
|
|
52980
|
+
cwd: directory
|
|
52945
52981
|
});
|
|
52946
52982
|
const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
|
|
52947
52983
|
const result = await Promise.race([
|
|
@@ -53058,13 +53094,13 @@ function mapNpmSeverity(severity) {
|
|
|
53058
53094
|
return "info";
|
|
53059
53095
|
}
|
|
53060
53096
|
}
|
|
53061
|
-
async function runPipAudit() {
|
|
53097
|
+
async function runPipAudit(directory) {
|
|
53062
53098
|
const command = ["pip-audit", "--format=json"];
|
|
53063
53099
|
try {
|
|
53064
53100
|
const proc = Bun.spawn(command, {
|
|
53065
53101
|
stdout: "pipe",
|
|
53066
53102
|
stderr: "pipe",
|
|
53067
|
-
cwd:
|
|
53103
|
+
cwd: directory
|
|
53068
53104
|
});
|
|
53069
53105
|
const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
|
|
53070
53106
|
const result = await Promise.race([
|
|
@@ -53189,13 +53225,13 @@ async function runPipAudit() {
|
|
|
53189
53225
|
};
|
|
53190
53226
|
}
|
|
53191
53227
|
}
|
|
53192
|
-
async function runCargoAudit() {
|
|
53228
|
+
async function runCargoAudit(directory) {
|
|
53193
53229
|
const command = ["cargo", "audit", "--json"];
|
|
53194
53230
|
try {
|
|
53195
53231
|
const proc = Bun.spawn(command, {
|
|
53196
53232
|
stdout: "pipe",
|
|
53197
53233
|
stderr: "pipe",
|
|
53198
|
-
cwd:
|
|
53234
|
+
cwd: directory
|
|
53199
53235
|
});
|
|
53200
53236
|
const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
|
|
53201
53237
|
const result = await Promise.race([
|
|
@@ -53303,7 +53339,7 @@ function mapCargoSeverity(cvss) {
|
|
|
53303
53339
|
return "moderate";
|
|
53304
53340
|
return "low";
|
|
53305
53341
|
}
|
|
53306
|
-
async function runGoAudit() {
|
|
53342
|
+
async function runGoAudit(directory) {
|
|
53307
53343
|
const command = ["govulncheck", "-json", "./..."];
|
|
53308
53344
|
if (!isCommandAvailable("govulncheck")) {
|
|
53309
53345
|
warn("[pkg-audit] govulncheck not found, skipping Go audit");
|
|
@@ -53322,7 +53358,7 @@ async function runGoAudit() {
|
|
|
53322
53358
|
const proc = Bun.spawn(command, {
|
|
53323
53359
|
stdout: "pipe",
|
|
53324
53360
|
stderr: "pipe",
|
|
53325
|
-
cwd:
|
|
53361
|
+
cwd: directory
|
|
53326
53362
|
});
|
|
53327
53363
|
const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
|
|
53328
53364
|
const result = await Promise.race([
|
|
@@ -53433,7 +53469,7 @@ async function runGoAudit() {
|
|
|
53433
53469
|
};
|
|
53434
53470
|
}
|
|
53435
53471
|
}
|
|
53436
|
-
async function runDotnetAudit() {
|
|
53472
|
+
async function runDotnetAudit(directory) {
|
|
53437
53473
|
const command = [
|
|
53438
53474
|
"dotnet",
|
|
53439
53475
|
"list",
|
|
@@ -53458,7 +53494,7 @@ async function runDotnetAudit() {
|
|
|
53458
53494
|
const proc = Bun.spawn(command, {
|
|
53459
53495
|
stdout: "pipe",
|
|
53460
53496
|
stderr: "pipe",
|
|
53461
|
-
cwd:
|
|
53497
|
+
cwd: directory
|
|
53462
53498
|
});
|
|
53463
53499
|
const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
|
|
53464
53500
|
const result = await Promise.race([
|
|
@@ -53557,7 +53593,7 @@ function mapDotnetSeverity(severity) {
|
|
|
53557
53593
|
return "info";
|
|
53558
53594
|
}
|
|
53559
53595
|
}
|
|
53560
|
-
async function runBundleAudit() {
|
|
53596
|
+
async function runBundleAudit(directory) {
|
|
53561
53597
|
const useBundleExec = !isCommandAvailable("bundle-audit") && isCommandAvailable("bundle");
|
|
53562
53598
|
if (!isCommandAvailable("bundle-audit") && !isCommandAvailable("bundle")) {
|
|
53563
53599
|
warn("[pkg-audit] bundle-audit not found, skipping Ruby audit");
|
|
@@ -53577,7 +53613,7 @@ async function runBundleAudit() {
|
|
|
53577
53613
|
const proc = Bun.spawn(command, {
|
|
53578
53614
|
stdout: "pipe",
|
|
53579
53615
|
stderr: "pipe",
|
|
53580
|
-
cwd:
|
|
53616
|
+
cwd: directory
|
|
53581
53617
|
});
|
|
53582
53618
|
const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
|
|
53583
53619
|
const result = await Promise.race([
|
|
@@ -53704,7 +53740,7 @@ function mapBundleSeverity(adv) {
|
|
|
53704
53740
|
return "moderate";
|
|
53705
53741
|
return "low";
|
|
53706
53742
|
}
|
|
53707
|
-
async function runDartAudit() {
|
|
53743
|
+
async function runDartAudit(directory) {
|
|
53708
53744
|
const dartBin = isCommandAvailable("dart") ? "dart" : isCommandAvailable("flutter") ? "flutter" : null;
|
|
53709
53745
|
if (!dartBin) {
|
|
53710
53746
|
warn("[pkg-audit] dart/flutter not found, skipping Dart audit");
|
|
@@ -53724,7 +53760,7 @@ async function runDartAudit() {
|
|
|
53724
53760
|
const proc = Bun.spawn(command, {
|
|
53725
53761
|
stdout: "pipe",
|
|
53726
53762
|
stderr: "pipe",
|
|
53727
|
-
cwd:
|
|
53763
|
+
cwd: directory
|
|
53728
53764
|
});
|
|
53729
53765
|
const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
|
|
53730
53766
|
const result = await Promise.race([
|
|
@@ -53823,8 +53859,8 @@ async function runDartAudit() {
|
|
|
53823
53859
|
};
|
|
53824
53860
|
}
|
|
53825
53861
|
}
|
|
53826
|
-
async function runAutoAudit() {
|
|
53827
|
-
const ecosystems = detectEcosystems();
|
|
53862
|
+
async function runAutoAudit(directory) {
|
|
53863
|
+
const ecosystems = detectEcosystems(directory);
|
|
53828
53864
|
if (ecosystems.length === 0) {
|
|
53829
53865
|
return {
|
|
53830
53866
|
ecosystems: [],
|
|
@@ -53839,25 +53875,25 @@ async function runAutoAudit() {
|
|
|
53839
53875
|
for (const eco of ecosystems) {
|
|
53840
53876
|
switch (eco) {
|
|
53841
53877
|
case "npm":
|
|
53842
|
-
results.push(await runNpmAudit());
|
|
53878
|
+
results.push(await runNpmAudit(directory));
|
|
53843
53879
|
break;
|
|
53844
53880
|
case "pip":
|
|
53845
|
-
results.push(await runPipAudit());
|
|
53881
|
+
results.push(await runPipAudit(directory));
|
|
53846
53882
|
break;
|
|
53847
53883
|
case "cargo":
|
|
53848
|
-
results.push(await runCargoAudit());
|
|
53884
|
+
results.push(await runCargoAudit(directory));
|
|
53849
53885
|
break;
|
|
53850
53886
|
case "go":
|
|
53851
|
-
results.push(await runGoAudit());
|
|
53887
|
+
results.push(await runGoAudit(directory));
|
|
53852
53888
|
break;
|
|
53853
53889
|
case "dotnet":
|
|
53854
|
-
results.push(await runDotnetAudit());
|
|
53890
|
+
results.push(await runDotnetAudit(directory));
|
|
53855
53891
|
break;
|
|
53856
53892
|
case "ruby":
|
|
53857
|
-
results.push(await runBundleAudit());
|
|
53893
|
+
results.push(await runBundleAudit(directory));
|
|
53858
53894
|
break;
|
|
53859
53895
|
case "dart":
|
|
53860
|
-
results.push(await runDartAudit());
|
|
53896
|
+
results.push(await runDartAudit(directory));
|
|
53861
53897
|
break;
|
|
53862
53898
|
}
|
|
53863
53899
|
}
|
|
@@ -53883,40 +53919,46 @@ var pkg_audit = createSwarmTool({
|
|
|
53883
53919
|
args: {
|
|
53884
53920
|
ecosystem: tool.schema.enum(["auto", "npm", "pip", "cargo", "go", "dotnet", "ruby", "dart"]).default("auto").describe('Package ecosystem to audit: "auto" (detect from project files), "npm", "pip", "cargo", "go" (govulncheck), "dotnet" (dotnet list package), "ruby" (bundle-audit), or "dart" (dart pub outdated)')
|
|
53885
53921
|
},
|
|
53886
|
-
async execute(args2,
|
|
53922
|
+
async execute(args2, directory) {
|
|
53887
53923
|
if (!validateArgs3(args2)) {
|
|
53888
53924
|
const errorResult = {
|
|
53889
53925
|
error: 'Invalid arguments: ecosystem must be "auto", "npm", "pip", "cargo", "go", "dotnet", "ruby", or "dart"'
|
|
53890
53926
|
};
|
|
53891
53927
|
return JSON.stringify(errorResult, null, 2);
|
|
53892
53928
|
}
|
|
53929
|
+
if (!directory || typeof directory !== "string" || directory.trim() === "") {
|
|
53930
|
+
const errorResult = {
|
|
53931
|
+
error: "project directory is required but was not provided"
|
|
53932
|
+
};
|
|
53933
|
+
return JSON.stringify(errorResult, null, 2);
|
|
53934
|
+
}
|
|
53893
53935
|
const obj = args2;
|
|
53894
53936
|
const ecosystem = obj.ecosystem || "auto";
|
|
53895
53937
|
let result;
|
|
53896
53938
|
switch (ecosystem) {
|
|
53897
53939
|
case "auto":
|
|
53898
|
-
result = await runAutoAudit();
|
|
53940
|
+
result = await runAutoAudit(directory);
|
|
53899
53941
|
break;
|
|
53900
53942
|
case "npm":
|
|
53901
|
-
result = await runNpmAudit();
|
|
53943
|
+
result = await runNpmAudit(directory);
|
|
53902
53944
|
break;
|
|
53903
53945
|
case "pip":
|
|
53904
|
-
result = await runPipAudit();
|
|
53946
|
+
result = await runPipAudit(directory);
|
|
53905
53947
|
break;
|
|
53906
53948
|
case "cargo":
|
|
53907
|
-
result = await runCargoAudit();
|
|
53949
|
+
result = await runCargoAudit(directory);
|
|
53908
53950
|
break;
|
|
53909
53951
|
case "go":
|
|
53910
|
-
result = await runGoAudit();
|
|
53952
|
+
result = await runGoAudit(directory);
|
|
53911
53953
|
break;
|
|
53912
53954
|
case "dotnet":
|
|
53913
|
-
result = await runDotnetAudit();
|
|
53955
|
+
result = await runDotnetAudit(directory);
|
|
53914
53956
|
break;
|
|
53915
53957
|
case "ruby":
|
|
53916
|
-
result = await runBundleAudit();
|
|
53958
|
+
result = await runBundleAudit(directory);
|
|
53917
53959
|
break;
|
|
53918
53960
|
case "dart":
|
|
53919
|
-
result = await runDartAudit();
|
|
53961
|
+
result = await runDartAudit(directory);
|
|
53920
53962
|
break;
|
|
53921
53963
|
}
|
|
53922
53964
|
return JSON.stringify(result, null, 2);
|
|
@@ -56088,7 +56130,7 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
56088
56130
|
duration_ms: Number(process.hrtime.bigint() - start2) / 1e6
|
|
56089
56131
|
};
|
|
56090
56132
|
}
|
|
56091
|
-
const result = await runWithTimeout(runLint(linter, "check"), TOOL_TIMEOUT_MS);
|
|
56133
|
+
const result = await runWithTimeout(runLint(linter, "check", directory), TOOL_TIMEOUT_MS);
|
|
56092
56134
|
return {
|
|
56093
56135
|
ran: true,
|
|
56094
56136
|
result,
|
|
@@ -56104,7 +56146,7 @@ async function runLintWrapped(files, directory, _config) {
|
|
|
56104
56146
|
}
|
|
56105
56147
|
async function runLintOnFiles(linter, files, workspaceDir) {
|
|
56106
56148
|
const isWindows = process.platform === "win32";
|
|
56107
|
-
const binDir = path37.join(
|
|
56149
|
+
const binDir = path37.join(workspaceDir, "node_modules", ".bin");
|
|
56108
56150
|
const validatedFiles = [];
|
|
56109
56151
|
for (const file3 of files) {
|
|
56110
56152
|
if (typeof file3 !== "string") {
|
|
@@ -56137,7 +56179,8 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
56137
56179
|
try {
|
|
56138
56180
|
const proc = Bun.spawn(command, {
|
|
56139
56181
|
stdout: "pipe",
|
|
56140
|
-
stderr: "pipe"
|
|
56182
|
+
stderr: "pipe",
|
|
56183
|
+
cwd: workspaceDir
|
|
56141
56184
|
});
|
|
56142
56185
|
const [stdout, stderr] = await Promise.all([
|
|
56143
56186
|
new Response(proc.stdout).text(),
|
|
@@ -56528,7 +56571,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
56528
56571
|
directory: tool.schema.string().describe('Directory to run checks in (e.g., "." or "./src")'),
|
|
56529
56572
|
sast_threshold: tool.schema.enum(["low", "medium", "high", "critical"]).optional().describe("Minimum severity for SAST findings to cause failure (default: medium)")
|
|
56530
56573
|
},
|
|
56531
|
-
async execute(args2,
|
|
56574
|
+
async execute(args2, directory) {
|
|
56532
56575
|
if (!args2 || typeof args2 !== "object") {
|
|
56533
56576
|
const errorResult = {
|
|
56534
56577
|
gates_passed: false,
|
|
@@ -56544,6 +56587,33 @@ var pre_check_batch = createSwarmTool({
|
|
|
56544
56587
|
};
|
|
56545
56588
|
return JSON.stringify(errorResult, null, 2);
|
|
56546
56589
|
}
|
|
56590
|
+
if (!directory || typeof directory !== "string" || directory.trim() === "") {
|
|
56591
|
+
const errorResult = {
|
|
56592
|
+
gates_passed: false,
|
|
56593
|
+
lint: {
|
|
56594
|
+
ran: false,
|
|
56595
|
+
error: "project directory is required but was not provided",
|
|
56596
|
+
duration_ms: 0
|
|
56597
|
+
},
|
|
56598
|
+
secretscan: {
|
|
56599
|
+
ran: false,
|
|
56600
|
+
error: "project directory is required but was not provided",
|
|
56601
|
+
duration_ms: 0
|
|
56602
|
+
},
|
|
56603
|
+
sast_scan: {
|
|
56604
|
+
ran: false,
|
|
56605
|
+
error: "project directory is required but was not provided",
|
|
56606
|
+
duration_ms: 0
|
|
56607
|
+
},
|
|
56608
|
+
quality_budget: {
|
|
56609
|
+
ran: false,
|
|
56610
|
+
error: "project directory is required but was not provided",
|
|
56611
|
+
duration_ms: 0
|
|
56612
|
+
},
|
|
56613
|
+
total_duration_ms: 0
|
|
56614
|
+
};
|
|
56615
|
+
return JSON.stringify(errorResult, null, 2);
|
|
56616
|
+
}
|
|
56547
56617
|
const typedArgs = args2;
|
|
56548
56618
|
if (!typedArgs.directory) {
|
|
56549
56619
|
const errorResult = {
|
package/dist/tools/lint.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export declare function containsControlChars(str: string): boolean;
|
|
|
29
29
|
export declare function validateArgs(args: unknown): args is {
|
|
30
30
|
mode: 'fix' | 'check';
|
|
31
31
|
};
|
|
32
|
-
export declare function getLinterCommand(linter: SupportedLinter, mode: 'fix' | 'check'): string[];
|
|
32
|
+
export declare function getLinterCommand(linter: SupportedLinter, mode: 'fix' | 'check', projectDir: string): string[];
|
|
33
33
|
/**
|
|
34
34
|
* Build the shell command for an additional (non-JS/TS) linter.
|
|
35
35
|
* cppcheck has no --fix mode; csharp and some others behave differently.
|
|
@@ -41,7 +41,7 @@ export declare function getAdditionalLinterCommand(linter: AdditionalLinter, mod
|
|
|
41
41
|
*/
|
|
42
42
|
export declare function detectAdditionalLinter(cwd: string): 'ruff' | 'clippy' | 'golangci-lint' | 'checkstyle' | 'ktlint' | 'dotnet-format' | 'cppcheck' | 'swiftlint' | 'dart-analyze' | 'rubocop' | null;
|
|
43
43
|
export declare function detectAvailableLinter(): Promise<SupportedLinter | null>;
|
|
44
|
-
export declare function runLint(linter: SupportedLinter, mode: 'fix' | 'check'): Promise<LintResult>;
|
|
44
|
+
export declare function runLint(linter: SupportedLinter, mode: 'fix' | 'check', directory: string): Promise<LintResult>;
|
|
45
45
|
/**
|
|
46
46
|
* Run an additional (non-JS/TS) linter.
|
|
47
47
|
* Follows the same structure as runLint() but uses getAdditionalLinterCommand().
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.20.
|
|
3
|
+
"version": "6.20.1",
|
|
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",
|