oh-my-opencode 4.19.0 → 4.19.1

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 (214) hide show
  1. package/.agents/command/omomomo.md +1 -1
  2. package/.agents/skills/omomomo/SKILL.md +1 -1
  3. package/.opencode/command/omomomo.md +1 -1
  4. package/README.ja.md +6 -6
  5. package/README.ko.md +6 -6
  6. package/README.md +6 -6
  7. package/README.ru.md +6 -6
  8. package/README.zh-cn.md +6 -6
  9. package/dist/agents/atlas/agent.d.ts +1 -1
  10. package/dist/agents/gpt-prompt-identity.d.ts +3 -0
  11. package/dist/agents/sisyphus/gpt-5-5.d.ts +1 -1
  12. package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +1 -0
  13. package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +2 -2
  14. package/dist/cli/index.js +148 -94
  15. package/dist/cli-node/index.js +148 -94
  16. package/dist/config/schema/agent-overrides.d.ts +48 -48
  17. package/dist/config/schema/categories.d.ts +6 -6
  18. package/dist/config/schema/codegraph.d.ts +2 -0
  19. package/dist/config/schema/fallback-models.d.ts +5 -5
  20. package/dist/config/schema/oh-my-opencode-config.d.ts +50 -48
  21. package/dist/hooks/codegraph-bootstrap/hook.d.ts +3 -2
  22. package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
  23. package/dist/hooks/start-work/notepad-scaffold.d.ts +10 -0
  24. package/dist/index.js +2612 -1473
  25. package/dist/oh-my-opencode.schema.json +11 -0
  26. package/dist/shared/omo-process-sweep.d.ts +18 -0
  27. package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
  28. package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
  29. package/dist/skills/ulw-plan/SKILL.md +20 -1
  30. package/dist/testing/create-plugin-module.d.ts +1 -0
  31. package/dist/tui.js +66 -56
  32. package/package.json +13 -13
  33. package/packages/git-bash-mcp/dist/cli.js +54 -8
  34. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +60 -0
  35. package/packages/lsp-core/src/lsp/client.ts +14 -1
  36. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +2 -2
  37. package/packages/lsp-core/src/mcp.ts +9 -0
  38. package/packages/lsp-daemon/dist/cli.js +319 -51
  39. package/packages/lsp-daemon/dist/client.js +136 -48
  40. package/packages/lsp-daemon/dist/daemon-client.d.ts +0 -10
  41. package/packages/lsp-daemon/dist/daemon-client.js +4 -34
  42. package/packages/lsp-daemon/dist/daemon-failure-result.d.ts +3 -0
  43. package/packages/lsp-daemon/dist/daemon-failure-result.js +38 -0
  44. package/packages/lsp-daemon/dist/daemon-request-error.d.ts +14 -0
  45. package/packages/lsp-daemon/dist/daemon-request-error.js +26 -0
  46. package/packages/lsp-daemon/dist/daemon-server.js +5 -1
  47. package/packages/lsp-daemon/dist/index.js +137 -48
  48. package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
  49. package/packages/lsp-daemon/dist/proxy.js +1 -0
  50. package/packages/lsp-daemon/dist/version-reap.d.ts +26 -0
  51. package/packages/lsp-daemon/dist/version-reap.js +182 -0
  52. package/packages/lsp-tools-mcp/dist/cli.js +61 -10
  53. package/packages/lsp-tools-mcp/dist/lsp/manager.js +6 -1
  54. package/packages/lsp-tools-mcp/dist/mcp.js +61 -10
  55. package/packages/lsp-tools-mcp/dist/tools.js +6 -1
  56. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  57. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +64 -8
  58. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  59. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  60. package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +22 -2
  61. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +555 -251
  62. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +178 -89
  63. package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
  64. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
  65. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +3 -1
  66. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +98 -32
  67. package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +5 -0
  68. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +15 -6
  69. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +6 -2
  70. package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +1 -0
  71. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +148 -0
  72. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +31 -2
  73. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +1 -1
  74. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +65 -1
  75. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -7
  76. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +1 -1
  77. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +57 -3
  78. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +41 -0
  79. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +109 -8
  80. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +2 -2
  81. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +43 -0
  82. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  83. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  84. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  85. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  86. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  87. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  88. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  89. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +80 -40
  90. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  91. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  92. package/packages/omo-codex/plugin/components/rules/dist/cli.js +11 -0
  93. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  94. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  95. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +11 -0
  96. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +60 -0
  97. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  98. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  99. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  100. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  101. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  102. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  103. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +2 -2
  104. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
  105. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
  106. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
  107. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +2 -2
  108. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
  109. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +1 -1
  110. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  111. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  112. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +20 -1
  113. package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +1 -1
  114. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +42 -0
  115. package/packages/omo-codex/plugin/components/ulw-loop/README.md +6 -4
  116. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.d.ts +21 -0
  117. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +64 -0
  118. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +15 -2
  119. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +1 -1
  120. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +2 -1
  121. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
  122. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +3 -3
  123. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.d.ts +3 -0
  124. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +85 -0
  125. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +0 -1
  126. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -33
  127. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +998 -593
  128. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +1 -0
  129. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +1 -1
  130. package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +2 -0
  131. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +6 -0
  132. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.d.ts +1 -0
  133. package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.js +3 -0
  134. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +1 -0
  135. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +4 -0
  136. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +1 -0
  137. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +10 -2
  138. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +1 -1
  139. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.d.ts +15 -0
  140. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +84 -0
  141. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.d.ts +5 -0
  142. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.js +81 -0
  143. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +7 -59
  144. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +12 -4
  145. package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.d.ts +9 -0
  146. package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.js +122 -0
  147. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  148. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  149. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +8 -6
  150. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +84 -0
  151. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +13 -2
  152. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +1 -1
  153. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +1 -1
  154. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +3 -3
  155. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +49 -0
  156. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +13 -45
  157. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +1 -0
  158. package/packages/omo-codex/plugin/components/ulw-loop/src/constants.ts +2 -0
  159. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +7 -0
  160. package/packages/omo-codex/plugin/components/ulw-loop/src/goal-status.ts +4 -0
  161. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +4 -1
  162. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +20 -2
  163. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +1 -1
  164. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +125 -0
  165. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-mutations.ts +59 -0
  166. package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +6 -58
  167. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +12 -4
  168. package/packages/omo-codex/plugin/components/ulw-loop/src/validation-batch.ts +122 -0
  169. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +76 -0
  170. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint-continuation.test.ts +111 -0
  171. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-batch.test.ts +67 -0
  172. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-validation-batch.test.ts +57 -0
  173. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +1 -0
  174. package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +152 -0
  175. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +29 -0
  176. package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch-checkpoint.test.ts +147 -0
  177. package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch.test.ts +73 -0
  178. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  179. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  180. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  181. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  182. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  183. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  184. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  185. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  186. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  187. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  188. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  189. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +2 -2
  190. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  191. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +2 -2
  192. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  193. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +2 -2
  194. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  195. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  196. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  197. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  198. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  199. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  200. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  201. package/packages/omo-codex/plugin/package-lock.json +41 -41
  202. package/packages/omo-codex/plugin/package.json +1 -1
  203. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +43 -0
  204. package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
  205. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +8 -6
  206. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +20 -1
  207. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +9 -9
  208. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +26 -0
  209. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +41 -0
  210. package/packages/omo-codex/scripts/install-dist/install-local.mjs +49 -5
  211. package/packages/omo-codex/scripts/install-marketplace-cache.test.mjs +4 -1
  212. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
  213. package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
  214. package/packages/shared-skills/skills/ulw-plan/SKILL.md +20 -1
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook session-start",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.19.0) Loading Project Rules"
10
+ "statusMessage": "(OmO 4.19.1) Loading Project Rules"
11
11
  }
12
12
  ]
13
13
  }
@@ -19,7 +19,7 @@
19
19
  "type": "command",
20
20
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
21
21
  "timeout": 10,
22
- "statusMessage": "(OmO 4.19.0) Loading Project Rules"
22
+ "statusMessage": "(OmO 4.19.1) Loading Project Rules"
23
23
  }
24
24
  ]
25
25
  }
@@ -32,7 +32,7 @@
32
32
  "type": "command",
33
33
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
34
34
  "timeout": 10,
35
- "statusMessage": "(OmO 4.19.0) Matching Project Rules"
35
+ "statusMessage": "(OmO 4.19.1) Matching Project Rules"
36
36
  }
37
37
  ]
38
38
  }
@@ -45,7 +45,7 @@
45
45
  "type": "command",
46
46
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
47
47
  "timeout": 10,
48
- "statusMessage": "(OmO 4.19.0) Resetting Project Rule Cache"
48
+ "statusMessage": "(OmO 4.19.1) Resetting Project Rule Cache"
49
49
  }
50
50
  ]
51
51
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-rules",
3
- "version": "4.19.0",
3
+ "version": "4.19.1",
4
4
  "description": "Codex plugin that injects project rule files into model context through lifecycle hooks.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -21,6 +21,17 @@ const POST_COMPACT_MIN_RESERVED_TOKENS = 8_000;
21
21
  const POST_COMPACT_MIN_GUIDE_CHARS = 500;
22
22
  const FALLBACK_CONTEXT_WINDOW_TOKENS = 200_000;
23
23
  const MODEL_CONTEXT_BUDGETS: readonly ModelContextBudget[] = [
24
+ { slug: "gpt-5.6-sol", contextWindowTokens: 372_000, effectivePercent: DEFAULT_EFFECTIVE_CONTEXT_WINDOW_PERCENT },
25
+ {
26
+ slug: "gpt-5.6-terra",
27
+ contextWindowTokens: 372_000,
28
+ effectivePercent: DEFAULT_EFFECTIVE_CONTEXT_WINDOW_PERCENT,
29
+ },
30
+ {
31
+ slug: "gpt-5.6-luna",
32
+ contextWindowTokens: 372_000,
33
+ effectivePercent: DEFAULT_EFFECTIVE_CONTEXT_WINDOW_PERCENT,
34
+ },
24
35
  { slug: "gpt-5.5", contextWindowTokens: 272_000, effectivePercent: DEFAULT_EFFECTIVE_CONTEXT_WINDOW_PERCENT },
25
36
  { slug: "gpt-5.4-mini", contextWindowTokens: 272_000, effectivePercent: DEFAULT_EFFECTIVE_CONTEXT_WINDOW_PERCENT },
26
37
  {
@@ -76,6 +76,66 @@ describe("post-compact context budget", () => {
76
76
  expect(budget.maxRuleChars).toBeLessThanOrEqual(budget.maxResultChars);
77
77
  });
78
78
 
79
+ it("#given gpt-5.6-sol within its 372k window #when resolving post-compact budget #then keeps configured post-compact cap", () => {
80
+ // given
81
+ const transcriptPath = writeCompactedTranscript("A".repeat(541_500));
82
+
83
+ // when
84
+ const budget = withPostCompactBudget(CONFIG, { model: "gpt-5.6-sol", transcriptPath });
85
+
86
+ // then
87
+ expect(budget.maxRuleChars).toBe(CONFIG.postCompactMaxRuleChars);
88
+ expect(budget.maxResultChars).toBe(CONFIG.postCompactMaxResultChars);
89
+ });
90
+
91
+ it("#given gpt-5.6-terra within its 372k window #when resolving post-compact budget #then keeps configured post-compact cap", () => {
92
+ // given
93
+ const transcriptPath = writeCompactedTranscript("A".repeat(541_500));
94
+
95
+ // when
96
+ const budget = withPostCompactBudget(CONFIG, { model: "gpt-5.6-terra", transcriptPath });
97
+
98
+ // then
99
+ expect(budget.maxRuleChars).toBe(CONFIG.postCompactMaxRuleChars);
100
+ expect(budget.maxResultChars).toBe(CONFIG.postCompactMaxResultChars);
101
+ });
102
+
103
+ it("#given gpt-5.6-luna within its 372k window #when resolving post-compact budget #then keeps configured post-compact cap", () => {
104
+ // given
105
+ const transcriptPath = writeCompactedTranscript("A".repeat(541_500));
106
+
107
+ // when
108
+ const budget = withPostCompactBudget(CONFIG, { model: "gpt-5.6-luna", transcriptPath });
109
+
110
+ // then
111
+ expect(budget.maxRuleChars).toBe(CONFIG.postCompactMaxRuleChars);
112
+ expect(budget.maxResultChars).toBe(CONFIG.postCompactMaxResultChars);
113
+ });
114
+
115
+ it("#given provider-prefixed gpt-5.6 variant within its 372k window #when resolving post-compact budget #then keeps configured post-compact cap", () => {
116
+ // given
117
+ const transcriptPath = writeCompactedTranscript("A".repeat(541_500));
118
+
119
+ // when
120
+ const budget = withPostCompactBudget(CONFIG, { model: "openai/gpt-5.6-sol", transcriptPath });
121
+
122
+ // then
123
+ expect(budget.maxRuleChars).toBe(CONFIG.postCompactMaxRuleChars);
124
+ expect(budget.maxResultChars).toBe(CONFIG.postCompactMaxResultChars);
125
+ });
126
+
127
+ it("#given unknown model with the same transcript #when resolving post-compact budget #then keeps the 200k fallback floor", () => {
128
+ // given
129
+ const transcriptPath = writeCompactedTranscript("A".repeat(541_500));
130
+
131
+ // when
132
+ const budget = withPostCompactBudget(CONFIG, { model: "unknown-model", transcriptPath });
133
+
134
+ // then
135
+ expect(budget.maxResultChars).toBe(500);
136
+ expect(budget.maxRuleChars).toBe(500);
137
+ });
138
+
79
139
  it("#given context pressure marker after compaction #when resolving post-compact budget #then shrinks projected rule injection", () => {
80
140
  // given
81
141
  const transcriptPath = writeCompactedPressureTranscript("small compacted summary");
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook stop",
9
9
  "timeout": 10,
10
- "statusMessage": "(OmO 4.19.0) Checking Start-Work Continuation"
10
+ "statusMessage": "(OmO 4.19.1) Checking Start-Work Continuation"
11
11
  }
12
12
  ]
13
13
  }
@@ -19,7 +19,7 @@
19
19
  "type": "command",
20
20
  "command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook subagent-stop",
21
21
  "timeout": 10,
22
- "statusMessage": "(OmO 4.19.0) Checking Start-Work Continuation"
22
+ "statusMessage": "(OmO 4.19.1) Checking Start-Work Continuation"
23
23
  }
24
24
  ]
25
25
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-start-work-continuation",
3
- "version": "4.19.0",
3
+ "version": "4.19.1",
4
4
  "description": "Codex Stop hook continuation injector for omo-codex start-work plans.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 10,
11
- "statusMessage": "(OmO 4.19.0) Checking Thread Title Hygiene"
11
+ "statusMessage": "(OmO 4.19.1) Checking Thread Title Hygiene"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-teammode",
3
- "version": "4.19.0",
3
+ "version": "4.19.1",
4
4
  "description": "Codex team-mode hook component that keeps background thread titles descriptive after create_thread.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook session-start",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.19.0) Recording Session Telemetry"
10
+ "statusMessage": "(OmO 4.19.1) Recording Session Telemetry"
11
11
  }
12
12
  ]
13
13
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-telemetry",
3
- "version": "4.19.0",
3
+ "version": "4.19.1",
4
4
  "description": "Codex plugin component that emits omo-codex anonymous daily-active telemetry on SessionStart.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -1,8 +1,8 @@
1
1
  name = "lazycodex-clone-fidelity-reviewer"
2
2
  description = "Read-only LazyCodex clone / design-system fidelity reviewer. Verifies clone and design-port work is a rigorous, token-driven design system, not a pasted screenshot or hardcoded fake."
3
3
  nickname_candidates = ["Clone Fidelity Reviewer"]
4
- model = "gpt-5.6-sol"
5
- model_reasoning_effort = "xhigh"
4
+ model = "gpt-5.6-terra"
5
+ model_reasoning_effort = "high"
6
6
 
7
7
  developer_instructions = """
8
8
  Role: clone / design-system fidelity reviewer. Read-only.
@@ -1,8 +1,8 @@
1
1
  name = "lazycodex-code-reviewer"
2
2
  description = "Read-only LazyCodex code-quality reviewer. Audits diffs, tests, and risk with strict artifact-backed findings."
3
3
  nickname_candidates = ["Code Reviewer"]
4
- model = "gpt-5.6-sol"
5
- model_reasoning_effort = "xhigh"
4
+ model = "gpt-5.6-terra"
5
+ model_reasoning_effort = "medium"
6
6
 
7
7
  developer_instructions = """
8
8
  Role: code quality reviewer. Read-only.
@@ -2,7 +2,7 @@ name = "lazycodex-gate-reviewer"
2
2
  description = "Read-only LazyCodex gate reviewer. Re-audits executor, code review, and QA artifacts before final approval."
3
3
  nickname_candidates = ["Gate Reviewer"]
4
4
  model = "gpt-5.6-sol"
5
- model_reasoning_effort = "high"
5
+ model_reasoning_effort = "low"
6
6
 
7
7
  developer_instructions = """
8
8
  Role: final gate reviewer. Read-only.
@@ -2,7 +2,7 @@ name = "lazycodex-worker-high"
2
2
  description = "LazyCodex high-difficulty implementation worker, sized for LARGE changes: a new module or abstraction, a cross-module refactor, concurrency/security/migration work, or any real, complex, big problem that has ONE clear goal. Owns the smallest correct change and records evidence before claiming completion."
3
3
  nickname_candidates = ["High Worker"]
4
4
  model = "gpt-5.6-sol"
5
- model_reasoning_effort = "max"
5
+ model_reasoning_effort = "medium"
6
6
 
7
7
  developer_instructions = """
8
8
  Role: implementation executor. You own the task end to end.
@@ -1,8 +1,8 @@
1
1
  name = "lazycodex-worker-medium"
2
2
  description = "LazyCodex medium-difficulty implementation worker, sized for MID-SIZED changes: a standard feature inside existing layers, touching a few files along established patterns. Owns the smallest correct change and records evidence before claiming completion."
3
3
  nickname_candidates = ["Medium Worker"]
4
- model = "gpt-5.6-luna"
5
- model_reasoning_effort = "max"
4
+ model = "gpt-5.6-terra"
5
+ model_reasoning_effort = "high"
6
6
 
7
7
  developer_instructions = """
8
8
  Role: implementation executor. You own the task end to end.
@@ -2,7 +2,7 @@ name = "plan"
2
2
  description = "Strategic planning consultant for work with unresolved design uncertainty after discovery. Produces one executable plan; never implements. Writes the plan to .omo/plans/<slug>.md."
3
3
  nickname_candidates = ["Planner"]
4
4
  model = "gpt-5.6-sol"
5
- model_reasoning_effort = "max"
5
+ model_reasoning_effort = "high"
6
6
 
7
7
  developer_instructions = """
8
8
  Role: strategic planning consultant. You produce a single, bulletproof, executable work plan only when discovery leaves unresolved design uncertainty.
@@ -60,7 +60,7 @@ function buildUltraworkAdditionalContext(options = {}) {
60
60
  }
61
61
 
62
62
  // components/ultrawork/src/codex-hook.ts
63
- var ULTRAWORK_CURRENT_PROMPT_PATTERN = /(?:ultrawork|ulw)/i;
63
+ var ULTRAWORK_CURRENT_PROMPT_PATTERN = /(?:ultrawork|ulw(?!-(?:plan|research)))/i;
64
64
  var ULTRAWORK_DIRECTIVE_MARKER = "<ultrawork-mode>";
65
65
  var TRANSCRIPT_SEARCH_BYTES = 512000;
66
66
  var CONTEXT_PRESSURE_MARKERS = [
@@ -7,7 +7,7 @@
7
7
  "type": "command",
8
8
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
9
9
  "timeout": 5,
10
- "statusMessage": "(OmO 4.19.0) Checking Ultrawork Trigger"
10
+ "statusMessage": "(OmO 4.19.1) Checking Ultrawork Trigger"
11
11
  }
12
12
  ]
13
13
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-ultrawork",
3
- "version": "4.19.0",
3
+ "version": "4.19.1",
4
4
  "description": "Codex plugin that injects the ultrawork orchestration directive and ships LazyCodex planning, review, QA, and gate agent roles.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -13,11 +13,30 @@ You are **Prometheus**, a planning consultant. You turn a vague or large request
13
13
 
14
14
  Outcome-first: explore a lot, ask few sharp questions - or none, when the intent is fuzzy (see routing) - and stop the moment the plan is done.
15
15
 
16
+ ## MANDATORY OPENING ANNOUNCEMENT
17
+
18
+ The FIRST user-visible line of the turn that activates this skill MUST be exactly:
19
+
20
+ `ULW-PLAN MODE ENABLED!`
21
+
22
+ If another active mode mandates its own first line (ultrawork does), print that line first and this marker on the next line - both contracts stay satisfied.
23
+
24
+ Directly under the marker, before any exploration, state the working contract once, in your own words, carrying ALL of these commitments:
25
+
26
+ 1. **Persona + no-implementation pledge** - from now on you work as Prometheus, a planning consultant, and you will never start implementation - no product-code edits, no implementer subagents - until the user explicitly says okay; even then, approval authorizes writing the plan only, and execution starts in a separate worker session (e.g. `$start-work`).
27
+ 2. **Workflow preview** - the order of what happens next: parallel read-only exploration (plus outside research when the repo cannot answer) until the open unknowns are resolved; the intent verdict from INTENT ROUTING, announced; questions to the user ONLY when a genuine owner-decision survives exploration - or when exploration and research both come back empty on a fork the plan cannot proceed without; then the approval brief, and the plan is written only after the explicit okay.
28
+
29
+ Example opening (adapt the wording, keep every commitment):
30
+
31
+ > ULW-PLAN MODE ENABLED!
32
+ > From now on I am working as Prometheus, a planning consultant. I will not start any implementation until you explicitly say okay - and approval authorizes writing the plan only; execution starts separately (e.g. `$start-work`).
33
+ > Next, in order: (1) parallel read-only exploration and research, (2) intent verdict announced (CLEAR or UNCLEAR, plus whether high-accuracy review is required), (3) questions only for the forks exploration cannot settle - or where research finds nothing on a blocking decision, (4) approval brief, then (5) the plan is written after your okay.
34
+
16
35
  ## INTENT ROUTING - pick ONE intent reference
17
36
 
18
37
  **Review modifiers are a gate trigger, not a style cue.** If the user says "high accuracy", "ultra high accuracy", "고정밀", "deep review", or equivalent - in ANY turn, even appended to a follow-up question and even after the plan already exists - set `review_required: true` in the draft: the dual high-accuracy review (native `momus` + the independent Codex CLI review) is now REQUIRED before handoff, and if the plan already exists you run it this same turn. Answering the current question more carefully does NOT satisfy it. This does NOT choose CLEAR/UNCLEAR and does NOT suppress interview.
19
38
 
20
- After grounding, make ONE judgment, record `intent: clear|unclear` plus `review_required`, **ANNOUNCE both to the user in one line**, then load ONE intent reference (you ALSO read `references/full-workflow.md` for the shared mechanics - see below). The test keys on whether the desired **OUTCOME** is clear, NOT on request length. The announcement is the user's first signal of whether they will be interviewed and whether high-accuracy review is already requested - never skip it.
39
+ After grounding, make ONE judgment, record `intent: clear|unclear` plus `review_required`, **ANNOUNCE both to the user in one line**, then load ONE intent reference (you ALSO read `references/full-workflow.md` for the shared mechanics - see below). The test keys on whether the desired **OUTCOME** is clear, NOT on request length. This verdict line and the opening announcement above are the two mandatory user-visible signals of a planning session - it tells the user whether they will be interviewed and whether high-accuracy review is already requested; never skip either.
21
40
 
22
41
  > "Intent: **CLEAR**, review required - you specified the endpoint and asked for high accuracy. I will ask only the genuine forks, then run the high-accuracy review after approval."
23
42
  > "Intent: **UNCLEAR**, review required - 'make auth better' is open-ended and you asked for high accuracy. I will choose best-practice defaults, then run the high-accuracy review automatically."
@@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
2
2
 
3
3
  import { buildUltraworkAdditionalContext, type UltraworkAdditionalContextOptions } from "./skill-pointer.js";
4
4
 
5
- const ULTRAWORK_CURRENT_PROMPT_PATTERN = /(?:ultrawork|ulw)/i;
5
+ const ULTRAWORK_CURRENT_PROMPT_PATTERN = /(?:ultrawork|ulw(?!-(?:plan|research)))/i;
6
6
  const ULTRAWORK_DIRECTIVE_MARKER = "<ultrawork-mode>";
7
7
  const TRANSCRIPT_SEARCH_BYTES = 512_000;
8
8
  const CONTEXT_PRESSURE_MARKERS = [
@@ -88,6 +88,48 @@ describe("codex ultrawork trigger policy", () => {
88
88
  expect(isUltraworkPrompt(prompt)).toBe(true);
89
89
  });
90
90
 
91
+ it("#given prompt invokes ulw-plan or ulw-research skills #when hook runs #then does not emit directive", () => {
92
+ // given
93
+ const prompts = [
94
+ "$omo:ulw-plan refactor the auth module",
95
+ "omo:ulw-plan",
96
+ "/ulw-plan",
97
+ "ulw-plan",
98
+ "$omo:ulw-research how does the hook pipeline work",
99
+ "ulw-research",
100
+ "please run ULW-PLAN for this",
101
+ ] as const;
102
+
103
+ // when
104
+ const outputs = prompts.map((prompt) => runUserPromptSubmitHook({ hook_event_name: "UserPromptSubmit", prompt }));
105
+
106
+ // then
107
+ expect(outputs).toEqual(["", "", "", "", "", "", ""]);
108
+ expect(prompts.map((prompt) => isUltraworkPrompt(prompt))).toEqual([false, false, false, false, false, false, false]);
109
+ });
110
+
111
+ it("#given prompt contains ultrawork or standalone ulw #when hook runs #then emits directive", () => {
112
+ // given
113
+ const prompts = [
114
+ "ultrawork this change",
115
+ "ulw",
116
+ "ulw ",
117
+ "ulw fix this failing test",
118
+ "ulw-loop keep iterating until green",
119
+ ] as const;
120
+
121
+ // when
122
+ const outputs = prompts.map((prompt) => runUserPromptSubmitHook({ hook_event_name: "UserPromptSubmit", prompt }));
123
+
124
+ // then
125
+ for (const output of outputs) {
126
+ const parsed = parseHookOutput(output);
127
+ expect(parsed.hookSpecificOutput.hookEventName).toBe("UserPromptSubmit");
128
+ expect(parsed.hookSpecificOutput.additionalContext).toMatch(/^<ultrawork-mode>/);
129
+ }
130
+ expect(prompts.map((prompt) => isUltraworkPrompt(prompt))).toEqual([true, true, true, true, true]);
131
+ });
132
+
91
133
  it("#given prior transcript contains triggers but current prompt does not #when hook runs #then does not emit directive", () => {
92
134
  // given
93
135
  const payload = {
@@ -11,11 +11,11 @@ Every subcommand below is implemented. Pass `--json` where supported for machine
11
11
  | Subcommand | Purpose |
12
12
  |------------|---------|
13
13
  | `omo ulw-loop help` | Print CLI usage. |
14
- | `omo ulw-loop create-goals` | Create repo-native goals and seed success criteria from a brief. |
14
+ | `omo ulw-loop create-goals` | Create repo-native goals and seed success criteria from a brief; optionally define review-boundary validation batches with `--validation-batch-json`. |
15
15
  | `omo ulw-loop status` | Report active goal, criteria, and evidence state. |
16
- | `omo ulw-loop complete-goals` | Start or resume the next eligible goal, or report aggregate completion / blocked handoff. |
17
- | `omo ulw-loop checkpoint` | Gate a goal transition with evidence; final completion requires a complete Codex goal snapshot and a passing quality gate. |
18
- | `omo ulw-loop steer` | Apply a steering mutation proposal to the plan. |
16
+ | `omo ulw-loop complete-goals` | Manual fallback to start or resume the next eligible goal, or report aggregate completion / blocked handoff. |
17
+ | `omo ulw-loop checkpoint` | Gate a goal transition with evidence; complete checkpoints auto-start the next eligible goal by default, with `--no-advance` preserving the legacy two-call flow. |
18
+ | `omo ulw-loop steer` | Apply one steering mutation proposal or an atomic all-or-nothing batch with `--proposals-json`. |
19
19
  | `omo ulw-loop add-goal` | Append a goal to the active plan. |
20
20
  | `omo ulw-loop criteria` | Inspect one goal's success criteria. |
21
21
  | `omo ulw-loop record-evidence` | Record observable evidence for one criterion. |
@@ -23,6 +23,8 @@ Every subcommand below is implemented. Pass `--json` where supported for machine
23
23
 
24
24
  The final quality gate parsed by `checkpoint` validates `codeReview`, `manualQa`, `gateReview`, `iteration`, and `criteriaCoverage`. `criteriaCoverage` records the original intent, desired outcome, user-facing outcome review, pass counts, and covered adversarial classes.
25
25
 
26
+ Validation batches are optional review boundaries declared at plan creation with `--validation-batch-json '[{"batchId":"VB001","memberIds":[...],"finalGoalId":"..."}]'`. The batch-final goal cannot complete until every other member is complete or superseded-resolved, every member criterion is pass, and a quality gate's coverage counts match the recomputed member criteria. Steering split/supersede mutations keep batch membership consistent and record `batch_updated`.
27
+
26
28
  ## Codex Plugin
27
29
 
28
30
  This directory is a component of the aggregate `@sisyphuslabs/omo-codex-plugin` root. Plugin discovery (`.codex-plugin/plugin.json`) is owned by that aggregate root, not by this component. The component ships:
@@ -0,0 +1,21 @@
1
+ import { type CheckpointUlwLoopArgs, type CheckpointUlwLoopResult } from "./checkpoint.js";
2
+ import { type UlwLoopGoalInstruction } from "./codex-goal-instruction.js";
3
+ import type { UlwLoopScope } from "./paths.js";
4
+ import type { UlwLoopItem } from "./types.js";
5
+ type ContinuationNext = {
6
+ readonly resumed: boolean;
7
+ readonly goal: UlwLoopItem;
8
+ readonly instruction: UlwLoopGoalInstruction;
9
+ } | {
10
+ readonly done: true;
11
+ readonly blocked: boolean;
12
+ readonly handoff: string;
13
+ };
14
+ export type CheckpointAndContinueResult = CheckpointUlwLoopResult & {
15
+ readonly next?: ContinuationNext;
16
+ };
17
+ export declare function checkpointAndContinue(repoRoot: string, args: CheckpointUlwLoopArgs & {
18
+ readonly advance: boolean;
19
+ }, scope?: UlwLoopScope): Promise<CheckpointAndContinueResult>;
20
+ export declare function checkpoint(repoRoot: string, argv: readonly string[], json: boolean, scope?: UlwLoopScope): Promise<number>;
21
+ export {};
@@ -0,0 +1,64 @@
1
+ import { checkpointUlwLoop } from "./checkpoint.js";
2
+ import { hasFlag, parseCodexGoalJson, readValue } from "./cli-arg-parser.js";
3
+ import { blockedDecisionHandoff, printJson } from "./cli-output.js";
4
+ import { buildCodexGoalInstruction } from "./codex-goal-instruction.js";
5
+ import { startNextUlwLoop, summarizeUlwLoopPlan } from "./plan-crud.js";
6
+ import { UlwLoopError } from "./types.js";
7
+ export async function checkpointAndContinue(repoRoot, args, scope) {
8
+ const result = await checkpointUlwLoop(repoRoot, args, scope);
9
+ if (args.status !== "complete" || result.aggregateCompletion !== undefined || !args.advance)
10
+ return result;
11
+ const next = await startNextUlwLoop(repoRoot, {}, scope);
12
+ if ("done" in next)
13
+ return { ...result, plan: next.plan, next: doneNext(next.plan) };
14
+ const instruction = buildCodexGoalInstruction({ plan: next.plan, goal: next.goal });
15
+ return { ...result, plan: next.plan, next: { resumed: next.resumed, goal: next.goal, instruction } };
16
+ }
17
+ export async function checkpoint(repoRoot, argv, json, scope) {
18
+ const goalId = required(argv, "--goal-id");
19
+ const statusValue = checkpointStatus(required(argv, "--status"));
20
+ const evidence = required(argv, "--evidence");
21
+ const codexGoalJson = await parseCodexGoalJson(statusValue === "complete" ? required(argv, "--codex-goal-json") : readValue(argv, "--codex-goal-json"));
22
+ if (statusValue === "complete" && codexGoalJson === undefined) {
23
+ throw new UlwLoopError("Missing --codex-goal-json.", "ULW_LOOP_CODEX_GOAL_JSON_REQUIRED");
24
+ }
25
+ const qualityGateJson = readValue(argv, "--quality-gate-json");
26
+ const args = {
27
+ goalId,
28
+ status: statusValue,
29
+ evidence,
30
+ advance: !hasFlag(argv, "--no-advance"),
31
+ ...(codexGoalJson === undefined ? {} : { codexGoalJson }),
32
+ ...(qualityGateJson === undefined ? {} : { qualityGateJson }),
33
+ };
34
+ const result = await checkpointAndContinue(repoRoot, args, scope);
35
+ if (json)
36
+ printJson({ ok: true, ...result, summary: summarizeUlwLoopPlan(result.plan) });
37
+ else
38
+ printCheckpointText(result);
39
+ return 0;
40
+ }
41
+ function printCheckpointText(result) {
42
+ process.stdout.write(`ulw-loop checkpoint: ${result.goal.id} -> ${result.goal.status}\n`);
43
+ if (result.next === undefined)
44
+ return;
45
+ if ("instruction" in result.next)
46
+ process.stdout.write(`${result.next.instruction.text}\n`);
47
+ else
48
+ process.stdout.write(`${result.next.handoff || "ulw-loop: all goals complete"}\n`);
49
+ }
50
+ function doneNext(plan) {
51
+ const handoff = blockedDecisionHandoff(plan);
52
+ return { done: true, blocked: handoff.length > 0, handoff };
53
+ }
54
+ function required(argv, flag) {
55
+ const value = readValue(argv, flag)?.trim();
56
+ if (value)
57
+ return value;
58
+ throw new UlwLoopError(`Missing ${flag}.`, "ULW_LOOP_ARGUMENT_MISSING", { details: { flag } });
59
+ }
60
+ function checkpointStatus(value) {
61
+ if (value === "complete" || value === "failed" || value === "blocked")
62
+ return value;
63
+ throw new UlwLoopError("Missing or invalid --status; expected complete, failed, or blocked.", "ULW_LOOP_STATUS_INVALID", { details: { status: value } });
64
+ }
@@ -1,4 +1,4 @@
1
- import { ulwLoopAttemptEvidenceDir } from "./paths.js";
1
+ // biome-ignore-all format: checkpoint stays under the pure LOC ceiling.
2
2
  import { existsSync, statSync } from "node:fs";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import { resolve } from "node:path";
@@ -6,9 +6,11 @@ import { buildTaskScopedAggregateReconciliationHint, canReconcileActiveFinalTask
6
6
  import { formatCodexGoalReconciliation, readCodexGoalSnapshotInput, reconcileCodexGoalSnapshot, } from "./codex-goal-snapshot.js";
7
7
  import { requireAllCriteriaPass, requireAllPlanCriteriaPass, requireEssentialCriteriaPass } from "./evidence.js";
8
8
  import { codexGoalMode, compatibleCodexObjectives, expectedCodexObjective, isFinalRunCompletionCandidate, } from "./goal-status.js";
9
+ import { ulwLoopAttemptEvidenceDir } from "./paths.js";
9
10
  import { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
10
11
  import { classifyExternalAuthorizationBlocker, clearGoalBlockerFields, sameBlockerOccurrences, validateQualityGate, } from "./quality-gate.js";
11
12
  import { iso, UlwLoopError } from "./types.js";
13
+ import { batchClosedBy, requireAllValidationBatchesClosed, requireBatchFinalReady, requireBatchGate } from "./validation-batch.js";
12
14
  const QUALITY_GATE_FS = { existsSync, statSync };
13
15
  function ulwLoopFail(message, code) {
14
16
  throw new UlwLoopError(message, code);
@@ -112,9 +114,11 @@ export async function checkpointUlwLoop(repoRoot, args, scope) {
112
114
  if (args.status === "complete") {
113
115
  const aggregate = codexGoalMode(plan) === "aggregate";
114
116
  const final = isFinalRunCompletionCandidate(plan, goal);
117
+ const closesBatch = batchClosedBy(plan, goal.id) !== undefined;
115
118
  if (final) {
116
119
  requireAllCriteriaPass(goal);
117
120
  requireAllPlanCriteriaPass(plan);
121
+ requireAllValidationBatchesClosed(plan, goal.id);
118
122
  }
119
123
  else if (aggregate)
120
124
  requireEssentialCriteriaPass(goal);
@@ -144,9 +148,13 @@ export async function checkpointUlwLoop(repoRoot, args, scope) {
144
148
  if (!taskScoped)
145
149
  throw new UlwLoopError(`${formatCodexGoalReconciliation(reconciliation)}${aggregate && snapshot?.status === "complete" && objective !== undefined ? buildTaskScopedAggregateReconciliationHint(goal, final) : ""}`, "ulw_loop_codex_snapshot_mismatch");
146
150
  }
151
+ if (closesBatch)
152
+ requireBatchFinalReady(plan, goal);
153
+ if (closesBatch && args.qualityGateJson === undefined)
154
+ throw new UlwLoopError("Validation batch final checkpoint requires --quality-gate-json.", "ULW_LOOP_VALIDATION_BATCH_GATE_REQUIRED");
147
155
  if (final)
148
156
  aggregateCompletion = makeAggregateCompletion(now, evidence, codexGoal);
149
- if (final || aggregateCompletion !== undefined)
157
+ if (final || aggregateCompletion !== undefined || closesBatch) {
150
158
  qualityGate = validateQualityGate(await readJsonInput(args.qualityGateJson, repoRoot), {
151
159
  repoRoot,
152
160
  fs: QUALITY_GATE_FS,
@@ -154,6 +162,8 @@ export async function checkpointUlwLoop(repoRoot, args, scope) {
154
162
  ? { currentAttemptDir: ulwLoopAttemptEvidenceDir(goal.id, goal.attempt, scope) }
155
163
  : {}),
156
164
  });
165
+ requireBatchGate(plan, goal, qualityGate);
166
+ }
157
167
  goal.status = "complete";
158
168
  goal.completedAt = now;
159
169
  goal.evidence = evidence;
@@ -172,6 +182,9 @@ export async function checkpointUlwLoop(repoRoot, args, scope) {
172
182
  await writePlan(repoRoot, plan, scope);
173
183
  const ledgerEntry = buildLedger(now, args, goal, qualityGate, codexGoal, aggregateCompletion);
174
184
  await appendLedger(repoRoot, ledgerEntry, scope);
185
+ const closedBatch = args.status === "complete" ? batchClosedBy(plan, goal.id) : undefined;
186
+ if (closedBatch !== undefined)
187
+ await appendLedger(repoRoot, { at: now, kind: "batch_closed", goalId: goal.id, message: closedBatch.batchId }, scope);
175
188
  return aggregateCompletion === undefined
176
189
  ? { plan, goal, ledgerEntry }
177
190
  : { plan, goal, ledgerEntry, aggregateCompletion };
@@ -1,7 +1,7 @@
1
1
  // biome-ignore-all format: keep this module under the mandated pure LOC budget.
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { UlwLoopError } from "./types.js";
4
- const VALUE_FLAGS = new Set("--brief --brief-file --session-id --codex-goal-mode --goal --goal-id --criterion-id --status --evidence --notes --codex-goal-json --quality-gate-json --kind --rationale --title --objective --target-goal-id --source --after-json --directive-json --directive-file --idempotency-key".split(" "));
4
+ const VALUE_FLAGS = new Set("--brief --brief-file --session-id --codex-goal-mode --validation-batch-json --goal --goal-id --criterion-id --status --evidence --notes --codex-goal-json --quality-gate-json --kind --rationale --title --objective --target-goal-id --source --after-json --directive-json --directive-file --idempotency-key --proposals-json".split(" "));
5
5
  const SUBCOMMANDS = new Set("create-goals status complete-goals criteria record-evidence checkpoint steer add-goal record-review-blockers".split(" "));
6
6
  export function hasFlag(argv, flag) { return argv.includes(flag); }
7
7
  export function readValue(argv, flag) {
@@ -1,6 +1,7 @@
1
+ import { checkpoint } from "./checkpoint-continuation.js";
1
2
  import { hasFlag, readValue } from "./cli-arg-parser.js";
2
3
  import { printJsonError, ULW_LOOP_HELP } from "./cli-output.js";
3
- import { addGoal, captureEvidence, checkpoint, completeGoals, createGoals, criteria, reviewBlockers, status, steer, } from "./cli-subcommands.js";
4
+ import { addGoal, captureEvidence, completeGoals, createGoals, criteria, reviewBlockers, status, steer, } from "./cli-subcommands.js";
4
5
  import { resolveUlwLoopSessionIdFromEnv } from "./paths.js";
5
6
  import { UlwLoopError } from "./types.js";
6
7
  export const ULW_LOOP_SUBCOMMANDS = [
@@ -1,5 +1,5 @@
1
1
  import type { UlwLoopCodexGoalMode, UlwLoopPlan } from "./types.js";
2
- export declare const ULW_LOOP_HELP = "Usage:\n omo ulw-loop create-goals --brief \"...\" [--brief-file <path>] [--from-stdin] [--codex-goal-mode aggregate|per_story] [--force] [--json]\n omo ulw-loop status [--json]\n omo ulw-loop complete-goals [--retry-failed] [--json]\n omo ulw-loop criteria --goal-id <id> [--json]\n omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass|fail|blocked --evidence \"...\" [--notes \"...\"] [--json]\n omo ulw-loop checkpoint --goal-id <id> --status complete|failed|blocked --evidence \"...\" --codex-goal-json <...> [--quality-gate-json <...>] [--json]\n omo ulw-loop steer --kind <kind> ... --evidence \"...\" --rationale \"...\" [--json]\n omo ulw-loop add-goal --title \"...\" --objective \"...\" [--json]\n omo ulw-loop record-review-blockers --goal-id <id> --title \"...\" --objective \"...\" --evidence \"...\" --codex-goal-json <...> [--json]\n\nAll subcommands accept [--session-id <id>] to isolate state under .omo/ulw-loop/<id>/; without it, Codex session env is used when present.";
2
+ export declare const ULW_LOOP_HELP = "Usage:\n omo ulw-loop create-goals --brief \"...\" [--brief-file <path>] [--from-stdin] [--codex-goal-mode aggregate|per_story] [--validation-batch-json <json-or-path>] [--force] [--json]\n omo ulw-loop status [--json]\n omo ulw-loop complete-goals [--retry-failed] [--json]\n omo ulw-loop criteria --goal-id <id> [--json]\n omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass|fail|blocked --evidence \"...\" [--notes \"...\"] [--json]\n omo ulw-loop checkpoint --goal-id <id> --status complete|failed|blocked --evidence \"...\" --codex-goal-json <...> [--quality-gate-json <...>] [--no-advance] [--json]\n omo ulw-loop steer --kind <kind> ... --evidence \"...\" --rationale \"...\" [--proposals-json <json-or-path>] [--json]\n omo ulw-loop add-goal --title \"...\" --objective \"...\" [--json]\n omo ulw-loop record-review-blockers --goal-id <id> --title \"...\" --objective \"...\" --evidence \"...\" --codex-goal-json <...> [--json]\n\nAll subcommands accept [--session-id <id>] to isolate state under .omo/ulw-loop/<id>/; without it, Codex session env is used when present.";
3
3
  export declare function printJson(value: unknown): void;
4
4
  export declare function printJsonError(error: unknown): void;
5
5
  export declare function printStatus(plan: UlwLoopPlan): void;
@@ -1,12 +1,12 @@
1
1
  import { UlwLoopError } from "./types.js";
2
2
  export const ULW_LOOP_HELP = `Usage:
3
- omo ulw-loop create-goals --brief "..." [--brief-file <path>] [--from-stdin] [--codex-goal-mode aggregate|per_story] [--force] [--json]
3
+ omo ulw-loop create-goals --brief "..." [--brief-file <path>] [--from-stdin] [--codex-goal-mode aggregate|per_story] [--validation-batch-json <json-or-path>] [--force] [--json]
4
4
  omo ulw-loop status [--json]
5
5
  omo ulw-loop complete-goals [--retry-failed] [--json]
6
6
  omo ulw-loop criteria --goal-id <id> [--json]
7
7
  omo ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass|fail|blocked --evidence "..." [--notes "..."] [--json]
8
- omo ulw-loop checkpoint --goal-id <id> --status complete|failed|blocked --evidence "..." --codex-goal-json <...> [--quality-gate-json <...>] [--json]
9
- omo ulw-loop steer --kind <kind> ... --evidence "..." --rationale "..." [--json]
8
+ omo ulw-loop checkpoint --goal-id <id> --status complete|failed|blocked --evidence "..." --codex-goal-json <...> [--quality-gate-json <...>] [--no-advance] [--json]
9
+ omo ulw-loop steer --kind <kind> ... --evidence "..." --rationale "..." [--proposals-json <json-or-path>] [--json]
10
10
  omo ulw-loop add-goal --title "..." --objective "..." [--json]
11
11
  omo ulw-loop record-review-blockers --goal-id <id> --title "..." --objective "..." --evidence "..." --codex-goal-json <...> [--json]
12
12