@soleri/core 2.1.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/dist/brain/brain.d.ts +10 -1
  2. package/dist/brain/brain.d.ts.map +1 -1
  3. package/dist/brain/brain.js +116 -13
  4. package/dist/brain/brain.js.map +1 -1
  5. package/dist/brain/intelligence.d.ts +36 -1
  6. package/dist/brain/intelligence.d.ts.map +1 -1
  7. package/dist/brain/intelligence.js +119 -14
  8. package/dist/brain/intelligence.js.map +1 -1
  9. package/dist/brain/types.d.ts +34 -2
  10. package/dist/brain/types.d.ts.map +1 -1
  11. package/dist/cognee/client.d.ts +3 -0
  12. package/dist/cognee/client.d.ts.map +1 -1
  13. package/dist/cognee/client.js +17 -0
  14. package/dist/cognee/client.js.map +1 -1
  15. package/dist/cognee/sync-manager.d.ts +94 -0
  16. package/dist/cognee/sync-manager.d.ts.map +1 -0
  17. package/dist/cognee/sync-manager.js +293 -0
  18. package/dist/cognee/sync-manager.js.map +1 -0
  19. package/dist/control/identity-manager.d.ts +22 -0
  20. package/dist/control/identity-manager.d.ts.map +1 -0
  21. package/dist/control/identity-manager.js +233 -0
  22. package/dist/control/identity-manager.js.map +1 -0
  23. package/dist/control/intent-router.d.ts +32 -0
  24. package/dist/control/intent-router.d.ts.map +1 -0
  25. package/dist/control/intent-router.js +242 -0
  26. package/dist/control/intent-router.js.map +1 -0
  27. package/dist/control/types.d.ts +68 -0
  28. package/dist/control/types.d.ts.map +1 -0
  29. package/dist/control/types.js +9 -0
  30. package/dist/control/types.js.map +1 -0
  31. package/dist/curator/curator.d.ts +37 -1
  32. package/dist/curator/curator.d.ts.map +1 -1
  33. package/dist/curator/curator.js +199 -1
  34. package/dist/curator/curator.js.map +1 -1
  35. package/dist/errors/classify.d.ts +13 -0
  36. package/dist/errors/classify.d.ts.map +1 -0
  37. package/dist/errors/classify.js +97 -0
  38. package/dist/errors/classify.js.map +1 -0
  39. package/dist/errors/index.d.ts +6 -0
  40. package/dist/errors/index.d.ts.map +1 -0
  41. package/dist/errors/index.js +4 -0
  42. package/dist/errors/index.js.map +1 -0
  43. package/dist/errors/retry.d.ts +40 -0
  44. package/dist/errors/retry.d.ts.map +1 -0
  45. package/dist/errors/retry.js +97 -0
  46. package/dist/errors/retry.js.map +1 -0
  47. package/dist/errors/types.d.ts +48 -0
  48. package/dist/errors/types.d.ts.map +1 -0
  49. package/dist/errors/types.js +59 -0
  50. package/dist/errors/types.js.map +1 -0
  51. package/dist/facades/types.d.ts +1 -1
  52. package/dist/governance/governance.d.ts +42 -0
  53. package/dist/governance/governance.d.ts.map +1 -0
  54. package/dist/governance/governance.js +488 -0
  55. package/dist/governance/governance.js.map +1 -0
  56. package/dist/governance/index.d.ts +3 -0
  57. package/dist/governance/index.d.ts.map +1 -0
  58. package/dist/governance/index.js +2 -0
  59. package/dist/governance/index.js.map +1 -0
  60. package/dist/governance/types.d.ts +102 -0
  61. package/dist/governance/types.d.ts.map +1 -0
  62. package/dist/governance/types.js +3 -0
  63. package/dist/governance/types.js.map +1 -0
  64. package/dist/index.d.ts +52 -3
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +47 -1
  67. package/dist/index.js.map +1 -1
  68. package/dist/intake/content-classifier.d.ts +14 -0
  69. package/dist/intake/content-classifier.d.ts.map +1 -0
  70. package/dist/intake/content-classifier.js +125 -0
  71. package/dist/intake/content-classifier.js.map +1 -0
  72. package/dist/intake/dedup-gate.d.ts +17 -0
  73. package/dist/intake/dedup-gate.d.ts.map +1 -0
  74. package/dist/intake/dedup-gate.js +66 -0
  75. package/dist/intake/dedup-gate.js.map +1 -0
  76. package/dist/intake/intake-pipeline.d.ts +63 -0
  77. package/dist/intake/intake-pipeline.d.ts.map +1 -0
  78. package/dist/intake/intake-pipeline.js +373 -0
  79. package/dist/intake/intake-pipeline.js.map +1 -0
  80. package/dist/intake/types.d.ts +65 -0
  81. package/dist/intake/types.d.ts.map +1 -0
  82. package/dist/intake/types.js +3 -0
  83. package/dist/intake/types.js.map +1 -0
  84. package/dist/intelligence/loader.js +1 -1
  85. package/dist/intelligence/loader.js.map +1 -1
  86. package/dist/intelligence/types.d.ts +3 -1
  87. package/dist/intelligence/types.d.ts.map +1 -1
  88. package/dist/logging/logger.d.ts +37 -0
  89. package/dist/logging/logger.d.ts.map +1 -0
  90. package/dist/logging/logger.js +145 -0
  91. package/dist/logging/logger.js.map +1 -0
  92. package/dist/logging/types.d.ts +19 -0
  93. package/dist/logging/types.d.ts.map +1 -0
  94. package/dist/logging/types.js +2 -0
  95. package/dist/logging/types.js.map +1 -0
  96. package/dist/loop/loop-manager.d.ts +100 -0
  97. package/dist/loop/loop-manager.d.ts.map +1 -0
  98. package/dist/loop/loop-manager.js +379 -0
  99. package/dist/loop/loop-manager.js.map +1 -0
  100. package/dist/loop/types.d.ts +103 -0
  101. package/dist/loop/types.d.ts.map +1 -0
  102. package/dist/loop/types.js +11 -0
  103. package/dist/loop/types.js.map +1 -0
  104. package/dist/persistence/index.d.ts +3 -0
  105. package/dist/persistence/index.d.ts.map +1 -0
  106. package/dist/persistence/index.js +2 -0
  107. package/dist/persistence/index.js.map +1 -0
  108. package/dist/persistence/sqlite-provider.d.ts +25 -0
  109. package/dist/persistence/sqlite-provider.d.ts.map +1 -0
  110. package/dist/persistence/sqlite-provider.js +59 -0
  111. package/dist/persistence/sqlite-provider.js.map +1 -0
  112. package/dist/persistence/types.d.ts +36 -0
  113. package/dist/persistence/types.d.ts.map +1 -0
  114. package/dist/persistence/types.js +8 -0
  115. package/dist/persistence/types.js.map +1 -0
  116. package/dist/planning/gap-analysis.d.ts +72 -0
  117. package/dist/planning/gap-analysis.d.ts.map +1 -0
  118. package/dist/planning/gap-analysis.js +442 -0
  119. package/dist/planning/gap-analysis.js.map +1 -0
  120. package/dist/planning/gap-types.d.ts +29 -0
  121. package/dist/planning/gap-types.d.ts.map +1 -0
  122. package/dist/planning/gap-types.js +28 -0
  123. package/dist/planning/gap-types.js.map +1 -0
  124. package/dist/planning/planner.d.ts +421 -4
  125. package/dist/planning/planner.d.ts.map +1 -1
  126. package/dist/planning/planner.js +949 -21
  127. package/dist/planning/planner.js.map +1 -1
  128. package/dist/playbooks/generic/brainstorming.d.ts +9 -0
  129. package/dist/playbooks/generic/brainstorming.d.ts.map +1 -0
  130. package/dist/playbooks/generic/brainstorming.js +105 -0
  131. package/dist/playbooks/generic/brainstorming.js.map +1 -0
  132. package/dist/playbooks/generic/code-review.d.ts +11 -0
  133. package/dist/playbooks/generic/code-review.d.ts.map +1 -0
  134. package/dist/playbooks/generic/code-review.js +176 -0
  135. package/dist/playbooks/generic/code-review.js.map +1 -0
  136. package/dist/playbooks/generic/subagent-execution.d.ts +9 -0
  137. package/dist/playbooks/generic/subagent-execution.d.ts.map +1 -0
  138. package/dist/playbooks/generic/subagent-execution.js +68 -0
  139. package/dist/playbooks/generic/subagent-execution.js.map +1 -0
  140. package/dist/playbooks/generic/systematic-debugging.d.ts +9 -0
  141. package/dist/playbooks/generic/systematic-debugging.d.ts.map +1 -0
  142. package/dist/playbooks/generic/systematic-debugging.js +87 -0
  143. package/dist/playbooks/generic/systematic-debugging.js.map +1 -0
  144. package/dist/playbooks/generic/tdd.d.ts +9 -0
  145. package/dist/playbooks/generic/tdd.d.ts.map +1 -0
  146. package/dist/playbooks/generic/tdd.js +70 -0
  147. package/dist/playbooks/generic/tdd.js.map +1 -0
  148. package/dist/playbooks/generic/verification.d.ts +9 -0
  149. package/dist/playbooks/generic/verification.d.ts.map +1 -0
  150. package/dist/playbooks/generic/verification.js +74 -0
  151. package/dist/playbooks/generic/verification.js.map +1 -0
  152. package/dist/playbooks/index.d.ts +4 -0
  153. package/dist/playbooks/index.d.ts.map +1 -0
  154. package/dist/playbooks/index.js +5 -0
  155. package/dist/playbooks/index.js.map +1 -0
  156. package/dist/playbooks/playbook-registry.d.ts +42 -0
  157. package/dist/playbooks/playbook-registry.d.ts.map +1 -0
  158. package/dist/playbooks/playbook-registry.js +227 -0
  159. package/dist/playbooks/playbook-registry.js.map +1 -0
  160. package/dist/playbooks/playbook-seeder.d.ts +47 -0
  161. package/dist/playbooks/playbook-seeder.d.ts.map +1 -0
  162. package/dist/playbooks/playbook-seeder.js +104 -0
  163. package/dist/playbooks/playbook-seeder.js.map +1 -0
  164. package/dist/playbooks/playbook-types.d.ts +132 -0
  165. package/dist/playbooks/playbook-types.d.ts.map +1 -0
  166. package/dist/playbooks/playbook-types.js +12 -0
  167. package/dist/playbooks/playbook-types.js.map +1 -0
  168. package/dist/project/project-registry.d.ts +79 -0
  169. package/dist/project/project-registry.d.ts.map +1 -0
  170. package/dist/project/project-registry.js +274 -0
  171. package/dist/project/project-registry.js.map +1 -0
  172. package/dist/project/types.d.ts +28 -0
  173. package/dist/project/types.d.ts.map +1 -0
  174. package/dist/project/types.js +5 -0
  175. package/dist/project/types.js.map +1 -0
  176. package/dist/prompts/index.d.ts +4 -0
  177. package/dist/prompts/index.d.ts.map +1 -0
  178. package/dist/prompts/index.js +3 -0
  179. package/dist/prompts/index.js.map +1 -0
  180. package/dist/prompts/parser.d.ts +17 -0
  181. package/dist/prompts/parser.d.ts.map +1 -0
  182. package/dist/prompts/parser.js +47 -0
  183. package/dist/prompts/parser.js.map +1 -0
  184. package/dist/prompts/template-manager.d.ts +25 -0
  185. package/dist/prompts/template-manager.d.ts.map +1 -0
  186. package/dist/prompts/template-manager.js +71 -0
  187. package/dist/prompts/template-manager.js.map +1 -0
  188. package/dist/prompts/types.d.ts +26 -0
  189. package/dist/prompts/types.d.ts.map +1 -0
  190. package/dist/prompts/types.js +5 -0
  191. package/dist/prompts/types.js.map +1 -0
  192. package/dist/runtime/admin-extra-ops.d.ts +15 -0
  193. package/dist/runtime/admin-extra-ops.d.ts.map +1 -0
  194. package/dist/runtime/admin-extra-ops.js +595 -0
  195. package/dist/runtime/admin-extra-ops.js.map +1 -0
  196. package/dist/runtime/admin-ops.d.ts +15 -0
  197. package/dist/runtime/admin-ops.d.ts.map +1 -0
  198. package/dist/runtime/admin-ops.js +329 -0
  199. package/dist/runtime/admin-ops.js.map +1 -0
  200. package/dist/runtime/capture-ops.d.ts +15 -0
  201. package/dist/runtime/capture-ops.d.ts.map +1 -0
  202. package/dist/runtime/capture-ops.js +363 -0
  203. package/dist/runtime/capture-ops.js.map +1 -0
  204. package/dist/runtime/cognee-sync-ops.d.ts +12 -0
  205. package/dist/runtime/cognee-sync-ops.d.ts.map +1 -0
  206. package/dist/runtime/cognee-sync-ops.js +55 -0
  207. package/dist/runtime/cognee-sync-ops.js.map +1 -0
  208. package/dist/runtime/core-ops.d.ts +9 -3
  209. package/dist/runtime/core-ops.d.ts.map +1 -1
  210. package/dist/runtime/core-ops.js +693 -10
  211. package/dist/runtime/core-ops.js.map +1 -1
  212. package/dist/runtime/curator-extra-ops.d.ts +9 -0
  213. package/dist/runtime/curator-extra-ops.d.ts.map +1 -0
  214. package/dist/runtime/curator-extra-ops.js +71 -0
  215. package/dist/runtime/curator-extra-ops.js.map +1 -0
  216. package/dist/runtime/domain-ops.d.ts.map +1 -1
  217. package/dist/runtime/domain-ops.js +61 -15
  218. package/dist/runtime/domain-ops.js.map +1 -1
  219. package/dist/runtime/grading-ops.d.ts +14 -0
  220. package/dist/runtime/grading-ops.d.ts.map +1 -0
  221. package/dist/runtime/grading-ops.js +105 -0
  222. package/dist/runtime/grading-ops.js.map +1 -0
  223. package/dist/runtime/intake-ops.d.ts +14 -0
  224. package/dist/runtime/intake-ops.d.ts.map +1 -0
  225. package/dist/runtime/intake-ops.js +110 -0
  226. package/dist/runtime/intake-ops.js.map +1 -0
  227. package/dist/runtime/loop-ops.d.ts +14 -0
  228. package/dist/runtime/loop-ops.d.ts.map +1 -0
  229. package/dist/runtime/loop-ops.js +251 -0
  230. package/dist/runtime/loop-ops.js.map +1 -0
  231. package/dist/runtime/memory-cross-project-ops.d.ts +12 -0
  232. package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -0
  233. package/dist/runtime/memory-cross-project-ops.js +165 -0
  234. package/dist/runtime/memory-cross-project-ops.js.map +1 -0
  235. package/dist/runtime/memory-extra-ops.d.ts +13 -0
  236. package/dist/runtime/memory-extra-ops.d.ts.map +1 -0
  237. package/dist/runtime/memory-extra-ops.js +173 -0
  238. package/dist/runtime/memory-extra-ops.js.map +1 -0
  239. package/dist/runtime/orchestrate-ops.d.ts +17 -0
  240. package/dist/runtime/orchestrate-ops.d.ts.map +1 -0
  241. package/dist/runtime/orchestrate-ops.js +246 -0
  242. package/dist/runtime/orchestrate-ops.js.map +1 -0
  243. package/dist/runtime/planning-extra-ops.d.ts +25 -0
  244. package/dist/runtime/planning-extra-ops.d.ts.map +1 -0
  245. package/dist/runtime/planning-extra-ops.js +663 -0
  246. package/dist/runtime/planning-extra-ops.js.map +1 -0
  247. package/dist/runtime/playbook-ops.d.ts +14 -0
  248. package/dist/runtime/playbook-ops.d.ts.map +1 -0
  249. package/dist/runtime/playbook-ops.js +141 -0
  250. package/dist/runtime/playbook-ops.js.map +1 -0
  251. package/dist/runtime/project-ops.d.ts +15 -0
  252. package/dist/runtime/project-ops.d.ts.map +1 -0
  253. package/dist/runtime/project-ops.js +186 -0
  254. package/dist/runtime/project-ops.js.map +1 -0
  255. package/dist/runtime/runtime.d.ts.map +1 -1
  256. package/dist/runtime/runtime.js +65 -3
  257. package/dist/runtime/runtime.js.map +1 -1
  258. package/dist/runtime/types.d.ts +29 -0
  259. package/dist/runtime/types.d.ts.map +1 -1
  260. package/dist/runtime/vault-extra-ops.d.ts +10 -0
  261. package/dist/runtime/vault-extra-ops.d.ts.map +1 -0
  262. package/dist/runtime/vault-extra-ops.js +536 -0
  263. package/dist/runtime/vault-extra-ops.js.map +1 -0
  264. package/dist/telemetry/telemetry.d.ts +48 -0
  265. package/dist/telemetry/telemetry.d.ts.map +1 -0
  266. package/dist/telemetry/telemetry.js +87 -0
  267. package/dist/telemetry/telemetry.js.map +1 -0
  268. package/dist/vault/playbook.d.ts +34 -0
  269. package/dist/vault/playbook.d.ts.map +1 -0
  270. package/dist/vault/playbook.js +60 -0
  271. package/dist/vault/playbook.js.map +1 -0
  272. package/dist/vault/vault.d.ts +97 -4
  273. package/dist/vault/vault.d.ts.map +1 -1
  274. package/dist/vault/vault.js +424 -65
  275. package/dist/vault/vault.js.map +1 -1
  276. package/package.json +7 -3
  277. package/src/__tests__/admin-extra-ops.test.ts +467 -0
  278. package/src/__tests__/admin-ops.test.ts +271 -0
  279. package/src/__tests__/brain-intelligence.test.ts +205 -0
  280. package/src/__tests__/brain.test.ts +134 -3
  281. package/src/__tests__/capture-ops.test.ts +509 -0
  282. package/src/__tests__/cognee-integration.test.ts +80 -0
  283. package/src/__tests__/cognee-sync-manager.test.ts +103 -0
  284. package/src/__tests__/core-ops.test.ts +292 -2
  285. package/src/__tests__/curator-extra-ops.test.ts +381 -0
  286. package/src/__tests__/domain-ops.test.ts +66 -0
  287. package/src/__tests__/errors.test.ts +388 -0
  288. package/src/__tests__/governance.test.ts +522 -0
  289. package/src/__tests__/grading-ops.test.ts +361 -0
  290. package/src/__tests__/identity-manager.test.ts +243 -0
  291. package/src/__tests__/intake-pipeline.test.ts +162 -0
  292. package/src/__tests__/intent-router.test.ts +222 -0
  293. package/src/__tests__/logger.test.ts +200 -0
  294. package/src/__tests__/loop-ops.test.ts +469 -0
  295. package/src/__tests__/memory-cross-project-ops.test.ts +248 -0
  296. package/src/__tests__/memory-extra-ops.test.ts +352 -0
  297. package/src/__tests__/orchestrate-ops.test.ts +289 -0
  298. package/src/__tests__/persistence.test.ts +225 -0
  299. package/src/__tests__/planner.test.ts +416 -7
  300. package/src/__tests__/planning-extra-ops.test.ts +706 -0
  301. package/src/__tests__/playbook-registry.test.ts +326 -0
  302. package/src/__tests__/playbook-seeder.test.ts +163 -0
  303. package/src/__tests__/playbook.test.ts +389 -0
  304. package/src/__tests__/project-ops.test.ts +381 -0
  305. package/src/__tests__/template-manager.test.ts +222 -0
  306. package/src/__tests__/vault-extra-ops.test.ts +482 -0
  307. package/src/brain/brain.ts +185 -16
  308. package/src/brain/intelligence.ts +179 -10
  309. package/src/brain/types.ts +40 -2
  310. package/src/cognee/client.ts +18 -0
  311. package/src/cognee/sync-manager.ts +389 -0
  312. package/src/control/identity-manager.ts +354 -0
  313. package/src/control/intent-router.ts +326 -0
  314. package/src/control/types.ts +102 -0
  315. package/src/curator/curator.ts +295 -1
  316. package/src/errors/classify.ts +102 -0
  317. package/src/errors/index.ts +5 -0
  318. package/src/errors/retry.ts +132 -0
  319. package/src/errors/types.ts +81 -0
  320. package/src/governance/governance.ts +698 -0
  321. package/src/governance/index.ts +18 -0
  322. package/src/governance/types.ts +111 -0
  323. package/src/index.ts +213 -2
  324. package/src/intake/content-classifier.ts +146 -0
  325. package/src/intake/dedup-gate.ts +92 -0
  326. package/src/intake/intake-pipeline.ts +503 -0
  327. package/src/intake/types.ts +69 -0
  328. package/src/intelligence/loader.ts +1 -1
  329. package/src/intelligence/types.ts +3 -1
  330. package/src/logging/logger.ts +154 -0
  331. package/src/logging/types.ts +21 -0
  332. package/src/loop/loop-manager.ts +448 -0
  333. package/src/loop/types.ts +115 -0
  334. package/src/persistence/index.ts +7 -0
  335. package/src/persistence/sqlite-provider.ts +62 -0
  336. package/src/persistence/types.ts +44 -0
  337. package/src/planning/gap-analysis.ts +775 -0
  338. package/src/planning/gap-types.ts +61 -0
  339. package/src/planning/planner.ts +1273 -24
  340. package/src/playbooks/generic/brainstorming.ts +110 -0
  341. package/src/playbooks/generic/code-review.ts +181 -0
  342. package/src/playbooks/generic/subagent-execution.ts +74 -0
  343. package/src/playbooks/generic/systematic-debugging.ts +92 -0
  344. package/src/playbooks/generic/tdd.ts +75 -0
  345. package/src/playbooks/generic/verification.ts +79 -0
  346. package/src/playbooks/index.ts +27 -0
  347. package/src/playbooks/playbook-registry.ts +284 -0
  348. package/src/playbooks/playbook-seeder.ts +119 -0
  349. package/src/playbooks/playbook-types.ts +162 -0
  350. package/src/project/project-registry.ts +370 -0
  351. package/src/project/types.ts +31 -0
  352. package/src/prompts/index.ts +3 -0
  353. package/src/prompts/parser.ts +59 -0
  354. package/src/prompts/template-manager.ts +77 -0
  355. package/src/prompts/types.ts +28 -0
  356. package/src/runtime/admin-extra-ops.ts +652 -0
  357. package/src/runtime/admin-ops.ts +340 -0
  358. package/src/runtime/capture-ops.ts +404 -0
  359. package/src/runtime/cognee-sync-ops.ts +63 -0
  360. package/src/runtime/core-ops.ts +787 -9
  361. package/src/runtime/curator-extra-ops.ts +85 -0
  362. package/src/runtime/domain-ops.ts +67 -15
  363. package/src/runtime/grading-ops.ts +130 -0
  364. package/src/runtime/intake-ops.ts +126 -0
  365. package/src/runtime/loop-ops.ts +277 -0
  366. package/src/runtime/memory-cross-project-ops.ts +191 -0
  367. package/src/runtime/memory-extra-ops.ts +186 -0
  368. package/src/runtime/orchestrate-ops.ts +278 -0
  369. package/src/runtime/planning-extra-ops.ts +718 -0
  370. package/src/runtime/playbook-ops.ts +169 -0
  371. package/src/runtime/project-ops.ts +202 -0
  372. package/src/runtime/runtime.ts +77 -3
  373. package/src/runtime/types.ts +29 -0
  374. package/src/runtime/vault-extra-ops.ts +606 -0
  375. package/src/telemetry/telemetry.ts +118 -0
  376. package/src/vault/playbook.ts +87 -0
  377. package/src/vault/vault.ts +575 -98
@@ -0,0 +1,162 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { dedupItems, DEDUP_THRESHOLD } from '../intake/dedup-gate.js';
3
+ import { Vault } from '../vault/vault.js';
4
+ import type { ClassifiedItem } from '../intake/types.js';
5
+
6
+ function makeItem(overrides: Partial<ClassifiedItem> = {}): ClassifiedItem {
7
+ return {
8
+ type: overrides.type ?? 'pattern',
9
+ title: overrides.title ?? 'Test Pattern',
10
+ description: overrides.description ?? 'A generic test description.',
11
+ tags: overrides.tags ?? ['test'],
12
+ severity: overrides.severity ?? 'suggestion',
13
+ citation: overrides.citation ?? 'p.1',
14
+ };
15
+ }
16
+
17
+ describe('Dedup Gate', () => {
18
+ let vault: Vault;
19
+
20
+ beforeEach(() => {
21
+ vault = new Vault(':memory:');
22
+ });
23
+
24
+ afterEach(() => {
25
+ vault.close();
26
+ });
27
+
28
+ it('should mark items as non-duplicate when vault is empty', () => {
29
+ const items: ClassifiedItem[] = [
30
+ makeItem({ title: 'Brand New Pattern', description: 'Something entirely new.' }),
31
+ ];
32
+
33
+ const results = dedupItems(items, vault);
34
+
35
+ expect(results).toHaveLength(1);
36
+ expect(results[0].isDuplicate).toBe(false);
37
+ expect(results[0].similarity).toBe(0);
38
+ expect(results[0].bestMatchId).toBeUndefined();
39
+ expect(results[0].item).toBe(items[0]);
40
+ });
41
+
42
+ it('should detect near-duplicates with high similarity', () => {
43
+ vault.seed([
44
+ {
45
+ id: 'existing-1',
46
+ type: 'pattern',
47
+ domain: 'design-patterns',
48
+ title: 'Singleton Pattern Implementation',
49
+ severity: 'suggestion',
50
+ description:
51
+ 'The singleton pattern ensures a class has only one instance and provides a global point of access to it.',
52
+ tags: ['singleton', 'design-pattern', 'creational'],
53
+ },
54
+ ]);
55
+
56
+ const items: ClassifiedItem[] = [
57
+ makeItem({
58
+ title: 'Singleton Pattern Implementation',
59
+ description:
60
+ 'The singleton pattern ensures a class has only one instance and provides a global point of access to it.',
61
+ tags: ['singleton', 'design-pattern', 'creational'],
62
+ }),
63
+ ];
64
+
65
+ const results = dedupItems(items, vault);
66
+
67
+ expect(results).toHaveLength(1);
68
+ expect(results[0].similarity).toBeGreaterThan(0.5);
69
+ expect(results[0].bestMatchId).toBe('existing-1');
70
+ });
71
+
72
+ it('should not flag dissimilar entries as duplicates', () => {
73
+ vault.seed([
74
+ {
75
+ id: 'existing-2',
76
+ type: 'pattern',
77
+ domain: 'design-patterns',
78
+ title: 'Observer Pattern',
79
+ severity: 'suggestion',
80
+ description:
81
+ 'The observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified.',
82
+ tags: ['observer', 'design-pattern', 'behavioral'],
83
+ },
84
+ ]);
85
+
86
+ const items: ClassifiedItem[] = [
87
+ makeItem({
88
+ title: 'God Object Anti-Pattern',
89
+ description:
90
+ 'A god object is an anti-pattern where a single class knows too much or does too much, violating the single responsibility principle.',
91
+ tags: ['anti-pattern', 'code-smell'],
92
+ }),
93
+ ];
94
+
95
+ const results = dedupItems(items, vault);
96
+
97
+ expect(results).toHaveLength(1);
98
+ expect(results[0].isDuplicate).toBe(false);
99
+ });
100
+
101
+ it('should handle multiple items at once', () => {
102
+ vault.seed([
103
+ {
104
+ id: 'existing-3',
105
+ type: 'pattern',
106
+ domain: 'design-patterns',
107
+ title: 'Factory Method Pattern',
108
+ severity: 'suggestion',
109
+ description:
110
+ 'The factory method pattern defines an interface for creating an object but lets subclasses decide which class to instantiate.',
111
+ tags: ['factory', 'design-pattern', 'creational'],
112
+ },
113
+ ]);
114
+
115
+ const items: ClassifiedItem[] = [
116
+ // Near-duplicate of vault entry
117
+ makeItem({
118
+ title: 'Factory Method Pattern',
119
+ description:
120
+ 'The factory method pattern defines an interface for creating an object but lets subclasses decide which class to instantiate.',
121
+ tags: ['factory', 'design-pattern', 'creational'],
122
+ }),
123
+ // Completely different
124
+ makeItem({
125
+ title: 'Dependency Injection',
126
+ description:
127
+ 'Dependency injection is a technique where an object receives other objects that it depends on, called dependencies, rather than creating them internally.',
128
+ tags: ['dependency-injection', 'inversion-of-control'],
129
+ }),
130
+ // Also different
131
+ makeItem({
132
+ title: 'Circuit Breaker Pattern',
133
+ description:
134
+ 'The circuit breaker pattern prevents an application from repeatedly trying to execute an operation that is likely to fail, allowing it to recover gracefully.',
135
+ tags: ['resilience', 'distributed-systems'],
136
+ }),
137
+ ];
138
+
139
+ const results = dedupItems(items, vault);
140
+
141
+ expect(results).toHaveLength(3);
142
+
143
+ // First item is a near-duplicate — should have high similarity
144
+ expect(results[0].similarity).toBeGreaterThan(0.5);
145
+ expect(results[0].bestMatchId).toBe('existing-3');
146
+
147
+ // Second and third items are different — should not be duplicates
148
+ expect(results[1].isDuplicate).toBe(false);
149
+ expect(results[2].isDuplicate).toBe(false);
150
+ });
151
+
152
+ it('DEDUP_THRESHOLD should be 0.85', () => {
153
+ expect(DEDUP_THRESHOLD).toBe(0.85);
154
+ });
155
+ });
156
+
157
+ describe('Intake Types', () => {
158
+ it('should import all type definitions', async () => {
159
+ const types = await import('../intake/types.js');
160
+ expect(types).toBeDefined();
161
+ });
162
+ });
@@ -0,0 +1,222 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdirSync, rmSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { createAgentRuntime } from '../runtime/runtime.js';
6
+ import { IntentRouter } from '../control/intent-router.js';
7
+ import type { AgentRuntime } from '../runtime/types.js';
8
+ import type { OperationalMode } from '../control/types.js';
9
+
10
+ describe('IntentRouter', () => {
11
+ let runtime: AgentRuntime;
12
+ let router: IntentRouter;
13
+ let plannerDir: string;
14
+
15
+ beforeEach(() => {
16
+ plannerDir = join(tmpdir(), 'intent-test-' + Date.now());
17
+ mkdirSync(plannerDir, { recursive: true });
18
+ runtime = createAgentRuntime({
19
+ agentId: 'intent-test',
20
+ vaultPath: ':memory:',
21
+ plansPath: join(plannerDir, 'plans.json'),
22
+ });
23
+ router = new IntentRouter(runtime.vault);
24
+ });
25
+
26
+ afterEach(() => {
27
+ runtime.close();
28
+ rmSync(plannerDir, { recursive: true, force: true });
29
+ });
30
+
31
+ // ─── Default Modes ──────────────────────────────────────────────────
32
+
33
+ it('should seed 10 default modes', () => {
34
+ const modes = router.getModes();
35
+ expect(modes).toHaveLength(10);
36
+ });
37
+
38
+ it('should include all expected modes', () => {
39
+ const modeNames = router.getModes().map((m) => m.mode);
40
+ expect(modeNames).toContain('BUILD-MODE');
41
+ expect(modeNames).toContain('FIX-MODE');
42
+ expect(modeNames).toContain('VALIDATE-MODE');
43
+ expect(modeNames).toContain('DESIGN-MODE');
44
+ expect(modeNames).toContain('IMPROVE-MODE');
45
+ expect(modeNames).toContain('DELIVER-MODE');
46
+ expect(modeNames).toContain('EXPLORE-MODE');
47
+ expect(modeNames).toContain('PLAN-MODE');
48
+ expect(modeNames).toContain('REVIEW-MODE');
49
+ expect(modeNames).toContain('GENERAL-MODE');
50
+ });
51
+
52
+ it('should start in GENERAL-MODE', () => {
53
+ expect(router.getCurrentMode()).toBe('GENERAL-MODE');
54
+ });
55
+
56
+ // ─── Intent Classification ──────────────────────────────────────────
57
+
58
+ it('should route "fix this bug" to FIX-MODE', () => {
59
+ const result = router.routeIntent('fix this bug');
60
+ expect(result.intent).toBe('fix');
61
+ expect(result.mode).toBe('FIX-MODE');
62
+ expect(result.confidence).toBeGreaterThan(0);
63
+ expect(result.method).toBe('keyword');
64
+ expect(result.matchedKeywords).toContain('fix');
65
+ expect(result.matchedKeywords).toContain('bug');
66
+ });
67
+
68
+ it('should route "build a new feature" to BUILD-MODE', () => {
69
+ const result = router.routeIntent('build a new feature');
70
+ expect(result.intent).toBe('build');
71
+ expect(result.mode).toBe('BUILD-MODE');
72
+ expect(result.matchedKeywords).toContain('build');
73
+ expect(result.matchedKeywords).toContain('new');
74
+ expect(result.matchedKeywords).toContain('feature');
75
+ });
76
+
77
+ it('should route "refactor the auth module" to IMPROVE-MODE', () => {
78
+ const result = router.routeIntent('refactor the auth module');
79
+ expect(result.intent).toBe('improve');
80
+ expect(result.mode).toBe('IMPROVE-MODE');
81
+ });
82
+
83
+ it('should route "deploy to production" to DELIVER-MODE', () => {
84
+ const result = router.routeIntent('deploy to production');
85
+ expect(result.intent).toBe('deliver');
86
+ expect(result.mode).toBe('DELIVER-MODE');
87
+ });
88
+
89
+ it('should route "review this code" to REVIEW-MODE', () => {
90
+ const result = router.routeIntent('review this code');
91
+ expect(result.intent).toBe('review');
92
+ expect(result.mode).toBe('REVIEW-MODE');
93
+ });
94
+
95
+ it('should route "plan the architect strategy" to PLAN-MODE', () => {
96
+ const result = router.routeIntent('plan the architect strategy');
97
+ expect(result.intent).toBe('plan');
98
+ expect(result.mode).toBe('PLAN-MODE');
99
+ expect(result.matchedKeywords).toContain('plan');
100
+ expect(result.matchedKeywords).toContain('architect');
101
+ expect(result.matchedKeywords).toContain('strategy');
102
+ });
103
+
104
+ it('should fall back to GENERAL-MODE for unrecognized input', () => {
105
+ const result = router.routeIntent('hello there how are you');
106
+ expect(result.intent).toBe('general');
107
+ expect(result.mode).toBe('GENERAL-MODE');
108
+ expect(result.confidence).toBe(0);
109
+ expect(result.matchedKeywords).toEqual([]);
110
+ });
111
+
112
+ it('should update current mode after routing', () => {
113
+ router.routeIntent('fix this bug');
114
+ expect(router.getCurrentMode()).toBe('FIX-MODE');
115
+ });
116
+
117
+ it('should handle case-insensitive matching', () => {
118
+ const result = router.routeIntent('FIX this BUG');
119
+ expect(result.intent).toBe('fix');
120
+ expect(result.mode).toBe('FIX-MODE');
121
+ });
122
+
123
+ it('should cap confidence at 1.0', () => {
124
+ const result = router.routeIntent('fix bug broken error crash issue debug repair janky');
125
+ expect(result.confidence).toBeLessThanOrEqual(1.0);
126
+ });
127
+
128
+ // ─── Mode Management ───────────────────────────────────────────────
129
+
130
+ it('should morph to a specified mode', () => {
131
+ const result = router.morph('BUILD-MODE');
132
+ expect(result.previousMode).toBe('GENERAL-MODE');
133
+ expect(result.currentMode).toBe('BUILD-MODE');
134
+ expect(result.behaviorRules.length).toBeGreaterThan(0);
135
+ expect(router.getCurrentMode()).toBe('BUILD-MODE');
136
+ });
137
+
138
+ it('should throw on morph to unknown mode', () => {
139
+ expect(() => router.morph('UNKNOWN-MODE' as OperationalMode)).toThrow('Unknown mode');
140
+ });
141
+
142
+ it('should get behavior rules for current mode', () => {
143
+ router.morph('FIX-MODE');
144
+ const rules = router.getBehaviorRules();
145
+ expect(rules).toContain('Identify root cause first');
146
+ });
147
+
148
+ it('should get behavior rules for a specific mode', () => {
149
+ const rules = router.getBehaviorRules('DESIGN-MODE');
150
+ expect(rules).toContain('Use semantic tokens');
151
+ });
152
+
153
+ it('should return empty rules for unknown mode', () => {
154
+ const rules = router.getBehaviorRules('NONEXISTENT' as OperationalMode);
155
+ expect(rules).toEqual([]);
156
+ });
157
+
158
+ // ─── Custom Modes ──────────────────────────────────────────────────
159
+
160
+ it('should register a custom mode', () => {
161
+ router.registerMode({
162
+ mode: 'CUSTOM-MODE' as OperationalMode,
163
+ intent: 'general' as const,
164
+ description: 'Custom test mode',
165
+ behaviorRules: ['Custom rule'],
166
+ keywords: ['custom', 'special'],
167
+ });
168
+ const modes = router.getModes();
169
+ expect(modes.length).toBe(11);
170
+ const custom = modes.find((m) => m.mode === 'CUSTOM-MODE');
171
+ expect(custom).toBeDefined();
172
+ expect(custom!.keywords).toContain('custom');
173
+ });
174
+
175
+ it('should route to custom mode', () => {
176
+ router.registerMode({
177
+ mode: 'CUSTOM-MODE' as OperationalMode,
178
+ intent: 'general' as const,
179
+ description: 'Custom test mode',
180
+ behaviorRules: ['Custom rule'],
181
+ keywords: ['custom', 'special'],
182
+ });
183
+ const result = router.routeIntent('do something custom and special');
184
+ expect(result.mode).toBe('CUSTOM-MODE');
185
+ });
186
+
187
+ it('should update mode rules', () => {
188
+ router.updateModeRules('BUILD-MODE', ['New rule 1', 'New rule 2']);
189
+ const rules = router.getBehaviorRules('BUILD-MODE');
190
+ expect(rules).toEqual(['New rule 1', 'New rule 2']);
191
+ });
192
+
193
+ it('should throw on updating unknown mode rules', () => {
194
+ expect(() => router.updateModeRules('NONEXISTENT' as OperationalMode, ['Rule'])).toThrow(
195
+ 'Unknown mode',
196
+ );
197
+ });
198
+
199
+ // ─── Analytics ──────────────────────────────────────────────────────
200
+
201
+ it('should track routing stats', () => {
202
+ router.routeIntent('fix this bug');
203
+ router.routeIntent('build a feature');
204
+ router.routeIntent('fix another error');
205
+ router.routeIntent('hello there');
206
+
207
+ const stats = router.getRoutingStats();
208
+ expect(stats.totalRouted).toBe(4);
209
+ expect(stats.byIntent.fix).toBe(2);
210
+ expect(stats.byIntent.build).toBe(1);
211
+ expect(stats.byIntent.general).toBe(1);
212
+ expect(stats.byMode['FIX-MODE']).toBe(2);
213
+ expect(stats.byMode['BUILD-MODE']).toBe(1);
214
+ });
215
+
216
+ it('should return empty stats initially', () => {
217
+ const stats = router.getRoutingStats();
218
+ expect(stats.totalRouted).toBe(0);
219
+ expect(stats.byIntent).toEqual({});
220
+ expect(stats.byMode).toEqual({});
221
+ });
222
+ });
@@ -0,0 +1,200 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { mkdirSync, rmSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { Logger, createLogger } from '../logging/logger.js';
6
+
7
+ describe('Logger', () => {
8
+ let errorSpy: ReturnType<typeof vi.spyOn>;
9
+ let warnSpy: ReturnType<typeof vi.spyOn>;
10
+
11
+ beforeEach(() => {
12
+ errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
13
+ warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
14
+ });
15
+
16
+ afterEach(() => {
17
+ vi.restoreAllMocks();
18
+ delete process.env.SOLERI_LOG_LEVEL;
19
+ });
20
+
21
+ it('should default to info level', () => {
22
+ const logger = createLogger();
23
+ logger.debug('hidden');
24
+ logger.info('visible');
25
+
26
+ expect(errorSpy).toHaveBeenCalledTimes(1);
27
+ expect(errorSpy).toHaveBeenCalledWith('[Soleri][INFO] visible');
28
+ });
29
+
30
+ it('should suppress messages below configured level', () => {
31
+ const logger = createLogger({ level: 'warn' });
32
+ logger.debug('d');
33
+ logger.info('i');
34
+ logger.warn('w');
35
+ logger.error('e');
36
+
37
+ expect(errorSpy).toHaveBeenCalledTimes(1); // error
38
+ expect(warnSpy).toHaveBeenCalledTimes(1); // warn
39
+ expect(warnSpy).toHaveBeenCalledWith('[Soleri][WARN] w');
40
+ expect(errorSpy).toHaveBeenCalledWith('[Soleri][ERROR] e');
41
+ });
42
+
43
+ it('should output everything at debug level', () => {
44
+ const logger = createLogger({ level: 'debug' });
45
+ logger.debug('d');
46
+ logger.info('i');
47
+ logger.warn('w');
48
+ logger.error('e');
49
+
50
+ // debug, info, error go through console.error; warn goes through console.warn
51
+ expect(errorSpy).toHaveBeenCalledTimes(3);
52
+ expect(warnSpy).toHaveBeenCalledTimes(1);
53
+ });
54
+
55
+ it('should route all output to stderr (not stdout)', () => {
56
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
57
+ const logger = createLogger({ level: 'debug' });
58
+ logger.debug('d');
59
+ logger.info('i');
60
+ logger.warn('w');
61
+ logger.error('e');
62
+
63
+ expect(logSpy).not.toHaveBeenCalled();
64
+ });
65
+
66
+ it('should use custom prefix', () => {
67
+ const logger = createLogger({ prefix: '[my-agent]' });
68
+ logger.info('hello');
69
+
70
+ expect(errorSpy).toHaveBeenCalledWith('[my-agent][INFO] hello');
71
+ });
72
+
73
+ it('should include context in log output', () => {
74
+ const logger = createLogger();
75
+ logger.info('msg', { key: 'value' });
76
+
77
+ expect(errorSpy).toHaveBeenCalledWith('[Soleri][INFO] msg', { key: 'value' });
78
+ });
79
+
80
+ it('should respect SOLERI_LOG_LEVEL env var', () => {
81
+ process.env.SOLERI_LOG_LEVEL = 'error';
82
+ const logger = createLogger();
83
+ logger.info('hidden');
84
+ logger.error('visible');
85
+
86
+ expect(errorSpy).toHaveBeenCalledTimes(1);
87
+ expect(errorSpy).toHaveBeenCalledWith('[Soleri][ERROR] visible');
88
+ });
89
+
90
+ it('should prefer explicit level over env var', () => {
91
+ process.env.SOLERI_LOG_LEVEL = 'error';
92
+ const logger = createLogger({ level: 'debug' });
93
+ logger.debug('visible');
94
+
95
+ expect(errorSpy).toHaveBeenCalledTimes(1);
96
+ });
97
+
98
+ it('should fall back to info level for invalid SOLERI_LOG_LEVEL', () => {
99
+ process.env.SOLERI_LOG_LEVEL = 'verbose'; // invalid
100
+ const logger = createLogger();
101
+ logger.debug('hidden');
102
+ logger.info('visible');
103
+
104
+ expect(errorSpy).toHaveBeenCalledTimes(1);
105
+ expect(errorSpy).toHaveBeenCalledWith('[Soleri][INFO] visible');
106
+ });
107
+
108
+ it('createLogger with no args returns a Logger instance', () => {
109
+ const logger = createLogger();
110
+ expect(logger).toBeInstanceOf(Logger);
111
+ });
112
+ });
113
+
114
+ describe('Logger file logging', () => {
115
+ let tempDir: string;
116
+
117
+ beforeEach(() => {
118
+ vi.spyOn(console, 'error').mockImplementation(() => {});
119
+ vi.spyOn(console, 'warn').mockImplementation(() => {});
120
+ tempDir = join(tmpdir(), `logger-test-${Date.now()}`);
121
+ mkdirSync(tempDir, { recursive: true });
122
+ });
123
+
124
+ afterEach(() => {
125
+ vi.restoreAllMocks();
126
+ rmSync(tempDir, { recursive: true, force: true });
127
+ });
128
+
129
+ it('should create log directory and write log files', () => {
130
+ const logDir = join(tempDir, 'logs');
131
+ const logger = createLogger({ fileLogDir: logDir });
132
+ logger.info('test message');
133
+
134
+ const logFiles = readdirSync(logDir).filter((f) => f.endsWith('.log'));
135
+ expect(logFiles.length).toBe(1);
136
+ expect(logFiles[0]).toMatch(/^agent-\d{4}-\d{2}-\d{2}\.log$/);
137
+
138
+ const content = readFileSync(join(logDir, logFiles[0]), 'utf-8');
139
+ expect(content).toContain('[INFO] test message');
140
+ });
141
+
142
+ it('should include context in file output', () => {
143
+ const logDir = join(tempDir, 'logs');
144
+ const logger = createLogger({ fileLogDir: logDir });
145
+ logger.info('event', { action: 'test' });
146
+
147
+ const logFile = readdirSync(logDir).find((f) => f.endsWith('.log'));
148
+ expect(logFile).toBeDefined();
149
+ const content = readFileSync(join(logDir, logFile!), 'utf-8');
150
+ expect(content).toContain('"action":"test"');
151
+ });
152
+
153
+ it('enableFileLog with custom prefix uses that prefix', () => {
154
+ const logDir = join(tempDir, 'logs');
155
+ const logger = createLogger();
156
+ logger.enableFileLog(logDir, 'custom');
157
+ logger.info('test');
158
+
159
+ const logFile = readdirSync(logDir).find((f) => f.endsWith('.log'));
160
+ expect(logFile).toBeDefined();
161
+ expect(logFile).toMatch(/^custom-/);
162
+ });
163
+
164
+ it('should prune log files older than 7 days', () => {
165
+ const logDir = join(tempDir, 'logs');
166
+ mkdirSync(logDir, { recursive: true });
167
+
168
+ // Create an "old" log file (10 days ago)
169
+ const oldDate = new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
170
+ writeFileSync(join(logDir, `agent-${oldDate}.log`), 'old log\n');
171
+
172
+ // Create a "recent" log file (2 days ago)
173
+ const recentDate = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
174
+ writeFileSync(join(logDir, `agent-${recentDate}.log`), 'recent log\n');
175
+
176
+ // enableFileLog triggers pruning
177
+ const logger = createLogger();
178
+ logger.enableFileLog(logDir);
179
+
180
+ const files = readdirSync(logDir).filter((f) => f.endsWith('.log'));
181
+
182
+ // Old file should be pruned, recent + today should remain
183
+ expect(files).not.toContain(`agent-${oldDate}.log`);
184
+ expect(files).toContain(`agent-${recentDate}.log`);
185
+ });
186
+
187
+ it('should not prune files from different prefix', () => {
188
+ const logDir = join(tempDir, 'logs');
189
+ mkdirSync(logDir, { recursive: true });
190
+
191
+ const oldDate = new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
192
+ writeFileSync(join(logDir, `other-${oldDate}.log`), 'other log\n');
193
+
194
+ const logger = createLogger();
195
+ logger.enableFileLog(logDir);
196
+
197
+ const files = readdirSync(logDir).filter((f) => f.endsWith('.log'));
198
+ expect(files).toContain(`other-${oldDate}.log`);
199
+ });
200
+ });