opencode-swarm 7.21.4 → 7.22.0

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 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.21.4",
37
+ version: "7.22.0",
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",
@@ -17378,7 +17378,8 @@ var init_schema = __esm(() => {
17378
17378
  AuthorityConfigSchema = exports_external.object({
17379
17379
  enabled: exports_external.boolean().default(true),
17380
17380
  rules: exports_external.record(exports_external.string(), AgentAuthorityRuleSchema).default({}),
17381
- universal_deny_prefixes: exports_external.array(exports_external.string().min(1)).default([])
17381
+ universal_deny_prefixes: exports_external.array(exports_external.string().min(1)).default([]),
17382
+ verifier_config_paths: exports_external.array(exports_external.string()).optional().describe("Additional glob patterns for verifier config files that are merged into the architect agent's blockedGlobs at plugin init. Writes to matching files are blocked by the authority layer.")
17382
17383
  });
17383
17384
  GeneralCouncilMemberConfigSchema = exports_external.object({
17384
17385
  memberId: exports_external.string().min(1),
@@ -17454,6 +17455,14 @@ var init_schema = __esm(() => {
17454
17455
  const trimmed = v.trim();
17455
17456
  return trimmed === "" ? undefined : trimmed;
17456
17457
  }),
17458
+ auto_select_architect: exports_external.union([exports_external.boolean(), exports_external.string()]).optional().transform((v) => {
17459
+ if (v === undefined)
17460
+ return;
17461
+ if (typeof v === "boolean")
17462
+ return v;
17463
+ const trimmed = v.trim();
17464
+ return trimmed === "" ? false : trimmed;
17465
+ }),
17457
17466
  swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
17458
17467
  max_iterations: exports_external.number().min(1).max(10).default(5),
17459
17468
  pipeline: PipelineConfigSchema.optional(),
@@ -641,6 +641,7 @@ export declare const AuthorityConfigSchema: z.ZodObject<{
641
641
  allowedGlobs: z.ZodOptional<z.ZodArray<z.ZodString>>;
642
642
  }, z.core.$strip>>>;
643
643
  universal_deny_prefixes: z.ZodDefault<z.ZodArray<z.ZodString>>;
644
+ verifier_config_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
644
645
  }, z.core.$strip>;
645
646
  export type AuthorityConfig = z.infer<typeof AuthorityConfigSchema>;
646
647
  export declare const GeneralCouncilConfigSchema: z.ZodObject<{
@@ -827,6 +828,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
827
828
  fallback_models: z.ZodOptional<z.ZodArray<z.ZodString>>;
828
829
  }, z.core.$strip>>>;
829
830
  default_agent: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<string | undefined, string | undefined>>;
831
+ auto_select_architect: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>, z.ZodTransform<string | boolean | undefined, string | boolean | undefined>>;
830
832
  swarms: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
831
833
  name: z.ZodOptional<z.ZodString>;
832
834
  agents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -1005,6 +1007,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
1005
1007
  allowedGlobs: z.ZodOptional<z.ZodArray<z.ZodString>>;
1006
1008
  }, z.core.$strip>>>;
1007
1009
  universal_deny_prefixes: z.ZodDefault<z.ZodArray<z.ZodString>>;
1010
+ verifier_config_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
1008
1011
  }, z.core.$strip>>;
1009
1012
  plan_cursor: z.ZodOptional<z.ZodObject<{
1010
1013
  enabled: z.ZodDefault<z.ZodBoolean>;
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.21.4",
36
+ version: "7.22.0",
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",
@@ -15591,7 +15591,8 @@ var init_schema = __esm(() => {
15591
15591
  AuthorityConfigSchema = exports_external.object({
15592
15592
  enabled: exports_external.boolean().default(true),
15593
15593
  rules: exports_external.record(exports_external.string(), AgentAuthorityRuleSchema).default({}),
15594
- universal_deny_prefixes: exports_external.array(exports_external.string().min(1)).default([])
15594
+ universal_deny_prefixes: exports_external.array(exports_external.string().min(1)).default([]),
15595
+ verifier_config_paths: exports_external.array(exports_external.string()).optional().describe("Additional glob patterns for verifier config files that are merged into the architect agent's blockedGlobs at plugin init. Writes to matching files are blocked by the authority layer.")
15595
15596
  });
15596
15597
  GeneralCouncilMemberConfigSchema = exports_external.object({
15597
15598
  memberId: exports_external.string().min(1),
@@ -15667,6 +15668,14 @@ var init_schema = __esm(() => {
15667
15668
  const trimmed = v.trim();
15668
15669
  return trimmed === "" ? undefined : trimmed;
15669
15670
  }),
15671
+ auto_select_architect: exports_external.union([exports_external.boolean(), exports_external.string()]).optional().transform((v) => {
15672
+ if (v === undefined)
15673
+ return;
15674
+ if (typeof v === "boolean")
15675
+ return v;
15676
+ const trimmed = v.trim();
15677
+ return trimmed === "" ? false : trimmed;
15678
+ }),
15670
15679
  swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
15671
15680
  max_iterations: exports_external.number().min(1).max(10).default(5),
15672
15681
  pipeline: PipelineConfigSchema.optional(),
@@ -24166,6 +24175,21 @@ var init_normalize_tool_name = __esm(() => {
24166
24175
  import * as fsSync2 from "node:fs";
24167
24176
  import * as fs8 from "node:fs/promises";
24168
24177
  import * as path10 from "node:path";
24178
+ function isConfigFilePath(filePath, cwd, extraGlobs) {
24179
+ const normalized = path10.relative(path10.resolve(cwd), path10.resolve(cwd, filePath)).replace(/\\/g, "/");
24180
+ const { zone } = classifyFile(normalized);
24181
+ if (zone === "config") {
24182
+ return true;
24183
+ }
24184
+ const allGlobs = extraGlobs && extraGlobs.length > 0 ? [...KNOWN_VERIFIER_CONFIG_GLOBS, ...extraGlobs] : KNOWN_VERIFIER_CONFIG_GLOBS;
24185
+ for (const glob of allGlobs) {
24186
+ const matcher = getGlobMatcher(glob);
24187
+ if (matcher(normalized)) {
24188
+ return true;
24189
+ }
24190
+ }
24191
+ return false;
24192
+ }
24169
24193
  function enforceSpecDriftGate(directory, toolName) {
24170
24194
  if (!directory)
24171
24195
  return;
@@ -24713,6 +24737,17 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
24713
24737
  };
24714
24738
  }
24715
24739
  const precomputedAuthorityRules = buildEffectiveRules(authorityConfig);
24740
+ const verifierPaths = authorityConfig?.verifier_config_paths;
24741
+ if (verifierPaths && verifierPaths.length > 0) {
24742
+ const existingArchitect = precomputedAuthorityRules.architect ?? {};
24743
+ precomputedAuthorityRules.architect = {
24744
+ ...existingArchitect,
24745
+ blockedGlobs: [
24746
+ ...existingArchitect.blockedGlobs ?? [],
24747
+ ...verifierPaths
24748
+ ]
24749
+ };
24750
+ }
24716
24751
  const universalDenyPrefixes = authorityConfig?.universal_deny_prefixes ?? [];
24717
24752
  const cfg = guardrailsConfig;
24718
24753
  const requiredQaGates = cfg.qa_gates?.required_tools ?? [
@@ -25102,6 +25137,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
25102
25137
  if (!authorityCheck.allowed) {
25103
25138
  throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${delegTargetPath}". Reason: ${authorityCheck.reason}`);
25104
25139
  }
25140
+ if (isConfigFilePath(delegTargetPath, cwd, authorityConfig?.verifier_config_paths)) {
25141
+ const normalizedPath = path10.relative(path10.resolve(cwd), path10.resolve(cwd, delegTargetPath)).replace(/\\/g, "/");
25142
+ const logEntry = {
25143
+ agent: agentName,
25144
+ path: normalizedPath,
25145
+ allowed: authorityCheck.allowed,
25146
+ type: "delegated_write"
25147
+ };
25148
+ if (!authorityCheck.allowed && "reason" in authorityCheck) {
25149
+ logEntry.reason = authorityCheck.reason;
25150
+ }
25151
+ warn("Config file write attempt", logEntry);
25152
+ }
25105
25153
  if (!currentSession.modifiedFilesThisCoderTask.includes(delegTargetPath)) {
25106
25154
  currentSession.modifiedFilesThisCoderTask.push(delegTargetPath);
25107
25155
  }
@@ -25112,6 +25160,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
25112
25160
  const cwd = effectiveDirectory;
25113
25161
  for (const p of extractPatchTargetPaths(tool, args2)) {
25114
25162
  const authorityCheck = checkFileAuthorityWithRules(agentName, p, cwd, precomputedAuthorityRules, { declaredScope: resolveDeclaredScope(sessionID) });
25163
+ if (isConfigFilePath(p, cwd, authorityConfig?.verifier_config_paths)) {
25164
+ const normalizedPath = path10.relative(path10.resolve(cwd), path10.resolve(cwd, p)).replace(/\\/g, "/");
25165
+ const logEntry = {
25166
+ agent: agentName,
25167
+ path: normalizedPath,
25168
+ allowed: authorityCheck.allowed,
25169
+ type: "delegated_patch"
25170
+ };
25171
+ if (!authorityCheck.allowed && "reason" in authorityCheck) {
25172
+ logEntry.reason = authorityCheck.reason;
25173
+ }
25174
+ warn("Config file write attempt", logEntry);
25175
+ }
25115
25176
  if (!authorityCheck.allowed) {
25116
25177
  throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${p}" (via patch). Reason: ${authorityCheck.reason}`);
25117
25178
  }
@@ -25443,6 +25504,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
25443
25504
  if (!authorityCheck.allowed) {
25444
25505
  throw new Error(`WRITE BLOCKED: Agent "${agentName}" is not authorised to write "${targetPath}". Reason: ${authorityCheck.reason}`);
25445
25506
  }
25507
+ if (isConfigFilePath(targetPath, effectiveDirectory, authorityConfig?.verifier_config_paths)) {
25508
+ const normalizedPath = path10.relative(path10.resolve(effectiveDirectory), path10.resolve(effectiveDirectory, targetPath)).replace(/\\/g, "/");
25509
+ const logEntry = {
25510
+ agent: agentName,
25511
+ path: normalizedPath,
25512
+ allowed: authorityCheck.allowed,
25513
+ type: "direct_write"
25514
+ };
25515
+ if (!authorityCheck.allowed && "reason" in authorityCheck) {
25516
+ logEntry.reason = authorityCheck.reason;
25517
+ }
25518
+ warn("Config file write attempt", logEntry);
25519
+ }
25446
25520
  }
25447
25521
  }
25448
25522
  if (input.tool === "apply_patch" || input.tool === "patch") {
@@ -25468,6 +25542,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
25468
25542
  if (!authorityCheck.allowed) {
25469
25543
  throw new Error(`WRITE BLOCKED: Agent "${patchAgentName}" is not authorised to write "${p}" (via patch). Reason: ${authorityCheck.reason}`);
25470
25544
  }
25545
+ if (isConfigFilePath(p, effectiveDirectory, authorityConfig?.verifier_config_paths)) {
25546
+ const normalizedPath = path10.relative(path10.resolve(effectiveDirectory), path10.resolve(effectiveDirectory, p)).replace(/\\/g, "/");
25547
+ const logEntry = {
25548
+ agent: patchAgentName,
25549
+ path: normalizedPath,
25550
+ allowed: authorityCheck.allowed,
25551
+ type: "direct_patch"
25552
+ };
25553
+ if (!authorityCheck.allowed && "reason" in authorityCheck) {
25554
+ logEntry.reason = authorityCheck.reason;
25555
+ }
25556
+ warn("Config file write attempt", logEntry);
25557
+ }
25471
25558
  }
25472
25559
  }
25473
25560
  {
@@ -26170,11 +26257,11 @@ function checkWriteTargetForSymlink(targetPath, cwd) {
26170
26257
  }
26171
26258
  function buildEffectiveRules(authorityConfig) {
26172
26259
  if (authorityConfig?.enabled === false || !authorityConfig?.rules) {
26173
- return DEFAULT_AGENT_AUTHORITY_RULES;
26260
+ return { ...DEFAULT_AGENT_AUTHORITY_RULES };
26174
26261
  }
26175
26262
  const entries = Object.entries(authorityConfig.rules);
26176
26263
  if (entries.length === 0) {
26177
- return DEFAULT_AGENT_AUTHORITY_RULES;
26264
+ return { ...DEFAULT_AGENT_AUTHORITY_RULES };
26178
26265
  }
26179
26266
  const merged = {
26180
26267
  ...DEFAULT_AGENT_AUTHORITY_RULES
@@ -26312,7 +26399,7 @@ function checkFileAuthorityWithRules(agentName, filePath, cwd, effectiveRules, o
26312
26399
  }
26313
26400
  return { allowed: true };
26314
26401
  }
26315
- var import_picomatch, _internals10, SPEC_DRIFT_BLOCKED_TOOLS, storedInputArgs, TRANSIENT_STATUS_CODES, TRANSIENT_MODEL_ERROR_PATTERN, TRANSIENT_PROVIDER_RECOVERY_TAG = "TRANSIENT PROVIDER RECOVERY", DEGRADED_ERROR_PATTERN, CONTENT_FILTER_PATTERN, toolCallsSinceLastWrite, noOpWarningIssued, consecutiveNoToolTurns, DC_MAX_UNWRAP_DEPTH = 5, DC_SAFE_TARGETS, DC_BLOCKED_ABSOLUTE_PREFIXES, DC_FS_ROOTS, DC_REMOTE_PREFIXES, pathNormalizationCache, globMatcherCache, DEFAULT_AGENT_AUTHORITY_RULES;
26402
+ var import_picomatch, KNOWN_VERIFIER_CONFIG_GLOBS, _internals10, SPEC_DRIFT_BLOCKED_TOOLS, storedInputArgs, TRANSIENT_STATUS_CODES, TRANSIENT_MODEL_ERROR_PATTERN, TRANSIENT_PROVIDER_RECOVERY_TAG = "TRANSIENT PROVIDER RECOVERY", DEGRADED_ERROR_PATTERN, CONTENT_FILTER_PATTERN, toolCallsSinceLastWrite, noOpWarningIssued, consecutiveNoToolTurns, DC_MAX_UNWRAP_DEPTH = 5, DC_SAFE_TARGETS, DC_BLOCKED_ABSOLUTE_PREFIXES, DC_FS_ROOTS, DC_REMOTE_PREFIXES, pathNormalizationCache, globMatcherCache, DEFAULT_AGENT_AUTHORITY_RULES;
26316
26403
  var init_guardrails = __esm(() => {
26317
26404
  init_quick_lru();
26318
26405
  init_agents2();
@@ -26332,6 +26419,17 @@ var init_guardrails = __esm(() => {
26332
26419
  init_model_limits();
26333
26420
  init_normalize_tool_name();
26334
26421
  import_picomatch = __toESM(require_picomatch2(), 1);
26422
+ KNOWN_VERIFIER_CONFIG_GLOBS = [
26423
+ "**/oxlintrc*",
26424
+ "**/.oxlintrc*",
26425
+ "**/.eslintrc*",
26426
+ "**/eslint.config.*",
26427
+ "**/.prettierrc*",
26428
+ "**/prettier.config.*",
26429
+ "**/biome.jsonc",
26430
+ "**/.secretscanignore",
26431
+ "**/.golangci*"
26432
+ ];
26335
26433
  _internals10 = {
26336
26434
  getSwarmAgents,
26337
26435
  getMostRecentAssistantText,
@@ -26426,7 +26524,18 @@ var init_guardrails = __esm(() => {
26426
26524
  explore: {},
26427
26525
  architect: {
26428
26526
  blockedExact: [".swarm/plan.md", ".swarm/plan.json"],
26429
- blockedZones: ["generated"]
26527
+ blockedZones: ["generated", "config"],
26528
+ blockedGlobs: [
26529
+ "**/oxlintrc*",
26530
+ "**/.oxlintrc*",
26531
+ "**/.eslintrc*",
26532
+ "**/eslint.config.*",
26533
+ "**/.prettierrc*",
26534
+ "**/prettier.config.*",
26535
+ "**/biome.jsonc",
26536
+ "**/.secretscanignore",
26537
+ "**/.golangci*"
26538
+ ]
26430
26539
  },
26431
26540
  coder: {
26432
26541
  blockedPrefix: [".swarm/"],
@@ -65779,6 +65888,18 @@ DO (explicitly):
65779
65888
  - VERIFY platform compatibility: path.join() used for all paths, no hardcoded separators
65780
65889
  - For confirmed issues requiring a concrete fix: use suggest_patch to produce a structured patch artifact for the coder
65781
65890
 
65891
+ ## CONFIG STRICTNESS VERIFICATION
65892
+
65893
+ When the declared scope includes a verifier/linter config file (biome.json, biome.jsonc, oxlintrc, oxlintrc.json, .eslintrc, .eslintrc.json, eslint.config.*, .prettierrc, .prettierrc.json, prettier.config.*, biome.jsonc, .secretscanignore, golangci-lint configs, tsconfig.json, tsconfig.*.json, or any other linter/formatter/security-tool configuration):
65894
+
65895
+ - Verify the change does NOT reduce strictness of any existing rule
65896
+ - Reject changes that downgrade "error" to "warn", remove rules, weaken validation thresholds, or narrow file/directory scopes
65897
+ - Allow changes that ADD new stricter rules, enable additional rule categories, fix syntax errors, or correct misconfigured paths
65898
+ - Document the specific config change and its impact on validation strictness in your review output
65899
+ - If a rule is changed from "error" to "warn" or a rule is removed: REJECT with STRICTNESS_REDUCTION: [rule name] — [original setting] → [new setting]
65900
+
65901
+ This is a pre-review gate: if config strictness is reduced, reject immediately without proceeding to Tier review.
65902
+
65782
65903
  ## REUSE RE-VERIFICATION (MANDATORY FOR NEW EXPORTS)
65783
65904
 
65784
65905
  When EXPORTS_ADDED is non-empty in the coder's completion report:
@@ -80616,7 +80737,9 @@ var DENY_SHELL_PATTERNS = [
80616
80737
  /\bbunx?\s+publish\b/i,
80617
80738
  /\bterraform\s+(?:apply|destroy)\b/i,
80618
80739
  /\bkubectl\s+(?:delete|apply\s+-f)/i,
80619
- /\bdrop\s+(?:database|table)\b/i
80740
+ /\bdrop\s+(?:database|table)\b/i,
80741
+ /\bsed\s+-i\b(?=[^\n]*\b(?:biome\.json|eslintrc|oxlintrc)\b)(?=[^\n]*\b(?:error|warn|off)\b)/i,
80742
+ /\b(?:cat|tee)\b[^\n]*>\s*[^\n]*\b(biome\.json|eslintrc|oxlintrc)\b[^\n]*\b(error|warn|off)\b/i
80620
80743
  ];
80621
80744
  var ESCALATE_SHELL_PATTERNS = [
80622
80745
  /\bcurl\b/i,
@@ -80636,7 +80759,9 @@ var ESCALATE_SHELL_PATTERNS = [
80636
80759
  /\bgit\s+pull\b/i,
80637
80760
  /\bgit\s+rebase\b/i,
80638
80761
  /\bgit\s+merge\b/i,
80639
- /\bgit\s+commit\b/i
80762
+ /\bgit\s+commit\b/i,
80763
+ /\b(sed\s+-i|echo\s+|printf\s+)[^\n]*\b(biome\.jsonc?|eslintrc|eslint\.config|oxlintrc|prettierrc|secretscanignore|golangci|tsconfig\.json|tsconfig\.[^.]+\.json)\b/i,
80764
+ /\b(?:cat|tee)\b[^\n]*>\s*[^\n]*\b(biome\.jsonc?|eslintrc|eslint\.config|oxlintrc|prettierrc|secretscanignore|golangci|tsconfig\.json|tsconfig\.[^.]+\.json)\b/i
80640
80765
  ];
80641
80766
  function isReadOnlyTool(toolName) {
80642
80767
  if (!toolName)
@@ -105206,11 +105331,65 @@ async function initializeOpenCodeSwarm(ctx) {
105206
105331
  swarm_command: createSwarmCommandTool(agentDefinitionMap)
105207
105332
  },
105208
105333
  config: async (opencodeConfig) => {
105334
+ if (!opencodeConfig.agent || typeof opencodeConfig.agent !== "object") {
105335
+ opencodeConfig.agent = {};
105336
+ }
105209
105337
  if (!opencodeConfig.agent) {
105210
105338
  opencodeConfig.agent = { ...agents };
105211
105339
  } else {
105212
105340
  Object.assign(opencodeConfig.agent, agents);
105213
105341
  }
105342
+ const autoSelect = config3?.auto_select_architect;
105343
+ if (autoSelect) {
105344
+ const hasArchitect = Object.keys(agents).some((name2) => stripKnownSwarmPrefix(name2) === "architect");
105345
+ if (hasArchitect) {
105346
+ for (const builtin of ["build", "plan"]) {
105347
+ const existing = opencodeConfig.agent?.[builtin];
105348
+ if (existing && typeof existing === "object" && existing.disable === true) {
105349
+ continue;
105350
+ }
105351
+ opencodeConfig.agent[builtin] = {
105352
+ ...existing && typeof existing === "object" ? existing : {},
105353
+ disable: true
105354
+ };
105355
+ }
105356
+ if (autoSelect === true) {
105357
+ const primaryArchitects = Object.entries(agents).filter(([name2, cfg]) => stripKnownSwarmPrefix(name2) === "architect" && cfg.mode === "primary");
105358
+ if (primaryArchitects.length > 1) {
105359
+ const names = primaryArchitects.map(([n]) => n).join(", ");
105360
+ addDeferredWarning(`[swarm] auto_select_architect is true but ${primaryArchitects.length} architect agents are primary (${names}). Consider setting auto_select_architect to a specific agent name.`);
105361
+ }
105362
+ }
105363
+ if (typeof autoSelect === "string" && autoSelect !== "") {
105364
+ const targetName = autoSelect;
105365
+ const targetIsArchitect = Object.hasOwn(agents, targetName) && stripKnownSwarmPrefix(targetName) === "architect";
105366
+ if (targetIsArchitect) {
105367
+ for (const [name2, cfg] of Object.entries(agents)) {
105368
+ if (stripKnownSwarmPrefix(name2) === "architect" && name2 !== targetName) {
105369
+ if (opencodeConfig.agent && typeof opencodeConfig.agent === "object") {
105370
+ opencodeConfig.agent[name2] = {
105371
+ ...cfg && typeof cfg === "object" ? cfg : {},
105372
+ mode: "subagent"
105373
+ };
105374
+ }
105375
+ }
105376
+ }
105377
+ if (opencodeConfig.agent && typeof opencodeConfig.agent === "object") {
105378
+ const targetExisting = opencodeConfig.agent[targetName];
105379
+ opencodeConfig.agent[targetName] = {
105380
+ ...targetExisting && typeof targetExisting === "object" ? targetExisting : {},
105381
+ ...agents[targetName] && typeof agents[targetName] === "object" ? agents[targetName] : {},
105382
+ mode: "primary"
105383
+ };
105384
+ }
105385
+ } else {
105386
+ addDeferredWarning(`[swarm] auto_select_architect is set to "${targetName}" but that is not a known architect agent. No architect demotion applied.`);
105387
+ }
105388
+ }
105389
+ } else {
105390
+ addDeferredWarning("[swarm] auto_select_architect is enabled but no architect agents were found in the generated set. The option has no effect.");
105391
+ }
105392
+ }
105214
105393
  opencodeConfig.command = {
105215
105394
  ...opencodeConfig.command || {},
105216
105395
  swarm: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.21.4",
3
+ "version": "7.22.0",
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",