@soleri/core 9.0.4 → 9.3.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 (744) hide show
  1. package/data/flows/build.flow.yaml +8 -9
  2. package/data/flows/deliver.flow.yaml +9 -10
  3. package/data/flows/design.flow.yaml +3 -4
  4. package/data/flows/enhance.flow.yaml +5 -6
  5. package/data/flows/explore.flow.yaml +3 -4
  6. package/data/flows/fix.flow.yaml +5 -6
  7. package/data/flows/plan.flow.yaml +4 -5
  8. package/data/flows/review.flow.yaml +3 -4
  9. package/dist/brain/intelligence.d.ts +27 -0
  10. package/dist/brain/intelligence.d.ts.map +1 -1
  11. package/dist/brain/intelligence.js +160 -14
  12. package/dist/brain/intelligence.js.map +1 -1
  13. package/dist/brain/learning-radar.d.ts +4 -0
  14. package/dist/brain/learning-radar.d.ts.map +1 -1
  15. package/dist/brain/learning-radar.js +20 -1
  16. package/dist/brain/learning-radar.js.map +1 -1
  17. package/dist/brain/strength-scorer.d.ts +31 -0
  18. package/dist/brain/strength-scorer.d.ts.map +1 -0
  19. package/dist/brain/strength-scorer.js +264 -0
  20. package/dist/brain/strength-scorer.js.map +1 -0
  21. package/dist/chat/agent-loop.d.ts.map +1 -1
  22. package/dist/chat/agent-loop.js +2 -0
  23. package/dist/chat/agent-loop.js.map +1 -1
  24. package/dist/chat/notifications.d.ts.map +1 -1
  25. package/dist/chat/notifications.js +2 -0
  26. package/dist/chat/notifications.js.map +1 -1
  27. package/dist/claudemd/compose.js +1 -1
  28. package/dist/claudemd/compose.js.map +1 -1
  29. package/dist/control/intent-router.d.ts.map +1 -1
  30. package/dist/control/intent-router.js +12 -4
  31. package/dist/control/intent-router.js.map +1 -1
  32. package/dist/curator/contradiction-detector.d.ts +27 -0
  33. package/dist/curator/contradiction-detector.d.ts.map +1 -0
  34. package/dist/curator/contradiction-detector.js +62 -0
  35. package/dist/curator/contradiction-detector.js.map +1 -0
  36. package/dist/curator/curator.d.ts +3 -4
  37. package/dist/curator/curator.d.ts.map +1 -1
  38. package/dist/curator/curator.js +94 -453
  39. package/dist/curator/curator.js.map +1 -1
  40. package/dist/curator/duplicate-detector.d.ts +14 -0
  41. package/dist/curator/duplicate-detector.d.ts.map +1 -0
  42. package/dist/curator/duplicate-detector.js +77 -0
  43. package/dist/curator/duplicate-detector.js.map +1 -0
  44. package/dist/curator/health-audit.d.ts +15 -0
  45. package/dist/curator/health-audit.d.ts.map +1 -0
  46. package/dist/curator/health-audit.js +97 -0
  47. package/dist/curator/health-audit.js.map +1 -0
  48. package/dist/curator/metadata-enricher.d.ts +17 -0
  49. package/dist/curator/metadata-enricher.d.ts.map +1 -0
  50. package/dist/curator/metadata-enricher.js +60 -0
  51. package/dist/curator/metadata-enricher.js.map +1 -0
  52. package/dist/curator/schema.d.ts +7 -0
  53. package/dist/curator/schema.d.ts.map +1 -0
  54. package/dist/curator/schema.js +62 -0
  55. package/dist/curator/schema.js.map +1 -0
  56. package/dist/curator/tag-manager.d.ts +36 -0
  57. package/dist/curator/tag-manager.d.ts.map +1 -0
  58. package/dist/curator/tag-manager.js +78 -0
  59. package/dist/curator/tag-manager.js.map +1 -0
  60. package/dist/engine/bin/soleri-engine.js +24 -3
  61. package/dist/engine/bin/soleri-engine.js.map +1 -1
  62. package/dist/engine/core-ops.d.ts.map +1 -1
  63. package/dist/engine/core-ops.js +23 -8
  64. package/dist/engine/core-ops.js.map +1 -1
  65. package/dist/engine/module-manifest.d.ts.map +1 -1
  66. package/dist/engine/module-manifest.js +42 -2
  67. package/dist/engine/module-manifest.js.map +1 -1
  68. package/dist/engine/register-engine.d.ts.map +1 -1
  69. package/dist/engine/register-engine.js +50 -2
  70. package/dist/engine/register-engine.js.map +1 -1
  71. package/dist/errors/retry.d.ts.map +1 -1
  72. package/dist/errors/retry.js +2 -0
  73. package/dist/errors/retry.js.map +1 -1
  74. package/dist/facades/types.d.ts +1 -1
  75. package/dist/flows/chain-types.d.ts +18 -18
  76. package/dist/flows/gate-evaluator.d.ts.map +1 -1
  77. package/dist/flows/gate-evaluator.js +22 -0
  78. package/dist/flows/gate-evaluator.js.map +1 -1
  79. package/dist/flows/types.d.ts +157 -28
  80. package/dist/flows/types.d.ts.map +1 -1
  81. package/dist/flows/types.js +4 -0
  82. package/dist/flows/types.js.map +1 -1
  83. package/dist/index.d.ts +10 -2
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +9 -1
  86. package/dist/index.js.map +1 -1
  87. package/dist/intake/intake-pipeline.d.ts.map +1 -1
  88. package/dist/intake/intake-pipeline.js +1 -0
  89. package/dist/intake/intake-pipeline.js.map +1 -1
  90. package/dist/intake/text-ingester.d.ts.map +1 -1
  91. package/dist/intake/text-ingester.js +2 -0
  92. package/dist/intake/text-ingester.js.map +1 -1
  93. package/dist/llm/key-pool.d.ts +1 -1
  94. package/dist/llm/key-pool.d.ts.map +1 -1
  95. package/dist/llm/key-pool.js +3 -4
  96. package/dist/llm/key-pool.js.map +1 -1
  97. package/dist/llm/utils.d.ts.map +1 -1
  98. package/dist/llm/utils.js +2 -0
  99. package/dist/llm/utils.js.map +1 -1
  100. package/dist/migrations/migration-runner.test-helpers.d.ts +13 -0
  101. package/dist/migrations/migration-runner.test-helpers.d.ts.map +1 -0
  102. package/dist/migrations/migration-runner.test-helpers.js +47 -0
  103. package/dist/migrations/migration-runner.test-helpers.js.map +1 -0
  104. package/dist/operator/operator-profile.d.ts +44 -0
  105. package/dist/operator/operator-profile.d.ts.map +1 -0
  106. package/dist/operator/operator-profile.js +383 -0
  107. package/dist/operator/operator-profile.js.map +1 -0
  108. package/dist/operator/operator-signals.d.ts +45 -0
  109. package/dist/operator/operator-signals.d.ts.map +1 -0
  110. package/dist/operator/operator-signals.js +228 -0
  111. package/dist/operator/operator-signals.js.map +1 -0
  112. package/dist/operator/operator-types.d.ts +360 -0
  113. package/dist/operator/operator-types.d.ts.map +1 -0
  114. package/dist/operator/operator-types.js +24 -0
  115. package/dist/operator/operator-types.js.map +1 -0
  116. package/dist/packs/types.d.ts +27 -27
  117. package/dist/paths.d.ts +40 -0
  118. package/dist/paths.d.ts.map +1 -0
  119. package/dist/paths.js +98 -0
  120. package/dist/paths.js.map +1 -0
  121. package/dist/persistence/index.d.ts +1 -1
  122. package/dist/persistence/index.d.ts.map +1 -1
  123. package/dist/persistence/index.js +1 -1
  124. package/dist/persistence/index.js.map +1 -1
  125. package/dist/persistence/sqlite-provider.d.ts +2 -0
  126. package/dist/persistence/sqlite-provider.d.ts.map +1 -1
  127. package/dist/persistence/sqlite-provider.js +8 -5
  128. package/dist/persistence/sqlite-provider.js.map +1 -1
  129. package/dist/planning/evidence-collector.d.ts +13 -1
  130. package/dist/planning/evidence-collector.d.ts.map +1 -1
  131. package/dist/planning/evidence-collector.js +33 -0
  132. package/dist/planning/evidence-collector.js.map +1 -1
  133. package/dist/planning/gap-analysis.d.ts +5 -4
  134. package/dist/planning/gap-analysis.d.ts.map +1 -1
  135. package/dist/planning/gap-analysis.js +7 -341
  136. package/dist/planning/gap-analysis.js.map +1 -1
  137. package/dist/planning/gap-passes.d.ts +19 -0
  138. package/dist/planning/gap-passes.d.ts.map +1 -0
  139. package/dist/planning/gap-passes.js +174 -0
  140. package/dist/planning/gap-passes.js.map +1 -0
  141. package/dist/planning/gap-patterns.d.ts +29 -0
  142. package/dist/planning/gap-patterns.d.ts.map +1 -0
  143. package/dist/planning/gap-patterns.js +175 -0
  144. package/dist/planning/gap-patterns.js.map +1 -0
  145. package/dist/planning/gap-types.d.ts +1 -1
  146. package/dist/planning/gap-types.d.ts.map +1 -1
  147. package/dist/planning/gap-types.js +1 -0
  148. package/dist/planning/gap-types.js.map +1 -1
  149. package/dist/planning/github-projection.d.ts +122 -0
  150. package/dist/planning/github-projection.d.ts.map +1 -0
  151. package/dist/planning/github-projection.js +313 -0
  152. package/dist/planning/github-projection.js.map +1 -0
  153. package/dist/planning/impact-analyzer.d.ts +26 -0
  154. package/dist/planning/impact-analyzer.d.ts.map +1 -0
  155. package/dist/planning/impact-analyzer.js +201 -0
  156. package/dist/planning/impact-analyzer.js.map +1 -0
  157. package/dist/planning/plan-lifecycle.d.ts +136 -0
  158. package/dist/planning/plan-lifecycle.d.ts.map +1 -0
  159. package/dist/planning/plan-lifecycle.js +309 -0
  160. package/dist/planning/plan-lifecycle.js.map +1 -0
  161. package/dist/planning/planner-types.d.ts +202 -0
  162. package/dist/planning/planner-types.d.ts.map +1 -0
  163. package/dist/planning/planner-types.js +6 -0
  164. package/dist/planning/planner-types.js.map +1 -0
  165. package/dist/planning/planner.d.ts +31 -383
  166. package/dist/planning/planner.d.ts.map +1 -1
  167. package/dist/planning/planner.js +151 -832
  168. package/dist/planning/planner.js.map +1 -1
  169. package/dist/planning/rationalization-detector.d.ts +32 -0
  170. package/dist/planning/rationalization-detector.d.ts.map +1 -0
  171. package/dist/planning/rationalization-detector.js +89 -0
  172. package/dist/planning/rationalization-detector.js.map +1 -0
  173. package/dist/planning/reconciliation-engine.d.ts +47 -0
  174. package/dist/planning/reconciliation-engine.d.ts.map +1 -0
  175. package/dist/planning/reconciliation-engine.js +128 -0
  176. package/dist/planning/reconciliation-engine.js.map +1 -0
  177. package/dist/planning/task-verifier.d.ts +85 -0
  178. package/dist/planning/task-verifier.d.ts.map +1 -0
  179. package/dist/planning/task-verifier.js +235 -0
  180. package/dist/planning/task-verifier.js.map +1 -0
  181. package/dist/plugins/types.d.ts +4 -4
  182. package/dist/runtime/admin-ops.d.ts +2 -2
  183. package/dist/runtime/admin-ops.d.ts.map +1 -1
  184. package/dist/runtime/admin-ops.js +44 -17
  185. package/dist/runtime/admin-ops.js.map +1 -1
  186. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  187. package/dist/runtime/admin-setup-ops.js +22 -46
  188. package/dist/runtime/admin-setup-ops.js.map +1 -1
  189. package/dist/runtime/archive-ops.d.ts +10 -0
  190. package/dist/runtime/archive-ops.d.ts.map +1 -0
  191. package/dist/runtime/archive-ops.js +310 -0
  192. package/dist/runtime/archive-ops.js.map +1 -0
  193. package/dist/runtime/branching-ops.d.ts +12 -0
  194. package/dist/runtime/branching-ops.d.ts.map +1 -0
  195. package/dist/runtime/branching-ops.js +100 -0
  196. package/dist/runtime/branching-ops.js.map +1 -0
  197. package/dist/runtime/capture-ops.d.ts.map +1 -1
  198. package/dist/runtime/capture-ops.js +42 -7
  199. package/dist/runtime/capture-ops.js.map +1 -1
  200. package/dist/runtime/claude-md-helpers.js +1 -1
  201. package/dist/runtime/claude-md-helpers.js.map +1 -1
  202. package/dist/runtime/context-health.d.ts +31 -0
  203. package/dist/runtime/context-health.d.ts.map +1 -0
  204. package/dist/runtime/context-health.js +57 -0
  205. package/dist/runtime/context-health.js.map +1 -0
  206. package/dist/runtime/facades/archive-facade.d.ts +10 -0
  207. package/dist/runtime/facades/archive-facade.d.ts.map +1 -0
  208. package/dist/runtime/facades/archive-facade.js +11 -0
  209. package/dist/runtime/facades/archive-facade.js.map +1 -0
  210. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  211. package/dist/runtime/facades/brain-facade.js +2 -0
  212. package/dist/runtime/facades/brain-facade.js.map +1 -1
  213. package/dist/runtime/facades/branching-facade.d.ts +7 -0
  214. package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
  215. package/dist/runtime/facades/branching-facade.js +8 -0
  216. package/dist/runtime/facades/branching-facade.js.map +1 -0
  217. package/dist/runtime/facades/chat-facade.d.ts +7 -0
  218. package/dist/runtime/facades/chat-facade.d.ts.map +1 -1
  219. package/dist/runtime/facades/chat-facade.js +15 -800
  220. package/dist/runtime/facades/chat-facade.js.map +1 -1
  221. package/dist/runtime/facades/chat-service-ops.d.ts +9 -0
  222. package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -0
  223. package/dist/runtime/facades/chat-service-ops.js +332 -0
  224. package/dist/runtime/facades/chat-service-ops.js.map +1 -0
  225. package/dist/runtime/facades/chat-session-ops.d.ts +8 -0
  226. package/dist/runtime/facades/chat-session-ops.d.ts.map +1 -0
  227. package/dist/runtime/facades/chat-session-ops.js +136 -0
  228. package/dist/runtime/facades/chat-session-ops.js.map +1 -0
  229. package/dist/runtime/facades/chat-state.d.ts +31 -0
  230. package/dist/runtime/facades/chat-state.d.ts.map +1 -0
  231. package/dist/runtime/facades/chat-state.js +32 -0
  232. package/dist/runtime/facades/chat-state.js.map +1 -0
  233. package/dist/runtime/facades/chat-transport-ops.d.ts +9 -0
  234. package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -0
  235. package/dist/runtime/facades/chat-transport-ops.js +337 -0
  236. package/dist/runtime/facades/chat-transport-ops.js.map +1 -0
  237. package/dist/runtime/facades/control-facade.d.ts.map +1 -1
  238. package/dist/runtime/facades/control-facade.js +4 -1
  239. package/dist/runtime/facades/control-facade.js.map +1 -1
  240. package/dist/runtime/facades/index.d.ts.map +1 -1
  241. package/dist/runtime/facades/index.js +48 -0
  242. package/dist/runtime/facades/index.js.map +1 -1
  243. package/dist/runtime/facades/intake-facade.d.ts +9 -0
  244. package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
  245. package/dist/runtime/facades/intake-facade.js +11 -0
  246. package/dist/runtime/facades/intake-facade.js.map +1 -0
  247. package/dist/runtime/facades/links-facade.d.ts +9 -0
  248. package/dist/runtime/facades/links-facade.d.ts.map +1 -0
  249. package/dist/runtime/facades/links-facade.js +10 -0
  250. package/dist/runtime/facades/links-facade.js.map +1 -0
  251. package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
  252. package/dist/runtime/facades/memory-facade.js +75 -6
  253. package/dist/runtime/facades/memory-facade.js.map +1 -1
  254. package/dist/runtime/facades/operator-facade.d.ts +8 -0
  255. package/dist/runtime/facades/operator-facade.d.ts.map +1 -0
  256. package/dist/runtime/facades/operator-facade.js +220 -0
  257. package/dist/runtime/facades/operator-facade.js.map +1 -0
  258. package/dist/runtime/facades/orchestrate-facade.js +3 -3
  259. package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
  260. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  261. package/dist/runtime/facades/plan-facade.js +42 -6
  262. package/dist/runtime/facades/plan-facade.js.map +1 -1
  263. package/dist/runtime/facades/review-facade.d.ts +7 -0
  264. package/dist/runtime/facades/review-facade.d.ts.map +1 -0
  265. package/dist/runtime/facades/review-facade.js +8 -0
  266. package/dist/runtime/facades/review-facade.js.map +1 -0
  267. package/dist/runtime/facades/sync-facade.d.ts +7 -0
  268. package/dist/runtime/facades/sync-facade.d.ts.map +1 -0
  269. package/dist/runtime/facades/sync-facade.js +8 -0
  270. package/dist/runtime/facades/sync-facade.js.map +1 -0
  271. package/dist/runtime/facades/tier-facade.d.ts +7 -0
  272. package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
  273. package/dist/runtime/facades/tier-facade.js +8 -0
  274. package/dist/runtime/facades/tier-facade.js.map +1 -0
  275. package/dist/runtime/facades/vault-facade.d.ts +12 -1
  276. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  277. package/dist/runtime/facades/vault-facade.js +55 -251
  278. package/dist/runtime/facades/vault-facade.js.map +1 -1
  279. package/dist/runtime/github-integration.d.ts +49 -0
  280. package/dist/runtime/github-integration.d.ts.map +1 -0
  281. package/dist/runtime/github-integration.js +120 -0
  282. package/dist/runtime/github-integration.js.map +1 -0
  283. package/dist/runtime/grading-ops.js +1 -1
  284. package/dist/runtime/grading-ops.js.map +1 -1
  285. package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
  286. package/dist/runtime/memory-extra-ops.js +6 -2
  287. package/dist/runtime/memory-extra-ops.js.map +1 -1
  288. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  289. package/dist/runtime/orchestrate-ops.js +386 -37
  290. package/dist/runtime/orchestrate-ops.js.map +1 -1
  291. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  292. package/dist/runtime/planning-extra-ops.js +69 -4
  293. package/dist/runtime/planning-extra-ops.js.map +1 -1
  294. package/dist/runtime/review-ops.d.ts +10 -0
  295. package/dist/runtime/review-ops.d.ts.map +1 -0
  296. package/dist/runtime/review-ops.js +97 -0
  297. package/dist/runtime/review-ops.js.map +1 -0
  298. package/dist/runtime/runtime.d.ts.map +1 -1
  299. package/dist/runtime/runtime.js +29 -12
  300. package/dist/runtime/runtime.js.map +1 -1
  301. package/dist/runtime/session-briefing.d.ts +3 -0
  302. package/dist/runtime/session-briefing.d.ts.map +1 -1
  303. package/dist/runtime/session-briefing.js +72 -1
  304. package/dist/runtime/session-briefing.js.map +1 -1
  305. package/dist/runtime/sync-ops.d.ts +12 -0
  306. package/dist/runtime/sync-ops.d.ts.map +1 -0
  307. package/dist/runtime/sync-ops.js +288 -0
  308. package/dist/runtime/sync-ops.js.map +1 -0
  309. package/dist/runtime/tier-ops.d.ts +13 -0
  310. package/dist/runtime/tier-ops.d.ts.map +1 -0
  311. package/dist/runtime/tier-ops.js +110 -0
  312. package/dist/runtime/tier-ops.js.map +1 -0
  313. package/dist/runtime/types.d.ts +10 -4
  314. package/dist/runtime/types.d.ts.map +1 -1
  315. package/dist/runtime/vault-extra-ops.d.ts +5 -4
  316. package/dist/runtime/vault-extra-ops.d.ts.map +1 -1
  317. package/dist/runtime/vault-extra-ops.js +5 -300
  318. package/dist/runtime/vault-extra-ops.js.map +1 -1
  319. package/dist/runtime/vault-sharing-ops.d.ts +4 -4
  320. package/dist/runtime/vault-sharing-ops.d.ts.map +1 -1
  321. package/dist/runtime/vault-sharing-ops.js +5 -300
  322. package/dist/runtime/vault-sharing-ops.js.map +1 -1
  323. package/dist/skills/sync-skills.d.ts +27 -0
  324. package/dist/skills/sync-skills.d.ts.map +1 -0
  325. package/dist/skills/sync-skills.js +81 -0
  326. package/dist/skills/sync-skills.js.map +1 -0
  327. package/dist/update-check.d.ts +14 -0
  328. package/dist/update-check.d.ts.map +1 -0
  329. package/dist/update-check.js +96 -0
  330. package/dist/update-check.js.map +1 -0
  331. package/dist/vault/linking.d.ts +10 -12
  332. package/dist/vault/linking.d.ts.map +1 -1
  333. package/dist/vault/linking.js +140 -161
  334. package/dist/vault/linking.js.map +1 -1
  335. package/dist/vault/vault-entries.d.ts +69 -0
  336. package/dist/vault/vault-entries.d.ts.map +1 -0
  337. package/dist/vault/vault-entries.js +299 -0
  338. package/dist/vault/vault-entries.js.map +1 -0
  339. package/dist/vault/vault-interfaces.d.ts +153 -0
  340. package/dist/vault/vault-interfaces.d.ts.map +1 -0
  341. package/dist/vault/vault-interfaces.js +2 -0
  342. package/dist/vault/vault-interfaces.js.map +1 -0
  343. package/dist/vault/vault-maintenance.d.ts +40 -0
  344. package/dist/vault/vault-maintenance.d.ts.map +1 -0
  345. package/dist/vault/vault-maintenance.js +146 -0
  346. package/dist/vault/vault-maintenance.js.map +1 -0
  347. package/dist/vault/vault-markdown-sync.d.ts +22 -0
  348. package/dist/vault/vault-markdown-sync.d.ts.map +1 -0
  349. package/dist/vault/vault-markdown-sync.js +143 -0
  350. package/dist/vault/vault-markdown-sync.js.map +1 -0
  351. package/dist/vault/vault-memories.d.ts +61 -0
  352. package/dist/vault/vault-memories.d.ts.map +1 -0
  353. package/dist/vault/vault-memories.js +242 -0
  354. package/dist/vault/vault-memories.js.map +1 -0
  355. package/dist/vault/vault-schema.d.ts +9 -0
  356. package/dist/vault/vault-schema.d.ts.map +1 -0
  357. package/dist/vault/vault-schema.js +205 -0
  358. package/dist/vault/vault-schema.js.map +1 -0
  359. package/dist/vault/vault.d.ts +29 -81
  360. package/dist/vault/vault.d.ts.map +1 -1
  361. package/dist/vault/vault.js +82 -931
  362. package/dist/vault/vault.js.map +1 -1
  363. package/package.json +7 -7
  364. package/src/agency/agency-manager.test.ts +620 -0
  365. package/src/agency/default-rules.test.ts +236 -0
  366. package/src/{__tests__ → brain}/brain-intelligence.test.ts +37 -14
  367. package/src/{__tests__ → brain}/brain.test.ts +1 -1
  368. package/src/brain/intelligence.ts +196 -15
  369. package/src/brain/learning-radar.ts +22 -1
  370. package/src/{__tests__ → brain}/second-brain-features.test.ts +4 -4
  371. package/src/{__tests__ → brain}/session-lifecycle.test.ts +2 -2
  372. package/src/capabilities/chain-mapping.test.ts +66 -0
  373. package/src/capabilities/registry.test.ts +359 -0
  374. package/src/chat/agent-loop.test.ts +384 -0
  375. package/src/chat/agent-loop.ts +2 -0
  376. package/src/{__tests__ → chat}/chat-differentiators.test.ts +3 -3
  377. package/src/{__tests__ → chat}/chat-enhanced.test.ts +4 -4
  378. package/src/{__tests__ → chat}/chat-transport.test.ts +6 -6
  379. package/src/chat/mcp-bridge.test.ts +178 -0
  380. package/src/chat/notifications.ts +2 -0
  381. package/src/chat/output-compressor.test.ts +164 -0
  382. package/src/claudemd/compose.test.ts +178 -0
  383. package/src/claudemd/compose.ts +1 -1
  384. package/src/claudemd/inject.test.ts +201 -0
  385. package/src/context/context-engine.test.ts +506 -0
  386. package/src/control/identity-manager.test.ts +305 -0
  387. package/src/control/intent-router.test.ts +360 -0
  388. package/src/control/intent-router.ts +13 -4
  389. package/src/curator/classifier.test.ts +110 -0
  390. package/src/curator/contradiction-detector.test.ts +205 -0
  391. package/src/curator/contradiction-detector.ts +87 -0
  392. package/src/{__tests__ → curator}/curator-pipeline-e2e.test.ts +10 -10
  393. package/src/{__tests__ → curator}/curator.test.ts +77 -1
  394. package/src/curator/curator.ts +160 -600
  395. package/src/curator/duplicate-detector.test.ts +245 -0
  396. package/src/curator/duplicate-detector.ts +103 -0
  397. package/src/curator/health-audit.ts +126 -0
  398. package/src/curator/metadata-enricher.ts +84 -0
  399. package/src/curator/quality-gate.test.ts +175 -0
  400. package/src/curator/schema.ts +65 -0
  401. package/src/curator/tag-manager.test.ts +173 -0
  402. package/src/curator/tag-manager.ts +109 -0
  403. package/src/domain-packs/inject-rules.test.ts +117 -0
  404. package/src/domain-packs/knowledge-installer.test.ts +163 -0
  405. package/src/domain-packs/loader.test.ts +86 -0
  406. package/src/domain-packs/pack-runtime.test.ts +140 -0
  407. package/src/domain-packs/skills-installer.test.ts +135 -0
  408. package/src/domain-packs/token-resolver.test.ts +148 -0
  409. package/src/domain-packs/types.test.ts +144 -0
  410. package/src/enforcement/adapters/claude-code.test.ts +216 -0
  411. package/src/enforcement/registry.test.ts +258 -0
  412. package/src/engine/bin/soleri-engine.ts +30 -4
  413. package/src/engine/core-ops.test.ts +254 -0
  414. package/src/engine/core-ops.ts +25 -8
  415. package/src/engine/module-manifest.test.ts +125 -0
  416. package/src/engine/module-manifest.ts +42 -2
  417. package/src/engine/register-engine.test.ts +235 -0
  418. package/src/engine/register-engine.ts +50 -3
  419. package/src/errors/classify.test.ts +203 -0
  420. package/src/errors/retry.test.ts +153 -0
  421. package/src/errors/retry.ts +2 -0
  422. package/src/errors/types.test.ts +108 -0
  423. package/src/events/event-bus.test.ts +149 -0
  424. package/src/extensions/middleware.test.ts +234 -0
  425. package/src/facades/facade-factory.test.ts +470 -0
  426. package/src/flows/chain-runner.test.ts +273 -0
  427. package/src/flows/context-router.test.ts +52 -0
  428. package/src/flows/dispatch-registry.test.ts +128 -0
  429. package/src/flows/epilogue.test.ts +113 -0
  430. package/src/flows/executor.test.ts +263 -0
  431. package/src/flows/gate-evaluator.test.ts +200 -0
  432. package/src/flows/gate-evaluator.ts +23 -0
  433. package/src/flows/types.ts +4 -0
  434. package/src/governance/governance.test.ts +842 -0
  435. package/src/{__tests__ → health}/health-registry.test.ts +75 -55
  436. package/src/health/vault-integrity.test.ts +110 -0
  437. package/src/index.ts +92 -0
  438. package/src/intake/content-classifier.test.ts +279 -0
  439. package/src/intake/dedup-gate.test.ts +147 -0
  440. package/src/intake/intake-pipeline.test.ts +508 -0
  441. package/src/intake/intake-pipeline.ts +1 -0
  442. package/src/intake/text-ingester.test.ts +200 -0
  443. package/src/intake/text-ingester.ts +2 -0
  444. package/src/llm/key-pool.test.ts +234 -0
  445. package/src/llm/key-pool.ts +3 -4
  446. package/src/llm/llm-client.test.ts +342 -0
  447. package/src/llm/oauth-discovery.test.ts +180 -0
  448. package/src/llm/utils.test.ts +371 -0
  449. package/src/llm/utils.ts +2 -0
  450. package/src/{__tests__ → logging}/logger.test.ts +44 -62
  451. package/src/loop/loop-manager.test.ts +515 -0
  452. package/src/migrations/migration-runner.edge-cases.test.ts +314 -0
  453. package/src/migrations/migration-runner.test-helpers.ts +64 -0
  454. package/src/migrations/migration-runner.test.ts +385 -0
  455. package/src/operator/auto-signal-pipeline.test.ts +207 -0
  456. package/src/operator/operator-profile-extended.test.ts +330 -0
  457. package/src/operator/operator-profile.test.ts +332 -0
  458. package/src/operator/operator-profile.ts +485 -0
  459. package/src/operator/operator-signals-extended.test.ts +257 -0
  460. package/src/operator/operator-signals.test.ts +277 -0
  461. package/src/operator/operator-signals.ts +262 -0
  462. package/src/operator/operator-types.ts +444 -0
  463. package/src/operator/prompts/hook-precompact-operator-dispatch.md +98 -0
  464. package/src/operator/prompts/subagent-soft-signal-extractor.md +130 -0
  465. package/src/operator/prompts/subagent-synthesis-cognition.md +190 -0
  466. package/src/operator/prompts/subagent-synthesis-communication.md +146 -0
  467. package/src/operator/prompts/subagent-synthesis-technical.md +170 -0
  468. package/src/operator/prompts/subagent-synthesis-trust.md +149 -0
  469. package/src/{__tests__ → packs}/pack-lockfile.test.ts +3 -3
  470. package/src/{__tests__ → packs}/pack-system.test.ts +2 -2
  471. package/src/paths.ts +115 -0
  472. package/src/persistence/index.ts +1 -1
  473. package/src/persistence/sqlite-provider.test.ts +540 -0
  474. package/src/persistence/sqlite-provider.ts +8 -5
  475. package/src/persona/defaults.test.ts +55 -0
  476. package/src/persona/loader.test.ts +67 -0
  477. package/src/persona/prompt-generator.test.ts +127 -0
  478. package/src/planning/evidence-collector.test.ts +515 -0
  479. package/src/planning/evidence-collector.ts +47 -0
  480. package/src/planning/gap-analysis-alternatives.test.ts +199 -0
  481. package/src/planning/gap-analysis.ts +21 -636
  482. package/src/planning/gap-passes.test.ts +554 -0
  483. package/src/planning/gap-passes.ts +367 -0
  484. package/src/planning/gap-patterns.test.ts +394 -0
  485. package/src/planning/gap-patterns.ts +317 -0
  486. package/src/planning/gap-types.ts +4 -1
  487. package/src/planning/github-projection.test.ts +182 -0
  488. package/src/planning/github-projection.ts +446 -0
  489. package/src/planning/impact-analyzer.test.ts +167 -0
  490. package/src/planning/impact-analyzer.ts +251 -0
  491. package/src/planning/plan-lifecycle.test.ts +379 -0
  492. package/src/planning/plan-lifecycle.ts +377 -0
  493. package/src/planning/planner-types.ts +215 -0
  494. package/src/{__tests__ → planning}/planner.test.ts +179 -15
  495. package/src/planning/planner.ts +221 -1112
  496. package/src/planning/rationalization-detector.test.ts +156 -0
  497. package/src/planning/rationalization-detector.ts +136 -0
  498. package/src/planning/reconciliation-engine.test.ts +158 -0
  499. package/src/planning/reconciliation-engine.ts +161 -0
  500. package/src/planning/task-verifier.test.ts +267 -0
  501. package/src/planning/task-verifier.ts +309 -0
  502. package/src/planning/verification-protocol.test.ts +201 -0
  503. package/src/playbooks/generic/generic-playbooks.test.ts +438 -0
  504. package/src/playbooks/index.test.ts +77 -0
  505. package/src/playbooks/playbook-executor.test.ts +253 -0
  506. package/src/playbooks/playbook-registry.test.ts +232 -0
  507. package/src/playbooks/playbook-seeder.test.ts +153 -0
  508. package/src/plugins/plugin-loader.test.ts +217 -0
  509. package/src/plugins/plugin-registry.test.ts +284 -0
  510. package/src/project/project-registry.test.ts +439 -0
  511. package/src/prompts/parser.test.ts +100 -0
  512. package/src/prompts/template-manager.test.ts +112 -0
  513. package/src/{__tests__ → queue}/async-infrastructure.test.ts +3 -3
  514. package/src/queue/job-queue.test.ts +327 -0
  515. package/src/queue/pipeline-runner.test.ts +209 -0
  516. package/src/runtime/admin-extra-ops.test.ts +513 -0
  517. package/src/runtime/admin-ops.test.ts +255 -0
  518. package/src/runtime/admin-ops.ts +45 -17
  519. package/src/runtime/admin-setup-ops.test.ts +327 -0
  520. package/src/runtime/admin-setup-ops.ts +26 -42
  521. package/src/runtime/archive-ops.test.ts +272 -0
  522. package/src/runtime/archive-ops.ts +347 -0
  523. package/src/runtime/branching-ops.test.ts +144 -0
  524. package/src/runtime/branching-ops.ts +107 -0
  525. package/src/runtime/capture-ops.test.ts +419 -0
  526. package/src/runtime/capture-ops.ts +50 -8
  527. package/src/runtime/chain-ops.test.ts +159 -0
  528. package/src/runtime/claude-md-helpers.test.ts +189 -0
  529. package/src/runtime/claude-md-helpers.ts +1 -1
  530. package/src/runtime/context-health.test.ts +76 -0
  531. package/src/runtime/context-health.ts +83 -0
  532. package/src/runtime/curator-extra-ops.test.ts +204 -0
  533. package/src/runtime/deprecation.test.ts +98 -0
  534. package/src/runtime/domain-ops.test.ts +278 -0
  535. package/src/runtime/facades/admin-facade.test.ts +330 -0
  536. package/src/runtime/facades/agency-facade.test.ts +278 -0
  537. package/src/runtime/facades/archive-facade.test.ts +308 -0
  538. package/src/runtime/facades/archive-facade.ts +14 -0
  539. package/src/runtime/facades/brain-facade.test.ts +818 -0
  540. package/src/runtime/facades/brain-facade.ts +2 -0
  541. package/src/runtime/facades/branching-facade.test.ts +43 -0
  542. package/src/runtime/facades/branching-facade.ts +11 -0
  543. package/src/runtime/facades/chat-facade.test.ts +219 -0
  544. package/src/runtime/facades/chat-facade.ts +15 -906
  545. package/src/runtime/facades/chat-service-ops.test.ts +381 -0
  546. package/src/runtime/facades/chat-service-ops.ts +376 -0
  547. package/src/runtime/facades/chat-session-ops.test.ts +212 -0
  548. package/src/runtime/facades/chat-session-ops.ts +146 -0
  549. package/src/runtime/facades/chat-state.ts +60 -0
  550. package/src/runtime/facades/chat-transport-ops.test.ts +336 -0
  551. package/src/runtime/facades/chat-transport-ops.ts +379 -0
  552. package/src/runtime/facades/context-facade.test.ts +123 -0
  553. package/src/runtime/facades/control-facade.test.ts +436 -0
  554. package/src/runtime/facades/control-facade.ts +6 -1
  555. package/src/runtime/facades/curator-facade.test.ts +303 -0
  556. package/src/runtime/facades/index.ts +48 -0
  557. package/src/runtime/facades/intake-facade.test.ts +215 -0
  558. package/src/runtime/facades/intake-facade.ts +14 -0
  559. package/src/runtime/facades/links-facade.test.ts +203 -0
  560. package/src/runtime/facades/links-facade.ts +13 -0
  561. package/src/runtime/facades/loop-facade.test.ts +262 -0
  562. package/src/runtime/facades/memory-facade.test.ts +283 -0
  563. package/src/runtime/facades/memory-facade.ts +78 -6
  564. package/src/runtime/facades/operator-facade.test.ts +221 -0
  565. package/src/runtime/facades/operator-facade.ts +244 -0
  566. package/src/runtime/facades/orchestrate-facade.test.ts +191 -0
  567. package/src/runtime/facades/orchestrate-facade.ts +3 -3
  568. package/src/runtime/facades/plan-facade.test.ts +283 -0
  569. package/src/runtime/facades/plan-facade.ts +47 -6
  570. package/src/runtime/facades/review-facade.test.ts +82 -0
  571. package/src/runtime/facades/review-facade.ts +11 -0
  572. package/src/runtime/facades/sync-facade.test.ts +113 -0
  573. package/src/runtime/facades/sync-facade.ts +11 -0
  574. package/src/runtime/facades/tier-facade.test.ts +47 -0
  575. package/src/runtime/facades/tier-facade.ts +11 -0
  576. package/src/runtime/facades/vault-facade.test.ts +563 -0
  577. package/src/runtime/facades/vault-facade.ts +66 -265
  578. package/src/runtime/feature-flags.test.ts +140 -0
  579. package/src/runtime/github-integration.test.ts +89 -0
  580. package/src/runtime/github-integration.ts +162 -0
  581. package/src/runtime/grading-ops.test.ts +172 -0
  582. package/src/runtime/grading-ops.ts +1 -1
  583. package/src/runtime/intake-ops.test.ts +261 -0
  584. package/src/runtime/loop-ops.test.ts +248 -0
  585. package/src/runtime/memory-cross-project-ops.test.ts +188 -0
  586. package/src/runtime/memory-extra-ops.test.ts +453 -0
  587. package/src/runtime/memory-extra-ops.ts +6 -2
  588. package/src/runtime/orchestrate-ops.test.ts +302 -0
  589. package/src/runtime/orchestrate-ops.ts +461 -45
  590. package/src/runtime/pack-ops.test.ts +175 -0
  591. package/src/runtime/planning-extra-ops.test.ts +593 -0
  592. package/src/runtime/planning-extra-ops.ts +74 -4
  593. package/src/{__tests__ → runtime}/playbook-ops-execution.test.ts +3 -3
  594. package/src/runtime/playbook-ops.test.ts +285 -0
  595. package/src/runtime/plugin-ops.test.ts +259 -0
  596. package/src/runtime/project-ops.test.ts +255 -0
  597. package/src/runtime/review-ops.test.ts +142 -0
  598. package/src/runtime/review-ops.ts +99 -0
  599. package/src/runtime/runtime.test.ts +363 -0
  600. package/src/runtime/runtime.ts +41 -12
  601. package/src/runtime/session-briefing.test.ts +431 -0
  602. package/src/runtime/session-briefing.ts +86 -1
  603. package/src/runtime/sync-ops.test.ts +212 -0
  604. package/src/runtime/sync-ops.ts +325 -0
  605. package/src/runtime/telemetry-ops.test.ts +157 -0
  606. package/src/runtime/tier-ops.test.ts +159 -0
  607. package/src/runtime/tier-ops.ts +119 -0
  608. package/src/runtime/types.ts +10 -4
  609. package/src/runtime/vault-extra-ops.test.ts +270 -0
  610. package/src/runtime/vault-extra-ops.ts +5 -332
  611. package/src/runtime/vault-linking-ops.test.ts +237 -0
  612. package/src/runtime/vault-sharing-ops.test.ts +127 -0
  613. package/src/runtime/vault-sharing-ops.ts +5 -329
  614. package/src/skills/sync-skills.ts +98 -0
  615. package/src/streams/normalize.test.ts +95 -0
  616. package/src/streams/replayable-stream.test.ts +166 -0
  617. package/src/telemetry/telemetry.test.ts +143 -0
  618. package/src/transport/http-server.test.ts +394 -0
  619. package/src/transport/lsp-server.test.ts +458 -0
  620. package/src/transport/rate-limiter.test.ts +126 -0
  621. package/src/transport/session-manager.test.ts +133 -0
  622. package/src/transport/token-auth.test.ts +136 -0
  623. package/src/transport/ws-server.test.ts +297 -0
  624. package/src/update-check.ts +111 -0
  625. package/src/vault/__tests__/vault-characterization.test.ts +579 -0
  626. package/src/vault/content-hash.test.ts +78 -0
  627. package/src/vault/git-vault-sync.test.ts +234 -0
  628. package/src/vault/knowledge-review.test.ts +269 -0
  629. package/src/vault/linking.test.ts +391 -0
  630. package/src/vault/linking.ts +188 -181
  631. package/src/vault/obsidian-sync.test.ts +345 -0
  632. package/src/vault/playbook.test.ts +152 -0
  633. package/src/vault/scope-detector.test.ts +185 -0
  634. package/src/vault/vault-branching.test.ts +252 -0
  635. package/src/{__tests__ → vault}/vault-connect.test.ts +1 -1
  636. package/src/vault/vault-entries.ts +426 -0
  637. package/src/vault/vault-maintenance.ts +200 -0
  638. package/src/vault/vault-manager.test.ts +206 -0
  639. package/src/vault/vault-markdown-sync.test.ts +203 -0
  640. package/src/vault/vault-markdown-sync.ts +163 -0
  641. package/src/vault/vault-memories.ts +339 -0
  642. package/src/{__tests__ → vault}/vault-scaling.test.ts +1 -1
  643. package/src/vault/vault-schema.ts +238 -0
  644. package/src/{__tests__ → vault}/vault-sharing.test.ts +4 -4
  645. package/src/{__tests__ → vault}/vault.test.ts +2 -2
  646. package/src/vault/vault.ts +87 -1123
  647. package/dist/cognee/client.d.ts +0 -43
  648. package/dist/cognee/client.d.ts.map +0 -1
  649. package/dist/cognee/client.js +0 -375
  650. package/dist/cognee/client.js.map +0 -1
  651. package/dist/cognee/sync-manager.d.ts +0 -153
  652. package/dist/cognee/sync-manager.d.ts.map +0 -1
  653. package/dist/cognee/sync-manager.js +0 -390
  654. package/dist/cognee/sync-manager.js.map +0 -1
  655. package/dist/cognee/types.d.ts +0 -62
  656. package/dist/cognee/types.d.ts.map +0 -1
  657. package/dist/cognee/types.js +0 -3
  658. package/dist/cognee/types.js.map +0 -1
  659. package/dist/governance/index.d.ts +0 -3
  660. package/dist/governance/index.d.ts.map +0 -1
  661. package/dist/governance/index.js +0 -2
  662. package/dist/governance/index.js.map +0 -1
  663. package/dist/health/doctor-checks.d.ts +0 -15
  664. package/dist/health/doctor-checks.d.ts.map +0 -1
  665. package/dist/health/doctor-checks.js +0 -98
  666. package/dist/health/doctor-checks.js.map +0 -1
  667. package/dist/persistence/postgres-provider.d.ts +0 -81
  668. package/dist/persistence/postgres-provider.d.ts.map +0 -1
  669. package/dist/persistence/postgres-provider.js +0 -256
  670. package/dist/persistence/postgres-provider.js.map +0 -1
  671. package/dist/runtime/cognee-sync-ops.d.ts +0 -12
  672. package/dist/runtime/cognee-sync-ops.d.ts.map +0 -1
  673. package/dist/runtime/cognee-sync-ops.js +0 -93
  674. package/dist/runtime/cognee-sync-ops.js.map +0 -1
  675. package/dist/runtime/core-ops.d.ts +0 -23
  676. package/dist/runtime/core-ops.d.ts.map +0 -1
  677. package/dist/runtime/core-ops.js +0 -1296
  678. package/dist/runtime/core-ops.js.map +0 -1
  679. package/dist/runtime/facades/cognee-facade.d.ts +0 -8
  680. package/dist/runtime/facades/cognee-facade.d.ts.map +0 -1
  681. package/dist/runtime/facades/cognee-facade.js +0 -156
  682. package/dist/runtime/facades/cognee-facade.js.map +0 -1
  683. package/src/__tests__/admin-extra-ops.test.ts +0 -484
  684. package/src/__tests__/admin-ops.test.ts +0 -268
  685. package/src/__tests__/admin-setup-ops.test.ts +0 -355
  686. package/src/__tests__/agency-manager.test.ts +0 -374
  687. package/src/__tests__/agent-loop.test.ts +0 -256
  688. package/src/__tests__/capture-ops.test.ts +0 -784
  689. package/src/__tests__/claudemd.test.ts +0 -282
  690. package/src/__tests__/content-hash.test.ts +0 -60
  691. package/src/__tests__/context-engine.test.ts +0 -251
  692. package/src/__tests__/core-ops.test.ts +0 -550
  693. package/src/__tests__/curator-extra-ops.test.ts +0 -383
  694. package/src/__tests__/deprecation.test.ts +0 -78
  695. package/src/__tests__/domain-ops.test.ts +0 -226
  696. package/src/__tests__/domain-packs.test.ts +0 -421
  697. package/src/__tests__/enforcement.test.ts +0 -153
  698. package/src/__tests__/errors.test.ts +0 -388
  699. package/src/__tests__/extensions.test.ts +0 -233
  700. package/src/__tests__/facade-factory.test.ts +0 -271
  701. package/src/__tests__/feature-flags.test.ts +0 -137
  702. package/src/__tests__/flows.test.ts +0 -604
  703. package/src/__tests__/git-vault-sync.test.ts +0 -230
  704. package/src/__tests__/governance.test.ts +0 -522
  705. package/src/__tests__/grading-ops.test.ts +0 -361
  706. package/src/__tests__/identity-manager.test.ts +0 -243
  707. package/src/__tests__/intake-pipeline.test.ts +0 -162
  708. package/src/__tests__/intent-router.test.ts +0 -222
  709. package/src/__tests__/knowledge-review.test.ts +0 -104
  710. package/src/__tests__/llm-client.test.ts +0 -69
  711. package/src/__tests__/llm.test.ts +0 -556
  712. package/src/__tests__/loader.test.ts +0 -176
  713. package/src/__tests__/loop-ops.test.ts +0 -469
  714. package/src/__tests__/lsp-transport.test.ts +0 -442
  715. package/src/__tests__/memory-cross-project-ops.test.ts +0 -248
  716. package/src/__tests__/memory-extra-ops.test.ts +0 -352
  717. package/src/__tests__/migration-runner.test.ts +0 -170
  718. package/src/__tests__/module-manifest-drift.test.ts +0 -59
  719. package/src/__tests__/normalize.test.ts +0 -85
  720. package/src/__tests__/obsidian-sync.test.ts +0 -354
  721. package/src/__tests__/orchestrate-ops.test.ts +0 -289
  722. package/src/__tests__/pack-ops.test.ts +0 -146
  723. package/src/__tests__/persistence.test.ts +0 -291
  724. package/src/__tests__/planning-extra-ops.test.ts +0 -706
  725. package/src/__tests__/playbook-executor.test.ts +0 -249
  726. package/src/__tests__/playbook-registry.test.ts +0 -326
  727. package/src/__tests__/playbook-seeder.test.ts +0 -163
  728. package/src/__tests__/playbook.test.ts +0 -389
  729. package/src/__tests__/plugin-ops.test.ts +0 -411
  730. package/src/__tests__/plugin-system.test.ts +0 -509
  731. package/src/__tests__/project-ops.test.ts +0 -381
  732. package/src/__tests__/replayable-stream.test.ts +0 -177
  733. package/src/__tests__/runtime.test.ts +0 -95
  734. package/src/__tests__/scope-detector.test.ts +0 -121
  735. package/src/__tests__/template-manager.test.ts +0 -222
  736. package/src/__tests__/token-resolver.test.ts +0 -79
  737. package/src/__tests__/transport.test.ts +0 -758
  738. package/src/__tests__/vault-branching.test.ts +0 -274
  739. package/src/__tests__/vault-extra-ops.test.ts +0 -482
  740. package/src/__tests__/vault-integrity.test.ts +0 -71
  741. package/src/__tests__/vault-manager.test.ts +0 -238
  742. package/src/__tests__/ws-transport.test.ts +0 -479
  743. package/src/engine/index.ts +0 -21
  744. package/src/persona/index.ts +0 -9
@@ -0,0 +1,345 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { mkdirSync, rmSync, existsSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { randomUUID } from 'node:crypto';
6
+ import {
7
+ toObsidianMarkdown,
8
+ fromObsidianMarkdown,
9
+ titleToSlug,
10
+ ObsidianSync,
11
+ } from './obsidian-sync.js';
12
+ import type { IntelligenceEntry } from '../intelligence/types.js';
13
+
14
+ function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {
15
+ return {
16
+ id: `test-${randomUUID().slice(0, 8)}`,
17
+ type: 'pattern',
18
+ domain: 'architecture',
19
+ title: 'Test Pattern',
20
+ severity: 'suggestion',
21
+ description: 'A test pattern description.',
22
+ tags: ['testing', 'unit'],
23
+ ...overrides,
24
+ };
25
+ }
26
+
27
+ // ─── Format Helpers ──────────────────────────────────────────────────
28
+
29
+ describe('toObsidianMarkdown', () => {
30
+ it('produces valid frontmatter with id, type, domain', () => {
31
+ const md = toObsidianMarkdown(makeEntry({ id: 'e1', type: 'pattern', domain: 'arch' }));
32
+ expect(md).toContain('---');
33
+ expect(md).toContain('id: "e1"');
34
+ expect(md).toContain('type: "pattern"');
35
+ expect(md).toContain('domain: "arch"');
36
+ });
37
+
38
+ it('includes tags array in frontmatter', () => {
39
+ const md = toObsidianMarkdown(makeEntry({ tags: ['a', 'b'] }));
40
+ expect(md).toContain('tags: ["a", "b"]');
41
+ });
42
+
43
+ it('includes severity when present', () => {
44
+ const md = toObsidianMarkdown(makeEntry({ severity: 'critical' }));
45
+ expect(md).toContain('severity: "critical"');
46
+ });
47
+
48
+ it('includes title as H1 heading', () => {
49
+ const md = toObsidianMarkdown(makeEntry({ title: 'My Pattern' }));
50
+ expect(md).toContain('# My Pattern');
51
+ });
52
+
53
+ it('includes description as body', () => {
54
+ const md = toObsidianMarkdown(makeEntry({ description: 'Body text here.' }));
55
+ expect(md).toContain('Body text here.');
56
+ });
57
+
58
+ it('omits tags line when tags are empty', () => {
59
+ const md = toObsidianMarkdown(makeEntry({ tags: [] }));
60
+ expect(md).not.toContain('tags:');
61
+ });
62
+
63
+ it('includes updated timestamp', () => {
64
+ const md = toObsidianMarkdown(makeEntry());
65
+ expect(md).toMatch(/updated: \d+/);
66
+ });
67
+ });
68
+
69
+ describe('fromObsidianMarkdown', () => {
70
+ it('parses frontmatter and body', () => {
71
+ const md = [
72
+ '---',
73
+ 'id: "e1"',
74
+ 'type: "pattern"',
75
+ 'domain: "arch"',
76
+ 'severity: "warning"',
77
+ 'tags: ["a", "b"]',
78
+ 'updated: 123456',
79
+ '---',
80
+ '',
81
+ '# My Title',
82
+ '',
83
+ 'Some description text.',
84
+ ].join('\n');
85
+
86
+ const parsed = fromObsidianMarkdown(md);
87
+ expect(parsed.id).toBe('e1');
88
+ expect(parsed.type).toBe('pattern');
89
+ expect(parsed.domain).toBe('arch');
90
+ expect(parsed.severity).toBe('warning');
91
+ expect(parsed.tags).toEqual(['a', 'b']);
92
+ expect(parsed.title).toBe('My Title');
93
+ expect(parsed.description).toBe('Some description text.');
94
+ expect(parsed.updated).toBe(123456);
95
+ });
96
+
97
+ it('handles missing frontmatter gracefully', () => {
98
+ const parsed = fromObsidianMarkdown('# Just a Title\n\nSome text.');
99
+ expect(parsed.title).toBe('Just a Title');
100
+ expect(parsed.description).toBe('Some text.');
101
+ });
102
+
103
+ it('infers anti-pattern type from content', () => {
104
+ const md = '# Test\n\nAvoid using inline styles — anti-pattern detected.';
105
+ const parsed = fromObsidianMarkdown(md);
106
+ expect(parsed.type).toBe('anti-pattern');
107
+ });
108
+
109
+ it('infers pattern type from content', () => {
110
+ const md = '# Test\n\nAlways use semantic tokens in your components.';
111
+ const parsed = fromObsidianMarkdown(md);
112
+ expect(parsed.type).toBe('pattern');
113
+ });
114
+
115
+ it('infers rule type from content starting with Rule:', () => {
116
+ // "Rule:" must not also match anti-pattern keywords like "never"
117
+ const md = '# Test\n\nRule: keep components under 400 lines.';
118
+ const parsed = fromObsidianMarkdown(md);
119
+ expect(parsed.type).toBe('rule');
120
+ });
121
+
122
+ it('defaults to concept for ambiguous content', () => {
123
+ const md = '# Test\n\nThis is a general explanation of something.';
124
+ const parsed = fromObsidianMarkdown(md);
125
+ expect(parsed.type).toBe('concept');
126
+ });
127
+
128
+ it('preserves explicit type from frontmatter over inference', () => {
129
+ const md = '---\ntype: "rule"\n---\n# Test\n\nAvoid using inline styles.';
130
+ const parsed = fromObsidianMarkdown(md);
131
+ expect(parsed.type).toBe('rule');
132
+ });
133
+ });
134
+
135
+ describe('titleToSlug', () => {
136
+ it('converts to lowercase kebab-case', () => {
137
+ expect(titleToSlug('Hello World')).toBe('hello-world');
138
+ });
139
+
140
+ it('removes special characters', () => {
141
+ expect(titleToSlug('Use Semantic Tokens!')).toBe('use-semantic-tokens');
142
+ });
143
+
144
+ it('collapses multiple dashes', () => {
145
+ expect(titleToSlug('A -- B')).toBe('a-b');
146
+ });
147
+
148
+ it('trims leading and trailing dashes', () => {
149
+ expect(titleToSlug(' -Hello- ')).toBe('hello');
150
+ });
151
+
152
+ it('truncates to 80 characters', () => {
153
+ const long = 'A'.repeat(100);
154
+ expect(titleToSlug(long).length).toBeLessThanOrEqual(80);
155
+ });
156
+
157
+ it('returns empty string for empty input', () => {
158
+ expect(titleToSlug('')).toBe('');
159
+ });
160
+
161
+ it('handles whitespace-only input', () => {
162
+ expect(titleToSlug(' ')).toBe('');
163
+ });
164
+ });
165
+
166
+ // ─── Sync Engine ─────────────────────────────────────────────────────
167
+
168
+ describe('ObsidianSync', () => {
169
+ let tmpDir: string;
170
+ let obsidianDir: string;
171
+
172
+ function makeMockVault(entryList: IntelligenceEntry[] = []) {
173
+ return {
174
+ list: vi.fn().mockReturnValue(entryList),
175
+ get: vi.fn().mockImplementation((id: string) => entryList.find((e) => e.id === id) ?? null),
176
+ seed: vi.fn().mockReturnValue(1),
177
+ update: vi.fn().mockReturnValue(null),
178
+ } as unknown;
179
+ }
180
+
181
+ beforeEach(() => {
182
+ tmpDir = join(tmpdir(), `obsidian-sync-${randomUUID().slice(0, 8)}`);
183
+ obsidianDir = join(tmpDir, 'obsidian');
184
+ mkdirSync(obsidianDir, { recursive: true });
185
+ });
186
+
187
+ afterEach(() => {
188
+ rmSync(tmpDir, { recursive: true, force: true });
189
+ });
190
+
191
+ // ── export ──────────────────────────────────────────────────────────
192
+
193
+ it('exports entries as markdown files', () => {
194
+ const entries = [makeEntry({ id: 'e1', title: 'First', domain: 'arch' })];
195
+ const sync = new ObsidianSync({ vault: makeMockVault(entries) });
196
+ const result = sync.export(obsidianDir);
197
+ expect(result.exported).toBe(1);
198
+ expect(result.files).toHaveLength(1);
199
+ expect(existsSync(join(obsidianDir, 'arch', 'first.md'))).toBe(true);
200
+ });
201
+
202
+ it('filters by types when specified', () => {
203
+ const entries = [
204
+ makeEntry({ id: 'e1', type: 'pattern' }),
205
+ makeEntry({ id: 'e2', type: 'anti-pattern' }),
206
+ ];
207
+ const sync = new ObsidianSync({ vault: makeMockVault(entries) });
208
+ const result = sync.export(obsidianDir, { types: ['pattern'] });
209
+ expect(result.exported).toBe(1);
210
+ });
211
+
212
+ it('filters by domains when specified', () => {
213
+ const entries = [
214
+ makeEntry({ id: 'e1', domain: 'arch' }),
215
+ makeEntry({ id: 'e2', domain: 'security' }),
216
+ ];
217
+ const sync = new ObsidianSync({ vault: makeMockVault(entries) });
218
+ const result = sync.export(obsidianDir, { domains: ['security'] });
219
+ expect(result.exported).toBe(1);
220
+ });
221
+
222
+ it('skips entries with empty slugs', () => {
223
+ const entries = [makeEntry({ id: 'e1', title: '' })];
224
+ const sync = new ObsidianSync({ vault: makeMockVault(entries) });
225
+ const result = sync.export(obsidianDir);
226
+ expect(result.exported).toBe(0);
227
+ expect(result.skipped).toBe(1);
228
+ });
229
+
230
+ it('does not write files in dry run mode', () => {
231
+ const entries = [makeEntry({ id: 'e1', title: 'DryRun', domain: 'test' })];
232
+ const sync = new ObsidianSync({ vault: makeMockVault(entries) });
233
+ const result = sync.export(obsidianDir, { dryRun: true });
234
+ expect(result.exported).toBe(1);
235
+ expect(existsSync(join(obsidianDir, 'test', 'dryrun.md'))).toBe(false);
236
+ });
237
+
238
+ // ── import ──────────────────────────────────────────────────────────
239
+
240
+ it('imports markdown files into vault', () => {
241
+ const md = [
242
+ '---',
243
+ 'id: "new-entry"',
244
+ 'type: "pattern"',
245
+ 'domain: "test"',
246
+ '---',
247
+ '',
248
+ '# Imported Pattern',
249
+ '',
250
+ 'Description of imported pattern.',
251
+ ].join('\n');
252
+ mkdirSync(join(obsidianDir, 'test'), { recursive: true });
253
+ writeFileSync(join(obsidianDir, 'test', 'imported.md'), md, 'utf-8');
254
+
255
+ const mockVault = makeMockVault([]);
256
+ const sync = new ObsidianSync({ vault: mockVault });
257
+ const result = sync.import(obsidianDir);
258
+ expect(result.imported).toBe(1);
259
+ expect(mockVault.seed).toHaveBeenCalled();
260
+ });
261
+
262
+ it('updates existing entries on import', () => {
263
+ const existing = makeEntry({ id: 'existing', domain: 'test' });
264
+ const md = [
265
+ '---',
266
+ 'id: "existing"',
267
+ 'type: "pattern"',
268
+ '---',
269
+ '',
270
+ '# Updated Title',
271
+ '',
272
+ 'Updated description.',
273
+ ].join('\n');
274
+ mkdirSync(join(obsidianDir, 'test'), { recursive: true });
275
+ writeFileSync(join(obsidianDir, 'test', 'updated.md'), md, 'utf-8');
276
+
277
+ const mockVault = makeMockVault([existing]);
278
+ const sync = new ObsidianSync({ vault: mockVault });
279
+ const result = sync.import(obsidianDir);
280
+ expect(result.updated).toBe(1);
281
+ expect(mockVault.update).toHaveBeenCalledWith(
282
+ 'existing',
283
+ expect.objectContaining({
284
+ title: 'Updated Title',
285
+ }),
286
+ );
287
+ });
288
+
289
+ it('skips files without title or description', () => {
290
+ writeFileSync(join(obsidianDir, 'empty.md'), '---\nid: "x"\n---\n', 'utf-8');
291
+ const sync = new ObsidianSync({ vault: makeMockVault([]) });
292
+ const result = sync.import(obsidianDir);
293
+ expect(result.skipped).toBe(1);
294
+ expect(result.imported).toBe(0);
295
+ });
296
+
297
+ it('uses directory name as domain fallback', () => {
298
+ const md = '# Title\n\nDescription text.';
299
+ mkdirSync(join(obsidianDir, 'custom-domain'), { recursive: true });
300
+ writeFileSync(join(obsidianDir, 'custom-domain', 'entry.md'), md, 'utf-8');
301
+
302
+ const mockVault = makeMockVault([]);
303
+ const sync = new ObsidianSync({ vault: mockVault });
304
+ sync.import(obsidianDir);
305
+ const seedCall = mockVault.seed.mock.calls[0][0][0];
306
+ expect(seedCall.domain).toBe('custom-domain');
307
+ });
308
+
309
+ // ── sync ────────────────────────────────────────────────────────────
310
+
311
+ it('push mode only exports', () => {
312
+ const entries = [makeEntry({ id: 'e1', title: 'Push', domain: 'test' })];
313
+ const sync = new ObsidianSync({ vault: makeMockVault(entries) });
314
+ const result = sync.sync(obsidianDir, { mode: 'push' });
315
+ expect(result.pushed).toBe(1);
316
+ expect(result.pulled).toBe(0);
317
+ expect(result.mode).toBe('push');
318
+ });
319
+
320
+ it('pull mode only imports', () => {
321
+ const md = '# Pull Entry\n\nSome text.';
322
+ mkdirSync(join(obsidianDir, 'test'), { recursive: true });
323
+ writeFileSync(join(obsidianDir, 'test', 'pull.md'), md, 'utf-8');
324
+
325
+ const sync = new ObsidianSync({ vault: makeMockVault([]) });
326
+ const result = sync.sync(obsidianDir, { mode: 'pull' });
327
+ expect(result.pulled).toBe(1);
328
+ expect(result.pushed).toBe(0);
329
+ expect(result.mode).toBe('pull');
330
+ });
331
+
332
+ it('bidirectional mode exports and imports', () => {
333
+ const entries = [makeEntry({ id: 'e1', title: 'Bidir', domain: 'test' })];
334
+ const sync = new ObsidianSync({ vault: makeMockVault(entries) });
335
+ const result = sync.sync(obsidianDir, { mode: 'bidirectional' });
336
+ expect(result.mode).toBe('bidirectional');
337
+ expect(result.pushed).toBe(1);
338
+ });
339
+
340
+ it('defaults to bidirectional mode', () => {
341
+ const sync = new ObsidianSync({ vault: makeMockVault([]) });
342
+ const result = sync.sync(obsidianDir);
343
+ expect(result.mode).toBe('bidirectional');
344
+ });
345
+ });
@@ -0,0 +1,152 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ validatePlaybook,
4
+ parsePlaybookFromEntry,
5
+ type Playbook,
6
+ type PlaybookStep,
7
+ } from './playbook.js';
8
+ import type { IntelligenceEntry } from '../intelligence/types.js';
9
+
10
+ function makeStep(overrides: Partial<PlaybookStep> = {}, index = 1): PlaybookStep {
11
+ return {
12
+ order: index,
13
+ title: `Step ${index}`,
14
+ description: `Description for step ${index}`,
15
+ ...overrides,
16
+ };
17
+ }
18
+
19
+ function makePlaybook(overrides: Partial<Playbook> = {}): Playbook {
20
+ return {
21
+ id: 'pb-1',
22
+ title: 'Test Playbook',
23
+ domain: 'testing',
24
+ description: 'A test playbook',
25
+ steps: [makeStep({}, 1), makeStep({}, 2)],
26
+ tags: ['test'],
27
+ createdAt: 0,
28
+ updatedAt: 0,
29
+ ...overrides,
30
+ };
31
+ }
32
+
33
+ function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {
34
+ return {
35
+ id: 'entry-1',
36
+ type: 'playbook',
37
+ domain: 'testing',
38
+ title: 'Test Playbook',
39
+ severity: 'suggestion',
40
+ description: 'A test playbook entry',
41
+ tags: ['test'],
42
+ context: JSON.stringify({ steps: [makeStep({}, 1)] }),
43
+ ...overrides,
44
+ };
45
+ }
46
+
47
+ describe('validatePlaybook', () => {
48
+ it('returns valid for a well-formed playbook', () => {
49
+ const result = validatePlaybook(makePlaybook());
50
+ expect(result.valid).toBe(true);
51
+ expect(result.errors).toEqual([]);
52
+ });
53
+
54
+ it('rejects empty title', () => {
55
+ const result = validatePlaybook(makePlaybook({ title: '' }));
56
+ expect(result.valid).toBe(false);
57
+ expect(result.errors).toContain('Playbook title must not be empty');
58
+ });
59
+
60
+ it('rejects whitespace-only title', () => {
61
+ const result = validatePlaybook(makePlaybook({ title: ' ' }));
62
+ expect(result.valid).toBe(false);
63
+ expect(result.errors).toContain('Playbook title must not be empty');
64
+ });
65
+
66
+ it('rejects empty steps array', () => {
67
+ const result = validatePlaybook(makePlaybook({ steps: [] }));
68
+ expect(result.valid).toBe(false);
69
+ expect(result.errors).toContain('Playbook must have at least one step');
70
+ });
71
+
72
+ it('rejects out-of-order steps', () => {
73
+ const steps = [makeStep({ order: 2 }, 1), makeStep({ order: 1 }, 2)];
74
+ // Fix: steps[0] has order=2 but expected=1
75
+ const result = validatePlaybook(makePlaybook({ steps }));
76
+ expect(result.valid).toBe(false);
77
+ expect(result.errors[0]).toContain('Step 1 has order 2, expected 1');
78
+ });
79
+
80
+ it('rejects step with empty title', () => {
81
+ const steps = [makeStep({ title: '' }, 1)];
82
+ const result = validatePlaybook(makePlaybook({ steps }));
83
+ expect(result.valid).toBe(false);
84
+ expect(result.errors).toContain('Step 1 title must not be empty');
85
+ });
86
+
87
+ it('rejects step with empty description', () => {
88
+ const steps = [makeStep({ description: '' }, 1)];
89
+ const result = validatePlaybook(makePlaybook({ steps }));
90
+ expect(result.valid).toBe(false);
91
+ expect(result.errors).toContain('Step 1 description must not be empty');
92
+ });
93
+
94
+ it('collects multiple errors', () => {
95
+ const steps = [makeStep({ title: '', description: '' }, 1)];
96
+ const result = validatePlaybook(makePlaybook({ title: '', steps }));
97
+ expect(result.valid).toBe(false);
98
+ expect(result.errors.length).toBeGreaterThanOrEqual(3);
99
+ });
100
+ });
101
+
102
+ describe('parsePlaybookFromEntry', () => {
103
+ it('parses a valid playbook entry', () => {
104
+ const playbook = parsePlaybookFromEntry(makeEntry());
105
+ expect(playbook).not.toBeNull();
106
+ expect(playbook!.id).toBe('entry-1');
107
+ expect(playbook!.title).toBe('Test Playbook');
108
+ expect(playbook!.steps).toHaveLength(1);
109
+ expect(playbook!.steps[0].order).toBe(1);
110
+ });
111
+
112
+ it('returns null for non-playbook type', () => {
113
+ const result = parsePlaybookFromEntry(makeEntry({ type: 'pattern' }));
114
+ expect(result).toBeNull();
115
+ });
116
+
117
+ it('returns null for missing context', () => {
118
+ const result = parsePlaybookFromEntry(makeEntry({ context: undefined }));
119
+ expect(result).toBeNull();
120
+ });
121
+
122
+ it('returns null for invalid JSON context', () => {
123
+ const result = parsePlaybookFromEntry(makeEntry({ context: 'not-json' }));
124
+ expect(result).toBeNull();
125
+ });
126
+
127
+ it('returns null when context has no steps array', () => {
128
+ const result = parsePlaybookFromEntry(makeEntry({ context: JSON.stringify({ other: true }) }));
129
+ expect(result).toBeNull();
130
+ });
131
+
132
+ it('returns null when steps is not an array', () => {
133
+ const result = parsePlaybookFromEntry(
134
+ makeEntry({ context: JSON.stringify({ steps: 'not-array' }) }),
135
+ );
136
+ expect(result).toBeNull();
137
+ });
138
+
139
+ it('sets createdAt and updatedAt to 0', () => {
140
+ const playbook = parsePlaybookFromEntry(makeEntry());
141
+ expect(playbook!.createdAt).toBe(0);
142
+ expect(playbook!.updatedAt).toBe(0);
143
+ });
144
+
145
+ it('preserves domain and tags from the entry', () => {
146
+ const playbook = parsePlaybookFromEntry(
147
+ makeEntry({ domain: 'security', tags: ['sec', 'audit'] }),
148
+ );
149
+ expect(playbook!.domain).toBe('security');
150
+ expect(playbook!.tags).toEqual(['sec', 'audit']);
151
+ });
152
+ });
@@ -0,0 +1,185 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { detectScope, type ScopeInput } from './scope-detector.js';
3
+
4
+ function makeInput(overrides: Partial<ScopeInput> = {}): ScopeInput {
5
+ return {
6
+ title: 'Test Entry',
7
+ description: 'A generic description.',
8
+ ...overrides,
9
+ };
10
+ }
11
+
12
+ describe('detectScope', () => {
13
+ // ── Default behavior ──────────────────────────────────────────────
14
+
15
+ it('defaults to agent tier when no signals detected', () => {
16
+ const result = detectScope(makeInput());
17
+ expect(result.tier).toBe('agent');
18
+ expect(result.confidence).toBe('LOW');
19
+ expect(result.reason).toContain('defaulting to agent');
20
+ });
21
+
22
+ // ── Team detection via content ─────────────────────────────────────
23
+
24
+ it('detects team tier for accessibility content', () => {
25
+ const result = detectScope(
26
+ makeInput({ description: 'Always use ARIA labels for screen reader support' }),
27
+ );
28
+ expect(result.tier).toBe('team');
29
+ expect(result.signals.some((s) => s.tier === 'team' && s.source === 'content')).toBe(true);
30
+ });
31
+
32
+ it('detects team tier for WCAG/contrast content', () => {
33
+ const result = detectScope(
34
+ makeInput({ description: 'Ensure contrast ratio meets WCAG AA standard' }),
35
+ );
36
+ expect(result.tier).toBe('team');
37
+ });
38
+
39
+ it('detects team tier for design system content', () => {
40
+ const result = detectScope(
41
+ makeInput({ description: 'Use semantic token from the design system' }),
42
+ );
43
+ expect(result.tier).toBe('team');
44
+ });
45
+
46
+ it('detects team tier for security content', () => {
47
+ const result = detectScope(
48
+ makeInput({ description: 'Sanitize all user input to prevent XSS attacks' }),
49
+ );
50
+ expect(result.tier).toBe('team');
51
+ });
52
+
53
+ it('detects team tier for touch target / UX content', () => {
54
+ const result = detectScope(
55
+ makeInput({ description: 'Touch target must be 44px minimum per Fitts law' }),
56
+ );
57
+ expect(result.tier).toBe('team');
58
+ });
59
+
60
+ // ── Project detection via content ──────────────────────────────────
61
+
62
+ it('detects project tier for scoped package references', () => {
63
+ const result = detectScope(
64
+ makeInput({ description: 'Import from @soleri/core for vault operations' }),
65
+ );
66
+ expect(result.tier).toBe('project');
67
+ });
68
+
69
+ it('detects project tier for monorepo path references', () => {
70
+ const result = detectScope(
71
+ makeInput({ description: 'The module lives in packages/core/src/vault.ts' }),
72
+ );
73
+ expect(result.tier).toBe('project');
74
+ });
75
+
76
+ it('detects project tier for explicit project references', () => {
77
+ const result = detectScope(
78
+ makeInput({ description: 'This project uses a custom build pipeline' }),
79
+ );
80
+ expect(result.tier).toBe('project');
81
+ });
82
+
83
+ // ── Agent detection via content ────────────────────────────────────
84
+
85
+ it('detects agent tier for personal preferences', () => {
86
+ const result = detectScope(
87
+ makeInput({ description: 'I prefer using vim keybindings in my editor' }),
88
+ );
89
+ expect(result.tier).toBe('agent');
90
+ });
91
+
92
+ it('detects agent tier for home directory paths', () => {
93
+ const result = detectScope(makeInput({ description: 'Config lives in ~/dotfiles/zshrc' }));
94
+ expect(result.tier).toBe('agent');
95
+ });
96
+
97
+ // ── Category signals ───────────────────────────────────────────────
98
+
99
+ it('boosts team tier for team categories', () => {
100
+ const result = detectScope(makeInput({ category: 'accessibility' }));
101
+ expect(result.tier).toBe('team');
102
+ expect(result.signals.some((s) => s.source === 'category')).toBe(true);
103
+ });
104
+
105
+ it('boosts project tier for project categories', () => {
106
+ const result = detectScope(makeInput({ category: 'infrastructure' }));
107
+ expect(result.tier).toBe('project');
108
+ });
109
+
110
+ it('produces no category signal for unknown categories', () => {
111
+ const result = detectScope(makeInput({ category: 'random' }));
112
+ expect(result.signals.filter((s) => s.source === 'category')).toEqual([]);
113
+ });
114
+
115
+ // ── Tag signals ────────────────────────────────────────────────────
116
+
117
+ it('boosts team tier for team tags', () => {
118
+ const result = detectScope(makeInput({ tags: ['universal', 'best-practice'] }));
119
+ expect(result.tier).toBe('team');
120
+ });
121
+
122
+ it('boosts project tier for project tags', () => {
123
+ const result = detectScope(makeInput({ tags: ['project-specific', 'internal'] }));
124
+ expect(result.tier).toBe('project');
125
+ });
126
+
127
+ it('boosts agent tier for agent tags', () => {
128
+ const result = detectScope(makeInput({ tags: ['personal', 'preference'] }));
129
+ expect(result.tier).toBe('agent');
130
+ });
131
+
132
+ it('handles empty tags array', () => {
133
+ const result = detectScope(makeInput({ tags: [] }));
134
+ expect(result.tier).toBe('agent'); // default
135
+ });
136
+
137
+ // ── Confidence levels ──────────────────────────────────────────────
138
+
139
+ it('returns HIGH confidence when strong signals with no competition', () => {
140
+ const result = detectScope(
141
+ makeInput({
142
+ description: 'Accessibility a11y ARIA screen reader WCAG contrast ratio',
143
+ category: 'accessibility',
144
+ tags: ['a11y', 'wcag'],
145
+ }),
146
+ );
147
+ expect(result.tier).toBe('team');
148
+ expect(result.confidence).toBe('HIGH');
149
+ });
150
+
151
+ it('returns MEDIUM confidence for moderate signal competition', () => {
152
+ // Mix of team and project signals
153
+ const result = detectScope(
154
+ makeInput({
155
+ description: 'This project uses type safety patterns from @soleri/core',
156
+ tags: ['pattern'],
157
+ }),
158
+ );
159
+ expect(['HIGH', 'MEDIUM']).toContain(result.confidence);
160
+ });
161
+
162
+ // ── Signal structure ───────────────────────────────────────────────
163
+
164
+ it('includes signals with expected shape', () => {
165
+ const result = detectScope(
166
+ makeInput({ description: 'Use focus ring for keyboard navigation' }),
167
+ );
168
+ for (const signal of result.signals) {
169
+ expect(signal).toHaveProperty('tier');
170
+ expect(signal).toHaveProperty('source');
171
+ expect(signal).toHaveProperty('indicator');
172
+ expect(signal).toHaveProperty('weight');
173
+ expect(signal.weight).toBeGreaterThan(0);
174
+ expect(signal.weight).toBeLessThanOrEqual(1);
175
+ }
176
+ });
177
+
178
+ it('reason summarizes top signals', () => {
179
+ const result = detectScope(
180
+ makeInput({ description: 'Accessibility best practice for a11y compliance' }),
181
+ );
182
+ expect(result.reason.length).toBeGreaterThan(0);
183
+ expect(result.reason).not.toContain('defaulting');
184
+ });
185
+ });