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/index.js CHANGED
@@ -33,7 +33,7 @@ var package_default;
33
33
  var init_package = __esm(() => {
34
34
  package_default = {
35
35
  name: "opencode-swarm",
36
- version: "7.18.1",
36
+ version: "7.18.3",
37
37
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
38
38
  main: "dist/index.js",
39
39
  types: "dist/index.d.ts",
@@ -253,7 +253,7 @@ function isLowCapabilityModel(modelId) {
253
253
  const lower = (modelId || "").toLowerCase();
254
254
  return LOW_CAPABILITY_MODELS.some((substr) => lower.includes(substr));
255
255
  }
256
- var QA_AGENTS, PIPELINE_AGENTS, ORCHESTRATOR_NAME = "architect", ALL_SUBAGENT_NAMES, ALL_AGENT_NAMES, OPENCODE_NATIVE_AGENTS, CLAUDE_CODE_NATIVE_COMMANDS, AGENT_TOOL_MAP, WRITE_TOOL_NAMES, TOOL_DESCRIPTIONS, DEFAULT_MODELS, DEFAULT_SCORING_CONFIG, LOW_CAPABILITY_MODELS, TURBO_MODE_BANNER = `## \uD83D\uDE80 TURBO MODE ACTIVE
256
+ var QA_AGENTS, PIPELINE_AGENTS, ORCHESTRATOR_NAME = "architect", ALL_SUBAGENT_NAMES, ALL_AGENT_NAMES, OPENCODE_NATIVE_AGENTS, CLAUDE_CODE_NATIVE_COMMANDS, AGENT_TOOL_MAP, WRITE_TOOL_NAMES, TOOL_DESCRIPTIONS, DEFAULT_MODELS, DEFAULT_AGENT_CONFIGS, DEFAULT_SCORING_CONFIG, LOW_CAPABILITY_MODELS, TURBO_MODE_BANNER = `## \uD83D\uDE80 TURBO MODE ACTIVE
257
257
 
258
258
  **Speed optimization enabled for this session.**
259
259
 
@@ -687,8 +687,7 @@ var init_constants = __esm(() => {
687
687
  "skill_improve",
688
688
  "search",
689
689
  "doc_scan",
690
- "doc_extract",
691
- "web_search"
690
+ "doc_extract"
692
691
  ],
693
692
  spec_writer: [
694
693
  "search",
@@ -800,21 +799,87 @@ var init_constants = __esm(() => {
800
799
  explorer: "opencode/big-pickle",
801
800
  coder: "opencode/minimax-m2.5-free",
802
801
  reviewer: "opencode/big-pickle",
803
- test_engineer: "opencode/gpt-5-nano",
802
+ test_engineer: "opencode/big-pickle",
804
803
  sme: "opencode/big-pickle",
805
804
  critic: "opencode/big-pickle",
806
- critic_sounding_board: "opencode/gpt-5-nano",
807
- critic_drift_verifier: "opencode/gpt-5-nano",
808
- critic_hallucination_verifier: "opencode/gpt-5-nano",
809
- critic_oversight: "opencode/gpt-5-nano",
805
+ critic_sounding_board: "opencode/big-pickle",
806
+ critic_drift_verifier: "opencode/big-pickle",
807
+ critic_hallucination_verifier: "opencode/big-pickle",
808
+ critic_oversight: "opencode/big-pickle",
810
809
  docs: "opencode/big-pickle",
811
810
  designer: "opencode/big-pickle",
812
- curator_init: "opencode/gpt-5-nano",
813
- curator_phase: "opencode/gpt-5-nano",
811
+ curator_init: "opencode/big-pickle",
812
+ curator_phase: "opencode/big-pickle",
814
813
  skill_improver: "opencode/big-pickle",
815
814
  spec_writer: "opencode/big-pickle",
816
815
  default: "opencode/big-pickle"
817
816
  };
817
+ DEFAULT_AGENT_CONFIGS = {
818
+ coder: {
819
+ model: "opencode/minimax-m2.5-free",
820
+ fallback_models: ["opencode/big-pickle"]
821
+ },
822
+ reviewer: {
823
+ model: "opencode/big-pickle",
824
+ fallback_models: ["opencode/minimax-m2.5-free"]
825
+ },
826
+ test_engineer: {
827
+ model: "opencode/big-pickle",
828
+ fallback_models: ["opencode/minimax-m2.5-free"]
829
+ },
830
+ explorer: {
831
+ model: "opencode/big-pickle",
832
+ fallback_models: ["opencode/minimax-m2.5-free"]
833
+ },
834
+ sme: {
835
+ model: "opencode/big-pickle",
836
+ fallback_models: ["opencode/minimax-m2.5-free"]
837
+ },
838
+ critic: {
839
+ model: "opencode/big-pickle",
840
+ fallback_models: ["opencode/minimax-m2.5-free"]
841
+ },
842
+ docs: {
843
+ model: "opencode/big-pickle",
844
+ fallback_models: ["opencode/minimax-m2.5-free"]
845
+ },
846
+ designer: {
847
+ model: "opencode/big-pickle",
848
+ fallback_models: ["opencode/minimax-m2.5-free"]
849
+ },
850
+ critic_sounding_board: {
851
+ model: "opencode/big-pickle",
852
+ fallback_models: ["opencode/minimax-m2.5-free"]
853
+ },
854
+ critic_drift_verifier: {
855
+ model: "opencode/big-pickle",
856
+ fallback_models: ["opencode/minimax-m2.5-free"]
857
+ },
858
+ critic_hallucination_verifier: {
859
+ model: "opencode/big-pickle",
860
+ fallback_models: ["opencode/minimax-m2.5-free"]
861
+ },
862
+ critic_oversight: {
863
+ model: "opencode/big-pickle",
864
+ fallback_models: ["opencode/minimax-m2.5-free"]
865
+ },
866
+ curator_init: {
867
+ model: "opencode/big-pickle",
868
+ fallback_models: ["opencode/minimax-m2.5-free"]
869
+ },
870
+ curator_phase: {
871
+ model: "opencode/big-pickle",
872
+ fallback_models: ["opencode/minimax-m2.5-free"]
873
+ },
874
+ skill_improver: {
875
+ model: "opencode/big-pickle",
876
+ fallback_models: ["opencode/minimax-m2.5-free"]
877
+ },
878
+ spec_writer: {
879
+ model: "opencode/big-pickle",
880
+ fallback_models: ["opencode/minimax-m2.5-free"]
881
+ }
882
+ };
818
883
  DEFAULT_SCORING_CONFIG = {
819
884
  enabled: false,
820
885
  max_candidates: 100,
@@ -18532,7 +18597,8 @@ function handleAgentsCommand(agents, guardrails) {
18532
18597
  if (hasUnregistered) {
18533
18598
  lines.push("", "### Unregistered Subagents");
18534
18599
  for (const name2 of unregistered) {
18535
- lines.push(`- **${name2}** (requires configuration)`);
18600
+ const hint = UNREGISTERED_AGENT_HINTS[name2] ?? "requires configuration";
18601
+ lines.push(`- **${name2}** (${hint})`);
18536
18602
  }
18537
18603
  }
18538
18604
  if (guardrails?.profiles && Object.keys(guardrails.profiles).length > 0) {
@@ -18561,9 +18627,18 @@ function handleAgentsCommand(agents, guardrails) {
18561
18627
  return lines.join(`
18562
18628
  `);
18563
18629
  }
18630
+ var UNREGISTERED_AGENT_HINTS;
18564
18631
  var init_agents = __esm(() => {
18565
18632
  init_constants();
18566
18633
  init_schema();
18634
+ UNREGISTERED_AGENT_HINTS = {
18635
+ designer: "enable ui_review.enabled",
18636
+ council_generalist: "enable council.general.enabled",
18637
+ council_skeptic: "enable council.general.enabled",
18638
+ council_domain_expert: "enable council.general.enabled",
18639
+ skill_improver: "registered by default unless agents.skill_improver.disabled is true",
18640
+ spec_writer: "registered by default unless agents.spec_writer.disabled is true"
18641
+ };
18567
18642
  });
18568
18643
 
18569
18644
  // src/commands/analyze.ts
@@ -46825,12 +46900,31 @@ function parseArgs(args2) {
46825
46900
  }
46826
46901
  return out2;
46827
46902
  }
46828
- async function handleCouncilCommand(_directory, args2) {
46903
+ async function handleCouncilCommand(directory, args2) {
46829
46904
  const parsed = parseArgs(args2);
46830
46905
  const question = sanitizeQuestion(parsed.rest.join(" "));
46831
46906
  if (!question) {
46832
46907
  return USAGE;
46833
46908
  }
46909
+ const config3 = loadPluginConfig(directory);
46910
+ if (config3.council?.general?.enabled !== true) {
46911
+ return [
46912
+ "General Council is not enabled for this project.",
46913
+ "",
46914
+ "Enable it in `.opencode/opencode-swarm.json` or `~/.config/opencode/opencode-swarm.json`:",
46915
+ "",
46916
+ "```json",
46917
+ "{",
46918
+ ' "council": {',
46919
+ ' "general": { "enabled": true }',
46920
+ " }",
46921
+ "}",
46922
+ "```",
46923
+ "",
46924
+ "Then restart OpenCode and run `/swarm config doctor` before trying `/swarm council` again."
46925
+ ].join(`
46926
+ `);
46927
+ }
46834
46928
  const tokens = ["MODE: COUNCIL"];
46835
46929
  if (parsed.preset) {
46836
46930
  tokens.push(`preset=${parsed.preset}`);
@@ -46842,6 +46936,7 @@ async function handleCouncilCommand(_directory, args2) {
46842
46936
  }
46843
46937
  var MAX_QUESTION_LEN = 2000, USAGE;
46844
46938
  var init_council = __esm(() => {
46939
+ init_loader();
46845
46940
  USAGE = [
46846
46941
  "Usage: /swarm council <question> [--preset <name>] [--spec-review]",
46847
46942
  "",
@@ -48369,6 +48464,7 @@ __export(exports_config_doctor, {
48369
48464
  restoreFromBackup: () => restoreFromBackup,
48370
48465
  getConfigPaths: () => getConfigPaths,
48371
48466
  createConfigBackup: () => createConfigBackup,
48467
+ collectConfiguredModelRefs: () => collectConfiguredModelRefs,
48372
48468
  applySafeAutoFixes: () => applySafeAutoFixes
48373
48469
  });
48374
48470
  import * as crypto3 from "node:crypto";
@@ -48762,6 +48858,129 @@ function validateConfigKey(path31, value, _config) {
48762
48858
  }
48763
48859
  return findings;
48764
48860
  }
48861
+ function addConfiguredModel(refs, model, configPath) {
48862
+ if (typeof model !== "string")
48863
+ return;
48864
+ const trimmed = model.trim();
48865
+ if (!trimmed)
48866
+ return;
48867
+ const paths = refs.get(trimmed) ?? new Set;
48868
+ paths.add(configPath);
48869
+ refs.set(trimmed, paths);
48870
+ }
48871
+ function addConfiguredAgentModels(refs, agents, prefix) {
48872
+ if (!agents || typeof agents !== "object" || Array.isArray(agents))
48873
+ return;
48874
+ for (const [agentName, value] of Object.entries(agents)) {
48875
+ if (!value || typeof value !== "object" || Array.isArray(value))
48876
+ continue;
48877
+ const agent = value;
48878
+ addConfiguredModel(refs, agent.model, `${prefix}.${agentName}.model`);
48879
+ if (Array.isArray(agent.fallback_models)) {
48880
+ agent.fallback_models.forEach((model, index) => {
48881
+ addConfiguredModel(refs, model, `${prefix}.${agentName}.fallback_models[${index}]`);
48882
+ });
48883
+ }
48884
+ }
48885
+ }
48886
+ function collectConfiguredModelRefs(config3) {
48887
+ const refs = new Map;
48888
+ const rawConfig = config3;
48889
+ addConfiguredAgentModels(refs, rawConfig.agents, "agents");
48890
+ if (rawConfig.swarms && typeof rawConfig.swarms === "object" && !Array.isArray(rawConfig.swarms)) {
48891
+ for (const [swarmId, value] of Object.entries(rawConfig.swarms)) {
48892
+ if (!value || typeof value !== "object" || Array.isArray(value))
48893
+ continue;
48894
+ addConfiguredAgentModels(refs, value.agents, `swarms.${swarmId}.agents`);
48895
+ }
48896
+ }
48897
+ if (rawConfig.full_auto && typeof rawConfig.full_auto === "object" && !Array.isArray(rawConfig.full_auto)) {
48898
+ addConfiguredModel(refs, rawConfig.full_auto.critic_model, "full_auto.critic_model");
48899
+ }
48900
+ if (rawConfig.skill_improver && typeof rawConfig.skill_improver === "object" && !Array.isArray(rawConfig.skill_improver)) {
48901
+ const skillImprover = rawConfig.skill_improver;
48902
+ addConfiguredModel(refs, skillImprover.model, "skill_improver.model");
48903
+ if (Array.isArray(skillImprover.fallback_models)) {
48904
+ skillImprover.fallback_models.forEach((model, index) => {
48905
+ addConfiguredModel(refs, model, `skill_improver.fallback_models[${index}]`);
48906
+ });
48907
+ }
48908
+ }
48909
+ if (rawConfig.spec_writer && typeof rawConfig.spec_writer === "object" && !Array.isArray(rawConfig.spec_writer)) {
48910
+ const specWriter = rawConfig.spec_writer;
48911
+ addConfiguredModel(refs, specWriter.model, "spec_writer.model");
48912
+ if (Array.isArray(specWriter.fallback_models)) {
48913
+ specWriter.fallback_models.forEach((model, index) => {
48914
+ addConfiguredModel(refs, model, `spec_writer.fallback_models[${index}]`);
48915
+ });
48916
+ }
48917
+ }
48918
+ const council = rawConfig.council;
48919
+ const general = council && typeof council === "object" && !Array.isArray(council) ? council.general : undefined;
48920
+ if (general && typeof general === "object" && !Array.isArray(general)) {
48921
+ addConfiguredModel(refs, general.moderatorModel, "council.general.moderatorModel");
48922
+ if (Array.isArray(general.members)) {
48923
+ general.members.forEach((member, index) => {
48924
+ if (!member || typeof member !== "object" || Array.isArray(member)) {
48925
+ return;
48926
+ }
48927
+ addConfiguredModel(refs, member.model, `council.general.members[${index}].model`);
48928
+ });
48929
+ }
48930
+ if (general.presets && typeof general.presets === "object" && !Array.isArray(general.presets)) {
48931
+ for (const [presetName, members] of Object.entries(general.presets)) {
48932
+ if (!Array.isArray(members))
48933
+ continue;
48934
+ members.forEach((member, index) => {
48935
+ if (!member || typeof member !== "object" || Array.isArray(member)) {
48936
+ return;
48937
+ }
48938
+ addConfiguredModel(refs, member.model, `council.general.presets.${presetName}[${index}].model`);
48939
+ });
48940
+ }
48941
+ }
48942
+ }
48943
+ return refs;
48944
+ }
48945
+ function validateConfiguredModels(config3, modelAvailability) {
48946
+ const refs = collectConfiguredModelRefs(config3);
48947
+ const findings = [];
48948
+ if (modelAvailability.error) {
48949
+ findings.push({
48950
+ id: "model-availability-unchecked",
48951
+ title: "Model availability check skipped",
48952
+ description: `Could not load OpenCode provider models from ${modelAvailability.source}: ` + modelAvailability.error,
48953
+ severity: "info",
48954
+ path: "agents",
48955
+ autoFixable: false
48956
+ });
48957
+ return findings;
48958
+ }
48959
+ if (refs.size === 0)
48960
+ return findings;
48961
+ for (const [modelId, paths] of refs.entries()) {
48962
+ if (modelAvailability.availableModelIds.has(modelId))
48963
+ continue;
48964
+ findings.push({
48965
+ id: "configured-model-unavailable",
48966
+ title: "Configured model is unavailable",
48967
+ 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.",
48968
+ severity: "error",
48969
+ path: [...paths].sort().join(", "),
48970
+ currentValue: modelId,
48971
+ autoFixable: false
48972
+ });
48973
+ }
48974
+ return findings;
48975
+ }
48976
+ function formatModelIdForDoctor(modelId) {
48977
+ const json3 = JSON.stringify(modelId);
48978
+ if (!json3)
48979
+ return '"<invalid model id>"';
48980
+ if (json3.length <= 160)
48981
+ return json3;
48982
+ return `${json3.slice(0, 157)}..."`;
48983
+ }
48765
48984
  function walkConfigAndValidate(obj, path31, config3, findings) {
48766
48985
  if (obj === null || obj === undefined) {
48767
48986
  return;
@@ -48786,9 +49005,12 @@ function walkConfigAndValidate(obj, path31, config3, findings) {
48786
49005
  walkConfigAndValidate(value, newPath, config3, findings);
48787
49006
  }
48788
49007
  }
48789
- function runConfigDoctor(config3, directory) {
49008
+ function runConfigDoctor(config3, directory, options = {}) {
48790
49009
  const findings = [];
48791
49010
  walkConfigAndValidate(config3, "", config3, findings);
49011
+ if (options.modelAvailability) {
49012
+ findings.push(...validateConfiguredModels(config3, options.modelAvailability));
49013
+ }
48792
49014
  const summary = {
48793
49015
  info: findings.filter((f) => f.severity === "info").length,
48794
49016
  warn: findings.filter((f) => f.severity === "warn").length,
@@ -48950,8 +49172,8 @@ function shouldRunOnStartup(automationConfig) {
48950
49172
  }
48951
49173
  return automationConfig.capabilities?.config_doctor_on_startup === true;
48952
49174
  }
48953
- async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
48954
- const result = runConfigDoctor(config3, directory);
49175
+ async function runConfigDoctorWithFixes(directory, config3, autoFix = false, options = {}) {
49176
+ const result = runConfigDoctor(config3, directory, options);
48955
49177
  const artifactPath = writeDoctorArtifact(directory, result);
48956
49178
  if (!autoFix) {
48957
49179
  return {
@@ -48971,7 +49193,7 @@ async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
48971
49193
  if (appliedFixes.length > 0) {
48972
49194
  const freshConfig = readConfigFromFile(directory);
48973
49195
  if (freshConfig) {
48974
- const newResult = runConfigDoctor(freshConfig.config, directory);
49196
+ const newResult = runConfigDoctor(freshConfig.config, directory, options);
48975
49197
  writeDoctorArtifact(directory, newResult);
48976
49198
  }
48977
49199
  }
@@ -50616,6 +50838,31 @@ var init_tool_doctor = __esm(() => {
50616
50838
  ];
50617
50839
  });
50618
50840
 
50841
+ // src/utils/timeout.ts
50842
+ async function withTimeout(promise3, ms, timeoutError) {
50843
+ let timer;
50844
+ const timeoutPromise = new Promise((_, reject) => {
50845
+ timer = setTimeout(() => reject(timeoutError), ms);
50846
+ if (typeof timer.unref === "function") {
50847
+ timer.unref();
50848
+ }
50849
+ });
50850
+ try {
50851
+ return await Promise.race([promise3, timeoutPromise]);
50852
+ } finally {
50853
+ if (timer !== undefined)
50854
+ clearTimeout(timer);
50855
+ }
50856
+ }
50857
+ function yieldToEventLoop() {
50858
+ return new Promise((resolve11) => {
50859
+ const t = setTimeout(resolve11, 0);
50860
+ if (typeof t.unref === "function") {
50861
+ t.unref();
50862
+ }
50863
+ });
50864
+ }
50865
+
50619
50866
  // src/commands/doctor.ts
50620
50867
  function formatToolDoctorMarkdown(result) {
50621
50868
  const lines = [
@@ -50689,13 +50936,67 @@ function formatDoctorMarkdown(result) {
50689
50936
  return lines.join(`
50690
50937
  `);
50691
50938
  }
50692
- async function handleDoctorCommand(directory, args2) {
50939
+ function extractAvailableModelIds(response) {
50940
+ const available = new Set;
50941
+ if (response?.providers !== undefined && !Array.isArray(response.providers)) {
50942
+ throw new Error("provider registry returned malformed provider list");
50943
+ }
50944
+ for (const provider of response?.providers ?? []) {
50945
+ if (!provider || typeof provider !== "object" || !provider.id || !provider.models || typeof provider.models !== "object" || Array.isArray(provider.models)) {
50946
+ continue;
50947
+ }
50948
+ for (const [modelKey, modelInfo] of Object.entries(provider.models)) {
50949
+ available.add(`${provider.id}/${modelKey}`);
50950
+ if (modelInfo && typeof modelInfo === "object" && modelInfo.id) {
50951
+ available.add(`${provider.id}/${modelInfo.id}`);
50952
+ }
50953
+ }
50954
+ }
50955
+ return available;
50956
+ }
50957
+ async function loadModelAvailability(directory, client, options = {}) {
50958
+ const providerClient = client;
50959
+ const providers = providerClient?.config?.providers;
50960
+ if (typeof providers !== "function") {
50961
+ return;
50962
+ }
50963
+ try {
50964
+ 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`));
50965
+ if (response.error) {
50966
+ return {
50967
+ availableModelIds: new Set,
50968
+ source: MODEL_REGISTRY_SOURCE,
50969
+ error: typeof response.error === "string" ? response.error : JSON.stringify(response.error)
50970
+ };
50971
+ }
50972
+ if (!response.data) {
50973
+ return {
50974
+ availableModelIds: new Set,
50975
+ source: MODEL_REGISTRY_SOURCE,
50976
+ error: "provider registry returned no data"
50977
+ };
50978
+ }
50979
+ return {
50980
+ availableModelIds: extractAvailableModelIds(response.data),
50981
+ source: MODEL_REGISTRY_SOURCE
50982
+ };
50983
+ } catch (error93) {
50984
+ return {
50985
+ availableModelIds: new Set,
50986
+ source: MODEL_REGISTRY_SOURCE,
50987
+ error: error93 instanceof Error ? error93.message : String(error93)
50988
+ };
50989
+ }
50990
+ }
50991
+ async function handleDoctorCommand(directory, args2, options = {}) {
50693
50992
  const enableAutoFix = args2.includes("--fix") || args2.includes("-f");
50694
50993
  const config3 = loadPluginConfig(directory);
50695
- const result = runConfigDoctor(config3, directory);
50994
+ const modelAvailability = await loadModelAvailability(directory, options.client);
50995
+ const doctorOptions = { modelAvailability };
50996
+ const result = runConfigDoctor(config3, directory, doctorOptions);
50696
50997
  if (enableAutoFix && result.hasAutoFixableIssues) {
50697
50998
  const { runConfigDoctorWithFixes: runConfigDoctorWithFixes2 } = await Promise.resolve().then(() => (init_config_doctor(), exports_config_doctor));
50698
- const fixResult = await runConfigDoctorWithFixes2(directory, config3, true);
50999
+ const fixResult = await runConfigDoctorWithFixes2(directory, config3, true, doctorOptions);
50699
51000
  return formatDoctorMarkdown(fixResult.result);
50700
51001
  }
50701
51002
  return formatDoctorMarkdown(result);
@@ -50704,6 +51005,7 @@ async function handleDoctorToolsCommand(directory, _args) {
50704
51005
  const result = runToolDoctor(directory);
50705
51006
  return formatToolDoctorMarkdown(result);
50706
51007
  }
51008
+ var MODEL_REGISTRY_TIMEOUT_MS = 3000, MODEL_REGISTRY_SOURCE = "OpenCode config.providers";
50707
51009
  var init_doctor = __esm(() => {
50708
51010
  init_loader();
50709
51011
  init_config_doctor();
@@ -60772,6 +61074,7 @@ __export(exports_commands, {
60772
61074
  createSwarmCommandHandler: () => createSwarmCommandHandler,
60773
61075
  buildHelpText: () => buildHelpText,
60774
61076
  VALID_COMMANDS: () => VALID_COMMANDS,
61077
+ LLM_MEDIATION_WARNING: () => LLM_MEDIATION_WARNING,
60775
61078
  COMMAND_REGISTRY: () => COMMAND_REGISTRY,
60776
61079
  COMMAND_NAME_SET: () => COMMAND_NAME_SET,
60777
61080
  COMMAND_NAMES: () => COMMAND_NAMES
@@ -60779,7 +61082,7 @@ __export(exports_commands, {
60779
61082
  import fs37 from "node:fs";
60780
61083
  import path55 from "node:path";
60781
61084
  function buildHelpText() {
60782
- const lines = ["## Swarm Commands", ""];
61085
+ const lines = ["## Swarm Commands", "", LLM_MEDIATION_WARNING, ""];
60783
61086
  const CATEGORIES = [
60784
61087
  "core",
60785
61088
  "agent",
@@ -60874,7 +61177,7 @@ function buildHelpText() {
60874
61177
  return lines.join(`
60875
61178
  `);
60876
61179
  }
60877
- function createSwarmCommandHandler(directory, agents) {
61180
+ function createSwarmCommandHandler(directory, agents, client) {
60878
61181
  return async (input, output) => {
60879
61182
  if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
60880
61183
  return;
@@ -60921,7 +61224,8 @@ ${similar.map((cmd) => ` • /swarm ${cmd}`).join(`
60921
61224
  directory,
60922
61225
  args: resolved.remainingArgs,
60923
61226
  sessionID: input.sessionID,
60924
- agents
61227
+ agents,
61228
+ client
60925
61229
  });
60926
61230
  } catch (_err) {
60927
61231
  const cmdName = tokens[0] || "unknown";
@@ -60937,15 +61241,20 @@ ${text}`;
60937
61241
  if (isFirstRun) {
60938
61242
  const welcomeMessage = `Welcome to OpenCode Swarm! \uD83D\uDC1D
60939
61243
  ` + `
60940
- ` + `Run \`/swarm help\` to see all available commands, or \`/swarm config\` to review your configuration.
61244
+ ` + `Start here: run \`/swarm diagnose\`, then \`/swarm agents\` to confirm the plugin loaded and see the exact models in use.
61245
+ ` + `If a model is unavailable, edit \`.opencode/opencode-swarm.json\` or \`~/.config/opencode/opencode-swarm.json\` and run \`/swarm config doctor\`.
61246
+ ` + `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.
61247
+
60941
61248
  `;
60942
61249
  text = welcomeMessage + text;
60943
61250
  }
60944
- output.parts = [
60945
- { type: "text", text }
60946
- ];
61251
+ output.parts.splice(0, output.parts.length, {
61252
+ type: "text",
61253
+ text
61254
+ });
60947
61255
  };
60948
61256
  }
61257
+ var LLM_MEDIATION_WARNING;
60949
61258
  var init_commands = __esm(() => {
60950
61259
  init_registry();
60951
61260
  init_acknowledge_spec_drift();
@@ -60983,6 +61292,8 @@ var init_commands = __esm(() => {
60983
61292
  init_sync_plan();
60984
61293
  init_turbo();
60985
61294
  init_write_retro2();
61295
+ LLM_MEDIATION_WARNING = "> ⚠️ 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.
61296
+ ` + "> For deterministic output, run `bunx opencode-swarm run <subcommand>` from a terminal.";
60986
61297
  });
60987
61298
 
60988
61299
  // src/commands/registry.ts
@@ -61254,13 +61565,13 @@ var init_registry = __esm(() => {
61254
61565
  clashesWithNativeCcCommand: "/config"
61255
61566
  },
61256
61567
  "config doctor": {
61257
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
61568
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
61258
61569
  description: "Run config doctor checks",
61259
61570
  subcommandOf: "config",
61260
61571
  category: "diagnostics"
61261
61572
  },
61262
61573
  "config-doctor": {
61263
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
61574
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
61264
61575
  description: "Run config doctor checks",
61265
61576
  subcommandOf: "config",
61266
61577
  category: "diagnostics",
@@ -61335,7 +61646,7 @@ var init_registry = __esm(() => {
61335
61646
  deprecated: true
61336
61647
  },
61337
61648
  doctor: {
61338
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
61649
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
61339
61650
  description: "Run config doctor checks",
61340
61651
  category: "diagnostics",
61341
61652
  aliasOf: "config doctor",
@@ -71623,13 +71934,7 @@ function writeSwarmConfigExampleIfNew(projectDirectory) {
71623
71934
  fs40.mkdirSync(swarmDir, { recursive: true });
71624
71935
  }
71625
71936
  const example = {
71626
- agents: Object.fromEntries(Object.entries(DEFAULT_MODELS).filter(([name2]) => name2 !== "default").map(([name2, model]) => [
71627
- name2,
71628
- {
71629
- model,
71630
- fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
71631
- }
71632
- ])),
71937
+ agents: DEFAULT_AGENT_CONFIGS,
71633
71938
  max_iterations: 5
71634
71939
  };
71635
71940
  fs40.writeFileSync(dest, `${JSON.stringify(example, null, 2)}
@@ -74071,31 +74376,6 @@ import * as fsPromises5 from "node:fs/promises";
74071
74376
  import * as os7 from "node:os";
74072
74377
  import * as path66 from "node:path";
74073
74378
 
74074
- // src/utils/timeout.ts
74075
- async function withTimeout(promise3, ms, timeoutError) {
74076
- let timer;
74077
- const timeoutPromise = new Promise((_, reject) => {
74078
- timer = setTimeout(() => reject(timeoutError), ms);
74079
- if (typeof timer.unref === "function") {
74080
- timer.unref();
74081
- }
74082
- });
74083
- try {
74084
- return await Promise.race([promise3, timeoutPromise]);
74085
- } finally {
74086
- if (timer !== undefined)
74087
- clearTimeout(timer);
74088
- }
74089
- }
74090
- function yieldToEventLoop() {
74091
- return new Promise((resolve19) => {
74092
- const t = setTimeout(resolve19, 0);
74093
- if (typeof t.unref === "function") {
74094
- t.unref();
74095
- }
74096
- });
74097
- }
74098
-
74099
74379
  // src/tools/symbols.ts
74100
74380
  init_zod();
74101
74381
  init_create_tool();
@@ -103393,7 +103673,6 @@ init_write_retro();
103393
103673
 
103394
103674
  // src/index.ts
103395
103675
  init_utils();
103396
-
103397
103676
  // src/utils/tool-output.ts
103398
103677
  function truncateToolOutput(output, maxLines, toolName, tailLines = 10) {
103399
103678
  if (!output) {
@@ -103536,7 +103815,7 @@ async function initializeOpenCodeSwarm(ctx) {
103536
103815
  const systemEnhancerHook = createSystemEnhancerHook(config3, ctx.directory);
103537
103816
  const compactionHook = createCompactionCustomizerHook(config3, ctx.directory);
103538
103817
  const contextBudgetHandler = createContextBudgetHandler(config3);
103539
- const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
103818
+ const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])), ctx.client);
103540
103819
  const activityHooks = createAgentActivityHooks(config3, ctx.directory);
103541
103820
  const prmHook = createPrmHook(config3.prm ?? PrmConfigSchema.parse({}), ctx.directory);
103542
103821
  const trajectoryLoggerHook = createTrajectoryLoggerHook({
@@ -56,6 +56,18 @@ export interface ConfigDoctorResult {
56
56
  /** The config that was analyzed */
57
57
  configSource: string;
58
58
  }
59
+ /** Model availability snapshot from the active OpenCode provider registry. */
60
+ export interface ModelAvailability {
61
+ /** Fully-qualified model IDs in provider/model form. */
62
+ availableModelIds: ReadonlySet<string>;
63
+ /** Human-readable source for diagnostics. */
64
+ source: string;
65
+ /** Optional failure message when the registry could not be loaded. */
66
+ error?: string;
67
+ }
68
+ export interface ConfigDoctorOptions {
69
+ modelAvailability?: ModelAvailability;
70
+ }
59
71
  /** Backup artifact for rollback */
60
72
  export interface ConfigBackup {
61
73
  /** When the backup was created */
@@ -90,10 +102,11 @@ export declare function writeBackupArtifact(directory: string, backup: ConfigBac
90
102
  * @returns the path to the restored config file, or null if restore failed
91
103
  */
92
104
  export declare function restoreFromBackup(backupPath: string, directory: string): string | null;
105
+ export declare function collectConfiguredModelRefs(config: PluginConfig): Map<string, Set<string>>;
93
106
  /**
94
107
  * Run the config doctor on a loaded config
95
108
  */
96
- export declare function runConfigDoctor(config: PluginConfig, directory: string): ConfigDoctorResult;
109
+ export declare function runConfigDoctor(config: PluginConfig, directory: string, options?: ConfigDoctorOptions): ConfigDoctorResult;
97
110
  /**
98
111
  * Apply safe auto-fixes to config
99
112
  * Only applies low-risk, non-destructive fixes
@@ -116,7 +129,7 @@ export declare function shouldRunOnStartup(automationConfig: {
116
129
  /**
117
130
  * Full config doctor run with backup and fix application
118
131
  */
119
- export declare function runConfigDoctorWithFixes(directory: string, config: PluginConfig, autoFix?: boolean): Promise<{
132
+ export declare function runConfigDoctorWithFixes(directory: string, config: PluginConfig, autoFix?: boolean, options?: ConfigDoctorOptions): Promise<{
120
133
  result: ConfigDoctorResult;
121
134
  backupPath: string | null;
122
135
  appliedFixes: ConfigFix[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.18.1",
3
+ "version": "7.18.3",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",