@cleocode/core 2026.9.8 → 2026.9.9

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 (561) hide show
  1. package/dist/audit/reconstruct.d.ts +13 -43
  2. package/dist/audit/reconstruct.d.ts.map +1 -1
  3. package/dist/audit/reconstruct.js +295 -290
  4. package/dist/audit/reconstruct.js.map +1 -1
  5. package/dist/bootstrap.d.ts.map +1 -1
  6. package/dist/bootstrap.js +8 -2
  7. package/dist/bootstrap.js.map +1 -1
  8. package/dist/dispatch/mutate-projection.d.ts.map +1 -1
  9. package/dist/dispatch/mutate-projection.js +12 -0
  10. package/dist/dispatch/mutate-projection.js.map +1 -1
  11. package/dist/dispatch/mvi-projection.d.ts +29 -6
  12. package/dist/dispatch/mvi-projection.d.ts.map +1 -1
  13. package/dist/dispatch/mvi-projection.js +109 -139
  14. package/dist/dispatch/mvi-projection.js.map +1 -1
  15. package/dist/docs/docs-read-model.d.ts +3 -2
  16. package/dist/docs/docs-read-model.d.ts.map +1 -1
  17. package/dist/docs/docs-read-model.js +4 -3
  18. package/dist/docs/docs-read-model.js.map +1 -1
  19. package/dist/docs/export-document.js +5100 -2297
  20. package/dist/docs/export-document.js.map +3 -3
  21. package/dist/docs/projection.d.ts +67 -0
  22. package/dist/docs/projection.d.ts.map +1 -0
  23. package/dist/docs/projection.js +370 -0
  24. package/dist/docs/projection.js.map +1 -0
  25. package/dist/doctor/acceptance-drift.d.ts +6 -2
  26. package/dist/doctor/acceptance-drift.d.ts.map +1 -1
  27. package/dist/doctor/acceptance-drift.js +43 -5
  28. package/dist/doctor/acceptance-drift.js.map +1 -1
  29. package/dist/doctor/knowledge-summary.d.ts +41 -0
  30. package/dist/doctor/knowledge-summary.d.ts.map +1 -0
  31. package/dist/doctor/knowledge-summary.js +81 -0
  32. package/dist/doctor/knowledge-summary.js.map +1 -0
  33. package/dist/doctor/knowledge.d.ts +192 -0
  34. package/dist/doctor/knowledge.d.ts.map +1 -0
  35. package/dist/doctor/knowledge.js +1864 -0
  36. package/dist/doctor/knowledge.js.map +1 -0
  37. package/dist/git/work-tree.d.ts +64 -0
  38. package/dist/git/work-tree.d.ts.map +1 -0
  39. package/dist/git/work-tree.js +111 -0
  40. package/dist/git/work-tree.js.map +1 -0
  41. package/dist/hooks/handlers/task-hooks.d.ts +8 -5
  42. package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
  43. package/dist/hooks/handlers/task-hooks.js +15 -60
  44. package/dist/hooks/handlers/task-hooks.js.map +1 -1
  45. package/dist/identity/cleo-identity.d.ts +13 -0
  46. package/dist/identity/cleo-identity.d.ts.map +1 -1
  47. package/dist/identity/cleo-identity.js +20 -6
  48. package/dist/identity/cleo-identity.js.map +1 -1
  49. package/dist/injection.d.ts.map +1 -1
  50. package/dist/injection.js +29 -13
  51. package/dist/injection.js.map +1 -1
  52. package/dist/internal.d.ts +2 -0
  53. package/dist/internal.d.ts.map +1 -1
  54. package/dist/internal.js +2 -0
  55. package/dist/internal.js.map +1 -1
  56. package/dist/lifecycle/verification/satisfies-validator.d.ts.map +1 -1
  57. package/dist/lifecycle/verification/satisfies-validator.js +124 -120
  58. package/dist/lifecycle/verification/satisfies-validator.js.map +1 -1
  59. package/dist/llm/plugin-facade.js +4018 -1726
  60. package/dist/llm/plugin-facade.js.map +3 -3
  61. package/dist/memory/brain-backfill.d.ts +27 -12
  62. package/dist/memory/brain-backfill.d.ts.map +1 -1
  63. package/dist/memory/brain-backfill.js +325 -134
  64. package/dist/memory/brain-backfill.js.map +1 -1
  65. package/dist/memory/brain-doctor.d.ts +21 -0
  66. package/dist/memory/brain-doctor.d.ts.map +1 -1
  67. package/dist/memory/brain-doctor.js +111 -53
  68. package/dist/memory/brain-doctor.js.map +1 -1
  69. package/dist/memory/brain-links.d.ts.map +1 -1
  70. package/dist/memory/brain-links.js +31 -4
  71. package/dist/memory/brain-links.js.map +1 -1
  72. package/dist/memory/brain-reasoning.d.ts.map +1 -1
  73. package/dist/memory/brain-reasoning.js +28 -2
  74. package/dist/memory/brain-reasoning.js.map +1 -1
  75. package/dist/memory/brain-reconciler.d.ts +14 -19
  76. package/dist/memory/brain-reconciler.d.ts.map +1 -1
  77. package/dist/memory/brain-reconciler.js +70 -97
  78. package/dist/memory/brain-reconciler.js.map +1 -1
  79. package/dist/memory/brain-search.d.ts +2 -0
  80. package/dist/memory/brain-search.d.ts.map +1 -1
  81. package/dist/memory/brain-search.js +59 -29
  82. package/dist/memory/brain-search.js.map +1 -1
  83. package/dist/memory/brain-similarity.d.ts.map +1 -1
  84. package/dist/memory/brain-similarity.js +5 -4
  85. package/dist/memory/brain-similarity.js.map +1 -1
  86. package/dist/memory/brain-stub-prune.d.ts +31 -9
  87. package/dist/memory/brain-stub-prune.d.ts.map +1 -1
  88. package/dist/memory/brain-stub-prune.js +65 -18
  89. package/dist/memory/brain-stub-prune.js.map +1 -1
  90. package/dist/memory/brain-writer-handlers.d.ts +10 -1
  91. package/dist/memory/brain-writer-handlers.d.ts.map +1 -1
  92. package/dist/memory/brain-writer-handlers.js +23 -3
  93. package/dist/memory/brain-writer-handlers.js.map +1 -1
  94. package/dist/memory/brain-writer-thread.d.ts +11 -1
  95. package/dist/memory/brain-writer-thread.d.ts.map +1 -1
  96. package/dist/memory/brain-writer-thread.js +87 -20
  97. package/dist/memory/brain-writer-thread.js.map +1 -1
  98. package/dist/memory/brain-writer-worker.js +8 -1
  99. package/dist/memory/brain-writer-worker.js.map +1 -1
  100. package/dist/memory/decision-cross-link.d.ts +39 -0
  101. package/dist/memory/decision-cross-link.d.ts.map +1 -1
  102. package/dist/memory/decision-cross-link.js +316 -0
  103. package/dist/memory/decision-cross-link.js.map +1 -1
  104. package/dist/memory/decisions.d.ts +4 -1
  105. package/dist/memory/decisions.d.ts.map +1 -1
  106. package/dist/memory/decisions.js +7 -24
  107. package/dist/memory/decisions.js.map +1 -1
  108. package/dist/memory/dispatch-trace.d.ts +12 -5
  109. package/dist/memory/dispatch-trace.d.ts.map +1 -1
  110. package/dist/memory/dispatch-trace.js +17 -7
  111. package/dist/memory/dispatch-trace.js.map +1 -1
  112. package/dist/memory/eligibility.d.ts +51 -0
  113. package/dist/memory/eligibility.d.ts.map +1 -0
  114. package/dist/memory/eligibility.js +77 -0
  115. package/dist/memory/eligibility.js.map +1 -0
  116. package/dist/memory/engine-compat.d.ts +2 -0
  117. package/dist/memory/engine-compat.d.ts.map +1 -1
  118. package/dist/memory/engine-compat.js +10 -0
  119. package/dist/memory/engine-compat.js.map +1 -1
  120. package/dist/memory/extraction-gate.d.ts +21 -7
  121. package/dist/memory/extraction-gate.d.ts.map +1 -1
  122. package/dist/memory/extraction-gate.js +178 -216
  123. package/dist/memory/extraction-gate.js.map +1 -1
  124. package/dist/memory/graph-auto-populate.d.ts +38 -5
  125. package/dist/memory/graph-auto-populate.d.ts.map +1 -1
  126. package/dist/memory/graph-auto-populate.js +182 -60
  127. package/dist/memory/graph-auto-populate.js.map +1 -1
  128. package/dist/memory/graph-memory-bridge.d.ts +14 -1
  129. package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
  130. package/dist/memory/graph-memory-bridge.js +66 -28
  131. package/dist/memory/graph-memory-bridge.js.map +1 -1
  132. package/dist/memory/index.d.ts +1 -19
  133. package/dist/memory/index.d.ts.map +1 -1
  134. package/dist/memory/index.js +1 -50
  135. package/dist/memory/index.js.map +1 -1
  136. package/dist/memory/learnings.d.ts.map +1 -1
  137. package/dist/memory/learnings.js +2 -23
  138. package/dist/memory/learnings.js.map +1 -1
  139. package/dist/memory/manifest-filter.d.ts +21 -0
  140. package/dist/memory/manifest-filter.d.ts.map +1 -0
  141. package/dist/memory/manifest-filter.js +51 -0
  142. package/dist/memory/manifest-filter.js.map +1 -0
  143. package/dist/memory/manifest-ingestion.d.ts +28 -30
  144. package/dist/memory/manifest-ingestion.d.ts.map +1 -1
  145. package/dist/memory/manifest-ingestion.js +104 -235
  146. package/dist/memory/manifest-ingestion.js.map +1 -1
  147. package/dist/memory/observer-reflector.d.ts +2 -0
  148. package/dist/memory/observer-reflector.d.ts.map +1 -1
  149. package/dist/memory/observer-reflector.js +6 -49
  150. package/dist/memory/observer-reflector.js.map +1 -1
  151. package/dist/memory/patterns.d.ts +10 -0
  152. package/dist/memory/patterns.d.ts.map +1 -1
  153. package/dist/memory/patterns.js +25 -33
  154. package/dist/memory/patterns.js.map +1 -1
  155. package/dist/memory/pipeline-manifest-sqlite.d.ts +72 -9
  156. package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
  157. package/dist/memory/pipeline-manifest-sqlite.js +508 -412
  158. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
  159. package/dist/memory/retrieval/build-retrieval-bundle.d.ts.map +1 -1
  160. package/dist/memory/retrieval/build-retrieval-bundle.js +16 -15
  161. package/dist/memory/retrieval/build-retrieval-bundle.js.map +1 -1
  162. package/dist/memory/retrieval/fetch.d.ts +7 -0
  163. package/dist/memory/retrieval/fetch.d.ts.map +1 -1
  164. package/dist/memory/retrieval/fetch.js +14 -11
  165. package/dist/memory/retrieval/fetch.js.map +1 -1
  166. package/dist/memory/retrieval/observe.d.ts +7 -1
  167. package/dist/memory/retrieval/observe.d.ts.map +1 -1
  168. package/dist/memory/retrieval/observe.js +58 -4
  169. package/dist/memory/retrieval/observe.js.map +1 -1
  170. package/dist/memory/retrieval/search.d.ts +14 -1
  171. package/dist/memory/retrieval/search.d.ts.map +1 -1
  172. package/dist/memory/retrieval/search.js +133 -69
  173. package/dist/memory/retrieval/search.js.map +1 -1
  174. package/dist/memory/retrieval/telemetry.d.ts +31 -0
  175. package/dist/memory/retrieval/telemetry.d.ts.map +1 -0
  176. package/dist/memory/retrieval/telemetry.js +53 -0
  177. package/dist/memory/retrieval/telemetry.js.map +1 -0
  178. package/dist/nexus/analyze-orchestrator.d.ts +41 -9
  179. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  180. package/dist/nexus/analyze-orchestrator.js +257 -58
  181. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  182. package/dist/nexus/api-contracts.d.ts +2 -6
  183. package/dist/nexus/api-contracts.d.ts.map +1 -1
  184. package/dist/nexus/api-contracts.js +11 -2
  185. package/dist/nexus/api-contracts.js.map +1 -1
  186. package/dist/nexus/context.d.ts.map +1 -1
  187. package/dist/nexus/context.js +14 -37
  188. package/dist/nexus/context.js.map +1 -1
  189. package/dist/nexus/diff.d.ts.map +1 -1
  190. package/dist/nexus/diff.js +2 -1
  191. package/dist/nexus/diff.js.map +1 -1
  192. package/dist/nexus/identity.d.ts +29 -3
  193. package/dist/nexus/identity.d.ts.map +1 -1
  194. package/dist/nexus/identity.js +63 -12
  195. package/dist/nexus/identity.js.map +1 -1
  196. package/dist/nexus/impact.d.ts +21 -19
  197. package/dist/nexus/impact.d.ts.map +1 -1
  198. package/dist/nexus/impact.js +96 -192
  199. package/dist/nexus/impact.js.map +1 -1
  200. package/dist/nexus/knowledge.d.ts +80 -0
  201. package/dist/nexus/knowledge.d.ts.map +1 -0
  202. package/dist/nexus/knowledge.js +786 -0
  203. package/dist/nexus/knowledge.js.map +1 -0
  204. package/dist/nexus/living-brain.d.ts +8 -5
  205. package/dist/nexus/living-brain.d.ts.map +1 -1
  206. package/dist/nexus/living-brain.js +252 -188
  207. package/dist/nexus/living-brain.js.map +1 -1
  208. package/dist/nexus/registry.d.ts +11 -2
  209. package/dist/nexus/registry.d.ts.map +1 -1
  210. package/dist/nexus/registry.js +144 -128
  211. package/dist/nexus/registry.js.map +1 -1
  212. package/dist/nexus/source-roots.d.ts +16 -0
  213. package/dist/nexus/source-roots.d.ts.map +1 -0
  214. package/dist/nexus/source-roots.js +174 -0
  215. package/dist/nexus/source-roots.js.map +1 -0
  216. package/dist/nexus/task-evidence.d.ts +22 -0
  217. package/dist/nexus/task-evidence.d.ts.map +1 -0
  218. package/dist/nexus/task-evidence.js +210 -0
  219. package/dist/nexus/task-evidence.js.map +1 -0
  220. package/dist/nexus/tasks-bridge.d.ts +14 -7
  221. package/dist/nexus/tasks-bridge.d.ts.map +1 -1
  222. package/dist/nexus/tasks-bridge.js +81 -40
  223. package/dist/nexus/tasks-bridge.js.map +1 -1
  224. package/dist/orchestrate/lifecycle-ops.d.ts.map +1 -1
  225. package/dist/orchestrate/lifecycle-ops.js +170 -120
  226. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  227. package/dist/orchestrate/query-ops.d.ts +6 -7
  228. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  229. package/dist/orchestrate/query-ops.js +509 -532
  230. package/dist/orchestrate/query-ops.js.map +1 -1
  231. package/dist/orchestration/bootstrap.d.ts +15 -1
  232. package/dist/orchestration/bootstrap.d.ts.map +1 -1
  233. package/dist/orchestration/bootstrap.js +21 -10
  234. package/dist/orchestration/bootstrap.js.map +1 -1
  235. package/dist/orchestration/index.d.ts +35 -3
  236. package/dist/orchestration/index.d.ts.map +1 -1
  237. package/dist/orchestration/index.js +64 -35
  238. package/dist/orchestration/index.js.map +1 -1
  239. package/dist/orchestration/lead-rollup.d.ts +24 -1
  240. package/dist/orchestration/lead-rollup.d.ts.map +1 -1
  241. package/dist/orchestration/lead-rollup.js +31 -11
  242. package/dist/orchestration/lead-rollup.js.map +1 -1
  243. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  244. package/dist/orchestration/spawn-prompt.js +16 -41
  245. package/dist/orchestration/spawn-prompt.js.map +1 -1
  246. package/dist/orchestration/unblock.d.ts +15 -1
  247. package/dist/orchestration/unblock.d.ts.map +1 -1
  248. package/dist/orchestration/unblock.js +23 -12
  249. package/dist/orchestration/unblock.js.map +1 -1
  250. package/dist/orchestration/validate-spawn.d.ts.map +1 -1
  251. package/dist/orchestration/validate-spawn.js +3 -3
  252. package/dist/orchestration/validate-spawn.js.map +1 -1
  253. package/dist/orchestration/waves.d.ts +29 -13
  254. package/dist/orchestration/waves.d.ts.map +1 -1
  255. package/dist/orchestration/waves.js +43 -55
  256. package/dist/orchestration/waves.js.map +1 -1
  257. package/dist/paths.d.ts +17 -163
  258. package/dist/paths.d.ts.map +1 -1
  259. package/dist/paths.js +145 -496
  260. package/dist/paths.js.map +1 -1
  261. package/dist/project-info.d.ts +2 -11
  262. package/dist/project-info.d.ts.map +1 -1
  263. package/dist/project-info.js +3 -31
  264. package/dist/project-info.js.map +1 -1
  265. package/dist/project-scope.d.ts +239 -0
  266. package/dist/project-scope.d.ts.map +1 -0
  267. package/dist/project-scope.js +473 -0
  268. package/dist/project-scope.js.map +1 -0
  269. package/dist/release/pr-evidence.d.ts +16 -3
  270. package/dist/release/pr-evidence.d.ts.map +1 -1
  271. package/dist/release/pr-evidence.js +53 -7
  272. package/dist/release/pr-evidence.js.map +1 -1
  273. package/dist/render/nexus/graph/index.d.ts.map +1 -1
  274. package/dist/render/nexus/graph/index.js +4 -2
  275. package/dist/render/nexus/graph/index.js.map +1 -1
  276. package/dist/render/orchestration/audit-reconstruct.d.ts +11 -0
  277. package/dist/render/orchestration/audit-reconstruct.d.ts.map +1 -1
  278. package/dist/render/orchestration/audit-reconstruct.js +21 -6
  279. package/dist/render/orchestration/audit-reconstruct.js.map +1 -1
  280. package/dist/render/tasks/show.js +2 -1
  281. package/dist/render/tasks/show.js.map +1 -1
  282. package/dist/resources/spawn-wrapper.d.ts +82 -14
  283. package/dist/resources/spawn-wrapper.d.ts.map +1 -1
  284. package/dist/resources/spawn-wrapper.js +585 -27
  285. package/dist/resources/spawn-wrapper.js.map +1 -1
  286. package/dist/selfimprove/fix-gen.js +4026 -1734
  287. package/dist/selfimprove/fix-gen.js.map +3 -3
  288. package/dist/sequence/index.d.ts.map +1 -1
  289. package/dist/sequence/index.js +76 -68
  290. package/dist/sequence/index.js.map +1 -1
  291. package/dist/session/canon-lint.d.ts +24 -3
  292. package/dist/session/canon-lint.d.ts.map +1 -1
  293. package/dist/session/canon-lint.js +72 -31
  294. package/dist/session/canon-lint.js.map +1 -1
  295. package/dist/session/engine-ops.d.ts +1 -4
  296. package/dist/session/engine-ops.d.ts.map +1 -1
  297. package/dist/session/engine-ops.js +6 -2
  298. package/dist/session/engine-ops.js.map +1 -1
  299. package/dist/sessions/briefing.d.ts +11 -1
  300. package/dist/sessions/briefing.d.ts.map +1 -1
  301. package/dist/sessions/briefing.js +76 -8
  302. package/dist/sessions/briefing.js.map +1 -1
  303. package/dist/sessions/handoff.d.ts +3 -1
  304. package/dist/sessions/handoff.d.ts.map +1 -1
  305. package/dist/sessions/handoff.js +2 -0
  306. package/dist/sessions/handoff.js.map +1 -1
  307. package/dist/shutdown-deadline.d.ts +24 -33
  308. package/dist/shutdown-deadline.d.ts.map +1 -1
  309. package/dist/shutdown-deadline.js +71 -14
  310. package/dist/shutdown-deadline.js.map +1 -1
  311. package/dist/shutdown.d.ts +21 -10
  312. package/dist/shutdown.d.ts.map +1 -1
  313. package/dist/shutdown.js +89 -42
  314. package/dist/shutdown.js.map +1 -1
  315. package/dist/skills/index.d.ts +1 -1
  316. package/dist/skills/index.d.ts.map +1 -1
  317. package/dist/skills/index.js +1 -1
  318. package/dist/skills/index.js.map +1 -1
  319. package/dist/skills/orchestrator/validator.d.ts +87 -20
  320. package/dist/skills/orchestrator/validator.d.ts.map +1 -1
  321. package/dist/skills/orchestrator/validator.js +330 -241
  322. package/dist/skills/orchestrator/validator.js.map +1 -1
  323. package/dist/store/agent-resolver.d.ts.map +1 -1
  324. package/dist/store/agent-resolver.js +16 -9
  325. package/dist/store/agent-resolver.js.map +1 -1
  326. package/dist/store/attachment-store.d.ts +4 -1
  327. package/dist/store/attachment-store.d.ts.map +1 -1
  328. package/dist/store/attachment-store.js +20 -3
  329. package/dist/store/attachment-store.js.map +1 -1
  330. package/dist/store/background-jobs.d.ts +426 -105
  331. package/dist/store/background-jobs.d.ts.map +1 -1
  332. package/dist/store/background-jobs.js +1208 -252
  333. package/dist/store/background-jobs.js.map +1 -1
  334. package/dist/store/background-ops.d.ts +145 -8
  335. package/dist/store/background-ops.d.ts.map +1 -1
  336. package/dist/store/background-ops.js +459 -15
  337. package/dist/store/background-ops.js.map +1 -1
  338. package/dist/store/backup-inspect.d.ts +48 -4
  339. package/dist/store/backup-inspect.d.ts.map +1 -1
  340. package/dist/store/backup-inspect.js +384 -4
  341. package/dist/store/backup-inspect.js.map +1 -1
  342. package/dist/store/converters.d.ts.map +1 -1
  343. package/dist/store/converters.js +19 -2
  344. package/dist/store/converters.js.map +1 -1
  345. package/dist/store/data-accessor.d.ts +9 -1
  346. package/dist/store/data-accessor.d.ts.map +1 -1
  347. package/dist/store/data-accessor.js +22 -5
  348. package/dist/store/data-accessor.js.map +1 -1
  349. package/dist/store/data-safety-central.d.ts.map +1 -1
  350. package/dist/store/data-safety-central.js +272 -232
  351. package/dist/store/data-safety-central.js.map +1 -1
  352. package/dist/store/db-helpers.d.ts +19 -3
  353. package/dist/store/db-helpers.d.ts.map +1 -1
  354. package/dist/store/db-helpers.js +42 -58
  355. package/dist/store/db-helpers.js.map +1 -1
  356. package/dist/store/dual-scope-db.d.ts +63 -4
  357. package/dist/store/dual-scope-db.d.ts.map +1 -1
  358. package/dist/store/dual-scope-db.js +166 -19
  359. package/dist/store/dual-scope-db.js.map +1 -1
  360. package/dist/store/exodus/archive.d.ts +21 -7
  361. package/dist/store/exodus/archive.d.ts.map +1 -1
  362. package/dist/store/exodus/archive.js +60 -18
  363. package/dist/store/exodus/archive.js.map +1 -1
  364. package/dist/store/exodus/migrate.d.ts.map +1 -1
  365. package/dist/store/exodus/migrate.js +27 -23
  366. package/dist/store/exodus/migrate.js.map +1 -1
  367. package/dist/store/exodus/on-open.d.ts +16 -27
  368. package/dist/store/exodus/on-open.d.ts.map +1 -1
  369. package/dist/store/exodus/on-open.js +121 -169
  370. package/dist/store/exodus/on-open.js.map +1 -1
  371. package/dist/store/exodus/recovery.d.ts +90 -0
  372. package/dist/store/exodus/recovery.d.ts.map +1 -0
  373. package/dist/store/exodus/recovery.js +434 -0
  374. package/dist/store/exodus/recovery.js.map +1 -0
  375. package/dist/store/exodus/types.d.ts +15 -0
  376. package/dist/store/exodus/types.d.ts.map +1 -1
  377. package/dist/store/memory-accessor.d.ts +52 -3
  378. package/dist/store/memory-accessor.d.ts.map +1 -1
  379. package/dist/store/memory-accessor.js +122 -7
  380. package/dist/store/memory-accessor.js.map +1 -1
  381. package/dist/store/nexus-sqlite.d.ts +24 -6
  382. package/dist/store/nexus-sqlite.d.ts.map +1 -1
  383. package/dist/store/nexus-sqlite.js +39 -20
  384. package/dist/store/nexus-sqlite.js.map +1 -1
  385. package/dist/store/ports/domain-binding.d.ts.map +1 -1
  386. package/dist/store/ports/domain-binding.js +27 -5
  387. package/dist/store/ports/domain-binding.js.map +1 -1
  388. package/dist/store/schema/background-jobs.d.ts +181 -2
  389. package/dist/store/schema/background-jobs.d.ts.map +1 -1
  390. package/dist/store/schema/background-jobs.js +27 -3
  391. package/dist/store/schema/background-jobs.js.map +1 -1
  392. package/dist/store/schema/cleo-global/skills.d.ts +2 -2
  393. package/dist/store/schema/cleo-project/lifecycle.d.ts +2 -2
  394. package/dist/store/schema/cleo-project/runtime.d.ts +1 -1
  395. package/dist/store/schema/cleo-project/tasks-core.d.ts +1 -1
  396. package/dist/store/schema/lifecycle.d.ts +2 -2
  397. package/dist/store/schema/skills-schema.d.ts +2 -2
  398. package/dist/store/schema/tasks.d.ts +1 -1
  399. package/dist/store/session-store.d.ts +3 -1
  400. package/dist/store/session-store.d.ts.map +1 -1
  401. package/dist/store/session-store.js +252 -207
  402. package/dist/store/session-store.js.map +1 -1
  403. package/dist/store/sqlite-data-accessor.d.ts +39 -4
  404. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  405. package/dist/store/sqlite-data-accessor.js +689 -527
  406. package/dist/store/sqlite-data-accessor.js.map +1 -1
  407. package/dist/store/tasks-sqlite.d.ts +3 -1
  408. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  409. package/dist/store/tasks-sqlite.js +309 -279
  410. package/dist/store/tasks-sqlite.js.map +1 -1
  411. package/dist/store/validation-schemas.d.ts +8 -8
  412. package/dist/store/writer-lease.d.ts +80 -8
  413. package/dist/store/writer-lease.d.ts.map +1 -1
  414. package/dist/store/writer-lease.js +503 -134
  415. package/dist/store/writer-lease.js.map +1 -1
  416. package/dist/system/audit.d.ts +2 -1
  417. package/dist/system/audit.d.ts.map +1 -1
  418. package/dist/system/audit.js +118 -71
  419. package/dist/system/audit.js.map +1 -1
  420. package/dist/system/backup.d.ts.map +1 -1
  421. package/dist/system/backup.js +5 -5
  422. package/dist/system/backup.js.map +1 -1
  423. package/dist/system/inject-generate.js +1 -1
  424. package/dist/task-work/index.d.ts +3 -0
  425. package/dist/task-work/index.d.ts.map +1 -1
  426. package/dist/task-work/index.js +34 -37
  427. package/dist/task-work/index.js.map +1 -1
  428. package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
  429. package/dist/tasks/ac-coverage-gate.js +4 -0
  430. package/dist/tasks/ac-coverage-gate.js.map +1 -1
  431. package/dist/tasks/ac-immutability.d.ts +7 -4
  432. package/dist/tasks/ac-immutability.d.ts.map +1 -1
  433. package/dist/tasks/ac-immutability.js +19 -17
  434. package/dist/tasks/ac-immutability.js.map +1 -1
  435. package/dist/tasks/ac-table.d.ts +5 -5
  436. package/dist/tasks/ac-table.d.ts.map +1 -1
  437. package/dist/tasks/ac-table.js +26 -12
  438. package/dist/tasks/ac-table.js.map +1 -1
  439. package/dist/tasks/acceptance-input.d.ts +52 -0
  440. package/dist/tasks/acceptance-input.d.ts.map +1 -0
  441. package/dist/tasks/acceptance-input.js +259 -0
  442. package/dist/tasks/acceptance-input.js.map +1 -0
  443. package/dist/tasks/add.d.ts +67 -29
  444. package/dist/tasks/add.d.ts.map +1 -1
  445. package/dist/tasks/add.js +255 -97
  446. package/dist/tasks/add.js.map +1 -1
  447. package/dist/tasks/complete.d.ts +16 -1
  448. package/dist/tasks/complete.d.ts.map +1 -1
  449. package/dist/tasks/complete.js +152 -55
  450. package/dist/tasks/complete.js.map +1 -1
  451. package/dist/tasks/decompose.d.ts +103 -0
  452. package/dist/tasks/decompose.d.ts.map +1 -0
  453. package/dist/tasks/decompose.js +224 -0
  454. package/dist/tasks/decompose.js.map +1 -0
  455. package/dist/tasks/delete.d.ts +5 -8
  456. package/dist/tasks/delete.d.ts.map +1 -1
  457. package/dist/tasks/delete.js +4 -3
  458. package/dist/tasks/delete.js.map +1 -1
  459. package/dist/tasks/dependency-check.d.ts +59 -0
  460. package/dist/tasks/dependency-check.d.ts.map +1 -1
  461. package/dist/tasks/dependency-check.js +73 -0
  462. package/dist/tasks/dependency-check.js.map +1 -1
  463. package/dist/tasks/deps-ready.d.ts +13 -1
  464. package/dist/tasks/deps-ready.d.ts.map +1 -1
  465. package/dist/tasks/deps-ready.js +16 -5
  466. package/dist/tasks/deps-ready.js.map +1 -1
  467. package/dist/tasks/engine-converters.d.ts +7 -0
  468. package/dist/tasks/engine-converters.d.ts.map +1 -1
  469. package/dist/tasks/engine-converters.js +8 -1
  470. package/dist/tasks/engine-converters.js.map +1 -1
  471. package/dist/tasks/evidence.d.ts +54 -26
  472. package/dist/tasks/evidence.d.ts.map +1 -1
  473. package/dist/tasks/evidence.js +292 -40
  474. package/dist/tasks/evidence.js.map +1 -1
  475. package/dist/tasks/find.d.ts +16 -12
  476. package/dist/tasks/find.d.ts.map +1 -1
  477. package/dist/tasks/find.js +107 -93
  478. package/dist/tasks/find.js.map +1 -1
  479. package/dist/tasks/gate-runner.d.ts +88 -14
  480. package/dist/tasks/gate-runner.d.ts.map +1 -1
  481. package/dist/tasks/gate-runner.js +596 -253
  482. package/dist/tasks/gate-runner.js.map +1 -1
  483. package/dist/tasks/hierarchy-policy.d.ts +8 -0
  484. package/dist/tasks/hierarchy-policy.d.ts.map +1 -1
  485. package/dist/tasks/hierarchy-policy.js +9 -2
  486. package/dist/tasks/hierarchy-policy.js.map +1 -1
  487. package/dist/tasks/hierarchy.d.ts +67 -1
  488. package/dist/tasks/hierarchy.d.ts.map +1 -1
  489. package/dist/tasks/hierarchy.js +81 -1
  490. package/dist/tasks/hierarchy.js.map +1 -1
  491. package/dist/tasks/index.d.ts +3 -0
  492. package/dist/tasks/index.d.ts.map +1 -1
  493. package/dist/tasks/index.js +3 -0
  494. package/dist/tasks/index.js.map +1 -1
  495. package/dist/tasks/infer-add-params.d.ts +1 -20
  496. package/dist/tasks/infer-add-params.d.ts.map +1 -1
  497. package/dist/tasks/infer-add-params.js +2 -203
  498. package/dist/tasks/infer-add-params.js.map +1 -1
  499. package/dist/tasks/list.d.ts +7 -2
  500. package/dist/tasks/list.d.ts.map +1 -1
  501. package/dist/tasks/list.js +24 -36
  502. package/dist/tasks/list.js.map +1 -1
  503. package/dist/tasks/ops.d.ts +6 -61
  504. package/dist/tasks/ops.d.ts.map +1 -1
  505. package/dist/tasks/ops.js +5 -53
  506. package/dist/tasks/ops.js.map +1 -1
  507. package/dist/tasks/plan.d.ts +15 -1
  508. package/dist/tasks/plan.d.ts.map +1 -1
  509. package/dist/tasks/plan.js +23 -25
  510. package/dist/tasks/plan.js.map +1 -1
  511. package/dist/tasks/population.d.ts +46 -0
  512. package/dist/tasks/population.d.ts.map +1 -0
  513. package/dist/tasks/population.js +88 -0
  514. package/dist/tasks/population.js.map +1 -0
  515. package/dist/tasks/reconcile-scope.d.ts +157 -0
  516. package/dist/tasks/reconcile-scope.d.ts.map +1 -0
  517. package/dist/tasks/reconcile-scope.js +242 -0
  518. package/dist/tasks/reconcile-scope.js.map +1 -0
  519. package/dist/tasks/req.d.ts +51 -12
  520. package/dist/tasks/req.d.ts.map +1 -1
  521. package/dist/tasks/req.js +125 -69
  522. package/dist/tasks/req.js.map +1 -1
  523. package/dist/tasks/session-scope.d.ts +6 -31
  524. package/dist/tasks/session-scope.d.ts.map +1 -1
  525. package/dist/tasks/session-scope.js +3 -17
  526. package/dist/tasks/session-scope.js.map +1 -1
  527. package/dist/tasks/severity-attestation.d.ts +39 -10
  528. package/dist/tasks/severity-attestation.d.ts.map +1 -1
  529. package/dist/tasks/severity-attestation.js +75 -36
  530. package/dist/tasks/severity-attestation.js.map +1 -1
  531. package/dist/tasks/task-next.d.ts +5 -0
  532. package/dist/tasks/task-next.d.ts.map +1 -1
  533. package/dist/tasks/task-next.js +10 -9
  534. package/dist/tasks/task-next.js.map +1 -1
  535. package/dist/tasks/task-reparent.d.ts.map +1 -1
  536. package/dist/tasks/task-reparent.js +3 -13
  537. package/dist/tasks/task-reparent.js.map +1 -1
  538. package/dist/tasks/update.d.ts +20 -43
  539. package/dist/tasks/update.d.ts.map +1 -1
  540. package/dist/tasks/update.js +64 -49
  541. package/dist/tasks/update.js.map +1 -1
  542. package/dist/validation/engine-ops.d.ts +17 -1
  543. package/dist/validation/engine-ops.d.ts.map +1 -1
  544. package/dist/validation/engine-ops.js +149 -11
  545. package/dist/validation/engine-ops.js.map +1 -1
  546. package/dist/workgraph/reparent-preflight.d.ts +1 -1
  547. package/dist/workgraph/reparent-preflight.d.ts.map +1 -1
  548. package/dist/workgraph/reparent-preflight.js +6 -1
  549. package/dist/workgraph/reparent-preflight.js.map +1 -1
  550. package/dist/workgraph/scaffold-apply.d.ts.map +1 -1
  551. package/dist/workgraph/scaffold-apply.js +81 -76
  552. package/dist/workgraph/scaffold-apply.js.map +1 -1
  553. package/dist/workgraph/structure-validation.d.ts +1 -1
  554. package/dist/workgraph/structure-validation.d.ts.map +1 -1
  555. package/dist/workgraph/structure-validation.js +6 -1
  556. package/dist/workgraph/structure-validation.js.map +1 -1
  557. package/migrations/drizzle-tasks/20260919180000_t12263-job-ownership-fences/migration.sql +34 -0
  558. package/migrations/drizzle-tasks/20260919184500_t12265-durable-pending-proposals/migration.sql +4 -0
  559. package/package.json +18 -13
  560. package/schemas/config.schema.json +2 -2
  561. package/templates/CLEO-INJECTION.md +103 -101
package/dist/tasks/add.js CHANGED
@@ -13,17 +13,62 @@ import { resolveOrCwd } from '../paths.js';
13
13
  import { allocateNextTaskId } from '../sequence/index.js';
14
14
  import { requireActiveSession } from '../sessions/session-enforcement.js';
15
15
  import { trackBackgroundOp } from '../store/background-ops.js';
16
- import { acItemToText, applyAcPlan, buildAcRowId, buildChildProjectionAcText, buildFreshAcRows, childProjectionFreshnessFingerprint, childProjectionSourceKey, } from './ac-table.js';
16
+ import { applyAcPlan, buildAcRowId, buildChildProjectionAcText, buildFreshAcRows, childProjectionFreshnessFingerprint, childProjectionSourceKey, } from './ac-table.js';
17
+ import { normalizeAcceptance } from './acceptance-input.js';
17
18
  import { createAcceptanceEnforcement } from './enforcement.js';
18
19
  import { findEpicAncestor, validateChildStageCeiling, validateEpicCreation, } from './epic-enforcement.js';
19
- import { resolveHierarchyPolicy } from './hierarchy-policy.js';
20
+ import { childTypeForParentType } from './hierarchy.js';
21
+ import { exceedsMaxDepth, resolveHierarchyPolicy } from './hierarchy-policy.js';
20
22
  import { resolveDefaultPipelineStage, validatePipelineStage } from './pipeline-stage.js';
21
- /** Normalize AC arrays once so legacy JSON, AC rows, and projections stay aligned. */
22
- export function normalizeAcceptance(acceptance) {
23
- if (!acceptance)
24
- return undefined;
25
- const normalized = acceptance.map((item) => item.trim()).filter((item) => item.length > 0);
26
- return normalized.length > 0 ? normalized : undefined;
23
+ import { prepareSignedSeverityAttestation } from './severity-attestation.js';
24
+ export { normalizeAcceptance } from './acceptance-input.js';
25
+ /**
26
+ * Translate canonical creation input into core options without dropping fields.
27
+ * @param params - Canonical task creation input.
28
+ * @returns Core options with the parent alias and enum boundaries resolved.
29
+ * @remarks Entry points share this boundary; CLI parsing does not establish authorization.
30
+ * @example
31
+ * ```ts
32
+ * toTaskAddOptions({ title: 'Fix persistence', description: 'Verify durable task writes' });
33
+ * ```
34
+ */
35
+ export function toTaskAddOptions(params) {
36
+ const { parent, ...fields } = params;
37
+ return {
38
+ ...fields,
39
+ parentId: parent,
40
+ priority: params.priority,
41
+ size: params.size,
42
+ kind: params.kind,
43
+ scope: params.scope,
44
+ severity: params.severity,
45
+ };
46
+ }
47
+ /**
48
+ * Enforce the established explicit-critical dependency policy before mutation.
49
+ * @param priority - Explicit requested priority; waivers require critical.
50
+ * @param justification - Original reason, retained verbatim in transaction audit details.
51
+ * @param dependencies - Effective dependencies after applying the requested changes.
52
+ * @throws CleoError for invalid waivers or critical mutations without dependencies.
53
+ * @remarks Entry points share this boundary; CLI parsing does not establish authorization.
54
+ * @example
55
+ * ```ts
56
+ * validateDependencyWaiver('critical', 'Independent restoration', []);
57
+ * ```
58
+ */
59
+ export function validateDependencyWaiver(priority, justification, dependencies) {
60
+ if (justification !== undefined &&
61
+ (typeof justification !== 'string' ||
62
+ justification.trim().length === 0 ||
63
+ priority !== 'critical')) {
64
+ throw new CleoError(ExitCode.VALIDATION_ERROR, 'Dependency waiver requires a non-empty justification and an explicit critical-priority mutation', {
65
+ details: { field: 'dependsWaiver' },
66
+ fix: 'Supply a non-empty --depends-waiver with --priority critical, or omit the waiver',
67
+ });
68
+ }
69
+ if (priority === 'critical' && dependencies.length === 0 && justification === undefined) {
70
+ throw new CleoError(ExitCode.VALIDATION_ERROR, 'Critical tasks must declare at least one dependency or supply a dependency waiver', { details: { field: 'depends' }, fix: 'Supply --depends or a non-empty --depends-waiver' });
71
+ }
27
72
  }
28
73
  /**
29
74
  * Build the default verification metadata applied to every new task.
@@ -322,12 +367,14 @@ export function validateParent(parentId, tasks, maxDepth = 3, maxSiblings = 0) {
322
367
  if (parent.type === 'subtask') {
323
368
  throw new CleoError(ExitCode.INVALID_PARENT_TYPE, `Cannot add child to ${parentId}: subtasks cannot have children`, { fix: `Create as standalone task or add to parent's parent instead` });
324
369
  }
325
- // Check depth
370
+ // Check depth. Behaviourally identical to the previous `depth >= maxDepth`
371
+ // (this helper was always one of the two correct implementations); routed
372
+ // through the shared rule so there is exactly one copy of the comparison.
326
373
  const depth = getTaskDepth(parentId, tasks);
327
- if (depth >= maxDepth) {
374
+ if (exceedsMaxDepth(depth, maxDepth)) {
328
375
  throw new CleoError(ExitCode.DEPTH_EXCEEDED, `Cannot add child to ${parentId}: max hierarchy depth (${maxDepth}) would be exceeded`, {
329
376
  fix: 'Reparent this task under a higher-level epic',
330
- details: { field: 'parentId', expected: `depth < ${maxDepth}`, actual: depth },
377
+ details: { field: 'parentId', expected: `depth <= ${maxDepth}`, actual: depth + 1 },
331
378
  });
332
379
  }
333
380
  // Check sibling count
@@ -404,6 +451,23 @@ export function getTaskDepth(taskId, tasks) {
404
451
  * console.assert(inferTaskType('T002', tasks) === 'subtask', 'task parent → subtask');
405
452
  * ```
406
453
  */
454
+ /**
455
+ * Human-readable list of the tiers that may legally contain `childType`, per the
456
+ * PM-Core V2 containment matrix.
457
+ *
458
+ * Used to explain a refusal in the caller's own vocabulary ("a subtask can only
459
+ * be filed under a task") rather than quoting a numeric depth the caller never
460
+ * configured.
461
+ *
462
+ * @param childType - The tier the caller asked to create.
463
+ * @returns Comma-joined parent tier names, or `'nothing (it is a root tier)'`.
464
+ */
465
+ function describeLegalParents(childType) {
466
+ const allowed = ['saga', 'epic', 'task', 'subtask']
467
+ .filter((parent) => isAllowedWorkGraphParentType(childType, parent))
468
+ .map((parent) => `${/^[aeiou]/.test(parent) ? 'an' : 'a'} ${parent}`);
469
+ return allowed.length === 0 ? 'nothing (it is a root tier)' : allowed.join(' or ');
470
+ }
407
471
  export function inferTaskType(parentId, tasks) {
408
472
  if (!parentId)
409
473
  return 'task';
@@ -526,8 +590,12 @@ async function hasNoTasks(cwd, accessor) {
526
590
  * @task T4460
527
591
  */
528
592
  export async function addTask(options, cwd, accessor) {
593
+ const normalizedAcceptance = normalizeAcceptance(options.acceptance);
529
594
  // Validate title (early-exit — can't proceed without a title)
530
595
  validateTitle(options.title);
596
+ validateDependencyWaiver(options.priority, options.dependsWaiver, options.depends ?? []);
597
+ /** Set when `autoDecompose` converted a text-AC leaf parent into a container. */
598
+ let autoDecomposed;
531
599
  // Skip session enforcement for dry-run — no data is written
532
600
  if (!options.dryRun) {
533
601
  await requireActiveSession('tasks.add', cwd);
@@ -537,7 +605,6 @@ export async function addTask(options, cwd, accessor) {
537
605
  // preventing the common failure mode where agents drop flags like --parent.
538
606
  const issues = [];
539
607
  const warnings = [];
540
- const normalizedAcceptance = normalizeAcceptance(options.acceptance);
541
608
  // Anti-hallucination: title and description must be different (T5698)
542
609
  if (options.description &&
543
610
  options.title.trim().toLowerCase() === options.description.trim().toLowerCase()) {
@@ -765,12 +832,17 @@ export async function addTask(options, cwd, accessor) {
765
832
  // Depth check using ancestor chain
766
833
  const ancestors = await dataAccessor.getAncestorChain(parentId);
767
834
  const parentDepth = ancestors.length;
768
- if (parentDepth + 1 >= policy.maxDepth) {
835
+ if (exceedsMaxDepth(parentDepth, policy.maxDepth)) {
769
836
  // T11491 — DHQ-044: produce a clear actionable message that names the
770
- // parent epic the user SHOULD target instead. The ancestor chain is
771
- // ordered [immediateParent, grandparent, …, root]. When the parent is a
772
- // task (depth 2), ancestors[0] is the epic (depth 1) — tell the user
773
- // to file under THAT epic instead.
837
+ // container the caller SHOULD target instead.
838
+ //
839
+ // The ancestor chain is ordered [root, …, immediateParent]:
840
+ // `sqlite-data-accessor.ts` builds it with `ORDER BY depth DESC` and
841
+ // re-sorts "ancestors from root down", so the LAST element is the
842
+ // prospective parent's own parent — the grandparent of the node being
843
+ // added. (A prior comment here claimed the reverse order and pointed at
844
+ // ancestors[0]; the code was always right, the comment was not. Stated
845
+ // explicitly so nobody "fixes" the index to match the prose.)
774
846
  //
775
847
  // T11293: NEVER suggest "omit --parent to create a standalone task."
776
848
  // Under strict-spine containment (T11811) only sagas may be root-level,
@@ -778,13 +850,28 @@ export async function addTask(options, cwd, accessor) {
778
850
  // (so the user never supplied --parent in the first place). Point to a
779
851
  // concrete higher-level container, or to --parent none to escape
780
852
  // auto-inference (the task will still need a valid parent).
781
- const grandparentEpic = ancestors.length > 0 ? ancestors[ancestors.length - 1] : ancestors[0];
853
+ const grandparent = ancestors.length > 0 ? ancestors[ancestors.length - 1] : undefined;
854
+ // The tier the caller actually asked for. `taskType` is still the raw
855
+ // `--type` here (inference runs further down), so an unset type means
856
+ // "whatever this parent implies" — the same derivation the containment
857
+ // check below applies.
858
+ const requestedChildType = taskType ?? childTypeForParentType(parentTask.type ?? 'task');
859
+ // A suggestion that cannot be executed is worse than no suggestion. The
860
+ // previous version always offered `--parent <grandparent>` on the grounds
861
+ // that it is shallower, and said nothing about TYPE. But the caller's
862
+ // `--type` travels with the retry, and the containment matrix only admits
863
+ // saga→epic, epic→task, task→subtask — so `--type subtask --parent <epic>`
864
+ // clears this depth check and is then refused by the matrix below. Two
865
+ // field reports (GH: a user on 2026.9.5, and an agent that burned three
866
+ // `cleo add` calls) followed that hint from exit 11 straight into exit 6.
867
+ // Only offer the grandparent when it can legally hold what was asked for.
868
+ const grandparentAccepts = grandparent !== undefined &&
869
+ isAllowedWorkGraphParentType(requestedChildType, grandparent.type ?? 'task');
782
870
  // T12136 (GH #1232/#1238) — when the parent was INHERITED rather than
783
871
  // named, say so FIRST. Otherwise the message reads as though the caller
784
- // asked to file under `parentId`, and the "use --parent <epic>" advice
785
- // — the only actionable-looking line — points into a hierarchy the
786
- // caller never intended to touch. Naming the inference converts the
787
- // suggestion from misleading to optional.
872
+ // asked to file under `parentId`, and the only actionable-looking line
873
+ // points into a hierarchy the caller never intended to touch. Naming the
874
+ // inference converts the suggestion from misleading to optional.
788
875
  const wasInherited = options.parentSource === 'session-inference';
789
876
  const provenance = wasInherited
790
877
  ? `You did not pass --parent: ${parentId} was inherited from the active session ` +
@@ -793,20 +880,28 @@ export async function addTask(options, cwd, accessor) {
793
880
  const escapeHint = wasInherited
794
881
  ? ' Or pass --parent <id> explicitly to override the session pointer, or --parent none to suppress inference.'
795
882
  : '';
796
- const epicSuggestion = grandparentEpic
797
- ? ` Use --parent ${grandparentEpic.id} (the parent epic) instead.`
798
- : ' Reparent under a higher-level container, or use --parent none to suppress session-based parent inference.';
799
- throw new CleoError(ExitCode.DEPTH_EXCEEDED, `${provenance}Cannot add a child to ${parentId}: the hierarchy depth cap (${policy.maxDepth}) would be exceeded. ` +
800
- `Tasks at depth ${parentDepth} cannot have children.${epicSuggestion}${escapeHint}`, {
801
- fix: grandparentEpic
802
- ? `cleo add --parent ${grandparentEpic.id} --title "..." --acceptance "..."`
803
- : 'Reparent this task under a higher-level epic',
883
+ // T11293: NEVER suggest "omit --parent to create a standalone task" —
884
+ // under strict-spine containment only a saga may be a root.
885
+ const suggestion = grandparentAccepts
886
+ ? ` File it under --parent ${grandparent?.id} as --type ${requestedChildType} instead.`
887
+ : ` A ${requestedChildType} can only be filed under ${describeLegalParents(requestedChildType)}, ` +
888
+ `and every one of those is already at or past the cap here. Re-scope the work so it ` +
889
+ `belongs to an existing container, or raise hierarchy.maxDepth in .cleo/config.json.`;
890
+ throw new CleoError(ExitCode.DEPTH_EXCEEDED, `${provenance}Cannot add a ${requestedChildType} under ${parentId}: it is a ` +
891
+ `${parentTask.type ?? 'task'} at depth ${parentDepth}, and a child would sit at depth ` +
892
+ `${parentDepth + 1}, past the hierarchy cap of ${policy.maxDepth} ` +
893
+ `(saga 0, epic 1, task 2, subtask 3).${suggestion}${escapeHint}`, {
894
+ fix: grandparentAccepts
895
+ ? `cleo add --type ${requestedChildType} --parent ${grandparent?.id} --title "..." --acceptance "..."`
896
+ : `Re-scope under an existing container, or raise hierarchy.maxDepth above ${policy.maxDepth}`,
804
897
  details: {
805
898
  field: 'parentId',
806
- expected: `depth < ${policy.maxDepth}`,
899
+ expected: `depth <= ${policy.maxDepth}`,
807
900
  actual: parentDepth + 1,
808
- suggestedParentId: grandparentEpic?.id,
809
- suggestedParentTitle: grandparentEpic?.title,
901
+ requestedChildType,
902
+ // Only ever names a parent that can legally hold `requestedChildType`.
903
+ suggestedParentId: grandparentAccepts ? grandparent?.id : undefined,
904
+ suggestedParentTitle: grandparentAccepts ? grandparent?.title : undefined,
810
905
  parentSource: options.parentSource ?? 'explicit',
811
906
  },
812
907
  });
@@ -841,12 +936,11 @@ export async function addTask(options, cwd, accessor) {
841
936
  });
842
937
  }
843
938
  const parentTypeForValidation = parentTask.type ?? 'task';
844
- const childTypeForParent = taskType ??
845
- (parentTypeForValidation === 'saga'
846
- ? 'epic'
847
- : parentTypeForValidation === 'task'
848
- ? 'subtask'
849
- : 'task');
939
+ // An explicit `--type` is honoured verbatim so the containment check below
940
+ // can REJECT it. Passing it as `currentType` instead would let the helper's
941
+ // reparent fallback rewrite it (`--type subtask` under an epic would become
942
+ // `task`) and silently create the wrong tier rather than refusing.
943
+ const childTypeForParent = taskType ?? childTypeForParentType(parentTypeForValidation);
850
944
  if (!isAllowedWorkGraphParentType(childTypeForParent, parentTypeForValidation)) {
851
945
  throw new CleoError(ExitCode.VALIDATION_ERROR, `Invalid parent type for ${taskType}: parent ${parentId} has type '${parentTask.type}'.`, {
852
946
  fix: 'Use Saga→Epic, Epic→Task, and Task→Subtask containment.',
@@ -915,22 +1009,38 @@ export async function addTask(options, cwd, accessor) {
915
1009
  // pure single-mode leaves are unaffected — the guard fires only when a
916
1010
  // text-AC-bearing non-container leaf is about to gain its first child.
917
1011
  if (parentId &&
1012
+ !options.skipMixedAcParentGuard &&
918
1013
  parentTaskForProjection &&
919
1014
  parentTaskForProjection.type !== 'epic' &&
920
1015
  parentTaskForProjection.type !== 'saga') {
921
1016
  const parentAcRows = await dataAccessor.getAcRows(parentId);
922
1017
  const parentHasTextAc = parentAcRows.some((row) => row.kind === 'text');
923
- if (parentHasTextAc) {
1018
+ if (parentHasTextAc && options.autoDecompose && !options.dryRun) {
1019
+ // Resolve the guard instead of reporting it. Dynamic import because
1020
+ // `decompose.ts` imports `addTask` from here — a static import would close
1021
+ // the cycle. The decompose runs BEFORE the projection write below, so by
1022
+ // the time this add inserts, the parent is a pure container and
1023
+ // design-point 3 holds for real rather than being waived.
1024
+ const { decomposeTask } = await import('./decompose.js');
1025
+ const moved = await decomposeTask({ taskId: parentId }, cwd, dataAccessor);
1026
+ if (moved.childId) {
1027
+ autoDecomposed = { childId: moved.childId, movedAcceptance: moved.movedAcceptance };
1028
+ }
1029
+ }
1030
+ else if (parentHasTextAc) {
924
1031
  throw new CleoError(ExitCode.VALIDATION_ERROR, `Cannot add child under ${parentId}: it is a ${parentTaskForProjection.type} with its ` +
925
1032
  `own free-text acceptance criteria, and adding a child would mix hand-authored text ` +
926
1033
  `ACs with machine-managed child_task projections (PM-Core V2 design-point 3). A ` +
927
1034
  `${parentTaskForProjection.type} must be either a leaf defined by its own text ACs OR ` +
928
1035
  `a container defined by its children, not both. (Epics and sagas are exempt — they are ` +
929
1036
  `containers by design.)`, {
930
- fix: `Either (a) move ${parentId}'s text acceptance criteria onto a new child task and ` +
931
- `add work under that child, (b) clear ${parentId}'s text ACs ` +
932
- `(\`cleo update ${parentId} --acceptance ""\`) so it becomes a pure container, or ` +
933
- `(c) promote ${parentId} to an epic if it is meant to hold children.`,
1037
+ fix: `Re-run this add with --auto-decompose to do it in one step, or run ` +
1038
+ `\`cleo decompose ${parentId}\` first — either moves ${parentId}'s text acceptance ` +
1039
+ `criteria onto a new first child in one step, leaving ${parentId} a pure ` +
1040
+ `container, after which this add succeeds. (Or promote ${parentId} to an epic ` +
1041
+ `if it is meant to hold children.) Note that clearing the ACs by hand with ` +
1042
+ `\`cleo update ${parentId} --acceptance ""\` does NOT work: acceptance ` +
1043
+ `enforcement rejects an empty criteria list.`,
934
1044
  details: {
935
1045
  field: 'parentId',
936
1046
  parentId,
@@ -943,7 +1053,9 @@ export async function addTask(options, cwd, accessor) {
943
1053
  }
944
1054
  // BRAIN-powered duplicate detection (T1633) — query active tasks for semantic similarity.
945
1055
  // Runs before the exact-title duplicate check so warnings/rejections surface early.
946
- // Skip on dry-run (no data written) and skip when forceDuplicate bypasses rejection.
1056
+ // Capture the decision now; persist committed provenance with the task.
1057
+ let duplicateBypass;
1058
+ // Skip on dry-run (no data written).
947
1059
  if (!options.dryRun) {
948
1060
  const { checkDuplicatesBounded, buildWarnMessage, buildRejectMessage } = await import('./duplicate-detector.js');
949
1061
  // T12117 (#1244): bounded and fail-OPEN. This runs BEFORE the insert, so a
@@ -963,16 +1075,14 @@ export async function addTask(options, cwd, accessor) {
963
1075
  });
964
1076
  }
965
1077
  if (dupCheck.shouldReject && options.forceDuplicate) {
966
- // User forced past the rejection — audit the bypass
967
- const { appendDuplicateBypassAudit } = await import('./duplicate-bypass-audit.js');
968
- await appendDuplicateBypassAudit({
1078
+ duplicateBypass = {
969
1079
  incomingTitle: options.title,
970
1080
  incomingDescription: options.description ?? '',
971
1081
  matchedCandidates: dupCheck.candidates,
972
1082
  maxScore: dupCheck.maxScore,
973
1083
  timestamp: new Date().toISOString(),
974
1084
  agent: 'system',
975
- }, resolveOrCwd(cwd));
1085
+ };
976
1086
  }
977
1087
  if (dupCheck.shouldWarn) {
978
1088
  // Emit warning to stderr; does not block insertion.
@@ -985,7 +1095,16 @@ export async function addTask(options, cwd, accessor) {
985
1095
  search: options.title,
986
1096
  limit: 50,
987
1097
  });
988
- const duplicate = findRecentDuplicate(options.title, phase, candidateDupes);
1098
+ // `forceDuplicate` is honoured here as well as by the semantic check above.
1099
+ // This 60-second window exists to absorb accidental double-submits, but it
1100
+ // returned the EXISTING task without inserting and without throwing, so a
1101
+ // caller that had explicitly said "yes, create it anyway" silently got back a
1102
+ // row it did not create. `cleo decompose` hits this every time it runs on a
1103
+ // task filed moments earlier — the common case — because the child it creates
1104
+ // deliberately inherits the parent's title.
1105
+ const duplicate = options.forceDuplicate
1106
+ ? null
1107
+ : findRecentDuplicate(options.title, phase, candidateDupes);
989
1108
  if (duplicate) {
990
1109
  return { task: duplicate, duplicate: true };
991
1110
  }
@@ -1184,6 +1303,15 @@ export async function addTask(options, cwd, accessor) {
1184
1303
  const createdAcceptanceCriteriaIds = [];
1185
1304
  const reopenedAncestorIds = [];
1186
1305
  await dataAccessor.transaction(async (tx) => {
1306
+ const severityAttestation = options.severity === undefined
1307
+ ? undefined
1308
+ : await prepareSignedSeverityAttestation({
1309
+ timestamp: now,
1310
+ title: task.title,
1311
+ severity: options.severity,
1312
+ taskId,
1313
+ ...(parentId ? { epic: parentId } : {}),
1314
+ }, { cwd });
1187
1315
  // Position shuffling via bulk SQL update (T025)
1188
1316
  if (options.position !== undefined) {
1189
1317
  await dataAccessor.shiftPositions(parentId, options.position, 1);
@@ -1204,14 +1332,13 @@ export async function addTask(options, cwd, accessor) {
1204
1332
  // PM-Core V2 WorkGraph projection sync: parent_id is the containment edge,
1205
1333
  // and each newly-added direct child is mirrored as a parent-owned AC row so
1206
1334
  // completion criteria readers can resolve child work without inspecting
1207
- // task_relations. Keep the legacy parent acceptance JSON in sync as a
1208
- // text-only compatibility projection while the row table carries typed
1209
- // child_task, source_key, and target_task_id state.
1335
+ // task_relations. Preserve existing gate objects in the parent JSON while
1336
+ // the row table carries child_task, source_key, and target_task_id state.
1210
1337
  if (parentId && parentTaskForProjection) {
1211
1338
  const parentAcRows = await tx.getAcRows(parentId);
1212
- // PM-Core V2 typed child_task AC projection. The legacy parent
1213
- // acceptance JSON remains text-only compatibility state, but the row
1214
- // table now carries machine-checkable target_task_id/source_key fields.
1339
+ // PM-Core V2 child_task rows carry target_task_id/source_key fields.
1340
+ // The mixed JSON view retains existing typed gates and appends only the
1341
+ // new child projection as text. Text-input normalization is not a reader.
1215
1342
  const parentChildAcText = buildChildProjectionAcText(taskId, options.title);
1216
1343
  const parentChildOrdinal = parentAcRows.reduce((max, row) => Math.max(max, row.ordinal), 0) + 1;
1217
1344
  const parentChildSourceKey = childProjectionSourceKey(taskId);
@@ -1228,12 +1355,14 @@ export async function addTask(options, cwd, accessor) {
1228
1355
  };
1229
1356
  await tx.insertAcRows([parentChildAcRow]);
1230
1357
  createdAcceptanceCriteriaIds.push(parentChildAcRow.id);
1231
- const parentAcceptance = normalizeAcceptance([
1232
- ...(parentTaskForProjection.acceptance ?? []).map(acItemToText),
1233
- parentChildAcText,
1234
- ]);
1358
+ // Re-read under the transaction: sibling creators may have appended
1359
+ // their parent projection after the initial validation snapshot.
1360
+ const currentParent = await dataAccessor.loadSingleTask(parentId);
1361
+ if (!currentParent)
1362
+ throw new CleoError(ExitCode.NOT_FOUND, `Parent task not found: ${parentId}`);
1363
+ const parentAcceptance = [...(currentParent.acceptance ?? []), parentChildAcText];
1235
1364
  await tx.updateTaskFields(parentId, {
1236
- acceptanceJson: JSON.stringify(parentAcceptance ?? []),
1365
+ acceptanceJson: JSON.stringify(parentAcceptance),
1237
1366
  updatedAt: now,
1238
1367
  });
1239
1368
  }
@@ -1241,15 +1370,20 @@ export async function addTask(options, cwd, accessor) {
1241
1370
  // holds the unsatisfied child injected above. Mirrors coreTaskReopen:
1242
1371
  // status→pending, clear completedAt, preserve completion history in notes.
1243
1372
  for (const ancestor of ancestorsToReopen) {
1373
+ const currentAncestor = await dataAccessor.loadSingleTask(ancestor.id);
1374
+ if (!currentAncestor)
1375
+ throw new CleoError(ExitCode.NOT_FOUND, `Ancestor task not found: ${ancestor.id}`);
1376
+ if (currentAncestor.status !== 'done')
1377
+ continue;
1244
1378
  const reopened = {
1245
- ...ancestor,
1379
+ ...currentAncestor,
1246
1380
  status: 'pending',
1247
1381
  completedAt: undefined,
1248
1382
  updatedAt: now,
1249
1383
  notes: [
1250
- ...(ancestor.notes ?? []),
1251
- ...(ancestor.completedAt
1252
- ? [`[${now}] completion-history: completedAt=${ancestor.completedAt}`]
1384
+ ...(currentAncestor.notes ?? []),
1385
+ ...(currentAncestor.completedAt
1386
+ ? [`[${now}] completion-history: completedAt=${currentAncestor.completedAt}`]
1253
1387
  : []),
1254
1388
  `[${now}] Reopened by add of child ${taskId} (done parent gained an unsatisfied child)`,
1255
1389
  ],
@@ -1268,11 +1402,65 @@ export async function addTask(options, cwd, accessor) {
1268
1402
  action: 'task_created',
1269
1403
  taskId,
1270
1404
  actor: 'system',
1271
- details: { title: options.title, status, priority },
1405
+ details: {
1406
+ title: options.title,
1407
+ status,
1408
+ priority,
1409
+ ...(severityAttestation
1410
+ ? { severityAttestation: { ...severityAttestation, status: 'committed' } }
1411
+ : {}),
1412
+ ...(options.forceDuplicate
1413
+ ? {
1414
+ forceDuplicate: {
1415
+ ...duplicateBypass,
1416
+ requested: true,
1417
+ bypassed: duplicateBypass !== undefined,
1418
+ status: 'committed',
1419
+ },
1420
+ }
1421
+ : {}),
1422
+ ...(options.dependsWaiver !== undefined ? { dependsWaiver: options.dependsWaiver } : {}),
1423
+ },
1272
1424
  before: null,
1273
1425
  after: { title: options.title, status, priority },
1274
1426
  });
1427
+ // T945 Stage A — mint a `task:T###` brain graph node at creation, not at
1428
+ // completion. Lazy registration defers execution until the actual outer commit,
1429
+ // including batch transactions; rollback never starts these graph effects.
1430
+ // Tracked (T10490) so the test harness can flush it before tearing down the
1431
+ // shared SQLite singleton; production still runs it fully detached.
1432
+ trackBackgroundOp(() => import('../memory/graph-auto-populate.js')
1433
+ .then(({ ensureTaskNode }) => ensureTaskNode(resolveOrCwd(cwd), taskId, options.title, {
1434
+ status,
1435
+ priority,
1436
+ type: taskType,
1437
+ ...(parentId ? { parentId } : {}),
1438
+ }))
1439
+ .catch(() => {
1440
+ /* Graph population is best-effort — never fail addTask. */
1441
+ }));
1442
+ // T1634 — LOOM auto-init for new epics.
1443
+ // Every new epic automatically initializes the RCASD-IVTR lifecycle pipeline
1444
+ // at the 'research' stage so 'cleo orchestrate ready --epic <id>' always
1445
+ // has a LOOM context (and never returns 'epic has no children' due to an
1446
+ // uninitialized pipeline). Fire-and-forget: failures are swallowed inside
1447
+ // initLoomForEpic so LOOM init never blocks or fails epic creation.
1448
+ if (taskType === 'epic') {
1449
+ // Tracked (T10490) — initLoomForEpic touches the shared tasks singleton via
1450
+ // getDb(); flushing it before a test teardown prevents cross-test races.
1451
+ trackBackgroundOp(() => import('../orchestrate/lifecycle-ops.js')
1452
+ .then(({ initLoomForEpic }) => initLoomForEpic(taskId, resolveOrCwd(cwd)))
1453
+ .catch(() => {
1454
+ /* LOOM init is best-effort — never fail addTask. */
1455
+ }));
1456
+ }
1275
1457
  });
1458
+ if (duplicateBypass) {
1459
+ // Compatibility mirror only; the task transaction contains authoritative evidence.
1460
+ const { appendDuplicateBypassAudit } = await import('./duplicate-bypass-audit.js');
1461
+ const committedBypass = { ...duplicateBypass, taskId, status: 'committed' };
1462
+ await appendDuplicateBypassAudit(committedBypass, resolveOrCwd(cwd));
1463
+ }
1276
1464
  // T10538 / design-point 5: surface the ancestor reopen on the add result so
1277
1465
  // the operator is never surprised by a parent silently transitioning out of
1278
1466
  // `done`. The reopen itself already happened inside the transaction above.
@@ -1282,42 +1470,12 @@ export async function addTask(options, cwd, accessor) {
1282
1470
  `because new child ${taskId} added unsatisfied work under a completed parent. ` +
1283
1471
  `Re-complete the ancestor(s) once ${taskId} is done.`);
1284
1472
  }
1285
- // T945 Stage A — mint a `task:T###` brain graph node at creation, not at
1286
- // completion. Prior to this hook, addTask never wrote to the graph, so new
1287
- // tasks were invisible until completeTask ran. Fire-and-forget: any failure
1288
- // is swallowed inside ensureTaskNode so graph writes never fail task creation.
1289
- // Tracked (T10490) so the test harness can flush it before tearing down the
1290
- // shared SQLite singleton; production still runs it fully detached.
1291
- trackBackgroundOp(import('../memory/graph-auto-populate.js')
1292
- .then(({ ensureTaskNode }) => ensureTaskNode(resolveOrCwd(cwd), taskId, options.title, {
1293
- status,
1294
- priority,
1295
- type: taskType,
1296
- ...(parentId ? { parentId } : {}),
1297
- }))
1298
- .catch(() => {
1299
- /* Graph population is best-effort — never fail addTask. */
1300
- }));
1301
- // T1634 — LOOM auto-init for new epics.
1302
- // Every new epic automatically initializes the RCASD-IVTR lifecycle pipeline
1303
- // at the 'research' stage so 'cleo orchestrate ready --epic <id>' always
1304
- // has a LOOM context (and never returns 'epic has no children' due to an
1305
- // uninitialized pipeline). Fire-and-forget: failures are swallowed inside
1306
- // initLoomForEpic so LOOM init never blocks or fails epic creation.
1307
- if (taskType === 'epic') {
1308
- // Tracked (T10490) — initLoomForEpic touches the shared tasks singleton via
1309
- // getDb(); flushing it before a test teardown prevents cross-test races.
1310
- trackBackgroundOp(import('../orchestrate/lifecycle-ops.js')
1311
- .then(({ initLoomForEpic }) => initLoomForEpic(taskId, resolveOrCwd(cwd)))
1312
- .catch(() => {
1313
- /* LOOM init is best-effort — never fail addTask. */
1314
- }));
1315
- }
1316
1473
  return {
1317
1474
  task,
1318
1475
  createdIds: { tasks: [taskId], acceptanceCriteria: createdAcceptanceCriteriaIds },
1319
1476
  ...(warnings.length > 0 && { warnings }),
1320
1477
  ...(reopenedAncestorIds.length > 0 && { reopenedAncestors: reopenedAncestorIds }),
1478
+ ...(autoDecomposed && { autoDecomposed }),
1321
1479
  };
1322
1480
  }
1323
1481
  //# sourceMappingURL=add.js.map