opencode-swarm 6.86.7 → 6.86.9

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 CHANGED
@@ -17669,14 +17669,14 @@ __export(exports_config_doctor, {
17669
17669
  });
17670
17670
  import * as crypto3 from "crypto";
17671
17671
  import * as fs8 from "fs";
17672
- import * as os5 from "os";
17673
- import * as path18 from "path";
17672
+ import * as os6 from "os";
17673
+ import * as path19 from "path";
17674
17674
  function getUserConfigDir3() {
17675
- return process.env.XDG_CONFIG_HOME || path18.join(os5.homedir(), ".config");
17675
+ return process.env.XDG_CONFIG_HOME || path19.join(os6.homedir(), ".config");
17676
17676
  }
17677
17677
  function getConfigPaths(directory) {
17678
- const userConfigPath = path18.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
17679
- const projectConfigPath = path18.join(directory, ".opencode", "opencode-swarm.json");
17678
+ const userConfigPath = path19.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
17679
+ const projectConfigPath = path19.join(directory, ".opencode", "opencode-swarm.json");
17680
17680
  return { userConfigPath, projectConfigPath };
17681
17681
  }
17682
17682
  function computeHash(content) {
@@ -17701,9 +17701,9 @@ function isValidConfigPath(configPath, directory) {
17701
17701
  const normalizedUser = userConfigPath.replace(/\\/g, "/");
17702
17702
  const normalizedProject = projectConfigPath.replace(/\\/g, "/");
17703
17703
  try {
17704
- const resolvedConfig = path18.resolve(configPath);
17705
- const resolvedUser = path18.resolve(normalizedUser);
17706
- const resolvedProject = path18.resolve(normalizedProject);
17704
+ const resolvedConfig = path19.resolve(configPath);
17705
+ const resolvedUser = path19.resolve(normalizedUser);
17706
+ const resolvedProject = path19.resolve(normalizedProject);
17707
17707
  return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
17708
17708
  } catch {
17709
17709
  return false;
@@ -17743,12 +17743,12 @@ function createConfigBackup(directory) {
17743
17743
  };
17744
17744
  }
17745
17745
  function writeBackupArtifact(directory, backup) {
17746
- const swarmDir = path18.join(directory, ".swarm");
17746
+ const swarmDir = path19.join(directory, ".swarm");
17747
17747
  if (!fs8.existsSync(swarmDir)) {
17748
17748
  fs8.mkdirSync(swarmDir, { recursive: true });
17749
17749
  }
17750
17750
  const backupFilename = `config-backup-${backup.createdAt}.json`;
17751
- const backupPath = path18.join(swarmDir, backupFilename);
17751
+ const backupPath = path19.join(swarmDir, backupFilename);
17752
17752
  const artifact = {
17753
17753
  createdAt: backup.createdAt,
17754
17754
  configPath: backup.configPath,
@@ -17778,7 +17778,7 @@ function restoreFromBackup(backupPath, directory) {
17778
17778
  return null;
17779
17779
  }
17780
17780
  const targetPath = artifact.configPath;
17781
- const targetDir = path18.dirname(targetPath);
17781
+ const targetDir = path19.dirname(targetPath);
17782
17782
  if (!fs8.existsSync(targetDir)) {
17783
17783
  fs8.mkdirSync(targetDir, { recursive: true });
17784
17784
  }
@@ -17809,9 +17809,9 @@ function readConfigFromFile(directory) {
17809
17809
  return null;
17810
17810
  }
17811
17811
  }
17812
- function validateConfigKey(path19, value, _config) {
17812
+ function validateConfigKey(path20, value, _config) {
17813
17813
  const findings = [];
17814
- switch (path19) {
17814
+ switch (path20) {
17815
17815
  case "agents": {
17816
17816
  if (value !== undefined) {
17817
17817
  findings.push({
@@ -18058,27 +18058,27 @@ function validateConfigKey(path19, value, _config) {
18058
18058
  }
18059
18059
  return findings;
18060
18060
  }
18061
- function walkConfigAndValidate(obj, path19, config3, findings) {
18061
+ function walkConfigAndValidate(obj, path20, config3, findings) {
18062
18062
  if (obj === null || obj === undefined) {
18063
18063
  return;
18064
18064
  }
18065
- if (path19 && typeof obj === "object" && !Array.isArray(obj)) {
18066
- const keyFindings = validateConfigKey(path19, obj, config3);
18065
+ if (path20 && typeof obj === "object" && !Array.isArray(obj)) {
18066
+ const keyFindings = validateConfigKey(path20, obj, config3);
18067
18067
  findings.push(...keyFindings);
18068
18068
  }
18069
18069
  if (typeof obj !== "object") {
18070
- const keyFindings = validateConfigKey(path19, obj, config3);
18070
+ const keyFindings = validateConfigKey(path20, obj, config3);
18071
18071
  findings.push(...keyFindings);
18072
18072
  return;
18073
18073
  }
18074
18074
  if (Array.isArray(obj)) {
18075
18075
  obj.forEach((item, index) => {
18076
- walkConfigAndValidate(item, `${path19}[${index}]`, config3, findings);
18076
+ walkConfigAndValidate(item, `${path20}[${index}]`, config3, findings);
18077
18077
  });
18078
18078
  return;
18079
18079
  }
18080
18080
  for (const [key, value] of Object.entries(obj)) {
18081
- const newPath = path19 ? `${path19}.${key}` : key;
18081
+ const newPath = path20 ? `${path20}.${key}` : key;
18082
18082
  walkConfigAndValidate(value, newPath, config3, findings);
18083
18083
  }
18084
18084
  }
@@ -18198,7 +18198,7 @@ function applySafeAutoFixes(directory, result) {
18198
18198
  }
18199
18199
  }
18200
18200
  if (appliedFixes.length > 0) {
18201
- const configDir = path18.dirname(configPath);
18201
+ const configDir = path19.dirname(configPath);
18202
18202
  if (!fs8.existsSync(configDir)) {
18203
18203
  fs8.mkdirSync(configDir, { recursive: true });
18204
18204
  }
@@ -18208,12 +18208,12 @@ function applySafeAutoFixes(directory, result) {
18208
18208
  return { appliedFixes, updatedConfigPath };
18209
18209
  }
18210
18210
  function writeDoctorArtifact(directory, result) {
18211
- const swarmDir = path18.join(directory, ".swarm");
18211
+ const swarmDir = path19.join(directory, ".swarm");
18212
18212
  if (!fs8.existsSync(swarmDir)) {
18213
18213
  fs8.mkdirSync(swarmDir, { recursive: true });
18214
18214
  }
18215
18215
  const artifactFilename = "config-doctor.json";
18216
- const artifactPath = path18.join(swarmDir, artifactFilename);
18216
+ const artifactPath = path19.join(swarmDir, artifactFilename);
18217
18217
  const guiOutput = {
18218
18218
  timestamp: result.timestamp,
18219
18219
  summary: result.summary,
@@ -18575,12 +18575,12 @@ var init_evidence_summary_service = __esm(() => {
18575
18575
 
18576
18576
  // src/cli/index.ts
18577
18577
  import * as fs21 from "fs";
18578
- import * as os6 from "os";
18579
- import * as path32 from "path";
18578
+ import * as os7 from "os";
18579
+ import * as path33 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.9",
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,83 @@ 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";
36262
- import path17 from "path";
36271
+ import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
36272
+ import path18 from "path";
36263
36273
  import { fileURLToPath } from "url";
36274
+
36275
+ // src/config/cache-paths.ts
36276
+ import * as os5 from "os";
36277
+ import * as path17 from "path";
36278
+ function getPluginConfigDir() {
36279
+ return path17.join(process.env.XDG_CONFIG_HOME || path17.join(os5.homedir(), ".config"), "opencode");
36280
+ }
36281
+ function getPluginCachePaths() {
36282
+ const cacheBase = process.env.XDG_CACHE_HOME || path17.join(os5.homedir(), ".cache");
36283
+ const configDir = getPluginConfigDir();
36284
+ return [
36285
+ path17.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
36286
+ path17.join(configDir, "node_modules", "opencode-swarm"),
36287
+ path17.join(cacheBase, "opencode", "node_modules", "opencode-swarm")
36288
+ ];
36289
+ }
36290
+
36291
+ // src/services/diagnose-service.ts
36264
36292
  init_manager2();
36265
36293
  init_utils2();
36266
36294
  init_manager();
36295
+
36296
+ // src/services/version-check.ts
36297
+ import { existsSync as existsSync8, mkdirSync as mkdirSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
36298
+ import { homedir as homedir5 } from "os";
36299
+ import { join as join15 } from "path";
36300
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
36301
+ function cacheDir() {
36302
+ const xdg = process.env.XDG_CACHE_HOME;
36303
+ const base = xdg && xdg.length > 0 ? xdg : join15(homedir5(), ".cache");
36304
+ return join15(base, "opencode-swarm");
36305
+ }
36306
+ function cacheFile() {
36307
+ return join15(cacheDir(), "version-check.json");
36308
+ }
36309
+ function readVersionCache() {
36310
+ try {
36311
+ const path18 = cacheFile();
36312
+ if (!existsSync8(path18))
36313
+ return null;
36314
+ const raw = readFileSync5(path18, "utf-8");
36315
+ const parsed = JSON.parse(raw);
36316
+ if (typeof parsed?.checkedAt !== "number")
36317
+ return null;
36318
+ const npmLatest = typeof parsed.npmLatest === "string" ? parsed.npmLatest : null;
36319
+ return { checkedAt: parsed.checkedAt, npmLatest };
36320
+ } catch {
36321
+ return null;
36322
+ }
36323
+ }
36324
+ function compareVersions(a, b) {
36325
+ const [aBase, aPre] = a.split("-", 2);
36326
+ const [bBase, bPre] = b.split("-", 2);
36327
+ const aParts = aBase.split(".").map((n) => Number.parseInt(n, 10) || 0);
36328
+ const bParts = bBase.split(".").map((n) => Number.parseInt(n, 10) || 0);
36329
+ const len = Math.max(aParts.length, bParts.length);
36330
+ for (let i = 0;i < len; i++) {
36331
+ const av = aParts[i] ?? 0;
36332
+ const bv = bParts[i] ?? 0;
36333
+ if (av > bv)
36334
+ return 1;
36335
+ if (av < bv)
36336
+ return -1;
36337
+ }
36338
+ if (aPre && !bPre)
36339
+ return -1;
36340
+ if (!aPre && bPre)
36341
+ return 1;
36342
+ if (aPre && bPre)
36343
+ return aPre < bPre ? -1 : aPre > bPre ? 1 : 0;
36344
+ return 0;
36345
+ }
36346
+
36347
+ // src/services/diagnose-service.ts
36267
36348
  var { version: version3 } = package_default;
36268
36349
  function validateTaskDag(plan) {
36269
36350
  const allTaskIds = new Set;
@@ -36496,7 +36577,7 @@ async function checkConfigBackups(directory) {
36496
36577
  }
36497
36578
  async function checkGitRepository(directory) {
36498
36579
  try {
36499
- if (!existsSync8(directory) || !statSync5(directory).isDirectory()) {
36580
+ if (!existsSync9(directory) || !statSync5(directory).isDirectory()) {
36500
36581
  return {
36501
36582
  name: "Git Repository",
36502
36583
  status: "\u274C",
@@ -36560,8 +36641,8 @@ async function checkSpecStaleness(directory, plan) {
36560
36641
  };
36561
36642
  }
36562
36643
  async function checkConfigParseability(directory) {
36563
- const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
36564
- if (!existsSync8(configPath)) {
36644
+ const configPath = path18.join(directory, ".opencode/opencode-swarm.json");
36645
+ if (!existsSync9(configPath)) {
36565
36646
  return {
36566
36647
  name: "Config Parseability",
36567
36648
  status: "\u2705",
@@ -36569,7 +36650,7 @@ async function checkConfigParseability(directory) {
36569
36650
  };
36570
36651
  }
36571
36652
  try {
36572
- const content = readFileSync5(configPath, "utf-8");
36653
+ const content = readFileSync6(configPath, "utf-8");
36573
36654
  JSON.parse(content);
36574
36655
  return {
36575
36656
  name: "Config Parseability",
@@ -36589,7 +36670,7 @@ function resolveGrammarDir(thisDir) {
36589
36670
  const normalized = thisDir.replace(/\\/g, "/");
36590
36671
  const isSource = normalized.endsWith("/src/services");
36591
36672
  const isCliBundle = normalized.endsWith("/cli");
36592
- return isSource || isCliBundle ? path17.join(thisDir, "..", "lang", "grammars") : path17.join(thisDir, "lang", "grammars");
36673
+ return isSource || isCliBundle ? path18.join(thisDir, "..", "lang", "grammars") : path18.join(thisDir, "lang", "grammars");
36593
36674
  }
36594
36675
  async function checkGrammarWasmFiles() {
36595
36676
  const grammarFiles = [
@@ -36613,14 +36694,14 @@ async function checkGrammarWasmFiles() {
36613
36694
  "tree-sitter-ini.wasm",
36614
36695
  "tree-sitter-regex.wasm"
36615
36696
  ];
36616
- const thisDir = path17.dirname(fileURLToPath(import.meta.url));
36697
+ const thisDir = path18.dirname(fileURLToPath(import.meta.url));
36617
36698
  const grammarDir = resolveGrammarDir(thisDir);
36618
36699
  const missing = [];
36619
- if (!existsSync8(path17.join(grammarDir, "tree-sitter.wasm"))) {
36700
+ if (!existsSync9(path18.join(grammarDir, "tree-sitter.wasm"))) {
36620
36701
  missing.push("tree-sitter.wasm (core runtime)");
36621
36702
  }
36622
36703
  for (const file3 of grammarFiles) {
36623
- if (!existsSync8(path17.join(grammarDir, file3))) {
36704
+ if (!existsSync9(path18.join(grammarDir, file3))) {
36624
36705
  missing.push(file3);
36625
36706
  }
36626
36707
  }
@@ -36638,8 +36719,8 @@ async function checkGrammarWasmFiles() {
36638
36719
  };
36639
36720
  }
36640
36721
  async function checkCheckpointManifest(directory) {
36641
- const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
36642
- if (!existsSync8(manifestPath)) {
36722
+ const manifestPath = path18.join(directory, ".swarm/checkpoints.json");
36723
+ if (!existsSync9(manifestPath)) {
36643
36724
  return {
36644
36725
  name: "Checkpoint Manifest",
36645
36726
  status: "\u2705",
@@ -36647,7 +36728,7 @@ async function checkCheckpointManifest(directory) {
36647
36728
  };
36648
36729
  }
36649
36730
  try {
36650
- const content = readFileSync5(manifestPath, "utf-8");
36731
+ const content = readFileSync6(manifestPath, "utf-8");
36651
36732
  const parsed = JSON.parse(content);
36652
36733
  if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
36653
36734
  return {
@@ -36690,8 +36771,8 @@ async function checkCheckpointManifest(directory) {
36690
36771
  }
36691
36772
  }
36692
36773
  async function checkEventStreamIntegrity(directory) {
36693
- const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36694
- if (!existsSync8(eventsPath)) {
36774
+ const eventsPath = path18.join(directory, ".swarm/events.jsonl");
36775
+ if (!existsSync9(eventsPath)) {
36695
36776
  return {
36696
36777
  name: "Event Stream",
36697
36778
  status: "\u2705",
@@ -36699,7 +36780,7 @@ async function checkEventStreamIntegrity(directory) {
36699
36780
  };
36700
36781
  }
36701
36782
  try {
36702
- const content = readFileSync5(eventsPath, "utf-8");
36783
+ const content = readFileSync6(eventsPath, "utf-8");
36703
36784
  const lines = content.split(`
36704
36785
  `).filter((line) => line.trim() !== "");
36705
36786
  let malformedCount = 0;
@@ -36731,8 +36812,8 @@ async function checkEventStreamIntegrity(directory) {
36731
36812
  }
36732
36813
  }
36733
36814
  async function checkSteeringDirectives(directory) {
36734
- const eventsPath = path17.join(directory, ".swarm/events.jsonl");
36735
- if (!existsSync8(eventsPath)) {
36815
+ const eventsPath = path18.join(directory, ".swarm/events.jsonl");
36816
+ if (!existsSync9(eventsPath)) {
36736
36817
  return {
36737
36818
  name: "Steering Directives",
36738
36819
  status: "\u2705",
@@ -36740,7 +36821,7 @@ async function checkSteeringDirectives(directory) {
36740
36821
  };
36741
36822
  }
36742
36823
  try {
36743
- const content = readFileSync5(eventsPath, "utf-8");
36824
+ const content = readFileSync6(eventsPath, "utf-8");
36744
36825
  const lines = content.split(`
36745
36826
  `).filter((line) => line.trim() !== "");
36746
36827
  const directivesIssued = [];
@@ -36787,8 +36868,8 @@ async function checkCurator(directory) {
36787
36868
  detail: "Disabled (enable via curator.enabled)"
36788
36869
  };
36789
36870
  }
36790
- const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
36791
- if (!existsSync8(summaryPath)) {
36871
+ const summaryPath = path18.join(directory, ".swarm/curator-summary.json");
36872
+ if (!existsSync9(summaryPath)) {
36792
36873
  return {
36793
36874
  name: "Curator",
36794
36875
  status: "\u2705",
@@ -36796,7 +36877,7 @@ async function checkCurator(directory) {
36796
36877
  };
36797
36878
  }
36798
36879
  try {
36799
- const content = readFileSync5(summaryPath, "utf-8");
36880
+ const content = readFileSync6(summaryPath, "utf-8");
36800
36881
  const parsed = JSON.parse(content);
36801
36882
  if (typeof parsed.schema_version !== "number" || parsed.schema_version !== 1) {
36802
36883
  return {
@@ -36831,10 +36912,23 @@ async function checkCurator(directory) {
36831
36912
  }
36832
36913
  async function getDiagnoseData(directory) {
36833
36914
  const checks5 = [];
36915
+ const versionCache = readVersionCache();
36916
+ let versionDetail = version3;
36917
+ let versionStatus = "\u2705";
36918
+ if (versionCache?.npmLatest) {
36919
+ const ageMs = Date.now() - versionCache.checkedAt;
36920
+ const ageMin = Math.max(0, Math.round(ageMs / 60000));
36921
+ if (compareVersions(versionCache.npmLatest, version3) > 0) {
36922
+ versionStatus = "\u26A0\uFE0F";
36923
+ versionDetail = `${version3} (npm latest: ${versionCache.npmLatest}, checked ${ageMin}m ago) ` + "\u2014 run `bunx opencode-swarm update` to refresh";
36924
+ } else {
36925
+ versionDetail = `${version3} (npm latest: ${versionCache.npmLatest}, checked ${ageMin}m ago)`;
36926
+ }
36927
+ }
36834
36928
  checks5.push({
36835
36929
  name: "Version",
36836
- status: "\u2705",
36837
- detail: version3
36930
+ status: versionStatus,
36931
+ detail: versionDetail
36838
36932
  });
36839
36933
  const plan = await loadPlanJsonOnly(directory);
36840
36934
  if (plan) {
@@ -36940,8 +37034,8 @@ async function getDiagnoseData(directory) {
36940
37034
  checks5.push(await checkSteeringDirectives(directory));
36941
37035
  checks5.push(await checkCurator(directory));
36942
37036
  try {
36943
- const evidenceDir = path17.join(directory, ".swarm", "evidence");
36944
- const snapshotFiles = existsSync8(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
37037
+ const evidenceDir = path18.join(directory, ".swarm", "evidence");
37038
+ const snapshotFiles = existsSync9(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
36945
37039
  if (snapshotFiles.length > 0) {
36946
37040
  const latest = snapshotFiles.sort().pop();
36947
37041
  checks5.push({
@@ -36970,7 +37064,36 @@ async function getDiagnoseData(directory) {
36970
37064
  detail: `${deferredWarnings.length} warning(s) deferred from init (run with verbose logs for details)`
36971
37065
  });
36972
37066
  }
36973
- const passCount = checks5.filter((c) => c.status === "\u2705").length;
37067
+ const cachePaths = getPluginCachePaths();
37068
+ const cacheRows = [];
37069
+ for (const cachePath of cachePaths) {
37070
+ try {
37071
+ if (!existsSync9(cachePath)) {
37072
+ cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
37073
+ continue;
37074
+ }
37075
+ const pkgJsonPath = path18.join(cachePath, "package.json");
37076
+ try {
37077
+ const raw = readFileSync6(pkgJsonPath, "utf-8");
37078
+ const parsed = JSON.parse(raw);
37079
+ const installedVersion = typeof parsed.version === "string" ? parsed.version : "?";
37080
+ cacheRows.push(`\u2705 ${cachePath} \u2014 v${installedVersion}`);
37081
+ } catch {
37082
+ cacheRows.push(`\u26A0\uFE0F ${cachePath} \u2014 present (package.json unreadable)`);
37083
+ }
37084
+ } catch {
37085
+ cacheRows.push(`\u26A0\uFE0F ${cachePath} \u2014 status unknown (read error)`);
37086
+ }
37087
+ }
37088
+ const hasCacheEntry = cacheRows.some((r) => r.startsWith("\u2705"));
37089
+ const hasCacheWarning = cacheRows.some((r) => r.startsWith("\u26A0\uFE0F"));
37090
+ const cacheStatus = hasCacheWarning ? "\u26A0\uFE0F" : hasCacheEntry ? "\u2705" : "\u2B1C";
37091
+ checks5.push({
37092
+ name: "Plugin Caches",
37093
+ status: cacheStatus,
37094
+ detail: cacheRows.join(" | ")
37095
+ });
37096
+ const passCount = checks5.filter((c) => c.status === "\u2705" || c.status === "\u2B1C").length;
36974
37097
  const totalCount = checks5.length;
36975
37098
  const allPassed = passCount === totalCount;
36976
37099
  return {
@@ -37008,15 +37131,15 @@ init_config_doctor();
37008
37131
 
37009
37132
  // src/services/tool-doctor.ts
37010
37133
  import * as fs10 from "fs";
37011
- import * as path20 from "path";
37134
+ import * as path21 from "path";
37012
37135
 
37013
37136
  // src/build/discovery.ts
37014
37137
  import * as fs9 from "fs";
37015
- import * as path19 from "path";
37138
+ import * as path20 from "path";
37016
37139
 
37017
37140
  // src/lang/detector.ts
37018
37141
  import { access as access2, readdir as readdir2 } from "fs/promises";
37019
- import { extname as extname2, join as join15 } from "path";
37142
+ import { extname as extname2, join as join17 } from "path";
37020
37143
 
37021
37144
  // src/lang/profiles.ts
37022
37145
  class LanguageRegistry {
@@ -37996,7 +38119,7 @@ async function detectProjectLanguages(projectDir) {
37996
38119
  if (detectFile.includes("*") || detectFile.includes("?"))
37997
38120
  continue;
37998
38121
  try {
37999
- await access2(join15(dir, detectFile));
38122
+ await access2(join17(dir, detectFile));
38000
38123
  detected.add(profile.id);
38001
38124
  break;
38002
38125
  } catch {}
@@ -38017,7 +38140,7 @@ async function detectProjectLanguages(projectDir) {
38017
38140
  const topEntries = await readdir2(projectDir, { withFileTypes: true });
38018
38141
  for (const entry of topEntries) {
38019
38142
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
38020
- await scanDir(join15(projectDir, entry.name));
38143
+ await scanDir(join17(projectDir, entry.name));
38021
38144
  }
38022
38145
  }
38023
38146
  } catch {}
@@ -38176,11 +38299,11 @@ function findBuildFiles(workingDir, patterns) {
38176
38299
  const regex = simpleGlobToRegex(pattern);
38177
38300
  const matches = files.filter((f) => regex.test(f));
38178
38301
  if (matches.length > 0) {
38179
- return path19.join(dir, matches[0]);
38302
+ return path20.join(dir, matches[0]);
38180
38303
  }
38181
38304
  } catch {}
38182
38305
  } else {
38183
- const filePath = path19.join(workingDir, pattern);
38306
+ const filePath = path20.join(workingDir, pattern);
38184
38307
  if (fs9.existsSync(filePath)) {
38185
38308
  return filePath;
38186
38309
  }
@@ -38189,7 +38312,7 @@ function findBuildFiles(workingDir, patterns) {
38189
38312
  return null;
38190
38313
  }
38191
38314
  function getRepoDefinedScripts(workingDir, scripts) {
38192
- const packageJsonPath = path19.join(workingDir, "package.json");
38315
+ const packageJsonPath = path20.join(workingDir, "package.json");
38193
38316
  if (!fs9.existsSync(packageJsonPath)) {
38194
38317
  return [];
38195
38318
  }
@@ -38230,7 +38353,7 @@ function findAllBuildFiles(workingDir) {
38230
38353
  const regex = simpleGlobToRegex(pattern);
38231
38354
  findFilesRecursive(workingDir, regex, allBuildFiles);
38232
38355
  } else {
38233
- const filePath = path19.join(workingDir, pattern);
38356
+ const filePath = path20.join(workingDir, pattern);
38234
38357
  if (fs9.existsSync(filePath)) {
38235
38358
  allBuildFiles.add(filePath);
38236
38359
  }
@@ -38243,7 +38366,7 @@ function findFilesRecursive(dir, regex, results) {
38243
38366
  try {
38244
38367
  const entries = fs9.readdirSync(dir, { withFileTypes: true });
38245
38368
  for (const entry of entries) {
38246
- const fullPath = path19.join(dir, entry.name);
38369
+ const fullPath = path20.join(dir, entry.name);
38247
38370
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
38248
38371
  findFilesRecursive(fullPath, regex, results);
38249
38372
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -38266,7 +38389,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
38266
38389
  let foundCommand = false;
38267
38390
  for (const cmd of sortedCommands) {
38268
38391
  if (cmd.detectFile) {
38269
- const detectFilePath = path19.join(workingDir, cmd.detectFile);
38392
+ const detectFilePath = path20.join(workingDir, cmd.detectFile);
38270
38393
  if (!fs9.existsSync(detectFilePath)) {
38271
38394
  continue;
38272
38395
  }
@@ -38441,8 +38564,8 @@ function checkBinaryReadiness() {
38441
38564
  }
38442
38565
  function runToolDoctor(_directory, pluginRoot) {
38443
38566
  const findings = [];
38444
- const resolvedPluginRoot = pluginRoot ?? path20.resolve(import.meta.dir, "..", "..");
38445
- const indexPath = path20.join(resolvedPluginRoot, "src", "index.ts");
38567
+ const resolvedPluginRoot = pluginRoot ?? path21.resolve(import.meta.dir, "..", "..");
38568
+ const indexPath = path21.join(resolvedPluginRoot, "src", "index.ts");
38446
38569
  if (!fs10.existsSync(indexPath)) {
38447
38570
  return {
38448
38571
  findings: [
@@ -39363,14 +39486,14 @@ async function handleHistoryCommand(directory, _args) {
39363
39486
  }
39364
39487
  // src/hooks/knowledge-migrator.ts
39365
39488
  import { randomUUID as randomUUID2 } from "crypto";
39366
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
39489
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
39367
39490
  import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
39368
- import * as path21 from "path";
39491
+ import * as path22 from "path";
39369
39492
  async function migrateContextToKnowledge(directory, config3) {
39370
- const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
39371
- const contextPath = path21.join(directory, ".swarm", "context.md");
39493
+ const sentinelPath = path22.join(directory, ".swarm", ".knowledge-migrated");
39494
+ const contextPath = path22.join(directory, ".swarm", "context.md");
39372
39495
  const knowledgePath = resolveSwarmKnowledgePath(directory);
39373
- if (existsSync12(sentinelPath)) {
39496
+ if (existsSync13(sentinelPath)) {
39374
39497
  return {
39375
39498
  migrated: false,
39376
39499
  entriesMigrated: 0,
@@ -39379,7 +39502,7 @@ async function migrateContextToKnowledge(directory, config3) {
39379
39502
  skippedReason: "sentinel-exists"
39380
39503
  };
39381
39504
  }
39382
- if (!existsSync12(contextPath)) {
39505
+ if (!existsSync13(contextPath)) {
39383
39506
  return {
39384
39507
  migrated: false,
39385
39508
  entriesMigrated: 0,
@@ -39564,16 +39687,16 @@ function truncateLesson(text) {
39564
39687
  return `${text.slice(0, 277)}...`;
39565
39688
  }
39566
39689
  function inferProjectName(directory) {
39567
- const packageJsonPath = path21.join(directory, "package.json");
39568
- if (existsSync12(packageJsonPath)) {
39690
+ const packageJsonPath = path22.join(directory, "package.json");
39691
+ if (existsSync13(packageJsonPath)) {
39569
39692
  try {
39570
- const pkg = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
39693
+ const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
39571
39694
  if (pkg.name && typeof pkg.name === "string") {
39572
39695
  return pkg.name;
39573
39696
  }
39574
39697
  } catch {}
39575
39698
  }
39576
- return path21.basename(directory);
39699
+ return path22.basename(directory);
39577
39700
  }
39578
39701
  async function writeSentinel(sentinelPath, migrated, dropped) {
39579
39702
  const sentinel = {
@@ -39585,7 +39708,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
39585
39708
  schema_version: 1,
39586
39709
  migration_tool: "knowledge-migrator.ts"
39587
39710
  };
39588
- await mkdir3(path21.dirname(sentinelPath), { recursive: true });
39711
+ await mkdir3(path22.dirname(sentinelPath), { recursive: true });
39589
39712
  await writeFile4(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
39590
39713
  }
39591
39714
 
@@ -39822,12 +39945,12 @@ async function handlePlanCommand(directory, args) {
39822
39945
  init_manager2();
39823
39946
  init_manager();
39824
39947
  import * as fs17 from "fs";
39825
- import * as path28 from "path";
39948
+ import * as path29 from "path";
39826
39949
 
39827
39950
  // src/tools/lint.ts
39828
39951
  init_zod();
39829
39952
  import * as fs11 from "fs";
39830
- import * as path22 from "path";
39953
+ import * as path23 from "path";
39831
39954
  init_utils();
39832
39955
 
39833
39956
  // src/utils/path-security.ts
@@ -39873,9 +39996,9 @@ function validateArgs(args) {
39873
39996
  }
39874
39997
  function getLinterCommand(linter, mode, projectDir) {
39875
39998
  const isWindows = process.platform === "win32";
39876
- const binDir = path22.join(projectDir, "node_modules", ".bin");
39877
- const biomeBin = isWindows ? path22.join(binDir, "biome.EXE") : path22.join(binDir, "biome");
39878
- const eslintBin = isWindows ? path22.join(binDir, "eslint.cmd") : path22.join(binDir, "eslint");
39999
+ const binDir = path23.join(projectDir, "node_modules", ".bin");
40000
+ const biomeBin = isWindows ? path23.join(binDir, "biome.EXE") : path23.join(binDir, "biome");
40001
+ const eslintBin = isWindows ? path23.join(binDir, "eslint.cmd") : path23.join(binDir, "eslint");
39879
40002
  switch (linter) {
39880
40003
  case "biome":
39881
40004
  if (mode === "fix") {
@@ -39891,7 +40014,7 @@ function getLinterCommand(linter, mode, projectDir) {
39891
40014
  }
39892
40015
  function getAdditionalLinterCommand(linter, mode, cwd) {
39893
40016
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
39894
- const gradlew = fs11.existsSync(path22.join(cwd, gradlewName)) ? path22.join(cwd, gradlewName) : null;
40017
+ const gradlew = fs11.existsSync(path23.join(cwd, gradlewName)) ? path23.join(cwd, gradlewName) : null;
39895
40018
  switch (linter) {
39896
40019
  case "ruff":
39897
40020
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -39925,10 +40048,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
39925
40048
  }
39926
40049
  }
39927
40050
  function detectRuff(cwd) {
39928
- if (fs11.existsSync(path22.join(cwd, "ruff.toml")))
40051
+ if (fs11.existsSync(path23.join(cwd, "ruff.toml")))
39929
40052
  return isCommandAvailable("ruff");
39930
40053
  try {
39931
- const pyproject = path22.join(cwd, "pyproject.toml");
40054
+ const pyproject = path23.join(cwd, "pyproject.toml");
39932
40055
  if (fs11.existsSync(pyproject)) {
39933
40056
  const content = fs11.readFileSync(pyproject, "utf-8");
39934
40057
  if (content.includes("[tool.ruff]"))
@@ -39938,19 +40061,19 @@ function detectRuff(cwd) {
39938
40061
  return false;
39939
40062
  }
39940
40063
  function detectClippy(cwd) {
39941
- return fs11.existsSync(path22.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
40064
+ return fs11.existsSync(path23.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
39942
40065
  }
39943
40066
  function detectGolangciLint(cwd) {
39944
- return fs11.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
40067
+ return fs11.existsSync(path23.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
39945
40068
  }
39946
40069
  function detectCheckstyle(cwd) {
39947
- const hasMaven = fs11.existsSync(path22.join(cwd, "pom.xml"));
39948
- const hasGradle = fs11.existsSync(path22.join(cwd, "build.gradle")) || fs11.existsSync(path22.join(cwd, "build.gradle.kts"));
39949
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs11.existsSync(path22.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
40070
+ const hasMaven = fs11.existsSync(path23.join(cwd, "pom.xml"));
40071
+ const hasGradle = fs11.existsSync(path23.join(cwd, "build.gradle")) || fs11.existsSync(path23.join(cwd, "build.gradle.kts"));
40072
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs11.existsSync(path23.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
39950
40073
  return (hasMaven || hasGradle) && hasBinary;
39951
40074
  }
39952
40075
  function detectKtlint(cwd) {
39953
- const hasKotlin = fs11.existsSync(path22.join(cwd, "build.gradle.kts")) || fs11.existsSync(path22.join(cwd, "build.gradle")) || (() => {
40076
+ const hasKotlin = fs11.existsSync(path23.join(cwd, "build.gradle.kts")) || fs11.existsSync(path23.join(cwd, "build.gradle")) || (() => {
39954
40077
  try {
39955
40078
  return fs11.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
39956
40079
  } catch {
@@ -39969,11 +40092,11 @@ function detectDotnetFormat(cwd) {
39969
40092
  }
39970
40093
  }
39971
40094
  function detectCppcheck(cwd) {
39972
- if (fs11.existsSync(path22.join(cwd, "CMakeLists.txt"))) {
40095
+ if (fs11.existsSync(path23.join(cwd, "CMakeLists.txt"))) {
39973
40096
  return isCommandAvailable("cppcheck");
39974
40097
  }
39975
40098
  try {
39976
- const dirsToCheck = [cwd, path22.join(cwd, "src")];
40099
+ const dirsToCheck = [cwd, path23.join(cwd, "src")];
39977
40100
  const hasCpp = dirsToCheck.some((dir) => {
39978
40101
  try {
39979
40102
  return fs11.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
@@ -39987,13 +40110,13 @@ function detectCppcheck(cwd) {
39987
40110
  }
39988
40111
  }
39989
40112
  function detectSwiftlint(cwd) {
39990
- return fs11.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
40113
+ return fs11.existsSync(path23.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
39991
40114
  }
39992
40115
  function detectDartAnalyze(cwd) {
39993
- return fs11.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
40116
+ return fs11.existsSync(path23.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
39994
40117
  }
39995
40118
  function detectRubocop(cwd) {
39996
- return (fs11.existsSync(path22.join(cwd, "Gemfile")) || fs11.existsSync(path22.join(cwd, "gems.rb")) || fs11.existsSync(path22.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
40119
+ return (fs11.existsSync(path23.join(cwd, "Gemfile")) || fs11.existsSync(path23.join(cwd, "gems.rb")) || fs11.existsSync(path23.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
39997
40120
  }
39998
40121
  function detectAdditionalLinter(cwd) {
39999
40122
  if (detectRuff(cwd))
@@ -40021,10 +40144,10 @@ function detectAdditionalLinter(cwd) {
40021
40144
  function findBinInAncestors(startDir, binName) {
40022
40145
  let dir = startDir;
40023
40146
  while (true) {
40024
- const candidate = path22.join(dir, "node_modules", ".bin", binName);
40147
+ const candidate = path23.join(dir, "node_modules", ".bin", binName);
40025
40148
  if (fs11.existsSync(candidate))
40026
40149
  return candidate;
40027
- const parent = path22.dirname(dir);
40150
+ const parent = path23.dirname(dir);
40028
40151
  if (parent === dir)
40029
40152
  break;
40030
40153
  dir = parent;
@@ -40033,10 +40156,10 @@ function findBinInAncestors(startDir, binName) {
40033
40156
  }
40034
40157
  function findBinInEnvPath(binName) {
40035
40158
  const searchPath = process.env.PATH ?? "";
40036
- for (const dir of searchPath.split(path22.delimiter)) {
40159
+ for (const dir of searchPath.split(path23.delimiter)) {
40037
40160
  if (!dir)
40038
40161
  continue;
40039
- const candidate = path22.join(dir, binName);
40162
+ const candidate = path23.join(dir, binName);
40040
40163
  if (fs11.existsSync(candidate))
40041
40164
  return candidate;
40042
40165
  }
@@ -40049,13 +40172,13 @@ async function detectAvailableLinter(directory) {
40049
40172
  return null;
40050
40173
  const projectDir = directory;
40051
40174
  const isWindows = process.platform === "win32";
40052
- const biomeBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "biome.EXE") : path22.join(projectDir, "node_modules", ".bin", "biome");
40053
- const eslintBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path22.join(projectDir, "node_modules", ".bin", "eslint");
40175
+ const biomeBin = isWindows ? path23.join(projectDir, "node_modules", ".bin", "biome.EXE") : path23.join(projectDir, "node_modules", ".bin", "biome");
40176
+ const eslintBin = isWindows ? path23.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path23.join(projectDir, "node_modules", ".bin", "eslint");
40054
40177
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
40055
40178
  if (localResult)
40056
40179
  return localResult;
40057
- const biomeAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
40058
- const eslintAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
40180
+ const biomeAncestor = findBinInAncestors(path23.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
40181
+ const eslintAncestor = findBinInAncestors(path23.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
40059
40182
  if (biomeAncestor || eslintAncestor) {
40060
40183
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
40061
40184
  }
@@ -40264,7 +40387,7 @@ For Rust: rustup component add clippy`
40264
40387
  // src/tools/secretscan.ts
40265
40388
  init_zod();
40266
40389
  import * as fs12 from "fs";
40267
- import * as path23 from "path";
40390
+ import * as path24 from "path";
40268
40391
  var MAX_FILE_PATH_LENGTH = 500;
40269
40392
  var MAX_FILE_SIZE_BYTES = 512 * 1024;
40270
40393
  var MAX_FILES_SCANNED = 1000;
@@ -40491,7 +40614,7 @@ function isGlobOrPathPattern(pattern) {
40491
40614
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
40492
40615
  }
40493
40616
  function loadSecretScanIgnore(scanDir) {
40494
- const ignorePath = path23.join(scanDir, ".secretscanignore");
40617
+ const ignorePath = path24.join(scanDir, ".secretscanignore");
40495
40618
  try {
40496
40619
  if (!fs12.existsSync(ignorePath))
40497
40620
  return [];
@@ -40514,7 +40637,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
40514
40637
  if (exactNames.has(entry))
40515
40638
  return true;
40516
40639
  for (const pattern of globPatterns) {
40517
- if (path23.matchesGlob(relPath, pattern))
40640
+ if (path24.matchesGlob(relPath, pattern))
40518
40641
  return true;
40519
40642
  }
40520
40643
  return false;
@@ -40535,7 +40658,7 @@ function validateDirectoryInput(dir) {
40535
40658
  return null;
40536
40659
  }
40537
40660
  function isBinaryFile(filePath, buffer) {
40538
- const ext = path23.extname(filePath).toLowerCase();
40661
+ const ext = path24.extname(filePath).toLowerCase();
40539
40662
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
40540
40663
  return true;
40541
40664
  }
@@ -40672,9 +40795,9 @@ function isSymlinkLoop(realPath, visited) {
40672
40795
  return false;
40673
40796
  }
40674
40797
  function isPathWithinScope(realPath, scanDir) {
40675
- const resolvedScanDir = path23.resolve(scanDir);
40676
- const resolvedRealPath = path23.resolve(realPath);
40677
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path23.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
40798
+ const resolvedScanDir = path24.resolve(scanDir);
40799
+ const resolvedRealPath = path24.resolve(realPath);
40800
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path24.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
40678
40801
  }
40679
40802
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
40680
40803
  skippedDirs: 0,
@@ -40700,8 +40823,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40700
40823
  return a.localeCompare(b);
40701
40824
  });
40702
40825
  for (const entry of entries) {
40703
- const fullPath = path23.join(dir, entry);
40704
- const relPath = path23.relative(scanDir, fullPath).replace(/\\/g, "/");
40826
+ const fullPath = path24.join(dir, entry);
40827
+ const relPath = path24.relative(scanDir, fullPath).replace(/\\/g, "/");
40705
40828
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
40706
40829
  stats.skippedDirs++;
40707
40830
  continue;
@@ -40736,7 +40859,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
40736
40859
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
40737
40860
  files.push(...subFiles);
40738
40861
  } else if (lstat.isFile()) {
40739
- const ext = path23.extname(fullPath).toLowerCase();
40862
+ const ext = path24.extname(fullPath).toLowerCase();
40740
40863
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
40741
40864
  files.push(fullPath);
40742
40865
  } else {
@@ -40802,7 +40925,7 @@ var secretscan = createSwarmTool({
40802
40925
  }
40803
40926
  }
40804
40927
  try {
40805
- const _scanDirRaw = path23.resolve(directory);
40928
+ const _scanDirRaw = path24.resolve(directory);
40806
40929
  const scanDir = (() => {
40807
40930
  try {
40808
40931
  return fs12.realpathSync(_scanDirRaw);
@@ -40962,11 +41085,11 @@ async function runSecretscan(directory) {
40962
41085
  // src/tools/test-runner.ts
40963
41086
  init_zod();
40964
41087
  import * as fs16 from "fs";
40965
- import * as path27 from "path";
41088
+ import * as path28 from "path";
40966
41089
 
40967
41090
  // src/test-impact/analyzer.ts
40968
41091
  import fs13 from "fs";
40969
- import path24 from "path";
41092
+ import path25 from "path";
40970
41093
  var IMPORT_REGEX_ES = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
40971
41094
  var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
40972
41095
  var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
@@ -40991,8 +41114,8 @@ function resolveRelativeImport(fromDir, importPath) {
40991
41114
  if (!importPath.startsWith(".")) {
40992
41115
  return null;
40993
41116
  }
40994
- const resolved = path24.resolve(fromDir, importPath);
40995
- if (path24.extname(resolved)) {
41117
+ const resolved = path25.resolve(fromDir, importPath);
41118
+ if (path25.extname(resolved)) {
40996
41119
  if (fs13.existsSync(resolved) && fs13.statSync(resolved).isFile()) {
40997
41120
  return normalizePath(resolved);
40998
41121
  }
@@ -41037,12 +41160,12 @@ function findTestFilesSync(cwd) {
41037
41160
  for (const entry of entries) {
41038
41161
  if (entry.isDirectory()) {
41039
41162
  if (!skipDirs.has(entry.name)) {
41040
- walk(path24.join(dir, entry.name), visitedInodes);
41163
+ walk(path25.join(dir, entry.name), visitedInodes);
41041
41164
  }
41042
41165
  } else if (entry.isFile()) {
41043
41166
  const name = entry.name;
41044
41167
  if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
41045
- testFiles.push(normalizePath(path24.join(dir, entry.name)));
41168
+ testFiles.push(normalizePath(path25.join(dir, entry.name)));
41046
41169
  }
41047
41170
  }
41048
41171
  }
@@ -41080,7 +41203,7 @@ async function buildImpactMapInternal(cwd) {
41080
41203
  continue;
41081
41204
  }
41082
41205
  const imports = extractImports(content);
41083
- const testDir = path24.dirname(testFile);
41206
+ const testDir = path25.dirname(testFile);
41084
41207
  for (const importPath of imports) {
41085
41208
  const resolvedSource = resolveRelativeImport(testDir, importPath);
41086
41209
  if (resolvedSource === null) {
@@ -41102,7 +41225,7 @@ async function buildImpactMap(cwd) {
41102
41225
  return impactMap;
41103
41226
  }
41104
41227
  async function loadImpactMap(cwd) {
41105
- const cachePath = path24.join(cwd, ".swarm", "cache", "impact-map.json");
41228
+ const cachePath = path25.join(cwd, ".swarm", "cache", "impact-map.json");
41106
41229
  if (fs13.existsSync(cachePath)) {
41107
41230
  try {
41108
41231
  const content = fs13.readFileSync(cachePath, "utf-8");
@@ -41117,10 +41240,10 @@ async function loadImpactMap(cwd) {
41117
41240
  return buildImpactMap(cwd);
41118
41241
  }
41119
41242
  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 });
41243
+ const cacheDir2 = path25.join(cwd, ".swarm", "cache");
41244
+ const cachePath = path25.join(cacheDir2, "impact-map.json");
41245
+ if (!fs13.existsSync(cacheDir2)) {
41246
+ fs13.mkdirSync(cacheDir2, { recursive: true });
41124
41247
  }
41125
41248
  const data = {
41126
41249
  generatedAt: new Date().toISOString(),
@@ -41144,7 +41267,7 @@ async function analyzeImpact(changedFiles, cwd) {
41144
41267
  const impactedTestsSet = new Set;
41145
41268
  const untestedFiles = [];
41146
41269
  for (const changedFile of validFiles) {
41147
- const normalizedChanged = normalizePath(path24.resolve(changedFile));
41270
+ const normalizedChanged = normalizePath(path25.resolve(changedFile));
41148
41271
  const tests = impactMap[normalizedChanged];
41149
41272
  if (tests && tests.length > 0) {
41150
41273
  for (const test of tests) {
@@ -41391,13 +41514,13 @@ function detectFlakyTests(allHistory) {
41391
41514
 
41392
41515
  // src/test-impact/history-store.ts
41393
41516
  import fs14 from "fs";
41394
- import path25 from "path";
41517
+ import path26 from "path";
41395
41518
  var MAX_HISTORY_PER_TEST = 20;
41396
41519
  var MAX_ERROR_LENGTH = 500;
41397
41520
  var MAX_STACK_LENGTH = 200;
41398
41521
  var MAX_CHANGED_FILES = 50;
41399
41522
  function getHistoryPath(workingDir) {
41400
- return path25.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
41523
+ return path26.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
41401
41524
  }
41402
41525
  function sanitizeErrorMessage(errorMessage) {
41403
41526
  if (errorMessage === undefined) {
@@ -41457,7 +41580,7 @@ function appendTestRun(record3, workingDir) {
41457
41580
  changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
41458
41581
  };
41459
41582
  const historyPath = getHistoryPath(workingDir);
41460
- const historyDir = path25.dirname(historyPath);
41583
+ const historyDir = path26.dirname(historyPath);
41461
41584
  if (!fs14.existsSync(historyDir)) {
41462
41585
  fs14.mkdirSync(historyDir, { recursive: true });
41463
41586
  }
@@ -41531,7 +41654,7 @@ function getAllHistory(workingDir) {
41531
41654
 
41532
41655
  // src/tools/resolve-working-directory.ts
41533
41656
  import * as fs15 from "fs";
41534
- import * as path26 from "path";
41657
+ import * as path27 from "path";
41535
41658
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41536
41659
  if (workingDirectory == null || workingDirectory === "") {
41537
41660
  return { success: true, directory: fallbackDirectory };
@@ -41551,15 +41674,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41551
41674
  };
41552
41675
  }
41553
41676
  }
41554
- const normalizedDir = path26.normalize(workingDirectory);
41555
- const pathParts = normalizedDir.split(path26.sep);
41677
+ const normalizedDir = path27.normalize(workingDirectory);
41678
+ const pathParts = normalizedDir.split(path27.sep);
41556
41679
  if (pathParts.includes("..")) {
41557
41680
  return {
41558
41681
  success: false,
41559
41682
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
41560
41683
  };
41561
41684
  }
41562
- const resolvedDir = path26.resolve(normalizedDir);
41685
+ const resolvedDir = path27.resolve(normalizedDir);
41563
41686
  let statResult;
41564
41687
  try {
41565
41688
  statResult = fs15.statSync(resolvedDir);
@@ -41575,7 +41698,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41575
41698
  message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
41576
41699
  };
41577
41700
  }
41578
- const resolvedFallback = path26.resolve(fallbackDirectory);
41701
+ const resolvedFallback = path27.resolve(fallbackDirectory);
41579
41702
  let fallbackExists = false;
41580
41703
  try {
41581
41704
  fs15.statSync(resolvedFallback);
@@ -41585,7 +41708,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
41585
41708
  }
41586
41709
  if (workingDirectory != null && workingDirectory !== "") {
41587
41710
  if (fallbackExists) {
41588
- const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path26.sep);
41711
+ const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path27.sep);
41589
41712
  if (isSubdirectory) {
41590
41713
  return {
41591
41714
  success: false,
@@ -41675,14 +41798,14 @@ function hasDevDependency(devDeps, ...patterns) {
41675
41798
  return hasPackageJsonDependency(devDeps, ...patterns);
41676
41799
  }
41677
41800
  function detectGoTest(cwd) {
41678
- return fs16.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
41801
+ return fs16.existsSync(path28.join(cwd, "go.mod")) && isCommandAvailable("go");
41679
41802
  }
41680
41803
  function detectJavaMaven(cwd) {
41681
- return fs16.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
41804
+ return fs16.existsSync(path28.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
41682
41805
  }
41683
41806
  function detectGradle(cwd) {
41684
- const hasBuildFile = fs16.existsSync(path27.join(cwd, "build.gradle")) || fs16.existsSync(path27.join(cwd, "build.gradle.kts"));
41685
- const hasGradlew = fs16.existsSync(path27.join(cwd, "gradlew")) || fs16.existsSync(path27.join(cwd, "gradlew.bat"));
41807
+ const hasBuildFile = fs16.existsSync(path28.join(cwd, "build.gradle")) || fs16.existsSync(path28.join(cwd, "build.gradle.kts"));
41808
+ const hasGradlew = fs16.existsSync(path28.join(cwd, "gradlew")) || fs16.existsSync(path28.join(cwd, "gradlew.bat"));
41686
41809
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
41687
41810
  }
41688
41811
  function detectDotnetTest(cwd) {
@@ -41695,30 +41818,30 @@ function detectDotnetTest(cwd) {
41695
41818
  }
41696
41819
  }
41697
41820
  function detectCTest(cwd) {
41698
- const hasSource = fs16.existsSync(path27.join(cwd, "CMakeLists.txt"));
41699
- const hasBuildCache = fs16.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
41821
+ const hasSource = fs16.existsSync(path28.join(cwd, "CMakeLists.txt"));
41822
+ const hasBuildCache = fs16.existsSync(path28.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path28.join(cwd, "build", "CMakeCache.txt"));
41700
41823
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
41701
41824
  }
41702
41825
  function detectSwiftTest(cwd) {
41703
- return fs16.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
41826
+ return fs16.existsSync(path28.join(cwd, "Package.swift")) && isCommandAvailable("swift");
41704
41827
  }
41705
41828
  function detectDartTest(cwd) {
41706
- return fs16.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
41829
+ return fs16.existsSync(path28.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
41707
41830
  }
41708
41831
  function detectRSpec(cwd) {
41709
- const hasRSpecFile = fs16.existsSync(path27.join(cwd, ".rspec"));
41710
- const hasGemfile = fs16.existsSync(path27.join(cwd, "Gemfile"));
41711
- const hasSpecDir = fs16.existsSync(path27.join(cwd, "spec"));
41832
+ const hasRSpecFile = fs16.existsSync(path28.join(cwd, ".rspec"));
41833
+ const hasGemfile = fs16.existsSync(path28.join(cwd, "Gemfile"));
41834
+ const hasSpecDir = fs16.existsSync(path28.join(cwd, "spec"));
41712
41835
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
41713
41836
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
41714
41837
  }
41715
41838
  function detectMinitest(cwd) {
41716
- return fs16.existsSync(path27.join(cwd, "test")) && (fs16.existsSync(path27.join(cwd, "Gemfile")) || fs16.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
41839
+ return fs16.existsSync(path28.join(cwd, "test")) && (fs16.existsSync(path28.join(cwd, "Gemfile")) || fs16.existsSync(path28.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
41717
41840
  }
41718
41841
  async function detectTestFramework(cwd) {
41719
41842
  const baseDir = cwd;
41720
41843
  try {
41721
- const packageJsonPath = path27.join(baseDir, "package.json");
41844
+ const packageJsonPath = path28.join(baseDir, "package.json");
41722
41845
  if (fs16.existsSync(packageJsonPath)) {
41723
41846
  const content = fs16.readFileSync(packageJsonPath, "utf-8");
41724
41847
  const pkg = JSON.parse(content);
@@ -41739,16 +41862,16 @@ async function detectTestFramework(cwd) {
41739
41862
  return "jest";
41740
41863
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
41741
41864
  return "mocha";
41742
- if (fs16.existsSync(path27.join(baseDir, "bun.lockb")) || fs16.existsSync(path27.join(baseDir, "bun.lock"))) {
41865
+ if (fs16.existsSync(path28.join(baseDir, "bun.lockb")) || fs16.existsSync(path28.join(baseDir, "bun.lock"))) {
41743
41866
  if (scripts.test?.includes("bun"))
41744
41867
  return "bun";
41745
41868
  }
41746
41869
  }
41747
41870
  } catch {}
41748
41871
  try {
41749
- const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
41750
- const setupCfgPath = path27.join(baseDir, "setup.cfg");
41751
- const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
41872
+ const pyprojectTomlPath = path28.join(baseDir, "pyproject.toml");
41873
+ const setupCfgPath = path28.join(baseDir, "setup.cfg");
41874
+ const requirementsTxtPath = path28.join(baseDir, "requirements.txt");
41752
41875
  if (fs16.existsSync(pyprojectTomlPath)) {
41753
41876
  const content = fs16.readFileSync(pyprojectTomlPath, "utf-8");
41754
41877
  if (content.includes("[tool.pytest"))
@@ -41768,7 +41891,7 @@ async function detectTestFramework(cwd) {
41768
41891
  }
41769
41892
  } catch {}
41770
41893
  try {
41771
- const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
41894
+ const cargoTomlPath = path28.join(baseDir, "Cargo.toml");
41772
41895
  if (fs16.existsSync(cargoTomlPath)) {
41773
41896
  const content = fs16.readFileSync(cargoTomlPath, "utf-8");
41774
41897
  if (content.includes("[dev-dependencies]")) {
@@ -41779,9 +41902,9 @@ async function detectTestFramework(cwd) {
41779
41902
  }
41780
41903
  } catch {}
41781
41904
  try {
41782
- const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
41783
- const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
41784
- const pesterPs1Path = path27.join(baseDir, "tests.ps1");
41905
+ const pesterConfigPath = path28.join(baseDir, "pester.config.ps1");
41906
+ const pesterConfigJsonPath = path28.join(baseDir, "pester.config.ps1.json");
41907
+ const pesterPs1Path = path28.join(baseDir, "tests.ps1");
41785
41908
  if (fs16.existsSync(pesterConfigPath) || fs16.existsSync(pesterConfigJsonPath) || fs16.existsSync(pesterPs1Path)) {
41786
41909
  return "pester";
41787
41910
  }
@@ -41824,12 +41947,12 @@ function isTestDirectoryPath(normalizedPath) {
41824
41947
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
41825
41948
  }
41826
41949
  function resolveWorkspacePath(file3, workingDir) {
41827
- return path27.isAbsolute(file3) ? path27.resolve(file3) : path27.resolve(workingDir, file3);
41950
+ return path28.isAbsolute(file3) ? path28.resolve(file3) : path28.resolve(workingDir, file3);
41828
41951
  }
41829
41952
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
41830
41953
  if (!preferRelative)
41831
41954
  return absolutePath;
41832
- return path27.relative(workingDir, absolutePath);
41955
+ return path28.relative(workingDir, absolutePath);
41833
41956
  }
41834
41957
  function dedupePush(target, value) {
41835
41958
  if (!target.includes(value)) {
@@ -41866,18 +41989,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
41866
41989
  }
41867
41990
  }
41868
41991
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
41869
- const relativeDir = path27.dirname(relativePath);
41992
+ const relativeDir = path28.dirname(relativePath);
41870
41993
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
41871
41994
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
41872
- const rootDir = path27.join(workingDir, dirName);
41873
- return nestedRelativeDir ? [rootDir, path27.join(rootDir, nestedRelativeDir)] : [rootDir];
41995
+ const rootDir = path28.join(workingDir, dirName);
41996
+ return nestedRelativeDir ? [rootDir, path28.join(rootDir, nestedRelativeDir)] : [rootDir];
41874
41997
  });
41875
41998
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
41876
41999
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
41877
- directories.push(path27.join(workingDir, "src/test/java", path27.dirname(normalizedRelativePath.slice("src/main/java/".length))));
42000
+ directories.push(path28.join(workingDir, "src/test/java", path28.dirname(normalizedRelativePath.slice("src/main/java/".length))));
41878
42001
  }
41879
42002
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
41880
- directories.push(path27.join(workingDir, "src/test/kotlin", path27.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
42003
+ directories.push(path28.join(workingDir, "src/test/kotlin", path28.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
41881
42004
  }
41882
42005
  return [...new Set(directories)];
41883
42006
  }
@@ -41905,23 +42028,23 @@ function isLanguageSpecificTestFile(basename4) {
41905
42028
  }
41906
42029
  function isConventionTestFilePath(filePath) {
41907
42030
  const normalizedPath = filePath.replace(/\\/g, "/");
41908
- const basename4 = path27.basename(filePath);
42031
+ const basename4 = path28.basename(filePath);
41909
42032
  return hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || isLanguageSpecificTestFile(basename4) || isTestDirectoryPath(normalizedPath);
41910
42033
  }
41911
42034
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41912
42035
  const testFiles = [];
41913
42036
  for (const file3 of sourceFiles) {
41914
42037
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
41915
- const relativeFile = path27.relative(workingDir, absoluteFile);
41916
- const basename4 = path27.basename(absoluteFile);
41917
- const dirname11 = path27.dirname(absoluteFile);
41918
- const preferRelativeOutput = !path27.isAbsolute(file3);
42038
+ const relativeFile = path28.relative(workingDir, absoluteFile);
42039
+ const basename4 = path28.basename(absoluteFile);
42040
+ const dirname11 = path28.dirname(absoluteFile);
42041
+ const preferRelativeOutput = !path28.isAbsolute(file3);
41919
42042
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
41920
42043
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
41921
42044
  continue;
41922
42045
  }
41923
42046
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
41924
- const ext = path27.extname(basename4);
42047
+ const ext = path28.extname(basename4);
41925
42048
  const genericTestNames = [
41926
42049
  `${nameWithoutExt}.spec${ext}`,
41927
42050
  `${nameWithoutExt}.test${ext}`
@@ -41930,7 +42053,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41930
42053
  const colocatedCandidates = [
41931
42054
  ...genericTestNames,
41932
42055
  ...languageSpecificTestNames
41933
- ].map((candidateName) => path27.join(dirname11, candidateName));
42056
+ ].map((candidateName) => path28.join(dirname11, candidateName));
41934
42057
  const testDirectoryNames = [
41935
42058
  basename4,
41936
42059
  ...genericTestNames,
@@ -41939,8 +42062,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
41939
42062
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
41940
42063
  const possibleTestFiles = [
41941
42064
  ...colocatedCandidates,
41942
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path27.join(dirname11, dirName, candidateName))),
41943
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path27.join(candidateDir, candidateName)))
42065
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path28.join(dirname11, dirName, candidateName))),
42066
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path28.join(candidateDir, candidateName)))
41944
42067
  ];
41945
42068
  for (const testFile of possibleTestFiles) {
41946
42069
  if (fs16.existsSync(testFile)) {
@@ -41961,7 +42084,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41961
42084
  try {
41962
42085
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
41963
42086
  const content = fs16.readFileSync(absoluteTestFile, "utf-8");
41964
- const testDir = path27.dirname(absoluteTestFile);
42087
+ const testDir = path28.dirname(absoluteTestFile);
41965
42088
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
41966
42089
  let match;
41967
42090
  match = importRegex.exec(content);
@@ -41969,8 +42092,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41969
42092
  const importPath = match[1];
41970
42093
  let resolvedImport;
41971
42094
  if (importPath.startsWith(".")) {
41972
- resolvedImport = path27.resolve(testDir, importPath);
41973
- const existingExt = path27.extname(resolvedImport);
42095
+ resolvedImport = path28.resolve(testDir, importPath);
42096
+ const existingExt = path28.extname(resolvedImport);
41974
42097
  if (!existingExt) {
41975
42098
  for (const extToTry of [
41976
42099
  ".ts",
@@ -41990,12 +42113,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
41990
42113
  } else {
41991
42114
  continue;
41992
42115
  }
41993
- const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
41994
- const importDir = path27.dirname(resolvedImport);
42116
+ const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
42117
+ const importDir = path28.dirname(resolvedImport);
41995
42118
  for (const sourceFile of absoluteSourceFiles) {
41996
- const sourceDir = path27.dirname(sourceFile);
41997
- const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
41998
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
42119
+ const sourceDir = path28.dirname(sourceFile);
42120
+ const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
42121
+ const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test") || importDir === path28.join(sourceDir, "spec");
41999
42122
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
42000
42123
  dedupePush(testFiles, testFile);
42001
42124
  break;
@@ -42008,8 +42131,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
42008
42131
  while (match !== null) {
42009
42132
  const importPath = match[1];
42010
42133
  if (importPath.startsWith(".")) {
42011
- let resolvedImport = path27.resolve(testDir, importPath);
42012
- const existingExt = path27.extname(resolvedImport);
42134
+ let resolvedImport = path28.resolve(testDir, importPath);
42135
+ const existingExt = path28.extname(resolvedImport);
42013
42136
  if (!existingExt) {
42014
42137
  for (const extToTry of [
42015
42138
  ".ts",
@@ -42026,12 +42149,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
42026
42149
  }
42027
42150
  }
42028
42151
  }
42029
- const importDir = path27.dirname(resolvedImport);
42030
- const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
42152
+ const importDir = path28.dirname(resolvedImport);
42153
+ const importBasename = path28.basename(resolvedImport, path28.extname(resolvedImport));
42031
42154
  for (const sourceFile of absoluteSourceFiles) {
42032
- const sourceDir = path27.dirname(sourceFile);
42033
- const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
42034
- const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
42155
+ const sourceDir = path28.dirname(sourceFile);
42156
+ const sourceBasename = path28.basename(sourceFile, path28.extname(sourceFile));
42157
+ const isRelatedDir = importDir === sourceDir || importDir === path28.join(sourceDir, "__tests__") || importDir === path28.join(sourceDir, "tests") || importDir === path28.join(sourceDir, "test") || importDir === path28.join(sourceDir, "spec");
42035
42158
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
42036
42159
  dedupePush(testFiles, testFile);
42037
42160
  break;
@@ -42134,8 +42257,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
42134
42257
  return ["mvn", "test"];
42135
42258
  case "gradle": {
42136
42259
  const isWindows = process.platform === "win32";
42137
- const hasGradlewBat = fs16.existsSync(path27.join(baseDir, "gradlew.bat"));
42138
- const hasGradlew = fs16.existsSync(path27.join(baseDir, "gradlew"));
42260
+ const hasGradlewBat = fs16.existsSync(path28.join(baseDir, "gradlew.bat"));
42261
+ const hasGradlew = fs16.existsSync(path28.join(baseDir, "gradlew"));
42139
42262
  if (hasGradlewBat && isWindows)
42140
42263
  return ["gradlew.bat", "test"];
42141
42264
  if (hasGradlew)
@@ -42152,7 +42275,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
42152
42275
  "cmake-build-release",
42153
42276
  "out"
42154
42277
  ];
42155
- const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
42278
+ const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path28.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
42156
42279
  return ["ctest", "--test-dir", actualBuildDir];
42157
42280
  }
42158
42281
  case "swift-test":
@@ -42780,7 +42903,7 @@ var test_runner = createSwarmTool({
42780
42903
  const sourceFiles = args.files.filter((file3) => {
42781
42904
  if (directTestFiles.includes(file3))
42782
42905
  return false;
42783
- const ext = path27.extname(file3).toLowerCase();
42906
+ const ext = path28.extname(file3).toLowerCase();
42784
42907
  return SOURCE_EXTENSIONS.has(ext);
42785
42908
  });
42786
42909
  const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
@@ -42815,7 +42938,7 @@ var test_runner = createSwarmTool({
42815
42938
  if (isConventionTestFilePath(f)) {
42816
42939
  return false;
42817
42940
  }
42818
- const ext = path27.extname(f).toLowerCase();
42941
+ const ext = path28.extname(f).toLowerCase();
42819
42942
  return SOURCE_EXTENSIONS.has(ext);
42820
42943
  });
42821
42944
  if (sourceFiles.length === 0) {
@@ -42842,7 +42965,7 @@ var test_runner = createSwarmTool({
42842
42965
  if (isConventionTestFilePath(f)) {
42843
42966
  return false;
42844
42967
  }
42845
- const ext = path27.extname(f).toLowerCase();
42968
+ const ext = path28.extname(f).toLowerCase();
42846
42969
  return SOURCE_EXTENSIONS.has(ext);
42847
42970
  });
42848
42971
  if (sourceFiles.length === 0) {
@@ -42860,8 +42983,8 @@ var test_runner = createSwarmTool({
42860
42983
  const impactResult = await analyzeImpact(sourceFiles, workingDir);
42861
42984
  if (impactResult.impactedTests.length > 0) {
42862
42985
  testFiles = impactResult.impactedTests.map((absPath) => {
42863
- const relativePath = path27.relative(workingDir, absPath);
42864
- return path27.isAbsolute(relativePath) ? absPath : relativePath;
42986
+ const relativePath = path28.relative(workingDir, absPath);
42987
+ return path28.isAbsolute(relativePath) ? absPath : relativePath;
42865
42988
  });
42866
42989
  } else {
42867
42990
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -42954,8 +43077,8 @@ function validateDirectoryPath(dir) {
42954
43077
  if (dir.includes("..")) {
42955
43078
  throw new Error("Directory path must not contain path traversal sequences");
42956
43079
  }
42957
- const normalized = path28.normalize(dir);
42958
- const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
43080
+ const normalized = path29.normalize(dir);
43081
+ const absolutePath = path29.isAbsolute(normalized) ? normalized : path29.resolve(normalized);
42959
43082
  return absolutePath;
42960
43083
  }
42961
43084
  function validateTimeout(timeoutMs, defaultValue) {
@@ -42978,7 +43101,7 @@ function validateTimeout(timeoutMs, defaultValue) {
42978
43101
  }
42979
43102
  function getPackageVersion(dir) {
42980
43103
  try {
42981
- const packagePath = path28.join(dir, "package.json");
43104
+ const packagePath = path29.join(dir, "package.json");
42982
43105
  if (fs17.existsSync(packagePath)) {
42983
43106
  const content = fs17.readFileSync(packagePath, "utf-8");
42984
43107
  const pkg = JSON.parse(content);
@@ -42989,7 +43112,7 @@ function getPackageVersion(dir) {
42989
43112
  }
42990
43113
  function getChangelogVersion(dir) {
42991
43114
  try {
42992
- const changelogPath = path28.join(dir, "CHANGELOG.md");
43115
+ const changelogPath = path29.join(dir, "CHANGELOG.md");
42993
43116
  if (fs17.existsSync(changelogPath)) {
42994
43117
  const content = fs17.readFileSync(changelogPath, "utf-8");
42995
43118
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
@@ -43003,7 +43126,7 @@ function getChangelogVersion(dir) {
43003
43126
  function getVersionFileVersion(dir) {
43004
43127
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
43005
43128
  for (const file3 of possibleFiles) {
43006
- const filePath = path28.join(dir, file3);
43129
+ const filePath = path29.join(dir, file3);
43007
43130
  if (fs17.existsSync(filePath)) {
43008
43131
  try {
43009
43132
  const content = fs17.readFileSync(filePath, "utf-8").trim();
@@ -43330,7 +43453,7 @@ async function runEvidenceCheck(dir) {
43330
43453
  async function runRequirementCoverageCheck(dir, currentPhase) {
43331
43454
  const startTime = Date.now();
43332
43455
  try {
43333
- const specPath = path28.join(dir, ".swarm", "spec.md");
43456
+ const specPath = path29.join(dir, ".swarm", "spec.md");
43334
43457
  if (!fs17.existsSync(specPath)) {
43335
43458
  return {
43336
43459
  type: "req_coverage",
@@ -44453,7 +44576,7 @@ async function handleResetCommand(directory, args) {
44453
44576
  // src/commands/reset-session.ts
44454
44577
  init_utils2();
44455
44578
  import * as fs19 from "fs";
44456
- import * as path29 from "path";
44579
+ import * as path30 from "path";
44457
44580
  async function handleResetSessionCommand(directory, _args) {
44458
44581
  const results = [];
44459
44582
  try {
@@ -44468,13 +44591,13 @@ async function handleResetSessionCommand(directory, _args) {
44468
44591
  results.push("\u274C Failed to delete state.json");
44469
44592
  }
44470
44593
  try {
44471
- const sessionDir = path29.dirname(validateSwarmPath(directory, "session/state.json"));
44594
+ const sessionDir = path30.dirname(validateSwarmPath(directory, "session/state.json"));
44472
44595
  if (fs19.existsSync(sessionDir)) {
44473
44596
  const files = fs19.readdirSync(sessionDir);
44474
44597
  const otherFiles = files.filter((f) => f !== "state.json");
44475
44598
  let deletedCount = 0;
44476
44599
  for (const file3 of otherFiles) {
44477
- const filePath = path29.join(sessionDir, file3);
44600
+ const filePath = path30.join(sessionDir, file3);
44478
44601
  if (fs19.lstatSync(filePath).isFile()) {
44479
44602
  fs19.unlinkSync(filePath);
44480
44603
  deletedCount++;
@@ -44504,7 +44627,7 @@ async function handleResetSessionCommand(directory, _args) {
44504
44627
  // src/summaries/manager.ts
44505
44628
  init_utils2();
44506
44629
  init_utils();
44507
- import * as path30 from "path";
44630
+ import * as path31 from "path";
44508
44631
  var SUMMARY_ID_REGEX = /^S\d+$/;
44509
44632
  function sanitizeSummaryId(id) {
44510
44633
  if (!id || id.length === 0) {
@@ -44528,7 +44651,7 @@ function sanitizeSummaryId(id) {
44528
44651
  }
44529
44652
  async function loadFullOutput(directory, id) {
44530
44653
  const sanitizedId = sanitizeSummaryId(id);
44531
- const relativePath = path30.join("summaries", `${sanitizedId}.json`);
44654
+ const relativePath = path31.join("summaries", `${sanitizedId}.json`);
44532
44655
  validateSwarmPath(directory, relativePath);
44533
44656
  const content = await readSwarmFileAsync(directory, relativePath);
44534
44657
  if (content === null) {
@@ -44584,7 +44707,7 @@ init_plan_schema();
44584
44707
  init_utils2();
44585
44708
  init_ledger();
44586
44709
  import * as fs20 from "fs";
44587
- import * as path31 from "path";
44710
+ import * as path32 from "path";
44588
44711
  async function handleRollbackCommand(directory, args) {
44589
44712
  const phaseArg = args[0];
44590
44713
  if (!phaseArg) {
@@ -44649,8 +44772,8 @@ async function handleRollbackCommand(directory, args) {
44649
44772
  if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
44650
44773
  continue;
44651
44774
  }
44652
- const src = path31.join(checkpointDir, file3);
44653
- const dest = path31.join(swarmDir, file3);
44775
+ const src = path32.join(checkpointDir, file3);
44776
+ const dest = path32.join(swarmDir, file3);
44654
44777
  try {
44655
44778
  fs20.cpSync(src, dest, { recursive: true, force: true });
44656
44779
  successes.push(file3);
@@ -44669,12 +44792,12 @@ async function handleRollbackCommand(directory, args) {
44669
44792
  ].join(`
44670
44793
  `);
44671
44794
  }
44672
- const existingLedgerPath = path31.join(swarmDir, "plan-ledger.jsonl");
44795
+ const existingLedgerPath = path32.join(swarmDir, "plan-ledger.jsonl");
44673
44796
  if (fs20.existsSync(existingLedgerPath)) {
44674
44797
  fs20.unlinkSync(existingLedgerPath);
44675
44798
  }
44676
44799
  try {
44677
- const planJsonPath = path31.join(swarmDir, "plan.json");
44800
+ const planJsonPath = path32.join(swarmDir, "plan.json");
44678
44801
  if (fs20.existsSync(planJsonPath)) {
44679
44802
  const planRaw = fs20.readFileSync(planJsonPath, "utf-8");
44680
44803
  const plan = PlanSchema.parse(JSON.parse(planRaw));
@@ -44747,9 +44870,9 @@ async function handleSimulateCommand(directory, args) {
44747
44870
  const report = reportLines.filter(Boolean).join(`
44748
44871
  `);
44749
44872
  const fs21 = await import("fs/promises");
44750
- const path32 = await import("path");
44751
- const reportPath = path32.join(directory, ".swarm", "simulate-report.md");
44752
- await fs21.mkdir(path32.dirname(reportPath), { recursive: true });
44873
+ const path33 = await import("path");
44874
+ const reportPath = path33.join(directory, ".swarm", "simulate-report.md");
44875
+ await fs21.mkdir(path33.dirname(reportPath), { recursive: true });
44753
44876
  await fs21.writeFile(reportPath, report, "utf-8");
44754
44877
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
44755
44878
  }
@@ -45284,11 +45407,35 @@ function resolveCommand(tokens) {
45284
45407
 
45285
45408
  // src/cli/index.ts
45286
45409
  var { version: version4 } = package_default;
45287
- var CONFIG_DIR = path32.join(process.env.XDG_CONFIG_HOME || path32.join(os6.homedir(), ".config"), "opencode");
45288
- var OPENCODE_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode.json");
45289
- var PLUGIN_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode-swarm.json");
45290
- 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");
45410
+ var CONFIG_DIR = getPluginConfigDir();
45411
+ var OPENCODE_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode.json");
45412
+ var PLUGIN_CONFIG_PATH = path33.join(CONFIG_DIR, "opencode-swarm.json");
45413
+ var PROMPTS_DIR = path33.join(CONFIG_DIR, "opencode-swarm");
45414
+ var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
45415
+ function isSafeCachePath(p) {
45416
+ const resolved = path33.resolve(p);
45417
+ const home = path33.resolve(os7.homedir());
45418
+ if (resolved === "/" || resolved === home || resolved.length <= home.length) {
45419
+ return false;
45420
+ }
45421
+ const segments = resolved.split(path33.sep).filter((s) => s.length > 0);
45422
+ if (segments.length < 4) {
45423
+ return false;
45424
+ }
45425
+ const leaf = path33.basename(resolved);
45426
+ if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
45427
+ return false;
45428
+ }
45429
+ const parent = path33.basename(path33.dirname(resolved));
45430
+ if (parent !== "packages" && parent !== "node_modules") {
45431
+ return false;
45432
+ }
45433
+ const grandparent = path33.basename(path33.dirname(path33.dirname(resolved)));
45434
+ if (grandparent !== "opencode") {
45435
+ return false;
45436
+ }
45437
+ return true;
45438
+ }
45292
45439
  function ensureDir(dir) {
45293
45440
  if (!fs21.existsSync(dir)) {
45294
45441
  fs21.mkdirSync(dir, { recursive: true });
@@ -45309,8 +45456,8 @@ function saveJson(filepath, data) {
45309
45456
  }
45310
45457
  function writeProjectConfigIfMissing(cwd) {
45311
45458
  try {
45312
- const opencodeDir = path32.join(cwd, ".opencode");
45313
- const projectConfigPath = path32.join(opencodeDir, "opencode-swarm.json");
45459
+ const opencodeDir = path33.join(cwd, ".opencode");
45460
+ const projectConfigPath = path33.join(opencodeDir, "opencode-swarm.json");
45314
45461
  if (fs21.existsSync(projectConfigPath)) {
45315
45462
  return;
45316
45463
  }
@@ -45328,7 +45475,7 @@ async function install() {
45328
45475
  `);
45329
45476
  ensureDir(CONFIG_DIR);
45330
45477
  ensureDir(PROMPTS_DIR);
45331
- const LEGACY_CONFIG_PATH = path32.join(CONFIG_DIR, "config.json");
45478
+ const LEGACY_CONFIG_PATH = path33.join(CONFIG_DIR, "config.json");
45332
45479
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
45333
45480
  if (!opencodeConfig) {
45334
45481
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -45359,14 +45506,13 @@ async function install() {
45359
45506
  saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
45360
45507
  console.log("\u2713 Added opencode-swarm to OpenCode plugins");
45361
45508
  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}`);
45509
+ const evicted = evictPluginCaches();
45510
+ if (evicted.cleared.length > 0) {
45511
+ console.log(`\u2713 Cleared opencode plugin cache (next start will fetch latest): ${evicted.cleared.join(", ")}`);
45512
+ }
45513
+ for (const failed of evicted.failed) {
45514
+ console.warn(`\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:
45515
+ ${failed}`);
45370
45516
  }
45371
45517
  if (!fs21.existsSync(PLUGIN_CONFIG_PATH)) {
45372
45518
  const defaultConfig = {
@@ -45466,6 +45612,51 @@ Next steps:`);
45466
45612
  console.log(" \u2014 use it as a reference for customizing model assignments.");
45467
45613
  return 0;
45468
45614
  }
45615
+ async function update() {
45616
+ console.log(`\uD83D\uDC1D Refreshing OpenCode Swarm plugin cache...
45617
+ `);
45618
+ const result = evictPluginCaches();
45619
+ if (result.cleared.length > 0) {
45620
+ for (const cleared of result.cleared) {
45621
+ console.log(`\u2713 Cleared: ${cleared}`);
45622
+ }
45623
+ console.log(`
45624
+ Restart OpenCode to fetch the latest version from npm.`);
45625
+ }
45626
+ if (result.cleared.length === 0 && result.failed.length === 0) {
45627
+ console.log("No cached plugin found. Restart OpenCode to fetch the latest version from npm.");
45628
+ console.log("Checked locations:");
45629
+ for (const p of OPENCODE_PLUGIN_CACHE_PATHS) {
45630
+ console.log(` - ${p}`);
45631
+ }
45632
+ }
45633
+ if (result.failed.length > 0) {
45634
+ for (const failed of result.failed) {
45635
+ console.error(`\u2717 Could not clear: ${failed}`);
45636
+ }
45637
+ return 1;
45638
+ }
45639
+ return 0;
45640
+ }
45641
+ function evictPluginCaches() {
45642
+ const cleared = [];
45643
+ const failed = [];
45644
+ for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
45645
+ if (!fs21.existsSync(cachePath))
45646
+ continue;
45647
+ if (!isSafeCachePath(cachePath)) {
45648
+ failed.push(`${cachePath} (refused: failed safety check)`);
45649
+ continue;
45650
+ }
45651
+ try {
45652
+ fs21.rmSync(cachePath, { recursive: true, force: true });
45653
+ cleared.push(cachePath);
45654
+ } catch (err) {
45655
+ failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
45656
+ }
45657
+ }
45658
+ return { cleared, failed };
45659
+ }
45469
45660
  async function uninstall() {
45470
45661
  try {
45471
45662
  console.log(`\uD83D\uDC1D Uninstalling OpenCode Swarm...
@@ -45536,6 +45727,7 @@ Usage: bunx opencode-swarm [command] [OPTIONS]
45536
45727
 
45537
45728
  Commands:
45538
45729
  install Install and configure the plugin (default)
45730
+ update Refresh OpenCode's plugin cache so the next start fetches latest from npm
45539
45731
  uninstall Remove the plugin from OpenCode config
45540
45732
  run Run a plugin command directly (for use outside OpenCode)
45541
45733
 
@@ -45560,6 +45752,7 @@ Custom Prompts:
45560
45752
 
45561
45753
  Examples:
45562
45754
  bunx opencode-swarm install
45755
+ bunx opencode-swarm update
45563
45756
  bunx opencode-swarm uninstall
45564
45757
  bunx opencode-swarm uninstall --clean
45565
45758
  bunx opencode-swarm --help
@@ -45585,6 +45778,9 @@ async function main() {
45585
45778
  if (command === "install") {
45586
45779
  const exitCode = await install();
45587
45780
  process.exit(exitCode);
45781
+ } else if (command === "update") {
45782
+ const exitCode = await update();
45783
+ process.exit(exitCode);
45588
45784
  } else if (command === "uninstall") {
45589
45785
  const exitCode = await uninstall();
45590
45786
  process.exit(exitCode);