opencode-swarm 7.8.1 → 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 +151 -45
- 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) {
|
|
@@ -44904,7 +44917,17 @@ async function handleDarkMatterCommand(directory, args2) {
|
|
|
44904
44917
|
i2++;
|
|
44905
44918
|
}
|
|
44906
44919
|
}
|
|
44907
|
-
|
|
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
|
+
}
|
|
44908
44931
|
const output = formatDarkMatterOutput(pairs);
|
|
44909
44932
|
if (pairs.length > 0) {
|
|
44910
44933
|
try {
|
|
@@ -49487,22 +49510,37 @@ var init_handoff_service = __esm(() => {
|
|
|
49487
49510
|
|
|
49488
49511
|
// src/commands/handoff.ts
|
|
49489
49512
|
import crypto4 from "node:crypto";
|
|
49490
|
-
import { renameSync as renameSync10 } from "node:fs";
|
|
49513
|
+
import { renameSync as renameSync10, unlinkSync as unlinkSync5 } from "node:fs";
|
|
49491
49514
|
async function handleHandoffCommand(directory, _args) {
|
|
49492
49515
|
const handoffData = await getHandoffData(directory);
|
|
49493
49516
|
const markdown = formatHandoffMarkdown(handoffData);
|
|
49494
|
-
|
|
49495
|
-
|
|
49496
|
-
|
|
49497
|
-
|
|
49498
|
-
|
|
49499
|
-
|
|
49500
|
-
|
|
49501
|
-
|
|
49502
|
-
|
|
49503
|
-
|
|
49504
|
-
|
|
49505
|
-
|
|
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
|
|
49506
49544
|
|
|
49507
49545
|
Brief written to \`.swarm/handoff.md\`.
|
|
49508
49546
|
Continuation prompt written to \`.swarm/handoff-prompt.md\`.
|
|
@@ -49516,6 +49554,16 @@ ${markdown}
|
|
|
49516
49554
|
Copy and paste the block below into your next session to resume cleanly:
|
|
49517
49555
|
|
|
49518
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
|
+
}
|
|
49519
49567
|
}
|
|
49520
49568
|
var init_handoff = __esm(() => {
|
|
49521
49569
|
init_utils2();
|
|
@@ -55712,7 +55760,19 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
55712
55760
|
options.minCommits = val;
|
|
55713
55761
|
}
|
|
55714
55762
|
}
|
|
55715
|
-
|
|
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
|
+
}
|
|
55716
55776
|
const reportLines = [
|
|
55717
55777
|
"# Simulate Report",
|
|
55718
55778
|
"",
|
|
@@ -55730,15 +55790,21 @@ async function handleSimulateCommand(directory, args2) {
|
|
|
55730
55790
|
];
|
|
55731
55791
|
const report = reportLines.filter(Boolean).join(`
|
|
55732
55792
|
`);
|
|
55733
|
-
|
|
55734
|
-
|
|
55735
|
-
|
|
55736
|
-
|
|
55737
|
-
|
|
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
|
+
}
|
|
55738
55803
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
55739
55804
|
}
|
|
55740
55805
|
var init_simulate = __esm(() => {
|
|
55741
55806
|
init_co_change_analyzer();
|
|
55807
|
+
init_utils();
|
|
55742
55808
|
});
|
|
55743
55809
|
|
|
55744
55810
|
// src/commands/specify.ts
|
|
@@ -56400,12 +56466,6 @@ function buildHelpText() {
|
|
|
56400
56466
|
return lines.join(`
|
|
56401
56467
|
`);
|
|
56402
56468
|
}
|
|
56403
|
-
function getHelpText() {
|
|
56404
|
-
if (!_helpText) {
|
|
56405
|
-
_helpText = buildHelpText();
|
|
56406
|
-
}
|
|
56407
|
-
return _helpText;
|
|
56408
|
-
}
|
|
56409
56469
|
function createSwarmCommandHandler(directory, agents) {
|
|
56410
56470
|
return async (input, output) => {
|
|
56411
56471
|
if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
|
|
@@ -56431,7 +56491,22 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
56431
56491
|
let text;
|
|
56432
56492
|
const resolved = resolveCommand(tokens);
|
|
56433
56493
|
if (!resolved) {
|
|
56434
|
-
|
|
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
|
+
}
|
|
56435
56510
|
} else {
|
|
56436
56511
|
try {
|
|
56437
56512
|
text = await resolved.entry.handler({
|
|
@@ -56463,7 +56538,6 @@ ${text}`;
|
|
|
56463
56538
|
];
|
|
56464
56539
|
};
|
|
56465
56540
|
}
|
|
56466
|
-
var _helpText;
|
|
56467
56541
|
var init_commands = __esm(() => {
|
|
56468
56542
|
init_registry();
|
|
56469
56543
|
init_acknowledge_spec_drift();
|
|
@@ -56523,14 +56597,38 @@ function levenshteinDistance(a, b) {
|
|
|
56523
56597
|
}
|
|
56524
56598
|
function findSimilarCommands(query) {
|
|
56525
56599
|
const q = query.toLowerCase();
|
|
56526
|
-
|
|
56527
|
-
|
|
56528
|
-
|
|
56529
|
-
|
|
56530
|
-
|
|
56531
|
-
|
|
56532
|
-
|
|
56533
|
-
|
|
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
|
+
});
|
|
56534
56632
|
scored.sort((a, b) => a.score - b.score);
|
|
56535
56633
|
return scored.slice(0, 3).map((s) => s.cmd);
|
|
56536
56634
|
}
|
|
@@ -67090,7 +67188,7 @@ init_state();
|
|
|
67090
67188
|
init_utils();
|
|
67091
67189
|
init_bun_compat();
|
|
67092
67190
|
init_utils2();
|
|
67093
|
-
import { renameSync as renameSync12, unlinkSync as
|
|
67191
|
+
import { renameSync as renameSync12, unlinkSync as unlinkSync9 } from "node:fs";
|
|
67094
67192
|
import * as nodePath2 from "node:path";
|
|
67095
67193
|
function createAgentActivityHooks(config3, directory) {
|
|
67096
67194
|
if (config3.hooks?.agent_activity === false) {
|
|
@@ -67168,7 +67266,7 @@ async function doFlush(directory) {
|
|
|
67168
67266
|
renameSync12(tempPath, path52);
|
|
67169
67267
|
} catch (writeError) {
|
|
67170
67268
|
try {
|
|
67171
|
-
|
|
67269
|
+
unlinkSync9(tempPath);
|
|
67172
67270
|
} catch {}
|
|
67173
67271
|
throw writeError;
|
|
67174
67272
|
}
|
|
@@ -92458,7 +92556,7 @@ import * as path110 from "node:path";
|
|
|
92458
92556
|
|
|
92459
92557
|
// src/mutation/engine.ts
|
|
92460
92558
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
92461
|
-
import { unlinkSync as
|
|
92559
|
+
import { unlinkSync as unlinkSync14, writeFileSync as writeFileSync22 } from "node:fs";
|
|
92462
92560
|
import * as path109 from "node:path";
|
|
92463
92561
|
|
|
92464
92562
|
// src/mutation/equivalence.ts
|
|
@@ -92697,7 +92795,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
92697
92795
|
revertError = new Error(`Failed to revert mutation ${patch.id}: ${revertErr}. Working tree may be dirty.`);
|
|
92698
92796
|
}
|
|
92699
92797
|
try {
|
|
92700
|
-
|
|
92798
|
+
unlinkSync14(patchFile);
|
|
92701
92799
|
} catch (_unlinkErr) {}
|
|
92702
92800
|
}
|
|
92703
92801
|
}
|
|
@@ -95366,7 +95464,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
95366
95464
|
...opencodeConfig.command || {},
|
|
95367
95465
|
swarm: {
|
|
95368
95466
|
template: "/swarm $ARGUMENTS",
|
|
95369
|
-
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]"
|
|
95370
95468
|
},
|
|
95371
95469
|
"swarm-status": {
|
|
95372
95470
|
template: "/swarm status",
|
|
@@ -95456,6 +95554,14 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
95456
95554
|
template: "/swarm council $ARGUMENTS",
|
|
95457
95555
|
description: "Use /swarm council <question> to convene a multi-model General Council deliberation (generalist / skeptic / domain expert) [--spec-review]"
|
|
95458
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
|
+
},
|
|
95459
95565
|
"swarm-qa-gates": {
|
|
95460
95566
|
template: "/swarm qa-gates $ARGUMENTS",
|
|
95461
95567
|
description: "Use /swarm qa-gates to view or modify QA gate profile for the current plan"
|
|
@@ -95477,7 +95583,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
95477
95583
|
description: "Use /swarm turbo to enable turbo mode for faster execution"
|
|
95478
95584
|
},
|
|
95479
95585
|
"swarm-full-auto": {
|
|
95480
|
-
template: "/swarm
|
|
95586
|
+
template: "/swarm full-auto $ARGUMENTS",
|
|
95481
95587
|
description: "Toggle Full-Auto Mode for the active session [on|off]"
|
|
95482
95588
|
},
|
|
95483
95589
|
"swarm-write-retro": {
|
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",
|