swarm-engine 1.1.1 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/CLAUDE.md +1 -1
  2. package/README.md +145 -30
  3. package/commands/diff-review.md +27 -15
  4. package/commands/discover.md +102 -0
  5. package/commands/dynamic.md +136 -0
  6. package/commands/fix-pr.md +30 -24
  7. package/commands/postmortem.md +106 -0
  8. package/commands/red-team.md +41 -26
  9. package/commands/research.md +22 -1
  10. package/commands/review-cycle.md +38 -20
  11. package/commands/spike.md +108 -0
  12. package/commands/swarm.md +68 -60
  13. package/commands/tdd.md +44 -24
  14. package/dist/cli/commands/acp.d.ts.map +1 -1
  15. package/dist/cli/commands/acp.js +12 -2
  16. package/dist/cli/commands/acp.js.map +1 -1
  17. package/dist/cli/commands/agents.d.ts.map +1 -1
  18. package/dist/cli/commands/agents.js +16 -13
  19. package/dist/cli/commands/agents.js.map +1 -1
  20. package/dist/cli/commands/completions.d.ts.map +1 -1
  21. package/dist/cli/commands/completions.js +21 -9
  22. package/dist/cli/commands/completions.js.map +1 -1
  23. package/dist/cli/commands/compound.d.ts.map +1 -1
  24. package/dist/cli/commands/compound.js +1 -2
  25. package/dist/cli/commands/compound.js.map +1 -1
  26. package/dist/cli/commands/configure.d.ts.map +1 -1
  27. package/dist/cli/commands/configure.js +24 -8
  28. package/dist/cli/commands/configure.js.map +1 -1
  29. package/dist/cli/commands/convert.d.ts +1 -1
  30. package/dist/cli/commands/convert.d.ts.map +1 -1
  31. package/dist/cli/commands/convert.js +22 -48
  32. package/dist/cli/commands/convert.js.map +1 -1
  33. package/dist/cli/commands/doctor.d.ts.map +1 -1
  34. package/dist/cli/commands/doctor.js +1 -3
  35. package/dist/cli/commands/doctor.js.map +1 -1
  36. package/dist/cli/commands/init.d.ts.map +1 -1
  37. package/dist/cli/commands/init.js +17 -7
  38. package/dist/cli/commands/init.js.map +1 -1
  39. package/dist/cli/commands/install.d.ts.map +1 -1
  40. package/dist/cli/commands/install.js +1 -1
  41. package/dist/cli/commands/install.js.map +1 -1
  42. package/dist/cli/commands/learn.js +6 -6
  43. package/dist/cli/commands/learn.js.map +1 -1
  44. package/dist/cli/commands/mcp.d.ts.map +1 -1
  45. package/dist/cli/commands/mcp.js +1 -2
  46. package/dist/cli/commands/mcp.js.map +1 -1
  47. package/dist/cli/commands/memory.d.ts.map +1 -1
  48. package/dist/cli/commands/memory.js +118 -2
  49. package/dist/cli/commands/memory.js.map +1 -1
  50. package/dist/cli/commands/orchestrate.d.ts.map +1 -1
  51. package/dist/cli/commands/orchestrate.js +20 -7
  52. package/dist/cli/commands/orchestrate.js.map +1 -1
  53. package/dist/cli/commands/plan.d.ts.map +1 -1
  54. package/dist/cli/commands/plan.js.map +1 -1
  55. package/dist/cli/commands/plugin.d.ts.map +1 -1
  56. package/dist/cli/commands/plugin.js +8 -5
  57. package/dist/cli/commands/plugin.js.map +1 -1
  58. package/dist/cli/commands/resume.js +1 -1
  59. package/dist/cli/commands/resume.js.map +1 -1
  60. package/dist/cli/commands/run.d.ts.map +1 -1
  61. package/dist/cli/commands/run.js +20 -6
  62. package/dist/cli/commands/run.js.map +1 -1
  63. package/dist/cli/commands/share.d.ts.map +1 -1
  64. package/dist/cli/commands/share.js +6 -1
  65. package/dist/cli/commands/share.js.map +1 -1
  66. package/dist/cli/commands/status.d.ts.map +1 -1
  67. package/dist/cli/commands/status.js +15 -7
  68. package/dist/cli/commands/status.js.map +1 -1
  69. package/dist/cli/commands/template.d.ts.map +1 -1
  70. package/dist/cli/commands/template.js +14 -6
  71. package/dist/cli/commands/template.js.map +1 -1
  72. package/dist/cli/commands/vault.d.ts.map +1 -1
  73. package/dist/cli/commands/vault.js +14 -9
  74. package/dist/cli/commands/vault.js.map +1 -1
  75. package/dist/cli/commands/verify.d.ts.map +1 -1
  76. package/dist/cli/commands/verify.js +2 -2
  77. package/dist/cli/commands/verify.js.map +1 -1
  78. package/dist/cli/commands/watch.js +1 -1
  79. package/dist/cli/commands/watch.js.map +1 -1
  80. package/dist/cli/index.js +14 -4
  81. package/dist/cli/index.js.map +1 -1
  82. package/dist/core/checkpoint.js +1 -1
  83. package/dist/core/checkpoint.js.map +1 -1
  84. package/dist/core/event-bus.d.ts.map +1 -1
  85. package/dist/core/event-bus.js +9 -3
  86. package/dist/core/event-bus.js.map +1 -1
  87. package/dist/core/lifecycle.js.map +1 -1
  88. package/dist/core/patterns.d.ts.map +1 -1
  89. package/dist/core/patterns.js +31 -8
  90. package/dist/core/patterns.js.map +1 -1
  91. package/dist/core/permissions.d.ts.map +1 -1
  92. package/dist/core/permissions.js +21 -10
  93. package/dist/core/permissions.js.map +1 -1
  94. package/dist/core/registry.d.ts.map +1 -1
  95. package/dist/core/registry.js +10 -6
  96. package/dist/core/registry.js.map +1 -1
  97. package/dist/core/snapshots.d.ts.map +1 -1
  98. package/dist/core/snapshots.js +17 -5
  99. package/dist/core/snapshots.js.map +1 -1
  100. package/dist/core/types.d.ts +33 -0
  101. package/dist/core/types.d.ts.map +1 -1
  102. package/dist/core/types.js.map +1 -1
  103. package/dist/hooks/index.js.map +1 -1
  104. package/dist/index.d.ts +114 -6
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +92 -4
  107. package/dist/index.js.map +1 -1
  108. package/dist/memory/index.d.ts +38 -0
  109. package/dist/memory/index.d.ts.map +1 -1
  110. package/dist/memory/index.js +136 -24
  111. package/dist/memory/index.js.map +1 -1
  112. package/dist/memory/schema.d.ts +1 -0
  113. package/dist/memory/schema.d.ts.map +1 -1
  114. package/dist/memory/schema.js +20 -19
  115. package/dist/memory/schema.js.map +1 -1
  116. package/dist/plugin/index.d.ts.map +1 -1
  117. package/dist/plugin/index.js.map +1 -1
  118. package/dist/runtime/acp.d.ts.map +1 -1
  119. package/dist/runtime/acp.js +71 -41
  120. package/dist/runtime/acp.js.map +1 -1
  121. package/dist/runtime/adaptive.d.ts.map +1 -1
  122. package/dist/runtime/adaptive.js +30 -31
  123. package/dist/runtime/adaptive.js.map +1 -1
  124. package/dist/runtime/agent-runner.d.ts +62 -0
  125. package/dist/runtime/agent-runner.d.ts.map +1 -0
  126. package/dist/runtime/agent-runner.js +224 -0
  127. package/dist/runtime/agent-runner.js.map +1 -0
  128. package/dist/runtime/autonomy.d.ts +1 -0
  129. package/dist/runtime/autonomy.d.ts.map +1 -1
  130. package/dist/runtime/autonomy.js +37 -19
  131. package/dist/runtime/autonomy.js.map +1 -1
  132. package/dist/runtime/backends/claude.d.ts.map +1 -1
  133. package/dist/runtime/backends/claude.js +2 -2
  134. package/dist/runtime/backends/claude.js.map +1 -1
  135. package/dist/runtime/backends/codex.d.ts.map +1 -1
  136. package/dist/runtime/backends/codex.js +8 -11
  137. package/dist/runtime/backends/codex.js.map +1 -1
  138. package/dist/runtime/backends/gemini.d.ts.map +1 -1
  139. package/dist/runtime/backends/gemini.js +11 -7
  140. package/dist/runtime/backends/gemini.js.map +1 -1
  141. package/dist/runtime/backends/index.js +1 -1
  142. package/dist/runtime/backends/index.js.map +1 -1
  143. package/dist/runtime/backends/mock.d.ts.map +1 -1
  144. package/dist/runtime/backends/mock.js +1 -1
  145. package/dist/runtime/backends/mock.js.map +1 -1
  146. package/dist/runtime/backends/vercel-ai.d.ts.map +1 -1
  147. package/dist/runtime/backends/vercel-ai.js +41 -9
  148. package/dist/runtime/backends/vercel-ai.js.map +1 -1
  149. package/dist/runtime/cache-optimizer.d.ts.map +1 -1
  150. package/dist/runtime/cache-optimizer.js +3 -9
  151. package/dist/runtime/cache-optimizer.js.map +1 -1
  152. package/dist/runtime/cascade.d.ts.map +1 -1
  153. package/dist/runtime/cascade.js +34 -7
  154. package/dist/runtime/cascade.js.map +1 -1
  155. package/dist/runtime/chunker.d.ts.map +1 -1
  156. package/dist/runtime/chunker.js +12 -6
  157. package/dist/runtime/chunker.js.map +1 -1
  158. package/dist/runtime/compounder.d.ts +1 -1
  159. package/dist/runtime/compounder.d.ts.map +1 -1
  160. package/dist/runtime/compounder.js +30 -11
  161. package/dist/runtime/compounder.js.map +1 -1
  162. package/dist/runtime/cost-model.d.ts.map +1 -1
  163. package/dist/runtime/cost-model.js +1 -1
  164. package/dist/runtime/cost-model.js.map +1 -1
  165. package/dist/runtime/database.d.ts +16 -0
  166. package/dist/runtime/database.d.ts.map +1 -0
  167. package/dist/runtime/database.js +39 -0
  168. package/dist/runtime/database.js.map +1 -0
  169. package/dist/runtime/distiller.d.ts.map +1 -1
  170. package/dist/runtime/distiller.js +6 -3
  171. package/dist/runtime/distiller.js.map +1 -1
  172. package/dist/runtime/engine.d.ts +25 -9
  173. package/dist/runtime/engine.d.ts.map +1 -1
  174. package/dist/runtime/engine.js +417 -378
  175. package/dist/runtime/engine.js.map +1 -1
  176. package/dist/runtime/execution-graph.d.ts +86 -0
  177. package/dist/runtime/execution-graph.d.ts.map +1 -0
  178. package/dist/runtime/execution-graph.js +441 -0
  179. package/dist/runtime/execution-graph.js.map +1 -0
  180. package/dist/runtime/executor.d.ts +1 -2
  181. package/dist/runtime/executor.d.ts.map +1 -1
  182. package/dist/runtime/executor.js +45 -14
  183. package/dist/runtime/executor.js.map +1 -1
  184. package/dist/runtime/graph-adversarial.d.ts +88 -0
  185. package/dist/runtime/graph-adversarial.d.ts.map +1 -0
  186. package/dist/runtime/graph-adversarial.js +378 -0
  187. package/dist/runtime/graph-adversarial.js.map +1 -0
  188. package/dist/runtime/graph-analyzer.d.ts +106 -0
  189. package/dist/runtime/graph-analyzer.d.ts.map +1 -0
  190. package/dist/runtime/graph-analyzer.js +321 -0
  191. package/dist/runtime/graph-analyzer.js.map +1 -0
  192. package/dist/runtime/graph-causal.d.ts +91 -0
  193. package/dist/runtime/graph-causal.d.ts.map +1 -0
  194. package/dist/runtime/graph-causal.js +292 -0
  195. package/dist/runtime/graph-causal.js.map +1 -0
  196. package/dist/runtime/graph-context-router.d.ts +73 -0
  197. package/dist/runtime/graph-context-router.d.ts.map +1 -0
  198. package/dist/runtime/graph-context-router.js +162 -0
  199. package/dist/runtime/graph-context-router.js.map +1 -0
  200. package/dist/runtime/graph-discovery.d.ts +71 -0
  201. package/dist/runtime/graph-discovery.d.ts.map +1 -0
  202. package/dist/runtime/graph-discovery.js +367 -0
  203. package/dist/runtime/graph-discovery.js.map +1 -0
  204. package/dist/runtime/graph-dropout.d.ts +59 -0
  205. package/dist/runtime/graph-dropout.d.ts.map +1 -0
  206. package/dist/runtime/graph-dropout.js +196 -0
  207. package/dist/runtime/graph-dropout.js.map +1 -0
  208. package/dist/runtime/graph-embeddings.d.ts +58 -0
  209. package/dist/runtime/graph-embeddings.d.ts.map +1 -0
  210. package/dist/runtime/graph-embeddings.js +301 -0
  211. package/dist/runtime/graph-embeddings.js.map +1 -0
  212. package/dist/runtime/graph-feedback.d.ts +30 -0
  213. package/dist/runtime/graph-feedback.d.ts.map +1 -0
  214. package/dist/runtime/graph-feedback.js +82 -0
  215. package/dist/runtime/graph-feedback.js.map +1 -0
  216. package/dist/runtime/graph-gnn.d.ts +120 -0
  217. package/dist/runtime/graph-gnn.d.ts.map +1 -0
  218. package/dist/runtime/graph-gnn.js +524 -0
  219. package/dist/runtime/graph-gnn.js.map +1 -0
  220. package/dist/runtime/graph-learner.d.ts +70 -0
  221. package/dist/runtime/graph-learner.d.ts.map +1 -0
  222. package/dist/runtime/graph-learner.js +265 -0
  223. package/dist/runtime/graph-learner.js.map +1 -0
  224. package/dist/runtime/graph-meta-adversarial.d.ts +113 -0
  225. package/dist/runtime/graph-meta-adversarial.d.ts.map +1 -0
  226. package/dist/runtime/graph-meta-adversarial.js +366 -0
  227. package/dist/runtime/graph-meta-adversarial.js.map +1 -0
  228. package/dist/runtime/graph-meta.d.ts +115 -0
  229. package/dist/runtime/graph-meta.d.ts.map +1 -0
  230. package/dist/runtime/graph-meta.js +437 -0
  231. package/dist/runtime/graph-meta.js.map +1 -0
  232. package/dist/runtime/graph-self-evolve.d.ts +92 -0
  233. package/dist/runtime/graph-self-evolve.d.ts.map +1 -0
  234. package/dist/runtime/graph-self-evolve.js +422 -0
  235. package/dist/runtime/graph-self-evolve.js.map +1 -0
  236. package/dist/runtime/graph-synthesis.d.ts +47 -0
  237. package/dist/runtime/graph-synthesis.d.ts.map +1 -0
  238. package/dist/runtime/graph-synthesis.js +232 -0
  239. package/dist/runtime/graph-synthesis.js.map +1 -0
  240. package/dist/runtime/graph-trajectory.d.ts +88 -0
  241. package/dist/runtime/graph-trajectory.d.ts.map +1 -0
  242. package/dist/runtime/graph-trajectory.js +339 -0
  243. package/dist/runtime/graph-trajectory.js.map +1 -0
  244. package/dist/runtime/heuristics.d.ts +1 -0
  245. package/dist/runtime/heuristics.d.ts.map +1 -1
  246. package/dist/runtime/heuristics.js +44 -22
  247. package/dist/runtime/heuristics.js.map +1 -1
  248. package/dist/runtime/learning-engine.d.ts +63 -0
  249. package/dist/runtime/learning-engine.d.ts.map +1 -0
  250. package/dist/runtime/learning-engine.js +273 -0
  251. package/dist/runtime/learning-engine.js.map +1 -0
  252. package/dist/runtime/living-spec.js +3 -3
  253. package/dist/runtime/living-spec.js.map +1 -1
  254. package/dist/runtime/lsp.d.ts.map +1 -1
  255. package/dist/runtime/lsp.js +41 -14
  256. package/dist/runtime/lsp.js.map +1 -1
  257. package/dist/runtime/mcp.d.ts.map +1 -1
  258. package/dist/runtime/mcp.js +56 -19
  259. package/dist/runtime/mcp.js.map +1 -1
  260. package/dist/runtime/model-router.d.ts +1 -0
  261. package/dist/runtime/model-router.d.ts.map +1 -1
  262. package/dist/runtime/model-router.js +37 -21
  263. package/dist/runtime/model-router.js.map +1 -1
  264. package/dist/runtime/panes.d.ts.map +1 -1
  265. package/dist/runtime/panes.js +50 -49
  266. package/dist/runtime/panes.js.map +1 -1
  267. package/dist/runtime/plan-search.js +2 -2
  268. package/dist/runtime/plan-search.js.map +1 -1
  269. package/dist/runtime/plugins.d.ts +1 -1
  270. package/dist/runtime/plugins.d.ts.map +1 -1
  271. package/dist/runtime/plugins.js +63 -47
  272. package/dist/runtime/plugins.js.map +1 -1
  273. package/dist/runtime/reflexion.d.ts.map +1 -1
  274. package/dist/runtime/reflexion.js +4 -8
  275. package/dist/runtime/reflexion.js.map +1 -1
  276. package/dist/runtime/review-schema.d.ts.map +1 -1
  277. package/dist/runtime/review-schema.js +12 -12
  278. package/dist/runtime/review-schema.js.map +1 -1
  279. package/dist/runtime/rewriter.d.ts.map +1 -1
  280. package/dist/runtime/rewriter.js +29 -9
  281. package/dist/runtime/rewriter.js.map +1 -1
  282. package/dist/runtime/sharing.d.ts +1 -1
  283. package/dist/runtime/sharing.d.ts.map +1 -1
  284. package/dist/runtime/sharing.js +55 -27
  285. package/dist/runtime/sharing.js.map +1 -1
  286. package/dist/runtime/stats.d.ts +1 -0
  287. package/dist/runtime/stats.d.ts.map +1 -1
  288. package/dist/runtime/stats.js +40 -24
  289. package/dist/runtime/stats.js.map +1 -1
  290. package/dist/runtime/templates.d.ts.map +1 -1
  291. package/dist/runtime/templates.js +2 -2
  292. package/dist/runtime/templates.js.map +1 -1
  293. package/dist/runtime/traces.d.ts +1 -0
  294. package/dist/runtime/traces.d.ts.map +1 -1
  295. package/dist/runtime/traces.js +50 -28
  296. package/dist/runtime/traces.js.map +1 -1
  297. package/dist/runtime/verifier.d.ts.map +1 -1
  298. package/dist/runtime/verifier.js +12 -6
  299. package/dist/runtime/verifier.js.map +1 -1
  300. package/dist/runtime/worktree.d.ts.map +1 -1
  301. package/dist/runtime/worktree.js +35 -18
  302. package/dist/runtime/worktree.js.map +1 -1
  303. package/dist/tui/dashboard.d.ts.map +1 -1
  304. package/dist/tui/dashboard.js +20 -16
  305. package/dist/tui/dashboard.js.map +1 -1
  306. package/dist/tui/progress.d.ts +2 -0
  307. package/dist/tui/progress.d.ts.map +1 -1
  308. package/dist/tui/progress.js +105 -33
  309. package/dist/tui/progress.js.map +1 -1
  310. package/dist/tui/renderer.d.ts.map +1 -1
  311. package/dist/tui/renderer.js.map +1 -1
  312. package/dist/utils/compact-format.js +1 -1
  313. package/dist/utils/compact-format.js.map +1 -1
  314. package/dist/utils/config.d.ts.map +1 -1
  315. package/dist/utils/config.js.map +1 -1
  316. package/dist/utils/env.d.ts.map +1 -1
  317. package/dist/utils/env.js +19 -5
  318. package/dist/utils/env.js.map +1 -1
  319. package/dist/utils/errors.d.ts.map +1 -1
  320. package/dist/utils/errors.js +3 -7
  321. package/dist/utils/errors.js.map +1 -1
  322. package/dist/utils/output.d.ts.map +1 -1
  323. package/dist/utils/output.js +6 -2
  324. package/dist/utils/output.js.map +1 -1
  325. package/dist/utils/project-config.d.ts +18 -0
  326. package/dist/utils/project-config.d.ts.map +1 -1
  327. package/dist/utils/project-config.js +14 -6
  328. package/dist/utils/project-config.js.map +1 -1
  329. package/dist/utils/schemas.d.ts.map +1 -1
  330. package/dist/utils/schemas.js +12 -12
  331. package/dist/utils/schemas.js.map +1 -1
  332. package/dist/utils/terminal.d.ts.map +1 -1
  333. package/dist/utils/terminal.js +18 -7
  334. package/dist/utils/terminal.js.map +1 -1
  335. package/dist/utils/tiers.d.ts.map +1 -1
  336. package/dist/utils/tiers.js +14 -6
  337. package/dist/utils/tiers.js.map +1 -1
  338. package/package.json +15 -4
  339. package/skills/swarm-output-style/SKILL.md +154 -48
@@ -19,14 +19,30 @@ import { KnowledgeCompounder } from './compounder.js';
19
19
  import { ModelRouter } from './model-router.js';
20
20
  import { AutonomyTracker } from './autonomy.js';
21
21
  import { ContinuousVerifier } from './verifier.js';
22
- import { optimizeForCache, estimateCacheSavings } from './cache-optimizer.js';
23
- import { classifyTaskComplexity, selectStartingTier } from './cascade.js';
24
- import { createLivingSpec, updateSpecFromPhase, formatLivingSpec } from './living-spec.js';
22
+ import { estimateCacheSavings } from './cache-optimizer.js';
23
+ import { createLivingSpec, updateSpecFromPhase } from './living-spec.js';
25
24
  import { estimateTokens } from '../utils/tokens.js';
26
- import { redactSecrets } from '../utils/redact.js';
27
- import { join } from 'path';
28
- import { existsSync, mkdirSync, writeFileSync, unlinkSync } from 'fs';
29
- import { randomUUID } from 'crypto';
25
+ import { unlinkSync } from 'fs';
26
+ import { AgentRunner } from './agent-runner.js';
27
+ import { LearningEngine } from './learning-engine.js';
28
+ import { ExecutionGraph } from './execution-graph.js';
29
+ import { GraphLearner } from './graph-learner.js';
30
+ import { GraphAnalyzer } from './graph-analyzer.js';
31
+ import { GraphContextRouter } from './graph-context-router.js';
32
+ import { ReviewFeedbackRecorder } from './graph-feedback.js';
33
+ import { parseReviewOutput } from './review-schema.js';
34
+ import { closeDatabase } from './database.js';
35
+ import { CausalGraphEngine } from './graph-causal.js';
36
+ import { FailurePropagationPredictor } from './graph-gnn.js';
37
+ import { AdversarialEvolver } from './graph-adversarial.js';
38
+ import { MetaPatternSelector } from './graph-meta.js';
39
+ import { PredictiveDropout } from './graph-dropout.js';
40
+ import { PatternSynthesizer } from './graph-synthesis.js';
41
+ import { TrajectoryPredictor } from './graph-trajectory.js';
42
+ import { MetaAdversarialTester } from './graph-meta-adversarial.js';
43
+ import { RuleEvolver } from './graph-self-evolve.js';
44
+ import { TaskDiscovery } from './graph-discovery.js';
45
+ import { OrchestrationEmbedder } from './graph-embeddings.js';
30
46
  /**
31
47
  * The Swarm Orchestration Engine.
32
48
  *
@@ -60,6 +76,24 @@ export class SwarmEngine {
60
76
  signalHandlers = [];
61
77
  sharedContextFiles = [];
62
78
  livingSpec = null;
79
+ agentRunner;
80
+ learningEngine;
81
+ executionGraph = null;
82
+ graphAnalyzer = null;
83
+ graphLearner = null;
84
+ reviewFeedback = null;
85
+ causalEngine = null;
86
+ gnnPredictor = null;
87
+ adversarialEvolver = null;
88
+ metaSelector = null;
89
+ predictiveDropout = null;
90
+ gnnWeights = null;
91
+ patternSynthesizer = null;
92
+ trajectoryPredictor = null;
93
+ metaAdversarial = null;
94
+ ruleEvolver = null;
95
+ taskDiscovery = null;
96
+ orchestrationEmbedder = null;
63
97
  constructor(options) {
64
98
  this.options = options;
65
99
  this.registry = options.registry;
@@ -85,43 +119,98 @@ export class SwarmEngine {
85
119
  this.stats.attachToEventBus(this.bus, undefined);
86
120
  this.costModel = new CostModel(this.stats);
87
121
  this.reflectionEngine = new ReflectionEngine();
88
- try {
89
- this.traceStore = new TraceStore();
90
- }
91
- catch (e) {
92
- this.log.warn('TraceStore init failed', { error: e instanceof Error ? e.message : e });
93
- }
122
+ this.traceStore = this.tryInit(() => new TraceStore(), 'TraceStore');
94
123
  this.replanner = new AdaptiveReplanner(options.logger, this.traceStore ?? undefined);
95
- try {
96
- this.heuristicStore = new HeuristicStore();
97
- }
98
- catch (e) {
99
- this.log.warn('HeuristicStore init failed', { error: e instanceof Error ? e.message : e });
100
- }
101
- try {
102
- this.modelRouter = new ModelRouter();
103
- }
104
- catch (e) {
105
- this.log.warn('ModelRouter init failed', { error: e instanceof Error ? e.message : e });
106
- }
107
- try {
108
- this.autonomyTracker = new AutonomyTracker();
109
- }
110
- catch (e) {
111
- this.log.warn('AutonomyTracker init failed', { error: e instanceof Error ? e.message : e });
112
- }
113
- try {
114
- this.compounder = new KnowledgeCompounder();
124
+ this.heuristicStore = this.tryInit(() => new HeuristicStore(), 'HeuristicStore');
125
+ this.modelRouter = this.tryInit(() => new ModelRouter(), 'ModelRouter');
126
+ this.autonomyTracker = this.tryInit(() => new AutonomyTracker(), 'AutonomyTracker');
127
+ this.compounder = this.tryInit(() => new KnowledgeCompounder(), 'KnowledgeCompounder');
128
+ this.executionGraph = this.tryInit(() => new ExecutionGraph(), 'ExecutionGraph');
129
+ this.executionGraph?.attachToEventBus(this.bus);
130
+ // Create graph analysis deps (reused by AgentRunner + LearningEngine)
131
+ this.graphLearner = this.executionGraph ? this.tryInit(() => new GraphLearner(this.executionGraph), 'GraphLearner') : null;
132
+ this.graphAnalyzer = this.executionGraph ? this.tryInit(() => new GraphAnalyzer(this.executionGraph), 'GraphAnalyzer') : null;
133
+ this.reviewFeedback = this.executionGraph ? this.tryInit(() => new ReviewFeedbackRecorder(this.executionGraph), 'ReviewFeedbackRecorder') : null;
134
+ // Cutting-edge ML features
135
+ this.causalEngine = this.executionGraph
136
+ ? this.tryInit(() => new CausalGraphEngine(this.executionGraph), 'CausalGraphEngine')
137
+ : null;
138
+ this.gnnPredictor = this.executionGraph
139
+ ? this.tryInit(() => new FailurePropagationPredictor(this.executionGraph), 'FailurePropagationPredictor')
140
+ : null;
141
+ this.adversarialEvolver = this.executionGraph
142
+ ? this.tryInit(() => new AdversarialEvolver(this.executionGraph), 'AdversarialEvolver')
143
+ : null;
144
+ this.metaSelector = this.executionGraph
145
+ ? this.tryInit(() => new MetaPatternSelector(this.executionGraph), 'MetaPatternSelector')
146
+ : null;
147
+ this.predictiveDropout = this.executionGraph
148
+ ? this.tryInit(() => new PredictiveDropout(this.executionGraph), 'PredictiveDropout')
149
+ : null;
150
+ // Initialize GNN weights (training happens lazily via background scheduling)
151
+ if (this.gnnPredictor) {
152
+ try {
153
+ this.gnnWeights = this.gnnPredictor.initWeights();
154
+ }
155
+ catch { /* silent */ }
156
+ }
157
+ // Self-aware engine features
158
+ this.patternSynthesizer = this.executionGraph ? this.tryInit(() => new PatternSynthesizer(this.executionGraph), 'PatternSynthesizer') : null;
159
+ this.trajectoryPredictor = this.executionGraph ? this.tryInit(() => new TrajectoryPredictor(this.executionGraph), 'TrajectoryPredictor') : null;
160
+ this.metaAdversarial = this.executionGraph ? this.tryInit(() => new MetaAdversarialTester(this.executionGraph), 'MetaAdversarialTester') : null;
161
+ this.ruleEvolver = this.executionGraph ? this.tryInit(() => new RuleEvolver(this.executionGraph), 'RuleEvolver') : null;
162
+ this.taskDiscovery = this.executionGraph ? this.tryInit(() => new TaskDiscovery(this.executionGraph), 'TaskDiscovery') : null;
163
+ this.orchestrationEmbedder = this.executionGraph ? this.tryInit(() => new OrchestrationEmbedder(this.executionGraph), 'OrchestrationEmbedder') : null;
164
+ // Prune stale graph data on init (Feature 6: graph decay)
165
+ if (this.executionGraph) {
166
+ try {
167
+ this.executionGraph.pruneOlderThan(90);
168
+ }
169
+ catch { /* silent */ }
115
170
  }
116
- catch (e) {
117
- this.log.warn('KnowledgeCompounder init failed', { error: e instanceof Error ? e.message : e });
171
+ // Rule evolution proposal on startup (skip in mock mode and when no historical data)
172
+ if (this.ruleEvolver && !this.options.mock) {
173
+ try {
174
+ const proposals = this.ruleEvolver.evolveRules(50);
175
+ if (proposals.length > 0) {
176
+ this.log.info(`Rule evolver proposes ${proposals.length} rule updates (top: ${proposals[0].rule.name}, +${Math.round(proposals[0].backtestedImprovement * 100)}%)`);
177
+ }
178
+ }
179
+ catch (e) {
180
+ this.log.debug(`Rule evolution failed: ${e}`);
181
+ }
118
182
  }
119
183
  if (options.worktreeEnabled) {
120
184
  try {
121
185
  this.worktreeManager = new WorktreeManager(options.cwd);
122
186
  }
123
- catch { /* not a git repo */ }
187
+ catch {
188
+ /* not a git repo */
189
+ }
124
190
  }
191
+ this.agentRunner = new AgentRunner({
192
+ registry: this.registry,
193
+ executor: this.executor,
194
+ bus: this.bus,
195
+ logger: options.logger,
196
+ compaction: this.compaction,
197
+ worktreeManager: this.worktreeManager,
198
+ contextRouter: this.executionGraph ? new GraphContextRouter(this.executionGraph) : undefined,
199
+ graphLearner: this.graphLearner,
200
+ graphAnalyzer: this.graphAnalyzer,
201
+ });
202
+ this.learningEngine = new LearningEngine({
203
+ traceStore: this.traceStore,
204
+ heuristicStore: this.heuristicStore,
205
+ modelRouter: this.modelRouter,
206
+ autonomyTracker: this.autonomyTracker,
207
+ compounder: this.compounder,
208
+ graphLearner: this.graphLearner,
209
+ metaSelector: this.metaSelector,
210
+ predictiveDropout: this.predictiveDropout,
211
+ orchestrationEmbedder: this.orchestrationEmbedder,
212
+ log: options.logger,
213
+ });
125
214
  if (options.pluginLoader) {
126
215
  options.pluginLoader.wireHooks(this.bus);
127
216
  }
@@ -147,16 +236,14 @@ export class SwarmEngine {
147
236
  orchestration.status = 'running';
148
237
  orchestration.startedAt = new Date();
149
238
  this.phaseOutputs = new Map();
239
+ // TODO: Checkpoint doesn't store phase outputs — resumed phases lose inter-phase context
150
240
  this.reflections = [];
151
241
  this.sharedContextFiles = [];
152
242
  this.abortController = new AbortController();
153
243
  this.livingSpec = createLivingSpec(config.description);
154
244
  // Start continuous verification
155
- let continuousVerifier = null;
156
- if (this.verifier) {
157
- continuousVerifier = new ContinuousVerifier(this.verifier, this.bus);
158
- continuousVerifier.start();
159
- }
245
+ const continuousVerifier = new ContinuousVerifier(this.verifier, this.bus);
246
+ continuousVerifier.start();
160
247
  try {
161
248
  // Execute phases using work-queue approach (handles DAGs correctly)
162
249
  // If resuming, seed completed phases so the DAG executor skips them
@@ -166,6 +253,20 @@ export class SwarmEngine {
166
253
  completed.add(phase.config.name);
167
254
  }
168
255
  }
256
+ // GNN pre-execution risk prediction (Feature 2: GNN Failure Propagation)
257
+ if (this.gnnPredictor && this.gnnWeights) {
258
+ try {
259
+ const risks = this.gnnPredictor.predict(orchestration.config.id, this.gnnWeights);
260
+ const highRisk = risks.filter(r => r.riskScore > 0.7);
261
+ if (highRisk.length > 0) {
262
+ this.log.warn(`GNN predicts high failure risk for ${highRisk.length} nodes`);
263
+ this.bus.emit('system:warning', { type: 'gnn-risk', risks: highRisk }, 'engine');
264
+ }
265
+ }
266
+ catch (e) {
267
+ this.log.debug(`GNN prediction failed: ${e}`);
268
+ }
269
+ }
169
270
  while (completed.size < orchestration.phases.length) {
170
271
  // Check if abort was requested
171
272
  if (this.abortController.signal.aborted) {
@@ -173,17 +274,19 @@ export class SwarmEngine {
173
274
  break;
174
275
  }
175
276
  // Find all runnable phases (dependencies met, not yet completed)
176
- const runnable = orchestration.phases.filter(p => {
277
+ const runnable = orchestration.phases.filter((p) => {
177
278
  if (completed.has(p.config.name))
178
279
  return false;
179
280
  if (p.status === 'failed')
180
281
  return false;
282
+ if (p.status === 'skipped')
283
+ return false;
181
284
  const deps = p.config.dependsOn ?? [];
182
- return deps.every(d => completed.has(d));
285
+ return deps.every((d) => completed.has(d));
183
286
  });
184
287
  if (runnable.length === 0) {
185
288
  // No runnable phases — either all done or deadlocked
186
- const incomplete = orchestration.phases.filter(p => !completed.has(p.config.name) && p.status !== 'failed');
289
+ const incomplete = orchestration.phases.filter((p) => !completed.has(p.config.name) && p.status !== 'failed');
187
290
  if (incomplete.length > 0) {
188
291
  // Deadlock — blocked phases with unmet dependencies
189
292
  for (const p of incomplete) {
@@ -191,15 +294,14 @@ export class SwarmEngine {
191
294
  }
192
295
  orchestration.status = 'failed';
193
296
  this.log.error('Orchestration deadlocked: blocked phases with unmet dependencies', {
194
- blocked: incomplete.map(p => p.config.name),
297
+ blocked: incomplete.map((p) => p.config.name),
195
298
  });
196
299
  }
197
300
  break;
198
301
  }
199
- // Execute runnable phases (could be parallel if multiple are ready)
302
+ // Handle approval gates sequentially (can't prompt in parallel)
303
+ const approved = [];
200
304
  for (const phase of runnable) {
201
- orchestration.currentPhase = orchestration.phases.indexOf(phase);
202
- // Check for approval gate
203
305
  if (phase.config.requiresApproval) {
204
306
  this.log.info(`Phase requires approval: ${phase.config.name}`);
205
307
  this.bus.emit('orchestration:paused', {
@@ -207,10 +309,9 @@ export class SwarmEngine {
207
309
  phase: phase.config.name,
208
310
  agentCount: phase.config.agents.length,
209
311
  }, 'engine');
210
- // In interactive mode, wait for approval
211
312
  if (!this.options.nonInteractive) {
212
- const approved = await this.requestApproval(phase.config.name, phase.config.agents);
213
- if (!approved) {
313
+ const ok = await this.requestApproval(phase.config.name, phase.config.agents);
314
+ if (!ok) {
214
315
  phase.status = 'skipped';
215
316
  this.log.info(`Phase skipped (not approved): ${phase.config.name}`);
216
317
  completed.add(phase.config.name);
@@ -218,14 +319,76 @@ export class SwarmEngine {
218
319
  }
219
320
  }
220
321
  }
322
+ approved.push(phase);
323
+ }
324
+ // Execute approved phases in parallel
325
+ orchestration.currentPhase = orchestration.phases.indexOf(approved[approved.length - 1] ?? runnable[0]);
326
+ const results = await Promise.allSettled(approved.map(async (phase) => {
221
327
  const outputs = await this.executePhase(orchestration, phase);
222
328
  this.phaseOutputs.set(phase.config.name, outputs);
329
+ }));
330
+ // Process results — mark completed or failed
331
+ for (let i = 0; i < results.length; i++) {
332
+ const phase = approved[i];
333
+ if (results[i].status === 'rejected') {
334
+ phase.status = 'failed';
335
+ }
223
336
  if (phase.status === 'completed') {
224
337
  completed.add(phase.config.name);
338
+ // Confidence-gated phase transition (Feature 3)
339
+ if (this.graphAnalyzer) {
340
+ try {
341
+ const reflection = this.reflectionEngine.reflect(phase);
342
+ const patternStats = this.graphLearner?.getPatternStats(orchestration.config.pattern)?.[0];
343
+ const gateOutputs = this.phaseOutputs.get(phase.config.name) || [];
344
+ const gate = this.graphAnalyzer.evaluatePhaseConfidence({ kind: phase.config.kind ?? 'implement', agentCount: phase.agents.length, outputs: gateOutputs, usage: phase.usage }, { confidence: reflection.confidence }, patternStats ? { successRate: patternStats.successRate, avgDurationMs: patternStats.avgDurationMs } : undefined);
345
+ if (gate.result === 'halt') {
346
+ this.log.warn(`Phase gate HALT: ${gate.reason}`);
347
+ orchestration.status = 'failed';
348
+ }
349
+ if (gate.result === 'warn') {
350
+ this.log.warn(`Phase gate WARNING: ${gate.reason}`);
351
+ this.bus.emit('system:warning', { type: 'gate-warning', orchestrationId: orchestration.config.id, phase: phase.config.name, reason: gate.reason }, 'engine');
352
+ }
353
+ }
354
+ catch { /* Graph gate evaluation failed — continue */ }
355
+ }
356
+ // Trajectory prediction after each completed phase
357
+ if (this.trajectoryPredictor) {
358
+ try {
359
+ const features = this.trajectoryPredictor.extractFeatures(orchestration, phase);
360
+ const pred = this.trajectoryPredictor.predict(features);
361
+ if (pred.successProbability < 0.3 && pred.confidence !== 'low') {
362
+ this.log.warn(`Trajectory predictor: ${(pred.successProbability * 100).toFixed(0)}% success probability (${pred.trajectory})`);
363
+ this.bus.emit('system:warning', { type: 'trajectory-risk', ...pred }, 'engine');
364
+ }
365
+ }
366
+ catch (e) {
367
+ this.log.debug(`Trajectory prediction failed: ${e}`);
368
+ }
369
+ }
225
370
  }
226
371
  else if (phase.status === 'failed') {
227
372
  orchestration.status = 'failed';
228
- break;
373
+ }
374
+ }
375
+ // Trajectory forecast over remaining phases
376
+ if (this.trajectoryPredictor) {
377
+ try {
378
+ const forecastCompleted = orchestration.phases
379
+ .filter(p => p.status === 'completed')
380
+ .map(p => ({ name: p.config.name, status: p.status, tokens: p.usage?.totalTokens || 0, durationMs: p.usage?.durationMs || 0, confidence: 'medium' }));
381
+ const forecastRemaining = orchestration.phases.filter(p => p.status === 'pending').map(p => p.config.name);
382
+ if (forecastRemaining.length > 0) {
383
+ const forecast = this.trajectoryPredictor.predictTrajectory(orchestration.config.id, forecastCompleted, forecastRemaining, orchestration.config.pattern);
384
+ if (forecast.overallSuccessProb < 0.3) {
385
+ this.log.warn(`Trajectory forecast: ${Math.round(forecast.overallSuccessProb * 100)}% success probability`);
386
+ this.bus.emit('system:warning', { type: 'trajectory-forecast', forecast }, 'engine');
387
+ }
388
+ }
389
+ }
390
+ catch (e) {
391
+ this.log.debug(`Trajectory forecast failed: ${e}`);
229
392
  }
230
393
  }
231
394
  if (orchestration.status === 'failed')
@@ -233,12 +396,13 @@ export class SwarmEngine {
233
396
  // Check cost budget after each batch of phases
234
397
  if (orchestration.config.costBudget) {
235
398
  const spent = orchestration.phases
236
- .filter(p => p.status === 'completed')
399
+ .filter((p) => p.status === 'completed')
237
400
  .reduce((sum, p) => sum + p.usage.costUsd, 0);
238
401
  if (spent >= orchestration.config.costBudget) {
239
402
  orchestration.status = 'failed';
240
403
  this.log.warn(`Cost budget exceeded: $${spent.toFixed(2)} >= $${orchestration.config.costBudget}`, {
241
- spent, budget: orchestration.config.costBudget,
404
+ spent,
405
+ budget: orchestration.config.costBudget,
242
406
  });
243
407
  this.bus.emit('system:warning', {
244
408
  reason: 'budget-exceeded',
@@ -250,7 +414,7 @@ export class SwarmEngine {
250
414
  }
251
415
  }
252
416
  }
253
- if (orchestration.status !== 'failed') {
417
+ if (orchestration.status !== 'failed' && orchestration.status !== 'cancelled') {
254
418
  orchestration.status = 'completed';
255
419
  }
256
420
  }
@@ -260,8 +424,50 @@ export class SwarmEngine {
260
424
  error: error instanceof Error ? error.message : String(error),
261
425
  });
262
426
  }
427
+ // Post-failure causal analysis (Feature 1: Causal Inference)
428
+ // Note: suggestIntervention scans all historical orchestrations — skip when graph is large
429
+ if (orchestration.status === 'failed' && this.causalEngine && this.executionGraph) {
430
+ try {
431
+ const orchCount = this.executionGraph.getNodesByType('orchestration').length;
432
+ if (orchCount <= 200) {
433
+ const suggestions = this.causalEngine.suggestIntervention(orchestration.config.id);
434
+ if (suggestions.length > 0) {
435
+ this.log.info(`Causal analysis suggests: ${suggestions[0].reasoning}`);
436
+ this.bus.emit('system:warning', { type: 'causal-suggestion', suggestions }, 'engine');
437
+ }
438
+ }
439
+ }
440
+ catch (e) {
441
+ this.log.debug(`Causal suggestion failed: ${e}`);
442
+ }
443
+ }
444
+ // Self-audit on failure: red-team the engine's own ML subsystems
445
+ // Skipped in mock mode and when insufficient historical data to avoid test overhead
446
+ if (orchestration.status === 'failed' && this.metaAdversarial && !this.options.mock) {
447
+ try {
448
+ const orchCount = this.executionGraph?.getNodesByType('orchestration').length ?? 0;
449
+ if (orchCount >= 5) {
450
+ const report = this.metaAdversarial.runFullAudit({
451
+ patternSelector: this.metaSelector ?? undefined,
452
+ dropout: this.predictiveDropout ?? undefined,
453
+ causal: this.causalEngine ? {
454
+ estimateCausalEffect: (t, tv, cv) =>
455
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
456
+ this.causalEngine.estimateCausalEffect(t, tv, cv),
457
+ } : undefined,
458
+ });
459
+ if (report.overallRisk !== 'low') {
460
+ this.log.warn(`Self-audit found ${report.vulnerabilities.length} ML vulnerabilities (risk: ${report.overallRisk})`);
461
+ this.bus.emit('system:warning', { type: 'self-audit', overallRisk: report.overallRisk, recommendations: report.recommendations }, 'engine');
462
+ }
463
+ }
464
+ }
465
+ catch (e) {
466
+ this.log.debug(`Meta-adversarial audit failed: ${e}`);
467
+ }
468
+ }
263
469
  orchestration.completedAt = new Date();
264
- continuousVerifier?.stop();
470
+ continuousVerifier.stop();
265
471
  // Clean up shared context files
266
472
  for (const f of this.sharedContextFiles) {
267
473
  try {
@@ -270,91 +476,17 @@ export class SwarmEngine {
270
476
  catch { }
271
477
  }
272
478
  this.sharedContextFiles = [];
273
- // Build phase data once for all consumers (avoids 4x redundant mapping)
274
- const phaseData = orchestration.phases.map(p => ({
275
- name: p.config.name,
276
- status: p.status,
277
- agentCount: p.agents.length,
278
- tokens: p.usage.totalTokens,
279
- durationMs: p.usage.durationMs,
280
- confidence: p.agents[0]?.result?.confidence ?? 'unknown',
281
- }));
282
- const traceData = {
283
- orchestrationId: config.id,
284
- task: config.description,
285
- pattern: config.pattern,
286
- status: orchestration.status,
287
- totalTokens: orchestration.usage.totalTokens,
288
- costUsd: orchestration.usage.costUsd,
289
- durationMs: orchestration.usage.durationMs,
290
- phaseCount: orchestration.phases.length,
291
- agentCount: orchestration.phases.reduce((n, p) => n + p.agents.length, 0),
292
- phases: phaseData,
293
- reflections: this.reflections.map(r => redactSecrets(r)),
294
- };
295
- // Store execution trace for learning
296
- if (this.traceStore) {
297
- try {
298
- this.traceStore.store(traceData);
299
- }
300
- catch { /* Don't fail orchestration if trace storage fails */ }
301
- // Extract heuristics from the trace for future learning
302
- if (this.heuristicStore) {
303
- try {
304
- this.heuristicStore.extractFromTrace(traceData);
305
- }
306
- catch { /* Don't fail orchestration if heuristic extraction fails */ }
307
- }
308
- // Auto-compound knowledge from completed orchestrations
309
- if (orchestration.status === 'completed' && this.compounder) {
310
- try {
311
- const doc = this.compounder.extractFromTrace({ ...traceData, status: 'completed' }, this.reflections);
312
- if (doc)
313
- this.compounder.store(doc);
314
- }
315
- catch { /* Don't fail orchestration if compounding fails */ }
316
- }
317
- // Auto-capture outcomes to memory
479
+ // Record learning outcomes (traces, heuristics, model routing, autonomy)
480
+ await this.learningEngine.recordOutcome(orchestration, config, this.reflections);
481
+ // Train trajectory predictor on final outcome
482
+ if (this.trajectoryPredictor) {
318
483
  try {
319
- const { traceToMemoryEntries } = await import('./traces.js');
320
- const memEntries = traceToMemoryEntries(traceData);
321
- // Store in memory if SwarmMemory is available
322
- let memory;
323
- try {
324
- const { SwarmMemory } = await import('../memory/index.js');
325
- memory = new SwarmMemory();
326
- for (const entry of memEntries) {
327
- memory.store({ type: entry.type, title: entry.title, content: entry.content });
328
- }
329
- }
330
- catch { /* Memory not available */ }
331
- finally {
332
- try {
333
- memory?.close();
334
- }
335
- catch { }
336
- }
484
+ this.trajectoryPredictor.recordOutcome(orchestration, orchestration.status === 'completed');
337
485
  }
338
- catch { /* Don't fail orchestration */ }
339
- }
340
- // Record model outcomes for routing
341
- if (this.modelRouter) {
342
- for (const phase of orchestration.phases) {
343
- for (const agent of phase.agents) {
344
- const model = agent.config.model;
345
- if (!model)
346
- continue;
347
- const success = agent.status === 'shutdown' || agent.status === 'idle';
348
- this.modelRouter.record(model, agent.config.name, success, success ? 1.0 : 0.0);
349
- }
486
+ catch (e) {
487
+ this.log.debug(`Trajectory training failed: ${e}`);
350
488
  }
351
489
  }
352
- // Record autonomy outcome
353
- if (this.autonomyTracker) {
354
- const success = orchestration.status === 'completed';
355
- const intervention = orchestration.phases.some(p => p.config.requiresApproval);
356
- this.autonomyTracker.record(config.pattern, success, intervention);
357
- }
358
490
  // Compute total usage
359
491
  orchestration.usage = orchestration.phases.reduce((total, phase) => mergeUsageStats(total, phase.usage), emptyUsageStats());
360
492
  this.bus.emit(orchestration.status === 'completed' ? 'orchestration:complete' : 'orchestration:failed', {
@@ -377,7 +509,10 @@ export class SwarmEngine {
377
509
  async runPattern(patternName, task, options) {
378
510
  const pattern = this.patterns.get(patternName);
379
511
  if (!pattern) {
380
- throw new Error(`Unknown pattern: ${patternName}. Available: ${this.patterns.list().map(p => p.name).join(', ')}`);
512
+ throw new Error(`Unknown pattern: ${patternName}. Available: ${this.patterns
513
+ .list()
514
+ .map((p) => p.name)
515
+ .join(', ')}`);
381
516
  }
382
517
  // Inject task into all agent prompts
383
518
  const config = {
@@ -385,9 +520,9 @@ export class SwarmEngine {
385
520
  name: `${patternName}: ${task.slice(0, 50)}`,
386
521
  description: task,
387
522
  pattern: patternName,
388
- phases: pattern.phases.map(phase => ({
523
+ phases: pattern.phases.map((phase) => ({
389
524
  ...phase,
390
- agents: phase.agents.map(a => ({
525
+ agents: phase.agents.map((a) => ({
391
526
  ...a,
392
527
  prompt: `${task}\n\n${a.prompt ?? ''}`.trim(),
393
528
  })),
@@ -396,17 +531,7 @@ export class SwarmEngine {
396
531
  };
397
532
  // Substitute pattern parameters into agent prompts
398
533
  if (options?.params && pattern.parameters) {
399
- for (const phase of config.phases) {
400
- for (const agent of phase.agents) {
401
- if (agent.prompt) {
402
- for (const [key, value] of Object.entries(options.params)) {
403
- // Use string replacement instead of regex to avoid ReDoS from user-controlled keys
404
- const placeholder = '${' + key + '}';
405
- agent.prompt = agent.prompt.split(placeholder).join(String(value));
406
- }
407
- }
408
- }
409
- }
534
+ this.substituteParams(config.phases, options.params);
410
535
  }
411
536
  return this.execute(config);
412
537
  }
@@ -417,37 +542,24 @@ export class SwarmEngine {
417
542
  plan(patternName, task, options) {
418
543
  const pattern = this.patterns.get(patternName);
419
544
  if (!pattern) {
420
- throw new Error(`Unknown pattern: ${patternName}. Available: ${this.patterns.list().map(p => p.name).join(', ')}`);
545
+ throw new Error(`Unknown pattern: ${patternName}. Available: ${this.patterns
546
+ .list()
547
+ .map((p) => p.name)
548
+ .join(', ')}`);
421
549
  }
422
550
  // Check for similar past traces to inform planning
423
- if (this.traceStore) {
424
- try {
425
- const similar = this.traceStore.findSimilar(task, 3);
426
- if (similar.length > 0) {
427
- let traceContext = '';
428
- const best = similar.find(t => t.status === 'completed');
429
- if (best) {
430
- traceContext = `Past successful orchestration for similar task used pattern "${best.pattern}" with ${best.agentCount} agents (${best.totalTokens} tokens, ${Math.round(best.durationMs / 1000)}s).`;
431
- }
432
- const failed = similar.find(t => t.status === 'failed');
433
- if (failed && failed.reflections.length > 0) {
434
- traceContext += ` Previous attempt failed. Lessons: ${failed.reflections[0]?.slice(0, 200)}`;
435
- }
436
- if (traceContext) {
437
- this.log.info('Found similar past traces', { context: traceContext.slice(0, 200) });
438
- }
439
- }
440
- }
441
- catch { /* Don't fail planning if trace lookup fails */ }
551
+ const traceContext = this.learningEngine.findSimilarTraces(task);
552
+ if (traceContext) {
553
+ this.log.info('Found similar past traces', { context: traceContext.slice(0, 200) });
442
554
  }
443
555
  const id = generateId();
444
- const phases = pattern.phases.map(phase => ({
556
+ const phases = pattern.phases.map((phase) => ({
445
557
  name: phase.name,
446
558
  parallel: phase.parallel,
447
559
  dependsOn: phase.dependsOn,
448
560
  requiresApproval: phase.requiresApproval,
449
561
  tokenBudget: phase.tokenBudget,
450
- agents: phase.agents.map(a => {
562
+ agents: phase.agents.map((a) => {
451
563
  const agentConfig = this.registry.getConfig(a.type);
452
564
  return {
453
565
  name: a.name,
@@ -462,14 +574,7 @@ export class SwarmEngine {
462
574
  }));
463
575
  // Substitute pattern parameters if provided
464
576
  if (options?.params && pattern.parameters) {
465
- for (const phase of phases) {
466
- for (const agent of phase.agents) {
467
- for (const [key, value] of Object.entries(options.params)) {
468
- const placeholder = '${' + key + '}';
469
- agent.prompt = agent.prompt.split(placeholder).join(String(value));
470
- }
471
- }
472
- }
577
+ this.substituteParams(phases, options.params);
473
578
  }
474
579
  const planResult = {
475
580
  id,
@@ -485,33 +590,58 @@ export class SwarmEngine {
485
590
  if (rewrites.length > 0) {
486
591
  this.log.info('Plan rewritten', { rewrites });
487
592
  }
488
- // Retrieve relevant heuristics and inject into first phase
489
- if (this.heuristicStore) {
593
+ // Inject learned heuristics and past solutions into the plan
594
+ this.learningEngine.injectHeuristics(rewrittenPlan);
595
+ this.learningEngine.injectSolutions(rewrittenPlan);
596
+ // Meta-pattern recommendation (Feature 4: Meta-Pattern Selector)
597
+ if (this.metaSelector) {
490
598
  try {
491
- const heuristics = this.heuristicStore.retrieve(task);
492
- if (heuristics.length > 0) {
493
- const context = this.heuristicStore.formatForContext(heuristics);
494
- for (const agent of rewrittenPlan.phases[0]?.agents ?? []) {
495
- agent.prompt = `${context}\n\n${agent.prompt}`;
496
- }
497
- this.log.info('Injected heuristics into plan', { count: heuristics.length });
599
+ const recommendation = this.metaSelector.selectPattern(task);
600
+ if (recommendation.confidence > 0.6) {
601
+ this.log.info(`Meta-selector recommends: ${recommendation.pattern} (${Math.round(recommendation.confidence * 100)}% confidence)`);
498
602
  }
499
603
  }
500
- catch { /* Don't fail planning if heuristic retrieval fails */ }
604
+ catch (e) {
605
+ this.log.debug(`Meta-pattern selection failed: ${e}`);
606
+ }
501
607
  }
502
- // Inject relevant past solutions from knowledge compounder (singleton)
503
- if (this.compounder) {
608
+ // Task discovery: log discovered backlog items from historical failure patterns (skip in mock mode)
609
+ if (this.taskDiscovery && !this.options.mock) {
504
610
  try {
505
- const solutions = this.compounder.findRelevant(task, 3);
506
- if (solutions.length > 0) {
507
- const solutionContext = this.compounder.formatForContext(solutions);
508
- for (const agent of rewrittenPlan.phases[0]?.agents ?? []) {
509
- agent.prompt = `${solutionContext}\n\n${agent.prompt}`;
510
- }
511
- this.log.info('Injected past solutions into plan', { count: solutions.length });
611
+ const backlog = this.taskDiscovery.generateBacklog(3);
612
+ if (backlog.length > 0) {
613
+ this.log.info(`Task discovery: ${backlog.length} actionable items found (top: ${backlog[0]?.title})`);
512
614
  }
513
615
  }
514
- catch { /* Don't fail planning if solution retrieval fails */ }
616
+ catch (e) {
617
+ this.log.debug(`Task discovery failed: ${e}`);
618
+ }
619
+ }
620
+ // Pattern synthesis: log insights from topology analysis (skip in mock mode)
621
+ if (this.patternSynthesizer && !this.options.mock) {
622
+ try {
623
+ const insights = this.patternSynthesizer.analyzeTopologyDiffs(3);
624
+ if (insights.length > 0) {
625
+ const top = insights[0];
626
+ this.log.info(`Pattern synthesis top insight: "${top.feature}" (correlation: ${top.successCorrelation.toFixed(2)}, n=${top.sampleSize})`);
627
+ }
628
+ }
629
+ catch (e) {
630
+ this.log.debug(`Pattern synthesis failed: ${e}`);
631
+ }
632
+ }
633
+ // Pattern synthesis: suggest novel pattern from historical success topology
634
+ if (this.patternSynthesizer && !this.options.mock) {
635
+ try {
636
+ const synthesized = this.patternSynthesizer.synthesizePattern(task);
637
+ if (synthesized && synthesized.confidence > 0.5) {
638
+ this.log.info(`Pattern synthesis suggests: ${synthesized.name} (${Math.round(synthesized.confidence * 100)}% confidence)`);
639
+ this.bus.emit('system:warning', { type: 'pattern-synthesis', pattern: synthesized }, 'engine');
640
+ }
641
+ }
642
+ catch (e) {
643
+ this.log.debug(`Pattern synthesis suggestion failed: ${e}`);
644
+ }
515
645
  }
516
646
  // Search over candidate plans to find the best one
517
647
  const searcher = new PlanSearcher(this.costModel, this.traceStore ?? undefined);
@@ -525,7 +655,7 @@ export class SwarmEngine {
525
655
  bestPlan.estimates = this.costModel.estimate(bestPlan);
526
656
  bestPlan.rewrites = rewrites;
527
657
  if (candidates.length > 1) {
528
- bestPlan._alternatives = candidates.slice(1).map(c => ({
658
+ bestPlan._alternatives = candidates.slice(1).map((c) => ({
529
659
  source: c.source,
530
660
  costUsd: c.cost.costUsd,
531
661
  quality: c.cost.qualityScore,
@@ -544,11 +674,31 @@ export class SwarmEngine {
544
674
  const dropout = this.replanner.evaluateDropout(orchestration, phase.config);
545
675
  if (dropout) {
546
676
  this.log.info(`Agent dropout: ${dropout.reason}`);
547
- phase.config.agents = phase.config.agents.filter(a => dropout.agentsToKeep.includes(a.name));
677
+ phase.config.agents = phase.config.agents.filter((a) => dropout.agentsToKeep.includes(a.name));
548
678
  this.bus.emit('system:warning', { type: 'agent-dropout', ...dropout }, 'adaptive');
549
679
  }
550
680
  }
681
+ // Predictive dropout from ML model (Feature 5: Predictive Dropout)
682
+ if (this.predictiveDropout && phase.config.agents.length > 1) {
683
+ try {
684
+ const recommendations = this.predictiveDropout.predictRedundant(phase.config.agents.map(a => ({ id: a.name || a.type, agentType: a.type })), phase.config.kind ?? 'implement', 0, orchestration.config.pattern || '');
685
+ const toDrop = recommendations.filter(r => r.shouldDropOut);
686
+ if (toDrop.length > 0) {
687
+ this.log.info(`Predictive dropout: skipping ${toDrop.map(d => d.agentType).join(', ')}`);
688
+ phase.config.agents = phase.config.agents.filter(a => !toDrop.some(d => d.agentType === a.type));
689
+ }
690
+ }
691
+ catch (e) {
692
+ this.log.debug(`Predictive dropout failed: ${e}`);
693
+ }
694
+ }
551
695
  const maxRetries = phase.config.maxRetries ?? 2;
696
+ const runContext = {
697
+ phaseOutputs: this.phaseOutputs,
698
+ livingSpec: this.livingSpec,
699
+ sharedContextFiles: this.sharedContextFiles,
700
+ cwd: this.options.cwd,
701
+ };
552
702
  this.log.info(`Phase started: ${phase.config.name}`, {
553
703
  agents: phase.config.agents.length,
554
704
  parallel: phase.config.parallel,
@@ -562,7 +712,7 @@ export class SwarmEngine {
562
712
  try {
563
713
  if (phase.config.parallel) {
564
714
  // Run all agents in parallel (with retry)
565
- const results = await Promise.allSettled(phase.config.agents.map(assignment => this.executeAgentWithRetry(assignment, phase, orchestration, maxRetries)));
715
+ const results = await Promise.allSettled(phase.config.agents.map((assignment) => this.agentRunner.executeAgentWithRetry(assignment, phase, orchestration, maxRetries, runContext)));
566
716
  // Log cache savings estimate for parallel phases
567
717
  if (phase.config.agents.length > 1) {
568
718
  const phaseContext = this.compaction.buildContextPrefix(this.phaseOutputs);
@@ -573,7 +723,7 @@ export class SwarmEngine {
573
723
  }
574
724
  }
575
725
  // Check for failures
576
- const failures = results.filter(r => r.status === 'rejected');
726
+ const failures = results.filter((r) => r.status === 'rejected');
577
727
  if (failures.length > 0) {
578
728
  const failureCount = failures.length;
579
729
  this.log.warn(`Phase had ${failureCount} agent failures`, {
@@ -592,9 +742,16 @@ export class SwarmEngine {
592
742
  }
593
743
  }
594
744
  else {
595
- // Run agents sequentially (with retry)
745
+ // Run agents sequentially (with retry) — accumulate intra-phase outputs for live re-routing (Feature 1)
746
+ const intraPhaseOutputs = new Map();
596
747
  for (const assignment of phase.config.agents) {
597
- await this.executeAgentWithRetry(assignment, phase, orchestration, maxRetries);
748
+ const agentInstance = await this.agentRunner.executeAgentWithRetry(assignment, phase, orchestration, maxRetries, { ...runContext, intraPhaseOutputs });
749
+ // After agent completes, add its output to intra-phase buffer for next sequential agent
750
+ if (agentInstance?.result?.output) {
751
+ const existing = intraPhaseOutputs.get(phase.config.name) || [];
752
+ existing.push(agentInstance.result.output);
753
+ intraPhaseOutputs.set(phase.config.name, existing);
754
+ }
598
755
  // Check phase token budget after each agent
599
756
  if (phase.config.tokenBudget) {
600
757
  const phaseTokens = phase.agents.reduce((sum, a) => sum + a.usage.totalTokens, 0);
@@ -615,8 +772,23 @@ export class SwarmEngine {
615
772
  }
616
773
  phase.completedAt = new Date();
617
774
  phase.usage = phase.agents.reduce((total, agent) => mergeUsageStats(total, agent.usage), emptyUsageStats());
775
+ // Record review feedback into the knowledge graph (Feature 7)
776
+ if (phase.config.kind === 'review' && this.reviewFeedback) {
777
+ for (const agent of phase.agents) {
778
+ if (agent.result?.output) {
779
+ try {
780
+ this.reviewFeedback.recordFindings(orchestration.config.id, phase.config.name, agent.result.output, agent.config.name);
781
+ const findings = parseReviewOutput(agent.result.output, agent.config.name);
782
+ this.reviewFeedback.adjustContextWeights(orchestration.config.id, findings);
783
+ }
784
+ catch (e) {
785
+ this.log.debug(`Review feedback recording failed: ${e}`);
786
+ }
787
+ }
788
+ }
789
+ }
618
790
  // Run verification after implementation phases
619
- if (this.verifier && (phase.config.name.includes('implement') || phase.config.name.includes('integrate'))) {
791
+ if (phase.config.kind === 'implement' || phase.config.kind === 'integrate') {
620
792
  const results = await this.verifier.verify();
621
793
  const summary = Verifier.summarize(results);
622
794
  this.log.info(`Verification: ${summary}`, { phase: phase.config.name });
@@ -647,8 +819,8 @@ export class SwarmEngine {
647
819
  });
648
820
  // Collect agent outputs for inter-phase context
649
821
  const outputs = phase.agents
650
- .filter(a => a.result?.output)
651
- .map(a => `[${a.config.name}]: ${a.result.output.slice(0, 2000)}`);
822
+ .filter((a) => a.result?.output)
823
+ .map((a) => `[${a.config.name}]: ${a.result.output.slice(0, 2000)}`);
652
824
  // Update living spec with phase outputs
653
825
  if (this.livingSpec) {
654
826
  this.livingSpec = updateSpecFromPhase(this.livingSpec, phase.config.name, outputs);
@@ -665,121 +837,6 @@ export class SwarmEngine {
665
837
  }
666
838
  return outputs;
667
839
  }
668
- /**
669
- * Execute a single agent within a phase.
670
- */
671
- async executeAgent(assignment, phase, orchestration) {
672
- // Spawn from registry, passing all assignment overrides
673
- const instance = this.registry.spawn(assignment.type, {
674
- name: assignment.name,
675
- model: assignment.model,
676
- backend: assignment.backend,
677
- backendModel: assignment.backendModel,
678
- });
679
- phase.agents.push(instance);
680
- // Build task prompt with cache-friendly ordering:
681
- // Shared prefix (orchestration + phase context) comes first for API cache hits,
682
- // agent-specific content (definition + task) comes last.
683
- const orchestrationContext = `## Orchestration: ${orchestration.config.name}\nPattern: ${orchestration.config.pattern}`;
684
- const phaseContext = this.compaction.buildContextPrefix(this.phaseOutputs);
685
- const agentPrompt = instance.config.prompt;
686
- const baseTask = assignment.prompt || `Execute task as ${assignment.type}`;
687
- const optimized = optimizeForCache(orchestrationContext, phaseContext, agentPrompt, baseTask);
688
- // For parallel phases with large shared prefix, use shared context file
689
- const sharedContextPath = phase.config.parallel
690
- ? this.writeSharedContext(optimized.sharedPrefix)
691
- : null;
692
- // Cascade model selection: if no explicit model override, pick starting tier by complexity
693
- if (!assignment.model) {
694
- const complexity = classifyTaskComplexity(baseTask);
695
- const startTier = selectStartingTier(complexity);
696
- if (startTier !== instance.config.model) {
697
- instance.config.model = startTier;
698
- }
699
- }
700
- // Inject living spec into task context
701
- const specPrefix = this.livingSpec ? formatLivingSpec(this.livingSpec) + '\n\n' : '';
702
- const task = sharedContextPath
703
- ? `Read the shared context file at ${sharedContextPath} first, then:\n\n${specPrefix}${optimized.agentSuffix}`
704
- : `${specPrefix}${optimized.full}`;
705
- // Transition to running
706
- this.registry.updateStatus(instance.id, 'running');
707
- // Create worktree if enabled and assignment requests it
708
- let worktreeId;
709
- if (this.worktreeManager && assignment.worktree) {
710
- try {
711
- const wt = this.worktreeManager.create(instance.id, assignment.name);
712
- worktreeId = wt.id;
713
- this.bus.emit('worktree:created', { agentId: instance.id, worktreeId: wt.id, path: wt.path }, instance.id);
714
- }
715
- catch (err) {
716
- this.log.warn(`Failed to create worktree for ${assignment.name}: ${err}`);
717
- }
718
- }
719
- // Execute with timeout
720
- const timeoutMs = (instance.config.timeout ?? 300) * 1000; // default 5 min
721
- let timer;
722
- const timeoutPromise = new Promise((_, reject) => {
723
- timer = setTimeout(() => reject(new Error(`Agent timeout after ${timeoutMs / 1000}s`)), timeoutMs);
724
- });
725
- try {
726
- await Promise.race([
727
- this.executor.execute(instance, task),
728
- timeoutPromise,
729
- ]);
730
- clearTimeout(timer);
731
- // Merge worktree if created
732
- if (worktreeId && this.worktreeManager) {
733
- try {
734
- this.worktreeManager.merge(worktreeId);
735
- this.bus.emit('worktree:merged', { agentId: instance.id, worktreeId }, instance.id);
736
- }
737
- catch (err) {
738
- this.log.warn(`Failed to merge worktree ${worktreeId}: ${err}`);
739
- }
740
- }
741
- // Transition to idle (completed successfully)
742
- this.registry.updateStatus(instance.id, 'idle');
743
- // Then shutdown
744
- this.registry.updateStatus(instance.id, 'shutdown');
745
- return instance;
746
- }
747
- catch (error) {
748
- clearTimeout(timer);
749
- if (String(error).includes('timeout')) {
750
- this.registry.updateStatus(instance.id, 'timeout');
751
- }
752
- else {
753
- this.registry.updateStatus(instance.id, 'error');
754
- }
755
- instance.error = error instanceof Error ? error.message : String(error);
756
- throw error;
757
- }
758
- }
759
- async executeAgentWithRetry(assignment, phase, orchestration, maxRetries = 2) {
760
- let lastError;
761
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
762
- try {
763
- return await this.executeAgent(assignment, phase, orchestration);
764
- }
765
- catch (error) {
766
- lastError = error instanceof Error ? error : new Error(String(error));
767
- // Remove the failed instance from phase agents to prevent duplicates on retry
768
- const failedIndex = phase.agents.findIndex(a => a.config.name === assignment.name && (a.status === 'error' || a.status === 'timeout'));
769
- if (failedIndex >= 0)
770
- phase.agents.splice(failedIndex, 1);
771
- if (attempt < maxRetries) {
772
- const delayMs = Math.min(1000 * Math.pow(2, attempt) + Math.random() * 1000, 30000);
773
- this.log.warn(`Agent failed, retrying in ${Math.round(delayMs / 1000)}s (attempt ${attempt + 1}/${maxRetries})`, {
774
- agent: assignment.name,
775
- error: lastError.message,
776
- });
777
- await new Promise(resolve => setTimeout(resolve, delayMs));
778
- }
779
- }
780
- }
781
- throw lastError;
782
- }
783
840
  // ─── Resume ────────────────────────────────────────────────────
784
841
  /**
785
842
  * Resume an orchestration from a checkpoint.
@@ -817,10 +874,8 @@ export class SwarmEngine {
817
874
  const { createInterface } = await import('readline');
818
875
  const rl = createInterface({ input: process.stdin, output: process.stdout });
819
876
  return new Promise((resolve) => {
820
- const agentList = agents.map(a => ` ${a.name} (${a.type})`).join('\n');
821
- rl.question(`\n⏸ Phase "${phaseName}" requires approval.\n` +
822
- ` Agents:\n${agentList}\n` +
823
- ` Proceed? [Y/n] `, (answer) => {
877
+ const agentList = agents.map((a) => ` ${a.name} (${a.type})`).join('\n');
878
+ rl.question(`\n⏸ Phase "${phaseName}" requires approval.\n` + ` Agents:\n${agentList}\n` + ` Proceed? [Y/n] `, (answer) => {
824
879
  rl.close();
825
880
  resolve(answer.toLowerCase() !== 'n');
826
881
  });
@@ -856,26 +911,7 @@ export class SwarmEngine {
856
911
  // Best effort — lifecycle may not allow transition
857
912
  }
858
913
  }
859
- try {
860
- this.stats.close();
861
- }
862
- catch { /* best effort */ }
863
- try {
864
- this.traceStore?.close();
865
- }
866
- catch { /* best effort */ }
867
- try {
868
- this.heuristicStore?.close();
869
- }
870
- catch { /* best effort */ }
871
- try {
872
- this.modelRouter?.close();
873
- }
874
- catch { }
875
- try {
876
- this.autonomyTracker?.close();
877
- }
878
- catch { }
914
+ this.close();
879
915
  this.bus.emit('system:warning', { message: 'Graceful shutdown complete' }, 'engine');
880
916
  };
881
917
  process.on('SIGINT', handler);
@@ -889,28 +925,18 @@ export class SwarmEngine {
889
925
  }
890
926
  this.signalHandlers = [];
891
927
  }
892
- /** Close all resources (stats, traces, heuristics, model router, autonomy tracker). */
928
+ /** Close all resources (stats, traces, heuristics, model router, autonomy tracker, database). */
893
929
  close() {
894
930
  try {
895
931
  this.stats.close();
896
932
  }
897
933
  catch { }
934
+ this.learningEngine.close();
898
935
  try {
899
- this.traceStore?.close();
900
- }
901
- catch { }
902
- try {
903
- this.heuristicStore?.close();
904
- }
905
- catch { }
906
- try {
907
- this.modelRouter?.close();
908
- }
909
- catch { }
910
- try {
911
- this.autonomyTracker?.close();
936
+ this.executionGraph?.close();
912
937
  }
913
938
  catch { }
939
+ closeDatabase();
914
940
  this.removeSignalHandlers();
915
941
  }
916
942
  // ─── Queries ───────────────────────────────────────────────────
@@ -930,33 +956,46 @@ export class SwarmEngine {
930
956
  * Get active orchestrations.
931
957
  */
932
958
  getActiveOrchestrations() {
933
- return [...this.orchestrations.values()].filter(o => o.status === 'running' || o.status === 'paused');
959
+ return [...this.orchestrations.values()].filter((o) => o.status === 'running' || o.status === 'paused');
934
960
  }
935
961
  get patternRegistry() {
936
962
  return this.patterns;
937
963
  }
938
- // ─── Shared Context ────────────────────────────────────────────
964
+ get graph() {
965
+ return this.executionGraph;
966
+ }
967
+ // ─── Helpers ───────────────────────────────────────────────────
968
+ tryInit(factory, name) {
969
+ try {
970
+ return factory();
971
+ }
972
+ catch (e) {
973
+ this.log.warn(`${name} init failed`, { error: e instanceof Error ? e.message : e });
974
+ return null;
975
+ }
976
+ }
939
977
  /**
940
- * Write shared context to a file for parallel agents to read,
941
- * avoiding duplicating large context in each agent's prompt.
978
+ * Substitute ${key} placeholders in agent prompts.
979
+ * Uses string split/join instead of regex to avoid ReDoS from user-controlled keys.
942
980
  */
943
- writeSharedContext(context) {
944
- if (!context || context.length < 2000)
945
- return null; // Not worth sharing for small contexts
946
- const contextDir = join(this.options.cwd ?? process.cwd(), '.swarm');
947
- if (!existsSync(contextDir))
948
- mkdirSync(contextDir, { recursive: true });
949
- const contextPath = join(contextDir, `shared-context-${randomUUID().slice(0, 8)}.md`);
950
- writeFileSync(contextPath, redactSecrets(context), { mode: 0o600 });
951
- this.sharedContextFiles.push(contextPath);
952
- return contextPath;
981
+ substituteParams(phases, params) {
982
+ for (const phase of phases) {
983
+ for (const agent of phase.agents) {
984
+ if (agent.prompt) {
985
+ for (const [key, value] of Object.entries(params)) {
986
+ const placeholder = '${' + key + '}';
987
+ agent.prompt = agent.prompt.split(placeholder).join(String(value));
988
+ }
989
+ }
990
+ }
991
+ }
953
992
  }
954
993
  // ─── Factory ───────────────────────────────────────────────────
955
994
  createInstance(config) {
956
995
  return {
957
996
  config,
958
997
  status: 'pending',
959
- phases: config.phases.map(phaseConfig => ({
998
+ phases: config.phases.map((phaseConfig) => ({
960
999
  config: phaseConfig,
961
1000
  status: 'pending',
962
1001
  agents: [],