opencode-swarm 6.86.6 → 6.86.8
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 +28 -0
- package/dist/cli/index.js +182 -45
- package/dist/config/schema.d.ts +3 -0
- package/dist/council/types.d.ts +5 -1
- package/dist/db/global-db.d.ts +1 -1
- package/dist/db/project-db.d.ts +1 -1
- package/dist/db/qa-gate-profile.d.ts +1 -1
- package/dist/index.js +4520 -4276
- package/dist/services/version-check.d.ts +28 -0
- package/dist/state.d.ts +16 -3
- package/dist/tools/convene-council.d.ts +10 -5
- package/dist/tools/declare-council-criteria.d.ts +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/tool-names.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -107,6 +107,34 @@ The 15-minute guide covers:
|
|
|
107
107
|
|
|
108
108
|
---
|
|
109
109
|
|
|
110
|
+
## Upgrading
|
|
111
|
+
|
|
112
|
+
**OpenCode caches plugins indefinitely.** A normal OpenCode restart does **not**
|
|
113
|
+
pull newer versions from npm — once a plugin is cached, OpenCode keeps using
|
|
114
|
+
that exact copy on every subsequent launch (issue #675). The cache lives in
|
|
115
|
+
one of two places depending on your platform:
|
|
116
|
+
|
|
117
|
+
- Linux / devcontainers / GitHub Codespaces:
|
|
118
|
+
`~/.config/opencode/node_modules/opencode-swarm/`
|
|
119
|
+
- Some macOS / Windows installs:
|
|
120
|
+
`~/.cache/opencode/packages/opencode-swarm@latest/`
|
|
121
|
+
|
|
122
|
+
To upgrade to the latest published version (clears both layouts automatically):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bunx opencode-swarm update # cache-only refresh, then restart opencode
|
|
126
|
+
# or
|
|
127
|
+
bunx opencode-swarm install # full reinstall (re-asserts config), then restart opencode
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`/swarm diagnose` shows the running version and, when available, the latest
|
|
131
|
+
version on npm so you can tell at a glance whether your cache is stale.
|
|
132
|
+
|
|
133
|
+
To disable the background staleness check entirely, set `version_check: false`
|
|
134
|
+
in your `opencode-swarm.json`.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
110
138
|
## Commands
|
|
111
139
|
|
|
112
140
|
All 41 subcommands at a glance:
|
package/dist/cli/index.js
CHANGED
|
@@ -18580,7 +18580,7 @@ import * as path32 from "path";
|
|
|
18580
18580
|
// package.json
|
|
18581
18581
|
var package_default = {
|
|
18582
18582
|
name: "opencode-swarm",
|
|
18583
|
-
version: "6.86.
|
|
18583
|
+
version: "6.86.8",
|
|
18584
18584
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
18585
18585
|
main: "dist/index.js",
|
|
18586
18586
|
types: "dist/index.d.ts",
|
|
@@ -18618,7 +18618,7 @@ var package_default = {
|
|
|
18618
18618
|
],
|
|
18619
18619
|
scripts: {
|
|
18620
18620
|
clean: `bun -e "require('fs').rmSync('dist',{recursive:true,force:true})"`,
|
|
18621
|
-
build: "bun run clean && bun run scripts/copy-grammars.ts && bun build src/index.ts --outdir dist --target
|
|
18621
|
+
build: "bun run clean && bun run scripts/copy-grammars.ts && bun build src/index.ts --outdir dist --target node --format esm && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && bun run scripts/copy-grammars.ts --to-dist && tsc --emitDeclarationOnly",
|
|
18622
18622
|
typecheck: "tsc --noEmit",
|
|
18623
18623
|
test: "bun test",
|
|
18624
18624
|
lint: "biome lint .",
|
|
@@ -18742,7 +18742,7 @@ var TOOL_NAMES = [
|
|
|
18742
18742
|
"evidence_check",
|
|
18743
18743
|
"check_gate_status",
|
|
18744
18744
|
"completion_verify",
|
|
18745
|
-
"
|
|
18745
|
+
"submit_council_verdicts",
|
|
18746
18746
|
"declare_council_criteria",
|
|
18747
18747
|
"sbom_generate",
|
|
18748
18748
|
"checkpoint",
|
|
@@ -18822,7 +18822,7 @@ var AGENT_TOOL_MAP = {
|
|
|
18822
18822
|
"check_gate_status",
|
|
18823
18823
|
"completion_verify",
|
|
18824
18824
|
"complexity_hotspots",
|
|
18825
|
-
"
|
|
18825
|
+
"submit_council_verdicts",
|
|
18826
18826
|
"declare_council_criteria",
|
|
18827
18827
|
"detect_domains",
|
|
18828
18828
|
"evidence_check",
|
|
@@ -19624,7 +19624,8 @@ var CouncilConfigSchema = exports_external.object({
|
|
|
19624
19624
|
maxRounds: exports_external.number().int().min(1).max(10).default(3),
|
|
19625
19625
|
parallelTimeoutMs: exports_external.number().int().min(5000).max(120000).default(30000),
|
|
19626
19626
|
vetoPriority: exports_external.boolean().default(true),
|
|
19627
|
-
requireAllMembers: exports_external.boolean().default(false).describe("When true,
|
|
19627
|
+
requireAllMembers: exports_external.boolean().default(false).describe("When true, submit_council_verdicts rejects if fewer than 5 member verdicts are provided. Equivalent to minimumMembers: 5."),
|
|
19628
|
+
minimumMembers: exports_external.number().int().min(1).max(5).default(3).describe("Minimum distinct council member verdicts required for synthesis. Default 3. Set to 1 to disable quorum enforcement. requireAllMembers: true overrides this to 5 (stricter constraint wins)."),
|
|
19628
19629
|
escalateOnMaxRounds: exports_external.string().optional().describe("Optional webhook URL or handler name invoked when maxRounds is reached without APPROVE. Declared for forward compatibility; no behavior is implemented yet."),
|
|
19629
19630
|
general: GeneralCouncilConfigSchema.optional()
|
|
19630
19631
|
}).strict();
|
|
@@ -19690,6 +19691,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19690
19691
|
parallelization: ParallelizationConfigSchema.optional(),
|
|
19691
19692
|
turbo_mode: exports_external.boolean().default(false).optional(),
|
|
19692
19693
|
quiet: exports_external.boolean().default(false).optional(),
|
|
19694
|
+
version_check: exports_external.boolean().default(true).optional(),
|
|
19693
19695
|
full_auto: exports_external.object({
|
|
19694
19696
|
enabled: exports_external.boolean().default(false),
|
|
19695
19697
|
critic_model: exports_external.string().optional(),
|
|
@@ -19966,9 +19968,17 @@ init_plan_schema();
|
|
|
19966
19968
|
import { createHash as createHash3 } from "crypto";
|
|
19967
19969
|
|
|
19968
19970
|
// src/db/project-db.ts
|
|
19969
|
-
import { Database } from "bun:sqlite";
|
|
19970
19971
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
|
|
19972
|
+
import { createRequire } from "module";
|
|
19971
19973
|
import { join as join7, resolve as resolve5 } from "path";
|
|
19974
|
+
var _DatabaseCtor = null;
|
|
19975
|
+
function loadDatabaseCtor() {
|
|
19976
|
+
if (_DatabaseCtor)
|
|
19977
|
+
return _DatabaseCtor;
|
|
19978
|
+
const req = createRequire(import.meta.url);
|
|
19979
|
+
_DatabaseCtor = req("bun:sqlite").Database;
|
|
19980
|
+
return _DatabaseCtor;
|
|
19981
|
+
}
|
|
19972
19982
|
var MIGRATIONS = [
|
|
19973
19983
|
{
|
|
19974
19984
|
version: 1,
|
|
@@ -20039,7 +20049,8 @@ function getProjectDb(directory) {
|
|
|
20039
20049
|
return existing;
|
|
20040
20050
|
const swarmDir = join7(key, ".swarm");
|
|
20041
20051
|
mkdirSync4(swarmDir, { recursive: true });
|
|
20042
|
-
const
|
|
20052
|
+
const Db = loadDatabaseCtor();
|
|
20053
|
+
const db = new Db(join7(swarmDir, "swarm.db"));
|
|
20043
20054
|
db.run("PRAGMA journal_mode = WAL;");
|
|
20044
20055
|
db.run("PRAGMA synchronous = NORMAL;");
|
|
20045
20056
|
db.run("PRAGMA busy_timeout = 5000;");
|
|
@@ -36257,12 +36268,65 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
36257
36268
|
|
|
36258
36269
|
// src/services/diagnose-service.ts
|
|
36259
36270
|
import * as child_process4 from "child_process";
|
|
36260
|
-
import { existsSync as
|
|
36271
|
+
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
36261
36272
|
import path17 from "path";
|
|
36262
36273
|
import { fileURLToPath } from "url";
|
|
36263
36274
|
init_manager2();
|
|
36264
36275
|
init_utils2();
|
|
36265
36276
|
init_manager();
|
|
36277
|
+
|
|
36278
|
+
// src/services/version-check.ts
|
|
36279
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
36280
|
+
import { homedir as homedir4 } from "os";
|
|
36281
|
+
import { join as join14 } from "path";
|
|
36282
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
36283
|
+
function cacheDir() {
|
|
36284
|
+
const xdg = process.env.XDG_CACHE_HOME;
|
|
36285
|
+
const base = xdg && xdg.length > 0 ? xdg : join14(homedir4(), ".cache");
|
|
36286
|
+
return join14(base, "opencode-swarm");
|
|
36287
|
+
}
|
|
36288
|
+
function cacheFile() {
|
|
36289
|
+
return join14(cacheDir(), "version-check.json");
|
|
36290
|
+
}
|
|
36291
|
+
function readVersionCache() {
|
|
36292
|
+
try {
|
|
36293
|
+
const path17 = cacheFile();
|
|
36294
|
+
if (!existsSync8(path17))
|
|
36295
|
+
return null;
|
|
36296
|
+
const raw = readFileSync5(path17, "utf-8");
|
|
36297
|
+
const parsed = JSON.parse(raw);
|
|
36298
|
+
if (typeof parsed?.checkedAt !== "number")
|
|
36299
|
+
return null;
|
|
36300
|
+
const npmLatest = typeof parsed.npmLatest === "string" ? parsed.npmLatest : null;
|
|
36301
|
+
return { checkedAt: parsed.checkedAt, npmLatest };
|
|
36302
|
+
} catch {
|
|
36303
|
+
return null;
|
|
36304
|
+
}
|
|
36305
|
+
}
|
|
36306
|
+
function compareVersions(a, b) {
|
|
36307
|
+
const [aBase, aPre] = a.split("-", 2);
|
|
36308
|
+
const [bBase, bPre] = b.split("-", 2);
|
|
36309
|
+
const aParts = aBase.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
36310
|
+
const bParts = bBase.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
36311
|
+
const len = Math.max(aParts.length, bParts.length);
|
|
36312
|
+
for (let i = 0;i < len; i++) {
|
|
36313
|
+
const av = aParts[i] ?? 0;
|
|
36314
|
+
const bv = bParts[i] ?? 0;
|
|
36315
|
+
if (av > bv)
|
|
36316
|
+
return 1;
|
|
36317
|
+
if (av < bv)
|
|
36318
|
+
return -1;
|
|
36319
|
+
}
|
|
36320
|
+
if (aPre && !bPre)
|
|
36321
|
+
return -1;
|
|
36322
|
+
if (!aPre && bPre)
|
|
36323
|
+
return 1;
|
|
36324
|
+
if (aPre && bPre)
|
|
36325
|
+
return aPre < bPre ? -1 : aPre > bPre ? 1 : 0;
|
|
36326
|
+
return 0;
|
|
36327
|
+
}
|
|
36328
|
+
|
|
36329
|
+
// src/services/diagnose-service.ts
|
|
36266
36330
|
var { version: version3 } = package_default;
|
|
36267
36331
|
function validateTaskDag(plan) {
|
|
36268
36332
|
const allTaskIds = new Set;
|
|
@@ -36495,7 +36559,7 @@ async function checkConfigBackups(directory) {
|
|
|
36495
36559
|
}
|
|
36496
36560
|
async function checkGitRepository(directory) {
|
|
36497
36561
|
try {
|
|
36498
|
-
if (!
|
|
36562
|
+
if (!existsSync9(directory) || !statSync5(directory).isDirectory()) {
|
|
36499
36563
|
return {
|
|
36500
36564
|
name: "Git Repository",
|
|
36501
36565
|
status: "\u274C",
|
|
@@ -36560,7 +36624,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
36560
36624
|
}
|
|
36561
36625
|
async function checkConfigParseability(directory) {
|
|
36562
36626
|
const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
|
|
36563
|
-
if (!
|
|
36627
|
+
if (!existsSync9(configPath)) {
|
|
36564
36628
|
return {
|
|
36565
36629
|
name: "Config Parseability",
|
|
36566
36630
|
status: "\u2705",
|
|
@@ -36568,7 +36632,7 @@ async function checkConfigParseability(directory) {
|
|
|
36568
36632
|
};
|
|
36569
36633
|
}
|
|
36570
36634
|
try {
|
|
36571
|
-
const content =
|
|
36635
|
+
const content = readFileSync6(configPath, "utf-8");
|
|
36572
36636
|
JSON.parse(content);
|
|
36573
36637
|
return {
|
|
36574
36638
|
name: "Config Parseability",
|
|
@@ -36615,11 +36679,11 @@ async function checkGrammarWasmFiles() {
|
|
|
36615
36679
|
const thisDir = path17.dirname(fileURLToPath(import.meta.url));
|
|
36616
36680
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
36617
36681
|
const missing = [];
|
|
36618
|
-
if (!
|
|
36682
|
+
if (!existsSync9(path17.join(grammarDir, "tree-sitter.wasm"))) {
|
|
36619
36683
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
36620
36684
|
}
|
|
36621
36685
|
for (const file3 of grammarFiles) {
|
|
36622
|
-
if (!
|
|
36686
|
+
if (!existsSync9(path17.join(grammarDir, file3))) {
|
|
36623
36687
|
missing.push(file3);
|
|
36624
36688
|
}
|
|
36625
36689
|
}
|
|
@@ -36638,7 +36702,7 @@ async function checkGrammarWasmFiles() {
|
|
|
36638
36702
|
}
|
|
36639
36703
|
async function checkCheckpointManifest(directory) {
|
|
36640
36704
|
const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
|
|
36641
|
-
if (!
|
|
36705
|
+
if (!existsSync9(manifestPath)) {
|
|
36642
36706
|
return {
|
|
36643
36707
|
name: "Checkpoint Manifest",
|
|
36644
36708
|
status: "\u2705",
|
|
@@ -36646,7 +36710,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
36646
36710
|
};
|
|
36647
36711
|
}
|
|
36648
36712
|
try {
|
|
36649
|
-
const content =
|
|
36713
|
+
const content = readFileSync6(manifestPath, "utf-8");
|
|
36650
36714
|
const parsed = JSON.parse(content);
|
|
36651
36715
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
36652
36716
|
return {
|
|
@@ -36690,7 +36754,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
36690
36754
|
}
|
|
36691
36755
|
async function checkEventStreamIntegrity(directory) {
|
|
36692
36756
|
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36693
|
-
if (!
|
|
36757
|
+
if (!existsSync9(eventsPath)) {
|
|
36694
36758
|
return {
|
|
36695
36759
|
name: "Event Stream",
|
|
36696
36760
|
status: "\u2705",
|
|
@@ -36698,7 +36762,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
36698
36762
|
};
|
|
36699
36763
|
}
|
|
36700
36764
|
try {
|
|
36701
|
-
const content =
|
|
36765
|
+
const content = readFileSync6(eventsPath, "utf-8");
|
|
36702
36766
|
const lines = content.split(`
|
|
36703
36767
|
`).filter((line) => line.trim() !== "");
|
|
36704
36768
|
let malformedCount = 0;
|
|
@@ -36731,7 +36795,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
36731
36795
|
}
|
|
36732
36796
|
async function checkSteeringDirectives(directory) {
|
|
36733
36797
|
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36734
|
-
if (!
|
|
36798
|
+
if (!existsSync9(eventsPath)) {
|
|
36735
36799
|
return {
|
|
36736
36800
|
name: "Steering Directives",
|
|
36737
36801
|
status: "\u2705",
|
|
@@ -36739,7 +36803,7 @@ async function checkSteeringDirectives(directory) {
|
|
|
36739
36803
|
};
|
|
36740
36804
|
}
|
|
36741
36805
|
try {
|
|
36742
|
-
const content =
|
|
36806
|
+
const content = readFileSync6(eventsPath, "utf-8");
|
|
36743
36807
|
const lines = content.split(`
|
|
36744
36808
|
`).filter((line) => line.trim() !== "");
|
|
36745
36809
|
const directivesIssued = [];
|
|
@@ -36787,7 +36851,7 @@ async function checkCurator(directory) {
|
|
|
36787
36851
|
};
|
|
36788
36852
|
}
|
|
36789
36853
|
const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
|
|
36790
|
-
if (!
|
|
36854
|
+
if (!existsSync9(summaryPath)) {
|
|
36791
36855
|
return {
|
|
36792
36856
|
name: "Curator",
|
|
36793
36857
|
status: "\u2705",
|
|
@@ -36795,7 +36859,7 @@ async function checkCurator(directory) {
|
|
|
36795
36859
|
};
|
|
36796
36860
|
}
|
|
36797
36861
|
try {
|
|
36798
|
-
const content =
|
|
36862
|
+
const content = readFileSync6(summaryPath, "utf-8");
|
|
36799
36863
|
const parsed = JSON.parse(content);
|
|
36800
36864
|
if (typeof parsed.schema_version !== "number" || parsed.schema_version !== 1) {
|
|
36801
36865
|
return {
|
|
@@ -36830,10 +36894,23 @@ async function checkCurator(directory) {
|
|
|
36830
36894
|
}
|
|
36831
36895
|
async function getDiagnoseData(directory) {
|
|
36832
36896
|
const checks5 = [];
|
|
36897
|
+
const versionCache = readVersionCache();
|
|
36898
|
+
let versionDetail = version3;
|
|
36899
|
+
let versionStatus = "\u2705";
|
|
36900
|
+
if (versionCache?.npmLatest) {
|
|
36901
|
+
const ageMs = Date.now() - versionCache.checkedAt;
|
|
36902
|
+
const ageMin = Math.max(0, Math.round(ageMs / 60000));
|
|
36903
|
+
if (compareVersions(versionCache.npmLatest, version3) > 0) {
|
|
36904
|
+
versionStatus = "\u26A0\uFE0F";
|
|
36905
|
+
versionDetail = `${version3} (npm latest: ${versionCache.npmLatest}, checked ${ageMin}m ago) ` + "\u2014 run `bunx opencode-swarm update` to refresh";
|
|
36906
|
+
} else {
|
|
36907
|
+
versionDetail = `${version3} (npm latest: ${versionCache.npmLatest}, checked ${ageMin}m ago)`;
|
|
36908
|
+
}
|
|
36909
|
+
}
|
|
36833
36910
|
checks5.push({
|
|
36834
36911
|
name: "Version",
|
|
36835
|
-
status:
|
|
36836
|
-
detail:
|
|
36912
|
+
status: versionStatus,
|
|
36913
|
+
detail: versionDetail
|
|
36837
36914
|
});
|
|
36838
36915
|
const plan = await loadPlanJsonOnly(directory);
|
|
36839
36916
|
if (plan) {
|
|
@@ -36940,7 +37017,7 @@ async function getDiagnoseData(directory) {
|
|
|
36940
37017
|
checks5.push(await checkCurator(directory));
|
|
36941
37018
|
try {
|
|
36942
37019
|
const evidenceDir = path17.join(directory, ".swarm", "evidence");
|
|
36943
|
-
const snapshotFiles =
|
|
37020
|
+
const snapshotFiles = existsSync9(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
36944
37021
|
if (snapshotFiles.length > 0) {
|
|
36945
37022
|
const latest = snapshotFiles.sort().pop();
|
|
36946
37023
|
checks5.push({
|
|
@@ -37015,7 +37092,7 @@ import * as path19 from "path";
|
|
|
37015
37092
|
|
|
37016
37093
|
// src/lang/detector.ts
|
|
37017
37094
|
import { access as access2, readdir as readdir2 } from "fs/promises";
|
|
37018
|
-
import { extname as extname2, join as
|
|
37095
|
+
import { extname as extname2, join as join16 } from "path";
|
|
37019
37096
|
|
|
37020
37097
|
// src/lang/profiles.ts
|
|
37021
37098
|
class LanguageRegistry {
|
|
@@ -37995,7 +38072,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
37995
38072
|
if (detectFile.includes("*") || detectFile.includes("?"))
|
|
37996
38073
|
continue;
|
|
37997
38074
|
try {
|
|
37998
|
-
await access2(
|
|
38075
|
+
await access2(join16(dir, detectFile));
|
|
37999
38076
|
detected.add(profile.id);
|
|
38000
38077
|
break;
|
|
38001
38078
|
} catch {}
|
|
@@ -38016,7 +38093,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
38016
38093
|
const topEntries = await readdir2(projectDir, { withFileTypes: true });
|
|
38017
38094
|
for (const entry of topEntries) {
|
|
38018
38095
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
38019
|
-
await scanDir(
|
|
38096
|
+
await scanDir(join16(projectDir, entry.name));
|
|
38020
38097
|
}
|
|
38021
38098
|
}
|
|
38022
38099
|
} catch {}
|
|
@@ -39362,14 +39439,14 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
39362
39439
|
}
|
|
39363
39440
|
// src/hooks/knowledge-migrator.ts
|
|
39364
39441
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
39365
|
-
import { existsSync as
|
|
39442
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
|
|
39366
39443
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
39367
39444
|
import * as path21 from "path";
|
|
39368
39445
|
async function migrateContextToKnowledge(directory, config3) {
|
|
39369
39446
|
const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
|
|
39370
39447
|
const contextPath = path21.join(directory, ".swarm", "context.md");
|
|
39371
39448
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
39372
|
-
if (
|
|
39449
|
+
if (existsSync13(sentinelPath)) {
|
|
39373
39450
|
return {
|
|
39374
39451
|
migrated: false,
|
|
39375
39452
|
entriesMigrated: 0,
|
|
@@ -39378,7 +39455,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
39378
39455
|
skippedReason: "sentinel-exists"
|
|
39379
39456
|
};
|
|
39380
39457
|
}
|
|
39381
|
-
if (!
|
|
39458
|
+
if (!existsSync13(contextPath)) {
|
|
39382
39459
|
return {
|
|
39383
39460
|
migrated: false,
|
|
39384
39461
|
entriesMigrated: 0,
|
|
@@ -39564,9 +39641,9 @@ function truncateLesson(text) {
|
|
|
39564
39641
|
}
|
|
39565
39642
|
function inferProjectName(directory) {
|
|
39566
39643
|
const packageJsonPath = path21.join(directory, "package.json");
|
|
39567
|
-
if (
|
|
39644
|
+
if (existsSync13(packageJsonPath)) {
|
|
39568
39645
|
try {
|
|
39569
|
-
const pkg = JSON.parse(
|
|
39646
|
+
const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
|
|
39570
39647
|
if (pkg.name && typeof pkg.name === "string") {
|
|
39571
39648
|
return pkg.name;
|
|
39572
39649
|
}
|
|
@@ -41116,10 +41193,10 @@ async function loadImpactMap(cwd) {
|
|
|
41116
41193
|
return buildImpactMap(cwd);
|
|
41117
41194
|
}
|
|
41118
41195
|
async function saveImpactMap(cwd, impactMap) {
|
|
41119
|
-
const
|
|
41120
|
-
const cachePath = path24.join(
|
|
41121
|
-
if (!fs13.existsSync(
|
|
41122
|
-
fs13.mkdirSync(
|
|
41196
|
+
const cacheDir2 = path24.join(cwd, ".swarm", "cache");
|
|
41197
|
+
const cachePath = path24.join(cacheDir2, "impact-map.json");
|
|
41198
|
+
if (!fs13.existsSync(cacheDir2)) {
|
|
41199
|
+
fs13.mkdirSync(cacheDir2, { recursive: true });
|
|
41123
41200
|
}
|
|
41124
41201
|
const data = {
|
|
41125
41202
|
generatedAt: new Date().toISOString(),
|
|
@@ -45287,7 +45364,18 @@ var CONFIG_DIR = path32.join(process.env.XDG_CONFIG_HOME || path32.join(os6.home
|
|
|
45287
45364
|
var OPENCODE_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode.json");
|
|
45288
45365
|
var PLUGIN_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode-swarm.json");
|
|
45289
45366
|
var PROMPTS_DIR = path32.join(CONFIG_DIR, "opencode-swarm");
|
|
45290
|
-
var
|
|
45367
|
+
var OPENCODE_PLUGIN_CACHE_PATHS = [
|
|
45368
|
+
path32.join(process.env.XDG_CACHE_HOME || path32.join(os6.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest"),
|
|
45369
|
+
path32.join(CONFIG_DIR, "node_modules", "opencode-swarm")
|
|
45370
|
+
];
|
|
45371
|
+
function isSafeCachePath(p) {
|
|
45372
|
+
const resolved = path32.resolve(p);
|
|
45373
|
+
const home = path32.resolve(os6.homedir());
|
|
45374
|
+
if (resolved === "/" || resolved === home || resolved.length <= home.length)
|
|
45375
|
+
return false;
|
|
45376
|
+
const leaf = path32.basename(resolved);
|
|
45377
|
+
return leaf === "opencode-swarm@latest" || leaf === "opencode-swarm";
|
|
45378
|
+
}
|
|
45291
45379
|
function ensureDir(dir) {
|
|
45292
45380
|
if (!fs21.existsSync(dir)) {
|
|
45293
45381
|
fs21.mkdirSync(dir, { recursive: true });
|
|
@@ -45358,14 +45446,13 @@ async function install() {
|
|
|
45358
45446
|
saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
|
|
45359
45447
|
console.log("\u2713 Added opencode-swarm to OpenCode plugins");
|
|
45360
45448
|
console.log("\u2713 Disabled default OpenCode agents (explore, general)");
|
|
45361
|
-
|
|
45362
|
-
|
|
45363
|
-
|
|
45364
|
-
|
|
45365
|
-
|
|
45366
|
-
|
|
45367
|
-
|
|
45368
|
-
console.warn(` ${OPENCODE_PLUGIN_CACHE_PATH}`);
|
|
45449
|
+
const evicted = evictPluginCaches();
|
|
45450
|
+
if (evicted.cleared.length > 0) {
|
|
45451
|
+
console.log(`\u2713 Cleared opencode plugin cache (next start will fetch latest): ${evicted.cleared.join(", ")}`);
|
|
45452
|
+
}
|
|
45453
|
+
for (const failed of evicted.failed) {
|
|
45454
|
+
console.warn(`\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:
|
|
45455
|
+
${failed}`);
|
|
45369
45456
|
}
|
|
45370
45457
|
if (!fs21.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
45371
45458
|
const defaultConfig = {
|
|
@@ -45465,6 +45552,51 @@ Next steps:`);
|
|
|
45465
45552
|
console.log(" \u2014 use it as a reference for customizing model assignments.");
|
|
45466
45553
|
return 0;
|
|
45467
45554
|
}
|
|
45555
|
+
async function update() {
|
|
45556
|
+
console.log(`\uD83D\uDC1D Refreshing OpenCode Swarm plugin cache...
|
|
45557
|
+
`);
|
|
45558
|
+
const result = evictPluginCaches();
|
|
45559
|
+
if (result.cleared.length > 0) {
|
|
45560
|
+
for (const cleared of result.cleared) {
|
|
45561
|
+
console.log(`\u2713 Cleared: ${cleared}`);
|
|
45562
|
+
}
|
|
45563
|
+
console.log(`
|
|
45564
|
+
Restart OpenCode to fetch the latest version from npm.`);
|
|
45565
|
+
}
|
|
45566
|
+
if (result.cleared.length === 0 && result.failed.length === 0) {
|
|
45567
|
+
console.log("No cached plugin found. Restart OpenCode to fetch the latest version from npm.");
|
|
45568
|
+
console.log("Checked locations:");
|
|
45569
|
+
for (const p of OPENCODE_PLUGIN_CACHE_PATHS) {
|
|
45570
|
+
console.log(` - ${p}`);
|
|
45571
|
+
}
|
|
45572
|
+
}
|
|
45573
|
+
if (result.failed.length > 0) {
|
|
45574
|
+
for (const failed of result.failed) {
|
|
45575
|
+
console.error(`\u2717 Could not clear: ${failed}`);
|
|
45576
|
+
}
|
|
45577
|
+
return 1;
|
|
45578
|
+
}
|
|
45579
|
+
return 0;
|
|
45580
|
+
}
|
|
45581
|
+
function evictPluginCaches() {
|
|
45582
|
+
const cleared = [];
|
|
45583
|
+
const failed = [];
|
|
45584
|
+
for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
|
|
45585
|
+
if (!fs21.existsSync(cachePath))
|
|
45586
|
+
continue;
|
|
45587
|
+
if (!isSafeCachePath(cachePath)) {
|
|
45588
|
+
failed.push(`${cachePath} (refused: failed safety check)`);
|
|
45589
|
+
continue;
|
|
45590
|
+
}
|
|
45591
|
+
try {
|
|
45592
|
+
fs21.rmSync(cachePath, { recursive: true, force: true });
|
|
45593
|
+
cleared.push(cachePath);
|
|
45594
|
+
} catch (err) {
|
|
45595
|
+
failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
|
|
45596
|
+
}
|
|
45597
|
+
}
|
|
45598
|
+
return { cleared, failed };
|
|
45599
|
+
}
|
|
45468
45600
|
async function uninstall() {
|
|
45469
45601
|
try {
|
|
45470
45602
|
console.log(`\uD83D\uDC1D Uninstalling OpenCode Swarm...
|
|
@@ -45535,6 +45667,7 @@ Usage: bunx opencode-swarm [command] [OPTIONS]
|
|
|
45535
45667
|
|
|
45536
45668
|
Commands:
|
|
45537
45669
|
install Install and configure the plugin (default)
|
|
45670
|
+
update Refresh OpenCode's plugin cache so the next start fetches latest from npm
|
|
45538
45671
|
uninstall Remove the plugin from OpenCode config
|
|
45539
45672
|
run Run a plugin command directly (for use outside OpenCode)
|
|
45540
45673
|
|
|
@@ -45559,6 +45692,7 @@ Custom Prompts:
|
|
|
45559
45692
|
|
|
45560
45693
|
Examples:
|
|
45561
45694
|
bunx opencode-swarm install
|
|
45695
|
+
bunx opencode-swarm update
|
|
45562
45696
|
bunx opencode-swarm uninstall
|
|
45563
45697
|
bunx opencode-swarm uninstall --clean
|
|
45564
45698
|
bunx opencode-swarm --help
|
|
@@ -45584,6 +45718,9 @@ async function main() {
|
|
|
45584
45718
|
if (command === "install") {
|
|
45585
45719
|
const exitCode = await install();
|
|
45586
45720
|
process.exit(exitCode);
|
|
45721
|
+
} else if (command === "update") {
|
|
45722
|
+
const exitCode = await update();
|
|
45723
|
+
process.exit(exitCode);
|
|
45587
45724
|
} else if (command === "uninstall") {
|
|
45588
45725
|
const exitCode = await uninstall();
|
|
45589
45726
|
process.exit(exitCode);
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -576,6 +576,7 @@ export declare const CouncilConfigSchema: z.ZodObject<{
|
|
|
576
576
|
parallelTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
577
577
|
vetoPriority: z.ZodDefault<z.ZodBoolean>;
|
|
578
578
|
requireAllMembers: z.ZodDefault<z.ZodBoolean>;
|
|
579
|
+
minimumMembers: z.ZodDefault<z.ZodNumber>;
|
|
579
580
|
escalateOnMaxRounds: z.ZodOptional<z.ZodString>;
|
|
580
581
|
general: z.ZodOptional<z.ZodObject<{
|
|
581
582
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -996,6 +997,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
996
997
|
parallelTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
997
998
|
vetoPriority: z.ZodDefault<z.ZodBoolean>;
|
|
998
999
|
requireAllMembers: z.ZodDefault<z.ZodBoolean>;
|
|
1000
|
+
minimumMembers: z.ZodDefault<z.ZodNumber>;
|
|
999
1001
|
escalateOnMaxRounds: z.ZodOptional<z.ZodString>;
|
|
1000
1002
|
general: z.ZodOptional<z.ZodObject<{
|
|
1001
1003
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -1046,6 +1048,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
1046
1048
|
}, z.core.$strip>>;
|
|
1047
1049
|
turbo_mode: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
1048
1050
|
quiet: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
1051
|
+
version_check: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
|
|
1049
1052
|
full_auto: z.ZodDefault<z.ZodOptional<z.ZodObject<{
|
|
1050
1053
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1051
1054
|
critic_model: z.ZodOptional<z.ZodString>;
|
package/dist/council/types.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export interface CouncilSynthesis {
|
|
|
48
48
|
/** 1-indexed */
|
|
49
49
|
roundNumber: number;
|
|
50
50
|
allCriteriaMet: boolean;
|
|
51
|
+
/** Distinct council members that produced verdicts (deduplicated count). */
|
|
52
|
+
quorumSize: number;
|
|
51
53
|
/** true when called with an empty verdicts array — the APPROVE is vacuous */
|
|
52
54
|
emptyVerdictsWarning?: boolean;
|
|
53
55
|
}
|
|
@@ -71,8 +73,10 @@ export interface CouncilConfig {
|
|
|
71
73
|
parallelTimeoutMs: number;
|
|
72
74
|
/** Default true — any REJECT blocks */
|
|
73
75
|
vetoPriority: boolean;
|
|
74
|
-
/** Default false — when true,
|
|
76
|
+
/** Default false — when true, submit_council_verdicts rejects unless all 5 member verdicts are provided */
|
|
75
77
|
requireAllMembers: boolean;
|
|
78
|
+
/** Default 3 — minimum distinct council members required for quorum. requireAllMembers: true overrides this to 5. */
|
|
79
|
+
minimumMembers: number;
|
|
76
80
|
/**
|
|
77
81
|
* Optional webhook URL or handler name for auto-escalation when maxRounds is
|
|
78
82
|
* reached without APPROVE. Reserved for forward compatibility — NOT yet
|
package/dist/db/global-db.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* rules and agent prompt sections. Per-project QA gate profiles live in the
|
|
6
6
|
* project DB (see `./project-db.ts`), not here.
|
|
7
7
|
*/
|
|
8
|
-
import { Database } from 'bun:sqlite';
|
|
8
|
+
import type { Database } from 'bun:sqlite';
|
|
9
9
|
/**
|
|
10
10
|
* Run all pending migrations on the provided database.
|
|
11
11
|
* Idempotent: existing migrations are not re-applied.
|
package/dist/db/project-db.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* constraints and QA gate profiles. One cached instance per normalized
|
|
6
6
|
* directory path.
|
|
7
7
|
*/
|
|
8
|
-
import { Database } from 'bun:sqlite';
|
|
8
|
+
import type { Database } from 'bun:sqlite';
|
|
9
9
|
/**
|
|
10
10
|
* Run all pending migrations on the provided database.
|
|
11
11
|
* Idempotent: existing migrations are not re-applied.
|
|
@@ -85,7 +85,7 @@ export declare function computeProfileHash(profile: QaGateProfile): string;
|
|
|
85
85
|
* machine; blocks coder→next-coder advancement until reviewer + test_engineer
|
|
86
86
|
* delegations observed).
|
|
87
87
|
* - council_mode — src/state.ts isCouncilGateActive + src/hooks/delegation-gate.ts
|
|
88
|
-
* (Stage B replaced by
|
|
88
|
+
* (Stage B replaced by submit_council_verdicts verdict).
|
|
89
89
|
* - sme_enabled — consumed during MODE: BRAINSTORM/SPECIFY architect dialogue.
|
|
90
90
|
* - critic_pre_plan — consumed by MODE: PLAN critic delegation before save_plan.
|
|
91
91
|
* - sast_enabled — consumed inside pre_check_batch tool.
|