opencode-swarm 7.18.1 → 7.18.3

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
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.18.1",
37
+ version: "7.18.3",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -16501,8 +16501,7 @@ var init_constants = __esm(() => {
16501
16501
  "skill_improve",
16502
16502
  "search",
16503
16503
  "doc_scan",
16504
- "doc_extract",
16505
- "web_search"
16504
+ "doc_extract"
16506
16505
  ],
16507
16506
  spec_writer: [
16508
16507
  "search",
@@ -16602,67 +16601,67 @@ var init_constants = __esm(() => {
16602
16601
  DEFAULT_AGENT_CONFIGS = {
16603
16602
  coder: {
16604
16603
  model: "opencode/minimax-m2.5-free",
16605
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16604
+ fallback_models: ["opencode/big-pickle"]
16606
16605
  },
16607
16606
  reviewer: {
16608
16607
  model: "opencode/big-pickle",
16609
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16608
+ fallback_models: ["opencode/minimax-m2.5-free"]
16610
16609
  },
16611
16610
  test_engineer: {
16612
- model: "opencode/gpt-5-nano",
16613
- fallback_models: ["opencode/big-pickle"]
16611
+ model: "opencode/big-pickle",
16612
+ fallback_models: ["opencode/minimax-m2.5-free"]
16614
16613
  },
16615
16614
  explorer: {
16616
16615
  model: "opencode/big-pickle",
16617
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16616
+ fallback_models: ["opencode/minimax-m2.5-free"]
16618
16617
  },
16619
16618
  sme: {
16620
16619
  model: "opencode/big-pickle",
16621
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16620
+ fallback_models: ["opencode/minimax-m2.5-free"]
16622
16621
  },
16623
16622
  critic: {
16624
16623
  model: "opencode/big-pickle",
16625
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16624
+ fallback_models: ["opencode/minimax-m2.5-free"]
16626
16625
  },
16627
16626
  docs: {
16628
16627
  model: "opencode/big-pickle",
16629
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16628
+ fallback_models: ["opencode/minimax-m2.5-free"]
16630
16629
  },
16631
16630
  designer: {
16632
16631
  model: "opencode/big-pickle",
16633
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16632
+ fallback_models: ["opencode/minimax-m2.5-free"]
16634
16633
  },
16635
16634
  critic_sounding_board: {
16636
- model: "opencode/gpt-5-nano",
16637
- fallback_models: ["opencode/big-pickle"]
16635
+ model: "opencode/big-pickle",
16636
+ fallback_models: ["opencode/minimax-m2.5-free"]
16638
16637
  },
16639
16638
  critic_drift_verifier: {
16640
- model: "opencode/gpt-5-nano",
16641
- fallback_models: ["opencode/big-pickle"]
16639
+ model: "opencode/big-pickle",
16640
+ fallback_models: ["opencode/minimax-m2.5-free"]
16642
16641
  },
16643
16642
  critic_hallucination_verifier: {
16644
- model: "opencode/gpt-5-nano",
16645
- fallback_models: ["opencode/big-pickle"]
16643
+ model: "opencode/big-pickle",
16644
+ fallback_models: ["opencode/minimax-m2.5-free"]
16646
16645
  },
16647
16646
  critic_oversight: {
16648
- model: "opencode/gpt-5-nano",
16649
- fallback_models: ["opencode/big-pickle"]
16647
+ model: "opencode/big-pickle",
16648
+ fallback_models: ["opencode/minimax-m2.5-free"]
16650
16649
  },
16651
16650
  curator_init: {
16652
- model: "opencode/gpt-5-nano",
16653
- fallback_models: ["opencode/big-pickle"]
16651
+ model: "opencode/big-pickle",
16652
+ fallback_models: ["opencode/minimax-m2.5-free"]
16654
16653
  },
16655
16654
  curator_phase: {
16656
- model: "opencode/gpt-5-nano",
16657
- fallback_models: ["opencode/big-pickle"]
16655
+ model: "opencode/big-pickle",
16656
+ fallback_models: ["opencode/minimax-m2.5-free"]
16658
16657
  },
16659
16658
  skill_improver: {
16660
16659
  model: "opencode/big-pickle",
16661
- fallback_models: ["opencode/gpt-5-nano"]
16660
+ fallback_models: ["opencode/minimax-m2.5-free"]
16662
16661
  },
16663
16662
  spec_writer: {
16664
16663
  model: "opencode/big-pickle",
16665
- fallback_models: ["opencode/gpt-5-nano"]
16664
+ fallback_models: ["opencode/minimax-m2.5-free"]
16666
16665
  }
16667
16666
  };
16668
16667
  });
@@ -17545,7 +17544,8 @@ function handleAgentsCommand(agents, guardrails) {
17545
17544
  if (hasUnregistered) {
17546
17545
  lines.push("", "### Unregistered Subagents");
17547
17546
  for (const name of unregistered) {
17548
- lines.push(`- **${name}** (requires configuration)`);
17547
+ const hint = UNREGISTERED_AGENT_HINTS[name] ?? "requires configuration";
17548
+ lines.push(`- **${name}** (${hint})`);
17549
17549
  }
17550
17550
  }
17551
17551
  if (guardrails?.profiles && Object.keys(guardrails.profiles).length > 0) {
@@ -17574,9 +17574,18 @@ function handleAgentsCommand(agents, guardrails) {
17574
17574
  return lines.join(`
17575
17575
  `);
17576
17576
  }
17577
+ var UNREGISTERED_AGENT_HINTS;
17577
17578
  var init_agents = __esm(() => {
17578
17579
  init_constants();
17579
17580
  init_schema();
17581
+ UNREGISTERED_AGENT_HINTS = {
17582
+ designer: "enable ui_review.enabled",
17583
+ council_generalist: "enable council.general.enabled",
17584
+ council_skeptic: "enable council.general.enabled",
17585
+ council_domain_expert: "enable council.general.enabled",
17586
+ skill_improver: "registered by default unless agents.skill_improver.disabled is true",
17587
+ spec_writer: "registered by default unless agents.spec_writer.disabled is true"
17588
+ };
17580
17589
  });
17581
17590
 
17582
17591
  // src/commands/analyze.ts
@@ -38247,12 +38256,31 @@ function parseArgs(args) {
38247
38256
  }
38248
38257
  return out;
38249
38258
  }
38250
- async function handleCouncilCommand(_directory, args) {
38259
+ async function handleCouncilCommand(directory, args) {
38251
38260
  const parsed = parseArgs(args);
38252
38261
  const question = sanitizeQuestion(parsed.rest.join(" "));
38253
38262
  if (!question) {
38254
38263
  return USAGE;
38255
38264
  }
38265
+ const config3 = loadPluginConfig(directory);
38266
+ if (config3.council?.general?.enabled !== true) {
38267
+ return [
38268
+ "General Council is not enabled for this project.",
38269
+ "",
38270
+ "Enable it in `.opencode/opencode-swarm.json` or `~/.config/opencode/opencode-swarm.json`:",
38271
+ "",
38272
+ "```json",
38273
+ "{",
38274
+ ' "council": {',
38275
+ ' "general": { "enabled": true }',
38276
+ " }",
38277
+ "}",
38278
+ "```",
38279
+ "",
38280
+ "Then restart OpenCode and run `/swarm config doctor` before trying `/swarm council` again."
38281
+ ].join(`
38282
+ `);
38283
+ }
38256
38284
  const tokens = ["MODE: COUNCIL"];
38257
38285
  if (parsed.preset) {
38258
38286
  tokens.push(`preset=${parsed.preset}`);
@@ -38264,6 +38292,7 @@ async function handleCouncilCommand(_directory, args) {
38264
38292
  }
38265
38293
  var MAX_QUESTION_LEN = 2000, USAGE;
38266
38294
  var init_council = __esm(() => {
38295
+ init_loader();
38267
38296
  USAGE = [
38268
38297
  "Usage: /swarm council <question> [--preset <name>] [--spec-review]",
38269
38298
  "",
@@ -39740,6 +39769,7 @@ __export(exports_config_doctor, {
39740
39769
  restoreFromBackup: () => restoreFromBackup,
39741
39770
  getConfigPaths: () => getConfigPaths,
39742
39771
  createConfigBackup: () => createConfigBackup,
39772
+ collectConfiguredModelRefs: () => collectConfiguredModelRefs,
39743
39773
  applySafeAutoFixes: () => applySafeAutoFixes
39744
39774
  });
39745
39775
  import * as crypto3 from "crypto";
@@ -40133,6 +40163,129 @@ function validateConfigKey(path24, value, _config) {
40133
40163
  }
40134
40164
  return findings;
40135
40165
  }
40166
+ function addConfiguredModel(refs, model, configPath) {
40167
+ if (typeof model !== "string")
40168
+ return;
40169
+ const trimmed = model.trim();
40170
+ if (!trimmed)
40171
+ return;
40172
+ const paths = refs.get(trimmed) ?? new Set;
40173
+ paths.add(configPath);
40174
+ refs.set(trimmed, paths);
40175
+ }
40176
+ function addConfiguredAgentModels(refs, agents, prefix) {
40177
+ if (!agents || typeof agents !== "object" || Array.isArray(agents))
40178
+ return;
40179
+ for (const [agentName, value] of Object.entries(agents)) {
40180
+ if (!value || typeof value !== "object" || Array.isArray(value))
40181
+ continue;
40182
+ const agent = value;
40183
+ addConfiguredModel(refs, agent.model, `${prefix}.${agentName}.model`);
40184
+ if (Array.isArray(agent.fallback_models)) {
40185
+ agent.fallback_models.forEach((model, index) => {
40186
+ addConfiguredModel(refs, model, `${prefix}.${agentName}.fallback_models[${index}]`);
40187
+ });
40188
+ }
40189
+ }
40190
+ }
40191
+ function collectConfiguredModelRefs(config3) {
40192
+ const refs = new Map;
40193
+ const rawConfig = config3;
40194
+ addConfiguredAgentModels(refs, rawConfig.agents, "agents");
40195
+ if (rawConfig.swarms && typeof rawConfig.swarms === "object" && !Array.isArray(rawConfig.swarms)) {
40196
+ for (const [swarmId, value] of Object.entries(rawConfig.swarms)) {
40197
+ if (!value || typeof value !== "object" || Array.isArray(value))
40198
+ continue;
40199
+ addConfiguredAgentModels(refs, value.agents, `swarms.${swarmId}.agents`);
40200
+ }
40201
+ }
40202
+ if (rawConfig.full_auto && typeof rawConfig.full_auto === "object" && !Array.isArray(rawConfig.full_auto)) {
40203
+ addConfiguredModel(refs, rawConfig.full_auto.critic_model, "full_auto.critic_model");
40204
+ }
40205
+ if (rawConfig.skill_improver && typeof rawConfig.skill_improver === "object" && !Array.isArray(rawConfig.skill_improver)) {
40206
+ const skillImprover = rawConfig.skill_improver;
40207
+ addConfiguredModel(refs, skillImprover.model, "skill_improver.model");
40208
+ if (Array.isArray(skillImprover.fallback_models)) {
40209
+ skillImprover.fallback_models.forEach((model, index) => {
40210
+ addConfiguredModel(refs, model, `skill_improver.fallback_models[${index}]`);
40211
+ });
40212
+ }
40213
+ }
40214
+ if (rawConfig.spec_writer && typeof rawConfig.spec_writer === "object" && !Array.isArray(rawConfig.spec_writer)) {
40215
+ const specWriter = rawConfig.spec_writer;
40216
+ addConfiguredModel(refs, specWriter.model, "spec_writer.model");
40217
+ if (Array.isArray(specWriter.fallback_models)) {
40218
+ specWriter.fallback_models.forEach((model, index) => {
40219
+ addConfiguredModel(refs, model, `spec_writer.fallback_models[${index}]`);
40220
+ });
40221
+ }
40222
+ }
40223
+ const council = rawConfig.council;
40224
+ const general = council && typeof council === "object" && !Array.isArray(council) ? council.general : undefined;
40225
+ if (general && typeof general === "object" && !Array.isArray(general)) {
40226
+ addConfiguredModel(refs, general.moderatorModel, "council.general.moderatorModel");
40227
+ if (Array.isArray(general.members)) {
40228
+ general.members.forEach((member, index) => {
40229
+ if (!member || typeof member !== "object" || Array.isArray(member)) {
40230
+ return;
40231
+ }
40232
+ addConfiguredModel(refs, member.model, `council.general.members[${index}].model`);
40233
+ });
40234
+ }
40235
+ if (general.presets && typeof general.presets === "object" && !Array.isArray(general.presets)) {
40236
+ for (const [presetName, members] of Object.entries(general.presets)) {
40237
+ if (!Array.isArray(members))
40238
+ continue;
40239
+ members.forEach((member, index) => {
40240
+ if (!member || typeof member !== "object" || Array.isArray(member)) {
40241
+ return;
40242
+ }
40243
+ addConfiguredModel(refs, member.model, `council.general.presets.${presetName}[${index}].model`);
40244
+ });
40245
+ }
40246
+ }
40247
+ }
40248
+ return refs;
40249
+ }
40250
+ function validateConfiguredModels(config3, modelAvailability) {
40251
+ const refs = collectConfiguredModelRefs(config3);
40252
+ const findings = [];
40253
+ if (modelAvailability.error) {
40254
+ findings.push({
40255
+ id: "model-availability-unchecked",
40256
+ title: "Model availability check skipped",
40257
+ description: `Could not load OpenCode provider models from ${modelAvailability.source}: ` + modelAvailability.error,
40258
+ severity: "info",
40259
+ path: "agents",
40260
+ autoFixable: false
40261
+ });
40262
+ return findings;
40263
+ }
40264
+ if (refs.size === 0)
40265
+ return findings;
40266
+ for (const [modelId, paths] of refs.entries()) {
40267
+ if (modelAvailability.availableModelIds.has(modelId))
40268
+ continue;
40269
+ findings.push({
40270
+ id: "configured-model-unavailable",
40271
+ title: "Configured model is unavailable",
40272
+ description: `Configured model ${formatModelIdForDoctor(modelId)} was not found in the active OpenCode provider model registry. ` + "Run `/models` to choose a currently available model, then update opencode-swarm.json.",
40273
+ severity: "error",
40274
+ path: [...paths].sort().join(", "),
40275
+ currentValue: modelId,
40276
+ autoFixable: false
40277
+ });
40278
+ }
40279
+ return findings;
40280
+ }
40281
+ function formatModelIdForDoctor(modelId) {
40282
+ const json3 = JSON.stringify(modelId);
40283
+ if (!json3)
40284
+ return '"<invalid model id>"';
40285
+ if (json3.length <= 160)
40286
+ return json3;
40287
+ return `${json3.slice(0, 157)}..."`;
40288
+ }
40136
40289
  function walkConfigAndValidate(obj, path24, config3, findings) {
40137
40290
  if (obj === null || obj === undefined) {
40138
40291
  return;
@@ -40157,9 +40310,12 @@ function walkConfigAndValidate(obj, path24, config3, findings) {
40157
40310
  walkConfigAndValidate(value, newPath, config3, findings);
40158
40311
  }
40159
40312
  }
40160
- function runConfigDoctor(config3, directory) {
40313
+ function runConfigDoctor(config3, directory, options = {}) {
40161
40314
  const findings = [];
40162
40315
  walkConfigAndValidate(config3, "", config3, findings);
40316
+ if (options.modelAvailability) {
40317
+ findings.push(...validateConfiguredModels(config3, options.modelAvailability));
40318
+ }
40163
40319
  const summary = {
40164
40320
  info: findings.filter((f) => f.severity === "info").length,
40165
40321
  warn: findings.filter((f) => f.severity === "warn").length,
@@ -40321,8 +40477,8 @@ function shouldRunOnStartup(automationConfig) {
40321
40477
  }
40322
40478
  return automationConfig.capabilities?.config_doctor_on_startup === true;
40323
40479
  }
40324
- async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
40325
- const result = runConfigDoctor(config3, directory);
40480
+ async function runConfigDoctorWithFixes(directory, config3, autoFix = false, options = {}) {
40481
+ const result = runConfigDoctor(config3, directory, options);
40326
40482
  const artifactPath = writeDoctorArtifact(directory, result);
40327
40483
  if (!autoFix) {
40328
40484
  return {
@@ -40342,7 +40498,7 @@ async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
40342
40498
  if (appliedFixes.length > 0) {
40343
40499
  const freshConfig = readConfigFromFile(directory);
40344
40500
  if (freshConfig) {
40345
- const newResult = runConfigDoctor(freshConfig.config, directory);
40501
+ const newResult = runConfigDoctor(freshConfig.config, directory, options);
40346
40502
  writeDoctorArtifact(directory, newResult);
40347
40503
  }
40348
40504
  }
@@ -41964,6 +42120,23 @@ var init_tool_doctor = __esm(() => {
41964
42120
  ];
41965
42121
  });
41966
42122
 
42123
+ // src/utils/timeout.ts
42124
+ async function withTimeout(promise3, ms, timeoutError) {
42125
+ let timer;
42126
+ const timeoutPromise = new Promise((_, reject) => {
42127
+ timer = setTimeout(() => reject(timeoutError), ms);
42128
+ if (typeof timer.unref === "function") {
42129
+ timer.unref();
42130
+ }
42131
+ });
42132
+ try {
42133
+ return await Promise.race([promise3, timeoutPromise]);
42134
+ } finally {
42135
+ if (timer !== undefined)
42136
+ clearTimeout(timer);
42137
+ }
42138
+ }
42139
+
41967
42140
  // src/commands/doctor.ts
41968
42141
  function formatToolDoctorMarkdown(result) {
41969
42142
  const lines = [
@@ -42037,13 +42210,67 @@ function formatDoctorMarkdown(result) {
42037
42210
  return lines.join(`
42038
42211
  `);
42039
42212
  }
42040
- async function handleDoctorCommand(directory, args) {
42213
+ function extractAvailableModelIds(response) {
42214
+ const available = new Set;
42215
+ if (response?.providers !== undefined && !Array.isArray(response.providers)) {
42216
+ throw new Error("provider registry returned malformed provider list");
42217
+ }
42218
+ for (const provider of response?.providers ?? []) {
42219
+ if (!provider || typeof provider !== "object" || !provider.id || !provider.models || typeof provider.models !== "object" || Array.isArray(provider.models)) {
42220
+ continue;
42221
+ }
42222
+ for (const [modelKey, modelInfo] of Object.entries(provider.models)) {
42223
+ available.add(`${provider.id}/${modelKey}`);
42224
+ if (modelInfo && typeof modelInfo === "object" && modelInfo.id) {
42225
+ available.add(`${provider.id}/${modelInfo.id}`);
42226
+ }
42227
+ }
42228
+ }
42229
+ return available;
42230
+ }
42231
+ async function loadModelAvailability(directory, client, options = {}) {
42232
+ const providerClient = client;
42233
+ const providers = providerClient?.config?.providers;
42234
+ if (typeof providers !== "function") {
42235
+ return;
42236
+ }
42237
+ try {
42238
+ const response = await withTimeout(providers({ directory }), options.timeoutMs ?? MODEL_REGISTRY_TIMEOUT_MS, new Error(`OpenCode provider model registry lookup exceeded ${options.timeoutMs ?? MODEL_REGISTRY_TIMEOUT_MS}ms`));
42239
+ if (response.error) {
42240
+ return {
42241
+ availableModelIds: new Set,
42242
+ source: MODEL_REGISTRY_SOURCE,
42243
+ error: typeof response.error === "string" ? response.error : JSON.stringify(response.error)
42244
+ };
42245
+ }
42246
+ if (!response.data) {
42247
+ return {
42248
+ availableModelIds: new Set,
42249
+ source: MODEL_REGISTRY_SOURCE,
42250
+ error: "provider registry returned no data"
42251
+ };
42252
+ }
42253
+ return {
42254
+ availableModelIds: extractAvailableModelIds(response.data),
42255
+ source: MODEL_REGISTRY_SOURCE
42256
+ };
42257
+ } catch (error93) {
42258
+ return {
42259
+ availableModelIds: new Set,
42260
+ source: MODEL_REGISTRY_SOURCE,
42261
+ error: error93 instanceof Error ? error93.message : String(error93)
42262
+ };
42263
+ }
42264
+ }
42265
+ async function handleDoctorCommand(directory, args, options = {}) {
42041
42266
  const enableAutoFix = args.includes("--fix") || args.includes("-f");
42042
42267
  const config3 = loadPluginConfig(directory);
42043
- const result = runConfigDoctor(config3, directory);
42268
+ const modelAvailability = await loadModelAvailability(directory, options.client);
42269
+ const doctorOptions = { modelAvailability };
42270
+ const result = runConfigDoctor(config3, directory, doctorOptions);
42044
42271
  if (enableAutoFix && result.hasAutoFixableIssues) {
42045
42272
  const { runConfigDoctorWithFixes: runConfigDoctorWithFixes2 } = await Promise.resolve().then(() => (init_config_doctor(), exports_config_doctor));
42046
- const fixResult = await runConfigDoctorWithFixes2(directory, config3, true);
42273
+ const fixResult = await runConfigDoctorWithFixes2(directory, config3, true, doctorOptions);
42047
42274
  return formatDoctorMarkdown(fixResult.result);
42048
42275
  }
42049
42276
  return formatDoctorMarkdown(result);
@@ -42052,6 +42279,7 @@ async function handleDoctorToolsCommand(directory, _args) {
42052
42279
  const result = runToolDoctor(directory);
42053
42280
  return formatToolDoctorMarkdown(result);
42054
42281
  }
42282
+ var MODEL_REGISTRY_TIMEOUT_MS = 3000, MODEL_REGISTRY_SOURCE = "OpenCode config.providers";
42055
42283
  var init_doctor = __esm(() => {
42056
42284
  init_loader();
42057
42285
  init_config_doctor();
@@ -51681,6 +51909,7 @@ __export(exports_commands, {
51681
51909
  createSwarmCommandHandler: () => createSwarmCommandHandler,
51682
51910
  buildHelpText: () => buildHelpText,
51683
51911
  VALID_COMMANDS: () => VALID_COMMANDS,
51912
+ LLM_MEDIATION_WARNING: () => LLM_MEDIATION_WARNING,
51684
51913
  COMMAND_REGISTRY: () => COMMAND_REGISTRY,
51685
51914
  COMMAND_NAME_SET: () => COMMAND_NAME_SET,
51686
51915
  COMMAND_NAMES: () => COMMAND_NAMES
@@ -51688,7 +51917,7 @@ __export(exports_commands, {
51688
51917
  import fs28 from "fs";
51689
51918
  import path46 from "path";
51690
51919
  function buildHelpText() {
51691
- const lines = ["## Swarm Commands", ""];
51920
+ const lines = ["## Swarm Commands", "", LLM_MEDIATION_WARNING, ""];
51692
51921
  const CATEGORIES = [
51693
51922
  "core",
51694
51923
  "agent",
@@ -51783,7 +52012,7 @@ function buildHelpText() {
51783
52012
  return lines.join(`
51784
52013
  `);
51785
52014
  }
51786
- function createSwarmCommandHandler(directory, agents) {
52015
+ function createSwarmCommandHandler(directory, agents, client) {
51787
52016
  return async (input, output) => {
51788
52017
  if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
51789
52018
  return;
@@ -51830,7 +52059,8 @@ ${similar.map((cmd) => ` \u2022 /swarm ${cmd}`).join(`
51830
52059
  directory,
51831
52060
  args: resolved.remainingArgs,
51832
52061
  sessionID: input.sessionID,
51833
- agents
52062
+ agents,
52063
+ client
51834
52064
  });
51835
52065
  } catch (_err) {
51836
52066
  const cmdName = tokens[0] || "unknown";
@@ -51846,15 +52076,20 @@ ${text}`;
51846
52076
  if (isFirstRun) {
51847
52077
  const welcomeMessage = `Welcome to OpenCode Swarm! \uD83D\uDC1D
51848
52078
  ` + `
51849
- ` + `Run \`/swarm help\` to see all available commands, or \`/swarm config\` to review your configuration.
52079
+ ` + `Start here: run \`/swarm diagnose\`, then \`/swarm agents\` to confirm the plugin loaded and see the exact models in use.
52080
+ ` + `If a model is unavailable, edit \`.opencode/opencode-swarm.json\` or \`~/.config/opencode/opencode-swarm.json\` and run \`/swarm config doctor\`.
52081
+ ` + `Useful next steps: \`/swarm brainstorm <task>\` for guided planning, \`/swarm full-auto on\` for autonomous runs after enabling it in config, and \`/swarm council <question>\` after enabling council.general.
52082
+
51850
52083
  `;
51851
52084
  text = welcomeMessage + text;
51852
52085
  }
51853
- output.parts = [
51854
- { type: "text", text }
51855
- ];
52086
+ output.parts.splice(0, output.parts.length, {
52087
+ type: "text",
52088
+ text
52089
+ });
51856
52090
  };
51857
52091
  }
52092
+ var LLM_MEDIATION_WARNING;
51858
52093
  var init_commands = __esm(() => {
51859
52094
  init_registry();
51860
52095
  init_acknowledge_spec_drift();
@@ -51892,6 +52127,8 @@ var init_commands = __esm(() => {
51892
52127
  init_sync_plan();
51893
52128
  init_turbo();
51894
52129
  init_write_retro2();
52130
+ LLM_MEDIATION_WARNING = "> \u26A0\uFE0F Chat-typed `/swarm` is LLM-mediated in current OpenCode (see anomalyco/opencode#9306).\n" + `> The text below is the canonical handler output, but the model may rephrase it before display.
52131
+ ` + "> For deterministic output, run `bunx opencode-swarm run <subcommand>` from a terminal.";
51895
52132
  });
51896
52133
 
51897
52134
  // src/commands/registry.ts
@@ -52163,13 +52400,13 @@ var init_registry = __esm(() => {
52163
52400
  clashesWithNativeCcCommand: "/config"
52164
52401
  },
52165
52402
  "config doctor": {
52166
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
52403
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
52167
52404
  description: "Run config doctor checks",
52168
52405
  subcommandOf: "config",
52169
52406
  category: "diagnostics"
52170
52407
  },
52171
52408
  "config-doctor": {
52172
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
52409
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
52173
52410
  description: "Run config doctor checks",
52174
52411
  subcommandOf: "config",
52175
52412
  category: "diagnostics",
@@ -52244,7 +52481,7 @@ var init_registry = __esm(() => {
52244
52481
  deprecated: true
52245
52482
  },
52246
52483
  doctor: {
52247
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
52484
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
52248
52485
  description: "Run config doctor checks",
52249
52486
  category: "diagnostics",
52250
52487
  aliasOf: "config doctor",
@@ -14,4 +14,4 @@
14
14
  * Sanitizes the question to prevent prompt injection of rival MODE: headers
15
15
  * or control sequences (mirrors brainstorm.ts).
16
16
  */
17
- export declare function handleCouncilCommand(_directory: string, args: string[]): Promise<string>;
17
+ export declare function handleCouncilCommand(directory: string, args: string[]): Promise<string>;
@@ -1,15 +1,20 @@
1
- import { type ConfigDoctorResult } from '../services/config-doctor';
1
+ import { type ConfigDoctorResult, type ModelAvailability } from '../services/config-doctor';
2
2
  /**
3
3
  * Format tool doctor result as markdown for command output.
4
4
  *
5
5
  * Exported for unit testing of the BLOCKING footer enforcement path.
6
6
  */
7
7
  export declare function formatToolDoctorMarkdown(result: ConfigDoctorResult): string;
8
+ export declare function loadModelAvailability(directory: string, client: unknown, options?: {
9
+ timeoutMs?: number;
10
+ }): Promise<ModelAvailability | undefined>;
8
11
  /**
9
12
  * Handle /swarm config doctor command.
10
13
  * Maps to: config doctor service (runConfigDoctor)
11
14
  */
12
- export declare function handleDoctorCommand(directory: string, args: string[]): Promise<string>;
15
+ export declare function handleDoctorCommand(directory: string, args: string[], options?: {
16
+ client?: unknown;
17
+ }): Promise<string>;
13
18
  /**
14
19
  * Handle /swarm doctor tools command.
15
20
  * Maps to: tool doctor service (runToolDoctor)
@@ -40,12 +40,13 @@ export { handleStatusCommand } from './status';
40
40
  export { handleSyncPlanCommand } from './sync-plan';
41
41
  export { handleTurboCommand } from './turbo';
42
42
  export { handleWriteRetroCommand } from './write-retro';
43
+ export declare const LLM_MEDIATION_WARNING: string;
43
44
  export declare function buildHelpText(): string;
44
45
  /**
45
46
  * Creates a command.execute.before handler for /swarm commands.
46
47
  * Uses factory pattern to close over directory and agents.
47
48
  */
48
- export declare function createSwarmCommandHandler(directory: string, agents: Record<string, AgentDefinition>): (input: {
49
+ export declare function createSwarmCommandHandler(directory: string, agents: Record<string, AgentDefinition>, client?: unknown): (input: {
49
50
  command: string;
50
51
  sessionID: string;
51
52
  arguments: string;
@@ -8,6 +8,7 @@ export type CommandContext = {
8
8
  args: string[];
9
9
  sessionID: string;
10
10
  agents: Record<string, AgentDefinition>;
11
+ client?: unknown;
11
12
  };
12
13
  export type CommandResult = Promise<string>;
13
14
  export type CommandCategory = 'core' | 'agent' | 'config' | 'diagnostics' | 'utility';