opencode-swarm 6.86.7 → 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 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.7",
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 bun --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",
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 .",
@@ -19691,6 +19691,7 @@ var PluginConfigSchema = exports_external.object({
19691
19691
  parallelization: ParallelizationConfigSchema.optional(),
19692
19692
  turbo_mode: exports_external.boolean().default(false).optional(),
19693
19693
  quiet: exports_external.boolean().default(false).optional(),
19694
+ version_check: exports_external.boolean().default(true).optional(),
19694
19695
  full_auto: exports_external.object({
19695
19696
  enabled: exports_external.boolean().default(false),
19696
19697
  critic_model: exports_external.string().optional(),
@@ -19967,9 +19968,17 @@ init_plan_schema();
19967
19968
  import { createHash as createHash3 } from "crypto";
19968
19969
 
19969
19970
  // src/db/project-db.ts
19970
- import { Database } from "bun:sqlite";
19971
19971
  import { existsSync as existsSync5, mkdirSync as mkdirSync4 } from "fs";
19972
+ import { createRequire } from "module";
19972
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
+ }
19973
19982
  var MIGRATIONS = [
19974
19983
  {
19975
19984
  version: 1,
@@ -20040,7 +20049,8 @@ function getProjectDb(directory) {
20040
20049
  return existing;
20041
20050
  const swarmDir = join7(key, ".swarm");
20042
20051
  mkdirSync4(swarmDir, { recursive: true });
20043
- const db = new Database(join7(swarmDir, "swarm.db"));
20052
+ const Db = loadDatabaseCtor();
20053
+ const db = new Db(join7(swarmDir, "swarm.db"));
20044
20054
  db.run("PRAGMA journal_mode = WAL;");
20045
20055
  db.run("PRAGMA synchronous = NORMAL;");
20046
20056
  db.run("PRAGMA busy_timeout = 5000;");
@@ -36258,12 +36268,65 @@ async function handleDarkMatterCommand(directory, args) {
36258
36268
 
36259
36269
  // src/services/diagnose-service.ts
36260
36270
  import * as child_process4 from "child_process";
36261
- import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync5 } from "fs";
36271
+ import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
36262
36272
  import path17 from "path";
36263
36273
  import { fileURLToPath } from "url";
36264
36274
  init_manager2();
36265
36275
  init_utils2();
36266
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
36267
36330
  var { version: version3 } = package_default;
36268
36331
  function validateTaskDag(plan) {
36269
36332
  const allTaskIds = new Set;
@@ -36496,7 +36559,7 @@ async function checkConfigBackups(directory) {
36496
36559
  }
36497
36560
  async function checkGitRepository(directory) {
36498
36561
  try {
36499
- if (!existsSync8(directory) || !statSync5(directory).isDirectory()) {
36562
+ if (!existsSync9(directory) || !statSync5(directory).isDirectory()) {
36500
36563
  return {
36501
36564
  name: "Git Repository",
36502
36565
  status: "\u274C",
@@ -36561,7 +36624,7 @@ async function checkSpecStaleness(directory, plan) {
36561
36624
  }
36562
36625
  async function checkConfigParseability(directory) {
36563
36626
  const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
36564
- if (!existsSync8(configPath)) {
36627
+ if (!existsSync9(configPath)) {
36565
36628
  return {
36566
36629
  name: "Config Parseability",
36567
36630
  status: "\u2705",
@@ -36569,7 +36632,7 @@ async function checkConfigParseability(directory) {
36569
36632
  };
36570
36633
  }
36571
36634
  try {
36572
- const content = readFileSync5(configPath, "utf-8");
36635
+ const content = readFileSync6(configPath, "utf-8");
36573
36636
  JSON.parse(content);
36574
36637
  return {
36575
36638
  name: "Config Parseability",
@@ -36616,11 +36679,11 @@ async function checkGrammarWasmFiles() {
36616
36679
  const thisDir = path17.dirname(fileURLToPath(import.meta.url));
36617
36680
  const grammarDir = resolveGrammarDir(thisDir);
36618
36681
  const missing = [];
36619
- if (!existsSync8(path17.join(grammarDir, "tree-sitter.wasm"))) {
36682
+ if (!existsSync9(path17.join(grammarDir, "tree-sitter.wasm"))) {
36620
36683
  missing.push("tree-sitter.wasm (core runtime)");
36621
36684
  }
36622
36685
  for (const file3 of grammarFiles) {
36623
- if (!existsSync8(path17.join(grammarDir, file3))) {
36686
+ if (!existsSync9(path17.join(grammarDir, file3))) {
36624
36687
  missing.push(file3);
36625
36688
  }
36626
36689
  }
@@ -36639,7 +36702,7 @@ async function checkGrammarWasmFiles() {
36639
36702
  }
36640
36703
  async function checkCheckpointManifest(directory) {
36641
36704
  const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
36642
- if (!existsSync8(manifestPath)) {
36705
+ if (!existsSync9(manifestPath)) {
36643
36706
  return {
36644
36707
  name: "Checkpoint Manifest",
36645
36708
  status: "\u2705",
@@ -36647,7 +36710,7 @@ async function checkCheckpointManifest(directory) {
36647
36710
  };
36648
36711
  }
36649
36712
  try {
36650
- const content = readFileSync5(manifestPath, "utf-8");
36713
+ const content = readFileSync6(manifestPath, "utf-8");
36651
36714
  const parsed = JSON.parse(content);
36652
36715
  if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
36653
36716
  return {
@@ -36691,7 +36754,7 @@ async function checkCheckpointManifest(directory) {
36691
36754
  }
36692
36755
  async function checkEventStreamIntegrity(directory) {
36693
36756
  const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36694
- if (!existsSync8(eventsPath)) {
36757
+ if (!existsSync9(eventsPath)) {
36695
36758
  return {
36696
36759
  name: "Event Stream",
36697
36760
  status: "\u2705",
@@ -36699,7 +36762,7 @@ async function checkEventStreamIntegrity(directory) {
36699
36762
  };
36700
36763
  }
36701
36764
  try {
36702
- const content = readFileSync5(eventsPath, "utf-8");
36765
+ const content = readFileSync6(eventsPath, "utf-8");
36703
36766
  const lines = content.split(`
36704
36767
  `).filter((line) => line.trim() !== "");
36705
36768
  let malformedCount = 0;
@@ -36732,7 +36795,7 @@ async function checkEventStreamIntegrity(directory) {
36732
36795
  }
36733
36796
  async function checkSteeringDirectives(directory) {
36734
36797
  const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36735
- if (!existsSync8(eventsPath)) {
36798
+ if (!existsSync9(eventsPath)) {
36736
36799
  return {
36737
36800
  name: "Steering Directives",
36738
36801
  status: "\u2705",
@@ -36740,7 +36803,7 @@ async function checkSteeringDirectives(directory) {
36740
36803
  };
36741
36804
  }
36742
36805
  try {
36743
- const content = readFileSync5(eventsPath, "utf-8");
36806
+ const content = readFileSync6(eventsPath, "utf-8");
36744
36807
  const lines = content.split(`
36745
36808
  `).filter((line) => line.trim() !== "");
36746
36809
  const directivesIssued = [];
@@ -36788,7 +36851,7 @@ async function checkCurator(directory) {
36788
36851
  };
36789
36852
  }
36790
36853
  const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
36791
- if (!existsSync8(summaryPath)) {
36854
+ if (!existsSync9(summaryPath)) {
36792
36855
  return {
36793
36856
  name: "Curator",
36794
36857
  status: "\u2705",
@@ -36796,7 +36859,7 @@ async function checkCurator(directory) {
36796
36859
  };
36797
36860
  }
36798
36861
  try {
36799
- const content = readFileSync5(summaryPath, "utf-8");
36862
+ const content = readFileSync6(summaryPath, "utf-8");
36800
36863
  const parsed = JSON.parse(content);
36801
36864
  if (typeof parsed.schema_version !== "number" || parsed.schema_version !== 1) {
36802
36865
  return {
@@ -36831,10 +36894,23 @@ async function checkCurator(directory) {
36831
36894
  }
36832
36895
  async function getDiagnoseData(directory) {
36833
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
+ }
36834
36910
  checks5.push({
36835
36911
  name: "Version",
36836
- status: "\u2705",
36837
- detail: version3
36912
+ status: versionStatus,
36913
+ detail: versionDetail
36838
36914
  });
36839
36915
  const plan = await loadPlanJsonOnly(directory);
36840
36916
  if (plan) {
@@ -36941,7 +37017,7 @@ async function getDiagnoseData(directory) {
36941
37017
  checks5.push(await checkCurator(directory));
36942
37018
  try {
36943
37019
  const evidenceDir = path17.join(directory, ".swarm", "evidence");
36944
- const snapshotFiles = existsSync8(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
37020
+ const snapshotFiles = existsSync9(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
36945
37021
  if (snapshotFiles.length > 0) {
36946
37022
  const latest = snapshotFiles.sort().pop();
36947
37023
  checks5.push({
@@ -37016,7 +37092,7 @@ import * as path19 from "path";
37016
37092
 
37017
37093
  // src/lang/detector.ts
37018
37094
  import { access as access2, readdir as readdir2 } from "fs/promises";
37019
- import { extname as extname2, join as join15 } from "path";
37095
+ import { extname as extname2, join as join16 } from "path";
37020
37096
 
37021
37097
  // src/lang/profiles.ts
37022
37098
  class LanguageRegistry {
@@ -37996,7 +38072,7 @@ async function detectProjectLanguages(projectDir) {
37996
38072
  if (detectFile.includes("*") || detectFile.includes("?"))
37997
38073
  continue;
37998
38074
  try {
37999
- await access2(join15(dir, detectFile));
38075
+ await access2(join16(dir, detectFile));
38000
38076
  detected.add(profile.id);
38001
38077
  break;
38002
38078
  } catch {}
@@ -38017,7 +38093,7 @@ async function detectProjectLanguages(projectDir) {
38017
38093
  const topEntries = await readdir2(projectDir, { withFileTypes: true });
38018
38094
  for (const entry of topEntries) {
38019
38095
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
38020
- await scanDir(join15(projectDir, entry.name));
38096
+ await scanDir(join16(projectDir, entry.name));
38021
38097
  }
38022
38098
  }
38023
38099
  } catch {}
@@ -39363,14 +39439,14 @@ async function handleHistoryCommand(directory, _args) {
39363
39439
  }
39364
39440
  // src/hooks/knowledge-migrator.ts
39365
39441
  import { randomUUID as randomUUID2 } from "crypto";
39366
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
39442
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
39367
39443
  import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
39368
39444
  import * as path21 from "path";
39369
39445
  async function migrateContextToKnowledge(directory, config3) {
39370
39446
  const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
39371
39447
  const contextPath = path21.join(directory, ".swarm", "context.md");
39372
39448
  const knowledgePath = resolveSwarmKnowledgePath(directory);
39373
- if (existsSync12(sentinelPath)) {
39449
+ if (existsSync13(sentinelPath)) {
39374
39450
  return {
39375
39451
  migrated: false,
39376
39452
  entriesMigrated: 0,
@@ -39379,7 +39455,7 @@ async function migrateContextToKnowledge(directory, config3) {
39379
39455
  skippedReason: "sentinel-exists"
39380
39456
  };
39381
39457
  }
39382
- if (!existsSync12(contextPath)) {
39458
+ if (!existsSync13(contextPath)) {
39383
39459
  return {
39384
39460
  migrated: false,
39385
39461
  entriesMigrated: 0,
@@ -39565,9 +39641,9 @@ function truncateLesson(text) {
39565
39641
  }
39566
39642
  function inferProjectName(directory) {
39567
39643
  const packageJsonPath = path21.join(directory, "package.json");
39568
- if (existsSync12(packageJsonPath)) {
39644
+ if (existsSync13(packageJsonPath)) {
39569
39645
  try {
39570
- const pkg = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
39646
+ const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
39571
39647
  if (pkg.name && typeof pkg.name === "string") {
39572
39648
  return pkg.name;
39573
39649
  }
@@ -41117,10 +41193,10 @@ async function loadImpactMap(cwd) {
41117
41193
  return buildImpactMap(cwd);
41118
41194
  }
41119
41195
  async function saveImpactMap(cwd, impactMap) {
41120
- const cacheDir = path24.join(cwd, ".swarm", "cache");
41121
- const cachePath = path24.join(cacheDir, "impact-map.json");
41122
- if (!fs13.existsSync(cacheDir)) {
41123
- fs13.mkdirSync(cacheDir, { recursive: true });
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 });
41124
41200
  }
41125
41201
  const data = {
41126
41202
  generatedAt: new Date().toISOString(),
@@ -45288,7 +45364,18 @@ var CONFIG_DIR = path32.join(process.env.XDG_CONFIG_HOME || path32.join(os6.home
45288
45364
  var OPENCODE_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode.json");
45289
45365
  var PLUGIN_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode-swarm.json");
45290
45366
  var PROMPTS_DIR = path32.join(CONFIG_DIR, "opencode-swarm");
45291
- var OPENCODE_PLUGIN_CACHE_PATH = path32.join(process.env.XDG_CACHE_HOME || path32.join(os6.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest");
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
+ }
45292
45379
  function ensureDir(dir) {
45293
45380
  if (!fs21.existsSync(dir)) {
45294
45381
  fs21.mkdirSync(dir, { recursive: true });
@@ -45359,14 +45446,13 @@ async function install() {
45359
45446
  saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
45360
45447
  console.log("\u2713 Added opencode-swarm to OpenCode plugins");
45361
45448
  console.log("\u2713 Disabled default OpenCode agents (explore, general)");
45362
- try {
45363
- if (fs21.existsSync(OPENCODE_PLUGIN_CACHE_PATH)) {
45364
- fs21.rmSync(OPENCODE_PLUGIN_CACHE_PATH, { recursive: true, force: true });
45365
- console.log("\u2713 Cleared opencode plugin cache (next start will fetch latest)");
45366
- }
45367
- } catch {
45368
- console.warn("\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:");
45369
- 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}`);
45370
45456
  }
45371
45457
  if (!fs21.existsSync(PLUGIN_CONFIG_PATH)) {
45372
45458
  const defaultConfig = {
@@ -45466,6 +45552,51 @@ Next steps:`);
45466
45552
  console.log(" \u2014 use it as a reference for customizing model assignments.");
45467
45553
  return 0;
45468
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
+ }
45469
45600
  async function uninstall() {
45470
45601
  try {
45471
45602
  console.log(`\uD83D\uDC1D Uninstalling OpenCode Swarm...
@@ -45536,6 +45667,7 @@ Usage: bunx opencode-swarm [command] [OPTIONS]
45536
45667
 
45537
45668
  Commands:
45538
45669
  install Install and configure the plugin (default)
45670
+ update Refresh OpenCode's plugin cache so the next start fetches latest from npm
45539
45671
  uninstall Remove the plugin from OpenCode config
45540
45672
  run Run a plugin command directly (for use outside OpenCode)
45541
45673
 
@@ -45560,6 +45692,7 @@ Custom Prompts:
45560
45692
 
45561
45693
  Examples:
45562
45694
  bunx opencode-swarm install
45695
+ bunx opencode-swarm update
45563
45696
  bunx opencode-swarm uninstall
45564
45697
  bunx opencode-swarm uninstall --clean
45565
45698
  bunx opencode-swarm --help
@@ -45585,6 +45718,9 @@ async function main() {
45585
45718
  if (command === "install") {
45586
45719
  const exitCode = await install();
45587
45720
  process.exit(exitCode);
45721
+ } else if (command === "update") {
45722
+ const exitCode = await update();
45723
+ process.exit(exitCode);
45588
45724
  } else if (command === "uninstall") {
45589
45725
  const exitCode = await uninstall();
45590
45726
  process.exit(exitCode);
@@ -1048,6 +1048,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
1048
1048
  }, z.core.$strip>>;
1049
1049
  turbo_mode: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
1050
1050
  quiet: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
1051
+ version_check: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
1051
1052
  full_auto: z.ZodDefault<z.ZodOptional<z.ZodObject<{
1052
1053
  enabled: z.ZodDefault<z.ZodBoolean>;
1053
1054
  critic_model: z.ZodOptional<z.ZodString>;
@@ -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.
@@ -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.