oh-my-codex 0.16.3 → 0.17.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 (339) hide show
  1. package/Cargo.lock +5 -5
  2. package/Cargo.toml +1 -1
  3. package/README.md +3 -3
  4. package/dist/catalog/__tests__/generator.test.js +2 -0
  5. package/dist/catalog/__tests__/generator.test.js.map +1 -1
  6. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js +9 -0
  7. package/dist/catalog/__tests__/plugin-bundle-ssot.test.js.map +1 -1
  8. package/dist/cli/__tests__/cleanup.test.js +27 -0
  9. package/dist/cli/__tests__/cleanup.test.js.map +1 -1
  10. package/dist/cli/__tests__/codex-plugin-layout.test.js +7 -5
  11. package/dist/cli/__tests__/codex-plugin-layout.test.js.map +1 -1
  12. package/dist/cli/__tests__/doctor-warning-copy.test.js +175 -7
  13. package/dist/cli/__tests__/doctor-warning-copy.test.js.map +1 -1
  14. package/dist/cli/__tests__/index.test.js +147 -12
  15. package/dist/cli/__tests__/index.test.js.map +1 -1
  16. package/dist/cli/__tests__/mcp-serve.test.js +4 -0
  17. package/dist/cli/__tests__/mcp-serve.test.js.map +1 -1
  18. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js +2 -0
  19. package/dist/cli/__tests__/ralph-goal-mode-contract.test.js.map +1 -1
  20. package/dist/cli/__tests__/ralph.test.js +47 -0
  21. package/dist/cli/__tests__/ralph.test.js.map +1 -1
  22. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js +10 -5
  23. package/dist/cli/__tests__/setup-hooks-shared-ownership.test.js.map +1 -1
  24. package/dist/cli/__tests__/setup-install-mode.test.js +299 -27
  25. package/dist/cli/__tests__/setup-install-mode.test.js.map +1 -1
  26. package/dist/cli/__tests__/setup-refresh.test.js +85 -3
  27. package/dist/cli/__tests__/setup-refresh.test.js.map +1 -1
  28. package/dist/cli/__tests__/setup-scope.test.js +1 -1
  29. package/dist/cli/__tests__/setup-scope.test.js.map +1 -1
  30. package/dist/cli/__tests__/setup-skills-overwrite.test.js +2 -1
  31. package/dist/cli/__tests__/setup-skills-overwrite.test.js.map +1 -1
  32. package/dist/cli/__tests__/team.test.js +108 -0
  33. package/dist/cli/__tests__/team.test.js.map +1 -1
  34. package/dist/cli/__tests__/ultragoal.test.js +91 -0
  35. package/dist/cli/__tests__/ultragoal.test.js.map +1 -1
  36. package/dist/cli/__tests__/uninstall.test.js +54 -8
  37. package/dist/cli/__tests__/uninstall.test.js.map +1 -1
  38. package/dist/cli/cleanup.d.ts.map +1 -1
  39. package/dist/cli/cleanup.js +8 -4
  40. package/dist/cli/cleanup.js.map +1 -1
  41. package/dist/cli/codex-feature-probe.d.ts +9 -0
  42. package/dist/cli/codex-feature-probe.d.ts.map +1 -0
  43. package/dist/cli/codex-feature-probe.js +28 -0
  44. package/dist/cli/codex-feature-probe.js.map +1 -0
  45. package/dist/cli/doctor.d.ts +1 -0
  46. package/dist/cli/doctor.d.ts.map +1 -1
  47. package/dist/cli/doctor.js +214 -23
  48. package/dist/cli/doctor.js.map +1 -1
  49. package/dist/cli/index.d.ts +17 -4
  50. package/dist/cli/index.d.ts.map +1 -1
  51. package/dist/cli/index.js +152 -24
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/cli/mcp-parity.js +8 -8
  54. package/dist/cli/mcp-parity.js.map +1 -1
  55. package/dist/cli/mcp-serve.d.ts.map +1 -1
  56. package/dist/cli/mcp-serve.js +4 -0
  57. package/dist/cli/mcp-serve.js.map +1 -1
  58. package/dist/cli/plugin-marketplace.d.ts +23 -0
  59. package/dist/cli/plugin-marketplace.d.ts.map +1 -1
  60. package/dist/cli/plugin-marketplace.js +203 -1
  61. package/dist/cli/plugin-marketplace.js.map +1 -1
  62. package/dist/cli/ralph.d.ts.map +1 -1
  63. package/dist/cli/ralph.js +21 -0
  64. package/dist/cli/ralph.js.map +1 -1
  65. package/dist/cli/setup-preferences.d.ts +4 -0
  66. package/dist/cli/setup-preferences.d.ts.map +1 -1
  67. package/dist/cli/setup-preferences.js +7 -0
  68. package/dist/cli/setup-preferences.js.map +1 -1
  69. package/dist/cli/setup.d.ts +5 -3
  70. package/dist/cli/setup.d.ts.map +1 -1
  71. package/dist/cli/setup.js +140 -51
  72. package/dist/cli/setup.js.map +1 -1
  73. package/dist/cli/ultragoal.d.ts +1 -1
  74. package/dist/cli/ultragoal.d.ts.map +1 -1
  75. package/dist/cli/ultragoal.js +70 -5
  76. package/dist/cli/ultragoal.js.map +1 -1
  77. package/dist/cli/uninstall.d.ts +2 -0
  78. package/dist/cli/uninstall.d.ts.map +1 -1
  79. package/dist/cli/uninstall.js +12 -3
  80. package/dist/cli/uninstall.js.map +1 -1
  81. package/dist/config/__tests__/codex-feature-flags.test.d.ts +2 -0
  82. package/dist/config/__tests__/codex-feature-flags.test.d.ts.map +1 -0
  83. package/dist/config/__tests__/codex-feature-flags.test.js +35 -0
  84. package/dist/config/__tests__/codex-feature-flags.test.js.map +1 -0
  85. package/dist/config/__tests__/codex-hooks.test.js +143 -9
  86. package/dist/config/__tests__/codex-hooks.test.js.map +1 -1
  87. package/dist/config/__tests__/generator-idempotent.test.js +85 -9
  88. package/dist/config/__tests__/generator-idempotent.test.js.map +1 -1
  89. package/dist/config/__tests__/generator-notify.test.js +116 -11
  90. package/dist/config/__tests__/generator-notify.test.js.map +1 -1
  91. package/dist/config/__tests__/wiki-config-contract.test.js +6 -3
  92. package/dist/config/__tests__/wiki-config-contract.test.js.map +1 -1
  93. package/dist/config/codex-feature-flags.d.ts +21 -0
  94. package/dist/config/codex-feature-flags.d.ts.map +1 -0
  95. package/dist/config/codex-feature-flags.js +56 -0
  96. package/dist/config/codex-feature-flags.js.map +1 -0
  97. package/dist/config/codex-hooks.d.ts +14 -13
  98. package/dist/config/codex-hooks.d.ts.map +1 -1
  99. package/dist/config/codex-hooks.js +108 -8
  100. package/dist/config/codex-hooks.js.map +1 -1
  101. package/dist/config/generator.d.ts +15 -3
  102. package/dist/config/generator.d.ts.map +1 -1
  103. package/dist/config/generator.js +233 -129
  104. package/dist/config/generator.js.map +1 -1
  105. package/dist/config/omx-first-party-mcp.d.ts +3 -1
  106. package/dist/config/omx-first-party-mcp.d.ts.map +1 -1
  107. package/dist/config/omx-first-party-mcp.js +9 -2
  108. package/dist/config/omx-first-party-mcp.js.map +1 -1
  109. package/dist/hooks/__tests__/design-skill.test.d.ts +2 -0
  110. package/dist/hooks/__tests__/design-skill.test.d.ts.map +1 -0
  111. package/dist/hooks/__tests__/design-skill.test.js +55 -0
  112. package/dist/hooks/__tests__/design-skill.test.js.map +1 -0
  113. package/dist/hooks/__tests__/keyword-detector.test.js +92 -2
  114. package/dist/hooks/__tests__/keyword-detector.test.js.map +1 -1
  115. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js +125 -1
  116. package/dist/hooks/__tests__/notify-hook-non-omx-guard.test.js.map +1 -1
  117. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js +265 -0
  118. package/dist/hooks/__tests__/notify-hook-tmux-heal.test.js.map +1 -1
  119. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts +2 -0
  120. package/dist/hooks/__tests__/skill-catalog-hygiene.test.d.ts.map +1 -0
  121. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js +84 -0
  122. package/dist/hooks/__tests__/skill-catalog-hygiene.test.js.map +1 -0
  123. package/dist/hooks/__tests__/skill-guidance-contract.test.js +41 -0
  124. package/dist/hooks/__tests__/skill-guidance-contract.test.js.map +1 -1
  125. package/dist/hooks/agents-overlay.js +2 -2
  126. package/dist/hooks/agents-overlay.js.map +1 -1
  127. package/dist/hooks/keyword-detector.d.ts +1 -0
  128. package/dist/hooks/keyword-detector.d.ts.map +1 -1
  129. package/dist/hooks/keyword-detector.js +12 -6
  130. package/dist/hooks/keyword-detector.js.map +1 -1
  131. package/dist/hooks/keyword-registry.d.ts.map +1 -1
  132. package/dist/hooks/keyword-registry.js +2 -0
  133. package/dist/hooks/keyword-registry.js.map +1 -1
  134. package/dist/hooks/prompt-guidance-contract.d.ts.map +1 -1
  135. package/dist/hooks/prompt-guidance-contract.js +47 -2
  136. package/dist/hooks/prompt-guidance-contract.js.map +1 -1
  137. package/dist/hud/__tests__/state.test.js +164 -0
  138. package/dist/hud/__tests__/state.test.js.map +1 -1
  139. package/dist/hud/state.d.ts.map +1 -1
  140. package/dist/hud/state.js +4 -5
  141. package/dist/hud/state.js.map +1 -1
  142. package/dist/mcp/__tests__/bootstrap.test.js +3 -0
  143. package/dist/mcp/__tests__/bootstrap.test.js.map +1 -1
  144. package/dist/mcp/__tests__/hermes-bridge.test.d.ts +2 -0
  145. package/dist/mcp/__tests__/hermes-bridge.test.d.ts.map +1 -0
  146. package/dist/mcp/__tests__/hermes-bridge.test.js +374 -0
  147. package/dist/mcp/__tests__/hermes-bridge.test.js.map +1 -0
  148. package/dist/mcp/__tests__/state-paths.test.js +155 -11
  149. package/dist/mcp/__tests__/state-paths.test.js.map +1 -1
  150. package/dist/mcp/__tests__/state-server.test.js +166 -0
  151. package/dist/mcp/__tests__/state-server.test.js.map +1 -1
  152. package/dist/mcp/bootstrap.d.ts +1 -1
  153. package/dist/mcp/bootstrap.d.ts.map +1 -1
  154. package/dist/mcp/bootstrap.js +2 -0
  155. package/dist/mcp/bootstrap.js.map +1 -1
  156. package/dist/mcp/hermes-bridge.d.ts +81 -0
  157. package/dist/mcp/hermes-bridge.d.ts.map +1 -0
  158. package/dist/mcp/hermes-bridge.js +400 -0
  159. package/dist/mcp/hermes-bridge.js.map +1 -0
  160. package/dist/mcp/hermes-server.d.ts +269 -0
  161. package/dist/mcp/hermes-server.d.ts.map +1 -0
  162. package/dist/mcp/hermes-server.js +121 -0
  163. package/dist/mcp/hermes-server.js.map +1 -0
  164. package/dist/mcp/state-paths.d.ts.map +1 -1
  165. package/dist/mcp/state-paths.js +64 -11
  166. package/dist/mcp/state-paths.js.map +1 -1
  167. package/dist/modes/__tests__/base-session-scope.test.js +22 -0
  168. package/dist/modes/__tests__/base-session-scope.test.js.map +1 -1
  169. package/dist/modes/__tests__/base-tmux-pane.test.js +88 -27
  170. package/dist/modes/__tests__/base-tmux-pane.test.js.map +1 -1
  171. package/dist/modes/base.d.ts.map +1 -1
  172. package/dist/modes/base.js +5 -0
  173. package/dist/modes/base.js.map +1 -1
  174. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts +2 -0
  175. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.d.ts.map +1 -0
  176. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js +316 -0
  177. package/dist/planning/__tests__/approved-execution-lifecycle-matrix.test.js.map +1 -0
  178. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts +2 -0
  179. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.d.ts.map +1 -0
  180. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js +481 -0
  181. package/dist/planning/__tests__/approved-launch-hint-lineage-matrix.test.js.map +1 -0
  182. package/dist/planning/__tests__/artifacts.test.js +533 -4
  183. package/dist/planning/__tests__/artifacts.test.js.map +1 -1
  184. package/dist/planning/__tests__/context-pack-status.test.js +524 -0
  185. package/dist/planning/__tests__/context-pack-status.test.js.map +1 -1
  186. package/dist/planning/__tests__/markdown-structure.test.d.ts +2 -0
  187. package/dist/planning/__tests__/markdown-structure.test.d.ts.map +1 -0
  188. package/dist/planning/__tests__/markdown-structure.test.js +459 -0
  189. package/dist/planning/__tests__/markdown-structure.test.js.map +1 -0
  190. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js +523 -1
  191. package/dist/planning/__tests__/ready-context-pack-role-refs.test.js.map +1 -1
  192. package/dist/planning/artifacts.d.ts +1 -1
  193. package/dist/planning/artifacts.d.ts.map +1 -1
  194. package/dist/planning/artifacts.js +227 -28
  195. package/dist/planning/artifacts.js.map +1 -1
  196. package/dist/planning/context-pack-status.d.ts +25 -0
  197. package/dist/planning/context-pack-status.d.ts.map +1 -1
  198. package/dist/planning/context-pack-status.js +272 -31
  199. package/dist/planning/context-pack-status.js.map +1 -1
  200. package/dist/planning/markdown-structure.d.ts +20 -0
  201. package/dist/planning/markdown-structure.d.ts.map +1 -0
  202. package/dist/planning/markdown-structure.js +137 -0
  203. package/dist/planning/markdown-structure.js.map +1 -0
  204. package/dist/ralph/__tests__/completion-audit.test.d.ts +2 -0
  205. package/dist/ralph/__tests__/completion-audit.test.d.ts.map +1 -0
  206. package/dist/ralph/__tests__/completion-audit.test.js +121 -0
  207. package/dist/ralph/__tests__/completion-audit.test.js.map +1 -0
  208. package/dist/ralph/completion-audit.d.ts +8 -0
  209. package/dist/ralph/completion-audit.d.ts.map +1 -0
  210. package/dist/ralph/completion-audit.js +99 -0
  211. package/dist/ralph/completion-audit.js.map +1 -0
  212. package/dist/scripts/__tests__/codex-native-hook.test.js +407 -15
  213. package/dist/scripts/__tests__/codex-native-hook.test.js.map +1 -1
  214. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts +2 -0
  215. package/dist/scripts/__tests__/notify-dispatcher.test.d.ts.map +1 -0
  216. package/dist/scripts/__tests__/notify-dispatcher.test.js +126 -0
  217. package/dist/scripts/__tests__/notify-dispatcher.test.js.map +1 -0
  218. package/dist/scripts/codex-native-hook.d.ts +1 -0
  219. package/dist/scripts/codex-native-hook.d.ts.map +1 -1
  220. package/dist/scripts/codex-native-hook.js +177 -71
  221. package/dist/scripts/codex-native-hook.js.map +1 -1
  222. package/dist/scripts/codex-native-pre-post.d.ts.map +1 -1
  223. package/dist/scripts/codex-native-pre-post.js +4 -2
  224. package/dist/scripts/codex-native-pre-post.js.map +1 -1
  225. package/dist/scripts/notify-dispatcher.js +30 -1
  226. package/dist/scripts/notify-dispatcher.js.map +1 -1
  227. package/dist/scripts/notify-hook/tmux-injection.d.ts.map +1 -1
  228. package/dist/scripts/notify-hook/tmux-injection.js +91 -2
  229. package/dist/scripts/notify-hook/tmux-injection.js.map +1 -1
  230. package/dist/scripts/notify-hook.js +3 -1
  231. package/dist/scripts/notify-hook.js.map +1 -1
  232. package/dist/state/__tests__/workflow-transition.test.js +102 -27
  233. package/dist/state/__tests__/workflow-transition.test.js.map +1 -1
  234. package/dist/state/mode-state-context.d.ts +2 -0
  235. package/dist/state/mode-state-context.d.ts.map +1 -1
  236. package/dist/state/mode-state-context.js +21 -0
  237. package/dist/state/mode-state-context.js.map +1 -1
  238. package/dist/state/operations.d.ts.map +1 -1
  239. package/dist/state/operations.js +9 -3
  240. package/dist/state/operations.js.map +1 -1
  241. package/dist/state/skill-active.d.ts +7 -0
  242. package/dist/state/skill-active.d.ts.map +1 -1
  243. package/dist/state/skill-active.js +25 -8
  244. package/dist/state/skill-active.js.map +1 -1
  245. package/dist/state/workflow-transition-reconcile.d.ts +1 -0
  246. package/dist/state/workflow-transition-reconcile.d.ts.map +1 -1
  247. package/dist/state/workflow-transition-reconcile.js +22 -15
  248. package/dist/state/workflow-transition-reconcile.js.map +1 -1
  249. package/dist/state/workflow-transition.js +3 -3
  250. package/dist/state/workflow-transition.js.map +1 -1
  251. package/dist/team/__tests__/approved-execution.test.js +39 -0
  252. package/dist/team/__tests__/approved-execution.test.js.map +1 -1
  253. package/dist/team/__tests__/runtime.test.js +5 -0
  254. package/dist/team/__tests__/runtime.test.js.map +1 -1
  255. package/dist/team/__tests__/scaling.test.js +497 -2
  256. package/dist/team/__tests__/scaling.test.js.map +1 -1
  257. package/dist/team/__tests__/state-root.test.js +1 -1
  258. package/dist/team/__tests__/state-root.test.js.map +1 -1
  259. package/dist/team/__tests__/worker-bootstrap.test.js +8 -0
  260. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  261. package/dist/team/approved-execution.d.ts.map +1 -1
  262. package/dist/team/approved-execution.js +3 -0
  263. package/dist/team/approved-execution.js.map +1 -1
  264. package/dist/team/scaling.d.ts.map +1 -1
  265. package/dist/team/scaling.js +43 -0
  266. package/dist/team/scaling.js.map +1 -1
  267. package/dist/team/state-root.d.ts.map +1 -1
  268. package/dist/team/state-root.js +4 -0
  269. package/dist/team/state-root.js.map +1 -1
  270. package/dist/team/state.d.ts.map +1 -1
  271. package/dist/team/state.js +2 -6
  272. package/dist/team/state.js.map +1 -1
  273. package/dist/ultragoal/__tests__/artifacts.test.js +245 -1
  274. package/dist/ultragoal/__tests__/artifacts.test.js.map +1 -1
  275. package/dist/ultragoal/__tests__/docs-contract.test.js +21 -0
  276. package/dist/ultragoal/__tests__/docs-contract.test.js.map +1 -1
  277. package/dist/ultragoal/artifacts.d.ts +52 -2
  278. package/dist/ultragoal/artifacts.d.ts.map +1 -1
  279. package/dist/ultragoal/artifacts.js +301 -15
  280. package/dist/ultragoal/artifacts.js.map +1 -1
  281. package/dist/utils/__tests__/paths.test.js +31 -1
  282. package/dist/utils/__tests__/paths.test.js.map +1 -1
  283. package/dist/utils/paths.d.ts +6 -0
  284. package/dist/utils/paths.d.ts.map +1 -1
  285. package/dist/utils/paths.js +18 -0
  286. package/dist/utils/paths.js.map +1 -1
  287. package/dist/wiki/lifecycle.js +4 -4
  288. package/dist/wiki/lifecycle.js.map +1 -1
  289. package/package.json +1 -1
  290. package/plugins/oh-my-codex/.codex-plugin/plugin.json +1 -1
  291. package/plugins/oh-my-codex/.mcp.json +13 -5
  292. package/plugins/oh-my-codex/skills/analyze/SKILL.md +0 -2
  293. package/plugins/oh-my-codex/skills/autopilot/SKILL.md +2 -2
  294. package/plugins/oh-my-codex/skills/code-review/SKILL.md +1 -3
  295. package/plugins/oh-my-codex/skills/deep-interview/SKILL.md +5 -7
  296. package/plugins/oh-my-codex/skills/design/SKILL.md +180 -0
  297. package/plugins/oh-my-codex/skills/doctor/SKILL.md +2 -2
  298. package/plugins/oh-my-codex/skills/omx-setup/SKILL.md +3 -3
  299. package/plugins/oh-my-codex/skills/pipeline/SKILL.md +3 -3
  300. package/plugins/oh-my-codex/skills/plan/SKILL.md +3 -6
  301. package/plugins/oh-my-codex/skills/ralph/SKILL.md +9 -10
  302. package/plugins/oh-my-codex/skills/skill/SKILL.md +2 -1
  303. package/plugins/oh-my-codex/skills/ultragoal/SKILL.md +36 -3
  304. package/plugins/oh-my-codex/skills/ultraqa/SKILL.md +175 -64
  305. package/plugins/oh-my-codex/skills/ultrawork/SKILL.md +8 -8
  306. package/plugins/oh-my-codex/skills/visual-ralph/SKILL.md +2 -2
  307. package/plugins/oh-my-codex/skills/wiki/SKILL.md +13 -13
  308. package/skills/analyze/SKILL.md +0 -2
  309. package/skills/ask-claude/SKILL.md +5 -3
  310. package/skills/ask-gemini/SKILL.md +5 -3
  311. package/skills/autopilot/SKILL.md +2 -2
  312. package/skills/code-review/SKILL.md +1 -3
  313. package/skills/deep-interview/SKILL.md +5 -7
  314. package/skills/design/SKILL.md +180 -0
  315. package/skills/doctor/SKILL.md +2 -2
  316. package/skills/ecomode/SKILL.md +105 -1
  317. package/skills/frontend-ui-ux/SKILL.md +6 -24
  318. package/skills/git-master/SKILL.md +2 -4
  319. package/skills/omx-setup/SKILL.md +3 -3
  320. package/skills/pipeline/SKILL.md +3 -3
  321. package/skills/plan/SKILL.md +3 -6
  322. package/skills/ralph/SKILL.md +9 -10
  323. package/skills/skill/SKILL.md +2 -1
  324. package/skills/swarm/SKILL.md +5 -3
  325. package/skills/tdd/SKILL.md +95 -1
  326. package/skills/ultragoal/SKILL.md +36 -3
  327. package/skills/ultraqa/SKILL.md +175 -64
  328. package/skills/ultrawork/SKILL.md +8 -8
  329. package/skills/visual-ralph/SKILL.md +2 -2
  330. package/skills/web-clone/SKILL.md +348 -1
  331. package/skills/wiki/SKILL.md +13 -13
  332. package/src/scripts/__tests__/codex-native-hook.test.ts +437 -14
  333. package/src/scripts/__tests__/notify-dispatcher.test.ts +153 -0
  334. package/src/scripts/codex-native-hook.ts +205 -61
  335. package/src/scripts/codex-native-pre-post.ts +4 -1
  336. package/src/scripts/notify-dispatcher.ts +40 -1
  337. package/src/scripts/notify-hook/tmux-injection.ts +110 -3
  338. package/src/scripts/notify-hook.ts +3 -1
  339. package/templates/catalog-manifest.json +9 -2
@@ -27,5 +27,26 @@ describe('ultragoal docs contract', () => {
27
27
  assert.match(doc, /Active or incomplete wrong Codex goals remain strict mismatch errors/i);
28
28
  assert.match(doc, /must not be used to bypass active-goal mismatch protection/i);
29
29
  });
30
+ it('documents the mandatory final cleanup and review gate', () => {
31
+ const docs = [
32
+ loadDoc('docs/ultragoal.md'),
33
+ loadDoc('skills/ultragoal/SKILL.md'),
34
+ loadDoc('plugins/oh-my-codex/skills/ultragoal/SKILL.md'),
35
+ ];
36
+ for (const doc of docs) {
37
+ assert.match(doc, /Mandatory final cleanup and review gate/);
38
+ assert.match(doc, /ai-slop-cleaner/);
39
+ assert.match(doc, /passed\/no-op report/);
40
+ assert.match(doc, /post-cleaner verification/i);
41
+ assert.match(doc, /\$code-review/);
42
+ assert.match(doc, /record-review-blockers/);
43
+ assert.match(doc, /review_blocked/);
44
+ assert.match(doc, /quality-gate-json/);
45
+ assert.match(doc, /APPROVE/);
46
+ assert.match(doc, /CLEAR/);
47
+ assert.doesNotMatch(doc, /not_applicable/);
48
+ assert.doesNotMatch(doc, /On the final story only, call `update_goal/);
49
+ }
50
+ });
30
51
  });
31
52
  //# sourceMappingURL=docs-contract.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"docs-contract.test.js","sourceRoot":"","sources":["../../../src/ultragoal/__tests__/docs-contract.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAE9C,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,GAAG,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAEzC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,+CAA+C,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,uDAAuD,CAAC,CAAC;QAC3E,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,sFAAsF,CAAC,CAAC;QAC1G,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,iFAAiF,CAAC,CAAC;IACvG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,GAAG,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAEzC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,oDAAoD,CAAC,CAAC;QACxE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,6CAA6C,CAAC,CAAC;QACjE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,uEAAuE,CAAC,CAAC;QAC3F,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,6DAA6D,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"docs-contract.test.js","sourceRoot":"","sources":["../../../src/ultragoal/__tests__/docs-contract.test.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ export declare const ULTRAGOAL_DIR = ".omx/ultragoal";
2
2
  export declare const ULTRAGOAL_BRIEF = "brief.md";
3
3
  export declare const ULTRAGOAL_GOALS = "goals.json";
4
4
  export declare const ULTRAGOAL_LEDGER = "ledger.jsonl";
5
- export type UltragoalStatus = 'pending' | 'in_progress' | 'complete' | 'failed';
5
+ export type UltragoalStatus = 'pending' | 'in_progress' | 'complete' | 'failed' | 'review_blocked';
6
6
  export type UltragoalCodexGoalMode = 'aggregate' | 'per_story';
7
7
  export interface UltragoalItem {
8
8
  id: string;
@@ -16,9 +16,16 @@ export interface UltragoalItem {
16
16
  startedAt?: string;
17
17
  completedAt?: string;
18
18
  failedAt?: string;
19
+ reviewBlockedAt?: string;
19
20
  evidence?: string;
20
21
  failureReason?: string;
21
22
  }
23
+ export interface UltragoalAggregateCompletion {
24
+ status: 'complete';
25
+ completedAt: string;
26
+ evidence: string;
27
+ codexGoal?: unknown;
28
+ }
22
29
  export interface UltragoalPlan {
23
30
  version: 1;
24
31
  createdAt: string;
@@ -28,17 +35,19 @@ export interface UltragoalPlan {
28
35
  ledgerPath: string;
29
36
  codexGoalMode?: UltragoalCodexGoalMode;
30
37
  codexObjective?: string;
38
+ aggregateCompletion?: UltragoalAggregateCompletion;
31
39
  activeGoalId?: string;
32
40
  goals: UltragoalItem[];
33
41
  }
34
42
  export interface UltragoalLedgerEntry {
35
43
  ts: string;
36
- event: 'plan_created' | 'goal_started' | 'goal_resumed' | 'goal_completed' | 'goal_blocked' | 'goal_failed' | 'goal_retried';
44
+ event: 'plan_created' | 'goal_started' | 'goal_resumed' | 'goal_completed' | 'goal_blocked' | 'goal_failed' | 'goal_retried' | 'aggregate_completed' | 'goal_added' | 'final_review_failed' | 'goal_review_blocked';
37
45
  goalId?: string;
38
46
  status?: UltragoalStatus;
39
47
  message?: string;
40
48
  codexGoal?: unknown;
41
49
  evidence?: string;
50
+ qualityGate?: UltragoalQualityGate;
42
51
  }
43
52
  export interface CreateUltragoalOptions {
44
53
  brief: string;
@@ -60,14 +69,44 @@ export interface CheckpointOptions {
60
69
  status: Extract<UltragoalStatus, 'complete' | 'failed'> | 'blocked';
61
70
  evidence?: string;
62
71
  codexGoal?: unknown;
72
+ qualityGate?: unknown;
73
+ allowActiveFinalCodexGoal?: boolean;
74
+ now?: Date;
75
+ }
76
+ export interface AddUltragoalGoalOptions {
77
+ title: string;
78
+ objective: string;
79
+ evidence?: string;
63
80
  now?: Date;
64
81
  }
82
+ export interface RecordFinalReviewBlockersOptions extends AddUltragoalGoalOptions {
83
+ goalId: string;
84
+ codexGoal?: unknown;
85
+ }
86
+ export interface UltragoalQualityGate {
87
+ aiSlopCleaner: {
88
+ status: 'passed';
89
+ evidence: string;
90
+ };
91
+ verification: {
92
+ status: 'passed';
93
+ commands: string[];
94
+ evidence: string;
95
+ };
96
+ codeReview: {
97
+ recommendation: 'APPROVE';
98
+ architectStatus: 'CLEAR';
99
+ evidence: string;
100
+ };
101
+ }
65
102
  export declare class UltragoalError extends Error {
66
103
  }
67
104
  export declare function ultragoalDir(cwd: string): string;
68
105
  export declare function ultragoalBriefPath(cwd: string): string;
69
106
  export declare function ultragoalGoalsPath(cwd: string): string;
70
107
  export declare function ultragoalLedgerPath(cwd: string): string;
108
+ export declare function isFinalRunCompletionCandidate(plan: UltragoalPlan, goal: UltragoalItem): boolean;
109
+ export declare function isUltragoalDone(plan: UltragoalPlan): boolean;
71
110
  export declare function deriveGoalCandidates(brief: string): Array<{
72
111
  title: string;
73
112
  objective: string;
@@ -80,8 +119,14 @@ export declare function summarizeUltragoalPlan(plan: UltragoalPlan): {
80
119
  inProgress: number;
81
120
  complete: number;
82
121
  failed: number;
122
+ reviewBlocked: number;
123
+ aggregateComplete: boolean;
83
124
  activeGoalId?: string;
84
125
  };
126
+ export declare function addUltragoalGoal(cwd: string, options: AddUltragoalGoalOptions): Promise<{
127
+ plan: UltragoalPlan;
128
+ goal: UltragoalItem;
129
+ }>;
85
130
  export declare function startNextUltragoal(cwd: string, options?: StartNextOptions): Promise<{
86
131
  plan: UltragoalPlan;
87
132
  goal: UltragoalItem | null;
@@ -89,5 +134,10 @@ export declare function startNextUltragoal(cwd: string, options?: StartNextOptio
89
134
  done: boolean;
90
135
  }>;
91
136
  export declare function checkpointUltragoal(cwd: string, options: CheckpointOptions): Promise<UltragoalPlan>;
137
+ export declare function recordFinalReviewBlockers(cwd: string, options: RecordFinalReviewBlockersOptions): Promise<{
138
+ plan: UltragoalPlan;
139
+ blockedGoal: UltragoalItem;
140
+ addedGoal: UltragoalItem;
141
+ }>;
92
142
  export declare function buildCodexGoalInstruction(goal: UltragoalItem, plan: UltragoalPlan): string;
93
143
  //# sourceMappingURL=artifacts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/ultragoal/artifacts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/ultragoal/artifacts.ts"],"names":[],"mappings":"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"}
@@ -32,9 +32,65 @@ function cleanLine(line) {
32
32
  function normalizeObjective(value) {
33
33
  return value.replace(/\s+/g, ' ').trim();
34
34
  }
35
+ function textMentionsUltragoalPlanArtifact(value) {
36
+ const normalized = (value ?? '').toLowerCase();
37
+ return normalized.includes(ULTRAGOAL_DIR.toLowerCase())
38
+ || normalized.includes(ULTRAGOAL_GOALS.toLowerCase())
39
+ || normalized.includes(ULTRAGOAL_LEDGER.toLowerCase());
40
+ }
41
+ function textMentionsGoalId(value, goalId) {
42
+ return (value ?? '').toLowerCase().includes(goalId.toLowerCase());
43
+ }
44
+ function textHasCompletionValidationEvidence(value) {
45
+ const normalized = (value ?? '').toLowerCase();
46
+ const hasImplementationCompletion = /\b(?:planned work|implementation|deliverables?|scope|task|work)\b/.test(normalized)
47
+ && /\b(?:done|complete|completed|finished|shipped)\b/.test(normalized);
48
+ const hasValidation = /\b(?:validation|verification|tests?|build|lint|review|quality gate|code-review)\b/.test(normalized)
49
+ && /\b(?:passed|complete|completed|clean|green|approve|approved|clear)\b/.test(normalized);
50
+ return hasImplementationCompletion && hasValidation;
51
+ }
52
+ async function snapshotObjectiveMapsToUltragoalPlan(cwd, snapshotObjective) {
53
+ const actual = normalizeObjective(snapshotObjective).toLowerCase();
54
+ if (textMentionsUltragoalPlanArtifact(actual))
55
+ return true;
56
+ if (actual.length < 24)
57
+ return false;
58
+ try {
59
+ const brief = normalizeObjective(await readFile(ultragoalBriefPath(cwd), 'utf-8')).toLowerCase();
60
+ if (!brief || brief.length < 24)
61
+ return false;
62
+ return brief.includes(actual) || actual.includes(brief);
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ async function canReconcileCompletedTaskScopedAggregateSnapshot(cwd, plan, goal, snapshotObjective, evidence) {
69
+ if (codexGoalMode(plan) !== 'aggregate')
70
+ return false;
71
+ if (goal.status !== 'in_progress' || plan.activeGoalId !== goal.id)
72
+ return false;
73
+ if (!textMentionsUltragoalPlanArtifact(evidence))
74
+ return false;
75
+ if (!textMentionsGoalId(evidence, goal.id))
76
+ return false;
77
+ if (!textHasCompletionValidationEvidence(evidence))
78
+ return false;
79
+ return snapshotObjectiveMapsToUltragoalPlan(cwd, snapshotObjective);
80
+ }
81
+ function buildCompletedLegacyGoalRemediation(goal) {
82
+ return [
83
+ 'If get_goal returns a different completed legacy/thread objective, do not repeat --status complete in this thread.',
84
+ `Record a non-terminal blocker with: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<different completed get_goal JSON or path>".`,
85
+ 'Then continue this ultragoal in a fresh Codex thread in the same repo/worktree and create the intended goal there.',
86
+ ].join(' ');
87
+ }
35
88
  function codexGoalMode(plan) {
36
89
  return plan.codexGoalMode ?? 'per_story';
37
90
  }
91
+ function isResolvedStatus(status) {
92
+ return status === 'complete' || status === 'review_blocked';
93
+ }
38
94
  function aggregateCodexObjective(goals) {
39
95
  const prefix = `Complete all ultragoal stories in ${ULTRAGOAL_DIR}/${ULTRAGOAL_GOALS}: `;
40
96
  const suffix = goals.map((goal) => `${goal.id} ${goal.title}`).join('; ');
@@ -51,8 +107,20 @@ function expectedCodexObjective(plan, goal) {
51
107
  ? (plan.codexObjective ?? aggregateCodexObjective(plan.goals))
52
108
  : goal.objective;
53
109
  }
54
- function isFinalAggregateCheckpoint(plan, goal) {
55
- return plan.goals.every((candidate) => candidate.id === goal.id || candidate.status === 'complete');
110
+ export function isFinalRunCompletionCandidate(plan, goal) {
111
+ return plan.goals.every((candidate) => candidate.id === goal.id || isResolvedStatus(candidate.status));
112
+ }
113
+ export function isUltragoalDone(plan) {
114
+ if (plan.aggregateCompletion?.status === 'complete')
115
+ return true;
116
+ if (plan.goals.length === 0)
117
+ return true;
118
+ if (plan.goals.some((goal) => goal.status === 'pending' || goal.status === 'in_progress' || goal.status === 'failed'))
119
+ return false;
120
+ if (!plan.goals.every((goal) => isResolvedStatus(goal.status)))
121
+ return false;
122
+ const latestNonReviewBlocked = [...plan.goals].reverse().find((goal) => goal.status !== 'review_blocked');
123
+ return latestNonReviewBlocked?.status === 'complete';
56
124
  }
57
125
  function titleFromObjective(objective, fallback) {
58
126
  const firstLine = objective.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? fallback;
@@ -156,12 +224,87 @@ export function summarizeUltragoalPlan(plan) {
156
224
  inProgress: plan.goals.filter((goal) => goal.status === 'in_progress').length,
157
225
  complete: plan.goals.filter((goal) => goal.status === 'complete').length,
158
226
  failed: plan.goals.filter((goal) => goal.status === 'failed').length,
227
+ reviewBlocked: plan.goals.filter((goal) => goal.status === 'review_blocked').length,
228
+ aggregateComplete: plan.aggregateCompletion?.status === 'complete',
159
229
  activeGoalId: plan.activeGoalId,
160
230
  };
161
231
  }
232
+ function assertNonEmpty(value, label) {
233
+ const trimmed = value?.trim();
234
+ if (!trimmed)
235
+ throw new UltragoalError(`Missing ${label}.`);
236
+ return trimmed;
237
+ }
238
+ function appendGoalToPlan(plan, options, now) {
239
+ const title = assertNonEmpty(options.title, '--title');
240
+ const objective = assertNonEmpty(options.objective, '--objective');
241
+ const goal = {
242
+ id: normalizeGoalId(title, plan.goals.length),
243
+ title,
244
+ objective,
245
+ status: 'pending',
246
+ attempt: 0,
247
+ createdAt: now,
248
+ updatedAt: now,
249
+ evidence: options.evidence,
250
+ };
251
+ plan.goals.push(goal);
252
+ plan.updatedAt = now;
253
+ return goal;
254
+ }
255
+ export async function addUltragoalGoal(cwd, options) {
256
+ const plan = await readUltragoalPlan(cwd);
257
+ const now = iso(options.now);
258
+ const goal = appendGoalToPlan(plan, options, now);
259
+ await writePlan(cwd, plan);
260
+ await appendLedger(cwd, {
261
+ ts: now,
262
+ event: 'goal_added',
263
+ goalId: goal.id,
264
+ status: goal.status,
265
+ evidence: options.evidence,
266
+ message: goal.title,
267
+ });
268
+ return { plan, goal };
269
+ }
270
+ function validateQualityGate(value) {
271
+ if (!value || typeof value !== 'object') {
272
+ throw new UltragoalError('Final ultragoal completion requires --quality-gate-json with ai-slop-cleaner, verification, and code-review evidence.');
273
+ }
274
+ const gate = value;
275
+ const cleaner = gate.aiSlopCleaner;
276
+ const verification = gate.verification;
277
+ const review = gate.codeReview;
278
+ if (!cleaner || typeof cleaner !== 'object')
279
+ throw new UltragoalError('Final quality gate is missing aiSlopCleaner evidence.');
280
+ if (cleaner.status !== 'passed') {
281
+ throw new UltragoalError('Final quality gate requires aiSlopCleaner.status="passed"; run ai-slop-cleaner even when it is a no-op.');
282
+ }
283
+ assertNonEmpty(cleaner.evidence, 'aiSlopCleaner.evidence');
284
+ if (!verification || typeof verification !== 'object')
285
+ throw new UltragoalError('Final quality gate is missing verification evidence.');
286
+ if (verification.status !== 'passed')
287
+ throw new UltragoalError('Final quality gate requires verification.status="passed".');
288
+ if (!Array.isArray(verification.commands) || verification.commands.length === 0 || verification.commands.some((command) => typeof command !== 'string' || command.trim() === '')) {
289
+ throw new UltragoalError('Final quality gate requires non-empty verification.commands.');
290
+ }
291
+ assertNonEmpty(verification.evidence, 'verification.evidence');
292
+ if (!review || typeof review !== 'object')
293
+ throw new UltragoalError('Final quality gate is missing codeReview evidence.');
294
+ if (review.recommendation !== 'APPROVE') {
295
+ throw new UltragoalError('Final code-review must be clean: codeReview.recommendation must be APPROVE; use record-review-blockers for COMMENT or REQUEST CHANGES.');
296
+ }
297
+ if (review.architectStatus !== 'CLEAR') {
298
+ throw new UltragoalError('Final code-review must be clean: codeReview.architectStatus must be CLEAR; use record-review-blockers for WATCH or BLOCK.');
299
+ }
300
+ assertNonEmpty(review.evidence, 'codeReview.evidence');
301
+ return gate;
302
+ }
162
303
  export async function startNextUltragoal(cwd, options = {}) {
163
304
  const plan = await readUltragoalPlan(cwd);
164
305
  const now = iso(options.now);
306
+ if (plan.aggregateCompletion?.status === 'complete')
307
+ return { plan, goal: null, resumed: false, done: true };
165
308
  const existing = plan.goals.find((goal) => goal.status === 'in_progress');
166
309
  if (existing) {
167
310
  await appendLedger(cwd, { ts: now, event: 'goal_resumed', goalId: existing.id, status: existing.status, message: 'Resuming active ultragoal' });
@@ -174,7 +317,7 @@ export async function startNextUltragoal(cwd, options = {}) {
174
317
  await appendLedger(cwd, { ts: now, event: 'goal_retried', goalId: next.id, status: 'pending', message: next.failureReason });
175
318
  }
176
319
  if (!next)
177
- return { plan, goal: null, resumed: false, done: plan.goals.every((goal) => goal.status === 'complete') };
320
+ return { plan, goal: null, resumed: false, done: isUltragoalDone(plan) };
178
321
  next.status = 'in_progress';
179
322
  next.attempt += 1;
180
323
  next.startedAt = now;
@@ -224,21 +367,70 @@ export async function checkpointUltragoal(cwd, options) {
224
367
  });
225
368
  return plan;
226
369
  }
370
+ let aggregateCompletion;
227
371
  if (options.status === 'complete') {
228
372
  const expectedObjective = expectedCodexObjective(plan, goal);
229
373
  const aggregateMode = codexGoalMode(plan) === 'aggregate';
230
- const finalAggregateCheckpoint = aggregateMode && isFinalAggregateCheckpoint(plan, goal);
231
- const reconciliation = reconcileCodexGoalSnapshot(options.codexGoal === undefined ? null : parseCodexGoalSnapshot(options.codexGoal), {
374
+ const finalRunCheckpoint = isFinalRunCompletionCandidate(plan, goal);
375
+ const snapshot = options.codexGoal === undefined ? null : parseCodexGoalSnapshot(options.codexGoal);
376
+ const reconciliation = reconcileCodexGoalSnapshot(snapshot, {
232
377
  expectedObjective,
233
378
  allowedStatuses: aggregateMode
234
- ? (finalAggregateCheckpoint ? ['complete'] : ['active'])
379
+ ? (finalRunCheckpoint && !options.allowActiveFinalCodexGoal ? ['complete'] : ['active'])
235
380
  : ['complete'],
236
381
  requireSnapshot: true,
237
- requireComplete: !aggregateMode || finalAggregateCheckpoint,
382
+ requireComplete: !aggregateMode || (finalRunCheckpoint && !options.allowActiveFinalCodexGoal),
238
383
  });
239
384
  if (!reconciliation.ok) {
240
- throw new UltragoalError(formatCodexGoalReconciliation(reconciliation));
385
+ const completedTaskScopedAggregateSnapshot = snapshot?.available
386
+ && snapshot.status === 'complete'
387
+ && Boolean(snapshot.objective)
388
+ && normalizeObjective(snapshot.objective ?? '') !== normalizeObjective(expectedObjective)
389
+ && await canReconcileCompletedTaskScopedAggregateSnapshot(cwd, plan, goal, snapshot.objective ?? '', options.evidence);
390
+ if (completedTaskScopedAggregateSnapshot) {
391
+ aggregateCompletion = {
392
+ status: 'complete',
393
+ completedAt: now,
394
+ evidence: assertNonEmpty(options.evidence, '--evidence'),
395
+ codexGoal: options.codexGoal,
396
+ };
397
+ }
398
+ else {
399
+ const taskScopedRequirement = aggregateMode && snapshot?.status === 'complete' && Boolean(snapshot.objective)
400
+ ? ' Completed task-scoped aggregate reconciliation requires the checkpoint goal to be the active in-progress OMX goal, evidence that names that active OMX goal id, names .omx/ultragoal/goals.json or ledger.jsonl, includes completed implementation plus validation/review evidence, and a get_goal objective that maps to the ultragoal brief/artifact.'
401
+ : '';
402
+ const remediation = reconciliation.snapshot.available
403
+ && reconciliation.snapshot.status === 'complete'
404
+ && Boolean(reconciliation.snapshot.objective)
405
+ && normalizeObjective(reconciliation.snapshot.objective ?? '') !== normalizeObjective(expectedObjective)
406
+ ? ` ${buildCompletedLegacyGoalRemediation(goal)}`
407
+ : '';
408
+ throw new UltragoalError(`${formatCodexGoalReconciliation(reconciliation)}${taskScopedRequirement}${remediation}`);
409
+ }
241
410
  }
411
+ if (finalRunCheckpoint && !options.allowActiveFinalCodexGoal)
412
+ goal.evidence = options.evidence;
413
+ }
414
+ const qualityGate = options.status === 'complete' && (aggregateCompletion !== undefined || (isFinalRunCompletionCandidate(plan, goal) && !options.allowActiveFinalCodexGoal))
415
+ ? validateQualityGate(options.qualityGate)
416
+ : undefined;
417
+ if (aggregateCompletion) {
418
+ plan.aggregateCompletion = aggregateCompletion;
419
+ if (plan.activeGoalId === goal.id)
420
+ delete plan.activeGoalId;
421
+ plan.updatedAt = now;
422
+ await writePlan(cwd, plan);
423
+ await appendLedger(cwd, {
424
+ ts: now,
425
+ event: 'aggregate_completed',
426
+ goalId: goal.id,
427
+ status: goal.status,
428
+ evidence: options.evidence,
429
+ codexGoal: options.codexGoal,
430
+ qualityGate,
431
+ message: 'Aggregate ultragoal plan completed via task-scoped Codex goal snapshot; microgoal ledger progress remains independent.',
432
+ });
433
+ return plan;
242
434
  }
243
435
  goal.status = options.status;
244
436
  goal.updatedAt = now;
@@ -265,9 +457,75 @@ export async function checkpointUltragoal(cwd, options) {
265
457
  status: goal.status,
266
458
  evidence: options.evidence,
267
459
  codexGoal: options.codexGoal,
460
+ qualityGate,
268
461
  });
269
462
  return plan;
270
463
  }
464
+ export async function recordFinalReviewBlockers(cwd, options) {
465
+ const plan = await readUltragoalPlan(cwd);
466
+ const goal = plan.goals.find((candidate) => candidate.id === options.goalId);
467
+ if (!goal)
468
+ throw new UltragoalError(`Unknown ultragoal id: ${options.goalId}`);
469
+ assertNonEmpty(options.evidence, '--evidence');
470
+ if (goal.status !== 'in_progress') {
471
+ throw new UltragoalError(`Cannot record final review blockers for ${goal.id} while it is ${goal.status}; start or resume the ultragoal first.`);
472
+ }
473
+ if (!isFinalRunCompletionCandidate(plan, goal)) {
474
+ throw new UltragoalError(`Cannot record final review blockers for ${goal.id}; it is not the only unresolved ultragoal story.`);
475
+ }
476
+ const now = iso(options.now);
477
+ const expectedObjective = expectedCodexObjective(plan, goal);
478
+ const aggregateMode = codexGoalMode(plan) === 'aggregate';
479
+ const reconciliation = reconcileCodexGoalSnapshot(options.codexGoal === undefined ? null : parseCodexGoalSnapshot(options.codexGoal), {
480
+ expectedObjective,
481
+ allowedStatuses: ['active'],
482
+ requireSnapshot: true,
483
+ requireComplete: false,
484
+ });
485
+ if (!reconciliation.ok) {
486
+ throw new UltragoalError(formatCodexGoalReconciliation(reconciliation));
487
+ }
488
+ const addedGoal = appendGoalToPlan(plan, options, now);
489
+ goal.status = 'review_blocked';
490
+ goal.reviewBlockedAt = now;
491
+ goal.updatedAt = now;
492
+ goal.completedAt = undefined;
493
+ goal.failedAt = undefined;
494
+ goal.failureReason = undefined;
495
+ goal.evidence = options.evidence;
496
+ if (plan.activeGoalId === goal.id)
497
+ delete plan.activeGoalId;
498
+ plan.updatedAt = now;
499
+ await writePlan(cwd, plan);
500
+ await appendLedger(cwd, {
501
+ ts: now,
502
+ event: 'final_review_failed',
503
+ goalId: goal.id,
504
+ status: goal.status,
505
+ evidence: options.evidence,
506
+ codexGoal: options.codexGoal,
507
+ message: aggregateMode
508
+ ? 'Final aggregate code-review was not clean; blocker story was appended while Codex goal remains active.'
509
+ : 'Final per-story code-review was not clean; blocker story was appended and may require a fresh/available Codex goal context.',
510
+ });
511
+ await appendLedger(cwd, {
512
+ ts: now,
513
+ event: 'goal_added',
514
+ goalId: addedGoal.id,
515
+ status: addedGoal.status,
516
+ evidence: options.evidence,
517
+ message: addedGoal.title,
518
+ });
519
+ await appendLedger(cwd, {
520
+ ts: now,
521
+ event: 'goal_review_blocked',
522
+ goalId: goal.id,
523
+ status: goal.status,
524
+ evidence: options.evidence,
525
+ codexGoal: options.codexGoal,
526
+ });
527
+ return { plan, blockedGoal: goal, addedGoal };
528
+ }
271
529
  export function buildCodexGoalInstruction(goal, plan) {
272
530
  if (codexGoalMode(plan) === 'aggregate')
273
531
  return buildAggregateCodexGoalInstruction(goal, plan);
@@ -278,6 +536,7 @@ function buildPerStoryCodexGoalInstruction(goal, plan) {
278
536
  objective: goal.objective,
279
537
  ...(goal.tokenBudget ? { token_budget: goal.tokenBudget } : {}),
280
538
  };
539
+ const finalStory = isFinalRunCompletionCandidate(plan, goal);
281
540
  return [
282
541
  'Ultragoal active-goal handoff',
283
542
  `Plan: ${plan.goalsPath}`,
@@ -290,8 +549,24 @@ function buildPerStoryCodexGoalInstruction(goal, plan) {
290
549
  '- If get_goal returns a different completed legacy/thread goal and create_goal rejects because this thread already has a completed goal, continue this ultragoal in a fresh Codex thread (same repo/worktree) and create the payload there.',
291
550
  `- To preserve the durable ledger before switching threads, record the non-terminal blocker without failing this goal: omx ultragoal checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<get_goal JSON or path>"`,
292
551
  '- Work only this goal until its completion audit passes.',
293
- '- After the goal is actually complete, call update_goal({status: "complete"}), call get_goal again for a fresh completion snapshot, then checkpoint the ledger with:',
294
- ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>"`,
552
+ finalStory
553
+ ? '- Final mandatory quality gate: run ai-slop-cleaner on changed files even when it is a no-op, rerun verification, then run $code-review.'
554
+ : '- This is not the final ultragoal story; do not run the final ai-slop-cleaner/$code-review gate yet.',
555
+ finalStory
556
+ ? '- If final $code-review is not APPROVE with architect status CLEAR, do not call update_goal. Record blockers with:'
557
+ : '- After the goal is actually complete, call update_goal({status: "complete"}), call get_goal again for a fresh completion snapshot, then checkpoint the ledger with:',
558
+ finalStory
559
+ ? ` omx ultragoal record-review-blockers --goal-id ${goal.id} --title "Resolve final code-review blockers" --objective "<blocker-resolution objective>" --evidence "<review findings>" --codex-goal-json "<active get_goal JSON or path>"`
560
+ : ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>"`,
561
+ finalStory
562
+ ? '- In legacy per-story mode, the blocker story may require a fresh/available Codex goal context because this story remains an active incomplete Codex goal; do not claim it is complete.'
563
+ : null,
564
+ finalStory
565
+ ? '- If final $code-review is clean (APPROVE + CLEAR), call update_goal({status: "complete"}), call get_goal again, then checkpoint with --quality-gate-json:'
566
+ : null,
567
+ finalStory
568
+ ? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`
569
+ : null,
295
570
  '- If blocked or failed, checkpoint with --status failed and the failure evidence; rerun complete-goals --retry-failed to resume.',
296
571
  '',
297
572
  'create_goal payload:',
@@ -299,11 +574,11 @@ function buildPerStoryCodexGoalInstruction(goal, plan) {
299
574
  '',
300
575
  'Objective:',
301
576
  goal.objective,
302
- ].join('\n');
577
+ ].filter((line) => line !== null).join('\n');
303
578
  }
304
579
  function buildAggregateCodexGoalInstruction(goal, plan) {
305
580
  const objective = plan.codexObjective ?? aggregateCodexObjective(plan.goals);
306
- const finalStory = isFinalAggregateCheckpoint(plan, goal);
581
+ const finalStory = isFinalRunCompletionCandidate(plan, goal);
307
582
  const createPayload = { objective };
308
583
  const checkpointStatus = finalStory ? 'complete' : 'active';
309
584
  return [
@@ -318,10 +593,21 @@ function buildAggregateCodexGoalInstruction(goal, plan) {
318
593
  '- If get_goal reports the same aggregate objective as active, continue this OMX story without creating a new Codex goal.',
319
594
  '- If a different active or incomplete Codex goal exists, finish/checkpoint that goal before starting this ultragoal; do not replace hidden Codex state from the shell.',
320
595
  finalStory
321
- ? '- This is the final pending story: after the story and whole-run audit pass, call update_goal({status: "complete"}), then call get_goal again for a fresh complete snapshot.'
596
+ ? '- This is the final pending story: run the mandatory final ai-slop-cleaner pass, rerun verification, and run $code-review before any update_goal call.'
322
597
  : '- This is not the final story: do not call update_goal yet; the aggregate Codex goal must remain active while later OMX stories remain.',
598
+ finalStory
599
+ ? '- If final $code-review is not APPROVE with architect status CLEAR, do not call update_goal. Record durable blocker work first:'
600
+ : null,
601
+ finalStory
602
+ ? ` omx ultragoal record-review-blockers --goal-id ${goal.id} --title "Resolve final code-review blockers" --objective "<blocker-resolution objective>" --evidence "<review findings>" --codex-goal-json "<active get_goal JSON or path>"`
603
+ : null,
604
+ finalStory
605
+ ? '- If final $code-review is clean (APPROVE + CLEAR), call update_goal({status: "complete"}), call get_goal again for a fresh complete snapshot, then checkpoint with --quality-gate-json.'
606
+ : null,
323
607
  `- Checkpoint this OMX story with a fresh get_goal snapshot whose objective matches the aggregate payload and whose status is ${checkpointStatus}:`,
324
- ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>"`,
608
+ finalStory
609
+ ? ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh complete get_goal JSON or path>" --quality-gate-json "<quality gate JSON or path>"`
610
+ : ` omx ultragoal checkpoint --goal-id ${goal.id} --status complete --evidence "<tests/files/PR evidence>" --codex-goal-json "<fresh get_goal JSON or path>"`,
325
611
  '- If blocked or failed, checkpoint with --status failed and the failure evidence; rerun complete-goals --retry-failed to resume.',
326
612
  '',
327
613
  'create_goal payload:',
@@ -332,6 +618,6 @@ function buildAggregateCodexGoalInstruction(goal, plan) {
332
618
  '',
333
619
  'Current OMX story objective:',
334
620
  goal.objective,
335
- ].join('\n');
621
+ ].filter((line) => line !== null).join('\n');
336
622
  }
337
623
  //# sourceMappingURL=artifacts.js.map