opencode-swarm 6.86.10 → 6.86.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +49 -22
- package/dist/commands/knowledge.d.ts +2 -0
- package/dist/index.js +88 -33
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -18580,7 +18580,7 @@ import * as path33 from "path";
|
|
|
18580
18580
|
// package.json
|
|
18581
18581
|
var package_default = {
|
|
18582
18582
|
name: "opencode-swarm",
|
|
18583
|
-
version: "6.86.
|
|
18583
|
+
version: "6.86.12",
|
|
18584
18584
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
18585
18585
|
main: "dist/index.js",
|
|
18586
18586
|
types: "dist/index.d.ts",
|
|
@@ -19091,13 +19091,6 @@ var AgentOverrideConfigSchema = exports_external.object({
|
|
|
19091
19091
|
temperature: exports_external.number().min(0).max(2).optional(),
|
|
19092
19092
|
disabled: exports_external.boolean().optional(),
|
|
19093
19093
|
fallback_models: exports_external.array(exports_external.string()).max(3).optional()
|
|
19094
|
-
}).refine((data) => {
|
|
19095
|
-
if (data.model && !data.fallback_models) {
|
|
19096
|
-
console.warn(`[opencode-swarm] WARNING: Agent configured with custom model "${data.model}" but no fallback_models. This means if the custom model fails, there is no fallback protection. Consider adding fallback_models for reliability.`);
|
|
19097
|
-
}
|
|
19098
|
-
return true;
|
|
19099
|
-
}, {
|
|
19100
|
-
message: "Agent configuration warning: Custom model without fallback protection"
|
|
19101
19094
|
});
|
|
19102
19095
|
var SwarmConfigSchema = exports_external.object({
|
|
19103
19096
|
name: exports_external.string().optional(),
|
|
@@ -39487,6 +39480,9 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
39487
39480
|
const historyData = await getHistoryData(directory);
|
|
39488
39481
|
return formatHistoryMarkdown(historyData);
|
|
39489
39482
|
}
|
|
39483
|
+
// src/commands/knowledge.ts
|
|
39484
|
+
import { join as join21 } from "path";
|
|
39485
|
+
|
|
39490
39486
|
// src/hooks/knowledge-migrator.ts
|
|
39491
39487
|
init_logger();
|
|
39492
39488
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -39717,34 +39713,65 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
39717
39713
|
}
|
|
39718
39714
|
|
|
39719
39715
|
// src/commands/knowledge.ts
|
|
39716
|
+
function resolveEntryByPrefix(entries, inputId) {
|
|
39717
|
+
const exact = entries.find((e) => e.id === inputId);
|
|
39718
|
+
if (exact)
|
|
39719
|
+
return { entry: exact };
|
|
39720
|
+
const matches = entries.filter((e) => e.id.startsWith(inputId));
|
|
39721
|
+
if (matches.length === 0) {
|
|
39722
|
+
return { error: `No entry found matching '${inputId}'.` };
|
|
39723
|
+
}
|
|
39724
|
+
if (matches.length === 1) {
|
|
39725
|
+
return { entry: matches[0] };
|
|
39726
|
+
}
|
|
39727
|
+
const candidates = matches.map((e) => e.id).join(`
|
|
39728
|
+
`);
|
|
39729
|
+
return {
|
|
39730
|
+
error: `Ambiguous prefix '${inputId}' matches ${matches.length} entries:
|
|
39731
|
+
${candidates}`
|
|
39732
|
+
};
|
|
39733
|
+
}
|
|
39720
39734
|
async function handleKnowledgeQuarantineCommand(directory, args) {
|
|
39721
|
-
const
|
|
39722
|
-
if (!
|
|
39735
|
+
const inputId = args[0];
|
|
39736
|
+
if (!inputId) {
|
|
39723
39737
|
return "Usage: /swarm knowledge quarantine <id> [reason]";
|
|
39724
39738
|
}
|
|
39725
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
39739
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
39726
39740
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
39727
39741
|
}
|
|
39728
39742
|
const reason = args.slice(1).join(" ") || "Quarantined via /swarm knowledge quarantine command";
|
|
39729
39743
|
try {
|
|
39730
|
-
await
|
|
39731
|
-
|
|
39744
|
+
const entries = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
39745
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
39746
|
+
if ("error" in resolved) {
|
|
39747
|
+
return `\u274C ${resolved.error}`;
|
|
39748
|
+
}
|
|
39749
|
+
const fullId = resolved.entry.id;
|
|
39750
|
+
await quarantineEntry(directory, fullId, reason, "user");
|
|
39751
|
+
return `\u2705 Entry ${fullId} quarantined successfully.`;
|
|
39732
39752
|
} catch (error93) {
|
|
39733
39753
|
console.warn("[knowledge-command] quarantineEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
39734
39754
|
return `\u274C Failed to quarantine entry. Check the entry ID and try again.`;
|
|
39735
39755
|
}
|
|
39736
39756
|
}
|
|
39737
39757
|
async function handleKnowledgeRestoreCommand(directory, args) {
|
|
39738
|
-
const
|
|
39739
|
-
if (!
|
|
39758
|
+
const inputId = args[0];
|
|
39759
|
+
if (!inputId) {
|
|
39740
39760
|
return "Usage: /swarm knowledge restore <id>";
|
|
39741
39761
|
}
|
|
39742
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
39762
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
39743
39763
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
39744
39764
|
}
|
|
39745
39765
|
try {
|
|
39746
|
-
|
|
39747
|
-
|
|
39766
|
+
const quarantinePath = join21(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
39767
|
+
const entries = await readKnowledge(quarantinePath);
|
|
39768
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
39769
|
+
if ("error" in resolved) {
|
|
39770
|
+
return `\u274C ${resolved.error}`;
|
|
39771
|
+
}
|
|
39772
|
+
const fullId = resolved.entry.id;
|
|
39773
|
+
await restoreEntry(directory, fullId);
|
|
39774
|
+
return `\u2705 Entry ${fullId} restored successfully.`;
|
|
39748
39775
|
} catch (error93) {
|
|
39749
39776
|
console.warn("[knowledge-command] restoreEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
39750
39777
|
return `\u274C Failed to restore entry. Check the entry ID and try again.`;
|
|
@@ -39782,16 +39809,16 @@ async function handleKnowledgeListCommand(directory, _args) {
|
|
|
39782
39809
|
const lines = [
|
|
39783
39810
|
`## Knowledge Entries (${entries.length} total)`,
|
|
39784
39811
|
"",
|
|
39785
|
-
"| ID | Category | Confidence | Lesson (truncated) |",
|
|
39786
|
-
"
|
|
39812
|
+
"| ID (prefix) | Category | Confidence | Lesson (truncated) |",
|
|
39813
|
+
"|--------------|----------|------------|---------------------|"
|
|
39787
39814
|
];
|
|
39788
39815
|
for (const entry of entries) {
|
|
39789
39816
|
const truncatedLesson = entry.lesson.length > 60 ? `${entry.lesson.slice(0, 57)}...` : entry.lesson;
|
|
39790
39817
|
const confidencePct = Math.round(entry.confidence * 100);
|
|
39791
|
-
lines.push(`| ${entry.id.slice(0,
|
|
39818
|
+
lines.push(`| ${entry.id.slice(0, 12)}\u2026 | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`);
|
|
39792
39819
|
}
|
|
39793
39820
|
lines.push("");
|
|
39794
|
-
lines.push("Use `/swarm knowledge quarantine <id>` to hide an entry.");
|
|
39821
|
+
lines.push("Use `/swarm knowledge quarantine <id-prefix>` to hide an entry. Prefix matching is supported \u2014 the 12-character prefix shown is unique in most stores.");
|
|
39795
39822
|
return lines.join(`
|
|
39796
39823
|
`);
|
|
39797
39824
|
} catch (error93) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Handles /swarm knowledge quarantine <id> [reason] command.
|
|
3
3
|
* Moves a knowledge entry to quarantine with optional reason.
|
|
4
|
+
* Accepts a full ID or a unique prefix.
|
|
4
5
|
*/
|
|
5
6
|
export declare function handleKnowledgeQuarantineCommand(directory: string, args: string[]): Promise<string>;
|
|
6
7
|
/**
|
|
7
8
|
* Handles /swarm knowledge restore <id> command.
|
|
8
9
|
* Restores a quarantined knowledge entry.
|
|
10
|
+
* Accepts a full ID or a unique prefix.
|
|
9
11
|
*/
|
|
10
12
|
export declare function handleKnowledgeRestoreCommand(directory: string, args: string[]): Promise<string>;
|
|
11
13
|
/**
|
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: "6.86.
|
|
36
|
+
version: "6.86.12",
|
|
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",
|
|
@@ -14798,13 +14798,6 @@ var init_schema = __esm(() => {
|
|
|
14798
14798
|
temperature: exports_external.number().min(0).max(2).optional(),
|
|
14799
14799
|
disabled: exports_external.boolean().optional(),
|
|
14800
14800
|
fallback_models: exports_external.array(exports_external.string()).max(3).optional()
|
|
14801
|
-
}).refine((data) => {
|
|
14802
|
-
if (data.model && !data.fallback_models) {
|
|
14803
|
-
console.warn(`[opencode-swarm] WARNING: Agent configured with custom model "${data.model}" but no fallback_models. This means if the custom model fails, there is no fallback protection. Consider adding fallback_models for reliability.`);
|
|
14804
|
-
}
|
|
14805
|
-
return true;
|
|
14806
|
-
}, {
|
|
14807
|
-
message: "Agent configuration warning: Custom model without fallback protection"
|
|
14808
14801
|
});
|
|
14809
14802
|
SwarmConfigSchema = exports_external.object({
|
|
14810
14803
|
name: exports_external.string().optional(),
|
|
@@ -48403,34 +48396,66 @@ var init_knowledge_migrator = __esm(() => {
|
|
|
48403
48396
|
});
|
|
48404
48397
|
|
|
48405
48398
|
// src/commands/knowledge.ts
|
|
48399
|
+
import { join as join28 } from "node:path";
|
|
48400
|
+
function resolveEntryByPrefix(entries, inputId) {
|
|
48401
|
+
const exact = entries.find((e) => e.id === inputId);
|
|
48402
|
+
if (exact)
|
|
48403
|
+
return { entry: exact };
|
|
48404
|
+
const matches = entries.filter((e) => e.id.startsWith(inputId));
|
|
48405
|
+
if (matches.length === 0) {
|
|
48406
|
+
return { error: `No entry found matching '${inputId}'.` };
|
|
48407
|
+
}
|
|
48408
|
+
if (matches.length === 1) {
|
|
48409
|
+
return { entry: matches[0] };
|
|
48410
|
+
}
|
|
48411
|
+
const candidates = matches.map((e) => e.id).join(`
|
|
48412
|
+
`);
|
|
48413
|
+
return {
|
|
48414
|
+
error: `Ambiguous prefix '${inputId}' matches ${matches.length} entries:
|
|
48415
|
+
${candidates}`
|
|
48416
|
+
};
|
|
48417
|
+
}
|
|
48406
48418
|
async function handleKnowledgeQuarantineCommand(directory, args2) {
|
|
48407
|
-
const
|
|
48408
|
-
if (!
|
|
48419
|
+
const inputId = args2[0];
|
|
48420
|
+
if (!inputId) {
|
|
48409
48421
|
return "Usage: /swarm knowledge quarantine <id> [reason]";
|
|
48410
48422
|
}
|
|
48411
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
48423
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
48412
48424
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
48413
48425
|
}
|
|
48414
48426
|
const reason = args2.slice(1).join(" ") || "Quarantined via /swarm knowledge quarantine command";
|
|
48415
48427
|
try {
|
|
48416
|
-
await
|
|
48417
|
-
|
|
48428
|
+
const entries = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
48429
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
48430
|
+
if ("error" in resolved) {
|
|
48431
|
+
return `❌ ${resolved.error}`;
|
|
48432
|
+
}
|
|
48433
|
+
const fullId = resolved.entry.id;
|
|
48434
|
+
await quarantineEntry(directory, fullId, reason, "user");
|
|
48435
|
+
return `✅ Entry ${fullId} quarantined successfully.`;
|
|
48418
48436
|
} catch (error93) {
|
|
48419
48437
|
console.warn("[knowledge-command] quarantineEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
48420
48438
|
return `❌ Failed to quarantine entry. Check the entry ID and try again.`;
|
|
48421
48439
|
}
|
|
48422
48440
|
}
|
|
48423
48441
|
async function handleKnowledgeRestoreCommand(directory, args2) {
|
|
48424
|
-
const
|
|
48425
|
-
if (!
|
|
48442
|
+
const inputId = args2[0];
|
|
48443
|
+
if (!inputId) {
|
|
48426
48444
|
return "Usage: /swarm knowledge restore <id>";
|
|
48427
48445
|
}
|
|
48428
|
-
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(
|
|
48446
|
+
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(inputId)) {
|
|
48429
48447
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
48430
48448
|
}
|
|
48431
48449
|
try {
|
|
48432
|
-
|
|
48433
|
-
|
|
48450
|
+
const quarantinePath = join28(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
48451
|
+
const entries = await readKnowledge(quarantinePath);
|
|
48452
|
+
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
48453
|
+
if ("error" in resolved) {
|
|
48454
|
+
return `❌ ${resolved.error}`;
|
|
48455
|
+
}
|
|
48456
|
+
const fullId = resolved.entry.id;
|
|
48457
|
+
await restoreEntry(directory, fullId);
|
|
48458
|
+
return `✅ Entry ${fullId} restored successfully.`;
|
|
48434
48459
|
} catch (error93) {
|
|
48435
48460
|
console.warn("[knowledge-command] restoreEntry error:", error93 instanceof Error ? error93.message : String(error93));
|
|
48436
48461
|
return `❌ Failed to restore entry. Check the entry ID and try again.`;
|
|
@@ -48468,16 +48493,16 @@ async function handleKnowledgeListCommand(directory, _args) {
|
|
|
48468
48493
|
const lines = [
|
|
48469
48494
|
`## Knowledge Entries (${entries.length} total)`,
|
|
48470
48495
|
"",
|
|
48471
|
-
"| ID | Category | Confidence | Lesson (truncated) |",
|
|
48472
|
-
"
|
|
48496
|
+
"| ID (prefix) | Category | Confidence | Lesson (truncated) |",
|
|
48497
|
+
"|--------------|----------|------------|---------------------|"
|
|
48473
48498
|
];
|
|
48474
48499
|
for (const entry of entries) {
|
|
48475
48500
|
const truncatedLesson = entry.lesson.length > 60 ? `${entry.lesson.slice(0, 57)}...` : entry.lesson;
|
|
48476
48501
|
const confidencePct = Math.round(entry.confidence * 100);
|
|
48477
|
-
lines.push(`| ${entry.id.slice(0,
|
|
48502
|
+
lines.push(`| ${entry.id.slice(0, 12)}… | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`);
|
|
48478
48503
|
}
|
|
48479
48504
|
lines.push("");
|
|
48480
|
-
lines.push("Use `/swarm knowledge quarantine <id>` to hide an entry.");
|
|
48505
|
+
lines.push("Use `/swarm knowledge quarantine <id-prefix>` to hide an entry. Prefix matching is supported — the 12-character prefix shown is unique in most stores.");
|
|
48481
48506
|
return lines.join(`
|
|
48482
48507
|
`);
|
|
48483
48508
|
} catch (error93) {
|
|
@@ -63848,7 +63873,7 @@ ${content.substring(endIndex + 1)}`;
|
|
|
63848
63873
|
init_manager();
|
|
63849
63874
|
init_utils2();
|
|
63850
63875
|
import * as fs31 from "node:fs";
|
|
63851
|
-
import { join as
|
|
63876
|
+
import { join as join42 } from "node:path";
|
|
63852
63877
|
function createCompactionCustomizerHook(config3, directory) {
|
|
63853
63878
|
const enabled = config3.hooks?.compaction !== false;
|
|
63854
63879
|
if (!enabled) {
|
|
@@ -63893,7 +63918,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
63893
63918
|
}
|
|
63894
63919
|
}
|
|
63895
63920
|
try {
|
|
63896
|
-
const summariesDir =
|
|
63921
|
+
const summariesDir = join42(directory, ".swarm", "summaries");
|
|
63897
63922
|
const files = await fs31.promises.readdir(summariesDir);
|
|
63898
63923
|
if (files.length > 0) {
|
|
63899
63924
|
const count = files.length;
|
|
@@ -74626,7 +74651,7 @@ import {
|
|
|
74626
74651
|
readFileSync as readFileSync36,
|
|
74627
74652
|
writeFileSync as writeFileSync11
|
|
74628
74653
|
} from "node:fs";
|
|
74629
|
-
import { join as
|
|
74654
|
+
import { join as join66 } from "node:path";
|
|
74630
74655
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
74631
74656
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
74632
74657
|
var COUNCIL_GATE_NAME = "council";
|
|
@@ -74660,9 +74685,9 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
74660
74685
|
if (!VALID_TASK_ID.test(synthesis.taskId)) {
|
|
74661
74686
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" — must match N.M or N.M.P format`);
|
|
74662
74687
|
}
|
|
74663
|
-
const dir =
|
|
74688
|
+
const dir = join66(workingDir, EVIDENCE_DIR2);
|
|
74664
74689
|
mkdirSync18(dir, { recursive: true });
|
|
74665
|
-
const filePath =
|
|
74690
|
+
const filePath = join66(dir, `${synthesis.taskId}.json`);
|
|
74666
74691
|
const existingRoot = Object.create(null);
|
|
74667
74692
|
if (existsSync37(filePath)) {
|
|
74668
74693
|
try {
|
|
@@ -74696,7 +74721,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
74696
74721
|
updated.required_gates = [];
|
|
74697
74722
|
writeFileSync11(filePath, JSON.stringify(updated, null, 2));
|
|
74698
74723
|
try {
|
|
74699
|
-
const councilDir =
|
|
74724
|
+
const councilDir = join66(workingDir, ".swarm", "council");
|
|
74700
74725
|
mkdirSync18(councilDir, { recursive: true });
|
|
74701
74726
|
const auditLine = JSON.stringify({
|
|
74702
74727
|
round: synthesis.roundNumber,
|
|
@@ -74704,7 +74729,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
74704
74729
|
timestamp: synthesis.timestamp,
|
|
74705
74730
|
vetoedBy: synthesis.vetoedBy
|
|
74706
74731
|
});
|
|
74707
|
-
appendFileSync6(
|
|
74732
|
+
appendFileSync6(join66(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
74708
74733
|
`);
|
|
74709
74734
|
} catch (auditError) {
|
|
74710
74735
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -74837,20 +74862,20 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
|
|
|
74837
74862
|
|
|
74838
74863
|
// src/council/criteria-store.ts
|
|
74839
74864
|
import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync37, writeFileSync as writeFileSync12 } from "node:fs";
|
|
74840
|
-
import { join as
|
|
74865
|
+
import { join as join67 } from "node:path";
|
|
74841
74866
|
var COUNCIL_DIR = ".swarm/council";
|
|
74842
74867
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
74843
|
-
const dir =
|
|
74868
|
+
const dir = join67(workingDir, COUNCIL_DIR);
|
|
74844
74869
|
mkdirSync19(dir, { recursive: true });
|
|
74845
74870
|
const payload = {
|
|
74846
74871
|
taskId,
|
|
74847
74872
|
criteria,
|
|
74848
74873
|
declaredAt: new Date().toISOString()
|
|
74849
74874
|
};
|
|
74850
|
-
writeFileSync12(
|
|
74875
|
+
writeFileSync12(join67(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
|
|
74851
74876
|
}
|
|
74852
74877
|
function readCriteria(workingDir, taskId) {
|
|
74853
|
-
const filePath =
|
|
74878
|
+
const filePath = join67(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
|
|
74854
74879
|
if (!existsSync38(filePath))
|
|
74855
74880
|
return null;
|
|
74856
74881
|
try {
|
|
@@ -77395,6 +77420,7 @@ var VALID_CATEGORIES2 = [
|
|
|
77395
77420
|
"debugging",
|
|
77396
77421
|
"performance",
|
|
77397
77422
|
"integration",
|
|
77423
|
+
"todo",
|
|
77398
77424
|
"other"
|
|
77399
77425
|
];
|
|
77400
77426
|
var knowledge_add = createSwarmTool({
|
|
@@ -77539,6 +77565,7 @@ var VALID_CATEGORIES3 = [
|
|
|
77539
77565
|
"debugging",
|
|
77540
77566
|
"performance",
|
|
77541
77567
|
"integration",
|
|
77568
|
+
"todo",
|
|
77542
77569
|
"other"
|
|
77543
77570
|
];
|
|
77544
77571
|
var VALID_STATUSES = ["candidate", "established", "promoted"];
|
|
@@ -88776,6 +88803,34 @@ async function initializeOpenCodeSwarm(ctx) {
|
|
|
88776
88803
|
}
|
|
88777
88804
|
}
|
|
88778
88805
|
}
|
|
88806
|
+
{
|
|
88807
|
+
const noFallback = [];
|
|
88808
|
+
const hasNoFallback = (cfg) => cfg.model && (!cfg.fallback_models || cfg.fallback_models.length === 0);
|
|
88809
|
+
if (config3.agents) {
|
|
88810
|
+
for (const [name2, cfg] of Object.entries(config3.agents)) {
|
|
88811
|
+
if (hasNoFallback(cfg))
|
|
88812
|
+
noFallback.push(`${name2}(${cfg.model})`);
|
|
88813
|
+
}
|
|
88814
|
+
}
|
|
88815
|
+
if (config3.swarms) {
|
|
88816
|
+
for (const [swarmId, swarm] of Object.entries(config3.swarms)) {
|
|
88817
|
+
if (swarm.agents) {
|
|
88818
|
+
for (const [name2, cfg] of Object.entries(swarm.agents)) {
|
|
88819
|
+
if (hasNoFallback(cfg))
|
|
88820
|
+
noFallback.push(`${swarmId}/${name2}(${cfg.model})`);
|
|
88821
|
+
}
|
|
88822
|
+
}
|
|
88823
|
+
}
|
|
88824
|
+
}
|
|
88825
|
+
if (noFallback.length > 0) {
|
|
88826
|
+
const msg = `[opencode-swarm] WARNING: ${noFallback.length} agent(s) use a custom model without fallback_models: ` + noFallback.join(", ") + '. Add "fallback_models": ["model-a"] to each agent config for reliability.';
|
|
88827
|
+
if (!config3.quiet) {
|
|
88828
|
+
console.warn(msg);
|
|
88829
|
+
} else {
|
|
88830
|
+
addDeferredWarning(msg);
|
|
88831
|
+
}
|
|
88832
|
+
}
|
|
88833
|
+
}
|
|
88779
88834
|
swarmState.fullAutoEnabledInConfig = config3.full_auto?.enabled === true;
|
|
88780
88835
|
swarmState.opencodeClient = ctx.client;
|
|
88781
88836
|
await loadSnapshot(ctx.directory);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.86.
|
|
3
|
+
"version": "6.86.12",
|
|
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",
|