@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
@@ -1,5 +1,7 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
2
  import { Planner } from '../planning/planner.js';
3
+ import type { PlanGap } from '../planning/gap-types.js';
4
+ import { generateGapId } from '../planning/gap-types.js';
3
5
  import { mkdirSync, rmSync } from 'node:fs';
4
6
  import { join } from 'node:path';
5
7
  import { tmpdir } from 'node:os';
@@ -93,7 +95,7 @@ describe('Planner', () => {
93
95
  it('should throw when approving non-draft plan', () => {
94
96
  const plan = planner.create({ objective: 'Already approved', scope: 'test' });
95
97
  planner.approve(plan.id);
96
- expect(() => planner.approve(plan.id)).toThrow('must be');
98
+ expect(() => planner.approve(plan.id)).toThrow('Invalid transition');
97
99
  });
98
100
 
99
101
  it('should throw for unknown plan', () => {
@@ -111,7 +113,7 @@ describe('Planner', () => {
111
113
 
112
114
  it('should throw when executing non-approved plan', () => {
113
115
  const plan = planner.create({ objective: 'Not approved', scope: 'test' });
114
- expect(() => planner.startExecution(plan.id)).toThrow('must be');
116
+ expect(() => planner.startExecution(plan.id)).toThrow('Invalid transition');
115
117
  });
116
118
  });
117
119
 
@@ -176,17 +178,25 @@ describe('Planner', () => {
176
178
  });
177
179
 
178
180
  describe('complete', () => {
179
- it('should transition executing to completed', () => {
181
+ it('should transition reconciling to completed', () => {
180
182
  const plan = planner.create({ objective: 'Complete me', scope: 'test' });
181
183
  planner.approve(plan.id);
182
184
  planner.startExecution(plan.id);
185
+ planner.startReconciliation(plan.id);
183
186
  const completed = planner.complete(plan.id);
184
187
  expect(completed.status).toBe('completed');
185
188
  });
186
189
 
187
- it('should throw when completing non-executing plan', () => {
190
+ it('should throw when completing from executing (must go through reconciling)', () => {
191
+ const plan = planner.create({ objective: 'Not reconciling', scope: 'test' });
192
+ planner.approve(plan.id);
193
+ planner.startExecution(plan.id);
194
+ expect(() => planner.complete(plan.id)).toThrow('Invalid transition');
195
+ });
196
+
197
+ it('should throw when completing from draft', () => {
188
198
  const plan = planner.create({ objective: 'Not executing', scope: 'test' });
189
- expect(() => planner.complete(plan.id)).toThrow('must be');
199
+ expect(() => planner.complete(plan.id)).toThrow('Invalid transition');
190
200
  });
191
201
  });
192
202
 
@@ -208,7 +218,7 @@ describe('Planner', () => {
208
218
  });
209
219
 
210
220
  describe('getActive', () => {
211
- it('should return draft, approved, and executing plans', () => {
221
+ it('should return brainstorming, draft, approved, executing, validating, and reconciling plans', () => {
212
222
  planner.create({ objective: 'Draft', scope: 'a' });
213
223
  const p2 = planner.create({ objective: 'Approved', scope: 'b' });
214
224
  const p3 = planner.create({ objective: 'Executing', scope: 'c' });
@@ -218,6 +228,7 @@ describe('Planner', () => {
218
228
  planner.startExecution(p3.id);
219
229
  planner.approve(p4.id);
220
230
  planner.startExecution(p4.id);
231
+ planner.startReconciliation(p4.id);
221
232
  planner.complete(p4.id);
222
233
  const active = planner.getActive();
223
234
  expect(active).toHaveLength(3);
@@ -225,8 +236,357 @@ describe('Planner', () => {
225
236
  });
226
237
  });
227
238
 
239
+ describe('grade', () => {
240
+ it('should grade a well-formed plan highly on first iteration', () => {
241
+ const plan = planner.create({
242
+ objective: 'Implement a Redis caching layer for the API to reduce DB load by 50%',
243
+ scope: 'Backend API services only. Does not include frontend caching or CDN.',
244
+ decisions: [
245
+ 'Use Redis because it provides sub-millisecond latency and supports TTL natively',
246
+ 'Set TTL to 5 minutes since average data freshness requirement is 10 minutes',
247
+ ],
248
+ tasks: [
249
+ {
250
+ title: 'Set up Redis client',
251
+ description: 'Install and configure Redis connection pool',
252
+ },
253
+ {
254
+ title: 'Add cache middleware',
255
+ description: 'Express middleware for transparent caching',
256
+ },
257
+ {
258
+ title: 'Add invalidation logic',
259
+ description: 'Purge cache on write operations to ensure consistency',
260
+ },
261
+ {
262
+ title: 'Write integration tests',
263
+ description: 'Test cache hit/miss scenarios with Redis',
264
+ },
265
+ { title: 'Add monitoring', description: 'Track and verify cache hit rate metrics' },
266
+ ],
267
+ });
268
+ const check = planner.grade(plan.id);
269
+ // Iteration 1: minor gaps are free, so well-formed plan scores very high
270
+ expect(check.score).toBeGreaterThanOrEqual(95);
271
+ expect(check.grade).toMatch(/^A/);
272
+ expect(check.iteration).toBe(1);
273
+ expect(check.checkId).toMatch(/^chk-/);
274
+ });
275
+
276
+ it('should give low score to empty plan', () => {
277
+ const plan = planner.create({ objective: '', scope: '' });
278
+ const check = planner.grade(plan.id);
279
+ // Missing objective (critical=30) + scope (critical=30) + no tasks (critical=30) = 90 deduction
280
+ expect(check.score).toBeLessThanOrEqual(10);
281
+ expect(check.grade).toBe('F');
282
+ expect(check.gaps.length).toBeGreaterThan(0);
283
+ });
284
+
285
+ it('should use severity-weighted scoring', () => {
286
+ // Plan with 1 critical gap (missing tasks) = -30 points
287
+ const plan = planner.create({
288
+ objective: 'Good objective with some detail',
289
+ scope: 'Narrow scope that excludes nothing important',
290
+ });
291
+ const check = planner.grade(plan.id);
292
+ // No tasks = critical (-30), but also minor gaps from completeness/semantic
293
+ // On iteration 1, minor gaps are free, so only critical gap counts
294
+ expect(check.score).toBe(70); // 100 - 30 (no tasks)
295
+ });
296
+
297
+ it('should detect duplicate task titles', () => {
298
+ const plan = planner.create({
299
+ objective: 'Test duplicate detection in plan grading system',
300
+ scope: 'Testing only, does not affect production',
301
+ decisions: ['Use approach A because it handles edge cases better due to type safety'],
302
+ tasks: [
303
+ { title: 'Same title', description: 'First task with description' },
304
+ { title: 'Same title', description: 'Second task with description' },
305
+ { title: 'Unique title', description: 'Third task with description' },
306
+ ],
307
+ });
308
+ const check = planner.grade(plan.id);
309
+ const dupGap = check.gaps.find((g) => g.description.includes('Duplicate'));
310
+ expect(dupGap).toBeDefined();
311
+ expect(dupGap!.category).toBe('semantic-quality');
312
+ });
313
+
314
+ it('should detect tasks with short/missing descriptions', () => {
315
+ const plan = planner.create({
316
+ objective: 'Test description detection in plan grading system',
317
+ scope: 'Testing only, does not affect production',
318
+ decisions: ['Use assertions because they provide clear feedback on failures'],
319
+ tasks: [
320
+ { title: 'Task with desc', description: 'Has a proper description' },
321
+ { title: 'Task without desc', description: '' },
322
+ { title: 'Another task', description: 'Also has a description' },
323
+ ],
324
+ });
325
+ const check = planner.grade(plan.id);
326
+ const descGap = check.gaps.find((g) => g.description.includes('short descriptions'));
327
+ expect(descGap).toBeDefined();
328
+ expect(descGap!.category).toBe('clarity');
329
+ });
330
+
331
+ it('should track iteration number across multiple grades', () => {
332
+ const plan = planner.create({
333
+ objective: 'Iteration tracking test plan',
334
+ scope: 'Test scope',
335
+ });
336
+ const check1 = planner.grade(plan.id);
337
+ const check2 = planner.grade(plan.id);
338
+ const check3 = planner.grade(plan.id);
339
+ expect(check1.iteration).toBe(1);
340
+ expect(check2.iteration).toBe(2);
341
+ expect(check3.iteration).toBe(3);
342
+ });
343
+
344
+ it('should apply iteration leniency — minor gaps free on iter 1', () => {
345
+ // Plan with only minor gaps: no metrics in objective, no exclusions in scope
346
+ const plan = planner.create({
347
+ objective: 'Build a comprehensive authentication system for the application',
348
+ scope: 'Backend authentication module',
349
+ decisions: ['Use JWT tokens because they are stateless and work well with microservices'],
350
+ tasks: [
351
+ { title: 'Create auth middleware', description: 'JWT validation middleware for Express' },
352
+ {
353
+ title: 'Add login endpoint',
354
+ description: 'POST /auth/login with credential validation',
355
+ },
356
+ {
357
+ title: 'Add refresh tokens',
358
+ description: 'Implement token refresh flow with rotation',
359
+ },
360
+ { title: 'Write auth tests', description: 'Integration tests for all auth endpoints' },
361
+ ],
362
+ });
363
+
364
+ // Iteration 1: minor gaps free → score should be 100
365
+ const check1 = planner.grade(plan.id);
366
+ expect(check1.score).toBe(100);
367
+
368
+ // Iteration 2: minor gaps at half weight → score slightly lower
369
+ const check2 = planner.grade(plan.id);
370
+ expect(check2.score).toBeLessThan(check1.score);
371
+
372
+ // Iteration 3: minor gaps at full weight → score even lower
373
+ const check3 = planner.grade(plan.id);
374
+ expect(check3.score).toBeLessThanOrEqual(check2.score);
375
+ });
376
+
377
+ it('should cap category deductions', () => {
378
+ // Plan with many clarity issues (ambiguous words) — capped at 10
379
+ const plan = planner.create({
380
+ objective: 'Maybe perhaps build something simple and easy, possibly soon, etc',
381
+ scope: 'Various things, probably several modules, somehow',
382
+ decisions: ['Use some appropriate approach because it seems good due to various reasons'],
383
+ tasks: [
384
+ { title: 'Do some stuff', description: 'Maybe implement various things somehow' },
385
+ { title: 'Maybe test', description: 'Perhaps write some tests probably' },
386
+ { title: 'Maybe deploy', description: 'Possibly deploy to various environments soon' },
387
+ ],
388
+ });
389
+ // Grade on iteration 3 to get full minor weight
390
+ planner.grade(plan.id);
391
+ planner.grade(plan.id);
392
+ const check3 = planner.grade(plan.id);
393
+ // Clarity category should be capped at 10 even though there are many ambiguous words
394
+ // Without cap, multiple minor clarity gaps (3x2=6, but also semantic-quality gaps)
395
+ // The key assertion: score shouldn't be destroyed by clarity alone
396
+ expect(check3.score).toBeGreaterThanOrEqual(50);
397
+ });
398
+
399
+ it('should store check in plan history', () => {
400
+ const plan = planner.create({
401
+ objective: 'History test plan objective',
402
+ scope: 'test scope',
403
+ });
404
+ planner.grade(plan.id);
405
+ planner.grade(plan.id);
406
+ const history = planner.getCheckHistory(plan.id);
407
+ expect(history).toHaveLength(2);
408
+ expect(history[0].checkId).not.toBe(history[1].checkId);
409
+ });
410
+
411
+ it('should persist latestCheck', () => {
412
+ const plan = planner.create({
413
+ objective: 'Persist test plan objective',
414
+ scope: 'test scope',
415
+ });
416
+ const check = planner.grade(plan.id);
417
+ const latest = planner.getLatestCheck(plan.id);
418
+ expect(latest).not.toBeNull();
419
+ expect(latest!.checkId).toBe(check.checkId);
420
+ });
421
+
422
+ it('should detect circular dependencies', () => {
423
+ const plan = planner.create({
424
+ objective: 'Circular dependency detection test plan',
425
+ scope: 'Test scope only, does not affect production',
426
+ decisions: ['Test with circular deps because it validates the analysis engine'],
427
+ tasks: [
428
+ { title: 'Task A', description: 'First task in the cycle' },
429
+ { title: 'Task B', description: 'Second task in the cycle' },
430
+ { title: 'Task C', description: 'Third task (not in cycle)' },
431
+ ],
432
+ });
433
+ // Manually create circular deps
434
+ const p = planner.get(plan.id)!;
435
+ p.tasks[0].dependsOn = ['task-2'];
436
+ p.tasks[1].dependsOn = ['task-1'];
437
+ const check = planner.grade(plan.id);
438
+ const circGap = check.gaps.find((g) => g.description.includes('Circular'));
439
+ expect(circGap).toBeDefined();
440
+ expect(circGap!.severity).toBe('critical');
441
+ });
442
+
443
+ it('should use correct grade thresholds: A+=95, A=90, B=80, C=70, D=60', () => {
444
+ // We can verify by creating plans with known gap profiles
445
+ // Plan with 1 major gap = score 85 → grade B (80-89)
446
+ const plan = planner.create({
447
+ objective: 'Test threshold plan with a good objective description',
448
+ scope: 'Narrow scope, does not include anything beyond testing',
449
+ decisions: [], // no decisions = major gap from semantic-quality (-15)
450
+ tasks: [
451
+ { title: 'Task 1', description: 'First detailed task description' },
452
+ { title: 'Task 2', description: 'Second detailed task description' },
453
+ { title: 'Task 3', description: 'Third detailed task description' },
454
+ ],
455
+ });
456
+ const check = planner.grade(plan.id);
457
+ // 1 major gap (no decisions for 3 tasks) = -15, iter 1 minor gaps free
458
+ expect(check.score).toBe(85);
459
+ expect(check.grade).toBe('B');
460
+ });
461
+ });
462
+
463
+ describe('meetsGrade', () => {
464
+ it('should return true when plan meets target grade', () => {
465
+ const plan = planner.create({
466
+ objective: 'Build a comprehensive feature for the testing module',
467
+ scope: 'Testing module only, does not include deployment',
468
+ decisions: ['Use vitest because it integrates well with TypeScript due to native support'],
469
+ tasks: [
470
+ { title: 'Write unit tests', description: 'Cover all edge cases in auth module' },
471
+ { title: 'Write integration tests', description: 'End-to-end API tests for auth flow' },
472
+ { title: 'Add CI pipeline', description: 'Run tests on every PR automatically' },
473
+ { title: 'Add coverage report', description: 'Track and verify code coverage metrics' },
474
+ ],
475
+ });
476
+ const result = planner.meetsGrade(plan.id, 'B');
477
+ expect(result.meets).toBe(true);
478
+ expect(result.check.score).toBeGreaterThanOrEqual(80);
479
+ });
480
+
481
+ it('should return false when plan does not meet target grade', () => {
482
+ const plan = planner.create({ objective: '', scope: '' });
483
+ const result = planner.meetsGrade(plan.id, 'A+');
484
+ expect(result.meets).toBe(false);
485
+ });
486
+ });
487
+
488
+ describe('getCheckHistory', () => {
489
+ it('should return empty array for plan with no checks', () => {
490
+ const plan = planner.create({ objective: 'No checks plan', scope: 'test scope' });
491
+ expect(planner.getCheckHistory(plan.id)).toEqual([]);
492
+ });
493
+
494
+ it('should throw for unknown plan', () => {
495
+ expect(() => planner.getCheckHistory('plan-nonexistent')).toThrow('not found');
496
+ });
497
+ });
498
+
499
+ describe('getLatestCheck', () => {
500
+ it('should return null for plan with no checks', () => {
501
+ const plan = planner.create({ objective: 'No checks plan', scope: 'test scope' });
502
+ expect(planner.getLatestCheck(plan.id)).toBeNull();
503
+ });
504
+
505
+ it('should throw for unknown plan', () => {
506
+ expect(() => planner.getLatestCheck('plan-nonexistent')).toThrow('not found');
507
+ });
508
+ });
509
+
510
+ describe('custom gap analysis passes', () => {
511
+ it('should run custom passes alongside built-in ones', () => {
512
+ const customPass = (plan: { objective: string }): PlanGap[] => {
513
+ if (plan.objective.includes('TODO')) {
514
+ return [
515
+ {
516
+ id: generateGapId(),
517
+ severity: 'major',
518
+ category: 'semantic-quality',
519
+ description: 'Objective contains TODO — not ready for grading.',
520
+ recommendation: 'Resolve all TODOs before grading the plan.',
521
+ location: 'objective',
522
+ _trigger: 'custom_todo_check',
523
+ },
524
+ ];
525
+ }
526
+ return [];
527
+ };
528
+
529
+ const customPlanner = new Planner(join(tempDir, 'custom-plans.json'), {
530
+ customPasses: [customPass],
531
+ });
532
+
533
+ // Plan with TODO should get the custom gap
534
+ const plan = customPlanner.create({
535
+ objective: 'TODO: flesh out this objective for the project',
536
+ scope: 'Backend services only. Does not include frontend.',
537
+ decisions: ['Use TypeScript because it provides type safety due to static analysis'],
538
+ tasks: [
539
+ { title: 'Task A', description: 'First implementation task' },
540
+ { title: 'Task B', description: 'Second implementation task' },
541
+ { title: 'Task C', description: 'Third implementation task' },
542
+ ],
543
+ });
544
+ const check = customPlanner.grade(plan.id);
545
+ const todoGap = check.gaps.find((g) => g._trigger === 'custom_todo_check');
546
+ expect(todoGap).toBeDefined();
547
+ expect(todoGap!.severity).toBe('major');
548
+ // Score should reflect the -15 from the major custom gap
549
+ expect(check.score).toBeLessThan(100);
550
+ });
551
+
552
+ it('should not fire custom gaps when condition is not met', () => {
553
+ const customPass = (plan: { objective: string }): PlanGap[] => {
554
+ if (plan.objective.includes('TODO')) {
555
+ return [
556
+ {
557
+ id: generateGapId(),
558
+ severity: 'major',
559
+ category: 'semantic-quality',
560
+ description: 'Contains TODO',
561
+ recommendation: 'Fix it',
562
+ },
563
+ ];
564
+ }
565
+ return [];
566
+ };
567
+
568
+ const customPlanner = new Planner(join(tempDir, 'custom-plans2.json'), {
569
+ customPasses: [customPass],
570
+ });
571
+
572
+ const plan = customPlanner.create({
573
+ objective: 'Build a clean authentication system for the API endpoints',
574
+ scope: 'Backend services only. Does not include frontend or mobile.',
575
+ decisions: ['Use JWT because it is stateless and works with microservices'],
576
+ tasks: [
577
+ { title: 'Auth middleware', description: 'Create JWT validation middleware' },
578
+ { title: 'Login endpoint', description: 'POST /auth/login with credentials' },
579
+ { title: 'Refresh tokens', description: 'Token refresh flow with rotation' },
580
+ ],
581
+ });
582
+ const check = customPlanner.grade(plan.id);
583
+ const todoGap = check.gaps.find((g) => g.description.includes('TODO'));
584
+ expect(todoGap).toBeUndefined();
585
+ });
586
+ });
587
+
228
588
  describe('full lifecycle', () => {
229
- it('should support draft → approved → executing → completed with tasks', () => {
589
+ it('should support draft → approved → executing → reconciling → completed with tasks', () => {
230
590
  const plan = planner.create({
231
591
  objective: 'Full lifecycle test',
232
592
  scope: 'integration',
@@ -251,11 +611,60 @@ describe('Planner', () => {
251
611
  planner.updateTask(plan.id, 'task-2', 'completed');
252
612
  planner.updateTask(plan.id, 'task-3', 'skipped');
253
613
 
614
+ planner.startReconciliation(plan.id);
615
+ expect(planner.get(plan.id)!.status).toBe('reconciling');
616
+
254
617
  const final = planner.complete(plan.id);
255
618
  expect(final.status).toBe('completed');
256
619
  expect(final.tasks[0].status).toBe('completed');
257
620
  expect(final.tasks[1].status).toBe('completed');
258
621
  expect(final.tasks[2].status).toBe('skipped');
259
622
  });
623
+
624
+ it('should support brainstorming → draft → approved → executing lifecycle', () => {
625
+ const plan = planner.create({
626
+ objective: 'Brainstorming lifecycle test',
627
+ scope: 'integration',
628
+ initialStatus: 'brainstorming',
629
+ });
630
+ expect(plan.status).toBe('brainstorming');
631
+
632
+ planner.promoteToDraft(plan.id);
633
+ expect(planner.get(plan.id)!.status).toBe('draft');
634
+
635
+ planner.approve(plan.id);
636
+ expect(planner.get(plan.id)!.status).toBe('approved');
637
+ });
638
+
639
+ it('should support validating state', () => {
640
+ const plan = planner.create({
641
+ objective: 'Validation lifecycle test',
642
+ scope: 'integration',
643
+ tasks: [{ title: 'Task 1', description: 'Test task' }],
644
+ });
645
+ planner.approve(plan.id);
646
+ planner.startExecution(plan.id);
647
+ planner.startValidation(plan.id);
648
+ expect(planner.get(plan.id)!.status).toBe('validating');
649
+
650
+ // Can update tasks during validation
651
+ planner.updateTask(plan.id, 'task-1', 'completed');
652
+
653
+ // Can go back to executing from validating
654
+ planner.startExecution(plan.id);
655
+ expect(planner.get(plan.id)!.status).toBe('executing');
656
+ });
657
+
658
+ it('should support archiving completed plans', () => {
659
+ const plan = planner.create({ objective: 'Archive test', scope: 'test' });
660
+ planner.approve(plan.id);
661
+ planner.startExecution(plan.id);
662
+ planner.startReconciliation(plan.id);
663
+ planner.complete(plan.id);
664
+
665
+ const archived = planner.archive();
666
+ expect(archived).toHaveLength(1);
667
+ expect(archived[0].status).toBe('archived');
668
+ });
260
669
  });
261
670
  });