@soleri/core 2.12.0 → 7.0.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 (251) hide show
  1. package/data/flows/build.flow.yaml +128 -0
  2. package/data/flows/deliver.flow.yaml +110 -0
  3. package/data/flows/design.flow.yaml +108 -0
  4. package/data/flows/enhance.flow.yaml +90 -0
  5. package/data/flows/explore.flow.yaml +84 -0
  6. package/data/flows/fix.flow.yaml +90 -0
  7. package/data/flows/plan.flow.yaml +87 -0
  8. package/data/flows/review.flow.yaml +90 -0
  9. package/dist/brain/intelligence.d.ts.map +1 -1
  10. package/dist/brain/intelligence.js +16 -2
  11. package/dist/brain/intelligence.js.map +1 -1
  12. package/dist/capabilities/chain-mapping.d.ts +21 -0
  13. package/dist/capabilities/chain-mapping.d.ts.map +1 -0
  14. package/dist/capabilities/chain-mapping.js +86 -0
  15. package/dist/capabilities/chain-mapping.js.map +1 -0
  16. package/dist/capabilities/index.d.ts +10 -0
  17. package/dist/capabilities/index.d.ts.map +1 -0
  18. package/dist/capabilities/index.js +8 -0
  19. package/dist/capabilities/index.js.map +1 -0
  20. package/dist/capabilities/registry.d.ts +95 -0
  21. package/dist/capabilities/registry.d.ts.map +1 -0
  22. package/dist/capabilities/registry.js +227 -0
  23. package/dist/capabilities/registry.js.map +1 -0
  24. package/dist/capabilities/types.d.ts +106 -0
  25. package/dist/capabilities/types.d.ts.map +1 -0
  26. package/dist/capabilities/types.js +12 -0
  27. package/dist/capabilities/types.js.map +1 -0
  28. package/dist/control/intent-router.d.ts.map +1 -1
  29. package/dist/control/intent-router.js +58 -2
  30. package/dist/control/intent-router.js.map +1 -1
  31. package/dist/domain-packs/index.d.ts +8 -0
  32. package/dist/domain-packs/index.d.ts.map +1 -0
  33. package/dist/domain-packs/index.js +8 -0
  34. package/dist/domain-packs/index.js.map +1 -0
  35. package/dist/domain-packs/inject-rules.d.ts +24 -0
  36. package/dist/domain-packs/inject-rules.d.ts.map +1 -0
  37. package/dist/domain-packs/inject-rules.js +65 -0
  38. package/dist/domain-packs/inject-rules.js.map +1 -0
  39. package/dist/domain-packs/knowledge-installer.d.ts +27 -0
  40. package/dist/domain-packs/knowledge-installer.d.ts.map +1 -0
  41. package/dist/domain-packs/knowledge-installer.js +89 -0
  42. package/dist/domain-packs/knowledge-installer.js.map +1 -0
  43. package/dist/domain-packs/loader.d.ts +28 -0
  44. package/dist/domain-packs/loader.d.ts.map +1 -0
  45. package/dist/domain-packs/loader.js +105 -0
  46. package/dist/domain-packs/loader.js.map +1 -0
  47. package/dist/domain-packs/pack-runtime.d.ts +80 -0
  48. package/dist/domain-packs/pack-runtime.d.ts.map +1 -0
  49. package/dist/domain-packs/pack-runtime.js +36 -0
  50. package/dist/domain-packs/pack-runtime.js.map +1 -0
  51. package/dist/domain-packs/skills-installer.d.ts +21 -0
  52. package/dist/domain-packs/skills-installer.d.ts.map +1 -0
  53. package/dist/domain-packs/skills-installer.js +38 -0
  54. package/dist/domain-packs/skills-installer.js.map +1 -0
  55. package/dist/domain-packs/token-resolver.d.ts +37 -0
  56. package/dist/domain-packs/token-resolver.d.ts.map +1 -0
  57. package/dist/domain-packs/token-resolver.js +109 -0
  58. package/dist/domain-packs/token-resolver.js.map +1 -0
  59. package/dist/domain-packs/types.d.ts +91 -0
  60. package/dist/domain-packs/types.d.ts.map +1 -0
  61. package/dist/domain-packs/types.js +122 -0
  62. package/dist/domain-packs/types.js.map +1 -0
  63. package/dist/engine/bin/soleri-engine.d.ts +12 -0
  64. package/dist/engine/bin/soleri-engine.d.ts.map +1 -0
  65. package/dist/engine/bin/soleri-engine.js +183 -0
  66. package/dist/engine/bin/soleri-engine.js.map +1 -0
  67. package/dist/engine/core-ops.d.ts +27 -0
  68. package/dist/engine/core-ops.d.ts.map +1 -0
  69. package/dist/engine/core-ops.js +159 -0
  70. package/dist/engine/core-ops.js.map +1 -0
  71. package/dist/engine/index.d.ts +19 -0
  72. package/dist/engine/index.d.ts.map +1 -0
  73. package/dist/engine/index.js +17 -0
  74. package/dist/engine/index.js.map +1 -0
  75. package/dist/engine/register-engine.d.ts +54 -0
  76. package/dist/engine/register-engine.d.ts.map +1 -0
  77. package/dist/engine/register-engine.js +270 -0
  78. package/dist/engine/register-engine.js.map +1 -0
  79. package/dist/engine/test-helpers.d.ts +30 -0
  80. package/dist/engine/test-helpers.d.ts.map +1 -0
  81. package/dist/engine/test-helpers.js +59 -0
  82. package/dist/engine/test-helpers.js.map +1 -0
  83. package/dist/flows/context-router.d.ts +39 -0
  84. package/dist/flows/context-router.d.ts.map +1 -0
  85. package/dist/flows/context-router.js +206 -0
  86. package/dist/flows/context-router.js.map +1 -0
  87. package/dist/flows/dispatch-registry.d.ts +24 -0
  88. package/dist/flows/dispatch-registry.d.ts.map +1 -0
  89. package/dist/flows/dispatch-registry.js +70 -0
  90. package/dist/flows/dispatch-registry.js.map +1 -0
  91. package/dist/flows/epilogue.d.ts +24 -0
  92. package/dist/flows/epilogue.d.ts.map +1 -0
  93. package/dist/flows/epilogue.js +52 -0
  94. package/dist/flows/epilogue.js.map +1 -0
  95. package/dist/flows/executor.d.ts +25 -0
  96. package/dist/flows/executor.d.ts.map +1 -0
  97. package/dist/flows/executor.js +153 -0
  98. package/dist/flows/executor.js.map +1 -0
  99. package/dist/flows/gate-evaluator.d.ts +26 -0
  100. package/dist/flows/gate-evaluator.d.ts.map +1 -0
  101. package/dist/flows/gate-evaluator.js +162 -0
  102. package/dist/flows/gate-evaluator.js.map +1 -0
  103. package/dist/flows/index.d.ts +14 -0
  104. package/dist/flows/index.d.ts.map +1 -0
  105. package/dist/flows/index.js +20 -0
  106. package/dist/flows/index.js.map +1 -0
  107. package/dist/flows/loader.d.ts +17 -0
  108. package/dist/flows/loader.d.ts.map +1 -0
  109. package/dist/flows/loader.js +61 -0
  110. package/dist/flows/loader.js.map +1 -0
  111. package/dist/flows/plan-builder.d.ts +40 -0
  112. package/dist/flows/plan-builder.d.ts.map +1 -0
  113. package/dist/flows/plan-builder.js +213 -0
  114. package/dist/flows/plan-builder.js.map +1 -0
  115. package/dist/flows/probes.d.ts +11 -0
  116. package/dist/flows/probes.d.ts.map +1 -0
  117. package/dist/flows/probes.js +62 -0
  118. package/dist/flows/probes.js.map +1 -0
  119. package/dist/flows/types.d.ts +950 -0
  120. package/dist/flows/types.d.ts.map +1 -0
  121. package/dist/flows/types.js +105 -0
  122. package/dist/flows/types.js.map +1 -0
  123. package/dist/index.d.ts +11 -1
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +10 -1
  126. package/dist/index.js.map +1 -1
  127. package/dist/intelligence/loader.d.ts +19 -0
  128. package/dist/intelligence/loader.d.ts.map +1 -1
  129. package/dist/intelligence/loader.js +35 -0
  130. package/dist/intelligence/loader.js.map +1 -1
  131. package/dist/intelligence/types.d.ts +1 -0
  132. package/dist/intelligence/types.d.ts.map +1 -1
  133. package/dist/packs/types.d.ts +58 -19
  134. package/dist/packs/types.d.ts.map +1 -1
  135. package/dist/packs/types.js +14 -0
  136. package/dist/packs/types.js.map +1 -1
  137. package/dist/playbooks/generic/onboarding.d.ts +9 -0
  138. package/dist/playbooks/generic/onboarding.d.ts.map +1 -0
  139. package/dist/playbooks/generic/onboarding.js +74 -0
  140. package/dist/playbooks/generic/onboarding.js.map +1 -0
  141. package/dist/playbooks/playbook-registry.d.ts.map +1 -1
  142. package/dist/playbooks/playbook-registry.js +2 -0
  143. package/dist/playbooks/playbook-registry.js.map +1 -1
  144. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  145. package/dist/runtime/admin-extra-ops.js +15 -9
  146. package/dist/runtime/admin-extra-ops.js.map +1 -1
  147. package/dist/runtime/admin-ops.js +4 -4
  148. package/dist/runtime/admin-ops.js.map +1 -1
  149. package/dist/runtime/capture-ops.d.ts.map +1 -1
  150. package/dist/runtime/capture-ops.js +33 -1
  151. package/dist/runtime/capture-ops.js.map +1 -1
  152. package/dist/runtime/domain-ops.d.ts +21 -5
  153. package/dist/runtime/domain-ops.d.ts.map +1 -1
  154. package/dist/runtime/domain-ops.js +64 -6
  155. package/dist/runtime/domain-ops.js.map +1 -1
  156. package/dist/runtime/facades/cognee-facade.d.ts.map +1 -1
  157. package/dist/runtime/facades/cognee-facade.js +3 -1
  158. package/dist/runtime/facades/cognee-facade.js.map +1 -1
  159. package/dist/runtime/facades/index.d.ts.map +1 -1
  160. package/dist/runtime/facades/index.js +10 -6
  161. package/dist/runtime/facades/index.js.map +1 -1
  162. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  163. package/dist/runtime/facades/vault-facade.js +2 -0
  164. package/dist/runtime/facades/vault-facade.js.map +1 -1
  165. package/dist/runtime/orchestrate-ops.d.ts +8 -7
  166. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  167. package/dist/runtime/orchestrate-ops.js +217 -61
  168. package/dist/runtime/orchestrate-ops.js.map +1 -1
  169. package/dist/runtime/runtime.d.ts.map +1 -1
  170. package/dist/runtime/runtime.js +23 -17
  171. package/dist/runtime/runtime.js.map +1 -1
  172. package/dist/runtime/types.d.ts +6 -2
  173. package/dist/runtime/types.d.ts.map +1 -1
  174. package/dist/runtime/vault-linking-ops.d.ts +13 -0
  175. package/dist/runtime/vault-linking-ops.d.ts.map +1 -0
  176. package/dist/runtime/vault-linking-ops.js +367 -0
  177. package/dist/runtime/vault-linking-ops.js.map +1 -0
  178. package/dist/vault/linking.d.ts +46 -0
  179. package/dist/vault/linking.d.ts.map +1 -0
  180. package/dist/vault/linking.js +275 -0
  181. package/dist/vault/linking.js.map +1 -0
  182. package/dist/vault/vault-types.d.ts +37 -0
  183. package/dist/vault/vault-types.d.ts.map +1 -1
  184. package/dist/vault/vault.d.ts +12 -0
  185. package/dist/vault/vault.d.ts.map +1 -1
  186. package/dist/vault/vault.js +85 -6
  187. package/dist/vault/vault.js.map +1 -1
  188. package/package.json +4 -1
  189. package/src/__tests__/admin-extra-ops.test.ts +1 -1
  190. package/src/__tests__/admin-ops.test.ts +2 -1
  191. package/src/__tests__/cognee-client-gaps.test.ts +470 -0
  192. package/src/__tests__/cognee-hybrid-search.test.ts +478 -0
  193. package/src/__tests__/cognee-sync-manager-deep.test.ts +630 -0
  194. package/src/__tests__/cognee-sync-manager.test.ts +1 -0
  195. package/src/__tests__/core-ops.test.ts +9 -61
  196. package/src/__tests__/domain-packs.test.ts +421 -0
  197. package/src/__tests__/flows.test.ts +604 -0
  198. package/src/__tests__/playbook-registry.test.ts +2 -2
  199. package/src/__tests__/playbook-seeder.test.ts +8 -8
  200. package/src/__tests__/playbook.test.ts +5 -5
  201. package/src/__tests__/token-resolver.test.ts +79 -0
  202. package/src/brain/intelligence.ts +21 -2
  203. package/src/capabilities/chain-mapping.ts +93 -0
  204. package/src/capabilities/index.ts +21 -0
  205. package/src/capabilities/registry.ts +290 -0
  206. package/src/capabilities/types.ts +143 -0
  207. package/src/control/intent-router.ts +46 -2
  208. package/src/domain-packs/index.ts +27 -0
  209. package/src/domain-packs/inject-rules.ts +74 -0
  210. package/src/domain-packs/knowledge-installer.ts +116 -0
  211. package/src/domain-packs/loader.ts +124 -0
  212. package/src/domain-packs/pack-runtime.ts +99 -0
  213. package/src/domain-packs/skills-installer.ts +56 -0
  214. package/src/domain-packs/token-resolver.ts +126 -0
  215. package/src/domain-packs/types.ts +229 -0
  216. package/src/engine/__tests__/register-engine.test.ts +104 -0
  217. package/src/engine/bin/soleri-engine.ts +217 -0
  218. package/src/engine/core-ops.ts +178 -0
  219. package/src/engine/index.ts +19 -0
  220. package/src/engine/register-engine.ts +385 -0
  221. package/src/engine/test-helpers.ts +83 -0
  222. package/src/flows/context-router.ts +257 -0
  223. package/src/flows/dispatch-registry.ts +80 -0
  224. package/src/flows/epilogue.ts +65 -0
  225. package/src/flows/executor.ts +182 -0
  226. package/src/flows/gate-evaluator.ts +171 -0
  227. package/src/flows/index.ts +52 -0
  228. package/src/flows/loader.ts +63 -0
  229. package/src/flows/plan-builder.ts +250 -0
  230. package/src/flows/probes.ts +70 -0
  231. package/src/flows/types.ts +217 -0
  232. package/src/index.ts +68 -1
  233. package/src/intelligence/loader.ts +38 -0
  234. package/src/intelligence/types.ts +1 -0
  235. package/src/packs/types.ts +19 -0
  236. package/src/playbooks/generic/onboarding.ts +79 -0
  237. package/src/playbooks/playbook-registry.ts +2 -0
  238. package/src/runtime/admin-extra-ops.ts +14 -8
  239. package/src/runtime/admin-ops.ts +4 -4
  240. package/src/runtime/capture-ops.ts +40 -1
  241. package/src/runtime/domain-ops.ts +71 -5
  242. package/src/runtime/facades/cognee-facade.ts +3 -1
  243. package/src/runtime/facades/index.ts +12 -6
  244. package/src/runtime/facades/vault-facade.ts +2 -0
  245. package/src/runtime/orchestrate-ops.ts +261 -65
  246. package/src/runtime/runtime.ts +27 -18
  247. package/src/runtime/types.ts +6 -2
  248. package/src/runtime/vault-linking-ops.ts +454 -0
  249. package/src/vault/linking.ts +333 -0
  250. package/src/vault/vault-types.ts +46 -0
  251. package/src/vault/vault.ts +94 -7
@@ -1,13 +1,18 @@
1
1
  /**
2
- * Domain facade factory — creates the standard 5-op domain facade pattern.
2
+ * Domain facade factory — creates domain facades with optional pack support.
3
3
  *
4
- * Every domain gets: get_patterns, search, get_entry, capture, remove.
5
- * This replaces per-domain generated facade files.
4
+ * Without packs: every domain gets the standard 5 ops (get_patterns, search,
5
+ * get_entry, capture, remove).
6
+ *
7
+ * With packs: pack ops are PRIMARY, standard 5 ops are FALLBACK for any op
8
+ * name not defined by the pack. Pack standalone facades are registered as
9
+ * additional MCP tools.
6
10
  */
7
11
 
8
12
  import { z } from 'zod';
9
13
  import type { FacadeConfig, OpDefinition } from '../facades/types.js';
10
14
  import type { AgentRuntime } from './types.js';
15
+ import type { DomainPack } from '../domain-packs/types.js';
11
16
 
12
17
  function capitalize(s: string): string {
13
18
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -200,16 +205,77 @@ export function createDomainFacade(
200
205
  }
201
206
 
202
207
  /**
203
- * Create domain facades for all domains.
208
+ * Create domain facades for all domains, with optional pack support.
209
+ *
210
+ * When packs are provided:
211
+ * - For each domain, check if any pack claims it via pack.domains[]
212
+ * - If a pack claims the domain: pack ops are PRIMARY, standard 5 ops are
213
+ * FALLBACK (only for op names not defined by the pack)
214
+ * - Pack standalone facades (pack.facades[]) are registered as additional
215
+ * MCP tools with agentId prefix
216
+ * - Domains not claimed by any pack get the standard 5 ops (OCP)
217
+ *
218
+ * When packs is undefined or empty: identical to previous behavior.
204
219
  *
205
220
  * @param runtime - The agent runtime
206
221
  * @param agentId - Agent identifier
207
222
  * @param domains - Array of domain names
223
+ * @param packs - Optional array of loaded domain packs
208
224
  */
209
225
  export function createDomainFacades(
210
226
  runtime: AgentRuntime,
211
227
  agentId: string,
212
228
  domains: string[],
229
+ packs?: DomainPack[],
213
230
  ): FacadeConfig[] {
214
- return domains.map((d) => createDomainFacade(runtime, agentId, d));
231
+ // Build a map: domain name pack that claims it
232
+ const packByDomain = new Map<string, DomainPack>();
233
+ if (packs) {
234
+ for (const pack of packs) {
235
+ for (const domain of pack.domains) {
236
+ packByDomain.set(domain, pack);
237
+ }
238
+ }
239
+ }
240
+
241
+ // Create domain facades (with pack merge when applicable)
242
+ const domainFacades = domains.map((domain) => {
243
+ const pack = packByDomain.get(domain);
244
+ if (!pack) {
245
+ // No pack claims this domain — standard 5-op facade (OCP)
246
+ return createDomainFacade(runtime, agentId, domain);
247
+ }
248
+
249
+ // Pack claims this domain — merge ops
250
+ const standardFacade = createDomainFacade(runtime, agentId, domain);
251
+ const packOpNames = new Set(pack.ops.map((op) => op.name));
252
+
253
+ // Pack ops are primary; standard ops are fallback for unclaimed names
254
+ const mergedOps: OpDefinition[] = [
255
+ ...pack.ops,
256
+ ...standardFacade.ops.filter((op) => !packOpNames.has(op.name)),
257
+ ];
258
+
259
+ return {
260
+ ...standardFacade,
261
+ ops: mergedOps,
262
+ };
263
+ });
264
+
265
+ // Collect standalone facades from packs (prefixed with agentId)
266
+ const standaloneFacades: FacadeConfig[] = [];
267
+ if (packs) {
268
+ for (const pack of packs) {
269
+ if (pack.facades) {
270
+ for (const facade of pack.facades) {
271
+ standaloneFacades.push({
272
+ ...facade,
273
+ name: `${agentId}_${facade.name}`,
274
+ });
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ return [...domainFacades, ...standaloneFacades];
215
281
  }
@@ -11,7 +11,9 @@ import type { CogneeSearchType } from '../../cognee/types.js';
11
11
  import { createCogneeSyncOps } from '../cognee-sync-ops.js';
12
12
 
13
13
  export function createCogneeFacadeOps(runtime: AgentRuntime): OpDefinition[] {
14
- const { cognee, vault, syncManager } = runtime;
14
+ // Only called when runtime.cognee is non-null (guarded in createSemanticFacades)
15
+ const cognee = runtime.cognee!;
16
+ const { vault, syncManager } = runtime;
15
17
 
16
18
  return [
17
19
  // ─── Cognee (inline from core-ops.ts) ───────────────────────
@@ -22,7 +22,7 @@ import { createAgencyFacadeOps } from './agency-facade.js';
22
22
  import { createChatFacadeOps } from './chat-facade.js';
23
23
 
24
24
  export function createSemanticFacades(runtime: AgentRuntime, agentId: string): FacadeConfig[] {
25
- return [
25
+ const facades: FacadeConfig[] = [
26
26
  {
27
27
  name: `${agentId}_vault`,
28
28
  description: 'Knowledge management — search, CRUD, import/export, intake, archival.',
@@ -69,11 +69,6 @@ export function createSemanticFacades(runtime: AgentRuntime, agentId: string): F
69
69
  description: 'Agent behavior — identity, intent routing, morphing, guidelines, governance.',
70
70
  ops: createControlFacadeOps(runtime),
71
71
  },
72
- {
73
- name: `${agentId}_cognee`,
74
- description: 'Knowledge graph — Cognee search, sync, export, graph stats.',
75
- ops: createCogneeFacadeOps(runtime),
76
- },
77
72
  {
78
73
  name: `${agentId}_context`,
79
74
  description: 'Context analysis — entity extraction, knowledge retrieval, confidence scoring.',
@@ -92,4 +87,15 @@ export function createSemanticFacades(runtime: AgentRuntime, agentId: string): F
92
87
  ops: createChatFacadeOps(runtime),
93
88
  },
94
89
  ];
90
+
91
+ // Cognee facade — only registered when Cognee integration is enabled
92
+ if (runtime.cognee) {
93
+ facades.push({
94
+ name: `${agentId}_cognee`,
95
+ description: 'Knowledge graph — Cognee search, sync, export, graph stats.',
96
+ ops: createCogneeFacadeOps(runtime),
97
+ });
98
+ }
99
+
100
+ return facades;
95
101
  }
@@ -12,6 +12,7 @@ import { createVaultExtraOps } from '../vault-extra-ops.js';
12
12
  import { createCaptureOps } from '../capture-ops.js';
13
13
  import { createIntakeOps } from '../intake-ops.js';
14
14
  import { createVaultSharingOps } from '../vault-sharing-ops.js';
15
+ import { createVaultLinkingOps } from '../vault-linking-ops.js';
15
16
  import { ObsidianSync } from '../../vault/obsidian-sync.js';
16
17
 
17
18
  export function createVaultFacadeOps(runtime: AgentRuntime): OpDefinition[] {
@@ -479,5 +480,6 @@ export function createVaultFacadeOps(runtime: AgentRuntime): OpDefinition[] {
479
480
  ...createCaptureOps(runtime),
480
481
  ...createIntakeOps(intakePipeline),
481
482
  ...createVaultSharingOps(runtime),
483
+ ...createVaultLinkingOps(runtime),
482
484
  ];
483
485
  }
@@ -1,57 +1,180 @@
1
1
  /**
2
- * Orchestration operations — compose planning + brain + vault into high-level workflows.
2
+ * Orchestration operations — flow-engine-driven workflows.
3
3
  *
4
- * These ops are convenience wrappers that sequence multiple module calls:
5
- * - orchestrate_plan: brain-informed plan creation
6
- * - orchestrate_execute: start plan + brain session together
7
- * - orchestrate_complete: finish plan + brain session + extract knowledge
4
+ * These ops wire the YAML flow engine into the facade layer:
5
+ * - orchestrate_plan: intent detection + buildPlan from flow engine
6
+ * - orchestrate_execute: FlowExecutor dispatches steps to facade ops
7
+ * - orchestrate_complete: runEpilogue captures knowledge + session
8
8
  * - orchestrate_status: combined status across all modules
9
9
  * - orchestrate_quick_capture: one-call knowledge capture without full planning
10
10
  */
11
11
 
12
12
  import { z } from 'zod';
13
- import type { OpDefinition } from '../facades/types.js';
13
+ import type { OpDefinition, FacadeConfig } from '../facades/types.js';
14
14
  import type { AgentRuntime } from './types.js';
15
+ import { buildPlan } from '../flows/plan-builder.js';
16
+ import { FlowExecutor } from '../flows/executor.js';
17
+ import { createDispatcher } from '../flows/dispatch-registry.js';
18
+ import { runEpilogue } from '../flows/epilogue.js';
19
+ import type { OrchestrationPlan, ExecutionResult } from '../flows/types.js';
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Intent detection — keyword-based mapping from prompt to intent
23
+ // ---------------------------------------------------------------------------
24
+
25
+ const INTENT_KEYWORDS: [RegExp, string][] = [
26
+ [/\b(fix|bug|broken|error|crash|issue)\b/i, 'FIX'],
27
+ [/\b(review|audit|check|inspect)\b/i, 'REVIEW'],
28
+ [/\b(build|create|add|new|implement|scaffold)\b/i, 'BUILD'],
29
+ [/\b(plan|architect|design-system|roadmap)\b/i, 'PLAN'],
30
+ [/\b(enhance|improve|refactor|optimize)\b/i, 'ENHANCE'],
31
+ [/\b(explore|research|investigate|spike)\b/i, 'EXPLORE'],
32
+ [/\b(deploy|ship|release|publish)\b/i, 'DELIVER'],
33
+ [/\b(design|palette|theme|color|typography)\b/i, 'DESIGN'],
34
+ ];
35
+
36
+ function detectIntent(prompt: string): string {
37
+ for (const [pattern, intent] of INTENT_KEYWORDS) {
38
+ if (pattern.test(prompt)) return intent;
39
+ }
40
+ return 'BUILD'; // default
41
+ }
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // In-memory plan store
45
+ // ---------------------------------------------------------------------------
46
+
47
+ interface PlanEntry {
48
+ plan: OrchestrationPlan;
49
+ executionResult?: ExecutionResult;
50
+ createdAt: number;
51
+ }
52
+
53
+ const planStore = new Map<string, PlanEntry>();
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Helper: create a runtime-backed dispatcher
57
+ // ---------------------------------------------------------------------------
58
+
59
+ /**
60
+ * Build a dispatch function that routes tool names to runtime modules.
61
+ * If facades are provided, uses the full dispatch registry.
62
+ * Otherwise, falls back to a simple runtime-based dispatcher.
63
+ */
64
+ function buildDispatch(
65
+ agentId: string,
66
+ runtime: AgentRuntime,
67
+ facades?: FacadeConfig[],
68
+ ) {
69
+ if (facades && facades.length > 0) {
70
+ return createDispatcher(agentId, facades);
71
+ }
72
+
73
+ // Fallback: runtime-based dispatch for known tool patterns
74
+ return async (
75
+ toolName: string,
76
+ params: Record<string, unknown>,
77
+ ): Promise<{ tool: string; status: string; data?: unknown; error?: string }> => {
78
+ try {
79
+ // Handle well-known epilogue tools directly via runtime
80
+ if (toolName === 'capture_knowledge' || toolName.endsWith('_capture_knowledge')) {
81
+ const title = (params.title as string) ?? 'Flow execution';
82
+ const description = (params.content as string) ?? (params.description as string) ?? '';
83
+ const tags = (params.tags as string[]) ?? ['workflow'];
84
+ runtime.vault.add({
85
+ id: `flow-${Date.now()}`,
86
+ title,
87
+ description,
88
+ type: 'pattern',
89
+ domain: 'workflow',
90
+ severity: 'suggestion',
91
+ tags,
92
+ });
93
+ return { tool: toolName, status: 'ok', data: { title } };
94
+ }
95
+
96
+ if (toolName === 'session_capture' || toolName.endsWith('_session_capture')) {
97
+ // Session capture is best-effort
98
+ return { tool: toolName, status: 'ok', data: { sessionId: 'flow-session' } };
99
+ }
100
+
101
+ // For other tools: mark as unregistered (graceful degradation)
102
+ return { tool: toolName, status: 'unregistered' };
103
+ } catch (err) {
104
+ return {
105
+ tool: toolName,
106
+ status: 'error',
107
+ error: err instanceof Error ? err.message : String(err),
108
+ };
109
+ }
110
+ };
111
+ }
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // Op factory
115
+ // ---------------------------------------------------------------------------
15
116
 
16
117
  /**
17
118
  * Create the 5 orchestration operations for an agent runtime.
119
+ * Optionally accepts facades for full dispatch capability.
18
120
  */
19
- export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
121
+ export function createOrchestrateOps(
122
+ runtime: AgentRuntime,
123
+ facades?: FacadeConfig[],
124
+ ): OpDefinition[] {
20
125
  const { planner, brainIntelligence, vault } = runtime;
126
+ const agentId = runtime.config.agentId;
21
127
 
22
128
  return [
23
129
  // ─── orchestrate_plan ─────────────────────────────────────────
24
130
  {
25
131
  name: 'orchestrate_plan',
26
132
  description:
27
- 'Create a brain-informed plan with recommendations from pattern strengths. ' +
28
- 'Fetches relevant brain recommendations for the domain/task, then creates a plan ' +
29
- 'with those recommendations injected as decisions.',
133
+ 'Create a flow-engine-driven plan. Detects intent from the prompt, ' +
134
+ 'loads the matching YAML flow, probes runtime capabilities, and builds ' +
135
+ 'a pruned orchestration plan with gate-guarded steps.',
30
136
  auth: 'write',
31
137
  schema: z.object({
32
- objective: z.string().describe('What the plan aims to achieve'),
33
- scope: z.string().describe('Boundaries of the work'),
138
+ prompt: z
139
+ .string()
140
+ .describe('Natural language description of what to do'),
141
+ projectPath: z
142
+ .string()
143
+ .optional()
144
+ .default('.')
145
+ .describe('Project root path'),
146
+ // Legacy params — still accepted for backward compat
147
+ objective: z
148
+ .string()
149
+ .optional()
150
+ .describe('(Legacy) Plan objective — use prompt instead'),
151
+ scope: z
152
+ .string()
153
+ .optional()
154
+ .describe('(Legacy) Plan scope'),
34
155
  domain: z
35
156
  .string()
36
157
  .optional()
37
- .describe('Domain for brain recommendations (e.g. "component", "styling")'),
158
+ .describe('Domain hint for brain recommendations'),
38
159
  tasks: z
39
160
  .array(z.object({ title: z.string(), description: z.string() }))
40
161
  .optional()
41
162
  .describe('Optional pre-defined tasks'),
42
163
  }),
43
164
  handler: async (params) => {
44
- const objective = params.objective as string;
45
- const scope = params.scope as string;
165
+ const prompt = (params.prompt as string) ?? (params.objective as string) ?? '';
166
+ const projectPath = (params.projectPath as string) ?? '.';
46
167
  const domain = params.domain as string | undefined;
47
- const tasks = (params.tasks as Array<{ title: string; description: string }>) ?? [];
48
168
 
49
- // Get brain recommendations graceful degradation if no data
169
+ // 1. Detect intent from prompt
170
+ const intent = detectIntent(prompt);
171
+
172
+ // 2. Get brain recommendations — graceful degradation
50
173
  let recommendations: Array<{ pattern: string; strength: number }> = [];
51
174
  try {
52
175
  const raw = brainIntelligence.recommend({
53
176
  domain,
54
- task: objective,
177
+ task: prompt,
55
178
  limit: 5,
56
179
  });
57
180
  recommendations = raw.map((r) => ({
@@ -59,36 +182,63 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
59
182
  strength: r.strength,
60
183
  }));
61
184
  } catch {
62
- // Brain has no data yet — proceed without recommendations
185
+ // Brain has no data yet
63
186
  }
64
187
 
65
- // Fallback: if brain returned nothing, pull from vault
188
+ // Fallback to vault if brain empty
66
189
  if (recommendations.length === 0) {
67
190
  try {
68
- const vaultResults = vault.search(objective, { domain, limit: 5 });
191
+ const vaultResults = vault.search(prompt, { domain, limit: 5 });
69
192
  recommendations = vaultResults.map((r) => ({
70
193
  pattern: r.entry.title,
71
194
  strength: 50,
72
195
  }));
73
196
  } catch {
74
- // Vault search failed — proceed without recommendations
197
+ // Vault search failed
75
198
  }
76
199
  }
77
200
 
78
- // Build decisions from recommendations
201
+ // 3. Build flow-engine plan
202
+ const plan = await buildPlan(intent, agentId, projectPath, runtime, prompt);
203
+
204
+ // 4. Store in planStore
205
+ planStore.set(plan.planId, { plan, createdAt: Date.now() });
206
+
207
+ // 5. Also create a planner plan for lifecycle tracking (backward compat)
79
208
  const decisions = recommendations.map(
80
209
  (r) => `Brain pattern: ${r.pattern} (strength: ${r.strength.toFixed(1)})`,
81
210
  );
211
+ const tasks = (params.tasks as Array<{ title: string; description: string }>) ?? [];
82
212
 
83
- // Create plan with recommendations as context
84
- const plan = planner.create({
85
- objective,
86
- scope,
87
- decisions,
88
- tasks,
89
- });
213
+ let legacyPlan;
214
+ try {
215
+ legacyPlan = planner.create({
216
+ objective: prompt,
217
+ scope: (params.scope as string) ?? `${intent} workflow`,
218
+ decisions,
219
+ tasks,
220
+ });
221
+ } catch {
222
+ // Planner creation failed — flow plan still valid
223
+ }
90
224
 
91
- return { plan, recommendations };
225
+ return {
226
+ plan: legacyPlan ?? {
227
+ id: plan.planId,
228
+ objective: prompt,
229
+ decisions,
230
+ },
231
+ recommendations,
232
+ flow: {
233
+ planId: plan.planId,
234
+ intent: plan.intent,
235
+ flowId: plan.flowId,
236
+ stepsCount: plan.steps.length,
237
+ skippedCount: plan.skipped.length,
238
+ warnings: plan.warnings,
239
+ estimatedTools: plan.estimatedTools,
240
+ },
241
+ };
92
242
  },
93
243
  },
94
244
 
@@ -96,11 +246,11 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
96
246
  {
97
247
  name: 'orchestrate_execute',
98
248
  description:
99
- 'Start plan execution and open a brain session to track the work. ' +
100
- 'The plan must be in "approved" status. Returns both the updated plan and session ID.',
249
+ 'Execute a flow-engine plan. Dispatches each step to its facade ops, ' +
250
+ 'evaluates gates, and tracks execution with a brain session.',
101
251
  auth: 'write',
102
252
  schema: z.object({
103
- planId: z.string().describe('ID of the approved plan to start executing'),
253
+ planId: z.string().describe('ID of the plan to execute (flow planId or legacy planId)'),
104
254
  domain: z.string().optional().describe('Domain for brain session tracking'),
105
255
  context: z.string().optional().describe('Additional context for the brain session'),
106
256
  }),
@@ -109,10 +259,41 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
109
259
  const domain = params.domain as string | undefined;
110
260
  const context = params.context as string | undefined;
111
261
 
112
- // Start plan execution
113
- const plan = planner.startExecution(planId);
262
+ // Look up flow plan
263
+ const entry = planStore.get(planId);
114
264
 
115
- // Start brain session linked to this plan
265
+ if (entry) {
266
+ // Flow-engine execution path
267
+ const dispatch = buildDispatch(agentId, runtime, facades);
268
+ const executor = new FlowExecutor(dispatch);
269
+ const executionResult = await executor.execute(entry.plan);
270
+
271
+ // Store result
272
+ entry.executionResult = executionResult;
273
+
274
+ // Start brain session
275
+ const session = brainIntelligence.lifecycle({
276
+ action: 'start',
277
+ domain,
278
+ context,
279
+ planId,
280
+ });
281
+
282
+ return {
283
+ plan: { id: planId, status: 'executing' },
284
+ session,
285
+ execution: {
286
+ status: executionResult.status,
287
+ stepsCompleted: executionResult.stepsCompleted,
288
+ totalSteps: executionResult.totalSteps,
289
+ toolsCalled: executionResult.toolsCalled,
290
+ durationMs: executionResult.durationMs,
291
+ },
292
+ };
293
+ }
294
+
295
+ // Legacy path: no flow plan found, use planner directly
296
+ const plan = planner.startExecution(planId);
116
297
  const session = brainIntelligence.lifecycle({
117
298
  action: 'start',
118
299
  domain,
@@ -128,9 +309,8 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
128
309
  {
129
310
  name: 'orchestrate_complete',
130
311
  description:
131
- 'Complete plan execution, end brain session, and extract knowledge. ' +
132
- 'Performs three steps: marks plan completed, ends the brain session with outcome, ' +
133
- 'and runs knowledge extraction on the session.',
312
+ 'Complete plan execution, run epilogue (knowledge capture + session capture), ' +
313
+ 'end brain session, and clean up.',
134
314
  auth: 'write',
135
315
  schema: z.object({
136
316
  planId: z.string().describe('ID of the executing plan to complete'),
@@ -150,10 +330,10 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
150
330
  const toolsUsed = (params.toolsUsed as string[]) ?? [];
151
331
  const filesModified = (params.filesModified as string[]) ?? [];
152
332
 
153
- // Complete the plan
333
+ // Complete the planner plan (legacy lifecycle)
154
334
  const plan = planner.complete(planId);
155
335
 
156
- // End brain session with outcome
336
+ // End brain session
157
337
  const session = brainIntelligence.lifecycle({
158
338
  action: 'end',
159
339
  sessionId,
@@ -163,15 +343,36 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
163
343
  filesModified,
164
344
  });
165
345
 
166
- // Extract knowledge from the session — graceful if nothing to extract
346
+ // Extract knowledge
167
347
  let extraction = null;
168
348
  try {
169
349
  extraction = brainIntelligence.extractKnowledge(sessionId);
170
350
  } catch {
171
- // Session may not have enough signal for extraction — that's OK
351
+ // Not enough signal
172
352
  }
173
353
 
174
- return { plan, session, extraction };
354
+ // Run flow-engine epilogue if we have a flow plan
355
+ let epilogueResult = null;
356
+ const entry = planStore.get(planId);
357
+ if (entry) {
358
+ try {
359
+ const dispatch = buildDispatch(agentId, runtime, facades);
360
+ const summary = `${outcome}: ${entry.plan.summary}. Tools: ${toolsUsed.join(', ') || 'none'}. Files: ${filesModified.join(', ') || 'none'}.`;
361
+ epilogueResult = await runEpilogue(
362
+ dispatch,
363
+ entry.plan.context.probes,
364
+ entry.plan.context.projectPath,
365
+ summary,
366
+ );
367
+ } catch {
368
+ // Epilogue is best-effort
369
+ }
370
+
371
+ // Clean up plan store
372
+ planStore.delete(planId);
373
+ }
374
+
375
+ return { plan, session, extraction, epilogue: epilogueResult };
175
376
  },
176
377
  },
177
378
 
@@ -180,7 +381,7 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
180
381
  name: 'orchestrate_status',
181
382
  description:
182
383
  'Get combined orchestration status: active plans, brain session context, ' +
183
- 'vault stats, and recent brain recommendations.',
384
+ 'vault stats, recent brain recommendations, and flow plan store.',
184
385
  auth: 'read',
185
386
  schema: z.object({
186
387
  domain: z.string().optional().describe('Filter recommendations by domain'),
@@ -193,22 +394,13 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
193
394
  const domain = params.domain as string | undefined;
194
395
  const sessionLimit = (params.sessionLimit as number) ?? 5;
195
396
 
196
- // Active plans
197
397
  const activePlans = planner.getActive();
198
-
199
- // Brain session context
200
398
  const sessionContext = brainIntelligence.getSessionContext(sessionLimit);
201
-
202
- // Vault stats
203
399
  const vaultStats = vault.stats();
204
400
 
205
- // Recent recommendations — graceful degradation
206
401
  let recommendations: Array<{ pattern: string; strength: number }> = [];
207
402
  try {
208
- const raw = brainIntelligence.recommend({
209
- domain,
210
- limit: 5,
211
- });
403
+ const raw = brainIntelligence.recommend({ domain, limit: 5 });
212
404
  recommendations = raw.map((r) => ({
213
405
  pattern: r.pattern,
214
406
  strength: r.strength,
@@ -217,15 +409,25 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
217
409
  // No recommendations available
218
410
  }
219
411
 
220
- // Brain intelligence stats
221
412
  const brainStats = brainIntelligence.getStats();
222
413
 
414
+ // Include flow plan store info
415
+ const flowPlans = Array.from(planStore.entries()).map(([id, e]) => ({
416
+ planId: id,
417
+ intent: e.plan.intent,
418
+ flowId: e.plan.flowId,
419
+ stepsCount: e.plan.steps.length,
420
+ hasResult: !!e.executionResult,
421
+ createdAt: e.createdAt,
422
+ }));
423
+
223
424
  return {
224
425
  activePlans,
225
426
  sessionContext,
226
427
  vaultStats,
227
428
  recommendations,
228
429
  brainStats,
430
+ flowPlans,
229
431
  };
230
432
  },
231
433
  },
@@ -255,7 +457,6 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
255
457
  const filesModified = (params.filesModified as string[]) ?? [];
256
458
  const outcome = (params.outcome as string) ?? 'completed';
257
459
 
258
- // Start session
259
460
  const startedSession = brainIntelligence.lifecycle({
260
461
  action: 'start',
261
462
  domain,
@@ -264,7 +465,6 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
264
465
  filesModified,
265
466
  });
266
467
 
267
- // End session immediately with outcome
268
468
  const endedSession = brainIntelligence.lifecycle({
269
469
  action: 'end',
270
470
  sessionId: startedSession.id,
@@ -273,18 +473,14 @@ export function createOrchestrateOps(runtime: AgentRuntime): OpDefinition[] {
273
473
  planOutcome: outcome,
274
474
  });
275
475
 
276
- // Extract knowledge — graceful if nothing to extract
277
476
  let extraction = null;
278
477
  try {
279
478
  extraction = brainIntelligence.extractKnowledge(startedSession.id);
280
479
  } catch {
281
- // Not enough signal — that's fine
480
+ // Not enough signal
282
481
  }
283
482
 
284
- return {
285
- session: endedSession,
286
- extraction,
287
- };
483
+ return { session: endedSession, extraction };
288
484
  },
289
485
  },
290
486
  ];