opencode-swarm 7.0.0 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,34 @@
1
1
  #!/usr/bin/env bun
2
+ export declare function isSafeCachePath(p: string): boolean;
3
+ /**
4
+ * Safety guard for lock file deletion. Lock files have different basenames
5
+ * than cache directories so they need a separate check. Mirrors
6
+ * isSafeCachePath()'s defense-in-depth: minimum segment depth, recognized
7
+ * basename, and parent directory must be 'opencode'.
8
+ */
9
+ export declare function isSafeLockFilePath(p: string): boolean;
10
+ /**
11
+ * Recursively delete every known opencode plugin cache location for
12
+ * opencode-swarm. Returns paths actually cleared and paths that errored.
13
+ * Skips paths that don't exist or fail the safety guard.
14
+ */
15
+ export declare function evictPluginCaches(): {
16
+ cleared: string[];
17
+ failed: string[];
18
+ };
19
+ /**
20
+ * Delete every known opencode plugin lock file (bun.lock, bun.lockb,
21
+ * package-lock.json). Returns paths actually cleared and paths that
22
+ * errored. Skips paths that don't exist or fail the safety guard.
23
+ *
24
+ * Why: opencode runs `bun install` at startup; bun.lock pins the
25
+ * installed plugin version. Deleting the lock forces re-resolution
26
+ * from npm so users actually receive the @latest version after `update`.
27
+ */
28
+ export declare function evictLockFiles(): {
29
+ cleared: string[];
30
+ failed: string[];
31
+ };
2
32
  /**
3
33
  * Dispatch function for routing argv tokens to plugin command handlers.
4
34
  * Used by the "run" subcommand entry point.
package/dist/cli/index.js CHANGED
@@ -14736,7 +14736,7 @@ async function loadPlan(directory) {
14736
14736
  const rebuilt = await replayFromLedger(directory);
14737
14737
  if (rebuilt) {
14738
14738
  await rebuildPlan(directory, rebuilt);
14739
- warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at SWARM_PLAN.md if it exists.");
14739
+ warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at .swarm/SWARM_PLAN.md if it exists.");
14740
14740
  return rebuilt;
14741
14741
  }
14742
14742
  } catch (replayError) {
@@ -14757,7 +14757,7 @@ async function loadPlan(directory) {
14757
14757
  return approved.plan;
14758
14758
  }
14759
14759
  } catch {}
14760
- warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
14760
+ warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check .swarm/SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
14761
14761
  }
14762
14762
  }
14763
14763
  }
@@ -14803,7 +14803,7 @@ async function loadPlan(directory) {
14803
14803
  }
14804
14804
  return validated;
14805
14805
  } catch (error49) {
14806
- warn(`[loadPlan] plan.json validation failed: ${error49 instanceof Error ? error49.message : String(error49)}. Attempting rebuild from ledger. If rebuild fails, check SWARM_PLAN.md for a checkpoint.`);
14806
+ warn(`[loadPlan] plan.json validation failed: ${error49 instanceof Error ? error49.message : String(error49)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/SWARM_PLAN.md for a checkpoint.`);
14807
14807
  let rawPlanId = null;
14808
14808
  try {
14809
14809
  const rawParsed = JSON.parse(planJsonContent);
@@ -18577,11 +18577,11 @@ var init_evidence_summary_service = __esm(() => {
18577
18577
  // src/cli/index.ts
18578
18578
  import * as fs21 from "fs";
18579
18579
  import * as os7 from "os";
18580
- import * as path33 from "path";
18580
+ import * as path34 from "path";
18581
18581
  // package.json
18582
18582
  var package_default = {
18583
18583
  name: "opencode-swarm",
18584
- version: "7.0.0",
18584
+ version: "7.0.1",
18585
18585
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
18586
18586
  main: "dist/index.js",
18587
18587
  types: "dist/index.d.ts",
@@ -35492,22 +35492,20 @@ async function handleCloseCommand(directory, args) {
35492
35492
  }
35493
35493
  } catch {}
35494
35494
  let swarmPlanFilesRemoved = 0;
35495
- const swarmPlanJsonPath = path12.join(directory, "SWARM_PLAN.json");
35496
- const swarmPlanMdPath = path12.join(directory, "SWARM_PLAN.md");
35497
- try {
35498
- await fs7.unlink(swarmPlanJsonPath);
35499
- swarmPlanFilesRemoved++;
35500
- } catch (err) {
35501
- if (err?.code !== "ENOENT") {
35502
- warnings.push(`Failed to remove SWARM_PLAN.json: ${err instanceof Error ? err.message : String(err)}`);
35503
- }
35504
- }
35505
- try {
35506
- await fs7.unlink(swarmPlanMdPath);
35507
- swarmPlanFilesRemoved++;
35508
- } catch (err) {
35509
- if (err?.code !== "ENOENT") {
35510
- warnings.push(`Failed to remove SWARM_PLAN.md: ${err instanceof Error ? err.message : String(err)}`);
35495
+ const candidates = [
35496
+ path12.join(directory, ".swarm", "SWARM_PLAN.json"),
35497
+ path12.join(directory, ".swarm", "SWARM_PLAN.md"),
35498
+ path12.join(directory, "SWARM_PLAN.json"),
35499
+ path12.join(directory, "SWARM_PLAN.md")
35500
+ ];
35501
+ for (const candidate of candidates) {
35502
+ try {
35503
+ await fs7.unlink(candidate);
35504
+ swarmPlanFilesRemoved++;
35505
+ } catch (err) {
35506
+ if (err?.code !== "ENOENT") {
35507
+ warnings.push(`Failed to remove ${path12.basename(candidate)}: ${err instanceof Error ? err.message : String(err)}`);
35508
+ }
35511
35509
  }
35512
35510
  }
35513
35511
  clearAllScopes(directory);
@@ -35582,9 +35580,7 @@ async function handleCloseCommand(directory, args) {
35582
35580
  "- Reset context.md for next session",
35583
35581
  "- Cleared agent sessions and delegation chains",
35584
35582
  ...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
35585
- ...swarmPlanFilesRemoved > 0 ? [
35586
- `- Removed ${swarmPlanFilesRemoved} root-level SWARM_PLAN checkpoint artifact(s)`
35587
- ] : [],
35583
+ ...swarmPlanFilesRemoved > 0 ? [`- Removed ${swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s)`] : [],
35588
35584
  ...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
35589
35585
  ...curationSucceeded && allLessons.length > 0 ? [`- Committed ${allLessons.length} lesson(s) to knowledge store`] : [],
35590
35586
  "",
@@ -36471,11 +36467,39 @@ function getPluginConfigDir() {
36471
36467
  function getPluginCachePaths() {
36472
36468
  const cacheBase = process.env.XDG_CACHE_HOME || path17.join(os5.homedir(), ".cache");
36473
36469
  const configDir = getPluginConfigDir();
36474
- return [
36470
+ const paths = [
36471
+ path17.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
36475
36472
  path17.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
36476
- path17.join(configDir, "node_modules", "opencode-swarm"),
36477
- path17.join(cacheBase, "opencode", "node_modules", "opencode-swarm")
36473
+ path17.join(configDir, "node_modules", "opencode-swarm")
36478
36474
  ];
36475
+ if (process.platform === "darwin") {
36476
+ const libCaches = path17.join(os5.homedir(), "Library", "Caches");
36477
+ paths.push(path17.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path17.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
36478
+ }
36479
+ if (process.platform === "win32") {
36480
+ const localAppData = process.env.LOCALAPPDATA || path17.join(os5.homedir(), "AppData", "Local");
36481
+ const appData = process.env.APPDATA || path17.join(os5.homedir(), "AppData", "Roaming");
36482
+ paths.push(path17.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path17.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path17.join(appData, "opencode", "node_modules", "opencode-swarm"));
36483
+ }
36484
+ return paths;
36485
+ }
36486
+ function getPluginLockFilePaths() {
36487
+ const cacheBase = process.env.XDG_CACHE_HOME || path17.join(os5.homedir(), ".cache");
36488
+ const configDir = getPluginConfigDir();
36489
+ const paths = [
36490
+ path17.join(cacheBase, "opencode", "bun.lock"),
36491
+ path17.join(cacheBase, "opencode", "bun.lockb"),
36492
+ path17.join(configDir, "package-lock.json")
36493
+ ];
36494
+ if (process.platform === "darwin") {
36495
+ const libCaches = path17.join(os5.homedir(), "Library", "Caches");
36496
+ paths.push(path17.join(libCaches, "opencode", "bun.lock"), path17.join(libCaches, "opencode", "bun.lockb"));
36497
+ }
36498
+ if (process.platform === "win32") {
36499
+ const localAppData = process.env.LOCALAPPDATA || path17.join(os5.homedir(), "AppData", "Local");
36500
+ paths.push(path17.join(localAppData, "opencode", "bun.lock"), path17.join(localAppData, "opencode", "bun.lockb"));
36501
+ }
36502
+ return paths;
36479
36503
  }
36480
36504
 
36481
36505
  // src/services/diagnose-service.ts
@@ -44454,6 +44478,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
44454
44478
 
44455
44479
  // src/commands/reset.ts
44456
44480
  import * as fs18 from "fs";
44481
+ import * as path30 from "path";
44457
44482
 
44458
44483
  // src/background/manager.ts
44459
44484
  init_utils();
@@ -45141,7 +45166,7 @@ async function handleResetCommand(directory, args) {
45141
45166
  return [
45142
45167
  "## Swarm Reset",
45143
45168
  "",
45144
- "\u26A0\uFE0F This will delete plan.md and context.md from .swarm/",
45169
+ "\u26A0\uFE0F This will delete all swarm state from .swarm/ (plan, context, checkpoints, SWARM_PLAN artifacts)",
45145
45170
  "",
45146
45171
  "**Tip**: Run `/swarm export` first to backup your state.",
45147
45172
  "",
@@ -45149,7 +45174,15 @@ async function handleResetCommand(directory, args) {
45149
45174
  ].join(`
45150
45175
  `);
45151
45176
  }
45152
- const filesToReset = ["plan.md", "context.md"];
45177
+ const filesToReset = [
45178
+ "plan.md",
45179
+ "plan.json",
45180
+ "context.md",
45181
+ "SWARM_PLAN.md",
45182
+ "SWARM_PLAN.json",
45183
+ "checkpoints.json",
45184
+ "events.jsonl"
45185
+ ];
45153
45186
  const results = [];
45154
45187
  for (const filename of filesToReset) {
45155
45188
  try {
@@ -45164,6 +45197,15 @@ async function handleResetCommand(directory, args) {
45164
45197
  results.push(`- \u274C Failed to delete ${filename}`);
45165
45198
  }
45166
45199
  }
45200
+ for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
45201
+ try {
45202
+ const rootPath = path30.join(directory, filename);
45203
+ if (fs18.existsSync(rootPath)) {
45204
+ fs18.unlinkSync(rootPath);
45205
+ results.push(`- \u2705 Deleted ${filename} (root)`);
45206
+ }
45207
+ } catch {}
45208
+ }
45167
45209
  try {
45168
45210
  resetAutomationManager();
45169
45211
  results.push("- \u2705 Stopped background automation (in-memory queues cleared)");
@@ -45194,7 +45236,7 @@ async function handleResetCommand(directory, args) {
45194
45236
  // src/commands/reset-session.ts
45195
45237
  init_utils2();
45196
45238
  import * as fs19 from "fs";
45197
- import * as path30 from "path";
45239
+ import * as path31 from "path";
45198
45240
  async function handleResetSessionCommand(directory, _args) {
45199
45241
  const results = [];
45200
45242
  try {
@@ -45209,13 +45251,13 @@ async function handleResetSessionCommand(directory, _args) {
45209
45251
  results.push("\u274C Failed to delete state.json");
45210
45252
  }
45211
45253
  try {
45212
- const sessionDir = path30.dirname(validateSwarmPath(directory, "session/state.json"));
45254
+ const sessionDir = path31.dirname(validateSwarmPath(directory, "session/state.json"));
45213
45255
  if (fs19.existsSync(sessionDir)) {
45214
45256
  const files = fs19.readdirSync(sessionDir);
45215
45257
  const otherFiles = files.filter((f) => f !== "state.json");
45216
45258
  let deletedCount = 0;
45217
45259
  for (const file3 of otherFiles) {
45218
- const filePath = path30.join(sessionDir, file3);
45260
+ const filePath = path31.join(sessionDir, file3);
45219
45261
  if (fs19.lstatSync(filePath).isFile()) {
45220
45262
  fs19.unlinkSync(filePath);
45221
45263
  deletedCount++;
@@ -45245,7 +45287,7 @@ async function handleResetSessionCommand(directory, _args) {
45245
45287
  // src/summaries/manager.ts
45246
45288
  init_utils2();
45247
45289
  init_utils();
45248
- import * as path31 from "path";
45290
+ import * as path32 from "path";
45249
45291
  var SUMMARY_ID_REGEX = /^S\d+$/;
45250
45292
  function sanitizeSummaryId(id) {
45251
45293
  if (!id || id.length === 0) {
@@ -45269,7 +45311,7 @@ function sanitizeSummaryId(id) {
45269
45311
  }
45270
45312
  async function loadFullOutput(directory, id) {
45271
45313
  const sanitizedId = sanitizeSummaryId(id);
45272
- const relativePath = path31.join("summaries", `${sanitizedId}.json`);
45314
+ const relativePath = path32.join("summaries", `${sanitizedId}.json`);
45273
45315
  validateSwarmPath(directory, relativePath);
45274
45316
  const content = await readSwarmFileAsync(directory, relativePath);
45275
45317
  if (content === null) {
@@ -45325,7 +45367,7 @@ init_plan_schema();
45325
45367
  init_utils2();
45326
45368
  init_ledger();
45327
45369
  import * as fs20 from "fs";
45328
- import * as path32 from "path";
45370
+ import * as path33 from "path";
45329
45371
  async function handleRollbackCommand(directory, args) {
45330
45372
  const phaseArg = args[0];
45331
45373
  if (!phaseArg) {
@@ -45390,8 +45432,8 @@ async function handleRollbackCommand(directory, args) {
45390
45432
  if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
45391
45433
  continue;
45392
45434
  }
45393
- const src = path32.join(checkpointDir, file3);
45394
- const dest = path32.join(swarmDir, file3);
45435
+ const src = path33.join(checkpointDir, file3);
45436
+ const dest = path33.join(swarmDir, file3);
45395
45437
  try {
45396
45438
  fs20.cpSync(src, dest, { recursive: true, force: true });
45397
45439
  successes.push(file3);
@@ -45410,12 +45452,12 @@ async function handleRollbackCommand(directory, args) {
45410
45452
  ].join(`
45411
45453
  `);
45412
45454
  }
45413
- const existingLedgerPath = path32.join(swarmDir, "plan-ledger.jsonl");
45455
+ const existingLedgerPath = path33.join(swarmDir, "plan-ledger.jsonl");
45414
45456
  if (fs20.existsSync(existingLedgerPath)) {
45415
45457
  fs20.unlinkSync(existingLedgerPath);
45416
45458
  }
45417
45459
  try {
45418
- const planJsonPath = path32.join(swarmDir, "plan.json");
45460
+ const planJsonPath = path33.join(swarmDir, "plan.json");
45419
45461
  if (fs20.existsSync(planJsonPath)) {
45420
45462
  const planRaw = fs20.readFileSync(planJsonPath, "utf-8");
45421
45463
  const plan = PlanSchema.parse(JSON.parse(planRaw));
@@ -45488,9 +45530,9 @@ async function handleSimulateCommand(directory, args) {
45488
45530
  const report = reportLines.filter(Boolean).join(`
45489
45531
  `);
45490
45532
  const fs21 = await import("fs/promises");
45491
- const path33 = await import("path");
45492
- const reportPath = path33.join(directory, ".swarm", "simulate-report.md");
45493
- await fs21.mkdir(path33.dirname(reportPath), { recursive: true });
45533
+ const path34 = await import("path");
45534
+ const reportPath = path34.join(directory, ".swarm", "simulate-report.md");
45535
+ await fs21.mkdir(path34.dirname(reportPath), { recursive: true });
45494
45536
  await fs21.writeFile(reportPath, report, "utf-8");
45495
45537
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
45496
45538
  }
@@ -46038,34 +46080,55 @@ function resolveCommand(tokens) {
46038
46080
  // src/cli/index.ts
46039
46081
  var { version: version4 } = package_default;
46040
46082
  var CONFIG_DIR = getPluginConfigDir();
46041
- var OPENCODE_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode.json");
46042
- var PLUGIN_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode-swarm.json");
46043
- var PROMPTS_DIR = path33.join(CONFIG_DIR, "opencode-swarm");
46083
+ var OPENCODE_CONFIG_PATH = path34.join(CONFIG_DIR, "opencode.json");
46084
+ var PLUGIN_CONFIG_PATH = path34.join(CONFIG_DIR, "opencode-swarm.json");
46085
+ var PROMPTS_DIR = path34.join(CONFIG_DIR, "opencode-swarm");
46044
46086
  var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
46087
+ var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
46045
46088
  function isSafeCachePath(p) {
46046
- const resolved = path33.resolve(p);
46047
- const home = path33.resolve(os7.homedir());
46089
+ const resolved = path34.resolve(p);
46090
+ const home = path34.resolve(os7.homedir());
46048
46091
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
46049
46092
  return false;
46050
46093
  }
46051
- const segments = resolved.split(path33.sep).filter((s) => s.length > 0);
46094
+ const segments = resolved.split(path34.sep).filter((s) => s.length > 0);
46052
46095
  if (segments.length < 4) {
46053
46096
  return false;
46054
46097
  }
46055
- const leaf = path33.basename(resolved);
46098
+ const leaf = path34.basename(resolved);
46056
46099
  if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
46057
46100
  return false;
46058
46101
  }
46059
- const parent = path33.basename(path33.dirname(resolved));
46102
+ const parent = path34.basename(path34.dirname(resolved));
46060
46103
  if (parent !== "packages" && parent !== "node_modules") {
46061
46104
  return false;
46062
46105
  }
46063
- const grandparent = path33.basename(path33.dirname(path33.dirname(resolved)));
46106
+ const grandparent = path34.basename(path34.dirname(path34.dirname(resolved)));
46064
46107
  if (grandparent !== "opencode") {
46065
46108
  return false;
46066
46109
  }
46067
46110
  return true;
46068
46111
  }
46112
+ function isSafeLockFilePath(p) {
46113
+ const resolved = path34.resolve(p);
46114
+ const home = path34.resolve(os7.homedir());
46115
+ if (resolved === "/" || resolved === home || resolved.length <= home.length) {
46116
+ return false;
46117
+ }
46118
+ const segments = resolved.split(path34.sep).filter((s) => s.length > 0);
46119
+ if (segments.length < 4) {
46120
+ return false;
46121
+ }
46122
+ const leaf = path34.basename(resolved);
46123
+ if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
46124
+ return false;
46125
+ }
46126
+ const parent = path34.basename(path34.dirname(resolved));
46127
+ if (parent !== "opencode") {
46128
+ return false;
46129
+ }
46130
+ return true;
46131
+ }
46069
46132
  function ensureDir(dir) {
46070
46133
  if (!fs21.existsSync(dir)) {
46071
46134
  fs21.mkdirSync(dir, { recursive: true });
@@ -46086,8 +46149,8 @@ function saveJson(filepath, data) {
46086
46149
  }
46087
46150
  function writeProjectConfigIfMissing(cwd) {
46088
46151
  try {
46089
- const opencodeDir = path33.join(cwd, ".opencode");
46090
- const projectConfigPath = path33.join(opencodeDir, "opencode-swarm.json");
46152
+ const opencodeDir = path34.join(cwd, ".opencode");
46153
+ const projectConfigPath = path34.join(opencodeDir, "opencode-swarm.json");
46091
46154
  if (fs21.existsSync(projectConfigPath)) {
46092
46155
  return;
46093
46156
  }
@@ -46105,7 +46168,7 @@ async function install() {
46105
46168
  `);
46106
46169
  ensureDir(CONFIG_DIR);
46107
46170
  ensureDir(PROMPTS_DIR);
46108
- const LEGACY_CONFIG_PATH = path33.join(CONFIG_DIR, "config.json");
46171
+ const LEGACY_CONFIG_PATH = path34.join(CONFIG_DIR, "config.json");
46109
46172
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
46110
46173
  if (!opencodeConfig) {
46111
46174
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -46144,6 +46207,14 @@ async function install() {
46144
46207
  console.warn(`\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:
46145
46208
  ${failed}`);
46146
46209
  }
46210
+ const lockEvicted = evictLockFiles();
46211
+ if (lockEvicted.cleared.length > 0) {
46212
+ console.log(`\u2713 Cleared opencode lock file(s) (next start will fetch latest): ${lockEvicted.cleared.join(", ")}`);
46213
+ }
46214
+ for (const failed of lockEvicted.failed) {
46215
+ console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
46216
+ ${failed}`);
46217
+ }
46147
46218
  if (!fs21.existsSync(PLUGIN_CONFIG_PATH)) {
46148
46219
  const defaultConfig = {
46149
46220
  agents: {
@@ -46246,6 +46317,7 @@ async function update() {
46246
46317
  console.log(`\uD83D\uDC1D Refreshing OpenCode Swarm plugin cache...
46247
46318
  `);
46248
46319
  const result = evictPluginCaches();
46320
+ const lockResult = evictLockFiles();
46249
46321
  if (result.cleared.length > 0) {
46250
46322
  for (const cleared of result.cleared) {
46251
46323
  console.log(`\u2713 Cleared: ${cleared}`);
@@ -46253,17 +46325,33 @@ async function update() {
46253
46325
  console.log(`
46254
46326
  Restart OpenCode to fetch the latest version from npm.`);
46255
46327
  }
46256
- if (result.cleared.length === 0 && result.failed.length === 0) {
46328
+ if (lockResult.cleared.length > 0) {
46329
+ for (const cleared of lockResult.cleared) {
46330
+ console.log(`\u2713 Cleared lock file: ${cleared}`);
46331
+ }
46332
+ }
46333
+ if (lockResult.failed.length > 0) {
46334
+ for (const failed of lockResult.failed) {
46335
+ console.error(`\u2717 Could not clear lock file: ${failed}`);
46336
+ }
46337
+ }
46338
+ if (result.cleared.length === 0 && result.failed.length === 0 && lockResult.cleared.length === 0 && lockResult.failed.length === 0) {
46257
46339
  console.log("No cached plugin found. Restart OpenCode to fetch the latest version from npm.");
46258
46340
  console.log("Checked locations:");
46259
46341
  for (const p of OPENCODE_PLUGIN_CACHE_PATHS) {
46260
46342
  console.log(` - ${p}`);
46261
46343
  }
46344
+ console.log("Lock files checked:");
46345
+ for (const p of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
46346
+ console.log(` - ${p}`);
46347
+ }
46262
46348
  }
46263
46349
  if (result.failed.length > 0) {
46264
46350
  for (const failed of result.failed) {
46265
46351
  console.error(`\u2717 Could not clear: ${failed}`);
46266
46352
  }
46353
+ }
46354
+ if (result.failed.length > 0 || lockResult.failed.length > 0) {
46267
46355
  return 1;
46268
46356
  }
46269
46357
  return 0;
@@ -46287,6 +46375,30 @@ function evictPluginCaches() {
46287
46375
  }
46288
46376
  return { cleared, failed };
46289
46377
  }
46378
+ function evictLockFiles() {
46379
+ const cleared = [];
46380
+ const failed = [];
46381
+ for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
46382
+ if (!fs21.existsSync(lockPath))
46383
+ continue;
46384
+ if (!isSafeLockFilePath(lockPath)) {
46385
+ failed.push(`${lockPath} (refused: failed safety check)`);
46386
+ continue;
46387
+ }
46388
+ try {
46389
+ fs21.unlinkSync(lockPath);
46390
+ cleared.push(lockPath);
46391
+ } catch (err) {
46392
+ const code = err?.code;
46393
+ if (code === "EISDIR") {
46394
+ failed.push(`${lockPath} (path is a directory, not a file)`);
46395
+ } else {
46396
+ failed.push(`${lockPath} (${err instanceof Error ? err.message : String(err)})`);
46397
+ }
46398
+ }
46399
+ }
46400
+ return { cleared, failed };
46401
+ }
46290
46402
  async function uninstall() {
46291
46403
  try {
46292
46404
  console.log(`\uD83D\uDC1D Uninstalling OpenCode Swarm...
@@ -46452,5 +46564,9 @@ Valid commands: ${VALID_COMMANDS.join(", ")}`);
46452
46564
  return 0;
46453
46565
  }
46454
46566
  export {
46455
- run
46567
+ run,
46568
+ isSafeLockFilePath,
46569
+ isSafeCachePath,
46570
+ evictPluginCaches,
46571
+ evictLockFiles
46456
46572
  };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Handles the /swarm reset command.
3
- * Clears plan.md and context.md from .swarm/ directory.
3
+ * Clears all swarm state files from .swarm/ and project root.
4
4
  * Stops background automation and resets in-memory queues.
5
5
  * Requires --confirm flag as a safety gate.
6
6
  */
@@ -9,3 +9,9 @@ export declare function getPluginConfigDir(): string;
9
9
  * path at the top.
10
10
  */
11
11
  export declare function getPluginCachePaths(): readonly string[];
12
+ /**
13
+ * All known locations where OpenCode stores npm lock files for the plugin
14
+ * environment. These pin the installed version of opencode-swarm and must
15
+ * be cleared during update/install to force a fresh resolution from npm.
16
+ */
17
+ export declare function getPluginLockFilePaths(): readonly string[];