@claude-flow/shared 3.0.0-alpha.7 → 3.0.0-alpha.8

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.
Files changed (195) hide show
  1. package/.claude-flow/daemon-state.json +135 -0
  2. package/.claude-flow/data/pending-insights.jsonl +2 -0
  3. package/.claude-flow/data/ranked-context.json +5 -0
  4. package/.claude-flow/logs/daemon.log +45 -0
  5. package/.claude-flow/logs/headless/audit_1777379186972_h5un5x_prompt.log +3210 -0
  6. package/.claude-flow/logs/headless/audit_1777379186972_h5un5x_result.log +117 -0
  7. package/.claude-flow/logs/headless/audit_1777379816437_w0eaul_prompt.log +3210 -0
  8. package/.claude-flow/logs/headless/audit_1777379816437_w0eaul_result.log +53 -0
  9. package/.claude-flow/logs/headless/audit_1777380440097_621y8m_prompt.log +3210 -0
  10. package/.claude-flow/logs/headless/audit_1777380440097_621y8m_result.log +75 -0
  11. package/.claude-flow/logs/headless/optimize_1777379306973_an4lmy_prompt.log +3504 -0
  12. package/.claude-flow/logs/headless/optimize_1777379306973_an4lmy_result.log +166 -0
  13. package/.claude-flow/logs/headless/optimize_1777380274732_apxz3s_prompt.log +3504 -0
  14. package/.claude-flow/logs/headless/optimize_1777380274732_apxz3s_result.log +219 -0
  15. package/.claude-flow/logs/headless/testgaps_1777379546969_dvf2a1_prompt.log +3189 -0
  16. package/.claude-flow/logs/headless/testgaps_1777379546969_dvf2a1_result.log +155 -0
  17. package/.claude-flow/metrics/codebase-map.json +11 -0
  18. package/.claude-flow/metrics/consolidation.json +6 -0
  19. package/.claude-flow/sessions/current.json +13 -0
  20. package/.swarm/hnsw.index +0 -0
  21. package/.swarm/hnsw.metadata.json +1 -0
  22. package/.swarm/memory.db +0 -0
  23. package/.swarm/memory.db-shm +0 -0
  24. package/.swarm/memory.db-wal +0 -0
  25. package/.swarm/schema.sql +305 -0
  26. package/dist/core/config/schema.d.ts +96 -96
  27. package/dist/events/event-store.d.ts.map +1 -1
  28. package/dist/events/event-store.js +20 -9
  29. package/dist/events/event-store.js.map +1 -1
  30. package/dist/hooks/executor.d.ts.map +1 -1
  31. package/dist/hooks/executor.js +7 -4
  32. package/dist/hooks/executor.js.map +1 -1
  33. package/dist/hooks/verify-exports.test.js +6 -6
  34. package/dist/hooks/verify-exports.test.js.map +1 -1
  35. package/dist/mcp/server.d.ts.map +1 -1
  36. package/dist/mcp/server.js +3 -6
  37. package/dist/mcp/server.js.map +1 -1
  38. package/dist/mcp/types.d.ts +4 -6
  39. package/dist/mcp/types.d.ts.map +1 -1
  40. package/dist/mcp/types.js.map +1 -1
  41. package/package.json +3 -2
  42. package/ruvector.db +0 -0
  43. package/src/events/event-store.ts +18 -9
  44. package/src/hooks/executor.ts +7 -5
  45. package/src/hooks/verify-exports.test.ts +6 -6
  46. package/src/mcp/server.ts +3 -6
  47. package/src/mcp/types.ts +4 -6
  48. package/tsconfig.tsbuildinfo +1 -1
  49. package/.agentic-flow/intelligence.json +0 -16
  50. package/__tests__/coverage/base.css +0 -224
  51. package/__tests__/coverage/block-navigation.js +0 -87
  52. package/__tests__/coverage/coverage-final.json +0 -50
  53. package/__tests__/coverage/favicon.png +0 -0
  54. package/__tests__/coverage/index.html +0 -326
  55. package/__tests__/coverage/lcov-report/base.css +0 -224
  56. package/__tests__/coverage/lcov-report/block-navigation.js +0 -87
  57. package/__tests__/coverage/lcov-report/favicon.png +0 -0
  58. package/__tests__/coverage/lcov-report/index.html +0 -326
  59. package/__tests__/coverage/lcov-report/prettify.css +0 -1
  60. package/__tests__/coverage/lcov-report/prettify.js +0 -2
  61. package/__tests__/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  62. package/__tests__/coverage/lcov-report/sorter.js +0 -210
  63. package/__tests__/coverage/lcov-report/src/core/config/defaults.ts.html +0 -706
  64. package/__tests__/coverage/lcov-report/src/core/config/index.html +0 -161
  65. package/__tests__/coverage/lcov-report/src/core/config/loader.ts.html +0 -898
  66. package/__tests__/coverage/lcov-report/src/core/config/schema.ts.html +0 -649
  67. package/__tests__/coverage/lcov-report/src/core/config/validator.ts.html +0 -712
  68. package/__tests__/coverage/lcov-report/src/core/event-bus.ts.html +0 -793
  69. package/__tests__/coverage/lcov-report/src/core/index.html +0 -116
  70. package/__tests__/coverage/lcov-report/src/core/interfaces/event.interface.ts.html +0 -886
  71. package/__tests__/coverage/lcov-report/src/core/interfaces/index.html +0 -116
  72. package/__tests__/coverage/lcov-report/src/core/orchestrator/event-coordinator.ts.html +0 -451
  73. package/__tests__/coverage/lcov-report/src/core/orchestrator/health-monitor.ts.html +0 -727
  74. package/__tests__/coverage/lcov-report/src/core/orchestrator/index.html +0 -176
  75. package/__tests__/coverage/lcov-report/src/core/orchestrator/lifecycle-manager.ts.html +0 -874
  76. package/__tests__/coverage/lcov-report/src/core/orchestrator/session-manager.ts.html +0 -922
  77. package/__tests__/coverage/lcov-report/src/core/orchestrator/task-manager.ts.html +0 -1036
  78. package/__tests__/coverage/lcov-report/src/events/domain-events.ts.html +0 -1837
  79. package/__tests__/coverage/lcov-report/src/events/event-store.ts.html +0 -1849
  80. package/__tests__/coverage/lcov-report/src/events/example-usage.ts.html +0 -964
  81. package/__tests__/coverage/lcov-report/src/events/index.html +0 -176
  82. package/__tests__/coverage/lcov-report/src/events/projections.ts.html +0 -1768
  83. package/__tests__/coverage/lcov-report/src/events/state-reconstructor.ts.html +0 -1132
  84. package/__tests__/coverage/lcov-report/src/events.ts.html +0 -1186
  85. package/__tests__/coverage/lcov-report/src/hooks/example-usage.ts.html +0 -1582
  86. package/__tests__/coverage/lcov-report/src/hooks/executor.ts.html +0 -1222
  87. package/__tests__/coverage/lcov-report/src/hooks/index.html +0 -191
  88. package/__tests__/coverage/lcov-report/src/hooks/registry.ts.html +0 -1084
  89. package/__tests__/coverage/lcov-report/src/hooks/safety/bash-safety.ts.html +0 -1897
  90. package/__tests__/coverage/lcov-report/src/hooks/safety/file-organization.ts.html +0 -1504
  91. package/__tests__/coverage/lcov-report/src/hooks/safety/git-commit.ts.html +0 -1954
  92. package/__tests__/coverage/lcov-report/src/hooks/safety/index.html +0 -146
  93. package/__tests__/coverage/lcov-report/src/hooks/session-hooks.ts.html +0 -1762
  94. package/__tests__/coverage/lcov-report/src/hooks/task-hooks.ts.html +0 -1624
  95. package/__tests__/coverage/lcov-report/src/hooks/types.ts.html +0 -1156
  96. package/__tests__/coverage/lcov-report/src/index.html +0 -176
  97. package/__tests__/coverage/lcov-report/src/mcp/connection-pool.ts.html +0 -1399
  98. package/__tests__/coverage/lcov-report/src/mcp/index.html +0 -176
  99. package/__tests__/coverage/lcov-report/src/mcp/server.ts.html +0 -2407
  100. package/__tests__/coverage/lcov-report/src/mcp/session-manager.ts.html +0 -1369
  101. package/__tests__/coverage/lcov-report/src/mcp/tool-registry.ts.html +0 -1783
  102. package/__tests__/coverage/lcov-report/src/mcp/transport/http.ts.html +0 -1756
  103. package/__tests__/coverage/lcov-report/src/mcp/transport/index.html +0 -146
  104. package/__tests__/coverage/lcov-report/src/mcp/transport/stdio.ts.html +0 -1057
  105. package/__tests__/coverage/lcov-report/src/mcp/transport/websocket.ts.html +0 -1537
  106. package/__tests__/coverage/lcov-report/src/mcp/types.ts.html +0 -1780
  107. package/__tests__/coverage/lcov-report/src/plugin-interface.ts.html +0 -2074
  108. package/__tests__/coverage/lcov-report/src/plugin-loader.ts.html +0 -1999
  109. package/__tests__/coverage/lcov-report/src/plugin-registry.ts.html +0 -1897
  110. package/__tests__/coverage/lcov-report/src/plugins/official/hive-mind-plugin.ts.html +0 -1075
  111. package/__tests__/coverage/lcov-report/src/plugins/official/index.html +0 -131
  112. package/__tests__/coverage/lcov-report/src/plugins/official/maestro-plugin.ts.html +0 -1609
  113. package/__tests__/coverage/lcov-report/src/resilience/bulkhead.ts.html +0 -916
  114. package/__tests__/coverage/lcov-report/src/resilience/circuit-breaker.ts.html +0 -1063
  115. package/__tests__/coverage/lcov-report/src/resilience/index.html +0 -161
  116. package/__tests__/coverage/lcov-report/src/resilience/rate-limiter.ts.html +0 -1345
  117. package/__tests__/coverage/lcov-report/src/resilience/retry.ts.html +0 -757
  118. package/__tests__/coverage/lcov-report/src/security/index.html +0 -131
  119. package/__tests__/coverage/lcov-report/src/security/input-validation.ts.html +0 -880
  120. package/__tests__/coverage/lcov-report/src/security/secure-random.ts.html +0 -562
  121. package/__tests__/coverage/lcov-report/src/types/index.html +0 -131
  122. package/__tests__/coverage/lcov-report/src/types/swarm.types.ts.html +0 -850
  123. package/__tests__/coverage/lcov-report/src/types/task.types.ts.html +0 -700
  124. package/__tests__/coverage/lcov-report/src/types.ts.html +0 -1186
  125. package/__tests__/coverage/lcov-report/src/utils/index.html +0 -116
  126. package/__tests__/coverage/lcov-report/src/utils/secure-logger.ts.html +0 -856
  127. package/__tests__/coverage/lcov.info +0 -19877
  128. package/__tests__/coverage/prettify.css +0 -1
  129. package/__tests__/coverage/prettify.js +0 -2
  130. package/__tests__/coverage/sort-arrow-sprite.png +0 -0
  131. package/__tests__/coverage/sorter.js +0 -210
  132. package/__tests__/coverage/src/core/config/defaults.ts.html +0 -706
  133. package/__tests__/coverage/src/core/config/index.html +0 -161
  134. package/__tests__/coverage/src/core/config/loader.ts.html +0 -898
  135. package/__tests__/coverage/src/core/config/schema.ts.html +0 -649
  136. package/__tests__/coverage/src/core/config/validator.ts.html +0 -712
  137. package/__tests__/coverage/src/core/event-bus.ts.html +0 -793
  138. package/__tests__/coverage/src/core/index.html +0 -116
  139. package/__tests__/coverage/src/core/interfaces/event.interface.ts.html +0 -886
  140. package/__tests__/coverage/src/core/interfaces/index.html +0 -116
  141. package/__tests__/coverage/src/core/orchestrator/event-coordinator.ts.html +0 -451
  142. package/__tests__/coverage/src/core/orchestrator/health-monitor.ts.html +0 -727
  143. package/__tests__/coverage/src/core/orchestrator/index.html +0 -176
  144. package/__tests__/coverage/src/core/orchestrator/lifecycle-manager.ts.html +0 -874
  145. package/__tests__/coverage/src/core/orchestrator/session-manager.ts.html +0 -922
  146. package/__tests__/coverage/src/core/orchestrator/task-manager.ts.html +0 -1036
  147. package/__tests__/coverage/src/events/domain-events.ts.html +0 -1837
  148. package/__tests__/coverage/src/events/event-store.ts.html +0 -1849
  149. package/__tests__/coverage/src/events/example-usage.ts.html +0 -964
  150. package/__tests__/coverage/src/events/index.html +0 -176
  151. package/__tests__/coverage/src/events/projections.ts.html +0 -1768
  152. package/__tests__/coverage/src/events/state-reconstructor.ts.html +0 -1132
  153. package/__tests__/coverage/src/events.ts.html +0 -1186
  154. package/__tests__/coverage/src/hooks/example-usage.ts.html +0 -1582
  155. package/__tests__/coverage/src/hooks/executor.ts.html +0 -1222
  156. package/__tests__/coverage/src/hooks/index.html +0 -191
  157. package/__tests__/coverage/src/hooks/registry.ts.html +0 -1084
  158. package/__tests__/coverage/src/hooks/safety/bash-safety.ts.html +0 -1897
  159. package/__tests__/coverage/src/hooks/safety/file-organization.ts.html +0 -1504
  160. package/__tests__/coverage/src/hooks/safety/git-commit.ts.html +0 -1954
  161. package/__tests__/coverage/src/hooks/safety/index.html +0 -146
  162. package/__tests__/coverage/src/hooks/session-hooks.ts.html +0 -1762
  163. package/__tests__/coverage/src/hooks/task-hooks.ts.html +0 -1624
  164. package/__tests__/coverage/src/hooks/types.ts.html +0 -1156
  165. package/__tests__/coverage/src/index.html +0 -176
  166. package/__tests__/coverage/src/mcp/connection-pool.ts.html +0 -1399
  167. package/__tests__/coverage/src/mcp/index.html +0 -176
  168. package/__tests__/coverage/src/mcp/server.ts.html +0 -2407
  169. package/__tests__/coverage/src/mcp/session-manager.ts.html +0 -1369
  170. package/__tests__/coverage/src/mcp/tool-registry.ts.html +0 -1783
  171. package/__tests__/coverage/src/mcp/transport/http.ts.html +0 -1756
  172. package/__tests__/coverage/src/mcp/transport/index.html +0 -146
  173. package/__tests__/coverage/src/mcp/transport/stdio.ts.html +0 -1057
  174. package/__tests__/coverage/src/mcp/transport/websocket.ts.html +0 -1537
  175. package/__tests__/coverage/src/mcp/types.ts.html +0 -1780
  176. package/__tests__/coverage/src/plugin-interface.ts.html +0 -2074
  177. package/__tests__/coverage/src/plugin-loader.ts.html +0 -1999
  178. package/__tests__/coverage/src/plugin-registry.ts.html +0 -1897
  179. package/__tests__/coverage/src/plugins/official/hive-mind-plugin.ts.html +0 -1075
  180. package/__tests__/coverage/src/plugins/official/index.html +0 -131
  181. package/__tests__/coverage/src/plugins/official/maestro-plugin.ts.html +0 -1609
  182. package/__tests__/coverage/src/resilience/bulkhead.ts.html +0 -916
  183. package/__tests__/coverage/src/resilience/circuit-breaker.ts.html +0 -1063
  184. package/__tests__/coverage/src/resilience/index.html +0 -161
  185. package/__tests__/coverage/src/resilience/rate-limiter.ts.html +0 -1345
  186. package/__tests__/coverage/src/resilience/retry.ts.html +0 -757
  187. package/__tests__/coverage/src/security/index.html +0 -131
  188. package/__tests__/coverage/src/security/input-validation.ts.html +0 -880
  189. package/__tests__/coverage/src/security/secure-random.ts.html +0 -562
  190. package/__tests__/coverage/src/types/index.html +0 -131
  191. package/__tests__/coverage/src/types/swarm.types.ts.html +0 -850
  192. package/__tests__/coverage/src/types/task.types.ts.html +0 -700
  193. package/__tests__/coverage/src/types.ts.html +0 -1186
  194. package/__tests__/coverage/src/utils/index.html +0 -116
  195. package/__tests__/coverage/src/utils/secure-logger.ts.html +0 -856
@@ -0,0 +1,3189 @@
1
+ [2026-04-28T12:32:26.973Z] PROMPT
2
+ ============================================================
3
+ Analyze test coverage and identify gaps:
4
+ - Find untested functions and classes
5
+ - Identify edge cases not covered
6
+ - Suggest new test scenarios
7
+ - Check for missing error handling tests
8
+ - Identify integration test gaps
9
+
10
+ For each gap, provide a test skeleton.
11
+
12
+ ## Codebase Context
13
+
14
+ --- __tests__/hooks/bash-safety.test.ts (truncated) ---
15
+ /**
16
+ * V3 Bash Safety Hook Tests
17
+ *
18
+ * Tests for command safety analysis and dangerous command detection.
19
+ *
20
+ * @module v3/shared/hooks/__tests__/bash-safety.test
21
+ */
22
+
23
+ import { describe, it, expect, beforeEach } from 'vitest';
24
+ import {
25
+ createHookRegistry,
26
+ createBashSafetyHook,
27
+ BashSafetyHook,
28
+ HookRegistry,
29
+ } from '../../src/hooks/index.js';
30
+
31
+ describe('BashSafetyHook', () => {
32
+ let registry: HookRegistry;
33
+ let bashSafety: BashSafetyHook;
34
+
35
+ beforeEach(() => {
36
+ registry = createHookRegistry();
37
+ bashSafety = createBashSafetyHook(registry);
38
+ });
39
+
40
+ describe('dangerous command detection', () => {
41
+ it('should block rm -rf / command', async () => {
42
+ const result = await bashSafety.analyze('rm -rf /');
43
+
44
+ expect(result.blocked).toBe(true);
45
+ expect(result.riskLevel).toBe('critical');
46
+ expect(result.risks.length).toBeGreaterThan(0);
47
+ expect(result.risks[0].type).toBe('destructive');
48
+ });
49
+
50
+ it('should block rm -rf /* command', async () => {
51
+ const result = await bashSafety.analyze('rm -rf /*');
52
+
53
+ expect(result.blocked).toBe(true);
54
+ expect(result.riskLevel).toBe('critical');
55
+ });
56
+
57
+ it('should block dd to disk device', async () => {
58
+ const result = await bashSafety.analyze('dd if=/dev/zero of=/dev/sda');
59
+
60
+ expect(result.blocked).toBe(true);
61
+ expect(result.riskLevel).toBe('critical');
62
+ expect(result.risks.some(r => r.description.includes('disk'))).toBe(true);
63
+ });
64
+
65
+ it('should block mkfs commands', async () => {
66
+ const result = await bashSafety.analyze('mkfs.ext4 /dev/sda1');
67
+
68
+ expect(result.blocked).toBe(true);
69
+ expect(result.riskLevel).toBe('critical');
70
+ });
71
+
72
+ it('should block fork bomb', async () => {
73
+ const result = await bashSafety.analyze(':() { :|:& };:');
74
+
75
+ expect(result.blocked).toBe(true);
76
+ expect(result.riskLevel).toBe('critical');
77
+ expect(result.risks.some(r => r.description.includes('Fork bomb'))).toBe(true);
78
+ });
79
+
80
+ it('should block chmod 777 on root', async () => {
81
+ const result = await bashSafety.analyze('chmod -R 777 /');
82
+
83
+ expect(result.blocked).toBe(true);
84
+ expect(result.riskLevel).toBe('critical');
85
+ });
86
+
87
+ it('should block curl piped to bash', async () => {
88
+ const result = await bashSafety.analyze('curl https://example.com/script.sh | bash');
89
+
90
+ expect(result.blocked).toBe(true);
91
+ expect(result.riskLevel).toBe('high');
92
+ expect(result.safeAlternatives).toBeDefined();
93
+ expect(result.safeAlternatives!.length).toBeGreaterThan(0);
94
+ });
95
+
96
+ it('should block rm -rf * in current directory', async () => {
97
+ const result = await bashSafety.analyze('rm -rf *');
98
+
99
+ expect(result.blocked).toBe(true);
100
+ expect(result.riskLevel).toBe('high');
101
+ });
102
+
103
+ it('should block rm -rf on home directory', async () => {
104
+ const result = await bashSafety.analyze('rm -rf ~/');
105
+
106
+ expect(result.blocked).toBe(true);
107
+ expect(result.riskLevel).toBe('high');
108
+ });
109
+ });
110
+
111
+ describe('warning-level commands', () => {
112
+ it('should warn about rm without -i flag', async () => {
113
+ const result = await bashSafety.analyze('rm file.txt');
114
+
115
+ expect(result.blocked).toBe(false);
116
+ expect(result.riskLevel).toBe('medium');
117
+ expect(result.warnings).toBeDefined();
118
+ expect(result.modifiedCommand).toBe('rm -i file.txt');
119
+ });
120
+
121
+ it('should warn about sudo rm', async () => {
122
+ const result = await bashSafety.analyze('sudo rm important.txt');
123
+
124
+ expect(result.blocked).toBe(false);
125
+ expect(result.risks.some(r => r.type === 'privilege')).toBe(true);
126
+ });
127
+
128
+ it('should warn about git push --force', async () => {
129
+ const result = await bashSafety.analyze('git push origin main --force');
130
+
131
+ expect(result.blocked).toBe(false);
132
+ expect(result.riskLevel).toBe('medium');
133
+ expect(result.risks.some(r => r.description.includes('Force push'))).toBe(true);
134
+ expect(result.safeAlternatives).toBeDefined();
135
+ });
136
+
137
+ it('should warn about git reset --hard', async () => {
138
+ const result = await bashSafety.analyze('git reset --hard HEAD~1');
139
+
140
+ expect(result.blocked).toBe(false);
141
+ expect(result.riskLevel).toBe('medium');
142
+ expect(result.risks.some(r => r.description.includes('Hard reset'))).toBe(true);
143
+ });
144
+
145
+ it('should warn about DROP DATABASE', async () => {
146
+ const result = await bashSafety.analyze('mysql -e "DROP DATABASE production"');
147
+
148
+ expect(result.blocked).toBe(false);
149
+ expect(result.riskLevel).toBe('high');
150
+ });
151
+
152
+ it('should warn about kill -9', async () => {
153
+ const result = await bashSafety.analyze('kill -9 12345');
154
+
155
+ expect(result.blocked).toBe(false);
156
+ expect(result.riskLevel).toBe('low');
157
+ });
158
+ });
159
+
160
+ describe('secret detection', () => {
161
+ it('should detect password in command', async () => {
162
+ const result = await bashSafety.analyze('mysql -p password=secret123');
163
+
164
+ expect(result.risks.some(r => r
165
+
166
+ --- __tests__/hooks/file-organization.test.ts (truncated) ---
167
+ /**
168
+ * V3 File Organization Hook Tests
169
+ *
170
+ * Tests for file organization enforcement and formatter recommendations.
171
+ *
172
+ * @module v3/shared/hooks/__tests__/file-organization.test
173
+ */
174
+
175
+ import { describe, it, expect, beforeEach } from 'vitest';
176
+ import {
177
+ createHookRegistry,
178
+ createFileOrganizationHook,
179
+ FileOrganizationHook,
180
+ HookRegistry,
181
+ } from '../../src/hooks/index.js';
182
+
183
+ describe('FileOrganizationHook', () => {
184
+ let registry: HookRegistry;
185
+ let fileOrg: FileOrganizationHook;
186
+
187
+ beforeEach(() => {
188
+ registry = createHookRegistry();
189
+ fileOrg = createFileOrganizationHook(registry);
190
+ });
191
+
192
+ describe('root folder blocking', () => {
193
+ it('should block TypeScript source files in root', async () => {
194
+ const result = await fileOrg.analyze('utils.ts');
195
+
196
+ expect(result.blocked).toBe(true);
197
+ expect(result.blockReason).toBeDefined();
198
+ expect(result.suggestedDirectory).toBe('src/');
199
+ expect(result.suggestedPath).toBe('src/utils.ts');
200
+ });
201
+
202
+ it('should block JavaScript source files in root', async () => {
203
+ const result = await fileOrg.analyze('index.js');
204
+
205
+ expect(result.blocked).toBe(true);
206
+ expect(result.suggestedDirectory).toBe('src/');
207
+ });
208
+
209
+ it('should block TypeScript test files in root', async () => {
210
+ const result = await fileOrg.analyze('utils.test.ts');
211
+
212
+ expect(result.blocked).toBe(true);
213
+ expect(result.suggestedDirectory).toBe('tests/');
214
+ expect(result.suggestedPath).toBe('tests/utils.test.ts');
215
+ });
216
+
217
+ it('should block spec files in root', async () => {
218
+ const result = await fileOrg.analyze('api.spec.ts');
219
+
220
+ expect(result.blocked).toBe(true);
221
+ expect(result.suggestedDirectory).toBe('tests/');
222
+ });
223
+
224
+ it('should block Python files in root', async () => {
225
+ const result = await fileOrg.analyze('main.py');
226
+
227
+ expect(result.blocked).toBe(true);
228
+ expect(result.suggestedDirectory).toBe('src/');
229
+ });
230
+
231
+ it('should block Go files in root', async () => {
232
+ const result = await fileOrg.analyze('main.go');
233
+
234
+ expect(result.blocked).toBe(true);
235
+ expect(result.suggestedDirectory).toBe('cmd/');
236
+ });
237
+
238
+ it('should block shell scripts in root', async () => {
239
+ const result = await fileOrg.analyze('deploy.sh');
240
+
241
+ expect(result.blocked).toBe(true);
242
+ expect(result.suggestedDirectory).toBe('scripts/');
243
+ });
244
+
245
+ it('should block CSS files in root', async () => {
246
+ const result = await fileOrg.analyze('styles.css');
247
+
248
+ expect(result.blocked).toBe(true);
249
+ expect(result.suggestedDirectory).toBe('styles/');
250
+ });
251
+ });
252
+
253
+ describe('allowed root files', () => {
254
+ it('should allow JSON config files in root', async () => {
255
+ const result = await fileOrg.analyze('package.json');
256
+
257
+ expect(result.blocked).toBe(false);
258
+ });
259
+
260
+ it('should allow YAML config files in root', async () => {
261
+ const result = await fileOrg.analyze('config.yaml');
262
+
263
+ expect(result.blocked).toBe(false);
264
+ });
265
+
266
+ it('should allow Markdown files in root', async () => {
267
+ const result = await fileOrg.analyze('README.md');
268
+
269
+ expect(result.blocked).toBe(false);
270
+ });
271
+
272
+ it('should allow environment files in root', async () => {
273
+ const result = await fileOrg.analyze('.env');
274
+
275
+ expect(result.blocked).toBe(false);
276
+ });
277
+
278
+ it('should allow .env.local files in root', async () => {
279
+ const result = await fileOrg.analyze('.env.local');
280
+
281
+ expect(result.blocked).toBe(false);
282
+ });
283
+ });
284
+
285
+ describe('files in correct directories', () => {
286
+ it('should allow TypeScript files in src/', async () => {
287
+ const result = await fileOrg.analyze('src/utils.ts');
288
+
289
+ expect(result.blocked).toBe(false);
290
+ expect(result.issues?.some(i => i.type === 'wrong-directory')).toBeFalsy();
291
+ });
292
+
293
+ it('should allow test files in tests/', async () => {
294
+ const result = await fileOrg.analyze('tests/utils.test.ts');
295
+
296
+ expect(result.blocked).toBe(false);
297
+ });
298
+
299
+ it('should allow test files in __tests__/', async () => {
300
+ const result = await fileOrg.analyze('__tests__/utils.test.ts');
301
+
302
+ expect(result.blocked).toBe(false);
303
+ });
304
+
305
+ it('should allow scripts in scripts/', async () => {
306
+ const result = await fileOrg.analyze('scripts/deploy.sh');
307
+
308
+ expect(result.blocked).toBe(false);
309
+ });
310
+
311
+ it('should allow Go files in cmd/', async () => {
312
+ const result = await fileOrg.analyze('cmd/main.go');
313
+
314
+ expect(result.blocked).toBe(false);
315
+ });
316
+ });
317
+
318
+ describe('files in wrong directories', () => {
319
+ it('should warn about test files in src/', async () => {
320
+ const result = await fileOrg.analyze('src/utils.test.ts');
321
+
322
+ expect(result.blocked).toBe(false);
323
+ expect(result.issues?.some(i => i.type === 'wrong-directory')).toBe(true);
324
+ expect(result.warnings?.length).toBeGreaterThan(0);
325
+ });
326
+
327
+ it('should warn about source files in tests/', async () => {
328
+ const result = await fileO
329
+
330
+ --- __tests__/hooks/git-commit.test.ts (truncated) ---
331
+ /**
332
+ * V3 Git Commit Hook Tests
333
+ *
334
+ * Tests for git commit message formatting and validation.
335
+ *
336
+ * @module v3/shared/hooks/__tests__/git-commit.test
337
+ */
338
+
339
+ import { describe, it, expect, beforeEach } from 'vitest';
340
+ import {
341
+ createHookRegistry,
342
+ createGitCommitHook,
343
+ GitCommitHook,
344
+ HookRegistry,
345
+ } from '../../src/hooks/index.js';
346
+
347
+ describe('GitCommitHook', () => {
348
+ let registry: HookRegistry;
349
+ let gitCommit: GitCommitHook;
350
+
351
+ beforeEach(() => {
352
+ registry = createHookRegistry();
353
+ gitCommit = createGitCommitHook(registry);
354
+ });
355
+
356
+ describe('commit type detection', () => {
357
+ it('should detect feat type from message', async () => {
358
+ const result = await gitCommit.process('Add user authentication');
359
+
360
+ expect(result.commitType).toBe('feat');
361
+ expect(result.modifiedMessage).toMatch(/^feat:/);
362
+ });
363
+
364
+ it('should detect fix type from message', async () => {
365
+ const result = await gitCommit.process('Fix login validation bug');
366
+
367
+ expect(result.commitType).toBe('fix');
368
+ expect(result.modifiedMessage).toMatch(/^fix:/);
369
+ });
370
+
371
+ it('should detect docs type from message', async () => {
372
+ const result = await gitCommit.process('Update README documentation');
373
+
374
+ expect(result.commitType).toBe('docs');
375
+ expect(result.modifiedMessage).toMatch(/^docs:/);
376
+ });
377
+
378
+ it('should detect refactor type from message', async () => {
379
+ const result = await gitCommit.process('Refactor authentication module');
380
+
381
+ expect(result.commitType).toBe('refactor');
382
+ expect(result.modifiedMessage).toMatch(/^refactor:/);
383
+ });
384
+
385
+ it('should detect test type from message', async () => {
386
+ const result = await gitCommit.process('Add unit tests for user service');
387
+
388
+ expect(result.commitType).toBe('test');
389
+ expect(result.modifiedMessage).toMatch(/^test:/);
390
+ });
391
+
392
+ it('should detect perf type from message', async () => {
393
+ const result = await gitCommit.process('Optimize database queries');
394
+
395
+ expect(result.commitType).toBe('perf');
396
+ expect(result.modifiedMessage).toMatch(/^perf:/);
397
+ });
398
+
399
+ it('should detect build type from message', async () => {
400
+ const result = await gitCommit.process('Update webpack configuration');
401
+
402
+ expect(result.commitType).toBe('build');
403
+ expect(result.modifiedMessage).toMatch(/^build:/);
404
+ });
405
+
406
+ it('should detect ci type from message', async () => {
407
+ const result = await gitCommit.process('Update GitHub Actions workflow');
408
+
409
+ expect(result.commitType).toBe('ci');
410
+ expect(result.modifiedMessage).toMatch(/^ci:/);
411
+ });
412
+
413
+ it('should detect chore type from message', async () => {
414
+ const result = await gitCommit.process('Update dependencies');
415
+
416
+ expect(result.commitType).toBe('chore');
417
+ expect(result.modifiedMessage).toMatch(/^chore:/);
418
+ });
419
+
420
+ it('should detect revert type from message', async () => {
421
+ const result = await gitCommit.process('Revert previous commit');
422
+
423
+ expect(result.commitType).toBe('revert');
424
+ expect(result.modifiedMessage).toMatch(/^revert:/);
425
+ });
426
+ });
427
+
428
+ describe('preserving existing prefixes', () => {
429
+ it('should not add duplicate prefix if already present', async () => {
430
+ const result = await gitCommit.process('feat: add user authentication');
431
+
432
+ expect(result.commitType).toBe('feat');
433
+ // Should not have double prefix
434
+ expect(result.modifiedMessage).not.toMatch(/^feat:.*feat:/);
435
+ });
436
+
437
+ it('should detect type from existing prefix', async () => {
438
+ const result = await gitCommit.process('fix(auth): resolve login issue');
439
+
440
+ expect(result.commitType).toBe('fix');
441
+ });
442
+
443
+ it('should handle scoped commits', async () => {
444
+ const result = await gitCommit.process('feat(api): add new endpoint');
445
+
446
+ expect(result.commitType).toBe('feat');
447
+ });
448
+ });
449
+
450
+ describe('ticket extraction', () => {
451
+ it('should extract JIRA ticket from branch name', async () => {
452
+ const result = await gitCommit.process('Add feature', 'feature/ABC-123-new-feature');
453
+
454
+ expect(result.ticketReference).toBe('ABC-123');
455
+ expect(result.modifiedMessage).toContain('Refs: ABC-123');
456
+ });
457
+
458
+ it('should extract GitHub issue from branch name', async () => {
459
+ const result = await gitCommit.process('Fix bug', 'fix/#456-login-bug');
460
+
461
+ expect(result.ticketReference).toBe('#456');
462
+ expect(result.modifiedMessage).toContain('Refs: #456');
463
+ });
464
+
465
+ it('should not duplicate ticket if already in message', async () => {
466
+ const result = await gitCommit.process('Fix ABC-123 bug', 'feature/ABC-123-test');
467
+
468
+ // Should only appear once
469
+ const matches = result.modifiedMessage.match(/ABC-123/g);
470
+ expect(matches).toBeDefined();
471
+ expect(matches!.length).toBeLessThanOrEqual(2);
472
+ });
473
+ });
474
+
475
+ describe('co-author addition', () => {
476
+ it('should add co-author by default', async () => {
477
+ const result = await gitCommit.process('Add feature');
478
+
479
+ expect(res
480
+
481
+ --- __tests__/hooks/index.ts ---
482
+ /**
483
+ * V3 Hooks Tests Index
484
+ *
485
+ * Exports all hook tests for the V3 hooks system.
486
+ *
487
+ * @module v3/shared/hooks/__tests__
488
+ */
489
+
490
+ // Test files are automatically discovered by vitest
491
+ // This file serves as documentation of available tests
492
+
493
+ export const testFiles = [
494
+ './task-hooks.test.ts',
495
+ './session-hooks.test.ts',
496
+ './bash-safety.test.ts',
497
+ './file-organization.test.ts',
498
+ './git-commit.test.ts',
499
+ ];
500
+
501
+ export const testCategories = {
502
+ 'Core Hooks': ['task-hooks.test.ts', 'session-hooks.test.ts'],
503
+ 'Safety Hooks': ['bash-safety.test.ts', 'file-organization.test.ts', 'git-commit.test.ts'],
504
+ };
505
+
506
+
507
+ --- __tests__/hooks/session-hooks.test.ts (truncated) ---
508
+ /**
509
+ * V3 Session Hooks Tests
510
+ *
511
+ * Tests for session-end and session-restore hook functionality.
512
+ *
513
+ * @module v3/shared/hooks/__tests__/session-hooks.test
514
+ */
515
+
516
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
517
+ import {
518
+ createHookRegistry,
519
+ createSessionHooksManager,
520
+ SessionHooksManager,
521
+ HookRegistry,
522
+ HookEvent,
523
+ InMemorySessionStorage,
524
+ } from '../../src/hooks/index.js';
525
+
526
+ describe('SessionHooksManager', () => {
527
+ let registry: HookRegistry;
528
+ let sessionManager: SessionHooksManager;
529
+ let storage: InMemorySessionStorage;
530
+
531
+ beforeEach(() => {
532
+ registry = createHookRegistry();
533
+ storage = new InMemorySessionStorage();
534
+ sessionManager = createSessionHooksManager(registry, storage);
535
+ });
536
+
537
+ describe('session lifecycle hooks', () => {
538
+ it('should register session hooks on creation', () => {
539
+ const startHooks = registry.getHandlers(HookEvent.SessionStart);
540
+ const endHooks = registry.getHandlers(HookEvent.SessionEnd);
541
+ const resumeHooks = registry.getHandlers(HookEvent.SessionResume);
542
+
543
+ expect(startHooks.some(h => h.name === 'session-hooks:start')).toBe(true);
544
+ expect(endHooks.some(h => h.name === 'session-hooks:end')).toBe(true);
545
+ expect(resumeHooks.some(h => h.name === 'session-hooks:resume')).toBe(true);
546
+ });
547
+ });
548
+
549
+ describe('session-end hook', () => {
550
+ it('should end session and return summary', async () => {
551
+ // Simulate session start by triggering tracking
552
+ const context = {
553
+ event: HookEvent.SessionStart,
554
+ timestamp: new Date(),
555
+ session: { id: 'test-session', startTime: new Date() },
556
+ };
557
+ await sessionManager['handleSessionStart'](context);
558
+
559
+ // Wait a moment to ensure duration > 0
560
+ await new Promise(resolve => setTimeout(resolve, 10));
561
+
562
+ const result = await sessionManager.executeSessionEnd();
563
+
564
+ expect(result.success).toBe(true);
565
+ expect(result.duration).toBeGreaterThanOrEqual(0);
566
+ expect(result.summary).toBeDefined();
567
+ expect(result.summary!.tasksExecuted).toBe(0);
568
+ expect(result.summary!.commandsExecuted).toBe(0);
569
+ });
570
+
571
+ it('should persist session state', async () => {
572
+ // Start session
573
+ const startContext = {
574
+ event: HookEvent.SessionStart,
575
+ timestamp: new Date(),
576
+ session: { id: 'persist-session', startTime: new Date() },
577
+ };
578
+ await sessionManager['handleSessionStart'](startContext);
579
+
580
+ const result = await sessionManager.executeSessionEnd();
581
+
582
+ expect(result.persistedState).toBeDefined();
583
+ expect(result.statePath).toBeDefined();
584
+
585
+ // Verify state was saved
586
+ const sessions = await storage.list();
587
+ expect(sessions.length).toBeGreaterThan(0);
588
+ });
589
+
590
+ it('should handle ending session without active session', async () => {
591
+ const result = await sessionManager.executeSessionEnd();
592
+ expect(result.success).toBe(true);
593
+ });
594
+
595
+ it('should reset activity tracking after session end', async () => {
596
+ // Start session
597
+ const context = {
598
+ event: HookEvent.SessionStart,
599
+ timestamp: new Date(),
600
+ session: { id: 'reset-session', startTime: new Date() },
601
+ };
602
+ await sessionManager['handleSessionStart'](context);
603
+
604
+ await sessionManager.executeSessionEnd();
605
+
606
+ expect(sessionManager.getCurrentSessionId()).toBeNull();
607
+ });
608
+ });
609
+
610
+ describe('session-restore hook', () => {
611
+ it('should restore a previous session', async () => {
612
+ // Create and end a session first
613
+ const startContext = {
614
+ event: HookEvent.SessionStart,
615
+ timestamp: new Date(),
616
+ session: { id: 'restore-test', startTime: new Date() },
617
+ };
618
+ await sessionManager['handleSessionStart'](startContext);
619
+ await sessionManager.executeSessionEnd();
620
+
621
+ // Restore the session
622
+ const result = await sessionManager.executeSessionRestore('restore-test');
623
+
624
+ expect(result.success).toBe(true);
625
+ expect(result.restoredState).toBeDefined();
626
+ expect(result.restoredState!.sessionId).toBe('restore-test');
627
+ });
628
+
629
+ it('should restore latest session when no ID specified', async () => {
630
+ // Create and end multiple sessions
631
+ for (const id of ['session-1', 'session-2', 'session-3']) {
632
+ const context = {
633
+ event: HookEvent.SessionStart,
634
+ timestamp: new Date(),
635
+ session: { id, startTime: new Date() },
636
+ };
637
+ await sessionManager['handleSessionStart'](context);
638
+ await sessionManager.executeSessionEnd();
639
+ await new Promise(resolve => setTimeout(resolve, 5));
640
+ }
641
+
642
+ const result = await sessionManager.executeSessionRestore();
643
+
644
+ expect(result.success).toBe(true);
645
+ expect(result.restoredState).toBeDefined();
646
+ });
647
+
648
+ it('should fail gracefully when session not found', async () => {
649
+ const result = await sessionManager.executeSessionRestore('non-existent');
650
+
651
+ expect(result.success).toBe(false);
652
+ expect(result.error).toBeDefin
653
+
654
+ --- __tests__/hooks/task-hooks.test.ts (truncated) ---
655
+ /**
656
+ * V3 Task Hooks Tests
657
+ *
658
+ * Tests for pre-task and post-task hook functionality.
659
+ *
660
+ * @module v3/shared/hooks/__tests__/task-hooks.test
661
+ */
662
+
663
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
664
+ import {
665
+ createHookRegistry,
666
+ createTaskHooksManager,
667
+ TaskHooksManager,
668
+ HookRegistry,
669
+ HookEvent,
670
+ } from '../../src/hooks/index.js';
671
+
672
+ describe('TaskHooksManager', () => {
673
+ let registry: HookRegistry;
674
+ let taskManager: TaskHooksManager;
675
+
676
+ beforeEach(() => {
677
+ registry = createHookRegistry();
678
+ taskManager = createTaskHooksManager(registry);
679
+ });
680
+
681
+ describe('pre-task hook', () => {
682
+ it('should register pre-task hook on creation', () => {
683
+ const hooks = registry.getHandlers(HookEvent.PreTaskExecute);
684
+ expect(hooks.length).toBeGreaterThan(0);
685
+ expect(hooks.some(h => h.name === 'task-hooks:pre-task')).toBe(true);
686
+ });
687
+
688
+ it('should analyze task and suggest agents for coding task', async () => {
689
+ const result = await taskManager.executePreTask(
690
+ 'task-123',
691
+ 'Implement user authentication feature'
692
+ );
693
+
694
+ expect(result.success).toBe(true);
695
+ expect(result.suggestedAgents).toBeDefined();
696
+ expect(result.suggestedAgents!.length).toBeGreaterThan(0);
697
+ expect(result.suggestedAgents![0].type).toBe('coder');
698
+ expect(result.suggestedAgents![0].confidence).toBeGreaterThan(0);
699
+ });
700
+
701
+ it('should suggest security-architect for security tasks', async () => {
702
+ const result = await taskManager.executePreTask(
703
+ 'task-456',
704
+ 'Fix security vulnerability in authentication'
705
+ );
706
+
707
+ expect(result.success).toBe(true);
708
+ expect(result.suggestedAgents).toBeDefined();
709
+ const securityAgent = result.suggestedAgents!.find(a => a.type === 'security-architect');
710
+ expect(securityAgent).toBeDefined();
711
+ });
712
+
713
+ it('should suggest tester for test-related tasks', async () => {
714
+ const result = await taskManager.executePreTask(
715
+ 'task-789',
716
+ 'Write unit tests for user service'
717
+ );
718
+
719
+ expect(result.success).toBe(true);
720
+ expect(result.suggestedAgents).toBeDefined();
721
+ const testerAgent = result.suggestedAgents!.find(a => a.type === 'tester');
722
+ expect(testerAgent).toBeDefined();
723
+ });
724
+
725
+ it('should estimate complexity based on task description', async () => {
726
+ // Simple task
727
+ const simpleResult = await taskManager.executePreTask(
728
+ 'task-simple',
729
+ 'Fix typo in readme'
730
+ );
731
+ expect(simpleResult.complexity).toBe('low');
732
+
733
+ // Complex task
734
+ const complexResult = await taskManager.executePreTask(
735
+ 'task-complex',
736
+ 'Refactor and redesign the entire authentication system with multiple OAuth providers'
737
+ );
738
+ expect(complexResult.complexity).toBe('high');
739
+ });
740
+
741
+ it('should detect risks in task description', async () => {
742
+ const result = await taskManager.executePreTask(
743
+ 'task-risky',
744
+ 'Delete old data from production database'
745
+ );
746
+
747
+ expect(result.risks).toBeDefined();
748
+ expect(result.risks!.length).toBeGreaterThan(0);
749
+ expect(result.risks!.some(r => r.includes('production'))).toBe(true);
750
+ });
751
+
752
+ it('should track active tasks', async () => {
753
+ await taskManager.executePreTask('task-1', 'Task 1');
754
+ await taskManager.executePreTask('task-2', 'Task 2');
755
+
756
+ const activeTasks = taskManager.getActiveTasks();
757
+ expect(activeTasks.size).toBe(2);
758
+ expect(activeTasks.has('task-1')).toBe(true);
759
+ expect(activeTasks.has('task-2')).toBe(true);
760
+ });
761
+
762
+ it('should provide recommendations for high complexity tasks', async () => {
763
+ const result = await taskManager.executePreTask(
764
+ 'task-high-complexity',
765
+ 'Implement complex distributed system with multiple services'
766
+ );
767
+
768
+ expect(result.recommendations).toBeDefined();
769
+ expect(result.recommendations!.length).toBeGreaterThan(0);
770
+ });
771
+ });
772
+
773
+ describe('post-task hook', () => {
774
+ it('should register post-task hook on creation', () => {
775
+ const hooks = registry.getHandlers(HookEvent.PostTaskExecute);
776
+ expect(hooks.length).toBeGreaterThan(0);
777
+ expect(hooks.some(h => h.name === 'task-hooks:post-task')).toBe(true);
778
+ });
779
+
780
+ it('should record successful task outcome', async () => {
781
+ // First start the task
782
+ await taskManager.executePreTask('task-success', 'Test task');
783
+
784
+ // Then complete it
785
+ const result = await taskManager.executePostTask('task-success', true);
786
+
787
+ expect(result.success).toBe(true);
788
+ expect(result.outcome).toBeDefined();
789
+ expect(result.outcome!.success).toBe(true);
790
+ expect(result.outcome!.duration).toBeGreaterThanOrEqual(0);
791
+ });
792
+
793
+ it('should record failed task outcome', async () => {
794
+ await taskManager.executePreTask('task-failed', 'Test task');
795
+
796
+ const result = await taskManager.executePostTask('task-failed', false, {
797
+ error: 'Test failed due to timeout',
798
+ });
799
+
800
+ ex
801
+
802
+ --- src/core/config/defaults.ts ---
803
+ /**
804
+ * V3 Default Configuration Values
805
+ */
806
+
807
+ import type {
808
+ AgentConfig,
809
+ TaskConfig,
810
+ SwarmConfig,
811
+ MemoryConfig,
812
+ MCPServerConfig,
813
+ OrchestratorConfig,
814
+ SystemConfig,
815
+ } from './schema.js';
816
+
817
+ /**
818
+ * Default agent configuration
819
+ */
820
+ export const defaultAgentConfig: Partial<AgentConfig> = {
821
+ capabilities: [],
822
+ maxConcurrentTasks: 5,
823
+ priority: 50,
824
+ retryPolicy: {
825
+ maxRetries: 3,
826
+ backoffMs: 1000,
827
+ backoffMultiplier: 2,
828
+ },
829
+ };
830
+
831
+ /**
832
+ * Default task configuration
833
+ */
834
+ export const defaultTaskConfig: Partial<TaskConfig> = {
835
+ priority: 50,
836
+ metadata: {
837
+ maxRetries: 3,
838
+ },
839
+ };
840
+
841
+ /**
842
+ * Default swarm configuration (core version)
843
+ */
844
+ export const defaultSwarmConfigCore: SwarmConfig = {
845
+ topology: 'hierarchical-mesh',
846
+ maxAgents: 20,
847
+ autoScale: {
848
+ enabled: false,
849
+ minAgents: 1,
850
+ maxAgents: 20,
851
+ scaleUpThreshold: 0.8,
852
+ scaleDownThreshold: 0.3,
853
+ },
854
+ coordination: {
855
+ consensusRequired: false,
856
+ timeoutMs: 10000,
857
+ retryPolicy: {
858
+ maxRetries: 3,
859
+ backoffMs: 500,
860
+ },
861
+ },
862
+ communication: {
863
+ protocol: 'events',
864
+ batchSize: 10,
865
+ flushIntervalMs: 100,
866
+ },
867
+ };
868
+
869
+ /**
870
+ * Default memory configuration (hybrid backend - ADR-009)
871
+ */
872
+ export const defaultMemoryConfig: MemoryConfig = {
873
+ type: 'hybrid',
874
+ path: './data/memory',
875
+ sqlite: {
876
+ inMemory: false,
877
+ wal: true,
878
+ },
879
+ agentdb: {
880
+ dimensions: 1536,
881
+ indexType: 'hnsw',
882
+ efConstruction: 200,
883
+ m: 16,
884
+ quantization: 'none',
885
+ },
886
+ hybrid: {
887
+ vectorThreshold: 100,
888
+ },
889
+ };
890
+
891
+ /**
892
+ * Default MCP server configuration
893
+ */
894
+ export const defaultMCPServerConfig: MCPServerConfig = {
895
+ name: 'claude-flow',
896
+ version: '3.0.0',
897
+ transport: {
898
+ type: 'stdio',
899
+ },
900
+ capabilities: {
901
+ tools: true,
902
+ resources: true,
903
+ prompts: true,
904
+ logging: true,
905
+ },
906
+ };
907
+
908
+ /**
909
+ * Default orchestrator configuration
910
+ */
911
+ export const defaultOrchestratorConfig: OrchestratorConfig = {
912
+ session: {
913
+ persistSessions: true,
914
+ dataDir: './data',
915
+ sessionRetentionMs: 3600000, // 1 hour
916
+ },
917
+ health: {
918
+ checkInterval: 30000, // 30 seconds
919
+ historyLimit: 100,
920
+ degradedThreshold: 1,
921
+ unhealthyThreshold: 2,
922
+ },
923
+ lifecycle: {
924
+ maxConcurrentAgents: 20,
925
+ spawnTimeout: 30000, // 30 seconds
926
+ terminateTimeout: 10000, // 10 seconds
927
+ maxSpawnRetries: 3,
928
+ },
929
+ };
930
+
931
+ /**
932
+ * Default full system configuration
933
+ */
934
+ export const defaultSystemConfig: SystemConfig = {
935
+ orchestrator: defaultOrchestratorConfig,
936
+ memory: defaultMemoryConfig,
937
+ mcp: defaultMCPServerConfig,
938
+ swarm: defaultSwarmConfigCore,
939
+ };
940
+
941
+ /**
942
+ * Agent type presets
943
+ */
944
+ export const agentTypePresets: Record<string, Partial<AgentConfig>> = {
945
+ coder: {
946
+ type: 'coder',
947
+ capabilities: ['code', 'debug', 'refactor', 'test'],
948
+ maxConcurrentTasks: 3,
949
+ priority: 70,
950
+ },
951
+ reviewer: {
952
+ type: 'reviewer',
953
+ capabilities: ['review', 'analyze', 'suggest'],
954
+ maxConcurrentTasks: 5,
955
+ priority: 60,
956
+ },
957
+ tester: {
958
+ type: 'tester',
959
+ capabilities: ['test', 'validate', 'benchmark'],
960
+ maxConcurrentTasks: 4,
961
+ priority: 65,
962
+ },
963
+ researcher: {
964
+ type: 'researcher',
965
+ capabilities: ['research', 'analyze', 'summarize'],
966
+ maxConcurrentTasks: 3,
967
+ priority: 50,
968
+ },
969
+ planner: {
970
+ type: 'planner',
971
+ capabilities: ['plan', 'organize', 'decompose'],
972
+ maxConcurrentTasks: 2,
973
+ priority: 80,
974
+ },
975
+ architect: {
976
+ type: 'architect',
977
+ capabilities: ['design', 'architecture', 'patterns'],
978
+ maxConcurrentTasks: 2,
979
+ priority: 85,
980
+ },
981
+ coordinator: {
982
+ type: 'coordinator',
983
+ capabilities: ['coordinate', 'delegate', 'monitor'],
984
+ maxConcurrentTasks: 10,
985
+ priority: 90,
986
+ },
987
+ security: {
988
+ type: 'security',
989
+ capabilities: ['audit', 'scan', 'validate', 'secure'],
990
+ maxConcurrentTasks: 3,
991
+ priority: 95,
992
+ },
993
+ performance: {
994
+ type: 'performance',
995
+ capabilities: ['benchmark', 'optimize', 'profile'],
996
+ maxConcurrentTasks: 2,
997
+ priority: 70,
998
+ },
999
+ };
1000
+
1001
+ /**
1002
+ * Get merged configuration with defaults
1003
+ */
1004
+ export function mergeWithDefaults<T extends Record<string, unknown>>(
1005
+ config: Partial<T>,
1006
+ defaults: T,
1007
+ ): T {
1008
+ return { ...defaults, ...config } as T;
1009
+ }
1010
+
1011
+
1012
+ --- src/core/config/index.ts ---
1013
+ /**
1014
+ * V3 Configuration - Public API
1015
+ */
1016
+
1017
+ // Schemas
1018
+ export * from './schema.js';
1019
+
1020
+ // Validation
1021
+ export * from './validator.js';
1022
+
1023
+ // Defaults
1024
+ export * from './defaults.js';
1025
+
1026
+ // Loader
1027
+ export * from './loader.js';
1028
+
1029
+
1030
+ --- src/core/config/loader.ts (truncated) ---
1031
+ /**
1032
+ * V3 Configuration Loader
1033
+ * Load configuration from various sources
1034
+ */
1035
+
1036
+ import { readFile } from 'fs/promises';
1037
+ import { join, resolve } from 'path';
1038
+ import { existsSync } from 'fs';
1039
+ import type { SystemConfig } from './schema.js';
1040
+ import { validateSystemConfig, type ValidationResult } from './validator.js';
1041
+ import { defaultSystemConfig, mergeWithDefaults } from './defaults.js';
1042
+
1043
+ /**
1044
+ * Configuration source type
1045
+ */
1046
+ export type ConfigSource = 'file' | 'env' | 'default' | 'merged';
1047
+
1048
+ /**
1049
+ * Loaded configuration with metadata
1050
+ */
1051
+ export interface LoadedConfig {
1052
+ config: SystemConfig;
1053
+ source: ConfigSource;
1054
+ path?: string;
1055
+ warnings?: string[];
1056
+ }
1057
+
1058
+ /**
1059
+ * Configuration file names to search for
1060
+ */
1061
+ const CONFIG_FILE_NAMES = [
1062
+ 'claude-flow.config.json',
1063
+ 'claude-flow.config.js',
1064
+ 'claude-flow.json',
1065
+ '.claude-flow.json',
1066
+ ];
1067
+
1068
+ /**
1069
+ * Find configuration file in directory
1070
+ */
1071
+ async function findConfigFile(directory: string): Promise<string | null> {
1072
+ for (const name of CONFIG_FILE_NAMES) {
1073
+ const path = join(directory, name);
1074
+ if (existsSync(path)) {
1075
+ return path;
1076
+ }
1077
+ }
1078
+ return null;
1079
+ }
1080
+
1081
+ /**
1082
+ * Load configuration from JSON file
1083
+ */
1084
+ async function loadJsonConfig(path: string): Promise<unknown> {
1085
+ const content = await readFile(path, 'utf8');
1086
+ return JSON.parse(content);
1087
+ }
1088
+
1089
+ /**
1090
+ * Load configuration from environment variables
1091
+ */
1092
+ function loadEnvConfig(): Partial<SystemConfig> {
1093
+ const config: Partial<SystemConfig> = {};
1094
+
1095
+ // Orchestrator settings
1096
+ if (process.env.CLAUDE_FLOW_MAX_AGENTS) {
1097
+ config.orchestrator = {
1098
+ ...defaultSystemConfig.orchestrator,
1099
+ lifecycle: {
1100
+ ...defaultSystemConfig.orchestrator.lifecycle,
1101
+ maxConcurrentAgents: parseInt(process.env.CLAUDE_FLOW_MAX_AGENTS, 10),
1102
+ },
1103
+ };
1104
+ }
1105
+
1106
+ // Data directory
1107
+ if (process.env.CLAUDE_FLOW_DATA_DIR) {
1108
+ config.orchestrator = {
1109
+ ...config.orchestrator,
1110
+ ...defaultSystemConfig.orchestrator,
1111
+ session: {
1112
+ ...defaultSystemConfig.orchestrator.session,
1113
+ dataDir: process.env.CLAUDE_FLOW_DATA_DIR,
1114
+ },
1115
+ };
1116
+ }
1117
+
1118
+ // Memory type
1119
+ if (process.env.CLAUDE_FLOW_MEMORY_TYPE) {
1120
+ const memoryType = process.env.CLAUDE_FLOW_MEMORY_TYPE as NonNullable<SystemConfig['memory']>['type'];
1121
+ if (['sqlite', 'agentdb', 'hybrid', 'redis', 'memory'].includes(memoryType)) {
1122
+ config.memory = {
1123
+ ...(defaultSystemConfig.memory ?? { type: 'hybrid' }),
1124
+ type: memoryType,
1125
+ };
1126
+ }
1127
+ }
1128
+
1129
+ // MCP transport
1130
+ const defaultMcp = defaultSystemConfig.mcp ?? { name: 'claude-flow', version: '3.0.0', transport: { type: 'stdio' as const } };
1131
+ if (process.env.CLAUDE_FLOW_MCP_TRANSPORT) {
1132
+ const transport = process.env.CLAUDE_FLOW_MCP_TRANSPORT as 'stdio' | 'http' | 'websocket';
1133
+ if (['stdio', 'http', 'websocket'].includes(transport)) {
1134
+ config.mcp = {
1135
+ ...defaultMcp,
1136
+ transport: {
1137
+ ...defaultMcp.transport,
1138
+ type: transport,
1139
+ },
1140
+ };
1141
+ }
1142
+ }
1143
+
1144
+ if (process.env.CLAUDE_FLOW_MCP_PORT) {
1145
+ config.mcp = {
1146
+ ...config.mcp,
1147
+ ...defaultMcp,
1148
+ transport: {
1149
+ ...config.mcp?.transport,
1150
+ ...defaultMcp.transport,
1151
+ port: parseInt(process.env.CLAUDE_FLOW_MCP_PORT, 10),
1152
+ },
1153
+ };
1154
+ }
1155
+
1156
+ // Swarm topology
1157
+ const defaultSwarm = defaultSystemConfig.swarm ?? { topology: 'hierarchical-mesh' as const, maxAgents: 20 };
1158
+ if (process.env.CLAUDE_FLOW_SWARM_TOPOLOGY) {
1159
+ const topology = process.env.CLAUDE_FLOW_SWARM_TOPOLOGY as NonNullable<SystemConfig['swarm']>['topology'];
1160
+ if (['hierarchical', 'mesh', 'ring', 'star', 'adaptive', 'hierarchical-mesh'].includes(topology)) {
1161
+ config.swarm = {
1162
+ ...defaultSwarm,
1163
+ topology,
1164
+ };
1165
+ }
1166
+ }
1167
+
1168
+ return config;
1169
+ }
1170
+
1171
+ /**
1172
+ * Configuration loader class
1173
+ */
1174
+ export class ConfigLoader {
1175
+ private searchPaths: string[] = [];
1176
+
1177
+ constructor(additionalPaths?: string[]) {
1178
+ // Default search paths
1179
+ this.searchPaths = [
1180
+ process.cwd(),
1181
+ resolve(process.cwd(), '..'),
1182
+ resolve(process.env.HOME ?? '', '.claude-flow'),
1183
+ ];
1184
+
1185
+ if (additionalPaths) {
1186
+ this.searchPaths.push(...additionalPaths);
1187
+ }
1188
+ }
1189
+
1190
+ /**
1191
+ * Load configuration from all sources
1192
+ */
1193
+ async load(): Promise<LoadedConfig> {
1194
+ const warnings: string[] = [];
1195
+
1196
+ // Start with defaults
1197
+ let config: SystemConfig = { ...defaultSystemConfig };
1198
+ let source: ConfigSource = 'default';
1199
+ let path: string | undefined;
1200
+
1201
+ // Try to load from file
1202
+ for (const searchPath of this.searchPaths) {
1203
+ const configPath = await findConfigFile(searchPath);
1204
+ if (configPath) {
1205
+ try {
1206
+ const fileConfig = await loadJsonConfig(configPath);
1207
+ const validation = validateSystemConfig(fileConfig);
1208
+
1209
+ if (validation.success) {
1210
+ config = mergeWithDefaults(validation.data!, defaultSystemConfig) as SystemConfig;
1211
+ source = 'file';
1212
+ path = configPath;
1213
+ break;
1214
+ } else {
1215
+
1216
+
1217
+ --- src/core/config/schema.ts (truncated) ---
1218
+ /**
1219
+ * V3 Configuration Schemas
1220
+ * Zod schemas for all configuration types
1221
+ */
1222
+
1223
+ import { z } from 'zod';
1224
+
1225
+ /**
1226
+ * Agent configuration schema
1227
+ */
1228
+ export const AgentConfigSchema = z.object({
1229
+ id: z.string().min(1),
1230
+ name: z.string().min(1),
1231
+ type: z.string().min(1),
1232
+ capabilities: z.array(z.string()).default([]),
1233
+ maxConcurrentTasks: z.number().int().min(1).default(5),
1234
+ priority: z.number().int().min(0).max(100).default(50),
1235
+ timeout: z.number().int().positive().optional(),
1236
+ retryPolicy: z.object({
1237
+ maxRetries: z.number().int().min(0).default(3),
1238
+ backoffMs: z.number().int().positive().default(1000),
1239
+ backoffMultiplier: z.number().positive().default(2),
1240
+ }).optional(),
1241
+ resources: z.object({
1242
+ maxMemoryMb: z.number().int().positive().optional(),
1243
+ maxCpuPercent: z.number().min(0).max(100).optional(),
1244
+ }).optional(),
1245
+ metadata: z.record(z.unknown()).optional(),
1246
+ });
1247
+
1248
+ /**
1249
+ * Task configuration schema
1250
+ */
1251
+ export const TaskConfigSchema = z.object({
1252
+ type: z.string().min(1),
1253
+ description: z.string().min(1),
1254
+ priority: z.number().int().min(0).max(100).default(50),
1255
+ timeout: z.number().int().positive().optional(),
1256
+ assignedAgent: z.string().optional(),
1257
+ input: z.record(z.unknown()).optional(),
1258
+ metadata: z.object({
1259
+ requiredCapabilities: z.array(z.string()).optional(),
1260
+ retryCount: z.number().int().min(0).optional(),
1261
+ maxRetries: z.number().int().min(0).optional(),
1262
+ critical: z.boolean().optional(),
1263
+ parentTaskId: z.string().optional(),
1264
+ childTaskIds: z.array(z.string()).optional(),
1265
+ tags: z.array(z.string()).optional(),
1266
+ }).optional(),
1267
+ });
1268
+
1269
+ /**
1270
+ * Swarm configuration schema
1271
+ */
1272
+ export const SwarmConfigSchema = z.object({
1273
+ topology: z.enum(['hierarchical', 'mesh', 'ring', 'star', 'adaptive', 'hierarchical-mesh']),
1274
+ maxAgents: z.number().int().positive().default(20),
1275
+ autoScale: z.object({
1276
+ enabled: z.boolean().default(false),
1277
+ minAgents: z.number().int().min(0).default(1),
1278
+ maxAgents: z.number().int().positive().default(20),
1279
+ scaleUpThreshold: z.number().min(0).max(1).default(0.8),
1280
+ scaleDownThreshold: z.number().min(0).max(1).default(0.3),
1281
+ }).optional(),
1282
+ coordination: z.object({
1283
+ consensusRequired: z.boolean().default(false),
1284
+ timeoutMs: z.number().int().positive().default(10000),
1285
+ retryPolicy: z.object({
1286
+ maxRetries: z.number().int().min(0).default(3),
1287
+ backoffMs: z.number().int().positive().default(500),
1288
+ }),
1289
+ }).optional(),
1290
+ communication: z.object({
1291
+ protocol: z.enum(['events', 'messages', 'shared-memory']).default('events'),
1292
+ batchSize: z.number().int().positive().default(10),
1293
+ flushIntervalMs: z.number().int().positive().default(100),
1294
+ }).optional(),
1295
+ metadata: z.record(z.unknown()).optional(),
1296
+ });
1297
+
1298
+ /**
1299
+ * Memory configuration schema
1300
+ */
1301
+ export const MemoryConfigSchema = z.object({
1302
+ type: z.enum(['sqlite', 'agentdb', 'hybrid', 'redis', 'memory']).default('hybrid'),
1303
+ path: z.string().optional(),
1304
+ maxSize: z.number().int().positive().optional(),
1305
+ ttlMs: z.number().int().positive().optional(),
1306
+ sqlite: z.object({
1307
+ filename: z.string().optional(),
1308
+ inMemory: z.boolean().default(false),
1309
+ wal: z.boolean().default(true),
1310
+ }).optional(),
1311
+ agentdb: z.object({
1312
+ dimensions: z.number().int().positive().default(1536),
1313
+ indexType: z.enum(['hnsw', 'flat', 'ivf']).default('hnsw'),
1314
+ efConstruction: z.number().int().positive().default(200),
1315
+ m: z.number().int().positive().default(16),
1316
+ quantization: z.enum(['none', 'scalar', 'product']).default('none'),
1317
+ }).optional(),
1318
+ redis: z.object({
1319
+ host: z.string().default('localhost'),
1320
+ port: z.number().int().positive().default(6379),
1321
+ password: z.string().optional(),
1322
+ db: z.number().int().min(0).default(0),
1323
+ keyPrefix: z.string().default('claude-flow:'),
1324
+ }).optional(),
1325
+ hybrid: z.object({
1326
+ vectorThreshold: z.number().int().positive().default(100),
1327
+ }).optional(),
1328
+ });
1329
+
1330
+ /**
1331
+ * MCP server configuration schema
1332
+ */
1333
+ export const MCPServerConfigSchema = z.object({
1334
+ name: z.string().min(1).default('claude-flow'),
1335
+ version: z.string().min(1).default('3.0.0'),
1336
+ transport: z.object({
1337
+ type: z.enum(['stdio', 'http', 'websocket']).default('stdio'),
1338
+ port: z.number().int().positive().optional(),
1339
+ host: z.string().optional(),
1340
+ path: z.string().optional(),
1341
+ }),
1342
+ capabilities: z.object({
1343
+ tools: z.boolean().default(true),
1344
+ resources: z.boolean().default(true),
1345
+ prompts: z.boolean().default(true),
1346
+ logging: z.boolean().default(true),
1347
+ experimental: z.record(z.boolean()).optional(),
1348
+ }).optional(),
1349
+ });
1350
+
1351
+ /**
1352
+ * Orchestrator configuration schema
1353
+ */
1354
+ export const OrchestratorConfigSchema = z.object({
1355
+ session: z.object({
1356
+ persistSessions: z.boolean().default(true),
1357
+ dataDir: z.string().default('./data'),
1358
+ sessionRetentionMs: z.number().int().positive().default(3600000),
1359
+ }),
1360
+ health: z.object({
1361
+ checkInterval: z.number().int().positive().default(30000),
1362
+ historyLimit: z.number().int().positive()
1363
+
1364
+ --- src/core/config/validator.ts ---
1365
+ /**
1366
+ * V3 Configuration Validator
1367
+ * Validation logic using Zod schemas
1368
+ */
1369
+
1370
+ import { z, type ZodError } from 'zod';
1371
+ import {
1372
+ AgentConfigSchema,
1373
+ TaskConfigSchema,
1374
+ SwarmConfigSchema,
1375
+ MemoryConfigSchema,
1376
+ MCPServerConfigSchema,
1377
+ OrchestratorConfigSchema,
1378
+ SystemConfigSchema,
1379
+ type AgentConfig,
1380
+ type TaskConfig,
1381
+ type SwarmConfig,
1382
+ type MemoryConfig,
1383
+ type MCPServerConfig,
1384
+ type OrchestratorConfig,
1385
+ type SystemConfig,
1386
+ } from './schema.js';
1387
+
1388
+ /**
1389
+ * Validation result
1390
+ */
1391
+ export interface ValidationResult<T> {
1392
+ success: boolean;
1393
+ data?: T;
1394
+ errors?: ValidationError[];
1395
+ }
1396
+
1397
+ /**
1398
+ * Validation error
1399
+ */
1400
+ export interface ValidationError {
1401
+ path: string;
1402
+ message: string;
1403
+ code: string;
1404
+ }
1405
+
1406
+ /**
1407
+ * Convert Zod error to validation errors
1408
+ */
1409
+ function zodErrorToValidationErrors(error: ZodError): ValidationError[] {
1410
+ return error.errors.map((e) => ({
1411
+ path: e.path.join('.'),
1412
+ message: e.message,
1413
+ code: e.code,
1414
+ }));
1415
+ }
1416
+
1417
+ /**
1418
+ * Generic validation function
1419
+ * Uses parse + try/catch to get output types with defaults applied
1420
+ */
1421
+ function validate<TInput, TOutput>(
1422
+ schema: z.ZodType<TOutput, z.ZodTypeDef, TInput>,
1423
+ data: unknown
1424
+ ): ValidationResult<TOutput> {
1425
+ try {
1426
+ const parsed = schema.parse(data);
1427
+ return {
1428
+ success: true,
1429
+ data: parsed,
1430
+ };
1431
+ } catch (error) {
1432
+ if (error instanceof z.ZodError) {
1433
+ return {
1434
+ success: false,
1435
+ errors: zodErrorToValidationErrors(error),
1436
+ };
1437
+ }
1438
+ throw error;
1439
+ }
1440
+ }
1441
+
1442
+ /**
1443
+ * Validate agent configuration
1444
+ */
1445
+ export function validateAgentConfig(data: unknown): ValidationResult<AgentConfig> {
1446
+ return validate(AgentConfigSchema, data);
1447
+ }
1448
+
1449
+ /**
1450
+ * Validate task configuration
1451
+ */
1452
+ export function validateTaskConfig(data: unknown): ValidationResult<TaskConfig> {
1453
+ return validate(TaskConfigSchema, data);
1454
+ }
1455
+
1456
+ /**
1457
+ * Validate swarm configuration
1458
+ */
1459
+ export function validateSwarmConfig(data: unknown): ValidationResult<SwarmConfig> {
1460
+ return validate(SwarmConfigSchema, data);
1461
+ }
1462
+
1463
+ /**
1464
+ * Validate memory configuration
1465
+ */
1466
+ export function validateMemoryConfig(data: unknown): ValidationResult<MemoryConfig> {
1467
+ return validate(MemoryConfigSchema, data);
1468
+ }
1469
+
1470
+ /**
1471
+ * Validate MCP server configuration
1472
+ */
1473
+ export function validateMCPServerConfig(data: unknown): ValidationResult<MCPServerConfig> {
1474
+ return validate(MCPServerConfigSchema, data);
1475
+ }
1476
+
1477
+ /**
1478
+ * Validate orchestrator configuration
1479
+ */
1480
+ export function validateOrchestratorConfig(data: unknown): ValidationResult<OrchestratorConfig> {
1481
+ return validate(OrchestratorConfigSchema, data);
1482
+ }
1483
+
1484
+ /**
1485
+ * Validate full system configuration
1486
+ */
1487
+ export function validateSystemConfig(data: unknown): ValidationResult<SystemConfig> {
1488
+ return validate(SystemConfigSchema, data);
1489
+ }
1490
+
1491
+ /**
1492
+ * Configuration validator class
1493
+ */
1494
+ export class ConfigValidator {
1495
+ /**
1496
+ * Validate and throw on error
1497
+ */
1498
+ static validateOrThrow<TInput, TOutput>(
1499
+ schema: z.ZodType<TOutput, z.ZodTypeDef, TInput>,
1500
+ data: unknown,
1501
+ configName: string
1502
+ ): TOutput {
1503
+ const result = validate(schema, data);
1504
+
1505
+ if (!result.success) {
1506
+ const errorMessages = result.errors
1507
+ ?.map((e) => ` - ${e.path}: ${e.message}`)
1508
+ .join('\n');
1509
+ throw new Error(`Invalid ${configName} configuration:\n${errorMessages}`);
1510
+ }
1511
+
1512
+ return result.data!;
1513
+ }
1514
+
1515
+ /**
1516
+ * Validate agent config or throw
1517
+ */
1518
+ static validateAgentOrThrow(data: unknown): AgentConfig {
1519
+ return this.validateOrThrow(AgentConfigSchema, data, 'agent');
1520
+ }
1521
+
1522
+ /**
1523
+ * Validate task config or throw
1524
+ */
1525
+ static validateTaskOrThrow(data: unknown): TaskConfig {
1526
+ return this.validateOrThrow(TaskConfigSchema, data, 'task');
1527
+ }
1528
+
1529
+ /**
1530
+ * Validate swarm config or throw
1531
+ */
1532
+ static validateSwarmOrThrow(data: unknown): SwarmConfig {
1533
+ return this.validateOrThrow(SwarmConfigSchema, data, 'swarm');
1534
+ }
1535
+
1536
+ /**
1537
+ * Validate memory config or throw
1538
+ */
1539
+ static validateMemoryOrThrow(data: unknown): MemoryConfig {
1540
+ return this.validateOrThrow(MemoryConfigSchema, data, 'memory');
1541
+ }
1542
+
1543
+ /**
1544
+ * Validate MCP server config or throw
1545
+ */
1546
+ static validateMCPServerOrThrow(data: unknown): MCPServerConfig {
1547
+ return this.validateOrThrow(MCPServerConfigSchema, data, 'MCP server');
1548
+ }
1549
+
1550
+ /**
1551
+ * Validate orchestrator config or throw
1552
+ */
1553
+ static validateOrchestratorOrThrow(data: unknown): OrchestratorConfig {
1554
+ return this.validateOrThrow(OrchestratorConfigSchema, data, 'orchestrator');
1555
+ }
1556
+
1557
+ /**
1558
+ * Validate system config or throw
1559
+ */
1560
+ static validateSystemOrThrow(data: unknown): SystemConfig {
1561
+ return this.validateOrThrow(SystemConfigSchema, data, 'system');
1562
+ }
1563
+
1564
+ /**
1565
+ * Check if data matches schema
1566
+ */
1567
+ static isValid<TInput, TOutput>(
1568
+ schema: z.ZodType<TOutput, z.ZodTypeDef, TInput>,
1569
+ data: unknown
1570
+ ): boolean {
1571
+ return validate(schema, data).success;
1572
+ }
1573
+ }
1574
+
1575
+
1576
+ --- src/core/event-bus.ts (truncated) ---
1577
+ /**
1578
+ * V3 Event Bus
1579
+ * Core event pub/sub implementation
1580
+ */
1581
+
1582
+ import type {
1583
+ IEvent,
1584
+ IEventBus,
1585
+ IEventCreate,
1586
+ IEventHandler,
1587
+ IEventSubscription,
1588
+ IEventFilter,
1589
+ } from './interfaces/event.interface.js';
1590
+ import { randomBytes } from 'crypto';
1591
+
1592
+ // Secure event ID generation
1593
+ function generateSecureEventId(): string {
1594
+ const timestamp = Date.now().toString(36);
1595
+ const random = randomBytes(12).toString('hex');
1596
+ return `evt_${timestamp}_${random}`;
1597
+ }
1598
+
1599
+ /**
1600
+ * Event subscription implementation
1601
+ */
1602
+ class EventSubscription implements IEventSubscription {
1603
+ private active = true;
1604
+ private paused = false;
1605
+
1606
+ constructor(
1607
+ readonly id: string,
1608
+ readonly filter: IEventFilter,
1609
+ private removeCallback: () => void,
1610
+ ) {}
1611
+
1612
+ unsubscribe(): void {
1613
+ this.active = false;
1614
+ this.removeCallback();
1615
+ }
1616
+
1617
+ pause(): void {
1618
+ this.paused = true;
1619
+ }
1620
+
1621
+ resume(): void {
1622
+ this.paused = false;
1623
+ }
1624
+
1625
+ isActive(): boolean {
1626
+ return this.active && !this.paused;
1627
+ }
1628
+ }
1629
+
1630
+ /**
1631
+ * Event bus implementation
1632
+ */
1633
+ export class EventBus implements IEventBus {
1634
+ private handlers = new Map<string, Set<IEventHandler>>();
1635
+ private subscriptions = new Map<string, { filter: IEventFilter; handler: IEventHandler; subscription: EventSubscription }>();
1636
+ private subscriptionId = 0;
1637
+
1638
+ emit<T = unknown>(type: string, payload: T, options?: Partial<IEventCreate<T>>): void {
1639
+ const event = this.createEvent(type, payload, options);
1640
+ this.dispatchEvent(event);
1641
+ }
1642
+
1643
+ async emitAsync<T = unknown>(type: string, payload: T, options?: Partial<IEventCreate<T>>): Promise<void> {
1644
+ const event = this.createEvent(type, payload, options);
1645
+ await this.dispatchEventAsync(event);
1646
+ }
1647
+
1648
+ on<T = unknown>(type: string, handler: IEventHandler<T>): IEventSubscription {
1649
+ return this.subscribe({ types: [type] }, handler);
1650
+ }
1651
+
1652
+ subscribe<T = unknown>(filter: IEventFilter, handler: IEventHandler<T>): IEventSubscription {
1653
+ const id = `sub_${++this.subscriptionId}`;
1654
+
1655
+ // Register for all matching types
1656
+ const types = filter.types ?? ['*'];
1657
+ for (const type of types) {
1658
+ let handlers = this.handlers.get(type);
1659
+ if (!handlers) {
1660
+ handlers = new Set();
1661
+ this.handlers.set(type, handlers);
1662
+ }
1663
+ handlers.add(handler as IEventHandler);
1664
+ }
1665
+
1666
+ const subscription = new EventSubscription(id, filter, () => {
1667
+ this.removeSubscription(id);
1668
+ });
1669
+
1670
+ this.subscriptions.set(id, { filter, handler: handler as IEventHandler, subscription });
1671
+
1672
+ return subscription;
1673
+ }
1674
+
1675
+ once<T = unknown>(type: string, handler: IEventHandler<T>): IEventSubscription {
1676
+ const wrappedHandler: IEventHandler<T> = async (event) => {
1677
+ subscription.unsubscribe();
1678
+ await handler(event);
1679
+ };
1680
+
1681
+ const subscription = this.on(type, wrappedHandler);
1682
+ return subscription;
1683
+ }
1684
+
1685
+ off(type: string, handler: IEventHandler): void {
1686
+ const handlers = this.handlers.get(type);
1687
+ if (handlers) {
1688
+ handlers.delete(handler);
1689
+ if (handlers.size === 0) {
1690
+ this.handlers.delete(type);
1691
+ }
1692
+ }
1693
+ }
1694
+
1695
+ removeAllListeners(type?: string): void {
1696
+ if (type) {
1697
+ this.handlers.delete(type);
1698
+ } else {
1699
+ this.handlers.clear();
1700
+ }
1701
+ }
1702
+
1703
+ listenerCount(type: string): number {
1704
+ return this.handlers.get(type)?.size ?? 0;
1705
+ }
1706
+
1707
+ eventNames(): string[] {
1708
+ return Array.from(this.handlers.keys());
1709
+ }
1710
+
1711
+ private createEvent<T>(type: string, payload: T, options?: Partial<IEventCreate<T>>): IEvent<T> {
1712
+ return {
1713
+ id: generateSecureEventId(),
1714
+ type,
1715
+ timestamp: new Date(),
1716
+ source: options?.source ?? 'event-bus',
1717
+ payload,
1718
+ priority: options?.priority,
1719
+ correlationId: options?.correlationId,
1720
+ causationId: options?.causationId,
1721
+ metadata: options?.metadata,
1722
+ };
1723
+ }
1724
+
1725
+ private dispatchEvent<T>(event: IEvent<T>): void {
1726
+ // Get handlers for specific type
1727
+ const typeHandlers = this.handlers.get(event.type);
1728
+
1729
+ // Get wildcard handlers
1730
+ const wildcardHandlers = this.handlers.get('*');
1731
+
1732
+ const allHandlers = new Set<IEventHandler>();
1733
+
1734
+ if (typeHandlers) {
1735
+ for (const handler of typeHandlers) {
1736
+ allHandlers.add(handler);
1737
+ }
1738
+ }
1739
+
1740
+ if (wildcardHandlers) {
1741
+ for (const handler of wildcardHandlers) {
1742
+ allHandlers.add(handler);
1743
+ }
1744
+ }
1745
+
1746
+ for (const handler of allHandlers) {
1747
+ try {
1748
+ const result = handler(event);
1749
+ if (result instanceof Promise) {
1750
+ result.catch((error) => {
1751
+ console.error(`Error in async event handler for ${event.type}:`, error);
1752
+ });
1753
+ }
1754
+ } catch (error) {
1755
+ console.error(`Error in event handler for ${event.type}:`, error);
1756
+ }
1757
+ }
1758
+ }
1759
+
1760
+ private async dispatchEventAsync<T>(event: IEvent<T>): Promise<void> {
1761
+ const typeHandlers = this.handlers.get(event.type);
1762
+ const wildcardHandlers = this.handlers.get('*');
1763
+
1764
+ const allHandlers = new Set<IEventHandler>();
1765
+
1766
+ if (typeHandlers) {
1767
+ for (const handler
1768
+
1769
+ --- src/core/index.ts ---
1770
+ /**
1771
+ * V3 Core Module - Public API
1772
+ * Domain-Driven Design with Clean Architecture
1773
+ *
1774
+ * This module provides the core architecture for claude-flow v3:
1775
+ * - Decomposed orchestrator (task, session, health, lifecycle management)
1776
+ * - Event-driven architecture with event bus and coordinator
1777
+ * - Type-safe configuration with Zod validation
1778
+ * - Clean interfaces following DDD principles
1779
+ */
1780
+
1781
+ // Interfaces (Domain contracts)
1782
+ export * from './interfaces/index.js';
1783
+
1784
+ // Event system
1785
+ export { EventBus, createEventBus } from './event-bus.js';
1786
+
1787
+ // Orchestrator components (decomposed)
1788
+ export * from './orchestrator/index.js';
1789
+
1790
+ // Configuration
1791
+ export * from './config/index.js';
1792
+
1793
+
1794
+ --- src/core/interfaces/agent.interface.ts ---
1795
+ /**
1796
+ * V3 Agent Interfaces
1797
+ * Domain-Driven Design - Agent Lifecycle Bounded Context
1798
+ */
1799
+
1800
+ /**
1801
+ * Agent status in the system
1802
+ */
1803
+ export type AgentStatus = 'spawning' | 'active' | 'idle' | 'busy' | 'error' | 'terminated';
1804
+
1805
+ /**
1806
+ * Agent type classification
1807
+ */
1808
+ export type AgentType =
1809
+ | 'coder'
1810
+ | 'reviewer'
1811
+ | 'tester'
1812
+ | 'researcher'
1813
+ | 'planner'
1814
+ | 'architect'
1815
+ | 'coordinator'
1816
+ | 'security'
1817
+ | 'performance'
1818
+ | 'custom';
1819
+
1820
+ /**
1821
+ * Agent capability declaration
1822
+ */
1823
+ export interface IAgentCapability {
1824
+ name: string;
1825
+ level: 'basic' | 'intermediate' | 'advanced' | 'expert';
1826
+ description?: string;
1827
+ }
1828
+
1829
+ /**
1830
+ * Agent configuration for spawning
1831
+ */
1832
+ export interface IAgentConfig {
1833
+ readonly id: string;
1834
+ readonly name: string;
1835
+ readonly type: AgentType | string;
1836
+
1837
+ capabilities: string[];
1838
+ maxConcurrentTasks: number;
1839
+ priority: number;
1840
+
1841
+ timeout?: number;
1842
+ retryPolicy?: {
1843
+ maxRetries: number;
1844
+ backoffMs: number;
1845
+ backoffMultiplier: number;
1846
+ };
1847
+
1848
+ resources?: {
1849
+ maxMemoryMb?: number;
1850
+ maxCpuPercent?: number;
1851
+ };
1852
+
1853
+ metadata?: Record<string, unknown>;
1854
+ }
1855
+
1856
+ /**
1857
+ * Core agent entity
1858
+ */
1859
+ export interface IAgent {
1860
+ readonly id: string;
1861
+ readonly name: string;
1862
+ readonly type: AgentType | string;
1863
+ readonly config: IAgentConfig;
1864
+ readonly createdAt: Date;
1865
+
1866
+ status: AgentStatus;
1867
+ currentTaskCount: number;
1868
+ lastActivity: Date;
1869
+
1870
+ sessionId?: string;
1871
+ terminalId?: string;
1872
+ memoryBankId?: string;
1873
+
1874
+ metrics?: {
1875
+ tasksCompleted: number;
1876
+ tasksFailed: number;
1877
+ avgTaskDuration: number;
1878
+ errorCount: number;
1879
+ uptime: number;
1880
+ };
1881
+
1882
+ health?: {
1883
+ status: 'healthy' | 'degraded' | 'unhealthy';
1884
+ lastCheck: Date;
1885
+ issues?: string[];
1886
+ };
1887
+ }
1888
+
1889
+ /**
1890
+ * Agent session for tracking active work
1891
+ */
1892
+ export interface IAgentSession {
1893
+ readonly id: string;
1894
+ readonly agentId: string;
1895
+ readonly startTime: Date;
1896
+
1897
+ status: 'active' | 'idle' | 'terminated';
1898
+ terminalId: string;
1899
+ memoryBankId: string;
1900
+
1901
+ lastActivity: Date;
1902
+ endTime?: Date;
1903
+
1904
+ metadata?: Record<string, unknown>;
1905
+ }
1906
+
1907
+ /**
1908
+ * Agent pool for managing multiple agents
1909
+ */
1910
+ export interface IAgentPool {
1911
+ /**
1912
+ * Add an agent to the pool
1913
+ */
1914
+ add(agent: IAgent): void;
1915
+
1916
+ /**
1917
+ * Remove an agent from the pool
1918
+ */
1919
+ remove(agentId: string): boolean;
1920
+
1921
+ /**
1922
+ * Get an agent by ID
1923
+ */
1924
+ get(agentId: string): IAgent | undefined;
1925
+
1926
+ /**
1927
+ * Get all agents in the pool
1928
+ */
1929
+ getAll(): IAgent[];
1930
+
1931
+ /**
1932
+ * Get agents by status
1933
+ */
1934
+ getByStatus(status: AgentStatus): IAgent[];
1935
+
1936
+ /**
1937
+ * Get agents by type
1938
+ */
1939
+ getByType(type: AgentType | string): IAgent[];
1940
+
1941
+ /**
1942
+ * Get available agents (can accept more tasks)
1943
+ */
1944
+ getAvailable(): IAgent[];
1945
+
1946
+ /**
1947
+ * Get pool size
1948
+ */
1949
+ size(): number;
1950
+
1951
+ /**
1952
+ * Check if pool has capacity
1953
+ */
1954
+ hasCapacity(maxSize: number): boolean;
1955
+
1956
+ /**
1957
+ * Clear all agents
1958
+ */
1959
+ clear(): void;
1960
+ }
1961
+
1962
+ /**
1963
+ * Agent lifecycle manager interface
1964
+ */
1965
+ export interface IAgentLifecycleManager {
1966
+ /**
1967
+ * Spawn a new agent
1968
+ */
1969
+ spawn(config: IAgentConfig): Promise<IAgent>;
1970
+
1971
+ /**
1972
+ * Spawn multiple agents in parallel
1973
+ */
1974
+ spawnBatch(configs: IAgentConfig[]): Promise<Map<string, IAgent>>;
1975
+
1976
+ /**
1977
+ * Terminate an agent
1978
+ */
1979
+ terminate(agentId: string, reason?: string): Promise<void>;
1980
+
1981
+ /**
1982
+ * Terminate all agents
1983
+ */
1984
+ terminateAll(reason?: string): Promise<void>;
1985
+
1986
+ /**
1987
+ * Restart an agent
1988
+ */
1989
+ restart(agentId: string): Promise<IAgent>;
1990
+
1991
+ /**
1992
+ * Update agent configuration
1993
+ */
1994
+ updateConfig(agentId: string, config: Partial<IAgentConfig>): Promise<void>;
1995
+
1996
+ /**
1997
+ * Get agent by ID
1998
+ */
1999
+ getAgent(agentId: string): IAgent | undefined;
2000
+
2001
+ /**
2002
+ * Get all agents
2003
+ */
2004
+ getAllAgents(): IAgent[];
2005
+
2006
+ /**
2007
+ * Get active agents count
2008
+ */
2009
+ getActiveCount(): number;
2010
+
2011
+ /**
2012
+ * Check agent health
2013
+ */
2014
+ checkHealth(agentId: string): Promise<IAgent['health']>;
2015
+ }
2016
+
2017
+ /**
2018
+ * Agent registry for type definitions
2019
+ */
2020
+ export interface IAgentRegistry {
2021
+ /**
2022
+ * Register an agent type with default config
2023
+ */
2024
+ register(type: string, defaultConfig: Partial<IAgentConfig>): void;
2025
+
2026
+ /**
2027
+ * Unregister an agent type
2028
+ */
2029
+ unregister(type: string): boolean;
2030
+
2031
+ /**
2032
+ * Get default config for a type
2033
+ */
2034
+ getDefaultConfig(type: string): Partial<IAgentConfig> | undefined;
2035
+
2036
+ /**
2037
+ * Get all registered types
2038
+ */
2039
+ getRegisteredTypes(): string[];
2040
+
2041
+ /**
2042
+ * Check if a type is registered
2043
+ */
2044
+ isRegistered(type: string): boolean;
2045
+ }
2046
+
2047
+
2048
+ --- src/core/interfaces/coordinator.interface.ts (truncated) ---
2049
+ /**
2050
+ * V3 Coordinator Interfaces
2051
+ * Domain-Driven Design - Coordination Bounded Context
2052
+ * Aligned with ADR-003 (Single Coordination Engine)
2053
+ */
2054
+
2055
+ import type { ITask, ITaskResult } from './task.interface.js';
2056
+ import type { IAgent, IAgentConfig } from './agent.interface.js';
2057
+
2058
+ /**
2059
+ * Swarm topology types
2060
+ */
2061
+ export type SwarmTopology =
2062
+ | 'hierarchical'
2063
+ | 'mesh'
2064
+ | 'ring'
2065
+ | 'star'
2066
+ | 'adaptive'
2067
+ | 'hierarchical-mesh';
2068
+
2069
+ /**
2070
+ * Coordination status
2071
+ */
2072
+ export type CoordinationStatus =
2073
+ | 'initializing'
2074
+ | 'ready'
2075
+ | 'coordinating'
2076
+ | 'degraded'
2077
+ | 'error'
2078
+ | 'shutdown';
2079
+
2080
+ /**
2081
+ * Swarm configuration
2082
+ */
2083
+ export interface ISwarmConfig {
2084
+ topology: SwarmTopology;
2085
+ maxAgents: number;
2086
+
2087
+ autoScale?: {
2088
+ enabled: boolean;
2089
+ minAgents: number;
2090
+ maxAgents: number;
2091
+ scaleUpThreshold: number;
2092
+ scaleDownThreshold: number;
2093
+ };
2094
+
2095
+ coordination?: {
2096
+ consensusRequired: boolean;
2097
+ timeoutMs: number;
2098
+ retryPolicy: {
2099
+ maxRetries: number;
2100
+ backoffMs: number;
2101
+ };
2102
+ };
2103
+
2104
+ communication?: {
2105
+ protocol: 'events' | 'messages' | 'shared-memory';
2106
+ batchSize: number;
2107
+ flushIntervalMs: number;
2108
+ };
2109
+
2110
+ metadata?: Record<string, unknown>;
2111
+ }
2112
+
2113
+ /**
2114
+ * Swarm state
2115
+ */
2116
+ export interface ISwarmState {
2117
+ readonly id: string;
2118
+ readonly topology: SwarmTopology;
2119
+ readonly createdAt: Date;
2120
+
2121
+ status: CoordinationStatus;
2122
+ agentCount: number;
2123
+ taskCount: number;
2124
+
2125
+ metrics?: {
2126
+ throughput: number;
2127
+ latencyMs: number;
2128
+ successRate: number;
2129
+ resourceUtilization: number;
2130
+ };
2131
+ }
2132
+
2133
+ /**
2134
+ * Coordinator interface - unified coordination engine
2135
+ */
2136
+ export interface ICoordinator {
2137
+ /**
2138
+ * Initialize the coordinator
2139
+ */
2140
+ initialize(): Promise<void>;
2141
+
2142
+ /**
2143
+ * Shutdown the coordinator
2144
+ */
2145
+ shutdown(): Promise<void>;
2146
+
2147
+ /**
2148
+ * Initialize a swarm with configuration
2149
+ */
2150
+ initializeSwarm(config: ISwarmConfig): Promise<ISwarmState>;
2151
+
2152
+ /**
2153
+ * Get swarm state
2154
+ */
2155
+ getSwarmState(): ISwarmState | undefined;
2156
+
2157
+ /**
2158
+ * Assign a task to an agent
2159
+ */
2160
+ assignTask(task: ITask, agentId: string): Promise<void>;
2161
+
2162
+ /**
2163
+ * Get tasks assigned to an agent
2164
+ */
2165
+ getAgentTasks(agentId: string): Promise<ITask[]>;
2166
+
2167
+ /**
2168
+ * Get task count for an agent
2169
+ */
2170
+ getAgentTaskCount(agentId: string): Promise<number>;
2171
+
2172
+ /**
2173
+ * Cancel a task
2174
+ */
2175
+ cancelTask(taskId: string): Promise<void>;
2176
+
2177
+ /**
2178
+ * Report task completion
2179
+ */
2180
+ reportTaskComplete(taskId: string, result: ITaskResult): Promise<void>;
2181
+
2182
+ /**
2183
+ * Get coordination health status
2184
+ */
2185
+ getHealthStatus(): Promise<{ healthy: boolean; error?: string; metrics?: Record<string, number> }>;
2186
+
2187
+ /**
2188
+ * Perform maintenance tasks
2189
+ */
2190
+ performMaintenance(): Promise<void>;
2191
+ }
2192
+
2193
+ /**
2194
+ * Coordination manager interface - higher-level orchestration
2195
+ */
2196
+ export interface ICoordinationManager extends ICoordinator {
2197
+ /**
2198
+ * Register an agent with the coordinator
2199
+ */
2200
+ registerAgent(agent: IAgent): Promise<void>;
2201
+
2202
+ /**
2203
+ * Unregister an agent
2204
+ */
2205
+ unregisterAgent(agentId: string): Promise<void>;
2206
+
2207
+ /**
2208
+ * Get all registered agents
2209
+ */
2210
+ getRegisteredAgents(): IAgent[];
2211
+
2212
+ /**
2213
+ * Request agent consensus on a decision
2214
+ */
2215
+ requestConsensus(topic: string, options: unknown[], timeout?: number): Promise<unknown>;
2216
+
2217
+ /**
2218
+ * Broadcast message to all agents
2219
+ */
2220
+ broadcast(message: unknown): Promise<void>;
2221
+
2222
+ /**
2223
+ * Send message to specific agent
2224
+ */
2225
+ sendToAgent(agentId: string, message: unknown): Promise<void>;
2226
+
2227
+ /**
2228
+ * Acquire a distributed lock
2229
+ */
2230
+ acquireLock(resourceId: string, agentId: string, timeout?: number): Promise<boolean>;
2231
+
2232
+ /**
2233
+ * Release a distributed lock
2234
+ */
2235
+ releaseLock(resourceId: string, agentId: string): Promise<void>;
2236
+
2237
+ /**
2238
+ * Check for deadlocks
2239
+ */
2240
+ detectDeadlocks(): Promise<{ detected: boolean; agents?: string[]; resources?: string[] }>;
2241
+ }
2242
+
2243
+ /**
2244
+ * Health status for components
2245
+ */
2246
+ export interface IHealthStatus {
2247
+ status: 'healthy' | 'degraded' | 'unhealthy';
2248
+ components: Record<string, IComponentHealth>;
2249
+ timestamp: Date;
2250
+ }
2251
+
2252
+ /**
2253
+ * Component health details
2254
+ */
2255
+ export interface IComponentHealth {
2256
+ name: string;
2257
+ status: 'healthy' | 'degraded' | 'unhealthy';
2258
+ lastCheck: Date;
2259
+ error?: string;
2260
+ metrics?: Record<string, number>;
2261
+ }
2262
+
2263
+ /**
2264
+ * Health monitor interface
2265
+ */
2266
+ export interface IHealthMonitor {
2267
+ /**
2268
+ * Start health monitoring
2269
+ */
2270
+ start(): void;
2271
+
2272
+ /**
2273
+ * Stop health monitoring
2274
+ */
2275
+ stop(): void;
2276
+
2277
+ /**
2278
+ * Get current health status
2279
+ */
2280
+ getStatus(): Promise<IHealthStatus>;
2281
+
2282
+ /**
2283
+ * Register a health check
2284
+ */
2285
+ registerCheck(
2286
+ name: string,
2287
+ check: () => Promise<{ healthy: boolean; error?: string; metrics?: Record<string, number> }>
2288
+ ): void;
2289
+
2290
+ /**
2291
+ * Unregister a health check
2292
+ */
2293
+ unregisterCheck(name: string): void;
2294
+
2295
+ /**
2296
+ * Get health history
2297
+ */
2298
+ getHistory(limit?: number): IHealthStatus[];
2299
+
2300
+ /**
2301
+ * Subscribe to health changes
2302
+ */
2303
+ onHealthChange(callback: (status: IHealthStatus) => void): () => void;
2304
+ }
2305
+
2306
+ /**
2307
+ * Metrics co
2308
+
2309
+ --- src/core/interfaces/event.interface.ts (truncated) ---
2310
+ /**
2311
+ * V3 Event Interfaces
2312
+ * Domain-Driven Design - Event Sourcing Pattern (ADR-007)
2313
+ */
2314
+
2315
+ /**
2316
+ * Event priority levels
2317
+ */
2318
+ export type EventPriority = 'critical' | 'high' | 'normal' | 'low';
2319
+
2320
+ /**
2321
+ * Core event structure
2322
+ */
2323
+ export interface IEvent<T = unknown> {
2324
+ readonly id: string;
2325
+ readonly type: string;
2326
+ readonly timestamp: Date;
2327
+ readonly source: string;
2328
+
2329
+ payload: T;
2330
+ priority?: EventPriority;
2331
+ correlationId?: string;
2332
+ causationId?: string;
2333
+
2334
+ metadata?: {
2335
+ version?: number;
2336
+ userId?: string;
2337
+ sessionId?: string;
2338
+ [key: string]: unknown;
2339
+ };
2340
+ }
2341
+
2342
+ /**
2343
+ * Event creation parameters
2344
+ */
2345
+ export interface IEventCreate<T = unknown> {
2346
+ type: string;
2347
+ payload: T;
2348
+ source?: string;
2349
+ priority?: EventPriority;
2350
+ correlationId?: string;
2351
+ causationId?: string;
2352
+ metadata?: IEvent['metadata'];
2353
+ }
2354
+
2355
+ /**
2356
+ * Event handler function type
2357
+ */
2358
+ export type IEventHandler<T = unknown> = (event: IEvent<T>) => void | Promise<void>;
2359
+
2360
+ /**
2361
+ * Event filter for subscriptions
2362
+ */
2363
+ export interface IEventFilter {
2364
+ types?: string[];
2365
+ sources?: string[];
2366
+ priority?: EventPriority[];
2367
+ correlationId?: string;
2368
+ }
2369
+
2370
+ /**
2371
+ * Event subscription handle
2372
+ */
2373
+ export interface IEventSubscription {
2374
+ readonly id: string;
2375
+ readonly filter: IEventFilter;
2376
+
2377
+ /**
2378
+ * Unsubscribe from events
2379
+ */
2380
+ unsubscribe(): void;
2381
+
2382
+ /**
2383
+ * Pause subscription
2384
+ */
2385
+ pause(): void;
2386
+
2387
+ /**
2388
+ * Resume subscription
2389
+ */
2390
+ resume(): void;
2391
+
2392
+ /**
2393
+ * Check if subscription is active
2394
+ */
2395
+ isActive(): boolean;
2396
+ }
2397
+
2398
+ /**
2399
+ * Event bus interface for pub/sub communication
2400
+ */
2401
+ export interface IEventBus {
2402
+ /**
2403
+ * Emit an event to all subscribers
2404
+ */
2405
+ emit<T = unknown>(type: string, payload: T, options?: Partial<IEventCreate<T>>): void;
2406
+
2407
+ /**
2408
+ * Emit an event and wait for all handlers
2409
+ */
2410
+ emitAsync<T = unknown>(type: string, payload: T, options?: Partial<IEventCreate<T>>): Promise<void>;
2411
+
2412
+ /**
2413
+ * Subscribe to events matching a type pattern
2414
+ */
2415
+ on<T = unknown>(type: string, handler: IEventHandler<T>): IEventSubscription;
2416
+
2417
+ /**
2418
+ * Subscribe to events with filter
2419
+ */
2420
+ subscribe<T = unknown>(filter: IEventFilter, handler: IEventHandler<T>): IEventSubscription;
2421
+
2422
+ /**
2423
+ * Subscribe to a single event occurrence
2424
+ */
2425
+ once<T = unknown>(type: string, handler: IEventHandler<T>): IEventSubscription;
2426
+
2427
+ /**
2428
+ * Remove a specific handler
2429
+ */
2430
+ off(type: string, handler: IEventHandler): void;
2431
+
2432
+ /**
2433
+ * Remove all handlers for a type
2434
+ */
2435
+ removeAllListeners(type?: string): void;
2436
+
2437
+ /**
2438
+ * Get count of listeners for a type
2439
+ */
2440
+ listenerCount(type: string): number;
2441
+
2442
+ /**
2443
+ * Get all event types with active listeners
2444
+ */
2445
+ eventNames(): string[];
2446
+ }
2447
+
2448
+ /**
2449
+ * System event types enumeration
2450
+ */
2451
+ export const SystemEventTypes = {
2452
+ // System lifecycle
2453
+ SYSTEM_READY: 'system:ready',
2454
+ SYSTEM_SHUTDOWN: 'system:shutdown',
2455
+ SYSTEM_ERROR: 'system:error',
2456
+ SYSTEM_HEALTHCHECK: 'system:healthcheck',
2457
+
2458
+ // Agent lifecycle
2459
+ AGENT_SPAWNED: 'agent:spawned',
2460
+ AGENT_TERMINATED: 'agent:terminated',
2461
+ AGENT_ERROR: 'agent:error',
2462
+ AGENT_IDLE: 'agent:idle',
2463
+ AGENT_BUSY: 'agent:busy',
2464
+ AGENT_HEALTH_CHANGED: 'agent:health:changed',
2465
+
2466
+ // Task lifecycle
2467
+ TASK_CREATED: 'task:created',
2468
+ TASK_ASSIGNED: 'task:assigned',
2469
+ TASK_STARTED: 'task:started',
2470
+ TASK_COMPLETED: 'task:completed',
2471
+ TASK_FAILED: 'task:failed',
2472
+ TASK_CANCELLED: 'task:cancelled',
2473
+ TASK_TIMEOUT: 'task:timeout',
2474
+ TASK_RETRY: 'task:retry',
2475
+
2476
+ // Session lifecycle
2477
+ SESSION_CREATED: 'session:created',
2478
+ SESSION_RESTORED: 'session:restored',
2479
+ SESSION_TERMINATED: 'session:terminated',
2480
+ SESSION_PERSISTED: 'session:persisted',
2481
+
2482
+ // Memory events
2483
+ MEMORY_STORED: 'memory:stored',
2484
+ MEMORY_RETRIEVED: 'memory:retrieved',
2485
+ MEMORY_CLEARED: 'memory:cleared',
2486
+
2487
+ // Coordination events
2488
+ COORDINATION_STARTED: 'coordination:started',
2489
+ COORDINATION_COMPLETED: 'coordination:completed',
2490
+ DEADLOCK_DETECTED: 'coordination:deadlock',
2491
+
2492
+ // Metrics events
2493
+ METRICS_COLLECTED: 'metrics:collected',
2494
+ } as const;
2495
+
2496
+ export type SystemEventType = typeof SystemEventTypes[keyof typeof SystemEventTypes];
2497
+
2498
+ /**
2499
+ * Event store interface for event sourcing
2500
+ */
2501
+ export interface IEventStore {
2502
+ /**
2503
+ * Append an event to the store
2504
+ */
2505
+ append(event: IEvent): Promise<void>;
2506
+
2507
+ /**
2508
+ * Get events by aggregate ID
2509
+ */
2510
+ getByAggregateId(aggregateId: string, fromVersion?: number): Promise<IEvent[]>;
2511
+
2512
+ /**
2513
+ * Get events by type
2514
+ */
2515
+ getByType(type: string, options?: { limit?: number; offset?: number }): Promise<IEvent[]>;
2516
+
2517
+ /**
2518
+ * Get events in time range
2519
+ */
2520
+ getByTimeRange(start: Date, end: Date): Promise<IEvent[]>;
2521
+
2522
+ /**
2523
+ * Get events by correlation ID
2524
+ */
2525
+ getByCorrelationId(correlationId: string): Promise<IEvent[]>;
2526
+
2527
+ /**
2528
+ * Get all events (paginated)
2529
+ */
2530
+ getAll(options?: { limit?: number; offset?: number }): Promise<IEvent[]>;
2531
+
2532
+ /**
2533
+ * Get event count
2534
+ */
2535
+ count(filter?: IEventFilter): Promise<number>;
2536
+
2537
+ /**
2538
+ * Clear old events
2539
+ */
2540
+ prune(olderThan: Date): P
2541
+
2542
+ --- src/core/interfaces/index.ts ---
2543
+ /**
2544
+ * V3 Core Interfaces - Public API
2545
+ * Domain-Driven Design with Clean Architecture
2546
+ */
2547
+
2548
+ // Task interfaces
2549
+ export * from './task.interface.js';
2550
+
2551
+ // Agent interfaces
2552
+ export * from './agent.interface.js';
2553
+
2554
+ // Event interfaces
2555
+ export * from './event.interface.js';
2556
+
2557
+ // Memory interfaces
2558
+ export * from './memory.interface.js';
2559
+
2560
+ // Coordinator interfaces
2561
+ export * from './coordinator.interface.js';
2562
+
2563
+
2564
+ --- src/core/interfaces/memory.interface.ts (truncated) ---
2565
+ /**
2566
+ * V3 Memory Interfaces
2567
+ * Domain-Driven Design - Memory Management Bounded Context
2568
+ * Aligned with ADR-006 (Unified Memory Service) and ADR-009 (Hybrid Memory Backend)
2569
+ */
2570
+
2571
+ /**
2572
+ * Memory entry types
2573
+ */
2574
+ export type MemoryType = 'session' | 'persistent' | 'vector' | 'cache' | 'pattern';
2575
+
2576
+ /**
2577
+ * Memory entry structure
2578
+ */
2579
+ export interface IMemoryEntry {
2580
+ readonly id: string;
2581
+ readonly key: string;
2582
+ readonly type: MemoryType;
2583
+ readonly createdAt: Date;
2584
+
2585
+ value: unknown;
2586
+ updatedAt: Date;
2587
+ expiresAt?: Date;
2588
+
2589
+ metadata?: {
2590
+ source?: string;
2591
+ agentId?: string;
2592
+ sessionId?: string;
2593
+ version?: number;
2594
+ tags?: string[];
2595
+ embedding?: number[];
2596
+ [key: string]: unknown;
2597
+ };
2598
+ }
2599
+
2600
+ /**
2601
+ * Memory entry creation parameters
2602
+ */
2603
+ export interface IMemoryEntryCreate {
2604
+ key: string;
2605
+ value: unknown;
2606
+ type?: MemoryType;
2607
+ expiresAt?: Date;
2608
+ ttlMs?: number;
2609
+ metadata?: IMemoryEntry['metadata'];
2610
+ }
2611
+
2612
+ /**
2613
+ * Vector search parameters
2614
+ */
2615
+ export interface IVectorSearchParams {
2616
+ embedding: number[];
2617
+ k?: number;
2618
+ threshold?: number;
2619
+ filter?: {
2620
+ type?: MemoryType;
2621
+ tags?: string[];
2622
+ agentId?: string;
2623
+ };
2624
+ }
2625
+
2626
+ /**
2627
+ * Vector search result
2628
+ */
2629
+ export interface IVectorSearchResult {
2630
+ entry: IMemoryEntry;
2631
+ score: number;
2632
+ distance: number;
2633
+ }
2634
+
2635
+ /**
2636
+ * Memory backend interface for storage operations
2637
+ */
2638
+ export interface IMemoryBackend {
2639
+ /**
2640
+ * Initialize the backend
2641
+ */
2642
+ initialize(): Promise<void>;
2643
+
2644
+ /**
2645
+ * Shutdown the backend
2646
+ */
2647
+ shutdown(): Promise<void>;
2648
+
2649
+ /**
2650
+ * Store a memory entry
2651
+ */
2652
+ store(entry: IMemoryEntryCreate): Promise<IMemoryEntry>;
2653
+
2654
+ /**
2655
+ * Retrieve a memory entry by key
2656
+ */
2657
+ retrieve(key: string): Promise<IMemoryEntry | undefined>;
2658
+
2659
+ /**
2660
+ * Retrieve by ID
2661
+ */
2662
+ retrieveById(id: string): Promise<IMemoryEntry | undefined>;
2663
+
2664
+ /**
2665
+ * Update a memory entry
2666
+ */
2667
+ update(key: string, value: unknown, metadata?: Partial<IMemoryEntry['metadata']>): Promise<IMemoryEntry | undefined>;
2668
+
2669
+ /**
2670
+ * Delete a memory entry
2671
+ */
2672
+ delete(key: string): Promise<boolean>;
2673
+
2674
+ /**
2675
+ * Check if a key exists
2676
+ */
2677
+ exists(key: string): Promise<boolean>;
2678
+
2679
+ /**
2680
+ * List all keys matching a pattern
2681
+ */
2682
+ keys(pattern?: string): Promise<string[]>;
2683
+
2684
+ /**
2685
+ * Get all entries matching filter
2686
+ */
2687
+ list(filter?: { type?: MemoryType; tags?: string[] }): Promise<IMemoryEntry[]>;
2688
+
2689
+ /**
2690
+ * Clear all entries
2691
+ */
2692
+ clear(): Promise<void>;
2693
+
2694
+ /**
2695
+ * Get entry count
2696
+ */
2697
+ count(): Promise<number>;
2698
+
2699
+ /**
2700
+ * Prune expired entries
2701
+ */
2702
+ prune(): Promise<number>;
2703
+
2704
+ /**
2705
+ * Get health status
2706
+ */
2707
+ getHealthStatus(): Promise<{ healthy: boolean; error?: string; metrics?: Record<string, number> }>;
2708
+ }
2709
+
2710
+ /**
2711
+ * Vector memory backend for similarity search
2712
+ */
2713
+ export interface IVectorMemoryBackend extends IMemoryBackend {
2714
+ /**
2715
+ * Store with embedding
2716
+ */
2717
+ storeVector(entry: IMemoryEntryCreate & { embedding: number[] }): Promise<IMemoryEntry>;
2718
+
2719
+ /**
2720
+ * Search by vector similarity
2721
+ */
2722
+ search(params: IVectorSearchParams): Promise<IVectorSearchResult[]>;
2723
+
2724
+ /**
2725
+ * Update embedding for an entry
2726
+ */
2727
+ updateEmbedding(key: string, embedding: number[]): Promise<boolean>;
2728
+
2729
+ /**
2730
+ * Build or rebuild index
2731
+ */
2732
+ buildIndex(): Promise<void>;
2733
+
2734
+ /**
2735
+ * Get index statistics
2736
+ */
2737
+ getIndexStats(): Promise<{
2738
+ vectorCount: number;
2739
+ dimensions: number;
2740
+ indexType: string;
2741
+ memoryUsageMb: number;
2742
+ }>;
2743
+ }
2744
+
2745
+ /**
2746
+ * Memory bank for agent-specific storage
2747
+ */
2748
+ export interface IMemoryBank {
2749
+ readonly id: string;
2750
+ readonly agentId: string;
2751
+ readonly createdAt: Date;
2752
+
2753
+ /**
2754
+ * Store in bank
2755
+ */
2756
+ store(key: string, value: unknown, options?: Partial<IMemoryEntryCreate>): Promise<IMemoryEntry>;
2757
+
2758
+ /**
2759
+ * Retrieve from bank
2760
+ */
2761
+ retrieve(key: string): Promise<IMemoryEntry | undefined>;
2762
+
2763
+ /**
2764
+ * Delete from bank
2765
+ */
2766
+ delete(key: string): Promise<boolean>;
2767
+
2768
+ /**
2769
+ * List all entries in bank
2770
+ */
2771
+ list(): Promise<IMemoryEntry[]>;
2772
+
2773
+ /**
2774
+ * Clear all entries in bank
2775
+ */
2776
+ clear(): Promise<void>;
2777
+
2778
+ /**
2779
+ * Get bank size
2780
+ */
2781
+ size(): Promise<number>;
2782
+
2783
+ /**
2784
+ * Close the bank
2785
+ */
2786
+ close(): Promise<void>;
2787
+ }
2788
+
2789
+ /**
2790
+ * Memory manager interface
2791
+ */
2792
+ export interface IMemoryManager {
2793
+ /**
2794
+ * Initialize the manager
2795
+ */
2796
+ initialize(): Promise<void>;
2797
+
2798
+ /**
2799
+ * Shutdown the manager
2800
+ */
2801
+ shutdown(): Promise<void>;
2802
+
2803
+ /**
2804
+ * Create a memory bank for an agent
2805
+ */
2806
+ createBank(agentId: string): Promise<string>;
2807
+
2808
+ /**
2809
+ * Get a memory bank
2810
+ */
2811
+ getBank(bankId: string): IMemoryBank | undefined;
2812
+
2813
+ /**
2814
+ * Close a memory bank
2815
+ */
2816
+ closeBank(bankId: string): Promise<void>;
2817
+
2818
+ /**
2819
+ * Store in global memory
2820
+ */
2821
+ store(entry: IMemoryEntryCreate): Promise<IMemoryEntry>;
2822
+
2823
+ /**
2824
+ * Retrieve from global memory
2825
+ */
2826
+ retrieve(key: string): Promise<IMemoryEntry | undefined>;
2827
+
2828
+ /**
2829
+ * Search vectors (if vector backend available)
2830
+ */
2831
+ searchVectors?(params: IVectorSearchParams): Promise<IVectorSearchResult[]>;
2832
+
2833
+ /**
2834
+
2835
+
2836
+ --- src/core/interfaces/task.interface.ts ---
2837
+ /**
2838
+ * V3 Task Interfaces
2839
+ * Domain-Driven Design - Task Bounded Context
2840
+ */
2841
+
2842
+ /**
2843
+ * Task priority levels
2844
+ */
2845
+ export type TaskPriority = 'critical' | 'high' | 'medium' | 'low';
2846
+
2847
+ /**
2848
+ * Task status throughout its lifecycle
2849
+ */
2850
+ export type TaskStatus =
2851
+ | 'pending'
2852
+ | 'queued'
2853
+ | 'assigned'
2854
+ | 'running'
2855
+ | 'completed'
2856
+ | 'failed'
2857
+ | 'cancelled'
2858
+ | 'timeout';
2859
+
2860
+ /**
2861
+ * Core task entity
2862
+ */
2863
+ export interface ITask {
2864
+ readonly id: string;
2865
+ readonly type: string;
2866
+ readonly description: string;
2867
+ readonly priority: number;
2868
+ readonly createdAt: Date;
2869
+
2870
+ status: TaskStatus;
2871
+ assignedAgent?: string;
2872
+ startedAt?: Date;
2873
+ completedAt?: Date;
2874
+ timeout?: number;
2875
+
2876
+ input?: Record<string, unknown>;
2877
+ output?: Record<string, unknown>;
2878
+ error?: Error;
2879
+
2880
+ metadata?: {
2881
+ requiredCapabilities?: string[];
2882
+ retryCount?: number;
2883
+ maxRetries?: number;
2884
+ critical?: boolean;
2885
+ parentTaskId?: string;
2886
+ childTaskIds?: string[];
2887
+ tags?: string[];
2888
+ [key: string]: unknown;
2889
+ };
2890
+ }
2891
+
2892
+ /**
2893
+ * Task creation parameters
2894
+ */
2895
+ export interface ITaskCreate {
2896
+ type: string;
2897
+ description: string;
2898
+ priority?: number;
2899
+ timeout?: number;
2900
+ assignedAgent?: string;
2901
+ input?: Record<string, unknown>;
2902
+ metadata?: ITask['metadata'];
2903
+ }
2904
+
2905
+ /**
2906
+ * Task result after completion
2907
+ */
2908
+ export interface ITaskResult {
2909
+ taskId: string;
2910
+ success: boolean;
2911
+ output?: Record<string, unknown>;
2912
+ error?: Error;
2913
+ duration: number;
2914
+ agentId?: string;
2915
+ metrics?: {
2916
+ tokensUsed?: number;
2917
+ memoryPeakMb?: number;
2918
+ retryCount?: number;
2919
+ };
2920
+ }
2921
+
2922
+ /**
2923
+ * Task queue interface for managing task ordering and processing
2924
+ */
2925
+ export interface ITaskQueue {
2926
+ /**
2927
+ * Add a task to the queue
2928
+ */
2929
+ enqueue(task: ITask): Promise<void>;
2930
+
2931
+ /**
2932
+ * Remove and return the highest priority task
2933
+ */
2934
+ dequeue(): Promise<ITask | undefined>;
2935
+
2936
+ /**
2937
+ * Peek at the next task without removing it
2938
+ */
2939
+ peek(): Promise<ITask | undefined>;
2940
+
2941
+ /**
2942
+ * Get the current queue size
2943
+ */
2944
+ size(): number;
2945
+
2946
+ /**
2947
+ * Check if the queue is empty
2948
+ */
2949
+ isEmpty(): boolean;
2950
+
2951
+ /**
2952
+ * Clear all tasks from the queue
2953
+ */
2954
+ clear(): Promise<void>;
2955
+
2956
+ /**
2957
+ * Get all queued tasks (for inspection)
2958
+ */
2959
+ getAll(): Promise<ITask[]>;
2960
+
2961
+ /**
2962
+ * Remove a specific task by ID
2963
+ */
2964
+ remove(taskId: string): Promise<boolean>;
2965
+
2966
+ /**
2967
+ * Update task priority
2968
+ */
2969
+ updatePriority(taskId: string, priority: number): Promise<boolean>;
2970
+ }
2971
+
2972
+ /**
2973
+ * Task manager interface for lifecycle management
2974
+ */
2975
+ export interface ITaskManager {
2976
+ /**
2977
+ * Create a new task
2978
+ */
2979
+ createTask(params: ITaskCreate): Promise<ITask>;
2980
+
2981
+ /**
2982
+ * Get a task by ID
2983
+ */
2984
+ getTask(taskId: string): ITask | undefined;
2985
+
2986
+ /**
2987
+ * Get all tasks matching optional filter
2988
+ */
2989
+ getTasks(filter?: Partial<Pick<ITask, 'status' | 'type' | 'assignedAgent'>>): ITask[];
2990
+
2991
+ /**
2992
+ * Assign a task to an agent
2993
+ */
2994
+ assignTask(taskId: string, agentId: string): Promise<void>;
2995
+
2996
+ /**
2997
+ * Start task execution
2998
+ */
2999
+ startTask(taskId: string): Promise<void>;
3000
+
3001
+ /**
3002
+ * Complete a task with result
3003
+ */
3004
+ completeTask(taskId: string, result: ITaskResult): Promise<void>;
3005
+
3006
+ /**
3007
+ * Fail a task with error
3008
+ */
3009
+ failTask(taskId: string, error: Error): Promise<void>;
3010
+
3011
+ /**
3012
+ * Cancel a task
3013
+ */
3014
+ cancelTask(taskId: string, reason?: string): Promise<void>;
3015
+
3016
+ /**
3017
+ * Retry a failed task
3018
+ */
3019
+ retryTask(taskId: string): Promise<void>;
3020
+
3021
+ /**
3022
+ * Get task metrics
3023
+ */
3024
+ getMetrics(): TaskManagerMetrics;
3025
+
3026
+ /**
3027
+ * Clean up old completed/failed tasks
3028
+ */
3029
+ cleanup(olderThan: Date): Promise<number>;
3030
+ }
3031
+
3032
+ /**
3033
+ * Task manager metrics
3034
+ */
3035
+ export interface TaskManagerMetrics {
3036
+ totalTasks: number;
3037
+ pendingTasks: number;
3038
+ runningTasks: number;
3039
+ completedTasks: number;
3040
+ failedTasks: number;
3041
+ cancelledTasks: number;
3042
+ avgDuration: number;
3043
+ avgWaitTime: number;
3044
+ }
3045
+
3046
+ /**
3047
+ * Task assignment strategy interface
3048
+ */
3049
+ export interface ITaskAssignmentStrategy {
3050
+ /**
3051
+ * Select the best agent for a task
3052
+ */
3053
+ selectAgent(task: ITask, availableAgents: string[]): Promise<string | undefined>;
3054
+
3055
+ /**
3056
+ * Score an agent for a task (higher is better)
3057
+ */
3058
+ scoreAgent(task: ITask, agentId: string): Promise<number>;
3059
+ }
3060
+
3061
+
3062
+ --- src/core/orchestrator/event-coordinator.ts ---
3063
+ /**
3064
+ * V3 Event Coordinator
3065
+ * Decomposed from orchestrator.ts - Event routing
3066
+ * ~100 lines (target achieved)
3067
+ */
3068
+
3069
+ import type {
3070
+ IEvent,
3071
+ IEventBus,
3072
+ IEventHandler,
3073
+ IEventCoordinator,
3074
+ } from '../interfaces/event.interface.js';
3075
+ import { SystemEventTypes } from '../interfaces/event.interface.js';
3076
+
3077
+ /**
3078
+ * Event coordinator implementation
3079
+ */
3080
+ export class EventCoordinator implements IEventCoordinator {
3081
+ private handlers = new Map<string, Set<IEventHandler>>();
3082
+ private initialized = false;
3083
+
3084
+ constructor(private eventBus: IEventBus) {}
3085
+
3086
+ async initialize(): Promise<void> {
3087
+ if (this.initialized) {
3088
+ return;
3089
+ }
3090
+
3091
+ // Register default system event handlers
3092
+ this.registerSystemHandlers();
3093
+
3094
+ this.initialized = true;
3095
+ }
3096
+
3097
+ async shutdown(): Promise<void> {
3098
+ // Clear all handlers
3099
+ this.handlers.clear();
3100
+ this.initialized = false;
3101
+ }
3102
+
3103
+ async route(event: IEvent): Promise<void> {
3104
+ const handlers = this.handlers.get(event.type);
3105
+ if (!handlers || handlers.size === 0) {
3106
+ return;
3107
+ }
3108
+
3109
+ const handlerPromises = Array.from(handlers).map(async handler => {
3110
+ try {
3111
+ await handler(event);
3112
+ } catch (error) {
3113
+ // Log error but don't throw
3114
+ console.error(`Error in event handler for ${event.type}:`, error);
3115
+ }
3116
+ });
3117
+
3118
+ await Promise.allSettled(handlerPromises);
3119
+ }
3120
+
3121
+ registerHandler(type: string, handler: IEventHandler): void {
3122
+ let handlers = this.handlers.get(type);
3123
+ if (!handlers) {
3124
+ handlers = new Set();
3125
+ this.handlers.set(type, handlers);
3126
+ }
3127
+ handlers.add(handler);
3128
+
3129
+ // Also register with event bus
3130
+ this.eventBus.on(type, handler);
3131
+ }
3132
+
3133
+ unregisterHandler(type: string, handler: IEventHandler): void {
3134
+ const handlers = this.handlers.get(type);
3135
+ if (handlers) {
3136
+ handlers.delete(handler);
3137
+ if (handlers.size === 0) {
3138
+ this.handlers.delete(type);
3139
+ }
3140
+ }
3141
+
3142
+ // Also unregister from event bus
3143
+ this.eventBus.off(type, handler);
3144
+ }
3145
+
3146
+ getEventBus(): IEventBus {
3147
+ return this.eventBus;
3148
+ }
3149
+
3150
+ private registerSystemHandlers(): void {
3151
+ // Error handling
3152
+ this.eventBus.on(SystemEventTypes.SYSTEM_ERROR, (event: IEvent) => {
3153
+ const { error, component } = event.payload as { error: Error; component: string };
3154
+ console.error(`System error in ${component}:`, error);
3155
+ });
3156
+
3157
+ // Deadlock detection
3158
+ this.eventBus.on(SystemEventTypes.DEADLOCK_DETECTED, (event: IEvent) => {
3159
+ const { agents, resources } = event.payload as { agents: string[]; resources: string[] };
3160
+ console.warn('Deadlock detected:', { agents, resources });
3161
+ });
3162
+ }
3163
+
3164
+ /**
3165
+ * Get registered handler count for a type
3166
+ */
3167
+ getHandlerCount(type: string): number {
3168
+ return this.handlers.get(type)?.size ?? 0;
3169
+ }
3170
+
3171
+ /**
3172
+ * Get all registered event types
3173
+ */
3174
+ getRegisteredTypes(): string[] {
3175
+ return Array.from(this.handlers.keys());
3176
+ }
3177
+
3178
+ /**
3179
+ * Check if coordinator is initialized
3180
+ */
3181
+ isInitialized(): boolean {
3182
+ return this.initialized;
3183
+ }
3184
+ }
3185
+
3186
+
3187
+ ## Instructions
3188
+
3189
+ Analyze the above codebase context and provide your response following the format specified in the task.