oh-my-opencode 4.18.1 → 4.19.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 (217) hide show
  1. package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +39 -16
  2. package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +111 -28
  3. package/README.ja.md +2 -2
  4. package/README.ko.md +2 -2
  5. package/README.md +4 -4
  6. package/README.ru.md +2 -2
  7. package/README.zh-cn.md +2 -2
  8. package/bin/AGENTS.md +33 -0
  9. package/dist/agents/atlas/agent.d.ts +6 -5
  10. package/dist/agents/sisyphus/index.d.ts +5 -0
  11. package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
  12. package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
  13. package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
  14. package/dist/agents/sisyphus-junior/index.d.ts +2 -0
  15. package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
  16. package/dist/agents/types.d.ts +2 -2
  17. package/dist/cli/index.js +690 -139
  18. package/dist/cli-node/index.js +690 -139
  19. package/dist/config/index.d.ts +1 -1
  20. package/dist/config/schema/browser-automation.d.ts +1 -0
  21. package/dist/config/schema/commands.d.ts +1 -3
  22. package/dist/config/schema/default-mode.d.ts +1 -1
  23. package/dist/config/schema/goal.d.ts +7 -0
  24. package/dist/config/schema/hooks.d.ts +1 -1
  25. package/dist/config/schema/oh-my-opencode-config.d.ts +6 -10
  26. package/dist/config/schema/ralph-loop.d.ts +1 -1
  27. package/dist/config/schema.d.ts +1 -1
  28. package/dist/create-hooks.d.ts +1 -1
  29. package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
  30. package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
  31. package/dist/features/builtin-commands/types.d.ts +1 -1
  32. package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
  33. package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
  34. package/dist/hooks/category-skill-reminder/hook.d.ts +9 -1
  35. package/dist/hooks/comment-checker/hook.d.ts +8 -1
  36. package/dist/hooks/goal/command-arguments.d.ts +13 -0
  37. package/dist/hooks/goal/controller.d.ts +26 -0
  38. package/dist/hooks/goal/index.d.ts +23 -0
  39. package/dist/hooks/goal/prompt.d.ts +3 -0
  40. package/dist/hooks/goal/store.d.ts +8 -0
  41. package/dist/hooks/goal/tools.d.ts +10 -0
  42. package/dist/hooks/goal/types.d.ts +93 -0
  43. package/dist/hooks/goal/validation.d.ts +4 -0
  44. package/dist/hooks/index.d.ts +1 -0
  45. package/dist/hooks/keyword-detector/hook.d.ts +1 -2
  46. package/dist/hooks/ralph-loop/types.d.ts +1 -1
  47. package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
  48. package/dist/index.js +3706 -4329
  49. package/dist/oh-my-opencode.schema.json +23 -19
  50. package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
  51. package/dist/plugin/chat-message/types.d.ts +23 -10
  52. package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
  53. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
  54. package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
  55. package/dist/plugin/messages-transform.d.ts +1 -0
  56. package/dist/plugin/stop-continuation.d.ts +2 -2
  57. package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
  58. package/dist/shared/system-directive.d.ts +0 -1
  59. package/dist/skills/ulw-plan/SKILL.md +11 -7
  60. package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
  61. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  62. package/dist/skills/ulw-research/SKILL.md +3 -3
  63. package/dist/tools/delegate-task/types.d.ts +0 -1
  64. package/dist/tui.js +115 -28
  65. package/package.json +14 -14
  66. package/packages/git-bash-mcp/dist/cli.js +81 -19
  67. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +4 -4
  68. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +118 -1
  69. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +1 -1
  70. package/packages/lsp-daemon/dist/cli.js +262 -63
  71. package/packages/lsp-daemon/dist/client.js +194 -50
  72. package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -2
  73. package/packages/lsp-daemon/dist/daemon-client.js +26 -2
  74. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +5 -4
  75. package/packages/lsp-daemon/dist/ensure-daemon.js +79 -18
  76. package/packages/lsp-daemon/dist/index.js +262 -63
  77. package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
  78. package/packages/lsp-daemon/dist/proxy.js +79 -23
  79. package/packages/lsp-tools-mcp/dist/cli.js +82 -20
  80. package/packages/lsp-tools-mcp/dist/mcp.js +82 -20
  81. package/packages/lsp-tools-mcp/dist/tools.js +1 -1
  82. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  83. package/packages/omo-codex/plugin/.mcp.json +2 -1
  84. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +352 -17
  85. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  86. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  87. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +7 -6
  88. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +195 -56
  89. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +100 -28
  90. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  91. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +21 -9
  92. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
  93. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +35 -0
  94. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +69 -0
  95. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +57 -1
  96. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  97. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  98. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  99. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  100. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  101. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  102. package/packages/omo-codex/plugin/components/lsp/.mcp.json +2 -1
  103. package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
  104. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  105. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +113 -31
  106. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  107. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  108. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +1 -0
  109. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
  110. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +5 -3
  111. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  112. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  113. package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +8 -0
  114. package/packages/omo-codex/plugin/components/start-work-continuation/README.md +2 -2
  115. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
  116. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +148 -61
  117. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  118. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  119. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +4 -72
  120. package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
  121. package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
  122. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +213 -24
  123. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
  124. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +25 -4
  125. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -0
  126. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  127. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  128. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  129. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  130. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -10
  131. package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
  132. package/packages/omo-codex/plugin/components/ultrawork/directive.md +50 -33
  133. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  134. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  135. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +50 -33
  136. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +11 -7
  137. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
  138. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  139. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +50 -33
  140. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +3 -3
  141. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +5 -6
  142. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  143. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  144. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
  145. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +5 -6
  146. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +2 -2
  147. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  148. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  149. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  150. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  151. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  152. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  153. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  154. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  155. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  156. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  157. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  158. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  159. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  160. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  161. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  162. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  163. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  164. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  165. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  166. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  170. package/packages/omo-codex/plugin/package-lock.json +13 -13
  171. package/packages/omo-codex/plugin/package.json +1 -1
  172. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
  173. package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
  174. package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
  175. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +13 -20
  176. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +7 -0
  177. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -2
  178. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +50 -33
  179. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
  180. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +11 -7
  181. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
  182. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  183. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +2 -2
  184. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
  185. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
  186. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
  187. package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
  188. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
  189. package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
  190. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
  191. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +38 -22
  192. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
  193. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
  194. package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
  195. package/packages/omo-codex/scripts/install-dist/install-local.mjs +353 -18
  196. package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
  197. package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -7
  198. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
  199. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  200. package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
  201. package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
  202. package/dist/skills/ultraresearch/SKILL.md +0 -10
  203. package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
  204. package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
  205. package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
  206. package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
  207. package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
  208. package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
  209. package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
  210. package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
  211. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
  212. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
  213. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
  214. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
  215. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
  216. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
  217. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
@@ -0,0 +1,293 @@
1
+ import assert from "node:assert/strict";
2
+ import { readFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import test from "node:test";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const pluginRoot = dirname(dirname(fileURLToPath(import.meta.url)));
8
+ const repositoryRoot = dirname(dirname(dirname(pluginRoot)));
9
+
10
+ const surfaces = [
11
+ {
12
+ name: "shared OpenCode",
13
+ skillPath: join(repositoryRoot, "packages", "shared-skills", "skills", "ulw-plan", "SKILL.md"),
14
+ workflowPath: join(repositoryRoot, "packages", "shared-skills", "skills", "ulw-plan", "references", "full-workflow.md"),
15
+ independentReviewer: "oracle",
16
+ reviewRoots: {
17
+ momus: "<literal-canonical-source-workspace-root>",
18
+ independent: "<literal-canonical-source-workspace-root>",
19
+ },
20
+ runtimeHomes: { momus: null, independent: null },
21
+ },
22
+ {
23
+ name: "Codex",
24
+ skillPath: join(pluginRoot, "components", "ultrawork", "skills", "ulw-plan", "SKILL.md"),
25
+ workflowPath: join(pluginRoot, "components", "ultrawork", "skills", "ulw-plan", "references", "full-workflow.md"),
26
+ independentReviewer: "codex-cli:gpt-5.6-sol:xhigh",
27
+ reviewRoots: {
28
+ momus: "<literal-canonical-source-workspace-root>",
29
+ independent: "<literal-canonical-disposable-review-workspace-root>",
30
+ },
31
+ runtimeHomes: { momus: null, independent: "<literal-isolated-codex-home>" },
32
+ },
33
+ ];
34
+
35
+ function readJsonContract(workflow, contractName) {
36
+ const fence = "```";
37
+ const pattern = new RegExp(`<!-- ${contractName} -->\\s*${fence}json\\s*([\\s\\S]*?)\\s*${fence}`);
38
+ const match = workflow.match(pattern);
39
+ assert.ok(match, `missing ${contractName}`);
40
+ return JSON.parse(match[1]);
41
+ }
42
+
43
+ function matchesCas(state, expected, clauses) {
44
+ return clauses.every((clause) => {
45
+ const separator = clause.indexOf("=");
46
+ if (separator !== -1) {
47
+ const key = clause.slice(0, separator);
48
+ const value = clause.slice(separator + 1);
49
+ return state[key] === value;
50
+ }
51
+ return Object.hasOwn(expected, clause) && state[clause] === expected[clause];
52
+ });
53
+ }
54
+
55
+ for (const surface of surfaces) {
56
+ test(`#given ${surface.name} #when deeper review becomes required before plan completion #then durable request state covers explicit and automatic review without inventing a digest`, async () => {
57
+ const skill = await readFile(surface.skillPath, "utf8");
58
+ const workflow = await readFile(surface.workflowPath, "utf8");
59
+ const contract = readJsonContract(workflow, "ulw-plan-review-request-state-contract");
60
+
61
+ assert.equal(contract.transition, "replace");
62
+ assert.equal(contract.phase, "review_requested");
63
+ assert.deepEqual(contract.applies_when, ["explicit_review_modifier_before_complete_plan", "intent=unclear_and_nontrivial"]);
64
+ assert.match(skill, /Include `--review-required`[\s\S]{0,180}non-Trivial UNCLEAR/);
65
+ assert.match(workflow, /--draft-only/);
66
+ assert.equal(contract.atomic, true);
67
+ assert.equal(contract.review_required, true);
68
+ assert.equal(contract.plan_path, ".omo/plans/<slug>.md");
69
+ assert.equal(contract.plan_sha256, null);
70
+ assert.equal(contract.review_round_id, null);
71
+ assert.deepEqual(contract.pending_action_policy, {
72
+ review_required: "write and review .omo/plans/<slug>.md",
73
+ otherwise: "write .omo/plans/<slug>.md",
74
+ });
75
+ assert.equal(contract["pending-action"], contract.pending_action_policy.review_required);
76
+ assert.deepEqual(Object.keys(contract.review).sort(), ["independent", "momus"]);
77
+
78
+ for (const lane of Object.values(contract.review)) {
79
+ assert.deepEqual(lane, {
80
+ status: "pending",
81
+ workspace_root: null,
82
+ runtime_home: null,
83
+ target: ".omo/plans/<slug>.md",
84
+ round_id: null,
85
+ plan_sha256: null,
86
+ launch_id: null,
87
+ session: null,
88
+ result: null,
89
+ });
90
+ }
91
+ });
92
+
93
+ test(`#given a complete ${surface.name} plan #when a fresh review round starts #then both lanes persist literal workspace and artifact bindings`, async () => {
94
+ const workflow = await readFile(surface.workflowPath, "utf8");
95
+ const contract = readJsonContract(workflow, "ulw-plan-review-round-state-contract");
96
+
97
+ assert.equal(contract.transition, "replace");
98
+ assert.equal(contract.phase, "review_round_initialized");
99
+ assert.deepEqual(contract.applies_when, [
100
+ "complete_plan_after_review_request",
101
+ "explicit_review_modifier_with_complete_plan",
102
+ "retry_after_plan_change",
103
+ ]);
104
+ assert.equal(contract.atomic, true);
105
+ assert.equal(contract.review_required, true);
106
+ assert.equal(contract.plan_path, ".omo/plans/<slug>.md");
107
+ assert.equal(contract.plan_sha256, "<sha256-of-complete-plan>");
108
+ assert.equal(contract.review_round_id, "<fresh-unique-round-id>");
109
+ assert.equal(contract.round_status, "active");
110
+ assert.deepEqual(contract.completion_cas, [
111
+ "status=in_flight",
112
+ "workspace_root",
113
+ "runtime_home",
114
+ "target",
115
+ "launch_id",
116
+ "round_id",
117
+ "plan_sha256",
118
+ "session",
119
+ "receipt_identity=session",
120
+ "live_plan_sha256=plan_sha256",
121
+ "echoed_binding",
122
+ "terminal_transition=in_flight->approved|changes_requested|inconclusive",
123
+ ]);
124
+ assert.equal(contract["pending-action"], "review .omo/plans/<slug>.md");
125
+
126
+ for (const [laneName, lane] of Object.entries(contract.review)) {
127
+ assert.deepEqual(lane, {
128
+ status: "pending",
129
+ workspace_root: surface.reviewRoots[laneName],
130
+ runtime_home: surface.runtimeHomes[laneName],
131
+ target: ".omo/plans/<validated-slug>.md",
132
+ round_id: "<review-round-id>",
133
+ plan_sha256: "<plan-sha256>",
134
+ launch_id: null,
135
+ session: null,
136
+ result: null,
137
+ });
138
+ }
139
+ });
140
+
141
+ test(`#given a ${surface.name} review round #when launch, interruption, completion, or compaction occurs #then the durable transition table fails closed`, async () => {
142
+ const workflow = await readFile(surface.workflowPath, "utf8");
143
+ const contract = readJsonContract(workflow, "ulw-plan-review-lifecycle-state-contract");
144
+
145
+ assert.deepEqual(contract.transitions.launch, {
146
+ from: "pending",
147
+ to: "launching",
148
+ cas: ["round_status=active", "status=pending", "workspace_root", "runtime_home", "target", "round_id", "plan_sha256"],
149
+ writes: ["launch_id=<fresh-launch-id>"],
150
+ });
151
+ assert.deepEqual(contract.transitions.receipt, {
152
+ from: "launching",
153
+ to: "in_flight",
154
+ cas: [
155
+ "round_status=active",
156
+ "status=launching",
157
+ "workspace_root",
158
+ "runtime_home",
159
+ "target",
160
+ "round_id",
161
+ "plan_sha256",
162
+ "launch_id",
163
+ ],
164
+ writes: ["session=<session-or-process-receipt>"],
165
+ });
166
+ assert.deepEqual(contract.transitions.complete, {
167
+ from: "in_flight",
168
+ to: ["approved", "changes_requested", "inconclusive"],
169
+ one_shot: true,
170
+ cas: [
171
+ "round_status=active",
172
+ "workspace_root",
173
+ "runtime_home",
174
+ "target",
175
+ "launch_id",
176
+ "round_id",
177
+ "plan_sha256",
178
+ "session",
179
+ "receipt_identity=session",
180
+ "live_plan_sha256=plan_sha256",
181
+ "echoed_binding",
182
+ ],
183
+ });
184
+ assert.deepEqual(contract.transitions.launch_interrupted, {
185
+ from: { round_status: "active", lane_status: "launching" },
186
+ to: {
187
+ round_status: "inconclusive",
188
+ lane_status: "inconclusive",
189
+ result: "launch_interrupted_without_receipt",
190
+ },
191
+ cas: [
192
+ "round_status=active",
193
+ "status=launching",
194
+ "workspace_root",
195
+ "runtime_home",
196
+ "target",
197
+ "round_id",
198
+ "plan_sha256",
199
+ "launch_id",
200
+ ],
201
+ invalidates_other_lane: true,
202
+ next: "fresh_review_round",
203
+ });
204
+ assert.deepEqual(contract.resume_after_compaction, {
205
+ pending: "dispatch_with_launch_cas",
206
+ launching: "apply_launch_interrupted_transition",
207
+ in_flight: "wait_for_matching_completion_only",
208
+ "approved|changes_requested|inconclusive": "do_not_mutate",
209
+ "round_status=inconclusive": "start_fresh_review_round",
210
+ });
211
+ assert.deepEqual(contract.rejected_completions, ["duplicate", "late", "stale", "mismatched"]);
212
+ });
213
+
214
+ test(`#given ${surface.name} round R2 replaced R1 #when a delayed R1 launch or receipt arrives #then identity-bound CAS leaves R2 unchanged`, async () => {
215
+ const workflow = await readFile(surface.workflowPath, "utf8");
216
+ const contract = readJsonContract(workflow, "ulw-plan-review-lifecycle-state-contract");
217
+ const currentRound = {
218
+ round_status: "active",
219
+ status: "pending",
220
+ workspace_root: surface.reviewRoots.independent,
221
+ runtime_home: surface.runtimeHomes.independent,
222
+ target: ".omo/plans/demo.md",
223
+ round_id: "round-r2",
224
+ plan_sha256: "sha-r2",
225
+ launch_id: null,
226
+ };
227
+ const staleRound = {
228
+ ...currentRound,
229
+ round_id: "round-r1",
230
+ plan_sha256: "sha-r1",
231
+ launch_id: "launch-r1",
232
+ };
233
+
234
+ assert.equal(matchesCas(currentRound, currentRound, contract.transitions.launch.cas), true);
235
+ assert.equal(matchesCas(currentRound, staleRound, contract.transitions.launch.cas), false);
236
+
237
+ const launchedCurrentRound = { ...currentRound, status: "launching", launch_id: "launch-r2" };
238
+ assert.equal(matchesCas(launchedCurrentRound, launchedCurrentRound, contract.transitions.receipt.cas), true);
239
+ assert.equal(matchesCas(launchedCurrentRound, staleRound, contract.transitions.receipt.cas), false);
240
+ assert.equal(matchesCas(launchedCurrentRound, staleRound, contract.transitions.launch_interrupted.cas), false);
241
+ });
242
+
243
+ test(`#given ${surface.name} independent reviewers #when exact-path retrieval drifts #then intake fails closed without alternate artifact recovery`, async () => {
244
+ const workflow = await readFile(surface.workflowPath, "utf8");
245
+ const contract = readJsonContract(workflow, "ulw-plan-review-intake-contract");
246
+
247
+ assert.equal(contract.independent_reviewer, surface.independentReviewer);
248
+ assert.deepEqual(contract.lanes, ["momus", "independent"]);
249
+ assert.equal(contract.binding, "substitute_literals_before_dispatch");
250
+ assert.equal(contract.workspace_root, "<literal-canonical-review-workspace-root>");
251
+ assert.equal(contract.runtime_home, "<literal-runtime-home-or-null>");
252
+ assert.equal(contract.target, "<literal-.omo/plans/validated-slug.md>");
253
+ assert.equal(contract.first_action, "read_exact_plan_path");
254
+ assert.equal(contract.read_mechanism, "open_workspace_root_then_openat_no_follow_each_segment_fstat_read_hash");
255
+ assert.equal(contract.artifact_identity, "<literal-plan-sha256>");
256
+ assert.equal(contract.round_identity, "<literal-review-round-id>");
257
+ assert.equal(contract.launch_identity, "<literal-launch-id>");
258
+ assert.deepEqual(contract.required_echo, [
259
+ "workspace_root",
260
+ "runtime_home",
261
+ "target",
262
+ "artifact_identity",
263
+ "round_identity",
264
+ "launch_identity",
265
+ ]);
266
+ assert.deepEqual(contract.required_receipt, ["session_or_process_identity"]);
267
+ assert.deepEqual(contract.pre_read_validation.sort(), [
268
+ "descriptor_relative_no_follow_each_segment",
269
+ "open_workspace_root_directory_descriptor",
270
+ "regular_file",
271
+ "workspace_relative_canonical_equality",
272
+ ]);
273
+ assert.equal(contract.drift_verdict, "INCONCLUSIVE");
274
+ assert.deepEqual(contract.drift_conditions.sort(), [
275
+ "ancestor_descriptor_mismatch",
276
+ "digest_mismatch",
277
+ "incomplete_retrieval",
278
+ "launch_identity_mismatch",
279
+ "path_mismatch",
280
+ "read_failure",
281
+ "receipt_identity_mismatch",
282
+ "runtime_home_mismatch",
283
+ "stale_or_different_artifact",
284
+ "unsafe_path",
285
+ ]);
286
+ assert.deepEqual(contract.forbidden_fallbacks.sort(), [
287
+ "alternate_files",
288
+ "memory",
289
+ "search",
290
+ "summaries",
291
+ ]);
292
+ });
293
+ }
@@ -29,9 +29,9 @@ test("#given empty Codex config #when script installer updates config #then sets
29
29
  assert.doesNotMatch(config, /^\s*multi_agent_mode\s*=/m);
30
30
  assert.doesNotMatch(config, /^\s*max_threads\s*=/m);
31
31
  assert.match(config, /\[features\.multi_agent_v2\]/);
32
- const v2Section = multiAgentV2Section(config);
32
+ const v2Section = multiAgentV2Section(config);
33
33
  assert.doesNotMatch(v2Section, /^enabled\s*=/m);
34
- assert.match(v2Section, /max_concurrent_threads_per_session = 1000/);
34
+ assert.match(v2Section, /max_concurrent_threads_per_session = 16/);
35
35
  });
36
36
 
37
37
  test("#given queue multi-agent mode #when script installer updates config #then removes unsupported root key", async () => {
@@ -313,8 +313,8 @@ test("#given existing MultiAgentV2 table #when script installer updates config #
313
313
  assert.match(config, /\[features\.multi_agent_v2\]/);
314
314
  assert.doesNotMatch(sectionText(config, "[features.multi_agent_v2]"), /enabled = true/);
315
315
  assert.match(config, /usage_hint_enabled = false/);
316
- assert.match(config, /max_concurrent_threads_per_session = 1000/);
317
- assert.doesNotMatch(config, /max_concurrent_threads_per_session = 4/);
316
+ assert.match(config, /max_concurrent_threads_per_session = 4/);
317
+ assert.doesNotMatch(config, /max_concurrent_threads_per_session = 1000/);
318
318
  });
319
319
 
320
320
  test("#given empty Codex config #when script installer updates config #then sets the generated MultiAgentV2 thread limit", async () => {
@@ -337,7 +337,7 @@ test("#given empty Codex config #when script installer updates config #then sets
337
337
  const config = await readFile(configPath, "utf8");
338
338
  const v2Section = config.slice(config.indexOf("[features.multi_agent_v2]"));
339
339
  assert.doesNotMatch(config, /^\s*max_threads\s*=/m);
340
- assert.match(v2Section, /max_concurrent_threads_per_session = 1000/);
340
+ assert.match(v2Section, /max_concurrent_threads_per_session = 16/);
341
341
  assert.doesNotMatch(v2Section, /hide_spawn_agent_metadata/);
342
342
  });
343
343
 
@@ -401,10 +401,10 @@ test("#given legacy boolean MultiAgentV2 flag and table #when script installer u
401
401
  const config = await readFile(configPath, "utf8");
402
402
  assert.doesNotMatch(config, /^multi_agent_v2\s*=/m);
403
403
  assert.match(config, /\[features\.multi_agent_v2\]/);
404
- const v2Section = multiAgentV2Section(config);
404
+ const v2Section = multiAgentV2Section(config);
405
405
  assert.doesNotMatch(v2Section, /^enabled\s*=/m);
406
406
  assert.match(v2Section, /usage_hint_enabled = false/);
407
- assert.match(v2Section, /max_concurrent_threads_per_session = 1000/);
407
+ assert.match(v2Section, /max_concurrent_threads_per_session = 16/);
408
408
  });
409
409
 
410
410
  test("#given legacy boolean MultiAgentV2 flag false #when script installer updates config #then normalizes to a disabled table config", async () => {
@@ -440,7 +440,7 @@ test("#given legacy boolean MultiAgentV2 flag false #when script installer updat
440
440
  assert.match(config, /\[features\.multi_agent_v2\]/);
441
441
  const disabledV2Section = multiAgentV2Section(config);
442
442
  assert.match(disabledV2Section, /^enabled = false$/m);
443
- assert.match(disabledV2Section, /^max_concurrent_threads_per_session = 1000$/m);
443
+ assert.match(disabledV2Section, /^max_concurrent_threads_per_session = 16$/m);
444
444
  });
445
445
 
446
446
  test("#given legacy agents max_threads #when script installer updates config #then raises the root subagent thread cap", async () => {
@@ -474,9 +474,9 @@ test("#given legacy agents max_threads #when script installer updates config #th
474
474
  // then
475
475
  const config = await readFile(configPath, "utf8");
476
476
  assert.match(config, /\[features\.multi_agent_v2\]/);
477
- const v2Section = multiAgentV2Section(config);
477
+ const v2Section = multiAgentV2Section(config);
478
478
  assert.doesNotMatch(v2Section, /^enabled\s*=/m);
479
- assert.match(v2Section, /max_concurrent_threads_per_session = 1000/);
479
+ assert.match(v2Section, /max_concurrent_threads_per_session = 16/);
480
480
  assert.match(config, /\[agents\]/);
481
481
  assert.match(config, /max_threads = 1000/);
482
482
  assert.doesNotMatch(config, /max_threads = 16/);