opencode-swarm 7.18.0 → 7.18.2
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 +27 -22
- package/dist/cli/index.js +273 -41
- package/dist/commands/council.d.ts +1 -1
- package/dist/commands/doctor.d.ts +7 -2
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/registry.d.ts +1 -0
- package/dist/index.js +410 -73
- 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.2",
|
|
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
|
|
@@ -26355,9 +26430,9 @@ async function getEvidenceTaskId(session, directory) {
|
|
|
26355
26430
|
const primary = session.currentTaskId ?? session.lastCoderDelegationTaskId;
|
|
26356
26431
|
if (primary)
|
|
26357
26432
|
return primary;
|
|
26358
|
-
|
|
26359
|
-
|
|
26360
|
-
|
|
26433
|
+
const onlyTaskId = getOnlyWorkflowTaskId(session);
|
|
26434
|
+
if (onlyTaskId)
|
|
26435
|
+
return onlyTaskId;
|
|
26361
26436
|
try {
|
|
26362
26437
|
if (typeof directory !== "string" || directory.length === 0) {
|
|
26363
26438
|
return null;
|
|
@@ -26707,18 +26782,25 @@ function createDelegationGateHook(config2, directory) {
|
|
|
26707
26782
|
const explicitEvidenceTaskId = extractTaskIdFromTaskArgs(mergedTaskArgs);
|
|
26708
26783
|
const stageBEvidenceTaskId = gateForEvidence === "reviewer" || gateForEvidence === "test_engineer" || gateForEvidence === "adversarial_test_engineer" ? resolveScopedStageBTaskId(session, mergedTaskArgs) : null;
|
|
26709
26784
|
const evidenceTaskId = stageBEvidenceTaskId ?? explicitEvidenceTaskId ?? await getEvidenceTaskId(session, directory);
|
|
26785
|
+
const gateAgents = [
|
|
26786
|
+
"reviewer",
|
|
26787
|
+
"test_engineer",
|
|
26788
|
+
"docs",
|
|
26789
|
+
"designer",
|
|
26790
|
+
"critic",
|
|
26791
|
+
"explorer",
|
|
26792
|
+
"sme"
|
|
26793
|
+
];
|
|
26794
|
+
if (evidenceTaskId === null && gateAgents.includes(targetAgentForEvidence)) {
|
|
26795
|
+
session.pendingAdvisoryMessages ??= [];
|
|
26796
|
+
if (!session.pendingAdvisoryMessages.some((m) => m.includes("evidence-task-id-unresolved"))) {
|
|
26797
|
+
session.pendingAdvisoryMessages.push(`[evidence-task-id-unresolved] Gate evidence has NOT been written for one or more recent gate-agent dispatches because the current task id is unresolved. Call update_task_status(<task_id>, 'in_progress') BEFORE dispatching gate agents (e.g. reviewer/test_engineer). Most recent affected agent: ${targetAgentForEvidence}.`);
|
|
26798
|
+
}
|
|
26799
|
+
console.warn(`[delegation-gate] evidence-task-id-unresolved sessionID=${input.sessionID} subagentType=${targetAgentForEvidence} reason=evidence-task-id-unresolved`);
|
|
26800
|
+
}
|
|
26710
26801
|
if (evidenceTaskId && typeof directory === "string") {
|
|
26711
26802
|
const turbo = hasActiveTurboMode(input.sessionID);
|
|
26712
26803
|
const parallelRuntime = resolveStandardParallelizationConfig(config2, directory);
|
|
26713
|
-
const gateAgents = [
|
|
26714
|
-
"reviewer",
|
|
26715
|
-
"test_engineer",
|
|
26716
|
-
"docs",
|
|
26717
|
-
"designer",
|
|
26718
|
-
"critic",
|
|
26719
|
-
"explorer",
|
|
26720
|
-
"sme"
|
|
26721
|
-
];
|
|
26722
26804
|
if (gateAgents.includes(targetAgentForEvidence)) {
|
|
26723
26805
|
const { recordGateEvidence: recordGateEvidence2 } = await Promise.resolve().then(() => (init_gate_evidence(), exports_gate_evidence));
|
|
26724
26806
|
await recordGateEvidence2(directory, evidenceTaskId, gateForEvidence, input.sessionID, turbo, parallelRuntime.evidenceLockTimeoutMs);
|
|
@@ -26728,7 +26810,7 @@ function createDelegationGateHook(config2, directory) {
|
|
|
26728
26810
|
}
|
|
26729
26811
|
}
|
|
26730
26812
|
} catch (err2) {
|
|
26731
|
-
console.warn(`[delegation-gate] evidence recording failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
26813
|
+
console.warn(`[delegation-gate] evidence recording failed reason=evidence-write-failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
26732
26814
|
}
|
|
26733
26815
|
}
|
|
26734
26816
|
if (storedArgs !== undefined) {
|
|
@@ -46818,12 +46900,31 @@ function parseArgs(args2) {
|
|
|
46818
46900
|
}
|
|
46819
46901
|
return out2;
|
|
46820
46902
|
}
|
|
46821
|
-
async function handleCouncilCommand(
|
|
46903
|
+
async function handleCouncilCommand(directory, args2) {
|
|
46822
46904
|
const parsed = parseArgs(args2);
|
|
46823
46905
|
const question = sanitizeQuestion(parsed.rest.join(" "));
|
|
46824
46906
|
if (!question) {
|
|
46825
46907
|
return USAGE;
|
|
46826
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
|
+
}
|
|
46827
46928
|
const tokens = ["MODE: COUNCIL"];
|
|
46828
46929
|
if (parsed.preset) {
|
|
46829
46930
|
tokens.push(`preset=${parsed.preset}`);
|
|
@@ -46835,6 +46936,7 @@ async function handleCouncilCommand(_directory, args2) {
|
|
|
46835
46936
|
}
|
|
46836
46937
|
var MAX_QUESTION_LEN = 2000, USAGE;
|
|
46837
46938
|
var init_council = __esm(() => {
|
|
46939
|
+
init_loader();
|
|
46838
46940
|
USAGE = [
|
|
46839
46941
|
"Usage: /swarm council <question> [--preset <name>] [--spec-review]",
|
|
46840
46942
|
"",
|
|
@@ -48362,6 +48464,7 @@ __export(exports_config_doctor, {
|
|
|
48362
48464
|
restoreFromBackup: () => restoreFromBackup,
|
|
48363
48465
|
getConfigPaths: () => getConfigPaths,
|
|
48364
48466
|
createConfigBackup: () => createConfigBackup,
|
|
48467
|
+
collectConfiguredModelRefs: () => collectConfiguredModelRefs,
|
|
48365
48468
|
applySafeAutoFixes: () => applySafeAutoFixes
|
|
48366
48469
|
});
|
|
48367
48470
|
import * as crypto3 from "node:crypto";
|
|
@@ -48755,6 +48858,129 @@ function validateConfigKey(path31, value, _config) {
|
|
|
48755
48858
|
}
|
|
48756
48859
|
return findings;
|
|
48757
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
|
+
}
|
|
48758
48984
|
function walkConfigAndValidate(obj, path31, config3, findings) {
|
|
48759
48985
|
if (obj === null || obj === undefined) {
|
|
48760
48986
|
return;
|
|
@@ -48779,9 +49005,12 @@ function walkConfigAndValidate(obj, path31, config3, findings) {
|
|
|
48779
49005
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
48780
49006
|
}
|
|
48781
49007
|
}
|
|
48782
|
-
function runConfigDoctor(config3, directory) {
|
|
49008
|
+
function runConfigDoctor(config3, directory, options = {}) {
|
|
48783
49009
|
const findings = [];
|
|
48784
49010
|
walkConfigAndValidate(config3, "", config3, findings);
|
|
49011
|
+
if (options.modelAvailability) {
|
|
49012
|
+
findings.push(...validateConfiguredModels(config3, options.modelAvailability));
|
|
49013
|
+
}
|
|
48785
49014
|
const summary = {
|
|
48786
49015
|
info: findings.filter((f) => f.severity === "info").length,
|
|
48787
49016
|
warn: findings.filter((f) => f.severity === "warn").length,
|
|
@@ -48943,8 +49172,8 @@ function shouldRunOnStartup(automationConfig) {
|
|
|
48943
49172
|
}
|
|
48944
49173
|
return automationConfig.capabilities?.config_doctor_on_startup === true;
|
|
48945
49174
|
}
|
|
48946
|
-
async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
|
|
48947
|
-
const result = runConfigDoctor(config3, directory);
|
|
49175
|
+
async function runConfigDoctorWithFixes(directory, config3, autoFix = false, options = {}) {
|
|
49176
|
+
const result = runConfigDoctor(config3, directory, options);
|
|
48948
49177
|
const artifactPath = writeDoctorArtifact(directory, result);
|
|
48949
49178
|
if (!autoFix) {
|
|
48950
49179
|
return {
|
|
@@ -48964,7 +49193,7 @@ async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
|
|
|
48964
49193
|
if (appliedFixes.length > 0) {
|
|
48965
49194
|
const freshConfig = readConfigFromFile(directory);
|
|
48966
49195
|
if (freshConfig) {
|
|
48967
|
-
const newResult = runConfigDoctor(freshConfig.config, directory);
|
|
49196
|
+
const newResult = runConfigDoctor(freshConfig.config, directory, options);
|
|
48968
49197
|
writeDoctorArtifact(directory, newResult);
|
|
48969
49198
|
}
|
|
48970
49199
|
}
|
|
@@ -50609,6 +50838,31 @@ var init_tool_doctor = __esm(() => {
|
|
|
50609
50838
|
];
|
|
50610
50839
|
});
|
|
50611
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
|
+
|
|
50612
50866
|
// src/commands/doctor.ts
|
|
50613
50867
|
function formatToolDoctorMarkdown(result) {
|
|
50614
50868
|
const lines = [
|
|
@@ -50682,13 +50936,67 @@ function formatDoctorMarkdown(result) {
|
|
|
50682
50936
|
return lines.join(`
|
|
50683
50937
|
`);
|
|
50684
50938
|
}
|
|
50685
|
-
|
|
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 = {}) {
|
|
50686
50992
|
const enableAutoFix = args2.includes("--fix") || args2.includes("-f");
|
|
50687
50993
|
const config3 = loadPluginConfig(directory);
|
|
50688
|
-
const
|
|
50994
|
+
const modelAvailability = await loadModelAvailability(directory, options.client);
|
|
50995
|
+
const doctorOptions = { modelAvailability };
|
|
50996
|
+
const result = runConfigDoctor(config3, directory, doctorOptions);
|
|
50689
50997
|
if (enableAutoFix && result.hasAutoFixableIssues) {
|
|
50690
50998
|
const { runConfigDoctorWithFixes: runConfigDoctorWithFixes2 } = await Promise.resolve().then(() => (init_config_doctor(), exports_config_doctor));
|
|
50691
|
-
const fixResult = await runConfigDoctorWithFixes2(directory, config3, true);
|
|
50999
|
+
const fixResult = await runConfigDoctorWithFixes2(directory, config3, true, doctorOptions);
|
|
50692
51000
|
return formatDoctorMarkdown(fixResult.result);
|
|
50693
51001
|
}
|
|
50694
51002
|
return formatDoctorMarkdown(result);
|
|
@@ -50697,6 +51005,7 @@ async function handleDoctorToolsCommand(directory, _args) {
|
|
|
50697
51005
|
const result = runToolDoctor(directory);
|
|
50698
51006
|
return formatToolDoctorMarkdown(result);
|
|
50699
51007
|
}
|
|
51008
|
+
var MODEL_REGISTRY_TIMEOUT_MS = 3000, MODEL_REGISTRY_SOURCE = "OpenCode config.providers";
|
|
50700
51009
|
var init_doctor = __esm(() => {
|
|
50701
51010
|
init_loader();
|
|
50702
51011
|
init_config_doctor();
|
|
@@ -60867,7 +61176,7 @@ function buildHelpText() {
|
|
|
60867
61176
|
return lines.join(`
|
|
60868
61177
|
`);
|
|
60869
61178
|
}
|
|
60870
|
-
function createSwarmCommandHandler(directory, agents) {
|
|
61179
|
+
function createSwarmCommandHandler(directory, agents, client) {
|
|
60871
61180
|
return async (input, output) => {
|
|
60872
61181
|
if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
|
|
60873
61182
|
return;
|
|
@@ -60914,7 +61223,8 @@ ${similar.map((cmd) => ` • /swarm ${cmd}`).join(`
|
|
|
60914
61223
|
directory,
|
|
60915
61224
|
args: resolved.remainingArgs,
|
|
60916
61225
|
sessionID: input.sessionID,
|
|
60917
|
-
agents
|
|
61226
|
+
agents,
|
|
61227
|
+
client
|
|
60918
61228
|
});
|
|
60919
61229
|
} catch (_err) {
|
|
60920
61230
|
const cmdName = tokens[0] || "unknown";
|
|
@@ -60930,7 +61240,10 @@ ${text}`;
|
|
|
60930
61240
|
if (isFirstRun) {
|
|
60931
61241
|
const welcomeMessage = `Welcome to OpenCode Swarm! \uD83D\uDC1D
|
|
60932
61242
|
` + `
|
|
60933
|
-
` + `
|
|
61243
|
+
` + `Start here: run \`/swarm diagnose\`, then \`/swarm agents\` to confirm the plugin loaded and see the exact models in use.
|
|
61244
|
+
` + `If a model is unavailable, edit \`.opencode/opencode-swarm.json\` or \`~/.config/opencode/opencode-swarm.json\` and run \`/swarm config doctor\`.
|
|
61245
|
+
` + `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.
|
|
61246
|
+
|
|
60934
61247
|
`;
|
|
60935
61248
|
text = welcomeMessage + text;
|
|
60936
61249
|
}
|
|
@@ -61247,13 +61560,13 @@ var init_registry = __esm(() => {
|
|
|
61247
61560
|
clashesWithNativeCcCommand: "/config"
|
|
61248
61561
|
},
|
|
61249
61562
|
"config doctor": {
|
|
61250
|
-
handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
|
|
61563
|
+
handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
|
|
61251
61564
|
description: "Run config doctor checks",
|
|
61252
61565
|
subcommandOf: "config",
|
|
61253
61566
|
category: "diagnostics"
|
|
61254
61567
|
},
|
|
61255
61568
|
"config-doctor": {
|
|
61256
|
-
handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
|
|
61569
|
+
handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
|
|
61257
61570
|
description: "Run config doctor checks",
|
|
61258
61571
|
subcommandOf: "config",
|
|
61259
61572
|
category: "diagnostics",
|
|
@@ -61328,7 +61641,7 @@ var init_registry = __esm(() => {
|
|
|
61328
61641
|
deprecated: true
|
|
61329
61642
|
},
|
|
61330
61643
|
doctor: {
|
|
61331
|
-
handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
|
|
61644
|
+
handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
|
|
61332
61645
|
description: "Run config doctor checks",
|
|
61333
61646
|
category: "diagnostics",
|
|
61334
61647
|
aliasOf: "config doctor",
|
|
@@ -71616,13 +71929,7 @@ function writeSwarmConfigExampleIfNew(projectDirectory) {
|
|
|
71616
71929
|
fs40.mkdirSync(swarmDir, { recursive: true });
|
|
71617
71930
|
}
|
|
71618
71931
|
const example = {
|
|
71619
|
-
agents:
|
|
71620
|
-
name2,
|
|
71621
|
-
{
|
|
71622
|
-
model,
|
|
71623
|
-
fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
|
|
71624
|
-
}
|
|
71625
|
-
])),
|
|
71932
|
+
agents: DEFAULT_AGENT_CONFIGS,
|
|
71626
71933
|
max_iterations: 5
|
|
71627
71934
|
};
|
|
71628
71935
|
fs40.writeFileSync(dest, `${JSON.stringify(example, null, 2)}
|
|
@@ -74064,31 +74371,6 @@ import * as fsPromises5 from "node:fs/promises";
|
|
|
74064
74371
|
import * as os7 from "node:os";
|
|
74065
74372
|
import * as path66 from "node:path";
|
|
74066
74373
|
|
|
74067
|
-
// src/utils/timeout.ts
|
|
74068
|
-
async function withTimeout(promise3, ms, timeoutError) {
|
|
74069
|
-
let timer;
|
|
74070
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
74071
|
-
timer = setTimeout(() => reject(timeoutError), ms);
|
|
74072
|
-
if (typeof timer.unref === "function") {
|
|
74073
|
-
timer.unref();
|
|
74074
|
-
}
|
|
74075
|
-
});
|
|
74076
|
-
try {
|
|
74077
|
-
return await Promise.race([promise3, timeoutPromise]);
|
|
74078
|
-
} finally {
|
|
74079
|
-
if (timer !== undefined)
|
|
74080
|
-
clearTimeout(timer);
|
|
74081
|
-
}
|
|
74082
|
-
}
|
|
74083
|
-
function yieldToEventLoop() {
|
|
74084
|
-
return new Promise((resolve19) => {
|
|
74085
|
-
const t = setTimeout(resolve19, 0);
|
|
74086
|
-
if (typeof t.unref === "function") {
|
|
74087
|
-
t.unref();
|
|
74088
|
-
}
|
|
74089
|
-
});
|
|
74090
|
-
}
|
|
74091
|
-
|
|
74092
74374
|
// src/tools/symbols.ts
|
|
74093
74375
|
init_zod();
|
|
74094
74376
|
init_create_tool();
|
|
@@ -89503,6 +89785,7 @@ function verifyLeanTurboPhaseReady(directory, phase, sessionIDOrConfig, config3)
|
|
|
89503
89785
|
}
|
|
89504
89786
|
|
|
89505
89787
|
// src/tools/phase-complete.ts
|
|
89788
|
+
init_task_id();
|
|
89506
89789
|
init_create_tool();
|
|
89507
89790
|
init_resolve_working_directory();
|
|
89508
89791
|
function safeWarn(message, error93) {
|
|
@@ -89510,6 +89793,15 @@ function safeWarn(message, error93) {
|
|
|
89510
89793
|
console.warn(message, error93 instanceof Error ? error93.message : String(error93));
|
|
89511
89794
|
} catch {}
|
|
89512
89795
|
}
|
|
89796
|
+
function taskIdToPhase(taskId) {
|
|
89797
|
+
if (typeof taskId !== "string")
|
|
89798
|
+
return null;
|
|
89799
|
+
if (!isStrictTaskId(taskId))
|
|
89800
|
+
return null;
|
|
89801
|
+
const head = taskId.split(".")[0];
|
|
89802
|
+
const n = Number.parseInt(head, 10);
|
|
89803
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
89804
|
+
}
|
|
89513
89805
|
function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSessionId) {
|
|
89514
89806
|
const agents = new Set;
|
|
89515
89807
|
const contributorSessionIds = [];
|
|
@@ -90622,6 +90914,52 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
|
|
|
90622
90914
|
const oldPhase = contributorSession.lastPhaseCompletePhase;
|
|
90623
90915
|
contributorSession.lastPhaseCompletePhase = phase;
|
|
90624
90916
|
telemetry.phaseChanged(contributorSessionId, oldPhase ?? 0, phase);
|
|
90917
|
+
const currentTid = contributorSession.currentTaskId;
|
|
90918
|
+
if (currentTid) {
|
|
90919
|
+
const tp = taskIdToPhase(currentTid);
|
|
90920
|
+
if (tp !== null && tp <= phase) {
|
|
90921
|
+
contributorSession.currentTaskId = null;
|
|
90922
|
+
}
|
|
90923
|
+
}
|
|
90924
|
+
const lastCoderTid = contributorSession.lastCoderDelegationTaskId;
|
|
90925
|
+
if (lastCoderTid) {
|
|
90926
|
+
const tp = taskIdToPhase(lastCoderTid);
|
|
90927
|
+
if (tp !== null && tp <= phase) {
|
|
90928
|
+
contributorSession.lastCoderDelegationTaskId = null;
|
|
90929
|
+
}
|
|
90930
|
+
}
|
|
90931
|
+
const openStates = new Set([
|
|
90932
|
+
"coder_delegated",
|
|
90933
|
+
"pre_check_passed",
|
|
90934
|
+
"reviewer_run"
|
|
90935
|
+
]);
|
|
90936
|
+
if (contributorSession.taskWorkflowStates instanceof Map) {
|
|
90937
|
+
for (const [taskId, state] of Array.from(contributorSession.taskWorkflowStates.entries())) {
|
|
90938
|
+
const tp = taskIdToPhase(taskId);
|
|
90939
|
+
if (tp === null || tp > phase)
|
|
90940
|
+
continue;
|
|
90941
|
+
if (openStates.has(state)) {
|
|
90942
|
+
console.warn(`[phase-complete] dropping open task state at phase boundary: taskId=${taskId} state=${state} phaseCompleted=${phase}`);
|
|
90943
|
+
}
|
|
90944
|
+
contributorSession.taskWorkflowStates.delete(taskId);
|
|
90945
|
+
}
|
|
90946
|
+
}
|
|
90947
|
+
if (contributorSession.stageBCompletion instanceof Map) {
|
|
90948
|
+
for (const taskId of Array.from(contributorSession.stageBCompletion.keys())) {
|
|
90949
|
+
const tp = taskIdToPhase(taskId);
|
|
90950
|
+
if (tp !== null && tp <= phase) {
|
|
90951
|
+
contributorSession.stageBCompletion.delete(taskId);
|
|
90952
|
+
}
|
|
90953
|
+
}
|
|
90954
|
+
}
|
|
90955
|
+
if (contributorSession.requiredStageBGates instanceof Map) {
|
|
90956
|
+
for (const taskId of Array.from(contributorSession.requiredStageBGates.keys())) {
|
|
90957
|
+
const tp = taskIdToPhase(taskId);
|
|
90958
|
+
if (tp !== null && tp <= phase) {
|
|
90959
|
+
contributorSession.requiredStageBGates.delete(taskId);
|
|
90960
|
+
}
|
|
90961
|
+
}
|
|
90962
|
+
}
|
|
90625
90963
|
}
|
|
90626
90964
|
}
|
|
90627
90965
|
try {
|
|
@@ -103330,7 +103668,6 @@ init_write_retro();
|
|
|
103330
103668
|
|
|
103331
103669
|
// src/index.ts
|
|
103332
103670
|
init_utils();
|
|
103333
|
-
|
|
103334
103671
|
// src/utils/tool-output.ts
|
|
103335
103672
|
function truncateToolOutput(output, maxLines, toolName, tailLines = 10) {
|
|
103336
103673
|
if (!output) {
|
|
@@ -103473,7 +103810,7 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
103473
103810
|
const systemEnhancerHook = createSystemEnhancerHook(config3, ctx.directory);
|
|
103474
103811
|
const compactionHook = createCompactionCustomizerHook(config3, ctx.directory);
|
|
103475
103812
|
const contextBudgetHandler = createContextBudgetHandler(config3);
|
|
103476
|
-
const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
|
|
103813
|
+
const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])), ctx.client);
|
|
103477
103814
|
const activityHooks = createAgentActivityHooks(config3, ctx.directory);
|
|
103478
103815
|
const prmHook = createPrmHook(config3.prm ?? PrmConfigSchema.parse({}), ctx.directory);
|
|
103479
103816
|
const trajectoryLoggerHook = createTrajectoryLoggerHook({
|