@soleri/core 9.11.0 → 9.12.1

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 (228) hide show
  1. package/dist/adapters/types.d.ts +2 -0
  2. package/dist/adapters/types.d.ts.map +1 -1
  3. package/dist/brain/brain.d.ts +5 -1
  4. package/dist/brain/brain.d.ts.map +1 -1
  5. package/dist/brain/brain.js +97 -10
  6. package/dist/brain/brain.js.map +1 -1
  7. package/dist/dream/cron-manager.d.ts +10 -0
  8. package/dist/dream/cron-manager.d.ts.map +1 -0
  9. package/dist/dream/cron-manager.js +122 -0
  10. package/dist/dream/cron-manager.js.map +1 -0
  11. package/dist/dream/dream-engine.d.ts +34 -0
  12. package/dist/dream/dream-engine.d.ts.map +1 -0
  13. package/dist/dream/dream-engine.js +88 -0
  14. package/dist/dream/dream-engine.js.map +1 -0
  15. package/dist/dream/dream-ops.d.ts +8 -0
  16. package/dist/dream/dream-ops.d.ts.map +1 -0
  17. package/dist/dream/dream-ops.js +49 -0
  18. package/dist/dream/dream-ops.js.map +1 -0
  19. package/dist/dream/index.d.ts +7 -0
  20. package/dist/dream/index.d.ts.map +1 -0
  21. package/dist/dream/index.js +5 -0
  22. package/dist/dream/index.js.map +1 -0
  23. package/dist/dream/schema.d.ts +3 -0
  24. package/dist/dream/schema.d.ts.map +1 -0
  25. package/dist/dream/schema.js +16 -0
  26. package/dist/dream/schema.js.map +1 -0
  27. package/dist/embeddings/index.d.ts +5 -0
  28. package/dist/embeddings/index.d.ts.map +1 -0
  29. package/dist/embeddings/index.js +3 -0
  30. package/dist/embeddings/index.js.map +1 -0
  31. package/dist/embeddings/openai-provider.d.ts +31 -0
  32. package/dist/embeddings/openai-provider.d.ts.map +1 -0
  33. package/dist/embeddings/openai-provider.js +120 -0
  34. package/dist/embeddings/openai-provider.js.map +1 -0
  35. package/dist/embeddings/pipeline.d.ts +36 -0
  36. package/dist/embeddings/pipeline.d.ts.map +1 -0
  37. package/dist/embeddings/pipeline.js +78 -0
  38. package/dist/embeddings/pipeline.js.map +1 -0
  39. package/dist/embeddings/types.d.ts +62 -0
  40. package/dist/embeddings/types.d.ts.map +1 -0
  41. package/dist/embeddings/types.js +3 -0
  42. package/dist/embeddings/types.js.map +1 -0
  43. package/dist/engine/bin/soleri-engine.js +4 -1
  44. package/dist/engine/bin/soleri-engine.js.map +1 -1
  45. package/dist/engine/module-manifest.d.ts.map +1 -1
  46. package/dist/engine/module-manifest.js +20 -0
  47. package/dist/engine/module-manifest.js.map +1 -1
  48. package/dist/engine/register-engine.d.ts.map +1 -1
  49. package/dist/engine/register-engine.js +12 -0
  50. package/dist/engine/register-engine.js.map +1 -1
  51. package/dist/flows/chain-types.d.ts +8 -8
  52. package/dist/flows/dispatch-registry.d.ts +15 -1
  53. package/dist/flows/dispatch-registry.d.ts.map +1 -1
  54. package/dist/flows/dispatch-registry.js +28 -1
  55. package/dist/flows/dispatch-registry.js.map +1 -1
  56. package/dist/flows/executor.d.ts +20 -2
  57. package/dist/flows/executor.d.ts.map +1 -1
  58. package/dist/flows/executor.js +79 -1
  59. package/dist/flows/executor.js.map +1 -1
  60. package/dist/flows/index.d.ts +2 -1
  61. package/dist/flows/index.d.ts.map +1 -1
  62. package/dist/flows/index.js.map +1 -1
  63. package/dist/flows/types.d.ts +43 -21
  64. package/dist/flows/types.d.ts.map +1 -1
  65. package/dist/index.d.ts +5 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +3 -0
  68. package/dist/index.js.map +1 -1
  69. package/dist/plugins/types.d.ts +31 -31
  70. package/dist/runtime/admin-ops.d.ts.map +1 -1
  71. package/dist/runtime/admin-ops.js +15 -0
  72. package/dist/runtime/admin-ops.js.map +1 -1
  73. package/dist/runtime/admin-setup-ops.js +2 -2
  74. package/dist/runtime/admin-setup-ops.js.map +1 -1
  75. package/dist/runtime/embedding-ops.d.ts +12 -0
  76. package/dist/runtime/embedding-ops.d.ts.map +1 -0
  77. package/dist/runtime/embedding-ops.js +96 -0
  78. package/dist/runtime/embedding-ops.js.map +1 -0
  79. package/dist/runtime/facades/embedding-facade.d.ts +7 -0
  80. package/dist/runtime/facades/embedding-facade.d.ts.map +1 -0
  81. package/dist/runtime/facades/embedding-facade.js +8 -0
  82. package/dist/runtime/facades/embedding-facade.js.map +1 -0
  83. package/dist/runtime/facades/index.d.ts.map +1 -1
  84. package/dist/runtime/facades/index.js +12 -0
  85. package/dist/runtime/facades/index.js.map +1 -1
  86. package/dist/runtime/facades/orchestrate-facade.d.ts.map +1 -1
  87. package/dist/runtime/facades/orchestrate-facade.js +120 -0
  88. package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
  89. package/dist/runtime/feature-flags.d.ts.map +1 -1
  90. package/dist/runtime/feature-flags.js +4 -0
  91. package/dist/runtime/feature-flags.js.map +1 -1
  92. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  93. package/dist/runtime/orchestrate-ops.js +140 -9
  94. package/dist/runtime/orchestrate-ops.js.map +1 -1
  95. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  96. package/dist/runtime/planning-extra-ops.js +51 -0
  97. package/dist/runtime/planning-extra-ops.js.map +1 -1
  98. package/dist/runtime/preflight.d.ts +32 -0
  99. package/dist/runtime/preflight.d.ts.map +1 -0
  100. package/dist/runtime/preflight.js +29 -0
  101. package/dist/runtime/preflight.js.map +1 -0
  102. package/dist/runtime/runtime.d.ts.map +1 -1
  103. package/dist/runtime/runtime.js +33 -2
  104. package/dist/runtime/runtime.js.map +1 -1
  105. package/dist/runtime/types.d.ts +27 -0
  106. package/dist/runtime/types.d.ts.map +1 -1
  107. package/dist/skills/step-tracker.d.ts +39 -0
  108. package/dist/skills/step-tracker.d.ts.map +1 -0
  109. package/dist/skills/step-tracker.js +105 -0
  110. package/dist/skills/step-tracker.js.map +1 -0
  111. package/dist/skills/sync-skills.d.ts +3 -2
  112. package/dist/skills/sync-skills.d.ts.map +1 -1
  113. package/dist/skills/sync-skills.js +42 -8
  114. package/dist/skills/sync-skills.js.map +1 -1
  115. package/dist/subagent/dispatcher.d.ts +4 -3
  116. package/dist/subagent/dispatcher.d.ts.map +1 -1
  117. package/dist/subagent/dispatcher.js +57 -35
  118. package/dist/subagent/dispatcher.js.map +1 -1
  119. package/dist/subagent/index.d.ts +1 -0
  120. package/dist/subagent/index.d.ts.map +1 -1
  121. package/dist/subagent/index.js.map +1 -1
  122. package/dist/subagent/orphan-reaper.d.ts +51 -4
  123. package/dist/subagent/orphan-reaper.d.ts.map +1 -1
  124. package/dist/subagent/orphan-reaper.js +103 -3
  125. package/dist/subagent/orphan-reaper.js.map +1 -1
  126. package/dist/subagent/types.d.ts +7 -0
  127. package/dist/subagent/types.d.ts.map +1 -1
  128. package/dist/subagent/workspace-resolver.d.ts +2 -0
  129. package/dist/subagent/workspace-resolver.d.ts.map +1 -1
  130. package/dist/subagent/workspace-resolver.js +3 -1
  131. package/dist/subagent/workspace-resolver.js.map +1 -1
  132. package/dist/vault/vault-entries.d.ts +18 -0
  133. package/dist/vault/vault-entries.d.ts.map +1 -1
  134. package/dist/vault/vault-entries.js +73 -0
  135. package/dist/vault/vault-entries.js.map +1 -1
  136. package/dist/vault/vault-manager.d.ts.map +1 -1
  137. package/dist/vault/vault-manager.js +1 -0
  138. package/dist/vault/vault-manager.js.map +1 -1
  139. package/dist/vault/vault-schema.d.ts.map +1 -1
  140. package/dist/vault/vault-schema.js +14 -0
  141. package/dist/vault/vault-schema.js.map +1 -1
  142. package/dist/vault/vault.d.ts +1 -0
  143. package/dist/vault/vault.d.ts.map +1 -1
  144. package/dist/vault/vault.js.map +1 -1
  145. package/package.json +3 -5
  146. package/src/__tests__/cron-manager.test.ts +132 -0
  147. package/src/__tests__/deviation-detection.test.ts +234 -0
  148. package/src/__tests__/embeddings.test.ts +536 -0
  149. package/src/__tests__/preflight.test.ts +97 -0
  150. package/src/__tests__/step-persistence.test.ts +324 -0
  151. package/src/__tests__/step-tracker.test.ts +260 -0
  152. package/src/__tests__/subagent/dispatcher.test.ts +122 -4
  153. package/src/__tests__/subagent/orphan-reaper.test.ts +148 -12
  154. package/src/__tests__/subagent/process-lifecycle.test.ts +422 -0
  155. package/src/__tests__/subagent/workspace-resolver.test.ts +6 -1
  156. package/src/adapters/types.ts +2 -0
  157. package/src/brain/brain.ts +117 -9
  158. package/src/dream/cron-manager.ts +137 -0
  159. package/src/dream/dream-engine.ts +119 -0
  160. package/src/dream/dream-ops.ts +56 -0
  161. package/src/dream/dream.test.ts +182 -0
  162. package/src/dream/index.ts +6 -0
  163. package/src/dream/schema.ts +17 -0
  164. package/src/embeddings/openai-provider.ts +158 -0
  165. package/src/embeddings/pipeline.ts +126 -0
  166. package/src/embeddings/types.ts +67 -0
  167. package/src/engine/bin/soleri-engine.ts +4 -1
  168. package/src/engine/module-manifest.test.ts +4 -4
  169. package/src/engine/module-manifest.ts +20 -0
  170. package/src/engine/register-engine.ts +12 -0
  171. package/src/flows/dispatch-registry.ts +44 -1
  172. package/src/flows/executor.ts +93 -2
  173. package/src/flows/index.ts +2 -0
  174. package/src/flows/types.ts +39 -1
  175. package/src/index.ts +11 -0
  176. package/src/planning/goal-ancestry.test.ts +3 -5
  177. package/src/planning/planner.test.ts +2 -3
  178. package/src/runtime/admin-ops.test.ts +2 -2
  179. package/src/runtime/admin-ops.ts +17 -0
  180. package/src/runtime/admin-setup-ops.ts +2 -2
  181. package/src/runtime/embedding-ops.ts +116 -0
  182. package/src/runtime/facades/admin-facade.test.ts +31 -0
  183. package/src/runtime/facades/embedding-facade.ts +11 -0
  184. package/src/runtime/facades/index.ts +12 -0
  185. package/src/runtime/facades/orchestrate-facade.test.ts +16 -0
  186. package/src/runtime/facades/orchestrate-facade.ts +146 -0
  187. package/src/runtime/feature-flags.ts +4 -0
  188. package/src/runtime/orchestrate-ops.test.ts +131 -0
  189. package/src/runtime/orchestrate-ops.ts +158 -10
  190. package/src/runtime/planning-extra-ops.ts +77 -0
  191. package/src/runtime/preflight.ts +53 -0
  192. package/src/runtime/runtime.ts +41 -2
  193. package/src/runtime/types.ts +20 -0
  194. package/src/skills/__tests__/sync-skills.test.ts +132 -0
  195. package/src/skills/step-tracker.ts +162 -0
  196. package/src/skills/sync-skills.ts +54 -9
  197. package/src/subagent/dispatcher.ts +62 -39
  198. package/src/subagent/index.ts +1 -0
  199. package/src/subagent/orphan-reaper.test.ts +135 -0
  200. package/src/subagent/orphan-reaper.ts +130 -7
  201. package/src/subagent/types.ts +10 -0
  202. package/src/subagent/workspace-resolver.ts +3 -1
  203. package/src/vault/vault-entries.ts +112 -0
  204. package/src/vault/vault-manager.ts +1 -0
  205. package/src/vault/vault-scaling.test.ts +3 -2
  206. package/src/vault/vault-schema.ts +15 -0
  207. package/src/vault/vault.ts +1 -0
  208. package/vitest.config.ts +2 -1
  209. package/dist/brain/strength-scorer.d.ts +0 -31
  210. package/dist/brain/strength-scorer.d.ts.map +0 -1
  211. package/dist/brain/strength-scorer.js +0 -264
  212. package/dist/brain/strength-scorer.js.map +0 -1
  213. package/dist/engine/index.d.ts +0 -21
  214. package/dist/engine/index.d.ts.map +0 -1
  215. package/dist/engine/index.js +0 -18
  216. package/dist/engine/index.js.map +0 -1
  217. package/dist/hooks/index.d.ts +0 -2
  218. package/dist/hooks/index.d.ts.map +0 -1
  219. package/dist/hooks/index.js +0 -2
  220. package/dist/hooks/index.js.map +0 -1
  221. package/dist/persona/index.d.ts +0 -5
  222. package/dist/persona/index.d.ts.map +0 -1
  223. package/dist/persona/index.js +0 -4
  224. package/dist/persona/index.js.map +0 -1
  225. package/dist/vault/vault-interfaces.d.ts +0 -153
  226. package/dist/vault/vault-interfaces.d.ts.map +0 -1
  227. package/dist/vault/vault-interfaces.js +0 -2
  228. package/dist/vault/vault-interfaces.js.map +0 -1
@@ -277,6 +277,23 @@ export function createAdminOps(runtime: AgentRuntime): OpDefinition[] {
277
277
  },
278
278
  },
279
279
 
280
+ // ─── Subagent Orphan Reaping ────────────────────────────────────
281
+ {
282
+ name: 'admin_reap_orphans',
283
+ description:
284
+ 'Detect and clean up orphaned subagent processes. Returns reaped PIDs and task IDs.',
285
+ auth: 'admin',
286
+ handler: async () => {
287
+ const dispatcher = runtime.subagentDispatcher;
288
+ const results = dispatcher.reapOrphans();
289
+ return {
290
+ reaped: results.reaped.length,
291
+ tasks: results.reaped,
292
+ alive: results.alive,
293
+ };
294
+ },
295
+ },
296
+
280
297
  // ─── Diagnostics ─────────────────────────────────────────────────
281
298
  {
282
299
  name: 'admin_diagnostic',
@@ -352,7 +352,7 @@ export function createAdminSetupOps(runtime: AgentRuntime): OpDefinition[] {
352
352
  {
353
353
  name: 'admin_setup_global',
354
354
  description:
355
- 'Install global agent configuration — hookify rules to ~/.claude/, skills to ~/.claude/commands/, lifecycle hooks to settings.json. Dry-run by default.',
355
+ 'Install global agent configuration — hookify rules to ~/.claude/, skills to ~/.claude/skills/, lifecycle hooks to settings.json. Dry-run by default.',
356
356
  auth: 'admin',
357
357
  schema: z.object({
358
358
  install: z.boolean().describe('Set true to install, false for dry-run preview'),
@@ -370,7 +370,7 @@ export function createAdminSetupOps(runtime: AgentRuntime): OpDefinition[] {
370
370
  .boolean()
371
371
  .optional()
372
372
  .default(false)
373
- .describe('Only install skills to ~/.claude/commands/'),
373
+ .describe('Only install skills to ~/.claude/skills/'),
374
374
  }),
375
375
  handler: async (params) => {
376
376
  const install = params.install as boolean;
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Embedding Ops — embed_status, embed_rebuild, embed_entry.
3
+ *
4
+ * Covers:
5
+ * - Embedding statistics and health
6
+ * - Batch rebuild of missing vectors
7
+ * - Single-entry embedding
8
+ */
9
+
10
+ import { z } from 'zod';
11
+ import type { OpDefinition } from '../facades/types.js';
12
+ import type { AgentRuntime } from './types.js';
13
+ import { getEntriesWithoutVectors } from '../vault/vault-entries.js';
14
+
15
+ export function createEmbeddingOps(runtime: AgentRuntime): OpDefinition[] {
16
+ const { vault, flags, embeddingProvider, embeddingPipeline } = runtime;
17
+
18
+ return [
19
+ {
20
+ name: 'embed_status',
21
+ description:
22
+ 'Get embedding subsystem status — provider info, vector counts, token usage. Returns { enabled: false } when embeddings are not configured.',
23
+ auth: 'read' as const,
24
+ handler: async () => {
25
+ if (!embeddingProvider || !flags.isEnabled('embedding-enabled')) {
26
+ return {
27
+ enabled: false,
28
+ reason: !flags.isEnabled('embedding-enabled')
29
+ ? 'feature flag embedding-enabled is off'
30
+ : 'no embedding config',
31
+ };
32
+ }
33
+
34
+ const persistence = vault.getProvider();
35
+ const model = embeddingProvider.model;
36
+ const missingIds = getEntriesWithoutVectors(persistence, model);
37
+
38
+ const embeddedRow = persistence.get<{ count: number }>(
39
+ 'SELECT COUNT(*) as count FROM entry_vectors WHERE model = ?',
40
+ [model],
41
+ );
42
+ const totalEmbedded = embeddedRow?.count ?? 0;
43
+
44
+ const tokensRow = persistence.get<{ total: number }>(
45
+ `SELECT COALESCE(SUM(1), 0) as total FROM entry_vectors`,
46
+ [],
47
+ );
48
+
49
+ return {
50
+ enabled: true,
51
+ provider: embeddingProvider.providerName,
52
+ model: embeddingProvider.model,
53
+ dimensions: embeddingProvider.dimensions,
54
+ totalEmbedded,
55
+ totalMissing: missingIds.length,
56
+ // Token tracking is per-call in pipeline — we report what we can from the DB
57
+ totalTokensUsed: tokensRow?.total ?? 0,
58
+ };
59
+ },
60
+ },
61
+ {
62
+ name: 'embed_rebuild',
63
+ description:
64
+ 'Trigger batch embedding of all vault entries missing vectors. Returns counts of embedded, skipped, failed entries and tokens used.',
65
+ auth: 'write' as const,
66
+ handler: async () => {
67
+ if (!embeddingPipeline || !flags.isEnabled('embedding-enabled')) {
68
+ return {
69
+ enabled: false,
70
+ reason: !flags.isEnabled('embedding-enabled')
71
+ ? 'feature flag embedding-enabled is off'
72
+ : 'no embedding pipeline configured',
73
+ };
74
+ }
75
+
76
+ const result = await embeddingPipeline.batchEmbed();
77
+ return {
78
+ enabled: true,
79
+ embedded: result.embedded,
80
+ skipped: result.skipped,
81
+ failed: result.failed,
82
+ tokensUsed: result.tokensUsed,
83
+ };
84
+ },
85
+ },
86
+ {
87
+ name: 'embed_entry',
88
+ description:
89
+ 'Embed a single vault entry by ID. Returns { embedded: true } if a new vector was created, { embedded: false } if already up to date.',
90
+ auth: 'write' as const,
91
+ schema: z.object({
92
+ entryId: z.string().describe('Vault entry ID to embed'),
93
+ }),
94
+ handler: async (params) => {
95
+ if (!embeddingPipeline || !flags.isEnabled('embedding-enabled')) {
96
+ return {
97
+ enabled: false,
98
+ reason: !flags.isEnabled('embedding-enabled')
99
+ ? 'feature flag embedding-enabled is off'
100
+ : 'no embedding pipeline configured',
101
+ };
102
+ }
103
+
104
+ const entryId = params.entryId as string;
105
+ const entry = vault.get(entryId);
106
+ if (!entry) {
107
+ return { embedded: false, error: `Entry "${entryId}" not found` };
108
+ }
109
+
110
+ const text = [entry.title, entry.description, entry.context].filter(Boolean).join('\n');
111
+ const embedded = await embeddingPipeline.embedEntry(entryId, text);
112
+ return { embedded };
113
+ },
114
+ },
115
+ ];
116
+ }
@@ -85,6 +85,9 @@ function mockRuntime(): AgentRuntime {
85
85
  get: vi.fn(),
86
86
  },
87
87
  packInstaller: { list: vi.fn(() => []) },
88
+ subagentDispatcher: {
89
+ reapOrphans: vi.fn().mockReturnValue({ reaped: [], alive: [] }),
90
+ },
88
91
  createdAt: Date.now() - 60000,
89
92
  persona: { name: 'TestAgent' },
90
93
  } as unknown as AgentRuntime;
@@ -327,4 +330,32 @@ describe('createAdminFacadeOps', () => {
327
330
  expect(result).toEqual({});
328
331
  });
329
332
  });
333
+
334
+ describe('admin_reap_orphans (from satellite)', () => {
335
+ it('returns empty when no orphans', async () => {
336
+ const result = (await findOp(ops, 'admin_reap_orphans').handler({})) as Record<
337
+ string,
338
+ unknown
339
+ >;
340
+ expect(result.reaped).toBe(0);
341
+ expect(result.tasks).toEqual([]);
342
+ expect(result.alive).toEqual([]);
343
+ });
344
+
345
+ it('returns reaped orphans', async () => {
346
+ vi.mocked(runtime.subagentDispatcher.reapOrphans).mockReturnValue({
347
+ reaped: ['task-1', 'task-2'],
348
+ alive: ['task-3'],
349
+ });
350
+ ops = createAdminFacadeOps(runtime);
351
+
352
+ const result = (await findOp(ops, 'admin_reap_orphans').handler({})) as Record<
353
+ string,
354
+ unknown
355
+ >;
356
+ expect(result.reaped).toBe(2);
357
+ expect(result.tasks).toEqual(['task-1', 'task-2']);
358
+ expect(result.alive).toEqual(['task-3']);
359
+ });
360
+ });
330
361
  });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Embedding facade — vector embedding management ops.
3
+ */
4
+
5
+ import type { OpDefinition } from '../../facades/types.js';
6
+ import type { AgentRuntime } from '../types.js';
7
+ import { createEmbeddingOps } from '../embedding-ops.js';
8
+
9
+ export function createEmbeddingFacadeOps(runtime: AgentRuntime): OpDefinition[] {
10
+ return [...createEmbeddingOps(runtime)];
11
+ }
@@ -27,6 +27,8 @@ import { createIntakeFacadeOps } from './intake-facade.js';
27
27
  import { createLinksFacadeOps } from './links-facade.js';
28
28
  import { createBranchingFacadeOps } from './branching-facade.js';
29
29
  import { createTierFacadeOps } from './tier-facade.js';
30
+ import { createEmbeddingFacadeOps } from './embedding-facade.js';
31
+ import { createDreamOps } from '../../dream/dream-ops.js';
30
32
 
31
33
  export function createSemanticFacades(runtime: AgentRuntime, agentId: string): FacadeConfig[] {
32
34
  const facades: FacadeConfig[] = [
@@ -128,11 +130,21 @@ export function createSemanticFacades(runtime: AgentRuntime, agentId: string): F
128
130
  description: 'Vault branching — create, list, merge, delete branches.',
129
131
  ops: createBranchingFacadeOps(runtime),
130
132
  },
133
+ {
134
+ name: `${agentId}_embedding`,
135
+ description: 'Embedding management — status, batch rebuild, single-entry embedding.',
136
+ ops: createEmbeddingFacadeOps(runtime),
137
+ },
131
138
  {
132
139
  name: `${agentId}_tier`,
133
140
  description: 'Multi-vault tiers — connect, disconnect, search across sources.',
134
141
  ops: createTierFacadeOps(runtime),
135
142
  },
143
+ {
144
+ name: `${agentId}_dream`,
145
+ description: 'Dream — automatic memory consolidation, vault cleanup, and maintenance.',
146
+ ops: createDreamOps(runtime),
147
+ },
136
148
  ];
137
149
 
138
150
  return facades;
@@ -95,6 +95,22 @@ describe('orchestrate-facade', () => {
95
95
  expect(data.governance).toBeDefined();
96
96
  });
97
97
 
98
+ it('session_start includes preflight manifest', async () => {
99
+ const result = await executeOp(ops, 'session_start', { projectPath: '/test/proj' });
100
+ expect(result.success).toBe(true);
101
+ const data = result.data as Record<string, unknown>;
102
+ const preflight = data.preflight as Record<string, unknown>;
103
+ expect(preflight).toBeDefined();
104
+ expect(Array.isArray(preflight.tools)).toBe(true);
105
+ expect(Array.isArray(preflight.skills)).toBe(true);
106
+ expect(Array.isArray(preflight.activePlans)).toBe(true);
107
+ expect(preflight.vaultSummary).toBeDefined();
108
+ const vaultSummary = preflight.vaultSummary as Record<string, unknown>;
109
+ expect(typeof vaultSummary.entryCount).toBe('number');
110
+ expect(typeof vaultSummary.connected).toBe('boolean');
111
+ expect(Array.isArray(vaultSummary.domains)).toBe(true);
112
+ });
113
+
98
114
  it('session_start increments session count on second call', async () => {
99
115
  await executeOp(ops, 'session_start', { projectPath: '/test/proj' });
100
116
  const result = await executeOp(ops, 'session_start', { projectPath: '/test/proj' });
@@ -10,6 +10,18 @@ import { createOrchestrateOps } from '../orchestrate-ops.js';
10
10
  import { createProjectOps } from '../project-ops.js';
11
11
  import { createPlaybookOps } from '../playbook-ops.js';
12
12
  import { checkForUpdate } from '../../update-check.js';
13
+ import { buildPreflightManifest } from '../preflight.js';
14
+ import { ENGINE_MODULE_MANIFEST } from '../../engine/module-manifest.js';
15
+ import {
16
+ createTracker,
17
+ advanceStep,
18
+ recordEvidence,
19
+ generateCheckpoint,
20
+ validateCompletion,
21
+ persistTracker,
22
+ loadTracker,
23
+ } from '../../skills/step-tracker.js';
24
+ import type { SkillStep, EvidenceType } from '../../skills/step-tracker.js';
13
25
 
14
26
  export function createOrchestrateFacadeOps(runtime: AgentRuntime): OpDefinition[] {
15
27
  const { vault, governance, projectRegistry } = runtime;
@@ -85,6 +97,59 @@ export function createOrchestrateFacadeOps(runtime: AgentRuntime): OpDefinition[
85
97
  // package.json not readable — skip update check silently
86
98
  }
87
99
 
100
+ // Auto-dream: increment session counter and check gate
101
+ let dreamInfo: { status: unknown; gate: { eligible: boolean; reason: string } } | null =
102
+ null;
103
+ try {
104
+ const { ensureDreamSchema } = await import('../../dream/schema.js');
105
+ const { DreamEngine } = await import('../../dream/dream-engine.js');
106
+ ensureDreamSchema(runtime.vault.getProvider());
107
+ const dreamEngine = new DreamEngine(runtime.vault, runtime.curator);
108
+ dreamEngine.incrementSessionCount();
109
+ const gate = dreamEngine.checkGate();
110
+ dreamInfo = { status: dreamEngine.getStatus(), gate };
111
+ if (gate.eligible) {
112
+ // Fire-and-forget: don't block session_start
113
+ Promise.resolve()
114
+ .then(() => dreamEngine.run())
115
+ .catch(() => {
116
+ /* best-effort */
117
+ });
118
+ }
119
+ } catch {
120
+ /* dream module not available — skip silently */
121
+ }
122
+
123
+ // ─── Pre-flight manifest ───────────────────────────────
124
+ let skills: string[] = [];
125
+ try {
126
+ const { discoverSkills } = await import('../../skills/sync-skills.js');
127
+ const agentDir = runtime.config.agentDir;
128
+ const skillsDirs = agentDir ? [join(agentDir, 'skills')] : [];
129
+ skills = discoverSkills(skillsDirs).map((s) => s.name);
130
+ } catch {
131
+ // Skills discovery is best-effort
132
+ }
133
+
134
+ const agentId = runtime.config.agentId;
135
+ const facades = ENGINE_MODULE_MANIFEST.map((m) => ({
136
+ name: `${agentId}_${m.suffix}`,
137
+ ops: m.keyOps.map((op) => ({ name: op, description: m.description })),
138
+ }));
139
+
140
+ const executingPlans = runtime.planner.getExecuting().map((p) => ({
141
+ id: p.id,
142
+ objective: p.objective,
143
+ status: p.status,
144
+ }));
145
+
146
+ const preflight = buildPreflightManifest({
147
+ facades,
148
+ skills,
149
+ executingPlans,
150
+ vaultStats: stats,
151
+ });
152
+
88
153
  return {
89
154
  project,
90
155
  is_new: isNew,
@@ -101,11 +166,92 @@ export function createOrchestrateFacadeOps(runtime: AgentRuntime): OpDefinition[
101
166
  isQuotaWarning: quotaStatus.isWarning,
102
167
  expiredThisSession: expired,
103
168
  },
169
+ preflight,
104
170
  ...(stagingWarning ? { stagingWarning } : {}),
171
+ ...(dreamInfo ? { dream: dreamInfo } : {}),
105
172
  };
106
173
  },
107
174
  },
108
175
 
176
+ // ─── Skill Step Tracking ──────────────────────────────────────
177
+ {
178
+ name: 'skill_step_start',
179
+ description:
180
+ 'Create a skill step tracker. Persists initial state to disk and returns the tracker with checkpoint summary.',
181
+ auth: 'write',
182
+ schema: z.object({
183
+ skillName: z.string().describe('Name of the skill being tracked'),
184
+ steps: z
185
+ .array(
186
+ z.object({
187
+ id: z.string(),
188
+ description: z.string(),
189
+ evidence: z.enum(['tool_called', 'file_exists']),
190
+ }),
191
+ )
192
+ .describe('Ordered steps with evidence requirements'),
193
+ }),
194
+ handler: async (params) => {
195
+ const steps = (
196
+ params.steps as Array<{ id: string; description: string; evidence: EvidenceType }>
197
+ ).map((s): SkillStep => ({ id: s.id, description: s.description, evidence: s.evidence }));
198
+ const tracker = createTracker(params.skillName as string, steps);
199
+ const filePath = persistTracker(tracker);
200
+ const checkpoint = generateCheckpoint(tracker);
201
+ return { tracker, filePath, checkpoint };
202
+ },
203
+ },
204
+ {
205
+ name: 'skill_step_advance',
206
+ description:
207
+ 'Record evidence for the current step, advance to the next step, persist state, and return checkpoint summary.',
208
+ auth: 'write',
209
+ schema: z.object({
210
+ runId: z.string().describe('Run ID returned by skill_step_start'),
211
+ stepId: z.string().describe('Step ID to record evidence for'),
212
+ evidence: z.string().describe('Evidence value (tool name or file path)'),
213
+ verified: z.boolean().optional().default(true).describe('Whether evidence is verified'),
214
+ }),
215
+ handler: async (params) => {
216
+ let tracker = loadTracker(params.runId as string);
217
+ if (!tracker) {
218
+ return { error: `No tracker found for runId: ${params.runId}` };
219
+ }
220
+ tracker = recordEvidence(
221
+ tracker,
222
+ params.stepId as string,
223
+ params.evidence as string,
224
+ (params.verified as boolean) ?? true,
225
+ );
226
+ tracker = advanceStep(tracker);
227
+ const filePath = persistTracker(tracker);
228
+ const checkpoint = generateCheckpoint(tracker);
229
+ return { tracker, filePath, checkpoint };
230
+ },
231
+ },
232
+ {
233
+ name: 'skill_step_complete',
234
+ description:
235
+ 'Validate skill completion, persist final state, and return a completion result with any skipped steps.',
236
+ auth: 'write',
237
+ schema: z.object({
238
+ runId: z.string().describe('Run ID returned by skill_step_start'),
239
+ }),
240
+ handler: async (params) => {
241
+ const tracker = loadTracker(params.runId as string);
242
+ if (!tracker) {
243
+ return { error: `No tracker found for runId: ${params.runId}` };
244
+ }
245
+ const result = validateCompletion(tracker);
246
+ // Mark completed if all steps have evidence
247
+ const finalTracker = result.complete
248
+ ? { ...tracker, completedAt: tracker.completedAt ?? new Date().toISOString() }
249
+ : tracker;
250
+ const filePath = persistTracker(finalTracker);
251
+ return { result, tracker: finalTracker, filePath };
252
+ },
253
+ },
254
+
109
255
  // ─── Satellite ops ───────────────────────────────────────────
110
256
  ...createOrchestrateOps(runtime),
111
257
  ...createProjectOps(runtime),
@@ -23,6 +23,10 @@ const BUILT_IN_FLAGS: Record<string, FlagDefinition> = {
23
23
  description: 'Sync vault entries to Cognee knowledge graph',
24
24
  defaultValue: true,
25
25
  },
26
+ 'embedding-enabled': {
27
+ description: 'Enable vector embedding provider for hybrid search',
28
+ defaultValue: false,
29
+ },
26
30
  };
27
31
 
28
32
  export class FeatureFlags {
@@ -245,6 +245,137 @@ describe('createOrchestrateOps', () => {
245
245
  expect(rt.contextHealth.track).toHaveBeenCalled();
246
246
  expect(rt.contextHealth.check).toHaveBeenCalled();
247
247
  });
248
+
249
+ // ─── Post-dispatch cleanup (subagent path) ─────────────────
250
+ describe('post-dispatch cleanup', () => {
251
+ function addSubagentDispatcher(
252
+ runtime: AgentRuntime,
253
+ opts: {
254
+ dispatchResult?: Record<string, unknown>;
255
+ dispatchError?: Error;
256
+ reapResult?: string[];
257
+ reapThrows?: boolean;
258
+ } = {},
259
+ ) {
260
+ const dispatchMock = opts.dispatchError
261
+ ? vi.fn().mockRejectedValue(opts.dispatchError)
262
+ : vi.fn().mockResolvedValue(
263
+ opts.dispatchResult ?? {
264
+ status: 'completed',
265
+ totalTasks: 1,
266
+ completed: 1,
267
+ failed: 0,
268
+ durationMs: 100,
269
+ totalUsage: {},
270
+ },
271
+ );
272
+ const reapMock = opts.reapThrows
273
+ ? vi.fn().mockImplementation(() => {
274
+ throw new Error('reap failed');
275
+ })
276
+ : vi.fn().mockReturnValue({
277
+ reaped: opts.reapResult ?? [],
278
+ alive: [],
279
+ });
280
+ const cleanupMock = vi.fn();
281
+
282
+ (runtime as Record<string, unknown>).subagentDispatcher = {
283
+ dispatch: dispatchMock,
284
+ reapOrphans: reapMock,
285
+ cleanup: cleanupMock,
286
+ };
287
+
288
+ return { dispatchMock, reapMock, cleanupMock };
289
+ }
290
+
291
+ it('calls reapOrphans after successful subagent dispatch', async () => {
292
+ const { reapMock } = addSubagentDispatcher(rt);
293
+ ops = createOrchestrateOps(rt);
294
+
295
+ const op = findOp(ops, 'orchestrate_execute');
296
+ await op.handler({ planId: 'legacy-plan', subagent: true });
297
+
298
+ expect(reapMock).toHaveBeenCalledTimes(1);
299
+ });
300
+
301
+ it('calls reapOrphans even when dispatch fails', async () => {
302
+ const { reapMock } = addSubagentDispatcher(rt, {
303
+ dispatchError: new Error('dispatch boom'),
304
+ });
305
+ ops = createOrchestrateOps(rt);
306
+
307
+ const op = findOp(ops, 'orchestrate_execute');
308
+ await expect(op.handler({ planId: 'legacy-plan', subagent: true })).rejects.toThrow(
309
+ 'dispatch boom',
310
+ );
311
+
312
+ expect(reapMock).toHaveBeenCalledTimes(1);
313
+ });
314
+
315
+ it('includes reapedOrphans in result when orphans found', async () => {
316
+ addSubagentDispatcher(rt, {
317
+ reapResult: ['t1'],
318
+ });
319
+ ops = createOrchestrateOps(rt);
320
+
321
+ const op = findOp(ops, 'orchestrate_execute');
322
+ const result = (await op.handler({
323
+ planId: 'legacy-plan',
324
+ subagent: true,
325
+ })) as Record<string, unknown>;
326
+
327
+ expect(result).toHaveProperty('reapedOrphans');
328
+ const reaped = result.reapedOrphans as Array<{ taskId: string }>;
329
+ expect(reaped).toHaveLength(1);
330
+ expect(reaped[0].taskId).toBe('t1');
331
+ });
332
+
333
+ it('omits reapedOrphans from result when none found', async () => {
334
+ addSubagentDispatcher(rt, { reapResult: [] });
335
+ ops = createOrchestrateOps(rt);
336
+
337
+ const op = findOp(ops, 'orchestrate_execute');
338
+ const result = (await op.handler({
339
+ planId: 'legacy-plan',
340
+ subagent: true,
341
+ })) as Record<string, unknown>;
342
+
343
+ expect(result).not.toHaveProperty('reapedOrphans');
344
+ });
345
+
346
+ it('does not throw when reapOrphans fails', async () => {
347
+ addSubagentDispatcher(rt, { reapThrows: true });
348
+ ops = createOrchestrateOps(rt);
349
+
350
+ const op = findOp(ops, 'orchestrate_execute');
351
+ // Should complete successfully despite reap failure
352
+ const result = (await op.handler({
353
+ planId: 'legacy-plan',
354
+ subagent: true,
355
+ })) as Record<string, unknown>;
356
+
357
+ expect(result).toHaveProperty('subagent');
358
+ expect(result).not.toHaveProperty('reapedOrphans');
359
+ });
360
+
361
+ it('logs reaped orphans to stderr', async () => {
362
+ const stderrSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
363
+ addSubagentDispatcher(rt, {
364
+ reapResult: ['t1', 't2'],
365
+ });
366
+ ops = createOrchestrateOps(rt);
367
+
368
+ const op = findOp(ops, 'orchestrate_execute');
369
+ await op.handler({ planId: 'legacy-plan', subagent: true });
370
+
371
+ expect(stderrSpy).toHaveBeenCalledWith(
372
+ expect.stringContaining('Reaped 2 orphaned subagent(s)'),
373
+ );
374
+ expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('t1'));
375
+ expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('t2'));
376
+ stderrSpy.mockRestore();
377
+ });
378
+ });
248
379
  });
249
380
 
250
381
  // ─── orchestrate_complete ─────────────────────────────────────