@soleri/core 9.14.4 → 9.16.7

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 (355) hide show
  1. package/data/flows/deliver.flow.yaml +11 -0
  2. package/data/flows/design.flow.yaml +4 -14
  3. package/data/flows/enhance.flow.yaml +10 -0
  4. package/data/flows/explore.flow.yaml +16 -0
  5. package/data/flows/fix.flow.yaml +1 -1
  6. package/data/flows/review.flow.yaml +13 -4
  7. package/dist/brain/brain.d.ts +9 -0
  8. package/dist/brain/brain.d.ts.map +1 -1
  9. package/dist/brain/brain.js +11 -1
  10. package/dist/brain/brain.js.map +1 -1
  11. package/dist/brain/intelligence.d.ts.map +1 -1
  12. package/dist/brain/intelligence.js +24 -0
  13. package/dist/brain/intelligence.js.map +1 -1
  14. package/dist/brain/types.d.ts +1 -0
  15. package/dist/brain/types.d.ts.map +1 -1
  16. package/dist/capabilities/chain-mapping.d.ts.map +1 -1
  17. package/dist/capabilities/chain-mapping.js +5 -4
  18. package/dist/capabilities/chain-mapping.js.map +1 -1
  19. package/dist/capabilities/registry.d.ts +6 -0
  20. package/dist/capabilities/registry.d.ts.map +1 -1
  21. package/dist/capabilities/registry.js +3 -2
  22. package/dist/capabilities/registry.js.map +1 -1
  23. package/dist/chat/chat-session.d.ts +6 -0
  24. package/dist/chat/chat-session.d.ts.map +1 -1
  25. package/dist/chat/chat-session.js +68 -17
  26. package/dist/chat/chat-session.js.map +1 -1
  27. package/dist/context/context-engine.js +1 -1
  28. package/dist/context/context-engine.js.map +1 -1
  29. package/dist/curator/curator.d.ts +6 -0
  30. package/dist/curator/curator.d.ts.map +1 -1
  31. package/dist/curator/curator.js +138 -0
  32. package/dist/curator/curator.js.map +1 -1
  33. package/dist/curator/types.d.ts +10 -0
  34. package/dist/curator/types.d.ts.map +1 -1
  35. package/dist/engine/bin/soleri-engine.js +0 -0
  36. package/dist/engine/core-ops.d.ts.map +1 -1
  37. package/dist/engine/core-ops.js +38 -1
  38. package/dist/engine/core-ops.js.map +1 -1
  39. package/dist/flows/epilogue.d.ts +5 -1
  40. package/dist/flows/epilogue.d.ts.map +1 -1
  41. package/dist/flows/epilogue.js +11 -3
  42. package/dist/flows/epilogue.js.map +1 -1
  43. package/dist/flows/executor.d.ts.map +1 -1
  44. package/dist/flows/executor.js +13 -5
  45. package/dist/flows/executor.js.map +1 -1
  46. package/dist/flows/index.d.ts +1 -2
  47. package/dist/flows/index.d.ts.map +1 -1
  48. package/dist/flows/index.js +1 -0
  49. package/dist/flows/index.js.map +1 -1
  50. package/dist/flows/plan-builder.d.ts +17 -1
  51. package/dist/flows/plan-builder.d.ts.map +1 -1
  52. package/dist/flows/plan-builder.js +67 -6
  53. package/dist/flows/plan-builder.js.map +1 -1
  54. package/dist/flows/probes.d.ts +1 -1
  55. package/dist/flows/probes.d.ts.map +1 -1
  56. package/dist/flows/probes.js +15 -3
  57. package/dist/flows/probes.js.map +1 -1
  58. package/dist/flows/types.d.ts +47 -20
  59. package/dist/flows/types.d.ts.map +1 -1
  60. package/dist/flows/types.js +6 -1
  61. package/dist/flows/types.js.map +1 -1
  62. package/dist/index.d.ts +10 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +9 -0
  65. package/dist/index.js.map +1 -1
  66. package/dist/intake/content-classifier.d.ts +10 -4
  67. package/dist/intake/content-classifier.d.ts.map +1 -1
  68. package/dist/intake/content-classifier.js +19 -5
  69. package/dist/intake/content-classifier.js.map +1 -1
  70. package/dist/intake/text-ingester.d.ts +18 -0
  71. package/dist/intake/text-ingester.d.ts.map +1 -1
  72. package/dist/intake/text-ingester.js +37 -13
  73. package/dist/intake/text-ingester.js.map +1 -1
  74. package/dist/packs/pack-installer.d.ts.map +1 -1
  75. package/dist/packs/pack-installer.js +28 -2
  76. package/dist/packs/pack-installer.js.map +1 -1
  77. package/dist/planning/planner-types.d.ts +2 -0
  78. package/dist/planning/planner-types.d.ts.map +1 -1
  79. package/dist/planning/planner.d.ts +4 -0
  80. package/dist/planning/planner.d.ts.map +1 -1
  81. package/dist/planning/planner.js +50 -4
  82. package/dist/planning/planner.js.map +1 -1
  83. package/dist/playbooks/playbook-executor.d.ts +10 -1
  84. package/dist/playbooks/playbook-executor.d.ts.map +1 -1
  85. package/dist/playbooks/playbook-executor.js +8 -2
  86. package/dist/playbooks/playbook-executor.js.map +1 -1
  87. package/dist/playbooks/playbook-types.d.ts +8 -0
  88. package/dist/playbooks/playbook-types.d.ts.map +1 -1
  89. package/dist/plugins/types.d.ts +2 -2
  90. package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
  91. package/dist/runtime/admin-extra-ops.js +30 -0
  92. package/dist/runtime/admin-extra-ops.js.map +1 -1
  93. package/dist/runtime/admin-ops.d.ts.map +1 -1
  94. package/dist/runtime/admin-ops.js +60 -21
  95. package/dist/runtime/admin-ops.js.map +1 -1
  96. package/dist/runtime/admin-setup-ops.d.ts +11 -0
  97. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  98. package/dist/runtime/admin-setup-ops.js +146 -37
  99. package/dist/runtime/admin-setup-ops.js.map +1 -1
  100. package/dist/runtime/capture-ops.d.ts.map +1 -1
  101. package/dist/runtime/capture-ops.js +38 -12
  102. package/dist/runtime/capture-ops.js.map +1 -1
  103. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  104. package/dist/runtime/facades/brain-facade.js +16 -4
  105. package/dist/runtime/facades/brain-facade.js.map +1 -1
  106. package/dist/runtime/facades/context-facade.d.ts.map +1 -1
  107. package/dist/runtime/facades/context-facade.js +9 -3
  108. package/dist/runtime/facades/context-facade.js.map +1 -1
  109. package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
  110. package/dist/runtime/facades/memory-facade.js +20 -7
  111. package/dist/runtime/facades/memory-facade.js.map +1 -1
  112. package/dist/runtime/facades/orchestrate-facade.d.ts.map +1 -1
  113. package/dist/runtime/facades/orchestrate-facade.js +40 -1
  114. package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
  115. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  116. package/dist/runtime/facades/plan-facade.js +113 -4
  117. package/dist/runtime/facades/plan-facade.js.map +1 -1
  118. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  119. package/dist/runtime/facades/vault-facade.js +24 -3
  120. package/dist/runtime/facades/vault-facade.js.map +1 -1
  121. package/dist/runtime/orchestrate-ops.d.ts +21 -0
  122. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  123. package/dist/runtime/orchestrate-ops.js +132 -38
  124. package/dist/runtime/orchestrate-ops.js.map +1 -1
  125. package/dist/runtime/runtime.d.ts.map +1 -1
  126. package/dist/runtime/runtime.js +16 -0
  127. package/dist/runtime/runtime.js.map +1 -1
  128. package/dist/runtime/schema-helpers.d.ts.map +1 -1
  129. package/dist/runtime/schema-helpers.js +4 -0
  130. package/dist/runtime/schema-helpers.js.map +1 -1
  131. package/dist/runtime/types.d.ts +19 -0
  132. package/dist/runtime/types.d.ts.map +1 -1
  133. package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
  134. package/dist/runtime/vault-linking-ops.js +16 -3
  135. package/dist/runtime/vault-linking-ops.js.map +1 -1
  136. package/dist/scheduler/cron-validator.d.ts +15 -0
  137. package/dist/scheduler/cron-validator.d.ts.map +1 -0
  138. package/dist/scheduler/cron-validator.js +93 -0
  139. package/dist/scheduler/cron-validator.js.map +1 -0
  140. package/dist/scheduler/platform-linux.d.ts +14 -0
  141. package/dist/scheduler/platform-linux.d.ts.map +1 -0
  142. package/dist/scheduler/platform-linux.js +107 -0
  143. package/dist/scheduler/platform-linux.js.map +1 -0
  144. package/dist/scheduler/platform-macos.d.ts +15 -0
  145. package/dist/scheduler/platform-macos.d.ts.map +1 -0
  146. package/dist/scheduler/platform-macos.js +131 -0
  147. package/dist/scheduler/platform-macos.js.map +1 -0
  148. package/dist/scheduler/scheduler-ops.d.ts +14 -0
  149. package/dist/scheduler/scheduler-ops.d.ts.map +1 -0
  150. package/dist/scheduler/scheduler-ops.js +77 -0
  151. package/dist/scheduler/scheduler-ops.js.map +1 -0
  152. package/dist/scheduler/scheduler.d.ts +55 -0
  153. package/dist/scheduler/scheduler.d.ts.map +1 -0
  154. package/dist/scheduler/scheduler.js +144 -0
  155. package/dist/scheduler/scheduler.js.map +1 -0
  156. package/dist/scheduler/types.d.ts +48 -0
  157. package/dist/scheduler/types.d.ts.map +1 -0
  158. package/dist/scheduler/types.js +6 -0
  159. package/dist/scheduler/types.js.map +1 -0
  160. package/dist/skills/sync-skills.d.ts +11 -0
  161. package/dist/skills/sync-skills.d.ts.map +1 -1
  162. package/dist/skills/sync-skills.js +132 -38
  163. package/dist/skills/sync-skills.js.map +1 -1
  164. package/dist/skills/validate-skills.d.ts +32 -0
  165. package/dist/skills/validate-skills.d.ts.map +1 -0
  166. package/dist/skills/validate-skills.js +396 -0
  167. package/dist/skills/validate-skills.js.map +1 -0
  168. package/dist/utils/worktree-reaper.d.ts +38 -0
  169. package/dist/utils/worktree-reaper.d.ts.map +1 -0
  170. package/dist/utils/worktree-reaper.js +85 -0
  171. package/dist/utils/worktree-reaper.js.map +1 -0
  172. package/dist/vault/default-canonical-tags.d.ts +15 -0
  173. package/dist/vault/default-canonical-tags.d.ts.map +1 -0
  174. package/dist/vault/default-canonical-tags.js +65 -0
  175. package/dist/vault/default-canonical-tags.js.map +1 -0
  176. package/dist/vault/scope-detector.d.ts.map +1 -1
  177. package/dist/vault/scope-detector.js +37 -4
  178. package/dist/vault/scope-detector.js.map +1 -1
  179. package/dist/vault/tag-normalizer.d.ts +42 -0
  180. package/dist/vault/tag-normalizer.d.ts.map +1 -0
  181. package/dist/vault/tag-normalizer.js +157 -0
  182. package/dist/vault/tag-normalizer.js.map +1 -0
  183. package/dist/vault/vault-entries.d.ts.map +1 -1
  184. package/dist/vault/vault-entries.js +3 -1
  185. package/dist/vault/vault-entries.js.map +1 -1
  186. package/package.json +5 -1
  187. package/src/__tests__/embeddings.test.ts +3 -3
  188. package/src/agency/agency-manager.test.ts +4 -4
  189. package/src/agency/default-rules.test.ts +0 -13
  190. package/src/brain/brain-intelligence.test.ts +0 -5
  191. package/src/brain/brain.ts +25 -1
  192. package/src/brain/intelligence.ts +25 -0
  193. package/src/brain/second-brain-features.test.ts +2 -14
  194. package/src/brain/types.ts +1 -0
  195. package/src/capabilities/chain-mapping.test.ts +1 -6
  196. package/src/capabilities/chain-mapping.ts +6 -4
  197. package/src/capabilities/registry.test.ts +1 -1
  198. package/src/capabilities/registry.ts +9 -2
  199. package/src/chat/agent-loop.test.ts +1 -1
  200. package/src/chat/chat-enhanced.test.ts +0 -8
  201. package/src/chat/chat-session.ts +75 -17
  202. package/src/chat/chat-transport.test.ts +31 -1
  203. package/src/claudemd/compose.test.ts +0 -5
  204. package/src/context/context-engine.test.ts +0 -1
  205. package/src/context/context-engine.ts +1 -1
  206. package/src/control/intent-router.test.ts +2 -2
  207. package/src/curator/curator.ts +180 -0
  208. package/src/curator/tag-manager.test.ts +0 -4
  209. package/src/curator/types.ts +10 -0
  210. package/src/domain-packs/types.test.ts +0 -5
  211. package/src/dream/dream.test.ts +0 -7
  212. package/src/enforcement/registry.test.ts +2 -2
  213. package/src/engine/core-ops.test.ts +4 -22
  214. package/src/engine/core-ops.ts +36 -1
  215. package/src/engine/module-manifest.test.ts +1 -31
  216. package/src/engine/register-engine.test.ts +3 -33
  217. package/src/errors/retry.test.ts +3 -1
  218. package/src/flows/chain-runner.test.ts +0 -6
  219. package/src/flows/context-router.test.ts +3 -3
  220. package/src/flows/epilogue.test.ts +40 -2
  221. package/src/flows/epilogue.ts +11 -2
  222. package/src/flows/executor.test.ts +48 -2
  223. package/src/flows/executor.ts +15 -5
  224. package/src/flows/index.ts +1 -3
  225. package/src/flows/plan-builder.test.ts +201 -0
  226. package/src/flows/plan-builder.ts +81 -5
  227. package/src/flows/probes.ts +17 -3
  228. package/src/flows/types.ts +31 -2
  229. package/src/health/health-registry.test.ts +3 -1
  230. package/src/index.ts +24 -0
  231. package/src/intake/content-classifier.ts +22 -4
  232. package/src/intake/dedup-gate.test.ts +2 -6
  233. package/src/intake/text-ingester.test.ts +3 -4
  234. package/src/intake/text-ingester.ts +61 -12
  235. package/src/llm/llm-client.test.ts +1 -1
  236. package/src/llm/utils.test.ts +1 -1
  237. package/src/migrations/migration-runner.test.ts +0 -1
  238. package/src/operator/operator-context-store.test.ts +0 -13
  239. package/src/operator/operator-profile.test.ts +2 -20
  240. package/src/packs/pack-installer.ts +28 -2
  241. package/src/packs/pack-system.test.ts +2 -2
  242. package/src/persona/defaults.test.ts +19 -19
  243. package/src/planning/gap-passes.test.ts +0 -46
  244. package/src/planning/gap-patterns.test.ts +0 -42
  245. package/src/planning/goal-ancestry.test.ts +3 -1
  246. package/src/planning/plan-lifecycle.test.ts +15 -7
  247. package/src/planning/planner-types.ts +2 -0
  248. package/src/planning/planner.test.ts +86 -90
  249. package/src/planning/planner.ts +56 -4
  250. package/src/planning/reconciliation-engine.test.ts +3 -10
  251. package/src/planning/task-complexity-assessor.test.ts +0 -5
  252. package/src/planning/task-verifier.test.ts +3 -1
  253. package/src/playbooks/generic/generic-playbooks.test.ts +0 -28
  254. package/src/playbooks/index.test.ts +0 -55
  255. package/src/playbooks/playbook-executor.test.ts +76 -0
  256. package/src/playbooks/playbook-executor.ts +24 -3
  257. package/src/playbooks/playbook-types.ts +8 -0
  258. package/src/plugins/plugin-registry.test.ts +6 -2
  259. package/src/project/project-registry.test.ts +2 -0
  260. package/src/queue/async-infrastructure.test.ts +6 -4
  261. package/src/queue/job-queue.test.ts +13 -7
  262. package/src/runtime/admin-extra-ops.test.ts +35 -30
  263. package/src/runtime/admin-extra-ops.ts +30 -0
  264. package/src/runtime/admin-ops.test.ts +0 -4
  265. package/src/runtime/admin-ops.ts +63 -21
  266. package/src/runtime/admin-setup-ops.test.ts +229 -13
  267. package/src/runtime/admin-setup-ops.ts +145 -36
  268. package/src/runtime/archive-ops.test.ts +0 -28
  269. package/src/runtime/branching-ops.test.ts +0 -17
  270. package/src/runtime/capture-ops.test.ts +41 -16
  271. package/src/runtime/capture-ops.ts +78 -46
  272. package/src/runtime/chain-ops.test.ts +0 -21
  273. package/src/runtime/facades/admin-facade.test.ts +0 -34
  274. package/src/runtime/facades/agency-facade.test.ts +0 -39
  275. package/src/runtime/facades/archive-facade.test.ts +0 -43
  276. package/src/runtime/facades/brain-facade.test.ts +8 -99
  277. package/src/runtime/facades/brain-facade.ts +29 -12
  278. package/src/runtime/facades/branching-facade.test.ts +30 -17
  279. package/src/runtime/facades/chat-facade.test.ts +0 -91
  280. package/src/runtime/facades/chat-service-ops.test.ts +0 -24
  281. package/src/runtime/facades/chat-session-ops.test.ts +0 -12
  282. package/src/runtime/facades/chat-transport-ops.test.ts +0 -23
  283. package/src/runtime/facades/context-facade.test.ts +0 -17
  284. package/src/runtime/facades/context-facade.ts +11 -4
  285. package/src/runtime/facades/control-facade.test.ts +0 -30
  286. package/src/runtime/facades/curator-facade.test.ts +0 -33
  287. package/src/runtime/facades/intake-facade.test.ts +0 -33
  288. package/src/runtime/facades/links-facade.test.ts +0 -37
  289. package/src/runtime/facades/loop-facade.test.ts +0 -26
  290. package/src/runtime/facades/memory-facade.test.ts +0 -18
  291. package/src/runtime/facades/memory-facade.ts +27 -11
  292. package/src/runtime/facades/operator-facade.test.ts +0 -31
  293. package/src/runtime/facades/orchestrate-facade.test.ts +0 -21
  294. package/src/runtime/facades/orchestrate-facade.ts +39 -1
  295. package/src/runtime/facades/plan-facade.test.ts +7 -32
  296. package/src/runtime/facades/plan-facade.ts +137 -4
  297. package/src/runtime/facades/review-facade.test.ts +1 -49
  298. package/src/runtime/facades/sync-facade.test.ts +24 -41
  299. package/src/runtime/facades/tier-facade.test.ts +30 -22
  300. package/src/runtime/facades/vault-facade.test.ts +0 -41
  301. package/src/runtime/facades/vault-facade.ts +26 -3
  302. package/src/runtime/grading-ops.test.ts +0 -27
  303. package/src/runtime/intake-ops.test.ts +0 -19
  304. package/src/runtime/loop-ops.test.ts +0 -48
  305. package/src/runtime/memory-cross-project-ops.test.ts +0 -14
  306. package/src/runtime/memory-extra-ops.test.ts +4 -8
  307. package/src/runtime/orchestrate-ops.test.ts +238 -19
  308. package/src/runtime/orchestrate-ops.ts +166 -41
  309. package/src/runtime/pack-ops.test.ts +0 -26
  310. package/src/runtime/planning-extra-ops.test.ts +2 -14
  311. package/src/runtime/playbook-ops-execution.test.ts +9 -20
  312. package/src/runtime/playbook-ops.test.ts +4 -67
  313. package/src/runtime/review-ops.test.ts +0 -15
  314. package/src/runtime/runtime.ts +18 -0
  315. package/src/runtime/schema-helpers.ts +4 -0
  316. package/src/runtime/sync-ops.test.ts +0 -18
  317. package/src/runtime/tier-ops.test.ts +0 -21
  318. package/src/runtime/types.ts +19 -0
  319. package/src/runtime/vault-extra-ops.test.ts +0 -12
  320. package/src/runtime/vault-linking-ops.test.ts +0 -4
  321. package/src/runtime/vault-linking-ops.ts +26 -8
  322. package/src/runtime/vault-sharing-ops.test.ts +0 -9
  323. package/src/scheduler/cron-validator.ts +101 -0
  324. package/src/scheduler/platform-linux.ts +122 -0
  325. package/src/scheduler/platform-macos.ts +150 -0
  326. package/src/scheduler/scheduler-ops.ts +77 -0
  327. package/src/scheduler/scheduler.test.ts +247 -0
  328. package/src/scheduler/scheduler.ts +174 -0
  329. package/src/scheduler/types.ts +52 -0
  330. package/src/skills/__tests__/sync-skills.test.ts +6 -17
  331. package/src/skills/global-claude-md.test.ts +113 -0
  332. package/src/skills/sync-skills.ts +143 -35
  333. package/src/skills/validate-skills.test.ts +206 -0
  334. package/src/skills/validate-skills.ts +470 -0
  335. package/src/telemetry/telemetry.test.ts +1 -0
  336. package/src/transport/http-server.test.ts +3 -0
  337. package/src/transport/session-manager.test.ts +3 -1
  338. package/src/transport/token-auth.test.ts +6 -9
  339. package/src/transport/ws-server.test.ts +10 -2
  340. package/src/utils/worktree-reaper.ts +113 -0
  341. package/src/vault/__tests__/vault-characterization.test.ts +0 -108
  342. package/src/vault/default-canonical-tags.ts +64 -0
  343. package/src/vault/linking.test.ts +0 -2
  344. package/src/vault/playbook.test.ts +4 -1
  345. package/src/vault/scope-detector.test.ts +3 -1
  346. package/src/vault/scope-detector.ts +42 -4
  347. package/src/vault/tag-normalizer.test.ts +214 -0
  348. package/src/vault/tag-normalizer.ts +188 -0
  349. package/src/vault/vault-connect.test.ts +1 -1
  350. package/src/vault/vault-entries.ts +3 -1
  351. package/src/vault/vault.test.ts +23 -8
  352. package/dist/embeddings/index.d.ts +0 -5
  353. package/dist/embeddings/index.d.ts.map +0 -1
  354. package/dist/embeddings/index.js +0 -3
  355. package/dist/embeddings/index.js.map +0 -1
@@ -121,30 +121,6 @@ describe('chat-service-ops', () => {
121
121
  ops = createChatServiceOps(state);
122
122
  });
123
123
 
124
- it('exports 18 service ops', () => {
125
- const names = ops.map((o) => o.name);
126
- expect(names).toEqual([
127
- 'chat_cancel_create',
128
- 'chat_cancel_stop',
129
- 'chat_cancel_status',
130
- 'chat_update_init',
131
- 'chat_update_request',
132
- 'chat_update_confirm',
133
- 'chat_file_detect_intent',
134
- 'chat_file_build_content',
135
- 'chat_file_cleanup',
136
- 'chat_notify_init',
137
- 'chat_notify_start',
138
- 'chat_notify_stop',
139
- 'chat_notify_poll',
140
- 'chat_notify_status',
141
- 'chat_browser_init',
142
- 'chat_browser_acquire',
143
- 'chat_browser_release',
144
- 'chat_browser_status',
145
- ]);
146
- });
147
-
148
124
  // ─── Task Cancellation ─────────────────────────────────────────
149
125
 
150
126
  describe('chat_cancel_create', () => {
@@ -68,18 +68,6 @@ describe('chat-session-ops', () => {
68
68
  ops = createChatSessionOps(state);
69
69
  });
70
70
 
71
- it('exports 6 session ops', () => {
72
- const names = ops.map((o) => o.name);
73
- expect(names).toEqual([
74
- 'chat_session_init',
75
- 'chat_session_get',
76
- 'chat_session_append',
77
- 'chat_session_clear',
78
- 'chat_session_delete',
79
- 'chat_session_list',
80
- ]);
81
- });
82
-
83
71
  describe('chat_session_init', () => {
84
72
  it('initializes session manager and returns status', async () => {
85
73
  const op = findOp(ops, 'chat_session_init');
@@ -111,29 +111,6 @@ describe('chat-transport-ops', () => {
111
111
  ops = createChatTransportOps(state);
112
112
  });
113
113
 
114
- it('exports 17 transport ops', () => {
115
- const names = ops.map((o) => o.name);
116
- expect(names).toEqual([
117
- 'chat_chunk_response',
118
- 'chat_auth_init',
119
- 'chat_auth_check',
120
- 'chat_auth_authenticate',
121
- 'chat_auth_revoke',
122
- 'chat_auth_status',
123
- 'chat_bridge_init',
124
- 'chat_bridge_register',
125
- 'chat_bridge_list',
126
- 'chat_bridge_execute',
127
- 'chat_compress_output',
128
- 'chat_voice_transcribe',
129
- 'chat_voice_synthesize',
130
- 'chat_queue_init',
131
- 'chat_queue_inbox',
132
- 'chat_queue_reply',
133
- 'chat_queue_drain',
134
- ]);
135
- });
136
-
137
114
  // ─── Chunking ──────────────────────────────────────────────────
138
115
 
139
116
  describe('chat_chunk_response', () => {
@@ -51,23 +51,6 @@ describe('context-facade', () => {
51
51
  ops = captureOps(createContextFacadeOps(makeRuntime(mockEngine)));
52
52
  });
53
53
 
54
- it('registers all 3 ops', () => {
55
- expect(ops.size).toBe(3);
56
- expect([...ops.keys()]).toEqual(
57
- expect.arrayContaining([
58
- 'context_extract_entities',
59
- 'context_retrieve_knowledge',
60
- 'context_analyze',
61
- ]),
62
- );
63
- });
64
-
65
- it('has correct auth levels', () => {
66
- expect(ops.get('context_extract_entities')!.auth).toBe('read');
67
- expect(ops.get('context_retrieve_knowledge')!.auth).toBe('read');
68
- expect(ops.get('context_analyze')!.auth).toBe('read');
69
- });
70
-
71
54
  // ─── context_extract_entities ──────────────────────────────────
72
55
 
73
56
  it('context_extract_entities calls engine with prompt', async () => {
@@ -15,11 +15,18 @@ export function createContextFacadeOps(runtime: AgentRuntime): OpDefinition[] {
15
15
  description:
16
16
  'Extract named entities from a prompt — files, functions, domains, actions, technologies, patterns.',
17
17
  auth: 'read',
18
- schema: z.object({
19
- prompt: z.string().describe('The user prompt to analyze.'),
20
- }),
18
+ schema: z
19
+ .object({
20
+ prompt: z.string().optional().describe('The user prompt to analyze.'),
21
+ text: z.string().optional().describe('Alias for prompt — use either field.'),
22
+ })
23
+ .refine((v) => v.prompt !== undefined || v.text !== undefined, {
24
+ message: 'Provide either "prompt" or "text"',
25
+ }),
21
26
  handler: async (params) => {
22
- return contextEngine.extractEntities(params.prompt as string);
27
+ const input =
28
+ (params.prompt as string | undefined) ?? (params.text as string | undefined) ?? '';
29
+ return contextEngine.extractEntities(input);
23
30
  },
24
31
  },
25
32
  {
@@ -51,36 +51,6 @@ describe('createControlFacadeOps', () => {
51
51
  ops = createControlFacadeOps(runtime);
52
52
  });
53
53
 
54
- it('returns all expected ops', () => {
55
- const names = ops.map((o) => o.name);
56
- expect(names).toContain('get_identity');
57
- expect(names).toContain('update_identity');
58
- expect(names).toContain('add_guideline');
59
- expect(names).toContain('remove_guideline');
60
- expect(names).toContain('rollback_identity');
61
- expect(names).toContain('route_intent');
62
- expect(names).toContain('morph');
63
- expect(names).toContain('get_behavior_rules');
64
- expect(names).toContain('governance_policy');
65
- expect(names).toContain('governance_proposals');
66
- expect(names).toContain('governance_stats');
67
- expect(names).toContain('governance_expire');
68
- expect(names).toContain('governance_dashboard');
69
- expect(names).toContain('routing_feedback');
70
- expect(names).toContain('routing_accuracy');
71
- });
72
-
73
- it('assigns correct auth levels', () => {
74
- expect(findOp(ops, 'get_identity').auth).toBe('read');
75
- expect(findOp(ops, 'update_identity').auth).toBe('write');
76
- expect(findOp(ops, 'route_intent').auth).toBe('read');
77
- expect(findOp(ops, 'morph').auth).toBe('write');
78
- expect(findOp(ops, 'governance_policy').auth).toBe('write');
79
- expect(findOp(ops, 'governance_stats').auth).toBe('read');
80
- expect(findOp(ops, 'routing_feedback').auth).toBe('write');
81
- expect(findOp(ops, 'routing_accuracy').auth).toBe('read');
82
- });
83
-
84
54
  describe('get_identity', () => {
85
55
  it('returns identity when found', async () => {
86
56
  const identity = { agentId: 'test', name: 'Test Agent', version: 1 };
@@ -74,39 +74,6 @@ describe('createCuratorFacadeOps', () => {
74
74
  ops = createCuratorFacadeOps(runtime);
75
75
  });
76
76
 
77
- it('returns all expected ops', () => {
78
- const names = ops.map((o) => o.name);
79
- expect(names).toContain('curator_status');
80
- expect(names).toContain('curator_detect_duplicates');
81
- expect(names).toContain('curator_contradictions');
82
- expect(names).toContain('curator_resolve_contradiction');
83
- expect(names).toContain('curator_groom');
84
- expect(names).toContain('curator_groom_all');
85
- expect(names).toContain('curator_consolidate');
86
- expect(names).toContain('curator_health_audit');
87
- // Extra ops
88
- expect(names).toContain('curator_entry_history');
89
- expect(names).toContain('curator_record_snapshot');
90
- expect(names).toContain('curator_queue_stats');
91
- expect(names).toContain('curator_enrich');
92
- expect(names).toContain('curator_hybrid_contradictions');
93
- expect(names).toContain('curator_pipeline_status');
94
- expect(names).toContain('curator_enqueue_pipeline');
95
- expect(names).toContain('curator_schedule_start');
96
- expect(names).toContain('curator_schedule_stop');
97
- });
98
-
99
- it('assigns correct auth levels', () => {
100
- expect(findOp(ops, 'curator_status').auth).toBe('read');
101
- expect(findOp(ops, 'curator_detect_duplicates').auth).toBe('read');
102
- expect(findOp(ops, 'curator_contradictions').auth).toBe('read');
103
- expect(findOp(ops, 'curator_resolve_contradiction').auth).toBe('write');
104
- expect(findOp(ops, 'curator_groom').auth).toBe('write');
105
- expect(findOp(ops, 'curator_groom_all').auth).toBe('write');
106
- expect(findOp(ops, 'curator_consolidate').auth).toBe('write');
107
- expect(findOp(ops, 'curator_health_audit').auth).toBe('read');
108
- });
109
-
110
77
  describe('curator_status', () => {
111
78
  it('returns curator status', async () => {
112
79
  const result = await findOp(ops, 'curator_status').handler({});
@@ -50,39 +50,6 @@ describe('intake-facade', () => {
50
50
  ops = captureOps(createIntakeFacadeOps(runtime));
51
51
  });
52
52
 
53
- // ─── Registration ─────────────────────────────────────────────────
54
-
55
- it('returns exactly 7 ops', () => {
56
- expect(ops.size).toBe(7);
57
- });
58
-
59
- it('includes all expected op names', () => {
60
- const expected = [
61
- 'intake_ingest_book',
62
- 'intake_process',
63
- 'intake_status',
64
- 'intake_preview',
65
- 'ingest_url',
66
- 'ingest_text',
67
- 'ingest_batch',
68
- ];
69
- for (const name of expected) {
70
- expect(ops.has(name), `missing op: ${name}`).toBe(true);
71
- }
72
- });
73
-
74
- // ─── Auth levels ─────────────────────────────────────────────────
75
-
76
- it('has correct auth levels', () => {
77
- expect(ops.get('intake_ingest_book')!.auth).toBe('write');
78
- expect(ops.get('intake_process')!.auth).toBe('write');
79
- expect(ops.get('intake_status')!.auth).toBe('read');
80
- expect(ops.get('intake_preview')!.auth).toBe('read');
81
- expect(ops.get('ingest_url')!.auth).toBe('write');
82
- expect(ops.get('ingest_text')!.auth).toBe('write');
83
- expect(ops.get('ingest_batch')!.auth).toBe('write');
84
- });
85
-
86
53
  // ─── Delegation ─────────────────────────────────────────────────
87
54
 
88
55
  describe('intake_ingest_book', () => {
@@ -50,43 +50,6 @@ describe('links-facade', () => {
50
50
  ops = captureOps(createLinksFacadeOps(runtime));
51
51
  });
52
52
 
53
- // ─── Registration ──────────────────────────────────────────────────
54
-
55
- it('registers exactly 9 ops', () => {
56
- expect(ops.size).toBe(9);
57
- });
58
-
59
- it('includes all expected op names', () => {
60
- const expected = [
61
- 'link_entries',
62
- 'unlink_entries',
63
- 'get_links',
64
- 'traverse',
65
- 'suggest_links',
66
- 'get_orphans',
67
- 'relink_vault',
68
- 'backfill_links',
69
- 'link_stats',
70
- ];
71
- for (const name of expected) {
72
- expect(ops.has(name), `missing op: ${name}`).toBe(true);
73
- }
74
- });
75
-
76
- // ─── Auth levels ───────────────────────────────────────────────────
77
-
78
- it('has correct auth levels', () => {
79
- expect(ops.get('link_entries')!.auth).toBe('write');
80
- expect(ops.get('unlink_entries')!.auth).toBe('write');
81
- expect(ops.get('get_links')!.auth).toBe('read');
82
- expect(ops.get('traverse')!.auth).toBe('read');
83
- expect(ops.get('suggest_links')!.auth).toBe('read');
84
- expect(ops.get('get_orphans')!.auth).toBe('read');
85
- expect(ops.get('relink_vault')!.auth).toBe('write');
86
- expect(ops.get('backfill_links')!.auth).toBe('write');
87
- expect(ops.get('link_stats')!.auth).toBe('read');
88
- });
89
-
90
53
  // ─── Handler delegation ───────────────────────────────────────────
91
54
 
92
55
  describe('link_entries', () => {
@@ -87,32 +87,6 @@ describe('loop-facade', () => {
87
87
  ops = captureOps(createLoopFacadeOps(makeRuntime(mockLoop)));
88
88
  });
89
89
 
90
- it('registers all 9 ops', () => {
91
- expect(ops.size).toBe(9);
92
- const names = [...ops.keys()];
93
- expect(names).toContain('loop_start');
94
- expect(names).toContain('loop_iterate');
95
- expect(names).toContain('loop_iterate_gate');
96
- expect(names).toContain('loop_status');
97
- expect(names).toContain('loop_cancel');
98
- expect(names).toContain('loop_history');
99
- expect(names).toContain('loop_is_active');
100
- expect(names).toContain('loop_complete');
101
- expect(names).toContain('loop_anomaly_check');
102
- });
103
-
104
- it('has correct auth levels', () => {
105
- expect(ops.get('loop_start')!.auth).toBe('write');
106
- expect(ops.get('loop_iterate')!.auth).toBe('write');
107
- expect(ops.get('loop_iterate_gate')!.auth).toBe('write');
108
- expect(ops.get('loop_status')!.auth).toBe('read');
109
- expect(ops.get('loop_cancel')!.auth).toBe('write');
110
- expect(ops.get('loop_history')!.auth).toBe('read');
111
- expect(ops.get('loop_is_active')!.auth).toBe('read');
112
- expect(ops.get('loop_complete')!.auth).toBe('write');
113
- expect(ops.get('loop_anomaly_check')!.auth).toBe('read');
114
- });
115
-
116
90
  // ─── loop_start ────────────────────────────────────────────────
117
91
 
118
92
  it('loop_start creates a loop with defaults', async () => {
@@ -30,24 +30,6 @@ describe('memory-facade', () => {
30
30
  vault.close();
31
31
  });
32
32
 
33
- it('registers base + extra + cross-project ops', () => {
34
- // 4 base + 18 extra + 3 cross-project = 25
35
- expect(ops.size).toBeGreaterThanOrEqual(25);
36
- expect([...ops.keys()]).toContain('memory_search');
37
- expect([...ops.keys()]).toContain('memory_capture');
38
- expect([...ops.keys()]).toContain('memory_list');
39
- expect([...ops.keys()]).toContain('session_capture');
40
- expect([...ops.keys()]).toContain('memory_delete');
41
- expect([...ops.keys()]).toContain('memory_promote_to_global');
42
- });
43
-
44
- it('has correct auth levels for base ops', () => {
45
- expect(ops.get('memory_search')!.auth).toBe('read');
46
- expect(ops.get('memory_capture')!.auth).toBe('write');
47
- expect(ops.get('memory_list')!.auth).toBe('read');
48
- expect(ops.get('session_capture')!.auth).toBe('write');
49
- });
50
-
51
33
  // ─── memory_capture ────────────────────────────────────────────
52
34
 
53
35
  it('memory_capture stores a memory', async () => {
@@ -60,21 +60,37 @@ export function createMemoryFacadeOps(runtime: AgentRuntime): OpDefinition[] {
60
60
  name: 'memory_capture',
61
61
  description: 'Capture a memory — session summary, lesson learned, or preference.',
62
62
  auth: 'write',
63
- schema: z.object({
64
- projectPath: z.string(),
65
- type: z.enum(['session', 'lesson', 'preference']),
66
- context: z.string(),
67
- summary: z.string(),
68
- topics: z.array(z.string()).optional().default([]),
69
- filesModified: z.array(z.string()).optional().default([]),
70
- toolsUsed: z.array(z.string()).optional().default([]),
71
- }),
63
+ schema: z
64
+ .object({
65
+ projectPath: z.string().optional().default('.'),
66
+ type: z
67
+ .enum(['session', 'lesson', 'preference'])
68
+ .optional()
69
+ .default('lesson')
70
+ .describe('Memory type: session | lesson | preference (default: "lesson")'),
71
+ context: z.string().optional().describe('What was happening — situation or task context'),
72
+ summary: z.string().optional().describe('What was learned or decided'),
73
+ content: z
74
+ .string()
75
+ .optional()
76
+ .describe('Alias: sets both context and summary when neither is provided'),
77
+ topics: z.array(z.string()).optional().default([]),
78
+ filesModified: z.array(z.string()).optional().default([]),
79
+ toolsUsed: z.array(z.string()).optional().default([]),
80
+ })
81
+ .refine(
82
+ (v) => v.context !== undefined || v.summary !== undefined || v.content !== undefined,
83
+ {
84
+ message: 'Provide at least one of: context, summary, or content',
85
+ },
86
+ ),
72
87
  handler: async (params) => {
88
+ const rawContent = params.content as string | undefined;
73
89
  const memory = vault.captureMemory({
74
90
  projectPath: params.projectPath as string,
75
91
  type: params.type as 'session' | 'lesson' | 'preference',
76
- context: params.context as string,
77
- summary: params.summary as string,
92
+ context: (params.context as string | undefined) ?? rawContent ?? '',
93
+ summary: (params.summary as string | undefined) ?? rawContent ?? '',
78
94
  topics: (params.topics as string[]) ?? [],
79
95
  filesModified: (params.filesModified as string[]) ?? [],
80
96
  toolsUsed: (params.toolsUsed as string[]) ?? [],
@@ -41,37 +41,6 @@ describe('operator-facade (colocated)', () => {
41
41
  vault.close();
42
42
  });
43
43
 
44
- it('registers all 10 ops', () => {
45
- expect(ops.size).toBe(10);
46
- expect([...ops.keys()]).toEqual(
47
- expect.arrayContaining([
48
- 'profile_get',
49
- 'profile_update_section',
50
- 'profile_correct',
51
- 'profile_delete',
52
- 'profile_export',
53
- 'signal_accumulate',
54
- 'signal_list',
55
- 'signal_stats',
56
- 'synthesis_check',
57
- 'profile_snapshot',
58
- ]),
59
- );
60
- });
61
-
62
- it('has correct auth levels', () => {
63
- expect(ops.get('profile_get')!.auth).toBe('read');
64
- expect(ops.get('profile_update_section')!.auth).toBe('write');
65
- expect(ops.get('profile_correct')!.auth).toBe('write');
66
- expect(ops.get('profile_delete')!.auth).toBe('admin');
67
- expect(ops.get('profile_export')!.auth).toBe('read');
68
- expect(ops.get('signal_accumulate')!.auth).toBe('write');
69
- expect(ops.get('signal_list')!.auth).toBe('read');
70
- expect(ops.get('signal_stats')!.auth).toBe('read');
71
- expect(ops.get('synthesis_check')!.auth).toBe('read');
72
- expect(ops.get('profile_snapshot')!.auth).toBe('write');
73
- });
74
-
75
44
  // ─── profile_get ───────────────────────────────────────────────
76
45
 
77
46
  it('profile_get returns null when no profile', async () => {
@@ -62,27 +62,6 @@ describe('orchestrate-facade', () => {
62
62
  vault.close();
63
63
  });
64
64
 
65
- it('registers session_start + satellite ops', () => {
66
- expect(ops.size).toBeGreaterThanOrEqual(20);
67
- expect([...ops.keys()]).toContain('session_start');
68
- expect([...ops.keys()]).toContain('orchestrate_plan');
69
- expect([...ops.keys()]).toContain('orchestrate_execute');
70
- expect([...ops.keys()]).toContain('orchestrate_complete');
71
- expect([...ops.keys()]).toContain('orchestrate_status');
72
- expect([...ops.keys()]).toContain('orchestrate_quick_capture');
73
- expect([...ops.keys()]).toContain('project_get');
74
- expect([...ops.keys()]).toContain('project_list');
75
- expect([...ops.keys()]).toContain('playbook_list');
76
- });
77
-
78
- it('has correct auth levels', () => {
79
- expect(ops.get('session_start')!.auth).toBe('write');
80
- expect(ops.get('orchestrate_plan')!.auth).toBe('write');
81
- expect(ops.get('orchestrate_status')!.auth).toBe('read');
82
- expect(ops.get('project_get')!.auth).toBe('read');
83
- expect(ops.get('project_list')!.auth).toBe('read');
84
- });
85
-
86
65
  // ─── session_start ─────────────────────────────────────────────
87
66
 
88
67
  it('session_start registers project and returns stats', async () => {
@@ -24,7 +24,7 @@ import {
24
24
  import type { SkillStep, EvidenceType } from '../../skills/step-tracker.js';
25
25
 
26
26
  export function createOrchestrateFacadeOps(runtime: AgentRuntime): OpDefinition[] {
27
- const { vault, governance, projectRegistry } = runtime;
27
+ const { vault, governance, projectRegistry, brainIntelligence } = runtime;
28
28
 
29
29
  return [
30
30
  // ─── Session Start (inline from core-ops.ts) ─────────────────────
@@ -120,6 +120,18 @@ export function createOrchestrateFacadeOps(runtime: AgentRuntime): OpDefinition[
120
120
  /* dream module not available — skip silently */
121
121
  }
122
122
 
123
+ // Auto-reap stale worktrees — best-effort, non-blocking
124
+ try {
125
+ const { worktreeReap } = await import('../../utils/worktree-reaper.js');
126
+ Promise.resolve()
127
+ .then(() => worktreeReap(projectPath))
128
+ .catch(() => {
129
+ /* best-effort */
130
+ });
131
+ } catch {
132
+ /* worktree-reaper not available — skip silently */
133
+ }
134
+
123
135
  // ─── Pre-flight manifest ───────────────────────────────
124
136
  let skills: string[] = [];
125
137
  try {
@@ -150,6 +162,31 @@ export function createOrchestrateFacadeOps(runtime: AgentRuntime): OpDefinition[
150
162
  vaultStats: stats,
151
163
  });
152
164
 
165
+ // Auto-close orphaned brain sessions (endedAt IS NULL, startedAt < now - 2h)
166
+ let orphansClosed = 0;
167
+ try {
168
+ const TWO_HOURS_MS = 2 * 60 * 60 * 1000;
169
+ const cutoff = new Date(Date.now() - TWO_HOURS_MS);
170
+ const activeSessions = brainIntelligence.listSessions({ active: true, limit: 1000 });
171
+ for (const s of activeSessions) {
172
+ if (new Date(s.startedAt) < cutoff) {
173
+ try {
174
+ brainIntelligence.lifecycle({
175
+ action: 'end',
176
+ sessionId: s.id,
177
+ planOutcome: 'abandoned',
178
+ context: 'auto-closed: orphan from previous conversation',
179
+ });
180
+ orphansClosed++;
181
+ } catch {
182
+ // Best-effort per session — never let one failure abort the rest
183
+ }
184
+ }
185
+ }
186
+ } catch {
187
+ // Non-critical — don't fail session start over orphan cleanup
188
+ }
189
+
153
190
  return {
154
191
  project,
155
192
  is_new: isNew,
@@ -167,6 +204,7 @@ export function createOrchestrateFacadeOps(runtime: AgentRuntime): OpDefinition[
167
204
  expiredThisSession: expired,
168
205
  },
169
206
  preflight,
207
+ orphansClosed,
170
208
  ...(stagingWarning ? { stagingWarning } : {}),
171
209
  ...(dreamInfo ? { dream: dreamInfo } : {}),
172
210
  };
@@ -48,26 +48,6 @@ describe('plan-facade', () => {
48
48
  vault.close();
49
49
  });
50
50
 
51
- it('registers base + extra + grading + chain ops', () => {
52
- // 5 base + 22 extra + 5 grading + 5 chain = 37
53
- expect(ops.size).toBeGreaterThanOrEqual(32);
54
- expect([...ops.keys()]).toContain('create_plan');
55
- expect([...ops.keys()]).toContain('get_plan');
56
- expect([...ops.keys()]).toContain('approve_plan');
57
- expect([...ops.keys()]).toContain('update_task');
58
- expect([...ops.keys()]).toContain('complete_plan');
59
- expect([...ops.keys()]).toContain('plan_grade');
60
- expect([...ops.keys()]).toContain('chain_execute');
61
- });
62
-
63
- it('has correct auth levels for base ops', () => {
64
- expect(ops.get('create_plan')!.auth).toBe('write');
65
- expect(ops.get('get_plan')!.auth).toBe('read');
66
- expect(ops.get('approve_plan')!.auth).toBe('write');
67
- expect(ops.get('update_task')!.auth).toBe('write');
68
- expect(ops.get('complete_plan')!.auth).toBe('write');
69
- });
70
-
71
51
  // ─── create_plan ───────────────────────────────────────────────
72
52
 
73
53
  it('create_plan creates a draft plan', async () => {
@@ -91,7 +71,7 @@ describe('plan-facade', () => {
91
71
  });
92
72
  expect(result.success).toBe(true);
93
73
  const plan = (result.data as Record<string, unknown>).plan as Record<string, unknown>;
94
- expect((plan.tasks as unknown[]).length).toBe(1);
74
+ expect((plan.tasks as unknown[]).length).toBeGreaterThanOrEqual(1);
95
75
  });
96
76
 
97
77
  // ─── get_plan ──────────────────────────────────────────────────
@@ -366,11 +346,11 @@ describe('plan-facade', () => {
366
346
  vaultEntryIds: string[];
367
347
  };
368
348
  expect(data.created).toBe(true);
369
- expect(data.vaultEntryIds.length).toBeGreaterThan(0);
349
+ expect(data.vaultEntryIds).toHaveLength(1); // exactly one seeded entry matches
370
350
  // Decisions should contain vault pattern references with entryId markers
371
351
  const decisions = data.plan.decisions as string[];
372
352
  const vaultDecisions = decisions.filter((d) => d.startsWith('Vault pattern:'));
373
- expect(vaultDecisions.length).toBeGreaterThan(0);
353
+ expect(vaultDecisions).toHaveLength(1); // one vault entry injected one decision
374
354
  // Each vault decision should have an [entryId:...] marker for brain feedback
375
355
  for (const vd of vaultDecisions) {
376
356
  expect(vd).toMatch(/\[entryId:[^\]]+\]/);
@@ -413,19 +393,14 @@ describe('plan-facade', () => {
413
393
  const decisions = data.plan.decisions as string[];
414
394
  // User decision preserved
415
395
  expect(decisions).toContain('Use vitest as test runner');
416
- // Vault enrichment added
417
- if (data.vaultEntryIds.length > 0) {
418
- const vaultDecisions = decisions.filter((d) => d.startsWith('Vault pattern:'));
419
- expect(vaultDecisions.length).toBeGreaterThan(0);
420
- }
396
+ // Vault enrichment added — one seeded entry matches the 'testing' query
397
+ expect(data.vaultEntryIds).toHaveLength(1);
398
+ const vaultDecisions = decisions.filter((d) => d.startsWith('Vault pattern:'));
399
+ expect(vaultDecisions).toHaveLength(1);
421
400
  });
422
401
 
423
402
  // ─── plan_close_stale ─────────────────────────────────────────
424
403
 
425
- it('plan_close_stale op is registered', () => {
426
- expect([...ops.keys()]).toContain('plan_close_stale');
427
- });
428
-
429
404
  it('plan_close_stale returns no plans when none are stale', async () => {
430
405
  const result = await executeOp(ops, 'plan_close_stale', {});
431
406
  expect(result.success).toBe(true);