opencode-swarm 6.37.0 → 6.39.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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -5,7 +5,7 @@
5
5
  * Events flow through the system without external dependencies.
6
6
  */
7
7
  /** Automation event types */
8
- export type AutomationEventType = 'queue.item.enqueued' | 'queue.item.dequeued' | 'queue.item.completed' | 'queue.item.failed' | 'queue.item.retry scheduled' | 'worker.started' | 'worker.stopped' | 'worker.error' | 'circuit.breaker.opened' | 'circuit.breaker.half-open' | 'circuit.breaker.closed' | 'loop.protection.triggered' | 'automation.started' | 'automation.stopped' | 'preflight.requested' | 'preflight.triggered' | 'preflight.skipped' | 'preflight.completed' | 'phase.boundary.detected' | 'phase.status.checked' | 'task.completed' | 'evidence.summary.generated' | 'evidence.summary.error' | 'curator.init.completed' | 'curator.phase.completed' | 'curator.drift.completed' | 'curator.error';
8
+ export type AutomationEventType = 'queue.item.enqueued' | 'queue.item.dequeued' | 'queue.item.completed' | 'queue.item.failed' | 'queue.item.retry scheduled' | 'worker.started' | 'worker.stopped' | 'worker.error' | 'circuit.breaker.opened' | 'circuit.breaker.half-open' | 'circuit.breaker.closed' | 'loop.protection.triggered' | 'automation.started' | 'automation.stopped' | 'preflight.requested' | 'preflight.triggered' | 'preflight.skipped' | 'preflight.completed' | 'phase.boundary.detected' | 'phase.status.checked' | 'task.completed' | 'evidence.summary.generated' | 'evidence.summary.error' | 'curator.init.completed' | 'curator.init.llm_completed' | 'curator.init.llm_fallback' | 'curator.phase.completed' | 'curator.phase.llm_completed' | 'curator.phase.llm_fallback' | 'curator.drift.completed' | 'curator.error';
9
9
  /** Base automation event */
10
10
  export interface AutomationEvent<T = unknown> {
11
11
  type: AutomationEventType;
package/dist/cli/index.js CHANGED
@@ -5,43 +5,25 @@ var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- function __accessProp(key) {
9
- return this[key];
10
- }
11
- var __toESMCache_node;
12
- var __toESMCache_esm;
13
8
  var __toESM = (mod, isNodeMode, target) => {
14
- var canCache = mod != null && typeof mod === "object";
15
- if (canCache) {
16
- var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
- var cached = cache.get(mod);
18
- if (cached)
19
- return cached;
20
- }
21
9
  target = mod != null ? __create(__getProtoOf(mod)) : {};
22
10
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
23
11
  for (let key of __getOwnPropNames(mod))
24
12
  if (!__hasOwnProp.call(to, key))
25
13
  __defProp(to, key, {
26
- get: __accessProp.bind(mod, key),
14
+ get: () => mod[key],
27
15
  enumerable: true
28
16
  });
29
- if (canCache)
30
- cache.set(mod, to);
31
17
  return to;
32
18
  };
33
19
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
- var __returnValue = (v) => v;
35
- function __exportSetter(name, newValue) {
36
- this[name] = __returnValue.bind(null, newValue);
37
- }
38
20
  var __export = (target, all) => {
39
21
  for (var name in all)
40
22
  __defProp(target, name, {
41
23
  get: all[name],
42
24
  enumerable: true,
43
25
  configurable: true,
44
- set: __exportSetter.bind(all, name)
26
+ set: (newValue) => all[name] = () => newValue
45
27
  });
46
28
  };
47
29
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -17620,7 +17602,13 @@ var TOOL_NAMES = [
17620
17602
  "update_task_status",
17621
17603
  "write_retro",
17622
17604
  "declare_scope",
17623
- "knowledge_query"
17605
+ "knowledge_query",
17606
+ "doc_scan",
17607
+ "doc_extract",
17608
+ "curator_analyze",
17609
+ "knowledgeAdd",
17610
+ "knowledgeRecall",
17611
+ "knowledgeRemove"
17624
17612
  ];
17625
17613
  var TOOL_NAME_SET = new Set(TOOL_NAMES);
17626
17614
 
@@ -17645,6 +17633,7 @@ var AGENT_TOOL_MAP = {
17645
17633
  architect: [
17646
17634
  "checkpoint",
17647
17635
  "check_gate_status",
17636
+ "completion_verify",
17648
17637
  "complexity_hotspots",
17649
17638
  "detect_domains",
17650
17639
  "evidence_check",
@@ -17656,6 +17645,7 @@ var AGENT_TOOL_MAP = {
17656
17645
  "diff",
17657
17646
  "pkg_audit",
17658
17647
  "pre_check_batch",
17648
+ "quality_budget",
17659
17649
  "retrieve_summary",
17660
17650
  "save_plan",
17661
17651
  "schema_drift",
@@ -17665,7 +17655,19 @@ var AGENT_TOOL_MAP = {
17665
17655
  "todo_extract",
17666
17656
  "update_task_status",
17667
17657
  "write_retro",
17668
- "declare_scope"
17658
+ "declare_scope",
17659
+ "sast_scan",
17660
+ "sbom_generate",
17661
+ "build_check",
17662
+ "syntax_check",
17663
+ "placeholder_scan",
17664
+ "phase_complete",
17665
+ "doc_scan",
17666
+ "doc_extract",
17667
+ "curator_analyze",
17668
+ "knowledgeAdd",
17669
+ "knowledgeRecall",
17670
+ "knowledgeRemove"
17669
17671
  ],
17670
17672
  explorer: [
17671
17673
  "complexity_hotspots",
@@ -17676,7 +17678,9 @@ var AGENT_TOOL_MAP = {
17676
17678
  "retrieve_summary",
17677
17679
  "schema_drift",
17678
17680
  "symbols",
17679
- "todo_extract"
17681
+ "todo_extract",
17682
+ "doc_scan",
17683
+ "knowledgeRecall"
17680
17684
  ],
17681
17685
  coder: [
17682
17686
  "diff",
@@ -17684,7 +17688,11 @@ var AGENT_TOOL_MAP = {
17684
17688
  "lint",
17685
17689
  "symbols",
17686
17690
  "extract_code_blocks",
17687
- "retrieve_summary"
17691
+ "retrieve_summary",
17692
+ "build_check",
17693
+ "syntax_check",
17694
+ "knowledgeAdd",
17695
+ "knowledgeRecall"
17688
17696
  ],
17689
17697
  test_engineer: [
17690
17698
  "test_runner",
@@ -17694,7 +17702,9 @@ var AGENT_TOOL_MAP = {
17694
17702
  "retrieve_summary",
17695
17703
  "imports",
17696
17704
  "complexity_hotspots",
17697
- "pkg_audit"
17705
+ "pkg_audit",
17706
+ "build_check",
17707
+ "syntax_check"
17698
17708
  ],
17699
17709
  sme: [
17700
17710
  "complexity_hotspots",
@@ -17703,7 +17713,8 @@ var AGENT_TOOL_MAP = {
17703
17713
  "imports",
17704
17714
  "retrieve_summary",
17705
17715
  "schema_drift",
17706
- "symbols"
17716
+ "symbols",
17717
+ "knowledgeRecall"
17707
17718
  ],
17708
17719
  reviewer: [
17709
17720
  "diff",
@@ -17716,28 +17727,34 @@ var AGENT_TOOL_MAP = {
17716
17727
  "complexity_hotspots",
17717
17728
  "retrieve_summary",
17718
17729
  "extract_code_blocks",
17719
- "test_runner"
17730
+ "test_runner",
17731
+ "sast_scan",
17732
+ "placeholder_scan",
17733
+ "knowledgeRecall"
17720
17734
  ],
17721
17735
  critic: [
17722
17736
  "complexity_hotspots",
17723
17737
  "detect_domains",
17724
17738
  "imports",
17725
17739
  "retrieve_summary",
17726
- "symbols"
17740
+ "symbols",
17741
+ "knowledgeRecall"
17727
17742
  ],
17728
17743
  critic_sounding_board: [
17729
17744
  "complexity_hotspots",
17730
17745
  "detect_domains",
17731
17746
  "imports",
17732
17747
  "retrieve_summary",
17733
- "symbols"
17748
+ "symbols",
17749
+ "knowledgeRecall"
17734
17750
  ],
17735
17751
  critic_drift_verifier: [
17736
17752
  "complexity_hotspots",
17737
17753
  "detect_domains",
17738
17754
  "imports",
17739
17755
  "retrieve_summary",
17740
- "symbols"
17756
+ "symbols",
17757
+ "knowledgeRecall"
17741
17758
  ],
17742
17759
  docs: [
17743
17760
  "detect_domains",
@@ -17747,9 +17764,15 @@ var AGENT_TOOL_MAP = {
17747
17764
  "retrieve_summary",
17748
17765
  "schema_drift",
17749
17766
  "symbols",
17750
- "todo_extract"
17767
+ "todo_extract",
17768
+ "knowledgeRecall"
17751
17769
  ],
17752
- designer: ["extract_code_blocks", "retrieve_summary", "symbols"]
17770
+ designer: [
17771
+ "extract_code_blocks",
17772
+ "retrieve_summary",
17773
+ "symbols",
17774
+ "knowledgeRecall"
17775
+ ]
17753
17776
  };
17754
17777
  for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
17755
17778
  const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
@@ -18185,7 +18208,7 @@ var KnowledgeConfigSchema = exports_external.object({
18185
18208
  max_encounter_score: exports_external.number().min(1).max(20).default(10)
18186
18209
  });
18187
18210
  var CuratorConfigSchema = exports_external.object({
18188
- enabled: exports_external.boolean().default(false),
18211
+ enabled: exports_external.boolean().default(true),
18189
18212
  init_enabled: exports_external.boolean().default(true),
18190
18213
  phase_enabled: exports_external.boolean().default(true),
18191
18214
  max_summary_tokens: exports_external.number().min(500).max(8000).default(2000),
@@ -35947,6 +35970,38 @@ var build_discovery = tool({
35947
35970
 
35948
35971
  // src/tools/lint.ts
35949
35972
  init_utils();
35973
+
35974
+ // src/utils/path-security.ts
35975
+ function containsPathTraversal(str) {
35976
+ if (/\.\.[/\\]/.test(str))
35977
+ return true;
35978
+ if (/(?:^|[/\\])\.\.(?:[/\\]|$)/.test(str))
35979
+ return true;
35980
+ if (/%2e%2e/i.test(str))
35981
+ return true;
35982
+ if (/%2e\./i.test(str))
35983
+ return true;
35984
+ if (/%2e/i.test(str) && /\.\./.test(str))
35985
+ return true;
35986
+ if (/%252e%252e/i.test(str))
35987
+ return true;
35988
+ if (/\uff0e/.test(str))
35989
+ return true;
35990
+ if (/\u3002/.test(str))
35991
+ return true;
35992
+ if (/\uff65/.test(str))
35993
+ return true;
35994
+ if (/%2f/i.test(str))
35995
+ return true;
35996
+ if (/%5c/i.test(str))
35997
+ return true;
35998
+ return false;
35999
+ }
36000
+ function containsControlChars(str) {
36001
+ return /[\0\t\r\n]/.test(str);
36002
+ }
36003
+
36004
+ // src/tools/lint.ts
35950
36005
  var MAX_OUTPUT_BYTES = 512000;
35951
36006
  var MAX_COMMAND_LENGTH = 500;
35952
36007
  function validateArgs(args) {
@@ -36516,19 +36571,6 @@ function isHighEntropyString(str) {
36516
36571
  const entropy = calculateShannonEntropy(str);
36517
36572
  return entropy > 4;
36518
36573
  }
36519
- function containsPathTraversal(str) {
36520
- if (/\.\.[/\\]/.test(str))
36521
- return true;
36522
- if (/[/\\]\.\.$/.test(str) || str === "..")
36523
- return true;
36524
- if (/\.\.[/\\]/.test(path18.normalize(str.replace(/\*/g, "x"))))
36525
- return true;
36526
- if (str.includes("%2e%2e") || str.includes("%2E%2E"))
36527
- return true;
36528
- if (str.includes("..") && /%2e/i.test(str))
36529
- return true;
36530
- return false;
36531
- }
36532
36574
  function validateExcludePattern(exc) {
36533
36575
  if (exc.length === 0)
36534
36576
  return null;
@@ -36581,9 +36623,6 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
36581
36623
  }
36582
36624
  return false;
36583
36625
  }
36584
- function containsControlChars(str) {
36585
- return /[\0\t\r\n]/.test(str);
36586
- }
36587
36626
  function validateDirectoryInput(dir) {
36588
36627
  if (!dir || dir.length === 0) {
36589
36628
  return "directory is required";
@@ -37024,31 +37063,6 @@ var MAX_COMMAND_LENGTH2 = 500;
37024
37063
  var DEFAULT_TIMEOUT_MS = 60000;
37025
37064
  var MAX_TIMEOUT_MS = 300000;
37026
37065
  var MAX_SAFE_TEST_FILES = 50;
37027
- function containsPathTraversal2(str) {
37028
- if (/\.\.[/\\]/.test(str))
37029
- return true;
37030
- if (/(?:^|[/\\])\.\.(?:[/\\]|$)/.test(str))
37031
- return true;
37032
- if (/%2e%2e/i.test(str))
37033
- return true;
37034
- if (/%2e\./i.test(str))
37035
- return true;
37036
- if (/%2e/i.test(str) && /\.\./.test(str))
37037
- return true;
37038
- if (/%252e%252e/i.test(str))
37039
- return true;
37040
- if (/\uff0e/.test(str))
37041
- return true;
37042
- if (/\u3002/.test(str))
37043
- return true;
37044
- if (/\uff65/.test(str))
37045
- return true;
37046
- if (/%2f/i.test(str))
37047
- return true;
37048
- if (/%5c/i.test(str))
37049
- return true;
37050
- return false;
37051
- }
37052
37066
  function isAbsolutePath(str) {
37053
37067
  if (str.startsWith("/"))
37054
37068
  return true;
@@ -37060,9 +37074,6 @@ function isAbsolutePath(str) {
37060
37074
  return true;
37061
37075
  return false;
37062
37076
  }
37063
- function containsControlChars2(str) {
37064
- return /[\x00-\x08\x0a\x0b\x0c\x0d\x0e-\x1f\x7f\x80-\x9f]/.test(str);
37065
- }
37066
37077
  var POWERSHELL_METACHARACTERS = /[|;&`$(){}[\]<>"'#*?\x00-\x1f]/;
37067
37078
  function containsPowerShellMetacharacters(str) {
37068
37079
  return POWERSHELL_METACHARACTERS.test(str);
@@ -37084,9 +37095,9 @@ function validateArgs2(args) {
37084
37095
  return false;
37085
37096
  if (isAbsolutePath(f))
37086
37097
  return false;
37087
- if (containsPathTraversal2(f))
37098
+ if (containsPathTraversal(f))
37088
37099
  return false;
37089
- if (containsControlChars2(f))
37100
+ if (containsControlChars(f))
37090
37101
  return false;
37091
37102
  if (containsPowerShellMetacharacters(f))
37092
37103
  return false;
@@ -37909,7 +37920,7 @@ var test_runner = createSwarmTool({
37909
37920
  };
37910
37921
  return JSON.stringify(errorResult, null, 2);
37911
37922
  }
37912
- if (containsControlChars2(workingDir)) {
37923
+ if (containsControlChars(workingDir)) {
37913
37924
  const errorResult = {
37914
37925
  success: false,
37915
37926
  framework: "none",
@@ -37918,7 +37929,7 @@ var test_runner = createSwarmTool({
37918
37929
  };
37919
37930
  return JSON.stringify(errorResult, null, 2);
37920
37931
  }
37921
- if (containsPathTraversal2(workingDir)) {
37932
+ if (containsPathTraversal(workingDir)) {
37922
37933
  const errorResult = {
37923
37934
  success: false,
37924
37935
  framework: "none",
@@ -38,4 +38,13 @@ export declare function handleDebuggingSpiral(match: AdversarialPatternMatch, ta
38
38
  checkpointCreated: boolean;
39
39
  message: string;
40
40
  }>;
41
+ /**
42
+ * Record a tool call for debugging spiral detection.
43
+ * Call this from toolAfter to track repetitive patterns.
44
+ */
45
+ export declare function recordToolCall(tool: string, args: unknown): void;
46
+ /**
47
+ * Detect debugging spiral: same tool called 5+ times in a row with similar args
48
+ * within a 5-minute window. Indicates the agent is stuck in a loop.
49
+ */
41
50
  export declare function detectDebuggingSpiral(_directory: string): Promise<AdversarialPatternMatch | null>;
@@ -2,9 +2,25 @@
2
2
  * Curator core — file I/O for curator summary persistence.
3
3
  * Extended incrementally: filterPhaseEvents, checkPhaseCompliance,
4
4
  * runCuratorInit, runCuratorPhase, applyCuratorKnowledgeUpdates added in subsequent tasks.
5
+ *
6
+ * LLM delegation: runCuratorPhase and runCuratorInit accept an optional llmDelegate
7
+ * callback for LLM-based analysis. When provided, the prepared data context is sent
8
+ * to the explorer agent in CURATOR_PHASE/CURATOR_INIT mode for richer analysis.
9
+ * When the delegate is absent or fails, falls back to data-only behavior.
5
10
  */
6
11
  import type { ComplianceObservation, CuratorConfig, CuratorInitResult, CuratorPhaseResult, CuratorSummary, KnowledgeRecommendation } from './curator-types.js';
7
12
  import type { KnowledgeConfig } from './knowledge-types.js';
13
+ /**
14
+ * Optional LLM delegate callback type.
15
+ * Takes a system prompt and user input, returns the LLM output text.
16
+ * Used to delegate analysis to the explorer agent in CURATOR mode.
17
+ */
18
+ export type CuratorLLMDelegate = (systemPrompt: string, userInput: string) => Promise<string>;
19
+ /**
20
+ * Parse KNOWLEDGE_UPDATES section from curator LLM output.
21
+ * Expected format per line: "- [action] [entry_id or "new"]: [reason]"
22
+ */
23
+ export declare function parseKnowledgeRecommendations(llmOutput: string): KnowledgeRecommendation[];
8
24
  /**
9
25
  * Read curator summary from .swarm/curator-summary.json
10
26
  * @param directory - The workspace directory
@@ -36,26 +52,29 @@ export declare function filterPhaseEvents(eventsJsonl: string, phase: number, si
36
52
  export declare function checkPhaseCompliance(phaseEvents: object[], agentsDispatched: string[], requiredAgents: string[], phase: number): ComplianceObservation[];
37
53
  /**
38
54
  * Prepare curator init data: reads prior summary, knowledge entries, and context.md.
39
- * Returns a structured briefing result. Does NOT make LLM calls.
40
- * The caller (phase-monitor integration) is responsible for the actual agent delegation.
55
+ * When an llmDelegate is provided, delegates to the explorer agent in CURATOR_INIT mode
56
+ * for LLM-based analysis that enhances the data-only briefing.
41
57
  * @param directory - The workspace directory
42
58
  * @param config - Curator configuration
59
+ * @param llmDelegate - Optional LLM delegate for enhanced analysis
43
60
  * @returns CuratorInitResult with briefing text, contradictions, and stats
44
61
  */
45
- export declare function runCuratorInit(directory: string, config: CuratorConfig): Promise<CuratorInitResult>;
62
+ export declare function runCuratorInit(directory: string, config: CuratorConfig, llmDelegate?: CuratorLLMDelegate): Promise<CuratorInitResult>;
46
63
  /**
47
64
  * Run curator phase analysis: reads events, runs compliance, updates and writes summary.
48
- * Does NOT make LLM calls. The caller is responsible for agent delegation.
65
+ * When an llmDelegate is provided, delegates to the explorer agent in CURATOR_PHASE mode
66
+ * for LLM-based architectural drift analysis and knowledge recommendations.
49
67
  * @param directory - The workspace directory
50
68
  * @param phase - The phase number that just completed
51
69
  * @param agentsDispatched - List of agent names dispatched in this phase
52
70
  * @param config - Curator configuration
53
71
  * @param knowledgeConfig - Knowledge configuration (used for knowledge path resolution)
72
+ * @param llmDelegate - Optional LLM delegate for enhanced analysis
54
73
  * @returns CuratorPhaseResult with digest, compliance, and recommendations
55
74
  */
56
75
  export declare function runCuratorPhase(directory: string, phase: number, agentsDispatched: string[], _config: CuratorConfig, _knowledgeConfig: {
57
76
  directory?: string;
58
- }): Promise<CuratorPhaseResult>;
77
+ }, llmDelegate?: CuratorLLMDelegate): Promise<CuratorPhaseResult>;
59
78
  /**
60
79
  * Apply curator knowledge recommendations: promote, archive, or flag contradictions.
61
80
  * Uses readKnowledge + rewriteKnowledge pattern for atomic updates.
@@ -6,9 +6,10 @@
6
6
  * Wrapped in safeHook — errors must never propagate.
7
7
  */
8
8
  import type { PreflightTriggerManager } from '../background/trigger';
9
+ import { type CuratorLLMDelegate } from './curator';
9
10
  import type { CuratorConfig, CuratorInitResult } from './curator-types';
10
11
  /** Injectable curator runner type — allows test injection without module mocking. */
11
- export type CuratorInitRunner = (directory: string, config: CuratorConfig) => Promise<CuratorInitResult>;
12
+ export type CuratorInitRunner = (directory: string, config: CuratorConfig, llmDelegate?: CuratorLLMDelegate) => Promise<CuratorInitResult>;
12
13
  /**
13
14
  * Creates a hook that monitors plan phase transitions and triggers preflight.
14
15
  *