opencode-swarm 6.42.1 → 6.43.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.
@@ -0,0 +1,14 @@
1
+ import type { AgentDefinition } from './architect';
2
+ export type CuratorRole = 'curator_init' | 'curator_phase';
3
+ /**
4
+ * Create a Curator agent definition for the given role.
5
+ *
6
+ * Follows the same pattern as createCriticAgent:
7
+ * - Two named variants: curator_init and curator_phase
8
+ * - Each carries its own baked-in system prompt so the correct agent is
9
+ * resolved by name in any swarm (default or prefixed)
10
+ * - customPrompt replaces the default prompt entirely; customAppendPrompt
11
+ * appends to the role-specific default (same semantics as createCriticAgent)
12
+ * - Read-only tool config: write/edit/patch all false
13
+ */
14
+ export declare function createCuratorAgent(model: string, customPrompt?: string, customAppendPrompt?: string, role?: CuratorRole): AgentDefinition;
@@ -1,3 +1,5 @@
1
1
  import type { AgentDefinition } from './architect';
2
+ export declare const CURATOR_INIT_PROMPT = "## IDENTITY\nYou are Explorer in CURATOR_INIT mode. You consolidate prior session knowledge into an architect briefing.\nDO NOT use the Task tool to delegate. You ARE the agent that does the work.\n\nINPUT FORMAT:\nTASK: CURATOR_INIT\nPRIOR_SUMMARY: [JSON or \"none\"]\nKNOWLEDGE_ENTRIES: [JSON array of high-confidence entries]\nPROJECT_CONTEXT: [context.md excerpt]\n\nACTIONS:\n- Read the prior summary to understand session history\n- Cross-reference knowledge entries against project context\n- Identify contradictions (knowledge says X, project state shows Y)\n- Produce a concise briefing for the architect\n\nRULES:\n- Output under 2000 chars\n- No code modifications\n- Flag contradictions explicitly with CONTRADICTION: prefix\n- If no prior summary exists, state \"First session \u2014 no prior context\"\n\nOUTPUT FORMAT:\nBRIEFING:\n[concise summary of prior session state, key decisions, active blockers]\n\nCONTRADICTIONS:\n- [entry_id]: [description] (or \"None detected\")\n\nKNOWLEDGE_STATS:\n- Entries reviewed: [N]\n- Prior phases covered: [N]\n";
3
+ export declare const CURATOR_PHASE_PROMPT = "## IDENTITY\nYou are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.\nDO NOT use the Task tool to delegate. You ARE the agent that does the work.\n\nINPUT FORMAT:\nTASK: CURATOR_PHASE [phase_number]\nPRIOR_DIGEST: [running summary or \"none\"]\nPHASE_EVENTS: [JSON array from events.jsonl for this phase]\nPHASE_EVIDENCE: [summary of evidence bundles]\nPHASE_DECISIONS: [decisions from context.md]\nAGENTS_DISPATCHED: [list]\nAGENTS_EXPECTED: [list from config]\n\nACTIONS:\n- Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)\n- Identify workflow deviations: missing reviewer, missing retro, skipped test_engineer\n- Recommend knowledge updates: entries to promote, archive, or flag as contradicted\n- Summarize key decisions and blockers resolved\n\nRULES:\n- Output under 2000 chars\n- No code modifications\n- Compliance observations are READ-ONLY \u2014 report, do not enforce\n- Extend the digest, never replace it\n\nOUTPUT FORMAT:\nPHASE_DIGEST:\nphase: [N]\nsummary: [what was accomplished]\nagents_used: [list]\ntasks_completed: [N]/[total]\nkey_decisions: [list]\nblockers_resolved: [list]\n\nCOMPLIANCE:\n- [type]: [description] (or \"No deviations observed\")\n\nKNOWLEDGE_UPDATES:\n- [action] [entry_id or \"new\"]: [reason] (or \"No recommendations\")\n\nEXTENDED_DIGEST:\n[the full running digest with this phase appended]\n";
2
4
  export declare function createExplorerAgent(model: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
3
5
  export declare function createExplorerCuratorAgent(model: string, mode: 'CURATOR_INIT' | 'CURATOR_PHASE', customAppendPrompt?: string): AgentDefinition;
@@ -37,6 +37,7 @@ export declare function getAgentConfigs(config?: PluginConfig): Record<string, S
37
37
  export { createArchitectAgent } from './architect';
38
38
  export { createCoderAgent } from './coder';
39
39
  export { createCriticAgent } from './critic';
40
+ export { createCuratorAgent } from './curator-agent';
40
41
  export { createDesignerAgent } from './designer';
41
42
  export { createDocsAgent } from './docs';
42
43
  export { createExplorerAgent } from './explorer';
package/dist/cli/index.js CHANGED
@@ -17654,6 +17654,8 @@ var ALL_SUBAGENT_NAMES = [
17654
17654
  "designer",
17655
17655
  "critic_sounding_board",
17656
17656
  "critic_drift_verifier",
17657
+ "curator_init",
17658
+ "curator_phase",
17657
17659
  ...QA_AGENTS,
17658
17660
  ...PIPELINE_AGENTS
17659
17661
  ];
@@ -17806,7 +17808,9 @@ var AGENT_TOOL_MAP = {
17806
17808
  "retrieve_summary",
17807
17809
  "symbols",
17808
17810
  "knowledgeRecall"
17809
- ]
17811
+ ],
17812
+ curator_init: ["knowledgeRecall"],
17813
+ curator_phase: ["knowledgeRecall"]
17810
17814
  };
17811
17815
  for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
17812
17816
  const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
@@ -18513,6 +18517,8 @@ var swarmState = {
18513
18517
  delegationChains: new Map,
18514
18518
  pendingEvents: 0,
18515
18519
  opencodeClient: null,
18520
+ curatorInitAgentNames: [],
18521
+ curatorPhaseAgentNames: [],
18516
18522
  lastBudgetPct: 0,
18517
18523
  agentSessions: new Map,
18518
18524
  pendingRehydrations: new Set
@@ -2,8 +2,8 @@ import type { ToolName } from '../tools/tool-names';
2
2
  export declare const QA_AGENTS: readonly ["reviewer", "critic"];
3
3
  export declare const PIPELINE_AGENTS: readonly ["explorer", "coder", "test_engineer"];
4
4
  export declare const ORCHESTRATOR_NAME: "architect";
5
- export declare const ALL_SUBAGENT_NAMES: readonly ["sme", "docs", "designer", "critic_sounding_board", "critic_drift_verifier", "reviewer", "critic", "explorer", "coder", "test_engineer"];
6
- export declare const ALL_AGENT_NAMES: readonly ["architect", "sme", "docs", "designer", "critic_sounding_board", "critic_drift_verifier", "reviewer", "critic", "explorer", "coder", "test_engineer"];
5
+ export declare const ALL_SUBAGENT_NAMES: readonly ["sme", "docs", "designer", "critic_sounding_board", "critic_drift_verifier", "curator_init", "curator_phase", "reviewer", "critic", "explorer", "coder", "test_engineer"];
6
+ export declare const ALL_AGENT_NAMES: readonly ["architect", "sme", "docs", "designer", "critic_sounding_board", "critic_drift_verifier", "curator_init", "curator_phase", "reviewer", "critic", "explorer", "coder", "test_engineer"];
7
7
  export type QAAgentName = (typeof QA_AGENTS)[number];
8
8
  export type PipelineAgentName = (typeof PIPELINE_AGENTS)[number];
9
9
  export type AgentName = (typeof ALL_AGENT_NAMES)[number];
@@ -1,11 +1,20 @@
1
1
  import type { CuratorLLMDelegate } from './curator.js';
2
2
  /**
3
3
  * Create a CuratorLLMDelegate that uses the opencode SDK to call
4
- * the Explorer agent in CURATOR_INIT or CURATOR_PHASE mode.
4
+ * the registered curator agent in CURATOR_INIT or CURATOR_PHASE mode.
5
5
  *
6
6
  * Uses an ephemeral session (create → prompt → delete) to avoid
7
7
  * re-entrancy with the current session's message flow.
8
8
  *
9
+ * The `mode` parameter determines which registered named agent is used:
10
+ * - 'init' → curator_init (e.g. 'curator_init' or 'swarm1_curator_init')
11
+ * - 'phase' → curator_phase (e.g. 'curator_phase' or 'swarm1_curator_phase')
12
+ *
13
+ * The optional `sessionId` parameter enables deterministic swarm resolution:
14
+ * when provided, the factory uses the calling session's registered agent to
15
+ * identify the swarm prefix, rather than scanning all active sessions.
16
+ * Pass `ctx?.sessionID` from tool handlers that have it available.
17
+ *
9
18
  * Returns undefined if swarmState.opencodeClient is not set (e.g. in unit tests).
10
19
  */
11
- export declare function createCuratorLLMDelegate(directory: string): CuratorLLMDelegate | undefined;
20
+ export declare function createCuratorLLMDelegate(directory: string, mode?: 'init' | 'phase', sessionId?: string): CuratorLLMDelegate | undefined;
@@ -10,7 +10,7 @@ export { createGuardrailsHooks } from './guardrails';
10
10
  export { classifyMessage, classifyMessages, containsPlanContent, isDuplicateToolRead, isStaleError, isToolResult, MessagePriority, type MessagePriorityType, type MessageWithParts, } from './message-priority';
11
11
  export { consolidateSystemMessages } from './messages-transform';
12
12
  export { extractModelInfo, NATIVE_MODEL_LIMITS, PROVIDER_CAPS, resolveModelLimit, } from './model-limits';
13
- export { createPhaseMonitorHook } from './phase-monitor';
13
+ export { type CuratorDelegateFactory, createPhaseMonitorHook, } from './phase-monitor';
14
14
  export { createPipelineTrackerHook } from './pipeline-tracker';
15
15
  export { buildApprovedReceipt, buildReceiptContextForDrift, buildRejectedReceipt, persistReviewReceipt, readAllReceipts, readReceiptsByScopeHash, } from './review-receipt';
16
16
  export { createSystemEnhancerHook } from './system-enhancer';
@@ -10,6 +10,8 @@ import { type CuratorLLMDelegate } from './curator';
10
10
  import type { CuratorConfig, CuratorInitResult } from './curator-types';
11
11
  /** Injectable curator runner type — allows test injection without module mocking. */
12
12
  export type CuratorInitRunner = (directory: string, config: CuratorConfig, llmDelegate?: CuratorLLMDelegate) => Promise<CuratorInitResult>;
13
+ /** Factory that creates a CuratorLLMDelegate for a given session — enables session-aware resolution. */
14
+ export type CuratorDelegateFactory = (sessionId?: string) => CuratorLLMDelegate | undefined;
13
15
  /**
14
16
  * Creates a hook that monitors plan phase transitions and triggers preflight.
15
17
  *
@@ -18,6 +20,10 @@ export type CuratorInitRunner = (directory: string, config: CuratorConfig, llmDe
18
20
  * When undefined, preflight checks are skipped but curator initialization still runs
19
21
  * at session start (useful when knowledge.enabled but phase_preflight is disabled).
20
22
  * @param curatorRunner - Optional curator init runner (defaults to runCuratorInit; injectable for tests)
23
+ * @param delegateFactory - Optional factory that creates a CuratorLLMDelegate for the calling session.
24
+ * Called lazily at hook invocation time with the session ID extracted from the hook input,
25
+ * enabling correct multi-swarm curator resolution. For test injection of a pre-built delegate,
26
+ * pass `() => myDelegate`.
21
27
  * @returns A safeHook-wrapped system.transform handler
22
28
  */
23
- export declare function createPhaseMonitorHook(directory: string, preflightManager?: PreflightTriggerManager, curatorRunner?: CuratorInitRunner, llmDelegate?: CuratorLLMDelegate): (input: unknown, output: unknown) => Promise<void>;
29
+ export declare function createPhaseMonitorHook(directory: string, preflightManager?: PreflightTriggerManager, curatorRunner?: CuratorInitRunner, delegateFactory?: CuratorDelegateFactory): (input: unknown, output: unknown) => Promise<void>;
package/dist/index.js CHANGED
@@ -143,6 +143,8 @@ var init_constants = __esm(() => {
143
143
  "designer",
144
144
  "critic_sounding_board",
145
145
  "critic_drift_verifier",
146
+ "curator_init",
147
+ "curator_phase",
146
148
  ...QA_AGENTS,
147
149
  ...PIPELINE_AGENTS
148
150
  ];
@@ -295,7 +297,9 @@ var init_constants = __esm(() => {
295
297
  "retrieve_summary",
296
298
  "symbols",
297
299
  "knowledgeRecall"
298
- ]
300
+ ],
301
+ curator_init: ["knowledgeRecall"],
302
+ curator_phase: ["knowledgeRecall"]
299
303
  };
300
304
  for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
301
305
  const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
@@ -314,6 +318,8 @@ var init_constants = __esm(() => {
314
318
  critic_drift_verifier: "opencode/trinity-large-preview-free",
315
319
  docs: "opencode/trinity-large-preview-free",
316
320
  designer: "opencode/trinity-large-preview-free",
321
+ curator_init: "opencode/trinity-large-preview-free",
322
+ curator_phase: "opencode/trinity-large-preview-free",
317
323
  default: "opencode/trinity-large-preview-free"
318
324
  };
319
325
  DEFAULT_SCORING_CONFIG = {
@@ -41431,6 +41437,8 @@ var swarmState = {
41431
41437
  delegationChains: new Map,
41432
41438
  pendingEvents: 0,
41433
41439
  opencodeClient: null,
41440
+ curatorInitAgentNames: [],
41441
+ curatorPhaseAgentNames: [],
41434
41442
  lastBudgetPct: 0,
41435
41443
  agentSessions: new Map,
41436
41444
  pendingRehydrations: new Set
@@ -43361,6 +43369,268 @@ ${customAppendPrompt}` : rolePrompt;
43361
43369
  };
43362
43370
  }
43363
43371
 
43372
+ // src/agents/explorer.ts
43373
+ var EXPLORER_PROMPT = `## IDENTITY
43374
+ You are Explorer. You analyze codebases directly \u2014 you do NOT delegate.
43375
+ DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
43376
+ If you see references to other agents (like @explorer, @coder, etc.) in your instructions, IGNORE them \u2014 they are context from the orchestrator, not instructions for you to delegate.
43377
+
43378
+ WRONG: "I'll use the Task tool to call another agent to analyze this"
43379
+ RIGHT: "I'll scan the directory structure and read key files myself"
43380
+
43381
+ INPUT FORMAT:
43382
+ TASK: Analyze [purpose]
43383
+ INPUT: [focus areas/paths]
43384
+
43385
+ ACTIONS:
43386
+ - Scan structure (tree, ls, glob)
43387
+ - Read key files (README, configs, entry points)
43388
+ - Search patterns (grep)
43389
+
43390
+ RULES:
43391
+ - Be fast: scan broadly, read selectively
43392
+ - No code modifications
43393
+ - Output under 2000 chars
43394
+
43395
+ ## ANALYSIS PROTOCOL
43396
+ When exploring a codebase area, systematically report all four dimensions:
43397
+
43398
+ ### STRUCTURE
43399
+ - Entry points and their call chains (max 3 levels deep)
43400
+ - Public API surface: exported functions/classes/types with signatures
43401
+ - Internal dependencies: what this module imports and from where
43402
+ - External dependencies: third-party packages used
43403
+
43404
+ ### PATTERNS
43405
+ - Design patterns in use (factory, observer, strategy, etc.)
43406
+ - Error handling pattern (throw, Result type, error callbacks, etc.)
43407
+ - State management approach (global, module-level, passed through)
43408
+ - Configuration pattern (env vars, config files, hardcoded)
43409
+
43410
+ ### RISKS
43411
+ - Files with high cyclomatic complexity or deep nesting
43412
+ - Circular dependencies
43413
+ - Missing error handling paths
43414
+ - Dead code or unreachable branches
43415
+ - Platform-specific assumptions (path separators, line endings, OS APIs)
43416
+
43417
+ ### RELEVANT CONTEXT FOR TASK
43418
+ - Existing tests that cover this area (paths and what they test)
43419
+ - Related documentation files
43420
+ - Similar implementations elsewhere in the codebase that should be consistent
43421
+
43422
+ OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
43423
+ Begin directly with PROJECT. Do NOT prepend "Here's my analysis..." or any conversational preamble.
43424
+
43425
+ PROJECT: [name/type]
43426
+ LANGUAGES: [list]
43427
+ FRAMEWORK: [if any]
43428
+
43429
+ STRUCTURE:
43430
+ [key directories, 5-10 lines max]
43431
+
43432
+ KEY FILES:
43433
+ - [path]: [purpose]
43434
+
43435
+ PATTERNS: [observations]
43436
+
43437
+ DOMAINS: [relevant SME domains: powershell, security, python, etc.]
43438
+
43439
+ REVIEW NEEDED:
43440
+ - [path]: [why, which SME]
43441
+
43442
+ ## INTEGRATION IMPACT ANALYSIS MODE
43443
+ Activates when delegated with "Integration impact analysis" or INPUT lists contract changes.
43444
+
43445
+ INPUT: List of contract changes (from diff tool output \u2014 changed exports, signatures, types)
43446
+
43447
+ STEPS:
43448
+ 1. For each changed export: grep the codebase for imports and usages of that symbol
43449
+ 2. Classify each change: BREAKING (callers must update) or COMPATIBLE (callers unaffected)
43450
+ 3. List all files that import or use the changed exports
43451
+
43452
+ OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
43453
+ Begin directly with BREAKING_CHANGES. Do NOT prepend conversational preamble.
43454
+
43455
+ BREAKING_CHANGES: [list with affected consumer files, or "none"]
43456
+ COMPATIBLE_CHANGES: [list, or "none"]
43457
+ CONSUMERS_AFFECTED: [list of files that import/use changed exports, or "none"]
43458
+ VERDICT: BREAKING | COMPATIBLE
43459
+ MIGRATION_NEEDED: [yes \u2014 description of required caller updates | no]
43460
+
43461
+ ## DOCUMENTATION DISCOVERY MODE
43462
+ Activates automatically during codebase reality check at plan ingestion.
43463
+ Use the doc_scan tool to scan and index documentation files. If doc_scan is unavailable, fall back to manual globbing.
43464
+
43465
+ STEPS:
43466
+ 1. Call doc_scan to build the manifest, OR glob for documentation files:
43467
+ - Root: README.md, CONTRIBUTING.md, CHANGELOG.md, ARCHITECTURE.md, CLAUDE.md, AGENTS.md, .github/*.md
43468
+ - docs/**/*.md, doc/**/*.md (one level deep only)
43469
+
43470
+ 2. For each file found, read the first 30 lines. Extract:
43471
+ - path: relative to project root
43472
+ - title: first # heading, or filename if no heading
43473
+ - summary: first non-empty paragraph after the title (max 200 chars, use the ACTUAL text, do NOT summarize with your own words)
43474
+ - lines: total line count
43475
+ - mtime: file modification timestamp
43476
+
43477
+ 3. Write manifest to .swarm/doc-manifest.json:
43478
+ { "schema_version": 1, "scanned_at": "ISO timestamp", "files": [...] }
43479
+
43480
+ 4. For each file in the manifest, check relevance to the current plan:
43481
+ - Score by keyword overlap: do any task file paths or directory names appear in the doc's path or summary?
43482
+ - For files scoring > 0, read the full content and extract up to 5 actionable constraints per doc (max 200 chars each)
43483
+ - Write constraints to .swarm/knowledge/doc-constraints.jsonl as knowledge entries with source: "doc-scan", category: "architecture"
43484
+
43485
+ 5. Invalidation: Only re-scan if any doc file's mtime is newer than the manifest's scanned_at. Otherwise reuse the cached manifest.
43486
+
43487
+ RULES:
43488
+ - The manifest must be small (<100 lines). Pointers only, not full content.
43489
+ - Do NOT rephrase or summarize doc content with your own words \u2014 use the actual text from the file
43490
+ - Full doc content is only loaded when relevant to the current task, never preloaded
43491
+ `;
43492
+ var CURATOR_INIT_PROMPT = `## IDENTITY
43493
+ You are Explorer in CURATOR_INIT mode. You consolidate prior session knowledge into an architect briefing.
43494
+ DO NOT use the Task tool to delegate. You ARE the agent that does the work.
43495
+
43496
+ INPUT FORMAT:
43497
+ TASK: CURATOR_INIT
43498
+ PRIOR_SUMMARY: [JSON or "none"]
43499
+ KNOWLEDGE_ENTRIES: [JSON array of high-confidence entries]
43500
+ PROJECT_CONTEXT: [context.md excerpt]
43501
+
43502
+ ACTIONS:
43503
+ - Read the prior summary to understand session history
43504
+ - Cross-reference knowledge entries against project context
43505
+ - Identify contradictions (knowledge says X, project state shows Y)
43506
+ - Produce a concise briefing for the architect
43507
+
43508
+ RULES:
43509
+ - Output under 2000 chars
43510
+ - No code modifications
43511
+ - Flag contradictions explicitly with CONTRADICTION: prefix
43512
+ - If no prior summary exists, state "First session \u2014 no prior context"
43513
+
43514
+ OUTPUT FORMAT:
43515
+ BRIEFING:
43516
+ [concise summary of prior session state, key decisions, active blockers]
43517
+
43518
+ CONTRADICTIONS:
43519
+ - [entry_id]: [description] (or "None detected")
43520
+
43521
+ KNOWLEDGE_STATS:
43522
+ - Entries reviewed: [N]
43523
+ - Prior phases covered: [N]
43524
+ `;
43525
+ var CURATOR_PHASE_PROMPT = `## IDENTITY
43526
+ You are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.
43527
+ DO NOT use the Task tool to delegate. You ARE the agent that does the work.
43528
+
43529
+ INPUT FORMAT:
43530
+ TASK: CURATOR_PHASE [phase_number]
43531
+ PRIOR_DIGEST: [running summary or "none"]
43532
+ PHASE_EVENTS: [JSON array from events.jsonl for this phase]
43533
+ PHASE_EVIDENCE: [summary of evidence bundles]
43534
+ PHASE_DECISIONS: [decisions from context.md]
43535
+ AGENTS_DISPATCHED: [list]
43536
+ AGENTS_EXPECTED: [list from config]
43537
+
43538
+ ACTIONS:
43539
+ - Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)
43540
+ - Identify workflow deviations: missing reviewer, missing retro, skipped test_engineer
43541
+ - Recommend knowledge updates: entries to promote, archive, or flag as contradicted
43542
+ - Summarize key decisions and blockers resolved
43543
+
43544
+ RULES:
43545
+ - Output under 2000 chars
43546
+ - No code modifications
43547
+ - Compliance observations are READ-ONLY \u2014 report, do not enforce
43548
+ - Extend the digest, never replace it
43549
+
43550
+ OUTPUT FORMAT:
43551
+ PHASE_DIGEST:
43552
+ phase: [N]
43553
+ summary: [what was accomplished]
43554
+ agents_used: [list]
43555
+ tasks_completed: [N]/[total]
43556
+ key_decisions: [list]
43557
+ blockers_resolved: [list]
43558
+
43559
+ COMPLIANCE:
43560
+ - [type]: [description] (or "No deviations observed")
43561
+
43562
+ KNOWLEDGE_UPDATES:
43563
+ - [action] [entry_id or "new"]: [reason] (or "No recommendations")
43564
+
43565
+ EXTENDED_DIGEST:
43566
+ [the full running digest with this phase appended]
43567
+ `;
43568
+ function createExplorerAgent(model, customPrompt, customAppendPrompt) {
43569
+ let prompt = EXPLORER_PROMPT;
43570
+ if (customPrompt) {
43571
+ prompt = customPrompt;
43572
+ } else if (customAppendPrompt) {
43573
+ prompt = `${EXPLORER_PROMPT}
43574
+
43575
+ ${customAppendPrompt}`;
43576
+ }
43577
+ return {
43578
+ name: "explorer",
43579
+ description: "Fast codebase discovery and analysis. Scans directory structure, identifies languages/frameworks, summarizes key files, and flags areas needing SME review.",
43580
+ config: {
43581
+ model,
43582
+ temperature: 0.1,
43583
+ prompt,
43584
+ tools: {
43585
+ write: false,
43586
+ edit: false,
43587
+ patch: false
43588
+ }
43589
+ }
43590
+ };
43591
+ }
43592
+
43593
+ // src/agents/curator-agent.ts
43594
+ var ROLE_CONFIG = {
43595
+ curator_init: {
43596
+ name: "curator_init",
43597
+ description: "Curator (Init). Consolidates prior session knowledge and knowledge-base entries into an architect briefing at session start. Read-only.",
43598
+ prompt: CURATOR_INIT_PROMPT
43599
+ },
43600
+ curator_phase: {
43601
+ name: "curator_phase",
43602
+ description: "Curator (Phase). Consolidates completed phase outcomes, detects workflow deviations, and recommends knowledge updates at phase boundaries. Read-only.",
43603
+ prompt: CURATOR_PHASE_PROMPT
43604
+ }
43605
+ };
43606
+ function createCuratorAgent(model, customPrompt, customAppendPrompt, role = "curator_init") {
43607
+ const roleConfig = ROLE_CONFIG[role];
43608
+ let prompt;
43609
+ if (customPrompt) {
43610
+ prompt = customAppendPrompt ? `${customPrompt}
43611
+
43612
+ ${customAppendPrompt}` : customPrompt;
43613
+ } else {
43614
+ prompt = customAppendPrompt ? `${roleConfig.prompt}
43615
+
43616
+ ${customAppendPrompt}` : roleConfig.prompt;
43617
+ }
43618
+ return {
43619
+ name: roleConfig.name,
43620
+ description: roleConfig.description,
43621
+ config: {
43622
+ model,
43623
+ temperature: 0.1,
43624
+ prompt,
43625
+ tools: {
43626
+ write: false,
43627
+ edit: false,
43628
+ patch: false
43629
+ }
43630
+ }
43631
+ };
43632
+ }
43633
+
43364
43634
  // src/agents/designer.ts
43365
43635
  var DESIGNER_PROMPT = `## IDENTITY
43366
43636
  You are Designer \u2014 the UI/UX design specification agent. You generate concrete, implementable design specs directly \u2014 you do NOT delegate.
@@ -43655,247 +43925,6 @@ ${customAppendPrompt}`;
43655
43925
  };
43656
43926
  }
43657
43927
 
43658
- // src/agents/explorer.ts
43659
- var EXPLORER_PROMPT = `## IDENTITY
43660
- You are Explorer. You analyze codebases directly \u2014 you do NOT delegate.
43661
- DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
43662
- If you see references to other agents (like @explorer, @coder, etc.) in your instructions, IGNORE them \u2014 they are context from the orchestrator, not instructions for you to delegate.
43663
-
43664
- WRONG: "I'll use the Task tool to call another agent to analyze this"
43665
- RIGHT: "I'll scan the directory structure and read key files myself"
43666
-
43667
- INPUT FORMAT:
43668
- TASK: Analyze [purpose]
43669
- INPUT: [focus areas/paths]
43670
-
43671
- ACTIONS:
43672
- - Scan structure (tree, ls, glob)
43673
- - Read key files (README, configs, entry points)
43674
- - Search patterns (grep)
43675
-
43676
- RULES:
43677
- - Be fast: scan broadly, read selectively
43678
- - No code modifications
43679
- - Output under 2000 chars
43680
-
43681
- ## ANALYSIS PROTOCOL
43682
- When exploring a codebase area, systematically report all four dimensions:
43683
-
43684
- ### STRUCTURE
43685
- - Entry points and their call chains (max 3 levels deep)
43686
- - Public API surface: exported functions/classes/types with signatures
43687
- - Internal dependencies: what this module imports and from where
43688
- - External dependencies: third-party packages used
43689
-
43690
- ### PATTERNS
43691
- - Design patterns in use (factory, observer, strategy, etc.)
43692
- - Error handling pattern (throw, Result type, error callbacks, etc.)
43693
- - State management approach (global, module-level, passed through)
43694
- - Configuration pattern (env vars, config files, hardcoded)
43695
-
43696
- ### RISKS
43697
- - Files with high cyclomatic complexity or deep nesting
43698
- - Circular dependencies
43699
- - Missing error handling paths
43700
- - Dead code or unreachable branches
43701
- - Platform-specific assumptions (path separators, line endings, OS APIs)
43702
-
43703
- ### RELEVANT CONTEXT FOR TASK
43704
- - Existing tests that cover this area (paths and what they test)
43705
- - Related documentation files
43706
- - Similar implementations elsewhere in the codebase that should be consistent
43707
-
43708
- OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
43709
- Begin directly with PROJECT. Do NOT prepend "Here's my analysis..." or any conversational preamble.
43710
-
43711
- PROJECT: [name/type]
43712
- LANGUAGES: [list]
43713
- FRAMEWORK: [if any]
43714
-
43715
- STRUCTURE:
43716
- [key directories, 5-10 lines max]
43717
-
43718
- KEY FILES:
43719
- - [path]: [purpose]
43720
-
43721
- PATTERNS: [observations]
43722
-
43723
- DOMAINS: [relevant SME domains: powershell, security, python, etc.]
43724
-
43725
- REVIEW NEEDED:
43726
- - [path]: [why, which SME]
43727
-
43728
- ## INTEGRATION IMPACT ANALYSIS MODE
43729
- Activates when delegated with "Integration impact analysis" or INPUT lists contract changes.
43730
-
43731
- INPUT: List of contract changes (from diff tool output \u2014 changed exports, signatures, types)
43732
-
43733
- STEPS:
43734
- 1. For each changed export: grep the codebase for imports and usages of that symbol
43735
- 2. Classify each change: BREAKING (callers must update) or COMPATIBLE (callers unaffected)
43736
- 3. List all files that import or use the changed exports
43737
-
43738
- OUTPUT FORMAT (MANDATORY \u2014 deviations will be rejected):
43739
- Begin directly with BREAKING_CHANGES. Do NOT prepend conversational preamble.
43740
-
43741
- BREAKING_CHANGES: [list with affected consumer files, or "none"]
43742
- COMPATIBLE_CHANGES: [list, or "none"]
43743
- CONSUMERS_AFFECTED: [list of files that import/use changed exports, or "none"]
43744
- VERDICT: BREAKING | COMPATIBLE
43745
- MIGRATION_NEEDED: [yes \u2014 description of required caller updates | no]
43746
-
43747
- ## DOCUMENTATION DISCOVERY MODE
43748
- Activates automatically during codebase reality check at plan ingestion.
43749
- Use the doc_scan tool to scan and index documentation files. If doc_scan is unavailable, fall back to manual globbing.
43750
-
43751
- STEPS:
43752
- 1. Call doc_scan to build the manifest, OR glob for documentation files:
43753
- - Root: README.md, CONTRIBUTING.md, CHANGELOG.md, ARCHITECTURE.md, CLAUDE.md, AGENTS.md, .github/*.md
43754
- - docs/**/*.md, doc/**/*.md (one level deep only)
43755
-
43756
- 2. For each file found, read the first 30 lines. Extract:
43757
- - path: relative to project root
43758
- - title: first # heading, or filename if no heading
43759
- - summary: first non-empty paragraph after the title (max 200 chars, use the ACTUAL text, do NOT summarize with your own words)
43760
- - lines: total line count
43761
- - mtime: file modification timestamp
43762
-
43763
- 3. Write manifest to .swarm/doc-manifest.json:
43764
- { "schema_version": 1, "scanned_at": "ISO timestamp", "files": [...] }
43765
-
43766
- 4. For each file in the manifest, check relevance to the current plan:
43767
- - Score by keyword overlap: do any task file paths or directory names appear in the doc's path or summary?
43768
- - For files scoring > 0, read the full content and extract up to 5 actionable constraints per doc (max 200 chars each)
43769
- - Write constraints to .swarm/knowledge/doc-constraints.jsonl as knowledge entries with source: "doc-scan", category: "architecture"
43770
-
43771
- 5. Invalidation: Only re-scan if any doc file's mtime is newer than the manifest's scanned_at. Otherwise reuse the cached manifest.
43772
-
43773
- RULES:
43774
- - The manifest must be small (<100 lines). Pointers only, not full content.
43775
- - Do NOT rephrase or summarize doc content with your own words \u2014 use the actual text from the file
43776
- - Full doc content is only loaded when relevant to the current task, never preloaded
43777
- `;
43778
- var CURATOR_INIT_PROMPT = `## IDENTITY
43779
- You are Explorer in CURATOR_INIT mode. You consolidate prior session knowledge into an architect briefing.
43780
- DO NOT use the Task tool to delegate. You ARE the agent that does the work.
43781
-
43782
- INPUT FORMAT:
43783
- TASK: CURATOR_INIT
43784
- PRIOR_SUMMARY: [JSON or "none"]
43785
- KNOWLEDGE_ENTRIES: [JSON array of high-confidence entries]
43786
- PROJECT_CONTEXT: [context.md excerpt]
43787
-
43788
- ACTIONS:
43789
- - Read the prior summary to understand session history
43790
- - Cross-reference knowledge entries against project context
43791
- - Identify contradictions (knowledge says X, project state shows Y)
43792
- - Produce a concise briefing for the architect
43793
-
43794
- RULES:
43795
- - Output under 2000 chars
43796
- - No code modifications
43797
- - Flag contradictions explicitly with CONTRADICTION: prefix
43798
- - If no prior summary exists, state "First session \u2014 no prior context"
43799
-
43800
- OUTPUT FORMAT:
43801
- BRIEFING:
43802
- [concise summary of prior session state, key decisions, active blockers]
43803
-
43804
- CONTRADICTIONS:
43805
- - [entry_id]: [description] (or "None detected")
43806
-
43807
- KNOWLEDGE_STATS:
43808
- - Entries reviewed: [N]
43809
- - Prior phases covered: [N]
43810
- `;
43811
- var CURATOR_PHASE_PROMPT = `## IDENTITY
43812
- You are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.
43813
- DO NOT use the Task tool to delegate. You ARE the agent that does the work.
43814
-
43815
- INPUT FORMAT:
43816
- TASK: CURATOR_PHASE [phase_number]
43817
- PRIOR_DIGEST: [running summary or "none"]
43818
- PHASE_EVENTS: [JSON array from events.jsonl for this phase]
43819
- PHASE_EVIDENCE: [summary of evidence bundles]
43820
- PHASE_DECISIONS: [decisions from context.md]
43821
- AGENTS_DISPATCHED: [list]
43822
- AGENTS_EXPECTED: [list from config]
43823
-
43824
- ACTIONS:
43825
- - Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)
43826
- - Identify workflow deviations: missing reviewer, missing retro, skipped test_engineer
43827
- - Recommend knowledge updates: entries to promote, archive, or flag as contradicted
43828
- - Summarize key decisions and blockers resolved
43829
-
43830
- RULES:
43831
- - Output under 2000 chars
43832
- - No code modifications
43833
- - Compliance observations are READ-ONLY \u2014 report, do not enforce
43834
- - Extend the digest, never replace it
43835
-
43836
- OUTPUT FORMAT:
43837
- PHASE_DIGEST:
43838
- phase: [N]
43839
- summary: [what was accomplished]
43840
- agents_used: [list]
43841
- tasks_completed: [N]/[total]
43842
- key_decisions: [list]
43843
- blockers_resolved: [list]
43844
-
43845
- COMPLIANCE:
43846
- - [type]: [description] (or "No deviations observed")
43847
-
43848
- KNOWLEDGE_UPDATES:
43849
- - [action] [entry_id or "new"]: [reason] (or "No recommendations")
43850
-
43851
- EXTENDED_DIGEST:
43852
- [the full running digest with this phase appended]
43853
- `;
43854
- function createExplorerAgent(model, customPrompt, customAppendPrompt) {
43855
- let prompt = EXPLORER_PROMPT;
43856
- if (customPrompt) {
43857
- prompt = customPrompt;
43858
- } else if (customAppendPrompt) {
43859
- prompt = `${EXPLORER_PROMPT}
43860
-
43861
- ${customAppendPrompt}`;
43862
- }
43863
- return {
43864
- name: "explorer",
43865
- description: "Fast codebase discovery and analysis. Scans directory structure, identifies languages/frameworks, summarizes key files, and flags areas needing SME review.",
43866
- config: {
43867
- model,
43868
- temperature: 0.1,
43869
- prompt,
43870
- tools: {
43871
- write: false,
43872
- edit: false,
43873
- patch: false
43874
- }
43875
- }
43876
- };
43877
- }
43878
- function createExplorerCuratorAgent(model, mode, customAppendPrompt) {
43879
- const basePrompt = mode === "CURATOR_INIT" ? CURATOR_INIT_PROMPT : CURATOR_PHASE_PROMPT;
43880
- const prompt = customAppendPrompt ? `${basePrompt}
43881
-
43882
- ${customAppendPrompt}` : basePrompt;
43883
- return {
43884
- name: "explorer",
43885
- description: `Explorer in ${mode} mode \u2014 consolidates context at phase boundaries.`,
43886
- config: {
43887
- model,
43888
- temperature: 0.1,
43889
- prompt,
43890
- tools: {
43891
- write: false,
43892
- edit: false,
43893
- patch: false
43894
- }
43895
- }
43896
- };
43897
- }
43898
-
43899
43928
  // src/agents/reviewer.ts
43900
43929
  var REVIEWER_PROMPT = `## PRESSURE IMMUNITY
43901
43930
 
@@ -44519,6 +44548,18 @@ If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the
44519
44548
  critic.name = prefixName("critic_drift_verifier");
44520
44549
  agents.push(applyOverrides(critic, swarmAgents, swarmPrefix));
44521
44550
  }
44551
+ if (!isAgentDisabled("curator_init", swarmAgents, swarmPrefix)) {
44552
+ const curatorInitPrompts = getPrompts("curator_init");
44553
+ const curatorInit = createCuratorAgent(swarmAgents?.curator_init?.model ?? getModel("curator_init"), curatorInitPrompts.prompt, curatorInitPrompts.appendPrompt, "curator_init");
44554
+ curatorInit.name = prefixName("curator_init");
44555
+ agents.push(applyOverrides(curatorInit, swarmAgents, swarmPrefix));
44556
+ }
44557
+ if (!isAgentDisabled("curator_phase", swarmAgents, swarmPrefix)) {
44558
+ const curatorPhasePrompts = getPrompts("curator_phase");
44559
+ const curatorPhase = createCuratorAgent(swarmAgents?.curator_phase?.model ?? getModel("curator_phase"), curatorPhasePrompts.prompt, curatorPhasePrompts.appendPrompt, "curator_phase");
44560
+ curatorPhase.name = prefixName("curator_phase");
44561
+ agents.push(applyOverrides(curatorPhase, swarmAgents, swarmPrefix));
44562
+ }
44522
44563
  if (!isAgentDisabled("test_engineer", swarmAgents, swarmPrefix)) {
44523
44564
  const testPrompts = getPrompts("test_engineer");
44524
44565
  const testEngineer = createTestEngineerAgent(getModel("test_engineer"), testPrompts.prompt, testPrompts.appendPrompt);
@@ -47786,7 +47827,6 @@ async function runCuratorInit(directory, config3, llmDelegate) {
47786
47827
  `);
47787
47828
  if (llmDelegate) {
47788
47829
  try {
47789
- const curatorAgent = createExplorerCuratorAgent("default", "CURATOR_INIT");
47790
47830
  const userInput = [
47791
47831
  "TASK: CURATOR_INIT",
47792
47832
  `PRIOR_SUMMARY: ${priorSummary ? JSON.stringify(priorSummary) : "none"}`,
@@ -47794,7 +47834,7 @@ async function runCuratorInit(directory, config3, llmDelegate) {
47794
47834
  `PROJECT_CONTEXT: ${contextMd?.slice(0, config3.max_summary_tokens * 2) ?? "none"}`
47795
47835
  ].join(`
47796
47836
  `);
47797
- const systemPrompt = curatorAgent.config.prompt ?? "";
47837
+ const systemPrompt = CURATOR_INIT_PROMPT;
47798
47838
  const llmOutput = await Promise.race([
47799
47839
  llmDelegate(systemPrompt, userInput),
47800
47840
  new Promise((_, reject) => setTimeout(() => reject(new Error("CURATOR_LLM_TIMEOUT")), CURATOR_LLM_TIMEOUT_MS))
@@ -47877,9 +47917,8 @@ async function runCuratorPhase(directory, phase, agentsDispatched, _config, _kno
47877
47917
  let knowledgeRecommendations = [];
47878
47918
  if (llmDelegate) {
47879
47919
  try {
47880
- const curatorAgent = createExplorerCuratorAgent("default", "CURATOR_PHASE");
47881
47920
  const priorDigest = priorSummary?.digest ?? "none";
47882
- const systemPrompt = curatorAgent.config.prompt ?? "";
47921
+ const systemPrompt = CURATOR_PHASE_PROMPT;
47883
47922
  const userInput = [
47884
47923
  `TASK: CURATOR_PHASE ${phase}`,
47885
47924
  `PRIOR_DIGEST: ${priorDigest}`,
@@ -52369,11 +52408,54 @@ function maskToolOutput(msg, _threshold) {
52369
52408
  return freedTokens;
52370
52409
  }
52371
52410
  // src/hooks/curator-llm-factory.ts
52372
- function createCuratorLLMDelegate(directory) {
52411
+ function resolveCuratorAgentName(mode, sessionId) {
52412
+ const suffix = mode === "init" ? "curator_init" : "curator_phase";
52413
+ const registeredNames = mode === "init" ? swarmState.curatorInitAgentNames : swarmState.curatorPhaseAgentNames;
52414
+ if (registeredNames.length === 1)
52415
+ return registeredNames[0];
52416
+ if (registeredNames.length === 0)
52417
+ return suffix;
52418
+ const prefixMap = new Map;
52419
+ for (const name2 of registeredNames) {
52420
+ const prefix = name2.endsWith(suffix) ? name2.slice(0, name2.length - suffix.length) : "";
52421
+ prefixMap.set(prefix, name2);
52422
+ }
52423
+ const matchForAgent = (agentName) => {
52424
+ let bestPrefix = "";
52425
+ let bestName = "";
52426
+ for (const [prefix, name2] of prefixMap) {
52427
+ if (prefix && agentName.startsWith(prefix)) {
52428
+ if (prefix.length > bestPrefix.length) {
52429
+ bestPrefix = prefix;
52430
+ bestName = name2;
52431
+ }
52432
+ }
52433
+ }
52434
+ return bestName;
52435
+ };
52436
+ if (sessionId) {
52437
+ const callingAgent = swarmState.activeAgent.get(sessionId);
52438
+ if (callingAgent) {
52439
+ const match = matchForAgent(callingAgent);
52440
+ if (match)
52441
+ return match;
52442
+ const defaultCurator = prefixMap.get("");
52443
+ if (defaultCurator)
52444
+ return defaultCurator;
52445
+ }
52446
+ }
52447
+ for (const activeAgentName of swarmState.activeAgent.values()) {
52448
+ const match = matchForAgent(activeAgentName);
52449
+ if (match)
52450
+ return match;
52451
+ }
52452
+ return prefixMap.get("") ?? registeredNames[0];
52453
+ }
52454
+ function createCuratorLLMDelegate(directory, mode = "init", sessionId) {
52373
52455
  const client = swarmState.opencodeClient;
52374
52456
  if (!client)
52375
52457
  return;
52376
- return async (systemPrompt, userInput) => {
52458
+ return async (_systemPrompt, userInput) => {
52377
52459
  let ephemeralSessionId;
52378
52460
  try {
52379
52461
  const createResult = await client.session.create({
@@ -52383,10 +52465,11 @@ function createCuratorLLMDelegate(directory) {
52383
52465
  throw new Error(`Failed to create curator session: ${JSON.stringify(createResult.error)}`);
52384
52466
  }
52385
52467
  ephemeralSessionId = createResult.data.id;
52468
+ const agentName = resolveCuratorAgentName(mode, sessionId);
52386
52469
  const promptResult = await client.session.prompt({
52387
52470
  path: { id: ephemeralSessionId },
52388
52471
  body: {
52389
- system: systemPrompt,
52472
+ agent: agentName,
52390
52473
  tools: { write: false, edit: false, patch: false },
52391
52474
  parts: [{ type: "text", text: userInput }]
52392
52475
  }
@@ -54428,10 +54511,11 @@ init_schema();
54428
54511
  init_manager2();
54429
54512
  import * as path37 from "path";
54430
54513
  init_utils2();
54431
- function createPhaseMonitorHook(directory, preflightManager, curatorRunner, llmDelegate) {
54514
+ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, delegateFactory) {
54432
54515
  let lastKnownPhase = null;
54433
- const handler = async (_input, _output) => {
54516
+ const handler = async (input, _output) => {
54434
54517
  const runner = curatorRunner ?? runCuratorInit;
54518
+ const sessionId = typeof input === "object" && input !== null ? input.sessionID : undefined;
54435
54519
  const plan = await loadPlan(directory);
54436
54520
  if (!plan)
54437
54521
  return;
@@ -54443,6 +54527,7 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, llmD
54443
54527
  const { config: config3 } = loadPluginConfigWithMeta2(directory);
54444
54528
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
54445
54529
  if (curatorConfig.enabled && curatorConfig.init_enabled) {
54530
+ const llmDelegate = delegateFactory?.(sessionId);
54446
54531
  const initResult = await runner(directory, curatorConfig, llmDelegate);
54447
54532
  if (initResult.briefing) {
54448
54533
  const briefingPath = path37.join(directory, ".swarm", "curator-briefing.md");
@@ -59172,7 +59257,7 @@ var curator_analyze = createSwarmTool({
59172
59257
  reason: tool.schema.string()
59173
59258
  })).optional().describe("Knowledge recommendations to apply. If omitted, only collects digest data.")
59174
59259
  },
59175
- execute: async (args2, directory) => {
59260
+ execute: async (args2, directory, ctx) => {
59176
59261
  const typedArgs = args2;
59177
59262
  try {
59178
59263
  if (!Number.isInteger(typedArgs.phase) || typedArgs.phase < 1) {
@@ -59191,7 +59276,7 @@ var curator_analyze = createSwarmTool({
59191
59276
  const { config: config3 } = loadPluginConfigWithMeta(directory);
59192
59277
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
59193
59278
  const knowledgeConfig = KnowledgeConfigSchema.parse(config3.knowledge ?? {});
59194
- const llmDelegate = createCuratorLLMDelegate(directory);
59279
+ const llmDelegate = createCuratorLLMDelegate(directory, "phase", ctx?.sessionID);
59195
59280
  const curatorResult = await runCuratorPhase(directory, typedArgs.phase, [], curatorConfig, {}, llmDelegate);
59196
59281
  {
59197
59282
  const scopeContent = curatorResult.digest?.summary ?? `Phase ${typedArgs.phase} curator analysis`;
@@ -61755,7 +61840,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
61755
61840
  try {
61756
61841
  const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
61757
61842
  if (curatorConfig.enabled && curatorConfig.phase_enabled) {
61758
- const llmDelegate = createCuratorLLMDelegate(dir);
61843
+ const llmDelegate = createCuratorLLMDelegate(dir, "phase", sessionID ?? undefined);
61759
61844
  const curatorResult = await runCuratorPhase(dir, phase, agentsDispatched, curatorConfig, {}, llmDelegate);
61760
61845
  {
61761
61846
  const scopeContent = curatorResult.digest?.summary ?? `Phase ${phase} curator analysis`;
@@ -68182,6 +68267,8 @@ var OpenCodeSwarm = async (ctx) => {
68182
68267
  initTelemetry(ctx.directory);
68183
68268
  const agents = getAgentConfigs(config3);
68184
68269
  const agentDefinitions = createAgents(config3);
68270
+ swarmState.curatorInitAgentNames = Object.keys(agents).filter((k) => k === "curator_init" || k.endsWith("_curator_init"));
68271
+ swarmState.curatorPhaseAgentNames = Object.keys(agents).filter((k) => k === "curator_phase" || k.endsWith("_curator_phase"));
68185
68272
  const pipelineHook = createPipelineTrackerHook(config3, ctx.directory);
68186
68273
  const systemEnhancerHook = createSystemEnhancerHook(config3, ctx.directory);
68187
68274
  const compactionHook = createCompactionCustomizerHook(config3, ctx.directory);
@@ -68620,7 +68707,7 @@ var OpenCodeSwarm = async (ctx) => {
68620
68707
  } catch {}
68621
68708
  return Promise.resolve();
68622
68709
  },
68623
- automationConfig.capabilities?.phase_preflight === true && preflightTriggerManager ? createPhaseMonitorHook(ctx.directory, preflightTriggerManager, undefined, createCuratorLLMDelegate(ctx.directory)) : knowledgeConfig.enabled ? createPhaseMonitorHook(ctx.directory, undefined, undefined, createCuratorLLMDelegate(ctx.directory)) : undefined
68710
+ automationConfig.capabilities?.phase_preflight === true && preflightTriggerManager ? createPhaseMonitorHook(ctx.directory, preflightTriggerManager, undefined, (sessionId) => createCuratorLLMDelegate(ctx.directory, "init", sessionId)) : knowledgeConfig.enabled ? createPhaseMonitorHook(ctx.directory, undefined, undefined, (sessionId) => createCuratorLLMDelegate(ctx.directory, "init", sessionId)) : undefined
68624
68711
  ].filter(Boolean)),
68625
68712
  "experimental.session.compacting": compactionHook["experimental.session.compacting"],
68626
68713
  "command.execute.before": safeHook(commandHandler),
package/dist/state.d.ts CHANGED
@@ -190,6 +190,13 @@ export declare const swarmState: {
190
190
  pendingEvents: number;
191
191
  /** SDK client — set at plugin init for curator LLM delegation */
192
192
  opencodeClient: OpencodeClient | null;
193
+ /** All registered curator agent names across all swarms (with their swarm prefix).
194
+ * e.g. ['curator_init'] for a single default swarm, or
195
+ * ['swarm1_curator_init', 'swarm2_curator_init', ...] for multiple named swarms.
196
+ * Set at plugin init after agents are built. The factory resolves the correct
197
+ * name at call time by matching the active session's agent prefix. */
198
+ curatorInitAgentNames: string[];
199
+ curatorPhaseAgentNames: string[];
193
200
  /** Last known context budget percentage (0-100), updated by system-enhancer */
194
201
  lastBudgetPct: number;
195
202
  /** Per-session guardrail state — keyed by sessionID */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.42.1",
3
+ "version": "6.43.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",