opencode-swarm 7.8.0 → 7.9.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 +137 -39
- package/dist/commands/archive.error-handling.test.d.ts +9 -0
- package/dist/commands/benchmark.error-handling.test.d.ts +7 -0
- package/dist/commands/dark-matter.error-handling.test.d.ts +1 -0
- package/dist/commands/handoff.error-handling.adversarial.test.d.ts +1 -0
- package/dist/commands/handoff.error-handling.test.d.ts +1 -0
- package/dist/commands/index.not-found.adversarial.test.d.ts +12 -0
- package/dist/commands/index.not-found.test.d.ts +11 -0
- package/dist/commands/registration-parity.test.d.ts +1 -0
- package/dist/commands/registry.find-similar.adversarial.test.d.ts +1 -0
- package/dist/commands/registry.find-similar.test.d.ts +1 -0
- package/dist/commands/simulate.report-write.adversarial.test.d.ts +1 -0
- package/dist/commands/simulate.report-write.test.d.ts +1 -0
- package/dist/index.js +231 -105
- package/dist/lang/runtime.d.ts +10 -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.9.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",
|
|
@@ -19738,7 +19738,13 @@ async function handleArchiveCommand(directory, args) {
|
|
|
19738
19738
|
const wouldArchiveAge = [];
|
|
19739
19739
|
const remainingBundles = [];
|
|
19740
19740
|
for (const taskId of beforeTaskIds) {
|
|
19741
|
-
|
|
19741
|
+
let result;
|
|
19742
|
+
try {
|
|
19743
|
+
result = await loadEvidence(directory, taskId);
|
|
19744
|
+
} catch (_evidenceErr) {
|
|
19745
|
+
warn("archive: skipping corrupt or unreadable evidence for task", taskId);
|
|
19746
|
+
continue;
|
|
19747
|
+
}
|
|
19742
19748
|
if (result.status !== "found") {
|
|
19743
19749
|
continue;
|
|
19744
19750
|
}
|
|
@@ -19793,6 +19799,7 @@ async function handleArchiveCommand(directory, args) {
|
|
|
19793
19799
|
var init_archive = __esm(() => {
|
|
19794
19800
|
init_loader();
|
|
19795
19801
|
init_manager2();
|
|
19802
|
+
init_utils();
|
|
19796
19803
|
});
|
|
19797
19804
|
|
|
19798
19805
|
// src/db/project-db.ts
|
|
@@ -20799,7 +20806,13 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
20799
20806
|
let totalTestToCodeRatio = 0;
|
|
20800
20807
|
let qualityEvidenceCount = 0;
|
|
20801
20808
|
for (const tid of await listEvidenceTaskIds(directory)) {
|
|
20802
|
-
|
|
20809
|
+
let result;
|
|
20810
|
+
try {
|
|
20811
|
+
result = await loadEvidence(directory, tid);
|
|
20812
|
+
} catch (_evidenceErr) {
|
|
20813
|
+
warn("benchmark: skipping corrupt or unreadable evidence for task", tid);
|
|
20814
|
+
continue;
|
|
20815
|
+
}
|
|
20803
20816
|
if (result.status !== "found")
|
|
20804
20817
|
continue;
|
|
20805
20818
|
for (const e of result.bundle.entries) {
|
|
@@ -37201,7 +37214,17 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
37201
37214
|
i++;
|
|
37202
37215
|
}
|
|
37203
37216
|
}
|
|
37204
|
-
|
|
37217
|
+
let pairs;
|
|
37218
|
+
try {
|
|
37219
|
+
pairs = await _internals10.detectDarkMatter(directory, options);
|
|
37220
|
+
} catch (err) {
|
|
37221
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
37222
|
+
return `## Dark Matter Analysis Failed
|
|
37223
|
+
|
|
37224
|
+
Error analyzing git history: ${errMsg}
|
|
37225
|
+
|
|
37226
|
+
Ensure this is a git repository with commit history.`;
|
|
37227
|
+
}
|
|
37205
37228
|
const output = formatDarkMatterOutput(pairs);
|
|
37206
37229
|
if (pairs.length > 0) {
|
|
37207
37230
|
try {
|
|
@@ -41607,22 +41630,37 @@ var init_handoff_service = __esm(() => {
|
|
|
41607
41630
|
|
|
41608
41631
|
// src/commands/handoff.ts
|
|
41609
41632
|
import crypto4 from "crypto";
|
|
41610
|
-
import { renameSync as renameSync7 } from "fs";
|
|
41633
|
+
import { renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
|
|
41611
41634
|
async function handleHandoffCommand(directory, _args) {
|
|
41612
41635
|
const handoffData = await getHandoffData(directory);
|
|
41613
41636
|
const markdown = formatHandoffMarkdown(handoffData);
|
|
41614
|
-
|
|
41615
|
-
|
|
41616
|
-
|
|
41617
|
-
|
|
41618
|
-
|
|
41619
|
-
|
|
41620
|
-
|
|
41621
|
-
|
|
41622
|
-
|
|
41623
|
-
|
|
41624
|
-
|
|
41625
|
-
|
|
41637
|
+
try {
|
|
41638
|
+
const resolvedPath = validateSwarmPath(directory, "handoff.md");
|
|
41639
|
+
const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
|
|
41640
|
+
await bunWrite(tempPath, markdown);
|
|
41641
|
+
try {
|
|
41642
|
+
renameSync7(tempPath, resolvedPath);
|
|
41643
|
+
} catch (renameErr) {
|
|
41644
|
+
try {
|
|
41645
|
+
unlinkSync4(tempPath);
|
|
41646
|
+
} catch {}
|
|
41647
|
+
throw renameErr;
|
|
41648
|
+
}
|
|
41649
|
+
const continuationPrompt = formatContinuationPrompt(handoffData);
|
|
41650
|
+
const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
|
|
41651
|
+
const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
|
|
41652
|
+
await bunWrite(promptTempPath, continuationPrompt);
|
|
41653
|
+
try {
|
|
41654
|
+
renameSync7(promptTempPath, promptPath);
|
|
41655
|
+
} catch (renameErr) {
|
|
41656
|
+
try {
|
|
41657
|
+
unlinkSync4(promptTempPath);
|
|
41658
|
+
} catch {}
|
|
41659
|
+
throw renameErr;
|
|
41660
|
+
}
|
|
41661
|
+
await writeSnapshot(directory, swarmState);
|
|
41662
|
+
await flushPendingSnapshot(directory);
|
|
41663
|
+
return `## Handoff Brief Written
|
|
41626
41664
|
|
|
41627
41665
|
Brief written to \`.swarm/handoff.md\`.
|
|
41628
41666
|
Continuation prompt written to \`.swarm/handoff-prompt.md\`.
|
|
@@ -41636,6 +41674,16 @@ ${markdown}
|
|
|
41636
41674
|
Copy and paste the block below into your next session to resume cleanly:
|
|
41637
41675
|
|
|
41638
41676
|
${continuationPrompt}`;
|
|
41677
|
+
} catch (err) {
|
|
41678
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
41679
|
+
return `## Handoff Generated (file write failed)
|
|
41680
|
+
|
|
41681
|
+
Handoff data was generated but could not be written to disk: ${errMsg}
|
|
41682
|
+
|
|
41683
|
+
The handoff content is included below for manual copy:
|
|
41684
|
+
|
|
41685
|
+
${markdown}`;
|
|
41686
|
+
}
|
|
41639
41687
|
}
|
|
41640
41688
|
var init_handoff = __esm(() => {
|
|
41641
41689
|
init_utils2();
|
|
@@ -47722,7 +47770,19 @@ async function handleSimulateCommand(directory, args) {
|
|
|
47722
47770
|
options.minCommits = val;
|
|
47723
47771
|
}
|
|
47724
47772
|
}
|
|
47725
|
-
|
|
47773
|
+
let darkMatterPairs;
|
|
47774
|
+
try {
|
|
47775
|
+
darkMatterPairs = await _internals10.detectDarkMatter(directory, options);
|
|
47776
|
+
} catch (err) {
|
|
47777
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
47778
|
+
return `## Simulate Report
|
|
47779
|
+
|
|
47780
|
+
### Error
|
|
47781
|
+
|
|
47782
|
+
Error analyzing git history: ${errMsg}
|
|
47783
|
+
|
|
47784
|
+
Ensure this is a git repository with commit history.`;
|
|
47785
|
+
}
|
|
47726
47786
|
const reportLines = [
|
|
47727
47787
|
"# Simulate Report",
|
|
47728
47788
|
"",
|
|
@@ -47740,15 +47800,21 @@ async function handleSimulateCommand(directory, args) {
|
|
|
47740
47800
|
];
|
|
47741
47801
|
const report = reportLines.filter(Boolean).join(`
|
|
47742
47802
|
`);
|
|
47743
|
-
|
|
47744
|
-
|
|
47745
|
-
|
|
47746
|
-
|
|
47747
|
-
|
|
47803
|
+
try {
|
|
47804
|
+
const fs22 = await import("fs/promises");
|
|
47805
|
+
const path37 = await import("path");
|
|
47806
|
+
const reportPath = path37.join(directory, ".swarm", "simulate-report.md");
|
|
47807
|
+
await fs22.mkdir(path37.dirname(reportPath), { recursive: true });
|
|
47808
|
+
await fs22.writeFile(reportPath, report, "utf-8");
|
|
47809
|
+
} catch (err) {
|
|
47810
|
+
const writeErr = err instanceof Error ? err.message : String(err);
|
|
47811
|
+
warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
|
|
47812
|
+
}
|
|
47748
47813
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
47749
47814
|
}
|
|
47750
47815
|
var init_simulate = __esm(() => {
|
|
47751
47816
|
init_co_change_analyzer();
|
|
47817
|
+
init_utils();
|
|
47752
47818
|
});
|
|
47753
47819
|
|
|
47754
47820
|
// src/commands/specify.ts
|
|
@@ -48195,12 +48261,6 @@ function buildHelpText() {
|
|
|
48195
48261
|
return lines.join(`
|
|
48196
48262
|
`);
|
|
48197
48263
|
}
|
|
48198
|
-
function getHelpText() {
|
|
48199
|
-
if (!_helpText) {
|
|
48200
|
-
_helpText = buildHelpText();
|
|
48201
|
-
}
|
|
48202
|
-
return _helpText;
|
|
48203
|
-
}
|
|
48204
48264
|
function createSwarmCommandHandler(directory, agents) {
|
|
48205
48265
|
return async (input, output) => {
|
|
48206
48266
|
if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
|
|
@@ -48226,7 +48286,22 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
48226
48286
|
let text;
|
|
48227
48287
|
const resolved = resolveCommand(tokens);
|
|
48228
48288
|
if (!resolved) {
|
|
48229
|
-
|
|
48289
|
+
if (tokens.length === 0) {
|
|
48290
|
+
text = buildHelpText();
|
|
48291
|
+
} else {
|
|
48292
|
+
const attemptedCommand = tokens[0] || "";
|
|
48293
|
+
const MAX_DISPLAY = 100;
|
|
48294
|
+
const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
|
|
48295
|
+
const similar = _internals19.findSimilarCommands(attemptedCommand);
|
|
48296
|
+
const header = `Command \`/swarm ${displayCommand}\` not found.`;
|
|
48297
|
+
const suggestions = similar.length > 0 ? `Did you mean:
|
|
48298
|
+
${similar.map((cmd) => ` \u2022 /swarm ${cmd}`).join(`
|
|
48299
|
+
`)}` : "";
|
|
48300
|
+
const footer = "Run `/swarm help` for all commands.";
|
|
48301
|
+
text = [header, suggestions, footer].filter(Boolean).join(`
|
|
48302
|
+
|
|
48303
|
+
`);
|
|
48304
|
+
}
|
|
48230
48305
|
} else {
|
|
48231
48306
|
try {
|
|
48232
48307
|
text = await resolved.entry.handler({
|
|
@@ -48258,7 +48333,6 @@ ${text}`;
|
|
|
48258
48333
|
];
|
|
48259
48334
|
};
|
|
48260
48335
|
}
|
|
48261
|
-
var _helpText;
|
|
48262
48336
|
var init_commands = __esm(() => {
|
|
48263
48337
|
init_registry();
|
|
48264
48338
|
init_acknowledge_spec_drift();
|
|
@@ -48318,14 +48392,38 @@ function levenshteinDistance(a, b) {
|
|
|
48318
48392
|
}
|
|
48319
48393
|
function findSimilarCommands(query) {
|
|
48320
48394
|
const q = query.toLowerCase();
|
|
48321
|
-
|
|
48322
|
-
|
|
48323
|
-
|
|
48324
|
-
|
|
48325
|
-
|
|
48326
|
-
|
|
48327
|
-
|
|
48328
|
-
|
|
48395
|
+
if (q.length > 500) {
|
|
48396
|
+
return [];
|
|
48397
|
+
}
|
|
48398
|
+
const scored = VALID_COMMANDS.map((cmd) => {
|
|
48399
|
+
const cmdLower = cmd.toLowerCase();
|
|
48400
|
+
const fullScore = _internals19.levenshteinDistance(q, cmdLower);
|
|
48401
|
+
let tokenScore = Infinity;
|
|
48402
|
+
if (cmd.includes(" ") || cmd.includes("-")) {
|
|
48403
|
+
const qTokens = q.split(/[\s-]+/);
|
|
48404
|
+
const cmdTokens = cmdLower.split(/[\s-]+/);
|
|
48405
|
+
let totalTokenDist = 0;
|
|
48406
|
+
for (const qt of qTokens) {
|
|
48407
|
+
if (qt.length === 0)
|
|
48408
|
+
continue;
|
|
48409
|
+
let minDist = Infinity;
|
|
48410
|
+
for (const ct of cmdTokens) {
|
|
48411
|
+
if (ct.length === 0)
|
|
48412
|
+
continue;
|
|
48413
|
+
const dist = _internals19.levenshteinDistance(qt, ct);
|
|
48414
|
+
if (dist < minDist)
|
|
48415
|
+
minDist = dist;
|
|
48416
|
+
}
|
|
48417
|
+
totalTokenDist += minDist;
|
|
48418
|
+
}
|
|
48419
|
+
tokenScore = totalTokenDist;
|
|
48420
|
+
}
|
|
48421
|
+
const dashStrippedQ = q.replace(/-/g, "");
|
|
48422
|
+
const dashStrippedCmd = cmdLower.replace(/-/g, "");
|
|
48423
|
+
const dashScore = _internals19.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
|
|
48424
|
+
const score = Math.min(fullScore, tokenScore, dashScore);
|
|
48425
|
+
return { cmd, score };
|
|
48426
|
+
});
|
|
48329
48427
|
scored.sort((a, b) => a.score - b.score);
|
|
48330
48428
|
return scored.slice(0, 3).map((s) => s.cmd);
|
|
48331
48429
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for archive.ts graceful handling of corrupt evidence files (Task 1.6)
|
|
3
|
+
*
|
|
4
|
+
* Verifies that the try/catch in handleArchiveCommand's dry-run loop
|
|
5
|
+
* catches exceptions from loadEvidence and skips corrupt/unreadable files.
|
|
6
|
+
*
|
|
7
|
+
* Uses real filesystem operations like existing archive tests.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adversarial security tests for command-not-found UX in createSwarmCommandHandler.
|
|
3
|
+
*
|
|
4
|
+
* Attack vectors covered:
|
|
5
|
+
* 1. Very long command name (10000+ chars) — does it hang or crash?
|
|
6
|
+
* 2. Command with special characters (script injection, shell injection, template literals)
|
|
7
|
+
* 3. Command with newlines/embedded control chars — does it break output format?
|
|
8
|
+
* 4. Command with unicode/emoji — handled gracefully?
|
|
9
|
+
* 5. Extremely deep tokens array (1000 elements) — does findSimilarCommands handle it?
|
|
10
|
+
* 6. Null bytes in command name
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for command-not-found UX improvement in createSwarmCommandHandler.
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* - Unknown single-word command shows "Command not found" + suggestions + footer
|
|
6
|
+
* - Unknown compound command shows header with command name
|
|
7
|
+
* - Empty tokens (empty array) → returns buildHelpText() output
|
|
8
|
+
* - Command with no similar matches → shows header + footer only (no "Did you mean" section)
|
|
9
|
+
* - Multiple similar commands returned → all shown with bullet format
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
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.9.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",
|
|
@@ -20405,7 +20405,13 @@ async function handleArchiveCommand(directory, args2) {
|
|
|
20405
20405
|
const wouldArchiveAge = [];
|
|
20406
20406
|
const remainingBundles = [];
|
|
20407
20407
|
for (const taskId of beforeTaskIds) {
|
|
20408
|
-
|
|
20408
|
+
let result;
|
|
20409
|
+
try {
|
|
20410
|
+
result = await loadEvidence(directory, taskId);
|
|
20411
|
+
} catch (_evidenceErr) {
|
|
20412
|
+
warn("archive: skipping corrupt or unreadable evidence for task", taskId);
|
|
20413
|
+
continue;
|
|
20414
|
+
}
|
|
20409
20415
|
if (result.status !== "found") {
|
|
20410
20416
|
continue;
|
|
20411
20417
|
}
|
|
@@ -20460,6 +20466,7 @@ async function handleArchiveCommand(directory, args2) {
|
|
|
20460
20466
|
var init_archive = __esm(() => {
|
|
20461
20467
|
init_loader();
|
|
20462
20468
|
init_manager2();
|
|
20469
|
+
init_utils();
|
|
20463
20470
|
});
|
|
20464
20471
|
|
|
20465
20472
|
// src/db/project-db.ts
|
|
@@ -27228,7 +27235,13 @@ async function handleBenchmarkCommand(directory, args2) {
|
|
|
27228
27235
|
let totalTestToCodeRatio = 0;
|
|
27229
27236
|
let qualityEvidenceCount = 0;
|
|
27230
27237
|
for (const tid of await listEvidenceTaskIds(directory)) {
|
|
27231
|
-
|
|
27238
|
+
let result;
|
|
27239
|
+
try {
|
|
27240
|
+
result = await loadEvidence(directory, tid);
|
|
27241
|
+
} catch (_evidenceErr) {
|
|
27242
|
+
warn("benchmark: skipping corrupt or unreadable evidence for task", tid);
|
|
27243
|
+
continue;
|
|
27244
|
+
}
|
|
27232
27245
|
if (result.status !== "found")
|
|
27233
27246
|
continue;
|
|
27234
27247
|
for (const e of result.bundle.entries) {
|
|
@@ -43835,8 +43848,10 @@ async function runCuratorInit(directory, config3, llmDelegate) {
|
|
|
43835
43848
|
const timer = setTimeout(() => ac.abort(), timeoutMs);
|
|
43836
43849
|
let llmOutput;
|
|
43837
43850
|
try {
|
|
43851
|
+
const delegatePromise = llmDelegate(systemPrompt, userInput, ac.signal);
|
|
43852
|
+
delegatePromise.catch(() => {});
|
|
43838
43853
|
llmOutput = await Promise.race([
|
|
43839
|
-
|
|
43854
|
+
delegatePromise,
|
|
43840
43855
|
new Promise((_, reject) => {
|
|
43841
43856
|
ac.signal.addEventListener("abort", () => reject(new Error("CURATOR_LLM_TIMEOUT")));
|
|
43842
43857
|
})
|
|
@@ -43963,8 +43978,10 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config3, _kno
|
|
|
43963
43978
|
const timer = setTimeout(() => ac.abort(), timeoutMs);
|
|
43964
43979
|
let llmOutput;
|
|
43965
43980
|
try {
|
|
43981
|
+
const delegatePromise = llmDelegate(systemPrompt, userInput, ac.signal);
|
|
43982
|
+
delegatePromise.catch(() => {});
|
|
43966
43983
|
llmOutput = await Promise.race([
|
|
43967
|
-
|
|
43984
|
+
delegatePromise,
|
|
43968
43985
|
new Promise((_, reject) => {
|
|
43969
43986
|
ac.signal.addEventListener("abort", () => reject(new Error("CURATOR_LLM_TIMEOUT")));
|
|
43970
43987
|
})
|
|
@@ -44900,7 +44917,17 @@ async function handleDarkMatterCommand(directory, args2) {
|
|
|
44900
44917
|
i2++;
|
|
44901
44918
|
}
|
|
44902
44919
|
}
|
|
44903
|
-
|
|
44920
|
+
let pairs;
|
|
44921
|
+
try {
|
|
44922
|
+
pairs = await _internals15.detectDarkMatter(directory, options);
|
|
44923
|
+
} catch (err2) {
|
|
44924
|
+
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
44925
|
+
return `## Dark Matter Analysis Failed
|
|
44926
|
+
|
|
44927
|
+
Error analyzing git history: ${errMsg}
|
|
44928
|
+
|
|
44929
|
+
Ensure this is a git repository with commit history.`;
|
|
44930
|
+
}
|
|
44904
44931
|
const output = formatDarkMatterOutput(pairs);
|
|
44905
44932
|
if (pairs.length > 0) {
|
|
44906
44933
|
try {
|
|
@@ -49483,22 +49510,37 @@ var init_handoff_service = __esm(() => {
|
|
|
49483
49510
|
|
|
49484
49511
|
// src/commands/handoff.ts
|
|
49485
49512
|
import crypto4 from "node:crypto";
|
|
49486
|
-
import { renameSync as renameSync10 } from "node:fs";
|
|
49513
|
+
import { renameSync as renameSync10, unlinkSync as unlinkSync5 } from "node:fs";
|
|
49487
49514
|
async function handleHandoffCommand(directory, _args) {
|
|
49488
49515
|
const handoffData = await getHandoffData(directory);
|
|
49489
49516
|
const markdown = formatHandoffMarkdown(handoffData);
|
|
49490
|
-
|
|
49491
|
-
|
|
49492
|
-
|
|
49493
|
-
|
|
49494
|
-
|
|
49495
|
-
|
|
49496
|
-
|
|
49497
|
-
|
|
49498
|
-
|
|
49499
|
-
|
|
49500
|
-
|
|
49501
|
-
|
|
49517
|
+
try {
|
|
49518
|
+
const resolvedPath = validateSwarmPath(directory, "handoff.md");
|
|
49519
|
+
const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
|
|
49520
|
+
await bunWrite(tempPath, markdown);
|
|
49521
|
+
try {
|
|
49522
|
+
renameSync10(tempPath, resolvedPath);
|
|
49523
|
+
} catch (renameErr) {
|
|
49524
|
+
try {
|
|
49525
|
+
unlinkSync5(tempPath);
|
|
49526
|
+
} catch {}
|
|
49527
|
+
throw renameErr;
|
|
49528
|
+
}
|
|
49529
|
+
const continuationPrompt = formatContinuationPrompt(handoffData);
|
|
49530
|
+
const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
|
|
49531
|
+
const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
|
|
49532
|
+
await bunWrite(promptTempPath, continuationPrompt);
|
|
49533
|
+
try {
|
|
49534
|
+
renameSync10(promptTempPath, promptPath);
|
|
49535
|
+
} catch (renameErr) {
|
|
49536
|
+
try {
|
|
49537
|
+
unlinkSync5(promptTempPath);
|
|
49538
|
+
} catch {}
|
|
49539
|
+
throw renameErr;
|
|
49540
|
+
}
|
|
49541
|
+
await writeSnapshot(directory, swarmState);
|
|
49542
|
+
await flushPendingSnapshot(directory);
|
|
49543
|
+
return `## Handoff Brief Written
|
|
49502
49544
|
|
|
49503
49545
|
Brief written to \`.swarm/handoff.md\`.
|
|
49504
49546
|
Continuation prompt written to \`.swarm/handoff-prompt.md\`.
|
|
@@ -49512,6 +49554,16 @@ ${markdown}
|
|
|
49512
49554
|
Copy and paste the block below into your next session to resume cleanly:
|
|
49513
49555
|
|
|
49514
49556
|
${continuationPrompt}`;
|
|
49557
|
+
} catch (err2) {
|
|
49558
|
+
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
49559
|
+
return `## Handoff Generated (file write failed)
|
|
49560
|
+
|
|
49561
|
+
Handoff data was generated but could not be written to disk: ${errMsg}
|
|
49562
|
+
|
|
49563
|
+
The handoff content is included below for manual copy:
|
|
49564
|
+
|
|
49565
|
+
${markdown}`;
|
|
49566
|
+
}
|
|
49515
49567
|
}
|
|
49516
49568
|
var init_handoff = __esm(() => {
|
|
49517
49569
|
init_utils2();
|
|
@@ -55708,7 +55760,19 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
55708
55760
|
options.minCommits = val;
|
|
55709
55761
|
}
|
|
55710
55762
|
}
|
|
55711
|
-
|
|
55763
|
+
let darkMatterPairs;
|
|
55764
|
+
try {
|
|
55765
|
+
darkMatterPairs = await _internals15.detectDarkMatter(directory, options);
|
|
55766
|
+
} catch (err2) {
|
|
55767
|
+
const errMsg = err2 instanceof Error ? err2.message : String(err2);
|
|
55768
|
+
return `## Simulate Report
|
|
55769
|
+
|
|
55770
|
+
### Error
|
|
55771
|
+
|
|
55772
|
+
Error analyzing git history: ${errMsg}
|
|
55773
|
+
|
|
55774
|
+
Ensure this is a git repository with commit history.`;
|
|
55775
|
+
}
|
|
55712
55776
|
const reportLines = [
|
|
55713
55777
|
"# Simulate Report",
|
|
55714
55778
|
"",
|
|
@@ -55726,15 +55790,21 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
55726
55790
|
];
|
|
55727
55791
|
const report = reportLines.filter(Boolean).join(`
|
|
55728
55792
|
`);
|
|
55729
|
-
|
|
55730
|
-
|
|
55731
|
-
|
|
55732
|
-
|
|
55733
|
-
|
|
55793
|
+
try {
|
|
55794
|
+
const fs29 = await import("node:fs/promises");
|
|
55795
|
+
const path44 = await import("node:path");
|
|
55796
|
+
const reportPath = path44.join(directory, ".swarm", "simulate-report.md");
|
|
55797
|
+
await fs29.mkdir(path44.dirname(reportPath), { recursive: true });
|
|
55798
|
+
await fs29.writeFile(reportPath, report, "utf-8");
|
|
55799
|
+
} catch (err2) {
|
|
55800
|
+
const writeErr = err2 instanceof Error ? err2.message : String(err2);
|
|
55801
|
+
warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
|
|
55802
|
+
}
|
|
55734
55803
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
55735
55804
|
}
|
|
55736
55805
|
var init_simulate = __esm(() => {
|
|
55737
55806
|
init_co_change_analyzer();
|
|
55807
|
+
init_utils();
|
|
55738
55808
|
});
|
|
55739
55809
|
|
|
55740
55810
|
// src/commands/specify.ts
|
|
@@ -56396,12 +56466,6 @@ function buildHelpText() {
|
|
|
56396
56466
|
return lines.join(`
|
|
56397
56467
|
`);
|
|
56398
56468
|
}
|
|
56399
|
-
function getHelpText() {
|
|
56400
|
-
if (!_helpText) {
|
|
56401
|
-
_helpText = buildHelpText();
|
|
56402
|
-
}
|
|
56403
|
-
return _helpText;
|
|
56404
|
-
}
|
|
56405
56469
|
function createSwarmCommandHandler(directory, agents) {
|
|
56406
56470
|
return async (input, output) => {
|
|
56407
56471
|
if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
|
|
@@ -56427,7 +56491,22 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
56427
56491
|
let text;
|
|
56428
56492
|
const resolved = resolveCommand(tokens);
|
|
56429
56493
|
if (!resolved) {
|
|
56430
|
-
|
|
56494
|
+
if (tokens.length === 0) {
|
|
56495
|
+
text = buildHelpText();
|
|
56496
|
+
} else {
|
|
56497
|
+
const attemptedCommand = tokens[0] || "";
|
|
56498
|
+
const MAX_DISPLAY = 100;
|
|
56499
|
+
const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
|
|
56500
|
+
const similar = _internals24.findSimilarCommands(attemptedCommand);
|
|
56501
|
+
const header = `Command \`/swarm ${displayCommand}\` not found.`;
|
|
56502
|
+
const suggestions = similar.length > 0 ? `Did you mean:
|
|
56503
|
+
${similar.map((cmd) => ` • /swarm ${cmd}`).join(`
|
|
56504
|
+
`)}` : "";
|
|
56505
|
+
const footer = "Run `/swarm help` for all commands.";
|
|
56506
|
+
text = [header, suggestions, footer].filter(Boolean).join(`
|
|
56507
|
+
|
|
56508
|
+
`);
|
|
56509
|
+
}
|
|
56431
56510
|
} else {
|
|
56432
56511
|
try {
|
|
56433
56512
|
text = await resolved.entry.handler({
|
|
@@ -56459,7 +56538,6 @@ ${text}`;
|
|
|
56459
56538
|
];
|
|
56460
56539
|
};
|
|
56461
56540
|
}
|
|
56462
|
-
var _helpText;
|
|
56463
56541
|
var init_commands = __esm(() => {
|
|
56464
56542
|
init_registry();
|
|
56465
56543
|
init_acknowledge_spec_drift();
|
|
@@ -56519,14 +56597,38 @@ function levenshteinDistance(a, b) {
|
|
|
56519
56597
|
}
|
|
56520
56598
|
function findSimilarCommands(query) {
|
|
56521
56599
|
const q = query.toLowerCase();
|
|
56522
|
-
|
|
56523
|
-
|
|
56524
|
-
|
|
56525
|
-
|
|
56526
|
-
|
|
56527
|
-
|
|
56528
|
-
|
|
56529
|
-
|
|
56600
|
+
if (q.length > 500) {
|
|
56601
|
+
return [];
|
|
56602
|
+
}
|
|
56603
|
+
const scored = VALID_COMMANDS.map((cmd) => {
|
|
56604
|
+
const cmdLower = cmd.toLowerCase();
|
|
56605
|
+
const fullScore = _internals24.levenshteinDistance(q, cmdLower);
|
|
56606
|
+
let tokenScore = Infinity;
|
|
56607
|
+
if (cmd.includes(" ") || cmd.includes("-")) {
|
|
56608
|
+
const qTokens = q.split(/[\s-]+/);
|
|
56609
|
+
const cmdTokens = cmdLower.split(/[\s-]+/);
|
|
56610
|
+
let totalTokenDist = 0;
|
|
56611
|
+
for (const qt of qTokens) {
|
|
56612
|
+
if (qt.length === 0)
|
|
56613
|
+
continue;
|
|
56614
|
+
let minDist = Infinity;
|
|
56615
|
+
for (const ct of cmdTokens) {
|
|
56616
|
+
if (ct.length === 0)
|
|
56617
|
+
continue;
|
|
56618
|
+
const dist = _internals24.levenshteinDistance(qt, ct);
|
|
56619
|
+
if (dist < minDist)
|
|
56620
|
+
minDist = dist;
|
|
56621
|
+
}
|
|
56622
|
+
totalTokenDist += minDist;
|
|
56623
|
+
}
|
|
56624
|
+
tokenScore = totalTokenDist;
|
|
56625
|
+
}
|
|
56626
|
+
const dashStrippedQ = q.replace(/-/g, "");
|
|
56627
|
+
const dashStrippedCmd = cmdLower.replace(/-/g, "");
|
|
56628
|
+
const dashScore = _internals24.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
|
|
56629
|
+
const score = Math.min(fullScore, tokenScore, dashScore);
|
|
56630
|
+
return { cmd, score };
|
|
56631
|
+
});
|
|
56530
56632
|
scored.sort((a, b) => a.score - b.score);
|
|
56531
56633
|
return scored.slice(0, 3).map((s) => s.cmd);
|
|
56532
56634
|
}
|
|
@@ -65345,27 +65447,32 @@ __export(exports_runtime, {
|
|
|
65345
65447
|
isGrammarAvailable: () => isGrammarAvailable,
|
|
65346
65448
|
getSupportedLanguages: () => getSupportedLanguages,
|
|
65347
65449
|
getInitializedLanguages: () => getInitializedLanguages,
|
|
65348
|
-
clearParserCache: () => clearParserCache
|
|
65450
|
+
clearParserCache: () => clearParserCache,
|
|
65451
|
+
_internals: () => _internals25
|
|
65349
65452
|
});
|
|
65350
65453
|
import * as path67 from "node:path";
|
|
65351
65454
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
65352
65455
|
async function initTreeSitter() {
|
|
65353
|
-
if (
|
|
65354
|
-
|
|
65355
|
-
|
|
65356
|
-
|
|
65357
|
-
|
|
65358
|
-
|
|
65359
|
-
|
|
65360
|
-
|
|
65361
|
-
|
|
65362
|
-
|
|
65363
|
-
|
|
65364
|
-
|
|
65456
|
+
if (!treeSitterInitPromise) {
|
|
65457
|
+
treeSitterInitPromise = (async () => {
|
|
65458
|
+
const thisDir = path67.dirname(fileURLToPath2(import.meta.url));
|
|
65459
|
+
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
|
|
65460
|
+
if (isSource) {
|
|
65461
|
+
await _internals25.parserInit();
|
|
65462
|
+
} else {
|
|
65463
|
+
const grammarsDir = getGrammarsDirAbsolute();
|
|
65464
|
+
await _internals25.parserInit({
|
|
65465
|
+
locateFile(scriptName) {
|
|
65466
|
+
return path67.join(grammarsDir, scriptName);
|
|
65467
|
+
}
|
|
65468
|
+
});
|
|
65365
65469
|
}
|
|
65470
|
+
})().catch((err2) => {
|
|
65471
|
+
treeSitterInitPromise = null;
|
|
65472
|
+
throw err2;
|
|
65366
65473
|
});
|
|
65367
65474
|
}
|
|
65368
|
-
|
|
65475
|
+
return treeSitterInitPromise;
|
|
65369
65476
|
}
|
|
65370
65477
|
function sanitizeLanguageId(languageId) {
|
|
65371
65478
|
const normalized = languageId.toLowerCase();
|
|
@@ -65448,7 +65555,7 @@ async function isGrammarAvailable(languageId) {
|
|
|
65448
65555
|
function clearParserCache() {
|
|
65449
65556
|
parserCache.clear();
|
|
65450
65557
|
initializedLanguages.clear();
|
|
65451
|
-
|
|
65558
|
+
treeSitterInitPromise = null;
|
|
65452
65559
|
}
|
|
65453
65560
|
function getInitializedLanguages() {
|
|
65454
65561
|
return Array.from(initializedLanguages);
|
|
@@ -65456,11 +65563,14 @@ function getInitializedLanguages() {
|
|
|
65456
65563
|
function getSupportedLanguages() {
|
|
65457
65564
|
return Object.keys(LANGUAGE_WASM_MAP);
|
|
65458
65565
|
}
|
|
65459
|
-
var parserCache, initializedLanguages,
|
|
65566
|
+
var parserCache, initializedLanguages, treeSitterInitPromise = null, _internals25, LANGUAGE_WASM_MAP;
|
|
65460
65567
|
var init_runtime = __esm(() => {
|
|
65461
65568
|
init_tree_sitter();
|
|
65462
65569
|
parserCache = new Map;
|
|
65463
65570
|
initializedLanguages = new Set;
|
|
65571
|
+
_internals25 = {
|
|
65572
|
+
parserInit: Parser.init
|
|
65573
|
+
};
|
|
65464
65574
|
LANGUAGE_WASM_MAP = {
|
|
65465
65575
|
javascript: "tree-sitter-javascript.wasm",
|
|
65466
65576
|
typescript: "tree-sitter-typescript.wasm",
|
|
@@ -65878,9 +65988,9 @@ var init_doc_scan = __esm(() => {
|
|
|
65878
65988
|
var exports_knowledge_recall = {};
|
|
65879
65989
|
__export(exports_knowledge_recall, {
|
|
65880
65990
|
knowledge_recall: () => knowledge_recall,
|
|
65881
|
-
_internals: () =>
|
|
65991
|
+
_internals: () => _internals26
|
|
65882
65992
|
});
|
|
65883
|
-
var knowledge_recall,
|
|
65993
|
+
var knowledge_recall, _internals26;
|
|
65884
65994
|
var init_knowledge_recall = __esm(() => {
|
|
65885
65995
|
init_zod();
|
|
65886
65996
|
init_knowledge_store();
|
|
@@ -65966,7 +66076,7 @@ var init_knowledge_recall = __esm(() => {
|
|
|
65966
66076
|
return JSON.stringify(result);
|
|
65967
66077
|
}
|
|
65968
66078
|
});
|
|
65969
|
-
|
|
66079
|
+
_internals26 = {
|
|
65970
66080
|
knowledge_recall
|
|
65971
66081
|
};
|
|
65972
66082
|
});
|
|
@@ -66021,7 +66131,7 @@ __export(exports_curator_drift, {
|
|
|
66021
66131
|
runDeterministicDriftCheck: () => runDeterministicDriftCheck,
|
|
66022
66132
|
readPriorDriftReports: () => readPriorDriftReports,
|
|
66023
66133
|
buildDriftInjectionText: () => buildDriftInjectionText,
|
|
66024
|
-
_internals: () =>
|
|
66134
|
+
_internals: () => _internals28
|
|
66025
66135
|
});
|
|
66026
66136
|
import * as fs54 from "node:fs";
|
|
66027
66137
|
import * as path73 from "node:path";
|
|
@@ -66066,7 +66176,7 @@ async function runDeterministicDriftCheck(directory, phase, curatorResult, confi
|
|
|
66066
66176
|
try {
|
|
66067
66177
|
const planMd = await readSwarmFileAsync(directory, "plan.md");
|
|
66068
66178
|
const specMd = await readSwarmFileAsync(directory, "spec.md");
|
|
66069
|
-
const priorReports = await
|
|
66179
|
+
const priorReports = await _internals28.readPriorDriftReports(directory);
|
|
66070
66180
|
const complianceCount = curatorResult.compliance.length;
|
|
66071
66181
|
const warningCompliance = curatorResult.compliance.filter((obs) => obs.severity === "warning");
|
|
66072
66182
|
let alignment = "ALIGNED";
|
|
@@ -66115,7 +66225,7 @@ async function runDeterministicDriftCheck(directory, phase, curatorResult, confi
|
|
|
66115
66225
|
scope_additions: [],
|
|
66116
66226
|
injection_summary: injectionSummary
|
|
66117
66227
|
};
|
|
66118
|
-
const reportPath = await
|
|
66228
|
+
const reportPath = await _internals28.writeDriftReport(directory, report);
|
|
66119
66229
|
getGlobalEventBus().publish("curator.drift.completed", {
|
|
66120
66230
|
phase,
|
|
66121
66231
|
alignment,
|
|
@@ -66178,12 +66288,12 @@ function buildDriftInjectionText(report, maxChars) {
|
|
|
66178
66288
|
}
|
|
66179
66289
|
return text.slice(0, maxChars);
|
|
66180
66290
|
}
|
|
66181
|
-
var DRIFT_REPORT_PREFIX = "drift-report-phase-",
|
|
66291
|
+
var DRIFT_REPORT_PREFIX = "drift-report-phase-", _internals28;
|
|
66182
66292
|
var init_curator_drift = __esm(() => {
|
|
66183
66293
|
init_event_bus();
|
|
66184
66294
|
init_logger();
|
|
66185
66295
|
init_utils2();
|
|
66186
|
-
|
|
66296
|
+
_internals28 = {
|
|
66187
66297
|
readPriorDriftReports,
|
|
66188
66298
|
writeDriftReport,
|
|
66189
66299
|
runDeterministicDriftCheck,
|
|
@@ -67078,7 +67188,7 @@ init_state();
|
|
|
67078
67188
|
init_utils();
|
|
67079
67189
|
init_bun_compat();
|
|
67080
67190
|
init_utils2();
|
|
67081
|
-
import { renameSync as renameSync12, unlinkSync as
|
|
67191
|
+
import { renameSync as renameSync12, unlinkSync as unlinkSync9 } from "node:fs";
|
|
67082
67192
|
import * as nodePath2 from "node:path";
|
|
67083
67193
|
function createAgentActivityHooks(config3, directory) {
|
|
67084
67194
|
if (config3.hooks?.agent_activity === false) {
|
|
@@ -67156,7 +67266,7 @@ async function doFlush(directory) {
|
|
|
67156
67266
|
renameSync12(tempPath, path52);
|
|
67157
67267
|
} catch (writeError) {
|
|
67158
67268
|
try {
|
|
67159
|
-
|
|
67269
|
+
unlinkSync9(tempPath);
|
|
67160
67270
|
} catch {}
|
|
67161
67271
|
throw writeError;
|
|
67162
67272
|
}
|
|
@@ -67903,14 +68013,22 @@ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
|
|
|
67903
68013
|
throw new Error("CURATOR_LLM_TIMEOUT");
|
|
67904
68014
|
}
|
|
67905
68015
|
const agentName = resolveCuratorAgentName(mode, sessionId);
|
|
67906
|
-
|
|
67907
|
-
|
|
67908
|
-
|
|
67909
|
-
|
|
67910
|
-
|
|
67911
|
-
|
|
68016
|
+
let promptResult;
|
|
68017
|
+
try {
|
|
68018
|
+
promptResult = await client.session.prompt({
|
|
68019
|
+
path: { id: ephemeralSessionId },
|
|
68020
|
+
body: {
|
|
68021
|
+
agent: agentName,
|
|
68022
|
+
tools: { write: false, edit: false, patch: false },
|
|
68023
|
+
parts: [{ type: "text", text: userInput }]
|
|
68024
|
+
}
|
|
68025
|
+
});
|
|
68026
|
+
} catch (promptErr) {
|
|
68027
|
+
if (signal?.aborted) {
|
|
68028
|
+
throw new Error("CURATOR_LLM_TIMEOUT");
|
|
67912
68029
|
}
|
|
67913
|
-
|
|
68030
|
+
throw promptErr;
|
|
68031
|
+
}
|
|
67914
68032
|
if (!promptResult.data) {
|
|
67915
68033
|
throw new Error(`Curator LLM prompt failed: ${JSON.stringify(promptResult.error)}`);
|
|
67916
68034
|
}
|
|
@@ -76307,10 +76425,10 @@ async function getRunMemorySummary(directory) {
|
|
|
76307
76425
|
if (entries.length === 0) {
|
|
76308
76426
|
return null;
|
|
76309
76427
|
}
|
|
76310
|
-
const groups =
|
|
76428
|
+
const groups = _internals27.groupByTaskId(entries);
|
|
76311
76429
|
const summaries = [];
|
|
76312
76430
|
for (const [taskId, taskEntries] of groups) {
|
|
76313
|
-
const summary =
|
|
76431
|
+
const summary = _internals27.summarizeTask(taskId, taskEntries);
|
|
76314
76432
|
if (summary) {
|
|
76315
76433
|
summaries.push(summary);
|
|
76316
76434
|
}
|
|
@@ -76343,7 +76461,7 @@ Use this data to avoid repeating known failure patterns.`;
|
|
|
76343
76461
|
}
|
|
76344
76462
|
return prefix + summaryText + suffix;
|
|
76345
76463
|
}
|
|
76346
|
-
var
|
|
76464
|
+
var _internals27 = {
|
|
76347
76465
|
generateTaskFingerprint,
|
|
76348
76466
|
recordOutcome,
|
|
76349
76467
|
getTaskHistory,
|
|
@@ -86442,11 +86560,11 @@ var quality_budget = createSwarmTool({
|
|
|
86442
86560
|
}).optional().describe("Quality budget thresholds")
|
|
86443
86561
|
},
|
|
86444
86562
|
async execute(args2, directory) {
|
|
86445
|
-
const result = await
|
|
86563
|
+
const result = await _internals29.qualityBudget(args2, directory);
|
|
86446
86564
|
return JSON.stringify(result);
|
|
86447
86565
|
}
|
|
86448
86566
|
});
|
|
86449
|
-
var
|
|
86567
|
+
var _internals29 = {
|
|
86450
86568
|
qualityBudget
|
|
86451
86569
|
};
|
|
86452
86570
|
|
|
@@ -87175,7 +87293,7 @@ import * as path97 from "node:path";
|
|
|
87175
87293
|
var semgrepAvailableCache = null;
|
|
87176
87294
|
var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
|
|
87177
87295
|
var DEFAULT_TIMEOUT_MS3 = 30000;
|
|
87178
|
-
var
|
|
87296
|
+
var _internals30 = {
|
|
87179
87297
|
isSemgrepAvailable,
|
|
87180
87298
|
checkSemgrepAvailable,
|
|
87181
87299
|
resetSemgrepCache,
|
|
@@ -87200,7 +87318,7 @@ function isSemgrepAvailable() {
|
|
|
87200
87318
|
}
|
|
87201
87319
|
}
|
|
87202
87320
|
async function checkSemgrepAvailable() {
|
|
87203
|
-
return
|
|
87321
|
+
return _internals30.isSemgrepAvailable();
|
|
87204
87322
|
}
|
|
87205
87323
|
function resetSemgrepCache() {
|
|
87206
87324
|
semgrepAvailableCache = null;
|
|
@@ -87297,12 +87415,12 @@ async function runSemgrep(options) {
|
|
|
87297
87415
|
const timeoutMs = options.timeoutMs || DEFAULT_TIMEOUT_MS3;
|
|
87298
87416
|
if (files.length === 0) {
|
|
87299
87417
|
return {
|
|
87300
|
-
available:
|
|
87418
|
+
available: _internals30.isSemgrepAvailable(),
|
|
87301
87419
|
findings: [],
|
|
87302
87420
|
engine: "tier_a"
|
|
87303
87421
|
};
|
|
87304
87422
|
}
|
|
87305
|
-
if (!
|
|
87423
|
+
if (!_internals30.isSemgrepAvailable()) {
|
|
87306
87424
|
return {
|
|
87307
87425
|
available: false,
|
|
87308
87426
|
findings: [],
|
|
@@ -87461,7 +87579,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
87461
87579
|
}
|
|
87462
87580
|
const occIdx = countMap.get(baseKey) ?? 0;
|
|
87463
87581
|
countMap.set(baseKey, occIdx + 1);
|
|
87464
|
-
const fp =
|
|
87582
|
+
const fp = _internals31.fingerprintFinding(finding, directory, occIdx);
|
|
87465
87583
|
return {
|
|
87466
87584
|
finding,
|
|
87467
87585
|
index: occIdx,
|
|
@@ -87530,7 +87648,7 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
87530
87648
|
}
|
|
87531
87649
|
} catch {}
|
|
87532
87650
|
const scannedRelFiles = new Set(scannedFiles.map((f) => normalizeFindingPath(directory, f)));
|
|
87533
|
-
const indexed =
|
|
87651
|
+
const indexed = _internals31.assignOccurrenceIndices(findings, directory);
|
|
87534
87652
|
if (existing && !opts?.force) {
|
|
87535
87653
|
const prunedFingerprints = existing.fingerprints.filter((fp) => {
|
|
87536
87654
|
const relFile = fp.slice(0, fp.indexOf("|"));
|
|
@@ -87670,7 +87788,7 @@ function loadBaseline(directory, phase) {
|
|
|
87670
87788
|
};
|
|
87671
87789
|
}
|
|
87672
87790
|
}
|
|
87673
|
-
var
|
|
87791
|
+
var _internals31 = {
|
|
87674
87792
|
fingerprintFinding,
|
|
87675
87793
|
assignOccurrenceIndices,
|
|
87676
87794
|
captureOrMergeBaseline,
|
|
@@ -88080,11 +88198,11 @@ var sast_scan = createSwarmTool({
|
|
|
88080
88198
|
capture_baseline: safeArgs.capture_baseline,
|
|
88081
88199
|
phase: safeArgs.phase
|
|
88082
88200
|
};
|
|
88083
|
-
const result = await
|
|
88201
|
+
const result = await _internals32.sastScan(input, directory);
|
|
88084
88202
|
return JSON.stringify(result, null, 2);
|
|
88085
88203
|
}
|
|
88086
88204
|
});
|
|
88087
|
-
var
|
|
88205
|
+
var _internals32 = {
|
|
88088
88206
|
sastScan,
|
|
88089
88207
|
sast_scan
|
|
88090
88208
|
};
|
|
@@ -92438,7 +92556,7 @@ import * as path110 from "node:path";
|
|
|
92438
92556
|
|
|
92439
92557
|
// src/mutation/engine.ts
|
|
92440
92558
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
92441
|
-
import { unlinkSync as
|
|
92559
|
+
import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync22 } from "node:fs";
|
|
92442
92560
|
import * as path109 from "node:path";
|
|
92443
92561
|
|
|
92444
92562
|
// src/mutation/equivalence.ts
|
|
@@ -92511,7 +92629,7 @@ function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
|
92511
92629
|
const strippedMutated = stripCode(mutatedCode);
|
|
92512
92630
|
return strippedOriginal === strippedMutated;
|
|
92513
92631
|
}
|
|
92514
|
-
var
|
|
92632
|
+
var _internals33 = {
|
|
92515
92633
|
isStaticallyEquivalent,
|
|
92516
92634
|
checkEquivalence,
|
|
92517
92635
|
batchCheckEquivalence
|
|
@@ -92551,7 +92669,7 @@ async function batchCheckEquivalence(patches, llmJudge) {
|
|
|
92551
92669
|
const results = [];
|
|
92552
92670
|
for (const { patch, originalCode, mutatedCode } of patches) {
|
|
92553
92671
|
try {
|
|
92554
|
-
const result = await
|
|
92672
|
+
const result = await _internals33.checkEquivalence(patch, originalCode, mutatedCode, llmJudge);
|
|
92555
92673
|
results.push(result);
|
|
92556
92674
|
} catch (err3) {
|
|
92557
92675
|
results.push({
|
|
@@ -92677,7 +92795,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
92677
92795
|
revertError = new Error(`Failed to revert mutation ${patch.id}: ${revertErr}. Working tree may be dirty.`);
|
|
92678
92796
|
}
|
|
92679
92797
|
try {
|
|
92680
|
-
|
|
92798
|
+
unlinkSync14(patchFile);
|
|
92681
92799
|
} catch (_unlinkErr) {}
|
|
92682
92800
|
}
|
|
92683
92801
|
}
|
|
@@ -92851,7 +92969,7 @@ async function executeMutationSuite(patches, testCommand, testFiles, workingDir,
|
|
|
92851
92969
|
}
|
|
92852
92970
|
|
|
92853
92971
|
// src/mutation/gate.ts
|
|
92854
|
-
var
|
|
92972
|
+
var _internals34 = {
|
|
92855
92973
|
evaluateMutationGate,
|
|
92856
92974
|
buildTestImprovementPrompt,
|
|
92857
92975
|
buildMessage
|
|
@@ -92872,8 +92990,8 @@ function evaluateMutationGate(report, passThreshold = PASS_THRESHOLD, warnThresh
|
|
|
92872
92990
|
} else {
|
|
92873
92991
|
verdict = "fail";
|
|
92874
92992
|
}
|
|
92875
|
-
const testImprovementPrompt =
|
|
92876
|
-
const message =
|
|
92993
|
+
const testImprovementPrompt = _internals34.buildTestImprovementPrompt(report, passThreshold, verdict);
|
|
92994
|
+
const message = _internals34.buildMessage(verdict, adjustedKillRate, report.killed, report.totalMutants, report.equivalent, warnThreshold);
|
|
92877
92995
|
return {
|
|
92878
92996
|
verdict,
|
|
92879
92997
|
killRate: report.killRate,
|
|
@@ -93490,7 +93608,7 @@ import * as path114 from "node:path";
|
|
|
93490
93608
|
init_bun_compat();
|
|
93491
93609
|
import * as fs92 from "node:fs";
|
|
93492
93610
|
import * as path113 from "node:path";
|
|
93493
|
-
var
|
|
93611
|
+
var _internals35 = { bunSpawn };
|
|
93494
93612
|
var _swarmGitExcludedChecked = false;
|
|
93495
93613
|
function fileCoversSwarm(content) {
|
|
93496
93614
|
for (const rawLine of content.split(`
|
|
@@ -93523,7 +93641,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
93523
93641
|
checkIgnoreExitCode
|
|
93524
93642
|
] = await Promise.all([
|
|
93525
93643
|
(async () => {
|
|
93526
|
-
const proc =
|
|
93644
|
+
const proc = _internals35.bunSpawn(["git", "-C", directory, "rev-parse", "--show-toplevel"], GIT_SPAWN_OPTIONS);
|
|
93527
93645
|
try {
|
|
93528
93646
|
return await Promise.all([proc.exited, proc.stdout.text()]);
|
|
93529
93647
|
} finally {
|
|
@@ -93533,7 +93651,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
93533
93651
|
}
|
|
93534
93652
|
})(),
|
|
93535
93653
|
(async () => {
|
|
93536
|
-
const proc =
|
|
93654
|
+
const proc = _internals35.bunSpawn(["git", "-C", directory, "rev-parse", "--git-path", "info/exclude"], GIT_SPAWN_OPTIONS);
|
|
93537
93655
|
try {
|
|
93538
93656
|
return await Promise.all([proc.exited, proc.stdout.text()]);
|
|
93539
93657
|
} finally {
|
|
@@ -93543,7 +93661,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
93543
93661
|
}
|
|
93544
93662
|
})(),
|
|
93545
93663
|
(async () => {
|
|
93546
|
-
const proc =
|
|
93664
|
+
const proc = _internals35.bunSpawn(["git", "-C", directory, "check-ignore", "-q", ".swarm/.gitkeep"], GIT_SPAWN_OPTIONS);
|
|
93547
93665
|
try {
|
|
93548
93666
|
return await proc.exited;
|
|
93549
93667
|
} finally {
|
|
@@ -93582,7 +93700,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
93582
93700
|
}
|
|
93583
93701
|
} catch {}
|
|
93584
93702
|
}
|
|
93585
|
-
const trackedProc =
|
|
93703
|
+
const trackedProc = _internals35.bunSpawn(["git", "-C", directory, "ls-files", "--", ".swarm"], GIT_SPAWN_OPTIONS);
|
|
93586
93704
|
let trackedExitCode;
|
|
93587
93705
|
let trackedOutput;
|
|
93588
93706
|
try {
|
|
@@ -93607,7 +93725,7 @@ async function ensureSwarmGitExcluded(directory, options = {}) {
|
|
|
93607
93725
|
}
|
|
93608
93726
|
|
|
93609
93727
|
// src/hooks/diff-scope.ts
|
|
93610
|
-
var
|
|
93728
|
+
var _internals36 = { bunSpawn };
|
|
93611
93729
|
function getDeclaredScope(taskId, directory) {
|
|
93612
93730
|
try {
|
|
93613
93731
|
const planPath = path114.join(directory, ".swarm", "plan.json");
|
|
@@ -93642,7 +93760,7 @@ var GIT_DIFF_SPAWN_OPTIONS = {
|
|
|
93642
93760
|
};
|
|
93643
93761
|
async function getChangedFiles(directory) {
|
|
93644
93762
|
try {
|
|
93645
|
-
const proc =
|
|
93763
|
+
const proc = _internals36.bunSpawn(["git", "diff", "--name-only", "HEAD~1"], {
|
|
93646
93764
|
cwd: directory,
|
|
93647
93765
|
...GIT_DIFF_SPAWN_OPTIONS
|
|
93648
93766
|
});
|
|
@@ -93659,7 +93777,7 @@ async function getChangedFiles(directory) {
|
|
|
93659
93777
|
return stdout.trim().split(`
|
|
93660
93778
|
`).map((f) => f.trim()).filter((f) => f.length > 0);
|
|
93661
93779
|
}
|
|
93662
|
-
const proc2 =
|
|
93780
|
+
const proc2 = _internals36.bunSpawn(["git", "diff", "--name-only", "HEAD"], {
|
|
93663
93781
|
cwd: directory,
|
|
93664
93782
|
...GIT_DIFF_SPAWN_OPTIONS
|
|
93665
93783
|
});
|
|
@@ -95346,7 +95464,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
95346
95464
|
...opencodeConfig.command || {},
|
|
95347
95465
|
swarm: {
|
|
95348
95466
|
template: "/swarm $ARGUMENTS",
|
|
95349
|
-
description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|qa-gates|dark-matter|knowledge|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor-tools|close]"
|
|
95467
|
+
description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|diagnosis|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|brainstorm|council|pr-review|issue|qa-gates|dark-matter|knowledge|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|acknowledge-spec-drift|doctor-tools|close]"
|
|
95350
95468
|
},
|
|
95351
95469
|
"swarm-status": {
|
|
95352
95470
|
template: "/swarm status",
|
|
@@ -95436,6 +95554,14 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
95436
95554
|
template: "/swarm council $ARGUMENTS",
|
|
95437
95555
|
description: "Use /swarm council <question> to convene a multi-model General Council deliberation (generalist / skeptic / domain expert) [--spec-review]"
|
|
95438
95556
|
},
|
|
95557
|
+
"swarm-pr-review": {
|
|
95558
|
+
template: "/swarm pr-review $ARGUMENTS",
|
|
95559
|
+
description: "Use /swarm pr-review to launch deep PR review with multi-lane analysis"
|
|
95560
|
+
},
|
|
95561
|
+
"swarm-issue": {
|
|
95562
|
+
template: "/swarm issue $ARGUMENTS",
|
|
95563
|
+
description: "Use /swarm issue to ingest a GitHub issue into the swarm workflow"
|
|
95564
|
+
},
|
|
95439
95565
|
"swarm-qa-gates": {
|
|
95440
95566
|
template: "/swarm qa-gates $ARGUMENTS",
|
|
95441
95567
|
description: "Use /swarm qa-gates to view or modify QA gate profile for the current plan"
|
|
@@ -95457,7 +95583,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
95457
95583
|
description: "Use /swarm turbo to enable turbo mode for faster execution"
|
|
95458
95584
|
},
|
|
95459
95585
|
"swarm-full-auto": {
|
|
95460
|
-
template: "/swarm
|
|
95586
|
+
template: "/swarm full-auto $ARGUMENTS",
|
|
95461
95587
|
description: "Toggle Full-Auto Mode for the active session [on|off]"
|
|
95462
95588
|
},
|
|
95463
95589
|
"swarm-write-retro": {
|
package/dist/lang/runtime.d.ts
CHANGED
|
@@ -4,6 +4,16 @@ export type Parser = ParserType;
|
|
|
4
4
|
* Parser cache to avoid reloading grammars multiple times per session
|
|
5
5
|
*/
|
|
6
6
|
export declare const parserCache: Map<string, ParserType>;
|
|
7
|
+
/**
|
|
8
|
+
* DI seam for testing — overridable reference to TreeSitterParser.init.
|
|
9
|
+
* Tests can replace this with a spy/mock to observe init calls without
|
|
10
|
+
* mock.module leakage. Restore the original reference in afterEach.
|
|
11
|
+
*/
|
|
12
|
+
export declare const _internals: {
|
|
13
|
+
parserInit: (opts?: {
|
|
14
|
+
locateFile: (scriptName: string) => string;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
};
|
|
7
17
|
/**
|
|
8
18
|
* Initialize a parser for the given language
|
|
9
19
|
* Loads WASM from dist/lang/grammars/ (copied during build)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.9.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",
|