@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
@@ -1129,6 +1129,30 @@ export class BrainIntelligence {
1129
1129
  // ─── Intelligence Pipeline ────────────────────────────────────────
1130
1130
 
1131
1131
  buildIntelligence(): BuildIntelligenceResult {
1132
+ // Step 0: GC — close orphaned sessions with no execution signal older than 24h
1133
+ const TTL_MS = 24 * 60 * 60 * 1000;
1134
+ const cutoff = new Date(Date.now() - TTL_MS).toISOString();
1135
+ const activeSessions = this.listSessions({ active: true, limit: 1000 });
1136
+ let gcClosed = 0;
1137
+ for (const s of activeSessions) {
1138
+ const isOld = s.startedAt < cutoff;
1139
+ const hasNoSignal =
1140
+ s.toolsUsed.length === 0 && s.filesModified.length === 0 && s.planOutcome === null;
1141
+ if (isOld && hasNoSignal) {
1142
+ try {
1143
+ this.lifecycle({
1144
+ action: 'end',
1145
+ sessionId: s.id,
1146
+ planOutcome: 'abandoned',
1147
+ context: 'auto-gc: no execution signal after TTL',
1148
+ });
1149
+ gcClosed++;
1150
+ } catch {
1151
+ // GC must never break the intelligence pipeline
1152
+ }
1153
+ }
1154
+ }
1155
+
1132
1156
  // Step 1: Compute and persist strengths
1133
1157
  const strengths = this.computeStrengths();
1134
1158
 
@@ -1154,6 +1178,7 @@ export class BrainIntelligence {
1154
1178
  strengthsComputed: strengths.length,
1155
1179
  globalPatterns,
1156
1180
  domainProfiles,
1181
+ gcClosed,
1157
1182
  };
1158
1183
  }
1159
1184
 
@@ -33,7 +33,7 @@ import type { IntelligenceEntry } from '../intelligence/types.js';
33
33
 
34
34
  let vault: Vault;
35
35
  let brain: Brain;
36
- let brainIntelligence: BrainIntelligence;
36
+ let _brainIntelligence: BrainIntelligence;
37
37
  let planner: Planner;
38
38
  let curator: Curator;
39
39
  let intentRouter: IntentRouter;
@@ -99,7 +99,7 @@ beforeAll(() => {
99
99
  vault = new Vault(':memory:');
100
100
  vault.seed(SEED);
101
101
  brain = new Brain(vault);
102
- brainIntelligence = new BrainIntelligence(vault, brain);
102
+ _brainIntelligence = new BrainIntelligence(vault, brain);
103
103
  planner = new Planner(join(tempDir, 'plans.json'));
104
104
  curator = new Curator(vault);
105
105
  intentRouter = new IntentRouter(vault);
@@ -160,18 +160,6 @@ describe('Two-pass vault retrieval (#205)', () => {
160
160
  // ─── 2. Session Briefing ─────────────────────────────────────────────
161
161
 
162
162
  describe('Session briefing (#202)', () => {
163
- // Session briefing is an op — tested via the module imports directly
164
- it('brainIntelligence.listSessions returns sessions', () => {
165
- const sessions = brainIntelligence.listSessions({ limit: 5 });
166
- // May be empty in a fresh vault, but shouldn't throw
167
- expect(Array.isArray(sessions)).toBe(true);
168
- });
169
-
170
- it('planner.list returns plans array', () => {
171
- const plans = planner.list();
172
- expect(Array.isArray(plans)).toBe(true);
173
- });
174
-
175
163
  it('vault.getRecent returns recent entries', () => {
176
164
  const recent = vault.getRecent(5);
177
165
  expect(recent.length).toBeGreaterThan(0);
@@ -198,6 +198,7 @@ export interface BuildIntelligenceResult {
198
198
  strengthsComputed: number;
199
199
  globalPatterns: number;
200
200
  domainProfiles: number;
201
+ gcClosed: number;
201
202
  }
202
203
 
203
204
  export interface BrainIntelligenceStats {
@@ -6,10 +6,6 @@ describe('chainToCapability', () => {
6
6
  expect(chainToCapability('vault-search')).toBe('vault.search');
7
7
  });
8
8
 
9
- it('maps vault-search-antipatterns to vault.search', () => {
10
- expect(chainToCapability('vault-search-antipatterns')).toBe('vault.search');
11
- });
12
-
13
9
  it('maps memory-search to memory.search', () => {
14
10
  expect(chainToCapability('memory-search')).toBe('memory.search');
15
11
  });
@@ -39,9 +35,8 @@ describe('chainToCapability', () => {
39
35
  expect(chainToCapability('get-stack-guidelines')).toBe('stack.guidelines');
40
36
  });
41
37
 
42
- it('maps architecture and cognee chains', () => {
38
+ it('maps architecture chains', () => {
43
39
  expect(chainToCapability('architecture-search')).toBe('architecture.search');
44
- expect(chainToCapability('cognee-design-search')).toBe('cognee.search');
45
40
  });
46
41
 
47
42
  it('maps planning chains', () => {
@@ -22,7 +22,7 @@
22
22
  * deliver.flow.yaml — validate-component, validate-tokens,
23
23
  * design-rules-check, test-coverage-check,
24
24
  * performance-audit, delivery-checklist
25
- * design.flow.yaml — vault-search, memory-search, cognee-design-search,
25
+ * design.flow.yaml — vault-search, memory-search,
26
26
  * recommend-design-system, recommend-style,
27
27
  * recommend-palette, recommend-typography,
28
28
  * get-stack-guidelines, brain-recommend
@@ -30,7 +30,7 @@
30
30
  * brain-recommend, validate-component, validate-tokens
31
31
  * explore.flow.yaml — vault-search, memory-search, brain-strengths,
32
32
  * brain-recommend, playbook-search
33
- * fix.flow.yaml — vault-search-antipatterns, memory-search,
33
+ * fix.flow.yaml — vault-search, memory-search,
34
34
  * error-pattern-search, brain-recommend,
35
35
  * validate-component, validate-tokens
36
36
  * plan.flow.yaml — vault-search, memory-search, brain-recommend,
@@ -42,7 +42,6 @@
42
42
  const CHAIN_TO_CAPABILITY: Record<string, string> = {
43
43
  // Vault & Knowledge
44
44
  'vault-search': 'vault.search',
45
- 'vault-search-antipatterns': 'vault.search',
46
45
  'memory-search': 'memory.search',
47
46
  'playbook-search': 'vault.playbook',
48
47
 
@@ -67,11 +66,14 @@ const CHAIN_TO_CAPABILITY: Record<string, string> = {
67
66
 
68
67
  // Architecture
69
68
  'architecture-search': 'architecture.search',
70
- 'cognee-design-search': 'cognee.search',
71
69
 
72
70
  // Planning
73
71
  'plan-create': 'plan.create',
74
72
 
73
+ // Capture & Synthesis
74
+ 'capture-baseline-state': 'vault.capture',
75
+ 'vault-synthesize': 'vault.synthesize',
76
+
75
77
  // Review & Quality
76
78
  'review-report': 'review.report',
77
79
  'accessibility-audit': 'a11y.audit',
@@ -237,7 +237,7 @@ describe('CapabilityRegistry', () => {
237
237
  it('classifies blocking capabilities correctly', () => {
238
238
  const result = registry.validateFlow({
239
239
  steps: [{ needs: ['vault.search', 'auth.validate'] }],
240
- onMissingCapability: { blocking: ['auth.validate'] },
240
+ 'on-missing-capability': { blocking: ['auth.validate'] },
241
241
  });
242
242
 
243
243
  expect(result.valid).toBe(false);
@@ -33,6 +33,12 @@ export interface FlowForValidation {
33
33
  needs?: string[];
34
34
  chains?: string[];
35
35
  }>;
36
+ /** Kebab-case (YAML / flow file format). */
37
+ 'on-missing-capability'?: {
38
+ default?: string;
39
+ blocking?: string[];
40
+ };
41
+ /** CamelCase alias for programmatic callers. */
36
42
  onMissingCapability?: {
37
43
  default?: string;
38
44
  blocking?: string[];
@@ -236,8 +242,9 @@ export class CapabilityRegistry {
236
242
  }
237
243
  }
238
244
 
239
- // Classify missing capabilities by impact
240
- const blockingSet = new Set(flow.onMissingCapability?.blocking ?? []);
245
+ // Classify missing capabilities by impact (accept both kebab and camelCase keys)
246
+ const missingCapConfig = flow['on-missing-capability'] ?? flow.onMissingCapability;
247
+ const blockingSet = new Set(missingCapConfig?.blocking ?? []);
241
248
 
242
249
  const degraded = missing.map((capability) => ({
243
250
  capability,
@@ -286,7 +286,7 @@ describe('runAgentLoop', () => {
286
286
  onToolUse: (name) => toolUses.push(name),
287
287
  onToolResult: (name, result, ms) => {
288
288
  toolResults.push(`${name}:${result.output}`);
289
- expect(ms).toBeGreaterThanOrEqual(0);
289
+ expect(typeof ms).toBe('number');
290
290
  },
291
291
  },
292
292
  );
@@ -14,7 +14,6 @@ import {
14
14
  cleanupTempFiles,
15
15
  sanitizeForPersistence,
16
16
  MAX_FILE_SIZE,
17
- TEXT_EXTENSIONS,
18
17
  } from './file-handler.js';
19
18
  import { NotificationEngine } from './notifications.js';
20
19
  import type { FileInfo, MultimodalContent } from './file-handler.js';
@@ -231,13 +230,6 @@ describe('File Handler', () => {
231
230
  });
232
231
  });
233
232
 
234
- test('TEXT_EXTENSIONS includes common types', () => {
235
- expect(TEXT_EXTENSIONS.has('.ts')).toBe(true);
236
- expect(TEXT_EXTENSIONS.has('.py')).toBe(true);
237
- expect(TEXT_EXTENSIONS.has('.json')).toBe(true);
238
- expect(TEXT_EXTENSIONS.has('.md')).toBe(true);
239
- });
240
-
241
233
  test('MAX_FILE_SIZE is 20MB', () => {
242
234
  expect(MAX_FILE_SIZE).toBe(20 * 1024 * 1024);
243
235
  });
@@ -16,6 +16,7 @@ const DEFAULT_TTL_MS = 7_200_000; // 2 hours
16
16
  const DEFAULT_COMPACTION_THRESHOLD = 100;
17
17
  const DEFAULT_COMPACTION_KEEP = 40;
18
18
  const REAPER_INTERVAL_MS = 60_000; // 1 minute
19
+ const SESSION_SUBDIR = 'sessions';
19
20
 
20
21
  export class ChatSessionManager {
21
22
  private sessions = new Map<string, ChatSession>();
@@ -31,6 +32,7 @@ export class ChatSessionManager {
31
32
  };
32
33
 
33
34
  mkdirSync(this.config.storageDir, { recursive: true });
35
+ mkdirSync(this.sessionDir(), { recursive: true });
34
36
  }
35
37
 
36
38
  // ─── Lifecycle ──────────────────────────────────────────────────
@@ -78,7 +80,8 @@ export class ChatSessionManager {
78
80
  */
79
81
  has(sessionId: string): boolean {
80
82
  if (this.sessions.has(sessionId)) return true;
81
- return existsSync(this.sessionPath(sessionId));
83
+ if (existsSync(this.sessionPath(sessionId))) return true;
84
+ return this.loadSessionFile(this.legacySessionPath(sessionId)) !== undefined;
82
85
  }
83
86
 
84
87
  // ─── Message Management ─────────────────────────────────────────
@@ -159,15 +162,11 @@ export class ChatSessionManager {
159
162
  */
160
163
  listAll(): string[] {
161
164
  const memoryIds = new Set(this.sessions.keys());
162
- try {
163
- const files = readdirSync(this.config.storageDir);
164
- for (const f of files) {
165
- if (f.endsWith('.json')) {
166
- memoryIds.add(f.replace('.json', ''));
167
- }
168
- }
169
- } catch {
170
- // Directory may not exist yet
165
+ for (const id of this.readPersistedSessionIds(this.sessionDir())) {
166
+ memoryIds.add(id);
167
+ }
168
+ for (const id of this.readPersistedSessionIds(this.config.storageDir)) {
169
+ memoryIds.add(id);
171
170
  }
172
171
  return [...memoryIds];
173
172
  }
@@ -246,38 +245,97 @@ export class ChatSessionManager {
246
245
  session.messages = session.messages.slice(-keep);
247
246
  }
248
247
 
248
+ private sessionDir(): string {
249
+ return join(this.config.storageDir, SESSION_SUBDIR);
250
+ }
251
+
249
252
  private sessionPath(sessionId: string): string {
250
253
  // Sanitize ID for filesystem safety
254
+ const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');
255
+ return join(this.sessionDir(), `${safe}.json`);
256
+ }
257
+
258
+ private legacySessionPath(sessionId: string): string {
251
259
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');
252
260
  return join(this.config.storageDir, `${safe}.json`);
253
261
  }
254
262
 
255
263
  private persistToDisk(session: ChatSession): void {
256
264
  try {
265
+ mkdirSync(this.sessionDir(), { recursive: true });
257
266
  writeFileSync(this.sessionPath(session.id), JSON.stringify(session), 'utf-8');
267
+
268
+ // Clean up valid legacy session files after migrating to the namespaced path.
269
+ const legacyPath = this.legacySessionPath(session.id);
270
+ if (this.loadSessionFile(legacyPath)) {
271
+ this.removeFile(legacyPath);
272
+ }
258
273
  } catch {
259
274
  // Disk write failure is non-critical — session lives in memory
260
275
  }
261
276
  }
262
277
 
263
278
  private loadFromDisk(sessionId: string): ChatSession | undefined {
264
- const path = this.sessionPath(sessionId);
279
+ const current = this.loadSessionFile(this.sessionPath(sessionId));
280
+ if (current) return current;
281
+
282
+ const legacyPath = this.legacySessionPath(sessionId);
283
+ const legacy = this.loadSessionFile(legacyPath);
284
+ if (legacy) {
285
+ this.persistToDisk(legacy);
286
+ return legacy;
287
+ }
288
+
289
+ return undefined;
290
+ }
291
+
292
+ private removeFromDisk(sessionId: string): void {
293
+ this.removeFile(this.sessionPath(sessionId));
294
+ const legacyPath = this.legacySessionPath(sessionId);
295
+ if (this.loadSessionFile(legacyPath)) {
296
+ this.removeFile(legacyPath);
297
+ }
298
+ }
299
+
300
+ private removeFile(path: string): void {
301
+ try {
302
+ rmSync(path, { force: true });
303
+ } catch {
304
+ // Removal failure is non-critical
305
+ }
306
+ }
307
+
308
+ private loadSessionFile(path: string): ChatSession | undefined {
265
309
  if (!existsSync(path)) return undefined;
266
310
 
267
311
  try {
268
- const data = readFileSync(path, 'utf-8');
269
- return JSON.parse(data) as ChatSession;
312
+ const data = JSON.parse(readFileSync(path, 'utf-8'));
313
+ return this.isChatSession(data) ? data : undefined;
270
314
  } catch {
271
315
  return undefined;
272
316
  }
273
317
  }
274
318
 
275
- private removeFromDisk(sessionId: string): void {
276
- const path = this.sessionPath(sessionId);
319
+ private readPersistedSessionIds(dir: string): string[] {
277
320
  try {
278
- rmSync(path, { force: true });
321
+ return readdirSync(dir).flatMap((file) => {
322
+ if (!file.endsWith('.json')) return [];
323
+ const session = this.loadSessionFile(join(dir, file));
324
+ return session ? [session.id] : [];
325
+ });
279
326
  } catch {
280
- // Removal failure is non-critical
327
+ return [];
281
328
  }
282
329
  }
330
+
331
+ private isChatSession(value: unknown): value is ChatSession {
332
+ if (!value || typeof value !== 'object') return false;
333
+ const session = value as Partial<ChatSession>;
334
+ return (
335
+ typeof session.id === 'string' &&
336
+ Array.isArray(session.messages) &&
337
+ typeof session.createdAt === 'number' &&
338
+ typeof session.lastActiveAt === 'number'
339
+ );
340
+ }
283
341
  }
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { describe, test, expect, beforeEach, afterEach } from 'vitest';
7
- import { mkdtempSync, rmSync } from 'node:fs';
7
+ import { mkdtempSync, rmSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
9
  import { tmpdir } from 'node:os';
10
10
  import { ChatSessionManager } from './chat-session.js';
@@ -136,6 +136,19 @@ describe('ChatSessionManager', () => {
136
136
  expect(all).toContain('chat-2');
137
137
  });
138
138
 
139
+ test('listAll ignores non-session JSON files in the storage root', () => {
140
+ manager.getOrCreate('chat-1');
141
+ writeFileSync(
142
+ join(dir, 'plans.json'),
143
+ JSON.stringify({ version: '1.0', plans: [] }),
144
+ 'utf-8',
145
+ );
146
+
147
+ const all = manager.listAll();
148
+ expect(all).toContain('chat-1');
149
+ expect(all).not.toContain('plans');
150
+ });
151
+
139
152
  test('setMeta updates metadata', () => {
140
153
  manager.getOrCreate('chat-1');
141
154
  manager.setMeta('chat-1', { mood: 'happy' });
@@ -162,6 +175,23 @@ describe('ChatSessionManager', () => {
162
175
  manager2.close();
163
176
  });
164
177
 
178
+ test('session files are namespaced away from plans.json collisions', () => {
179
+ writeFileSync(
180
+ join(dir, 'plans.json'),
181
+ JSON.stringify({ version: '1.0', plans: [{ id: 'plan-1' }] }),
182
+ 'utf-8',
183
+ );
184
+
185
+ const session = manager.getOrCreate('plans');
186
+
187
+ expect(session.messages).toEqual([]);
188
+ expect(JSON.parse(readFileSync(join(dir, 'plans.json'), 'utf-8'))).toEqual({
189
+ version: '1.0',
190
+ plans: [{ id: 'plan-1' }],
191
+ });
192
+ expect(existsSync(join(dir, 'sessions', 'plans.json'))).toBe(true);
193
+ });
194
+
165
195
  test('delete removes from disk', () => {
166
196
  manager.getOrCreate('chat-1');
167
197
  manager.delete('chat-1');
@@ -35,11 +35,6 @@ const facades: FacadeConfig[] = [
35
35
  ];
36
36
 
37
37
  describe('compose — constants', () => {
38
- it('FORMAT_VERSION is a positive integer', () => {
39
- expect(FORMAT_VERSION).toBeGreaterThan(0);
40
- expect(Number.isInteger(FORMAT_VERSION)).toBe(true);
41
- });
42
-
43
38
  it('markers contain version', () => {
44
39
  expect(OPEN_MARKER).toContain(`v${FORMAT_VERSION}`);
45
40
  });
@@ -398,7 +398,6 @@ describe('ContextEngine', () => {
398
398
 
399
399
  it('processing time is a non-negative number', async () => {
400
400
  const result = await engine.analyze('any prompt');
401
- expect(result.processingTimeMs).toBeGreaterThanOrEqual(0);
402
401
  expect(typeof result.processingTimeMs).toBe('number');
403
402
  });
404
403
 
@@ -48,7 +48,7 @@ const ENTITY_PATTERNS: Array<{ type: EntityType; pattern: RegExp; confidence: nu
48
48
  {
49
49
  type: 'technology',
50
50
  pattern:
51
- /\b(?:react|vue|svelte|angular|typescript|javascript|node\.?js|python|rust|go|docker|kubernetes|postgres|sqlite|redis|tailwind|css|html|graphql|rest|grpc)\b/gi,
51
+ /\b(?:react|vue|svelte|angular|typescript|javascript|node\.?js|python|rust|go|docker|kubernetes|postgres|sqlite|redis|tailwind|css|html|graphql|rest|grpc|vitest|jest|mocha|playwright|cypress)\b/gi,
52
52
  confidence: 0.85,
53
53
  },
54
54
  // Patterns: kebab-case compound terms that look like patterns
@@ -57,7 +57,7 @@ describe('IntentRouter', () => {
57
57
  expect(result.mode).toBe('FIX-MODE');
58
58
  expect(result.method).toBe('keyword');
59
59
  expect(result.confidence).toBeGreaterThan(0);
60
- expect(result.matchedKeywords.length).toBeGreaterThan(0);
60
+ expect(result.matchedKeywords.length).toBe(2);
61
61
  });
62
62
 
63
63
  it('classifies "build a new component" as BUILD intent', () => {
@@ -117,7 +117,7 @@ describe('IntentRouter', () => {
117
117
  // "fix bug broken error" has 4 FIX keywords vs anything else
118
118
  const result = router.routeIntent('fix bug broken error');
119
119
  expect(result.intent).toBe('fix');
120
- expect(result.matchedKeywords.length).toBeGreaterThanOrEqual(4);
120
+ expect(result.matchedKeywords.length).toBe(4);
121
121
  });
122
122
 
123
123
  it('confidence is capped at 1.0', () => {