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/README.md +35 -22
- package/dist/cli/index.js +282 -45
- package/dist/commands/council.d.ts +1 -1
- package/dist/commands/doctor.d.ts +7 -2
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/registry.d.ts +1 -0
- package/dist/index.js +343 -64
- package/dist/services/config-doctor.d.ts +15 -2
- package/package.json +1 -1
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.
|
|
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/
|
|
802
|
+
test_engineer: "opencode/big-pickle",
|
|
804
803
|
sme: "opencode/big-pickle",
|
|
805
804
|
critic: "opencode/big-pickle",
|
|
806
|
-
critic_sounding_board: "opencode/
|
|
807
|
-
critic_drift_verifier: "opencode/
|
|
808
|
-
critic_hallucination_verifier: "opencode/
|
|
809
|
-
critic_oversight: "opencode/
|
|
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/
|
|
813
|
-
curator_phase: "opencode/
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
` + `
|
|
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
|
-
|
|
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:
|
|
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.
|
|
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",
|