opencode-swarm 7.29.0 → 7.29.1

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.29.0",
37
+ version: "7.29.1",
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",
@@ -40260,19 +40260,9 @@ function validateConfigKey(path24, value, _config) {
40260
40260
  case "guardrails.profiles": {
40261
40261
  const profiles = value;
40262
40262
  if (profiles) {
40263
- const validAgents = [
40264
- "architect",
40265
- "coder",
40266
- "test_engineer",
40267
- "explorer",
40268
- "reviewer",
40269
- "critic",
40270
- "sme",
40271
- "docs",
40272
- "designer"
40273
- ];
40263
+ const validAgents = new Set(ALL_AGENT_NAMES);
40274
40264
  for (const [agentName, profile] of Object.entries(profiles)) {
40275
- if (!validAgents.includes(agentName)) {
40265
+ if (!validAgents.has(agentName)) {
40276
40266
  findings.push({
40277
40267
  id: "unknown-agent-profile",
40278
40268
  title: "Unknown agent profile",
@@ -40433,23 +40423,23 @@ function validateConfigKey(path24, value, _config) {
40433
40423
  case "swarms": {
40434
40424
  const swarms = value;
40435
40425
  if (swarms && typeof swarms === "object") {
40426
+ const validAgents = new Set(ALL_AGENT_NAMES);
40436
40427
  for (const [swarmId, swarmConfig] of Object.entries(swarms)) {
40437
40428
  const swarm = swarmConfig;
40438
40429
  if (swarm.agents && typeof swarm.agents === "object") {
40439
40430
  for (const [agentName] of Object.entries(swarm.agents)) {
40440
- const validAgents = [
40441
- "architect",
40442
- "coder",
40443
- "test_engineer",
40444
- "explorer",
40445
- "reviewer",
40446
- "critic",
40447
- "sme",
40448
- "docs",
40449
- "designer"
40450
- ];
40451
- const baseName = agentName.replace(/^[a-zA-Z0-9]+_/, "");
40452
- if (!validAgents.includes(baseName)) {
40431
+ const baseName = stripKnownSwarmPrefix(agentName);
40432
+ if (baseName !== agentName && agentName.startsWith(`${swarmId}_`) && validAgents.has(baseName)) {
40433
+ findings.push({
40434
+ id: "prefixed-swarm-agent-override",
40435
+ title: "Prefixed agent override is ignored",
40436
+ description: `Agent "${agentName}" in swarm "${swarmId}" uses a generated agent name. ` + `Per-swarm overrides must use the canonical key "${baseName}", e.g. ` + `"swarms.${swarmId}.agents.${baseName}.model". Otherwise the override is ignored and the agent falls back to its default model.`,
40437
+ severity: "warn",
40438
+ path: `swarms.${swarmId}.agents.${agentName}`,
40439
+ currentValue: swarm.agents[agentName],
40440
+ autoFixable: false
40441
+ });
40442
+ } else if (!validAgents.has(baseName)) {
40453
40443
  findings.push({
40454
40444
  id: "unknown-swarm-agent",
40455
40445
  title: "Unknown agent in swarm",
@@ -40800,6 +40790,8 @@ function removeStraySwarmDir(projectRoot, strayPath) {
40800
40790
  }
40801
40791
  var VALID_CONFIG_PATTERNS, DANGEROUS_PATH_SEGMENTS;
40802
40792
  var init_config_doctor = __esm(() => {
40793
+ init_constants();
40794
+ init_schema();
40803
40795
  init_utils();
40804
40796
  VALID_CONFIG_PATTERNS = [
40805
40797
  /^\.config[\\/]opencode[\\/]opencode-swarm\.json$/,
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ var package_default;
48
48
  var init_package = __esm(() => {
49
49
  package_default = {
50
50
  name: "opencode-swarm",
51
- version: "7.29.0",
51
+ version: "7.29.1",
52
52
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
53
53
  main: "dist/index.js",
54
54
  types: "dist/index.d.ts",
@@ -61164,19 +61164,9 @@ function validateConfigKey(path31, value, _config) {
61164
61164
  case "guardrails.profiles": {
61165
61165
  const profiles = value;
61166
61166
  if (profiles) {
61167
- const validAgents = [
61168
- "architect",
61169
- "coder",
61170
- "test_engineer",
61171
- "explorer",
61172
- "reviewer",
61173
- "critic",
61174
- "sme",
61175
- "docs",
61176
- "designer"
61177
- ];
61167
+ const validAgents = new Set(ALL_AGENT_NAMES);
61178
61168
  for (const [agentName, profile] of Object.entries(profiles)) {
61179
- if (!validAgents.includes(agentName)) {
61169
+ if (!validAgents.has(agentName)) {
61180
61170
  findings.push({
61181
61171
  id: "unknown-agent-profile",
61182
61172
  title: "Unknown agent profile",
@@ -61337,23 +61327,23 @@ function validateConfigKey(path31, value, _config) {
61337
61327
  case "swarms": {
61338
61328
  const swarms = value;
61339
61329
  if (swarms && typeof swarms === "object") {
61330
+ const validAgents = new Set(ALL_AGENT_NAMES);
61340
61331
  for (const [swarmId, swarmConfig] of Object.entries(swarms)) {
61341
61332
  const swarm = swarmConfig;
61342
61333
  if (swarm.agents && typeof swarm.agents === "object") {
61343
61334
  for (const [agentName] of Object.entries(swarm.agents)) {
61344
- const validAgents = [
61345
- "architect",
61346
- "coder",
61347
- "test_engineer",
61348
- "explorer",
61349
- "reviewer",
61350
- "critic",
61351
- "sme",
61352
- "docs",
61353
- "designer"
61354
- ];
61355
- const baseName = agentName.replace(/^[a-zA-Z0-9]+_/, "");
61356
- if (!validAgents.includes(baseName)) {
61335
+ const baseName = stripKnownSwarmPrefix(agentName);
61336
+ if (baseName !== agentName && agentName.startsWith(`${swarmId}_`) && validAgents.has(baseName)) {
61337
+ findings.push({
61338
+ id: "prefixed-swarm-agent-override",
61339
+ title: "Prefixed agent override is ignored",
61340
+ description: `Agent "${agentName}" in swarm "${swarmId}" uses a generated agent name. ` + `Per-swarm overrides must use the canonical key "${baseName}", e.g. ` + `"swarms.${swarmId}.agents.${baseName}.model". Otherwise the override is ignored and the agent falls back to its default model.`,
61341
+ severity: "warn",
61342
+ path: `swarms.${swarmId}.agents.${agentName}`,
61343
+ currentValue: swarm.agents[agentName],
61344
+ autoFixable: false
61345
+ });
61346
+ } else if (!validAgents.has(baseName)) {
61357
61347
  findings.push({
61358
61348
  id: "unknown-swarm-agent",
61359
61349
  title: "Unknown agent in swarm",
@@ -61704,6 +61694,8 @@ function removeStraySwarmDir(projectRoot, strayPath) {
61704
61694
  }
61705
61695
  var VALID_CONFIG_PATTERNS, DANGEROUS_PATH_SEGMENTS;
61706
61696
  var init_config_doctor = __esm(() => {
61697
+ init_constants();
61698
+ init_schema();
61707
61699
  init_utils();
61708
61700
  VALID_CONFIG_PATTERNS = [
61709
61701
  /^\.config[\\/]opencode[\\/]opencode-swarm\.json$/,
@@ -75598,7 +75590,7 @@ ANTI-RATIONALIZATION: Context does not clarify. Models revert to CC training.
75598
75590
  ## IDENTITY
75599
75591
 
75600
75592
  Swarm: {{SWARM_ID}}
75601
- Your agents: {{AGENT_PREFIX}}explorer, {{AGENT_PREFIX}}sme, {{AGENT_PREFIX}}coder, {{AGENT_PREFIX}}reviewer, {{AGENT_PREFIX}}test_engineer, {{AGENT_PREFIX}}critic, {{AGENT_PREFIX}}critic_sounding_board, {{AGENT_PREFIX}}docs, {{AGENT_PREFIX}}designer
75593
+ Your agents: {{AGENT_PREFIX}}explorer, {{AGENT_PREFIX}}sme, {{AGENT_PREFIX}}coder, {{AGENT_PREFIX}}reviewer, {{AGENT_PREFIX}}test_engineer, {{AGENT_PREFIX}}critic, {{AGENT_PREFIX}}critic_sounding_board, {{AGENT_PREFIX}}skill_improver, {{AGENT_PREFIX}}spec_writer, {{AGENT_PREFIX}}docs, {{AGENT_PREFIX}}designer
75602
75594
 
75603
75595
  ## PROJECT CONTEXT
75604
75596
  Session-start priming block. Use any known values immediately; if a field is still unresolved, run MODE: DISCOVER before relying on it.
@@ -75939,6 +75931,8 @@ SECURITY_KEYWORDS: password, secret, token, credential, auth, login, encryption,
75939
75931
  {{AGENT_PREFIX}}test_engineer - Test generation AND execution (writes tests, runs them, reports PASS/FAIL)
75940
75932
  {{AGENT_PREFIX}}critic - Plan review gate (reviews plan BEFORE implementation)
75941
75933
  {{AGENT_PREFIX}}critic_sounding_board - Pre-escalation pushback (honest engineer review before user contact)
75934
+ {{AGENT_PREFIX}}skill_improver - Low-frequency skill / knowledge / prompt improvement adviser
75935
+ {{AGENT_PREFIX}}spec_writer - .swarm/spec.md authoring via spec_write
75942
75936
  {{AGENT_PREFIX}}docs - Documentation updates (README, API docs, guides — NOT .swarm/ files)
75943
75937
  {{AGENT_PREFIX}}designer - UI/UX design specs (scaffold generation for UI components — runs BEFORE coder on UI tasks)
75944
75938
 
@@ -75989,30 +75983,20 @@ For every applicable directive in the block:
75989
75983
 
75990
75984
  You may also call the \`knowledge_ack\` tool to record an outcome explicitly when chat-text markers would be ambiguous (e.g. inside structured tool args).
75991
75985
 
75992
- ## SKILL IMPROVER (low-frequency, expensive-model adviser)
75986
+ ## SKILL IMPROVER
75993
75987
 
75994
- The \`skill_improver\` agent and the \`skill_improve\` tool exist for rare, deep
75995
- review of accumulated knowledge / skills / spec / architect prompt. They are
75996
- quota-bounded (default 10 calls/day) and disabled by default. Suggest running
75997
- \`skill_improve\` only after one of:
75998
- - repeated reviewer rejections in a row,
75999
- - many \`KNOWLEDGE_IGNORED\` outcomes for the same cluster,
76000
- - stale skills (no updates while their target area changed),
76001
- - a fresh spec mismatch with shipped behaviour.
75988
+ \`{{AGENT_PREFIX}}skill_improver\` / \`skill_improve\`: rare, quota-bounded,
75989
+ disabled by default, proposal-only. Use for repeated rejections,
75990
+ \`KNOWLEDGE_IGNORED\`, stale skills, or spec drift.
76002
75991
 
76003
75992
  When \`skill_improver.require_user_approval\` is true (default), ASK the user
76004
75993
  before running. Default outputs are proposals only — they never modify source.
76005
75994
 
76006
75995
  ## SPEC WRITER
76007
75996
 
76008
- For substantial spec authoring or revision, prefer delegating to the
76009
- \`spec_writer\` agent (independent model from architect). It writes only via
76010
- the safe \`spec_write\` tool. Use it when:
76011
- - the user requests a new spec or major spec revision,
76012
- - requirements decomposition is non-trivial,
76013
- - you would otherwise inline-author \`.swarm/spec.md\` yourself.
76014
-
76015
- Continue handling small touch-ups (typos, cross-references) inline.
75997
+ For substantial spec authoring/revision, prefer \`{{AGENT_PREFIX}}spec_writer\`;
75998
+ it writes via \`spec_write\`. Use for major specs or non-trivial
75999
+ decomposition. Handle small touch-ups.
76016
76000
 
76017
76001
  ### ANTI-RATIONALIZATION
76018
76002
  - ✗ "The coder already knows these conventions" → Skills contain project-specific rules the model cannot know from training. Always pass.
@@ -76193,11 +76177,12 @@ MODE: BRAINSTORM runs seven phases in strict order. Do not skip phases. Do not c
76193
76177
  - Exit with a design outline the user can skim in under two minutes.
76194
76178
 
76195
76179
  **Phase 5: SPEC WRITE + SELF-REVIEW (architect + reviewer).**
76196
- - Generate \`.swarm/spec.md\` following the same SPEC CONTENT RULES that MODE: SPECIFY uses: WHAT/WHY only, no tech stack, no implementation details, FR-### / SC-### numbering, Given/When/Then scenarios, \`[NEEDS CLARIFICATION]\` markers (max 3).
76180
+ - Delegate substantial spec drafting to \`{{AGENT_PREFIX}}spec_writer\` with the chosen design, dialogue notes, SME context, and SPEC CONTENT RULES. The spec writer must persist \`.swarm/spec.md\` through \`spec_write\`.
76181
+ - The spec must follow the same SPEC CONTENT RULES that MODE: SPECIFY uses: WHAT/WHY only, no tech stack, no implementation details, FR-### / SC-### numbering, Given/When/Then scenarios, \`[NEEDS CLARIFICATION]\` markers (max 3).
76197
76182
  - Cross-reference design sections by name where relevant context helps (but keep HOW out of the spec).
76198
76183
  - Delegate to \`{{AGENT_PREFIX}}reviewer\` for an independent review of the draft spec. Reviewer must flag: requirements that encode HOW, untestable requirements, missing edge cases, silent assumptions.
76199
76184
  - Apply reviewer feedback. If reviewer rejects, iterate once and re-review. After two rounds, surface remaining disagreements to the user.
76200
- - Write the final spec to \`.swarm/spec.md\`.
76185
+ - Read back and lint the final spec after \`{{AGENT_PREFIX}}spec_writer\` writes it.
76201
76186
  - Exit when reviewer signs off (or user explicitly accepts remaining disagreements).
76202
76187
 
76203
76188
  **Phase 6: QA GATE SELECTION (architect, dialogue only).**
@@ -76269,7 +76254,7 @@ Activates when: user asks to "specify", "define requirements", "write a spec", o
76269
76254
  1b. Run CODEBASE REALITY CHECK for any codebase references mentioned by the user or implied by the feature. Skip if work is purely greenfield (no existing codebase to check). Report discrepancies before proceeding to explorer.
76270
76255
  2. Delegate to \`{{AGENT_PREFIX}}explorer\` to scan the codebase for relevant context (existing patterns, related code, affected areas).
76271
76256
  3. Delegate to \`{{AGENT_PREFIX}}sme\` for domain research on the feature area to surface known constraints, best practices, and integration concerns.
76272
- 4. Generate \`.swarm/spec.md\` capturing:
76257
+ 4. Delegate substantial spec drafting to \`{{AGENT_PREFIX}}spec_writer\`. Include the user requirements, explorer findings, SME constraints, and these required contents:
76273
76258
  - First line must be: \`# Specification: <feature-name>\`
76274
76259
  - Feature description: WHAT users need and WHY — never HOW to implement
76275
76260
  - User scenarios with acceptance criteria (Given/When/Then format)
@@ -76278,7 +76263,7 @@ Activates when: user asks to "specify", "define requirements", "write a spec", o
76278
76263
  - Key entities if data is involved (no schema or field definitions — entity names only)
76279
76264
  - Edge cases and known failure modes
76280
76265
  - \`[NEEDS CLARIFICATION]\` markers (max 3) for items where uncertainty could change scope, security, or core behavior; prefer informed defaults over asking
76281
- 5. Write the spec to \`.swarm/spec.md\`.
76266
+ 5. Require \`{{AGENT_PREFIX}}spec_writer\` to write the spec via \`spec_write\`, then read back and lint \`.swarm/spec.md\`.
76282
76267
  5b. **QA GATE SELECTION (dialogue only).**
76283
76268
  {{QA_GATE_DIALOGUE_SPECIFY}}
76284
76269
 
@@ -79481,8 +79466,24 @@ function createSwarmAgents(swarmId, swarmConfig, isDefault, pluginConfig, projec
79481
79466
  const swarmIdentity = isDefault ? "default" : swarmId;
79482
79467
  const agentPrefix = prefix;
79483
79468
  architect.config.prompt = architect.config.prompt?.replace(/\{\{SWARM_ID\}\}/g, swarmIdentity).replace(/\{\{AGENT_PREFIX\}\}/g, agentPrefix).replace(/\{\{QA_RETRY_LIMIT\}\}/g, String(qaRetryLimit)).replace(/\{\{PROJECT_LANGUAGE\}\}/g, projectContext.PROJECT_LANGUAGE).replace(/\{\{PROJECT_FRAMEWORK\}\}/g, projectContext.PROJECT_FRAMEWORK).replace(/\{\{BUILD_CMD\}\}/g, projectContext.BUILD_CMD).replace(/\{\{TEST_CMD\}\}/g, projectContext.TEST_CMD).replace(/\{\{LINT_CMD\}\}/g, projectContext.LINT_CMD).replace(/\{\{ENTRY_POINTS\}\}/g, projectContext.ENTRY_POINTS).replace(/\{\{CODER_CONSTRAINTS\}\}/g, projectContext.CODER_CONSTRAINTS).replace(/\{\{TEST_CONSTRAINTS\}\}/g, projectContext.TEST_CONSTRAINTS).replace(/\{\{REVIEWER_CHECKLIST\}\}/g, projectContext.REVIEWER_CHECKLIST).replace(/\{\{PROJECT_CONTEXT_SECONDARY_LANGUAGES\}\}/g, projectContext.PROJECT_CONTEXT_SECONDARY_LANGUAGES);
79469
+ const skillImproverEnabled = !isAgentDisabled("skill_improver", swarmAgents, swarmPrefix);
79470
+ const specWriterEnabled = !isAgentDisabled("spec_writer", swarmAgents, swarmPrefix);
79471
+ if (!skillImproverEnabled) {
79472
+ architect.config.prompt = architect.config.prompt?.replace(`, ${agentPrefix}skill_improver`, "").replace(`
79473
+ ${agentPrefix}skill_improver - Low-frequency skill / knowledge / prompt improvement adviser`, "").replace(/\n## SKILL IMPROVER[\s\S]*?(?=\n\n## SPEC WRITER)/, "");
79474
+ }
79475
+ if (!specWriterEnabled) {
79476
+ const escapedAgentPrefix = agentPrefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
79477
+ architect.config.prompt = architect.config.prompt?.replace(`, ${agentPrefix}spec_writer`, "").replace(`
79478
+ ${agentPrefix}spec_writer - .swarm/spec.md authoring via spec_write`, "").replace(/\n## SPEC WRITER[\s\S]*?(?=\n\n### ANTI-RATIONALIZATION)/, "").replace(new RegExp(`- Delegate substantial spec drafting to \`${escapedAgentPrefix}spec_writer\`[^\\n]*\\n`, "g"), "- spec_writer is disabled. Ask the user to enable the spec_writer agent before creating or revising `.swarm/spec.md`.\n").replace(new RegExp(`4\\. Delegate substantial spec drafting to \`${escapedAgentPrefix}spec_writer\`[^\\n]*`), "4. spec_writer is disabled. Ask the user to enable the spec_writer agent before creating or revising `.swarm/spec.md`.").replace(new RegExp(`5\\. Require \`${escapedAgentPrefix}spec_writer\` to write the spec via \`spec_write\`, then read back and lint \`\\.swarm/spec\\.md\`\\.`), "5. Do not continue SPECIFY until spec_writer is available.").replace(new RegExp(`- Read back and lint the final spec after \`${escapedAgentPrefix}spec_writer\` writes it\\.`), "- Do not continue BRAINSTORM spec writing until spec_writer is available.");
79479
+ }
79484
79480
  if (!isDefault) {
79485
79481
  architect.description = `[${swarmName}] ${architect.description}`;
79482
+ const optionalAgentLines = [
79483
+ skillImproverEnabled ? `- @${swarmId}_skill_improver (not @skill_improver)` : undefined,
79484
+ specWriterEnabled ? `- @${swarmId}_spec_writer (not @spec_writer)` : undefined
79485
+ ].filter((line) => Boolean(line)).join(`
79486
+ `);
79486
79487
  const swarmHeader = `## ⚠️ YOU ARE THE ${swarmName.toUpperCase()} SWARM ARCHITECT
79487
79488
 
79488
79489
  Your swarm ID is "${swarmId}". ALL your agents have the "${swarmId}_" prefix:
@@ -79490,7 +79491,8 @@ Your swarm ID is "${swarmId}". ALL your agents have the "${swarmId}_" prefix:
79490
79491
  - @${swarmId}_coder (not @coder)
79491
79492
  - @${swarmId}_sme (not @sme)
79492
79493
  - @${swarmId}_reviewer (not @reviewer)
79493
- - etc.
79494
+ ${optionalAgentLines ? `${optionalAgentLines}
79495
+ ` : ""}- etc.
79494
79496
 
79495
79497
  CRITICAL: Agents without the "${swarmId}_" prefix DO NOT EXIST or belong to a DIFFERENT swarm.
79496
79498
  If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the wrong swarm.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.29.0",
3
+ "version": "7.29.1",
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",