@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,522 @@
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 type { AgentRuntime } from '../runtime/types.js';
7
+
8
+ describe('Governance', () => {
9
+ let runtime: AgentRuntime;
10
+ let plannerDir: string;
11
+
12
+ beforeEach(() => {
13
+ plannerDir = join(tmpdir(), 'governance-test-' + Date.now());
14
+ mkdirSync(plannerDir, { recursive: true });
15
+ runtime = createAgentRuntime({
16
+ agentId: 'test-governance',
17
+ vaultPath: ':memory:',
18
+ plansPath: join(plannerDir, 'plans.json'),
19
+ });
20
+ });
21
+
22
+ afterEach(() => {
23
+ runtime.close();
24
+ rmSync(plannerDir, { recursive: true, force: true });
25
+ });
26
+
27
+ // ─── Policy CRUD ──────────────────────────────────────────────────
28
+
29
+ describe('Policy CRUD', () => {
30
+ it('should return moderate defaults for unknown project', () => {
31
+ const policy = runtime.governance.getPolicy('/unknown');
32
+ expect(policy.projectPath).toBe('/unknown');
33
+ expect(policy.quotas.maxEntriesTotal).toBe(500);
34
+ expect(policy.retention.archiveAfterDays).toBe(90);
35
+ expect(policy.autoCapture.enabled).toBe(true);
36
+ expect(policy.autoCapture.requireReview).toBe(false);
37
+ });
38
+
39
+ it('should persist setPolicy changes', () => {
40
+ runtime.governance.setPolicy('/test', 'quota', {
41
+ maxEntriesTotal: 100,
42
+ maxEntriesPerCategory: 30,
43
+ maxEntriesPerType: 50,
44
+ warnAtPercent: 75,
45
+ });
46
+ const policy = runtime.governance.getPolicy('/test');
47
+ expect(policy.quotas.maxEntriesTotal).toBe(100);
48
+ expect(policy.quotas.warnAtPercent).toBe(75);
49
+ // Other policies should remain default
50
+ expect(policy.retention.archiveAfterDays).toBe(90);
51
+ });
52
+
53
+ it('should applyPreset for all 3 policy types', () => {
54
+ runtime.governance.applyPreset('/test', 'strict', 'admin');
55
+ const policy = runtime.governance.getPolicy('/test');
56
+ expect(policy.quotas.maxEntriesTotal).toBe(200);
57
+ expect(policy.retention.archiveAfterDays).toBe(30);
58
+ expect(policy.autoCapture.requireReview).toBe(true);
59
+ expect(policy.autoCapture.maxPendingProposals).toBe(10);
60
+ });
61
+ });
62
+
63
+ // ─── Evaluation Cascade ───────────────────────────────────────────
64
+
65
+ describe('Evaluation Cascade', () => {
66
+ it('should reject when auto-capture is disabled', () => {
67
+ runtime.governance.setPolicy('/test', 'auto-capture', {
68
+ enabled: false,
69
+ requireReview: false,
70
+ maxPendingProposals: 25,
71
+ autoExpireDays: 14,
72
+ });
73
+ const decision = runtime.governance.evaluateCapture('/test', {
74
+ type: 'pattern',
75
+ category: 'testing',
76
+ });
77
+ expect(decision.allowed).toBe(false);
78
+ expect(decision.action).toBe('reject');
79
+ expect(decision.reason).toContain('disabled');
80
+ });
81
+
82
+ it('should propose when review is required', () => {
83
+ runtime.governance.applyPreset('/test', 'strict'); // requireReview: true
84
+ const decision = runtime.governance.evaluateCapture('/test', {
85
+ type: 'pattern',
86
+ category: 'testing',
87
+ });
88
+ expect(decision.allowed).toBe(false);
89
+ expect(decision.action).toBe('propose');
90
+ });
91
+
92
+ it('should reject when total quota exceeded', () => {
93
+ // Set very low quota
94
+ runtime.governance.setPolicy('/test', 'quota', {
95
+ maxEntriesTotal: 1,
96
+ maxEntriesPerCategory: 100,
97
+ maxEntriesPerType: 100,
98
+ warnAtPercent: 80,
99
+ });
100
+ // Seed entries to exceed quota
101
+ runtime.vault.seed([
102
+ {
103
+ id: 'q1',
104
+ type: 'pattern',
105
+ domain: 'testing',
106
+ title: 'Test',
107
+ severity: 'warning',
108
+ description: 'Test',
109
+ tags: ['t'],
110
+ },
111
+ ]);
112
+ const decision = runtime.governance.evaluateCapture('/test', {
113
+ type: 'pattern',
114
+ category: 'testing',
115
+ });
116
+ expect(decision.allowed).toBe(false);
117
+ expect(decision.action).toBe('reject');
118
+ expect(decision.reason).toContain('Total quota exceeded');
119
+ });
120
+
121
+ it('should quarantine when category quota exceeded', () => {
122
+ runtime.governance.setPolicy('/test', 'quota', {
123
+ maxEntriesTotal: 1000,
124
+ maxEntriesPerCategory: 1,
125
+ maxEntriesPerType: 1000,
126
+ warnAtPercent: 80,
127
+ });
128
+ runtime.vault.seed([
129
+ {
130
+ id: 'cq1',
131
+ type: 'pattern',
132
+ domain: 'testing',
133
+ title: 'Test',
134
+ severity: 'warning',
135
+ description: 'Test',
136
+ tags: ['t'],
137
+ },
138
+ ]);
139
+ const decision = runtime.governance.evaluateCapture('/test', {
140
+ type: 'pattern',
141
+ category: 'testing',
142
+ });
143
+ expect(decision.allowed).toBe(false);
144
+ expect(decision.action).toBe('quarantine');
145
+ });
146
+
147
+ it('should quarantine when type quota exceeded', () => {
148
+ runtime.governance.setPolicy('/test', 'quota', {
149
+ maxEntriesTotal: 1000,
150
+ maxEntriesPerCategory: 1000,
151
+ maxEntriesPerType: 1,
152
+ warnAtPercent: 80,
153
+ });
154
+ runtime.vault.seed([
155
+ {
156
+ id: 'tq1',
157
+ type: 'pattern',
158
+ domain: 'testing',
159
+ title: 'Test',
160
+ severity: 'warning',
161
+ description: 'Test',
162
+ tags: ['t'],
163
+ },
164
+ ]);
165
+ const decision = runtime.governance.evaluateCapture('/test', {
166
+ type: 'pattern',
167
+ category: 'testing',
168
+ });
169
+ expect(decision.allowed).toBe(false);
170
+ expect(decision.action).toBe('quarantine');
171
+ });
172
+
173
+ it('should allow capture when within all quotas', () => {
174
+ const decision = runtime.governance.evaluateCapture('/test', {
175
+ type: 'pattern',
176
+ category: 'testing',
177
+ title: 'A good pattern',
178
+ });
179
+ expect(decision.allowed).toBe(true);
180
+ expect(decision.action).toBe('capture');
181
+ });
182
+ });
183
+
184
+ // ─── Batch Evaluation ─────────────────────────────────────────────
185
+
186
+ describe('Batch Evaluation', () => {
187
+ it('should evaluate multiple entries with running state', () => {
188
+ const results = runtime.governance.evaluateBatch('/test', [
189
+ { type: 'pattern', category: 'a' },
190
+ { type: 'anti-pattern', category: 'b' },
191
+ { type: 'rule', category: 'c' },
192
+ ]);
193
+ expect(results).toHaveLength(3);
194
+ expect(results.every((r) => r.decision.action === 'capture')).toBe(true);
195
+ });
196
+ });
197
+
198
+ // ─── Proposal Lifecycle ───────────────────────────────────────────
199
+
200
+ describe('Proposal Lifecycle', () => {
201
+ it('should create and approve a proposal', () => {
202
+ const id = runtime.governance.propose('/test', {
203
+ title: 'New pattern',
204
+ type: 'pattern',
205
+ category: 'testing',
206
+ data: { description: 'A discovered pattern' },
207
+ });
208
+ expect(id).toBeGreaterThan(0);
209
+
210
+ const approved = runtime.governance.approveProposal(id, 'admin');
211
+ expect(approved).not.toBeNull();
212
+ expect(approved!.status).toBe('approved');
213
+ expect(approved!.decidedBy).toBe('admin');
214
+ });
215
+
216
+ it('should auto-capture entry into vault on approval', () => {
217
+ const id = runtime.governance.propose('/test', {
218
+ entryId: 'approved-entry-1',
219
+ title: 'Approved pattern',
220
+ type: 'pattern',
221
+ category: 'testing',
222
+ data: {
223
+ severity: 'warning',
224
+ description: 'A pattern that was reviewed and approved.',
225
+ tags: ['governance', 'approved'],
226
+ },
227
+ });
228
+
229
+ // Before approval — not in vault
230
+ expect(runtime.vault.get('approved-entry-1')).toBeNull();
231
+
232
+ runtime.governance.approveProposal(id, 'admin');
233
+
234
+ // After approval — entry is in vault
235
+ const entry = runtime.vault.get('approved-entry-1');
236
+ expect(entry).not.toBeNull();
237
+ expect(entry!.domain).toBe('testing');
238
+ expect(entry!.title).toBe('Approved pattern');
239
+ expect(entry!.tags).toContain('governance');
240
+ });
241
+
242
+ it('should generate entry id from proposal id when entryId is missing', () => {
243
+ const id = runtime.governance.propose('/test', {
244
+ title: 'No entry id',
245
+ type: 'rule',
246
+ category: 'styling',
247
+ data: { severity: 'suggestion', description: 'Auto-id test.' },
248
+ });
249
+
250
+ runtime.governance.approveProposal(id);
251
+
252
+ const entry = runtime.vault.get(`proposal-${id}`);
253
+ expect(entry).not.toBeNull();
254
+ expect(entry!.type).toBe('rule');
255
+ expect(entry!.domain).toBe('styling');
256
+ });
257
+
258
+ it('should reject a proposal with a note', () => {
259
+ const id = runtime.governance.propose('/test', {
260
+ title: 'Bad pattern',
261
+ type: 'pattern',
262
+ category: 'testing',
263
+ });
264
+
265
+ const rejected = runtime.governance.rejectProposal(id, 'admin', 'Not useful');
266
+ expect(rejected).not.toBeNull();
267
+ expect(rejected!.status).toBe('rejected');
268
+ expect(rejected!.modificationNote).toBe('Not useful');
269
+ });
270
+
271
+ it('should modify a proposal and mark as modified', () => {
272
+ const id = runtime.governance.propose('/test', {
273
+ title: 'Draft pattern',
274
+ type: 'pattern',
275
+ category: 'testing',
276
+ data: { description: 'Original' },
277
+ });
278
+
279
+ const modified = runtime.governance.modifyProposal(
280
+ id,
281
+ { description: 'Updated description', severity: 'critical' },
282
+ 'editor',
283
+ );
284
+ expect(modified).not.toBeNull();
285
+ expect(modified!.status).toBe('modified');
286
+ expect(modified!.proposedData.description).toBe('Updated description');
287
+ expect(modified!.proposedData.severity).toBe('critical');
288
+ });
289
+
290
+ it('should auto-capture into vault on modify with merged data', () => {
291
+ const id = runtime.governance.propose('/test', {
292
+ entryId: 'mod-cap-1',
293
+ title: 'Modify me',
294
+ type: 'pattern',
295
+ category: 'testing',
296
+ data: { severity: 'warning', description: 'Original desc', tags: ['test'] },
297
+ });
298
+
299
+ // Before modify — not in vault
300
+ expect(runtime.vault.get('mod-cap-1')).toBeNull();
301
+
302
+ runtime.governance.modifyProposal(id, { description: 'Improved desc' }, 'editor');
303
+
304
+ // After modify — captured with merged data
305
+ const entry = runtime.vault.get('mod-cap-1');
306
+ expect(entry).not.toBeNull();
307
+ expect(entry!.description).toBe('Improved desc');
308
+ expect(entry!.domain).toBe('testing');
309
+ });
310
+
311
+ it('should return null when approving nonexistent proposal', () => {
312
+ const result = runtime.governance.approveProposal(999);
313
+ expect(result).toBeNull();
314
+ });
315
+
316
+ it('should not allow double-approval', () => {
317
+ const id = runtime.governance.propose('/test', {
318
+ title: 'Test',
319
+ type: 'pattern',
320
+ category: 'testing',
321
+ });
322
+ runtime.governance.approveProposal(id);
323
+ const second = runtime.governance.approveProposal(id);
324
+ expect(second).toBeNull();
325
+ });
326
+
327
+ it('should list pending proposals', () => {
328
+ runtime.governance.propose('/test', { title: 'P1', type: 'pattern', category: 'a' });
329
+ runtime.governance.propose('/test', { title: 'P2', type: 'rule', category: 'b' });
330
+ runtime.governance.propose('/other', { title: 'P3', type: 'pattern', category: 'c' });
331
+
332
+ const all = runtime.governance.listPendingProposals();
333
+ expect(all).toHaveLength(3);
334
+
335
+ const testOnly = runtime.governance.listPendingProposals('/test');
336
+ expect(testOnly).toHaveLength(2);
337
+ });
338
+ });
339
+
340
+ // ─── Proposal Stats ──────────────────────────────────────────────
341
+
342
+ describe('Proposal Stats', () => {
343
+ it('should compute counts and acceptance rate', () => {
344
+ const id1 = runtime.governance.propose('/test', {
345
+ title: 'P1',
346
+ type: 'pattern',
347
+ category: 'a',
348
+ });
349
+ const id2 = runtime.governance.propose('/test', {
350
+ title: 'P2',
351
+ type: 'pattern',
352
+ category: 'a',
353
+ });
354
+ runtime.governance.propose('/test', { title: 'P3', type: 'rule', category: 'b' });
355
+
356
+ runtime.governance.approveProposal(id1);
357
+ runtime.governance.rejectProposal(id2);
358
+ // id3 remains pending
359
+
360
+ const stats = runtime.governance.getProposalStats('/test');
361
+ expect(stats.total).toBe(3);
362
+ expect(stats.approved).toBe(1);
363
+ expect(stats.rejected).toBe(1);
364
+ expect(stats.pending).toBe(1);
365
+ expect(stats.acceptanceRate).toBe(0.5); // 1 approved / 2 decided
366
+ });
367
+
368
+ it('should compute byCategory breakdown', () => {
369
+ const id1 = runtime.governance.propose('/test', {
370
+ title: 'P1',
371
+ type: 'pattern',
372
+ category: 'styling',
373
+ });
374
+ const id2 = runtime.governance.propose('/test', {
375
+ title: 'P2',
376
+ type: 'pattern',
377
+ category: 'styling',
378
+ });
379
+ runtime.governance.approveProposal(id1);
380
+ runtime.governance.rejectProposal(id2);
381
+
382
+ const stats = runtime.governance.getProposalStats('/test');
383
+ expect(stats.byCategory.styling).toBeDefined();
384
+ expect(stats.byCategory.styling.total).toBe(2);
385
+ expect(stats.byCategory.styling.accepted).toBe(1);
386
+ expect(stats.byCategory.styling.rate).toBe(0.5);
387
+ });
388
+ });
389
+
390
+ // ─── Audit Trail ──────────────────────────────────────────────────
391
+
392
+ describe('Audit Trail', () => {
393
+ it('should log policy changes', () => {
394
+ runtime.governance.setPolicy(
395
+ '/test',
396
+ 'quota',
397
+ {
398
+ maxEntriesTotal: 100,
399
+ maxEntriesPerCategory: 30,
400
+ maxEntriesPerType: 50,
401
+ warnAtPercent: 75,
402
+ },
403
+ 'admin',
404
+ );
405
+
406
+ const trail = runtime.governance.getAuditTrail('/test');
407
+ expect(trail.length).toBeGreaterThan(0);
408
+ expect(trail[0].policyType).toBe('quota');
409
+ expect(trail[0].changedBy).toBe('admin');
410
+ expect(trail[0].oldConfig).toBeNull(); // First set, no previous
411
+ expect(trail[0].newConfig).toHaveProperty('maxEntriesTotal', 100);
412
+ });
413
+
414
+ it('should record old config on policy update', () => {
415
+ runtime.governance.setPolicy('/test', 'quota', { maxEntriesTotal: 100 } as Record<
416
+ string,
417
+ unknown
418
+ >);
419
+ runtime.governance.setPolicy('/test', 'quota', { maxEntriesTotal: 200 } as Record<
420
+ string,
421
+ unknown
422
+ >);
423
+
424
+ const trail = runtime.governance.getAuditTrail('/test');
425
+ expect(trail.length).toBe(2);
426
+ // Both entries present — find the second change (the one with oldConfig)
427
+ const updateEntry = trail.find((t) => t.oldConfig !== null);
428
+ expect(updateEntry).toBeDefined();
429
+ expect(updateEntry!.newConfig).toHaveProperty('maxEntriesTotal', 200);
430
+ expect(updateEntry!.oldConfig).toHaveProperty('maxEntriesTotal', 100);
431
+ });
432
+ });
433
+
434
+ // ─── Dashboard ────────────────────────────────────────────────────
435
+
436
+ describe('Dashboard', () => {
437
+ it('should return combined health view', () => {
438
+ const dashboard = runtime.governance.getDashboard('/test');
439
+ expect(dashboard.vaultSize).toBe(0);
440
+ expect(dashboard.quotaPercent).toBe(0);
441
+ expect(dashboard.pendingProposals).toBe(0);
442
+ expect(dashboard.policySummary.maxEntries).toBe(500);
443
+ expect(dashboard.policySummary.requireReview).toBe(false);
444
+ expect(typeof dashboard.acceptanceRate).toBe('number');
445
+ expect(typeof dashboard.evaluationTrend).toBe('object');
446
+ });
447
+
448
+ it('should reflect vault entries in quota percent', () => {
449
+ // Set low quota for easy percentage
450
+ runtime.governance.setPolicy('/test', 'quota', {
451
+ maxEntriesTotal: 10,
452
+ maxEntriesPerCategory: 100,
453
+ maxEntriesPerType: 100,
454
+ warnAtPercent: 80,
455
+ });
456
+ runtime.vault.seed([
457
+ {
458
+ id: 'dq1',
459
+ type: 'pattern',
460
+ domain: 'd',
461
+ title: 'T',
462
+ severity: 'warning',
463
+ description: 'D',
464
+ tags: ['t'],
465
+ },
466
+ {
467
+ id: 'dq2',
468
+ type: 'pattern',
469
+ domain: 'd',
470
+ title: 'T',
471
+ severity: 'warning',
472
+ description: 'D',
473
+ tags: ['t'],
474
+ },
475
+ {
476
+ id: 'dq3',
477
+ type: 'pattern',
478
+ domain: 'd',
479
+ title: 'T',
480
+ severity: 'warning',
481
+ description: 'D',
482
+ tags: ['t'],
483
+ },
484
+ ]);
485
+
486
+ const dashboard = runtime.governance.getDashboard('/test');
487
+ expect(dashboard.vaultSize).toBe(3);
488
+ expect(dashboard.quotaPercent).toBe(30);
489
+ });
490
+ });
491
+
492
+ // ─── Edge Cases ───────────────────────────────────────────────────
493
+
494
+ describe('Edge Cases', () => {
495
+ it('should handle empty vault gracefully', () => {
496
+ const status = runtime.governance.getQuotaStatus('/empty');
497
+ expect(status.total).toBe(0);
498
+ expect(status.isWarning).toBe(false);
499
+ });
500
+
501
+ it('should handle unknown project defaults', () => {
502
+ const policy = runtime.governance.getPolicy('/nonexistent');
503
+ expect(policy.quotas.maxEntriesTotal).toBe(500);
504
+ });
505
+
506
+ it('should return null for approving nonexistent proposal', () => {
507
+ expect(runtime.governance.approveProposal(9999)).toBeNull();
508
+ });
509
+
510
+ it('should return 0 expired when no stale proposals', () => {
511
+ const expired = runtime.governance.expireStaleProposals(1);
512
+ expect(expired).toBe(0);
513
+ });
514
+
515
+ it('should return empty stats when no proposals exist', () => {
516
+ const stats = runtime.governance.getProposalStats('/test');
517
+ expect(stats.total).toBe(0);
518
+ expect(stats.acceptanceRate).toBe(0);
519
+ expect(Object.keys(stats.byCategory)).toHaveLength(0);
520
+ });
521
+ });
522
+ });