opencode-swarm 7.3.4 → 7.3.5

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 CHANGED
@@ -788,6 +788,17 @@ Prefixed agents (e.g., `paid_coder`, `mega_reviewer`, `local_architect`) inherit
788
788
 
789
789
  In this example, `paid_coder` gets its own explicit rule, while other prefixed coders (e.g., `mega_coder`) fall back to `coder`.
790
790
 
791
+ #### Selecting the primary agent in multi-swarm configs (`default_agent`)
792
+
793
+ The top-level `default_agent` field controls which generated agents OpenCode treats as primary. **It is optional.** Behavior:
794
+
795
+ - **Omitted** — every architect-role agent is primary. In a multi-swarm config that means each swarm exposes its own architect (`local_architect`, `mega_architect`, `paid_architect`, `modelrelay_architect`, …) as a selectable session default. This is the v7.0.0-compatible behavior and the recommended setup.
796
+ - **Base role** (e.g. `"coder"`) — every generated agent whose canonical base role matches becomes primary (`local_coder`, `mega_coder`, …).
797
+ - **Exact generated name** (e.g. `"local_architect"`) — only that agent is primary.
798
+ - **Unknown / invalid value** — a one-time warning is logged and the resolver falls back to architect-role primaries (or the first generated agent if architects are disabled). The plugin never produces zero primaries when at least one agent exists.
799
+
800
+ See [`docs/configuration.md`](docs/configuration.md) for the full table.
801
+
791
802
  ### Runtime Enforcement
792
803
 
793
804
  Architect direct writes are enforced at runtime via `toolBefore` hook. This tracks writes to source code paths outside `.swarm/` and protects `.swarm/plan.md` and `.swarm/plan.json` from direct modification.
@@ -34,6 +34,34 @@ export declare function getSwarmAgents(): Record<string, {
34
34
  * Create all agent definitions with configuration applied
35
35
  */
36
36
  export declare function createAgents(config?: PluginConfig): AgentDefinition[];
37
+ /**
38
+ * Resolve the set of generated agent names that should be marked as primary
39
+ * for OpenCode's session-default-agent resolution.
40
+ *
41
+ * Resolution rules (see schema.ts default_agent comment for full semantics):
42
+ * - default_agent omitted ⇒ every architect-role agent is primary
43
+ * (canonical base role === "architect"). This restores v7.0.0 behavior in
44
+ * multi-swarm configs where there is no unprefixed `architect` agent.
45
+ * - default_agent exactly matches a generated agent name ⇒ only that agent.
46
+ * Exact match wins over base-role match — `local_architect` resolves to
47
+ * just `local_architect`, never the entire architect role.
48
+ * - default_agent is a base role in ALL_AGENT_NAMES ⇒ every generated agent
49
+ * whose canonical base role matches that role.
50
+ * - default_agent is invalid (matches nothing) ⇒ fall back to architect-role
51
+ * primaries; if no architect roles exist (architects disabled), fall back
52
+ * to the first generated agent. Always warns. Never returns empty when
53
+ * `agentNames` is non-empty.
54
+ *
55
+ * Important matching detail: a value like "not_an_architect" is NOT treated
56
+ * as a base-role request even though stripKnownSwarmPrefix() returns
57
+ * "architect" for it. Base-role matching only fires when the user-supplied
58
+ * value is itself one of ALL_AGENT_NAMES.
59
+ */
60
+ export declare function resolvePrimaryAgentNames(agentNames: string[], defaultAgent?: string): {
61
+ primaryNames: Set<string>;
62
+ reason: 'implicit-architects' | 'exact' | 'base-role' | 'fallback-architects' | 'fallback-first';
63
+ warning?: string;
64
+ };
37
65
  /**
38
66
  * Get agent configurations formatted for the OpenCode SDK.
39
67
  */
package/dist/cli/index.js CHANGED
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.3.4",
37
+ version: "7.3.5",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -16915,7 +16915,12 @@ var init_schema = __esm(() => {
16915
16915
  });
16916
16916
  PluginConfigSchema = exports_external.object({
16917
16917
  agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
16918
- default_agent: exports_external.enum(ALL_AGENT_NAMES).default("architect").optional(),
16918
+ default_agent: exports_external.string().optional().transform((v) => {
16919
+ if (v === undefined)
16920
+ return;
16921
+ const trimmed = v.trim();
16922
+ return trimmed === "" ? undefined : trimmed;
16923
+ }),
16919
16924
  swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
16920
16925
  max_iterations: exports_external.number().min(1).max(10).default(5),
16921
16926
  pipeline: PipelineConfigSchema.optional(),
@@ -643,26 +643,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
643
643
  disabled: z.ZodOptional<z.ZodBoolean>;
644
644
  fallback_models: z.ZodOptional<z.ZodArray<z.ZodString>>;
645
645
  }, z.core.$strip>>>;
646
- default_agent: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
647
- architect: "architect";
648
- sme: "sme";
649
- docs: "docs";
650
- designer: "designer";
651
- critic_sounding_board: "critic_sounding_board";
652
- critic_drift_verifier: "critic_drift_verifier";
653
- critic_hallucination_verifier: "critic_hallucination_verifier";
654
- curator_init: "curator_init";
655
- curator_phase: "curator_phase";
656
- council_generalist: "council_generalist";
657
- council_skeptic: "council_skeptic";
658
- council_domain_expert: "council_domain_expert";
659
- reviewer: "reviewer";
660
- critic: "critic";
661
- critic_oversight: "critic_oversight";
662
- explorer: "explorer";
663
- coder: "coder";
664
- test_engineer: "test_engineer";
665
- }>>>;
646
+ default_agent: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<string | undefined, string | undefined>>;
666
647
  swarms: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
667
648
  name: z.ZodOptional<z.ZodString>;
668
649
  agents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
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.3.4",
36
+ version: "7.3.5",
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",
@@ -15352,7 +15352,12 @@ var init_schema = __esm(() => {
15352
15352
  });
15353
15353
  PluginConfigSchema = exports_external.object({
15354
15354
  agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
15355
- default_agent: exports_external.enum(ALL_AGENT_NAMES).default("architect").optional(),
15355
+ default_agent: exports_external.string().optional().transform((v) => {
15356
+ if (v === undefined)
15357
+ return;
15358
+ const trimmed = v.trim();
15359
+ return trimmed === "" ? undefined : trimmed;
15360
+ }),
15356
15361
  swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
15357
15362
  max_iterations: exports_external.number().min(1).max(10).default(5),
15358
15363
  pipeline: PipelineConfigSchema.optional(),
@@ -59986,6 +59991,52 @@ function createAgents(config3) {
59986
59991
  }
59987
59992
  return allAgents;
59988
59993
  }
59994
+ function resolvePrimaryAgentNames(agentNames, defaultAgent) {
59995
+ const collectArchitectRole = () => agentNames.filter((n) => stripKnownSwarmPrefix(n) === "architect");
59996
+ const trimmed = typeof defaultAgent === "string" ? defaultAgent.trim() : undefined;
59997
+ const value = trimmed === "" ? undefined : trimmed;
59998
+ if (agentNames.length === 0) {
59999
+ return { primaryNames: new Set, reason: "implicit-architects" };
60000
+ }
60001
+ if (value === undefined) {
60002
+ const architects2 = collectArchitectRole();
60003
+ if (architects2.length > 0) {
60004
+ return {
60005
+ primaryNames: new Set(architects2),
60006
+ reason: "implicit-architects"
60007
+ };
60008
+ }
60009
+ const first2 = agentNames[0];
60010
+ return {
60011
+ primaryNames: new Set([first2]),
60012
+ reason: "fallback-first",
60013
+ warning: `[swarm] No architect-role agents are registered and default_agent is unset; falling back to '${first2}' as primary. Re-enable an architect agent or set default_agent to silence this warning.`
60014
+ };
60015
+ }
60016
+ if (ALL_AGENT_NAMES.includes(value)) {
60017
+ const matching = agentNames.filter((n) => stripKnownSwarmPrefix(n) === value);
60018
+ if (matching.length > 0) {
60019
+ return { primaryNames: new Set(matching), reason: "base-role" };
60020
+ }
60021
+ }
60022
+ if (agentNames.includes(value)) {
60023
+ return { primaryNames: new Set([value]), reason: "exact" };
60024
+ }
60025
+ const architects = collectArchitectRole();
60026
+ if (architects.length > 0) {
60027
+ return {
60028
+ primaryNames: new Set(architects),
60029
+ reason: "fallback-architects",
60030
+ warning: `[swarm] default_agent '${value}' did not match any registered agent; falling back to architect-role primaries: ${architects.join(", ")}.`
60031
+ };
60032
+ }
60033
+ const first = agentNames[0];
60034
+ return {
60035
+ primaryNames: new Set([first]),
60036
+ reason: "fallback-first",
60037
+ warning: `[swarm] default_agent '${value}' did not match any registered agent and no architect-role agents are registered; falling back to '${first}' as primary.`
60038
+ };
60039
+ }
59989
60040
  function getAgentConfigs(config3, directory, sessionId) {
59990
60041
  const agents = createAgents(config3);
59991
60042
  const toolFilterEnabled = config3?.tool_filter?.enabled ?? true;
@@ -59993,21 +60044,29 @@ function getAgentConfigs(config3, directory, sessionId) {
59993
60044
  const quiet = config3?.quiet ?? true;
59994
60045
  const warnedMissingWhitelist = new Set;
59995
60046
  const agentToolSnapshot = {};
60047
+ const resolution = resolvePrimaryAgentNames(agents.map((a) => a.name), config3?.default_agent);
60048
+ if (resolution.warning) {
60049
+ if (!quiet) {
60050
+ console.warn(resolution.warning);
60051
+ } else {
60052
+ addDeferredWarning(resolution.warning);
60053
+ }
60054
+ }
60055
+ if (agents.length > 0 && resolution.primaryNames.size === 0) {
60056
+ const generated = agents.map((a) => a.name).join(", ");
60057
+ const diagnostic = `[swarm] DIAGNOSTIC: ${agents.length} generated agents but zero primaries. Likely cause: a regression in resolvePrimaryAgentNames. Generated: ${generated}.`;
60058
+ if (!quiet) {
60059
+ console.warn(diagnostic);
60060
+ } else {
60061
+ addDeferredWarning(diagnostic);
60062
+ }
60063
+ }
59996
60064
  const result = Object.fromEntries(agents.map((agent) => {
59997
60065
  const sdkConfig = {
59998
60066
  ...agent.config,
59999
60067
  description: agent.description
60000
60068
  };
60001
- let defaultAgent = config3?.default_agent ?? "architect";
60002
- if (defaultAgent !== "architect" && !ALL_AGENT_NAMES.includes(defaultAgent)) {
60003
- if (!quiet) {
60004
- console.warn(`[swarm] Invalid default_agent '${defaultAgent}' — falling back to 'architect'. Valid values: ${ALL_AGENT_NAMES.join(", ")}`);
60005
- } else {
60006
- addDeferredWarning(`[swarm] Invalid default_agent '${defaultAgent}' — falling back to 'architect'. Valid values: ${ALL_AGENT_NAMES.join(", ")}`);
60007
- }
60008
- defaultAgent = "architect";
60009
- }
60010
- const isPrimaryAgent = agent.name === defaultAgent;
60069
+ const isPrimaryAgent = resolution.primaryNames.has(agent.name);
60011
60070
  if (isPrimaryAgent) {
60012
60071
  sdkConfig.mode = "primary";
60013
60072
  sdkConfig.permission = { task: "allow" };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.3.4",
3
+ "version": "7.3.5",
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",