lazycodex-ai 4.16.3 → 4.17.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 (189) hide show
  1. package/README.ja.md +4 -4
  2. package/README.ko.md +4 -4
  3. package/README.md +2 -2
  4. package/README.ru.md +4 -4
  5. package/README.zh-cn.md +4 -4
  6. package/dist/cli/index.js +195 -76
  7. package/dist/cli-node/index.js +195 -76
  8. package/package.json +1 -1
  9. package/packages/lsp-daemon/dist/cli.js +7 -13
  10. package/packages/lsp-daemon/dist/daemon-client.js +3 -5
  11. package/packages/lsp-daemon/dist/index.js +12 -18
  12. package/packages/lsp-daemon/dist/request-routing.js +6 -8
  13. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
  14. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +1080 -1017
  15. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  16. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  17. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  18. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  19. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  20. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  21. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  22. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +2 -2
  23. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +6 -2
  24. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +6 -2
  25. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +2 -2
  26. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +6 -2
  28. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
  29. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +67 -2
  30. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +14 -14
  31. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  32. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  33. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +0 -13
  34. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +2 -2
  35. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +3 -3
  36. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  37. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  38. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  39. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +1 -79
  41. package/packages/omo-codex/plugin/components/teammode/AGENTS.md +2 -2
  42. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  43. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  44. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +33 -16
  45. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +2 -1
  46. package/packages/omo-codex/plugin/components/teammode/test/v2-spawn-schema.test.ts +69 -0
  47. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  48. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  49. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +2 -2
  50. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
  51. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +6 -6
  52. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +5 -5
  53. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +26 -0
  54. package/packages/omo-codex/plugin/components/ultrawork/agents/{lazycodex-executor.toml → lazycodex-worker-low.toml} +6 -4
  55. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +26 -0
  56. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +2 -2
  57. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +7 -7
  58. package/packages/omo-codex/plugin/components/ultrawork/directive.md +76 -37
  59. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  60. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  61. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +76 -37
  62. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
  63. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  64. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +4 -4
  65. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  66. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +25 -0
  67. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +0 -68
  68. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
  69. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +2 -0
  70. package/packages/omo-codex/plugin/components/ulw-loop/README.md +3 -1
  71. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +76 -37
  72. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +6 -1
  73. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +1 -1
  74. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -2
  75. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +405 -25
  76. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +12 -1
  77. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +4 -2
  78. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +7 -0
  79. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +16 -1
  80. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +1 -0
  81. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.d.ts +6 -0
  82. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +20 -0
  83. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +1 -0
  84. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +12 -9
  85. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +3 -0
  86. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +148 -0
  87. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.d.ts +2 -0
  88. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +209 -0
  89. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +25 -2
  90. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  91. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +14 -15
  92. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +30 -28
  93. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +6 -1
  94. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +14 -3
  95. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +10 -0
  96. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +12 -1
  97. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +4 -2
  98. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +27 -1
  99. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +1 -0
  100. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +23 -0
  101. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +16 -9
  102. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +138 -0
  103. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +208 -0
  104. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +12 -0
  105. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +4 -1
  106. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +8 -35
  107. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +24 -13
  108. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -2
  109. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +43 -8
  110. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +55 -2
  111. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +228 -0
  112. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +193 -0
  113. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  114. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  115. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  116. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  118. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  119. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  120. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  121. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  122. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +18 -0
  123. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  124. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  125. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  126. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  127. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  128. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  129. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  130. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +17 -0
  131. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  132. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +2 -2
  133. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  134. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  135. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  136. package/packages/omo-codex/plugin/model-catalog.json +16 -7
  137. package/packages/omo-codex/plugin/package-lock.json +13 -13
  138. package/packages/omo-codex/plugin/package.json +1 -1
  139. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
  140. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +8 -2
  141. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +2 -2
  142. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +2 -2
  143. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -4
  144. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +18 -4
  145. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +6 -3
  146. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +33 -16
  147. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +2 -1
  148. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +2 -2
  149. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
  150. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
  151. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +76 -37
  152. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +14 -15
  153. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +30 -28
  154. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
  155. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  156. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +4 -4
  157. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  158. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
  159. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +11 -7
  160. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +76 -16
  161. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -2
  162. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
  163. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +4 -4
  164. package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
  165. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  166. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +4 -101
  167. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +14 -14
  168. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +11 -0
  169. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
  170. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +5 -3
  171. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +25 -0
  172. package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +24 -0
  173. package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +9 -40
  174. package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +4 -277
  175. package/packages/omo-codex/scripts/install-dist/install-local.mjs +98 -30
  176. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +2 -2
  177. package/packages/shared-skills/skills/review-work/SKILL.md +10 -2
  178. package/packages/shared-skills/skills/start-work/SKILL.md +6 -3
  179. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +2 -2
  180. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
  181. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
  182. package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
  183. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  184. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +4 -4
  185. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  186. package/packages/shared-skills/skills/visual-qa/SKILL.md +9 -5
  187. package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +0 -70
  188. package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +0 -98
  189. package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
@@ -67,6 +67,31 @@ test("#given flat V2 tools are available #when the leader reads teammode #then t
67
67
  assert.match(skill, /Codex App.*fallback/i);
68
68
  });
69
69
 
70
+ test("#given neither transport's tools are visible #when the leader reads teammode #then search hits are revalidated and fallback is capability-aware without team state", () => {
71
+ const skill = readFileSync(join(root, "components", "teammode", "skills", "teammode", "SKILL.md"), "utf8");
72
+
73
+ const searchIndex = skill.indexOf("tool_search");
74
+ const unavailableIndex = skill.indexOf("Teammode unavailable");
75
+ assert.notEqual(searchIndex, -1, "skill must route hidden tools through the tool_search check");
76
+ assert.notEqual(unavailableIndex, -1, "skill must give the leader unavailable announcement templates");
77
+ assert.ok(searchIndex < unavailableIndex, "tool_search must precede the unavailable conclusion");
78
+ assert.match(skill, /revalidate.*COMPLETE.*compatible transport set/is, "a deferred-tool hit must be revalidated as a complete transport");
79
+ assert.match(skill, /another visible plain-subagent mechanism.*spawn.*communicate.*observe/is, "plain-subagent fallback requires a complete visible lifecycle");
80
+ assert.match(skill, /Otherwise continue serially.*capability limitation/is, "missing all transports must continue serially rather than promise workers");
81
+ assert.match(skill, /Do NOT run `init`/, "the fallback must not create team state");
82
+ assert.doesNotMatch(skill, /splitting the work across plain fire-and-forget subagents/i, "the skill must not promise unavailable plain subagents");
83
+ });
84
+
85
+ test("#given a MultiAgentV2 team #when the leader spawns members #then guidance limits calls to exposed V2 fields", () => {
86
+ const skill = readFileSync(join(root, "components", "teammode", "skills", "teammode", "SKILL.md"), "utf8");
87
+
88
+ assert.match(skill, /using only the V2 schema fields/i);
89
+ assert.match(skill, /`task_name`[\s\S]*`message`[\s\S]*`fork_turns`/);
90
+ assert.match(skill, /role, priority, or task-specific routing instruction in `message`/i);
91
+ assert.match(skill, /V2 does not accept[\s\S]*`agent_type`, `model`, `reasoning_effort`, or `service_tier`/);
92
+ assert.match(skill, /inherit the[\s\S]*session model/i);
93
+ });
94
+
70
95
  test("#given MultiAgentV2 transport #when members are added and bound #then task names and canonical agent paths form the address book", () => {
71
96
  const tempRoot = createTeamRoot("omo-codex-teammode-v2-transport-");
72
97
  try {
@@ -0,0 +1,24 @@
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
+ const componentReference = join(pluginRoot, "components", "ultrawork", "skills", "ulw-plan", "references", "intent-unclear.md");
10
+ const sharedReference = join(repositoryRoot, "packages", "shared-skills", "skills", "ulw-plan", "references", "intent-unclear.md");
11
+
12
+ test("#given an unclear auth-improvement request #when ulw-plan derives its full-scope components #then it preserves evidenced intent without inventing reduction or MFA expansion", async () => {
13
+ const [component, shared] = await Promise.all([
14
+ readFile(componentReference, "utf8"),
15
+ readFile(sharedReference, "utf8"),
16
+ ]);
17
+
18
+ for (const reference of [component, shared]) {
19
+ assert.match(reference, /components that refine the user's requested or evidence-backed intent/i);
20
+ assert.match(reference, /neither collapse into an invented reduced subset nor expand into adjacent features/i);
21
+ assert.match(reference, /MFA is an adjacent capability.*Scope OUT unless the user asks.*evidence establishes/i);
22
+ assert.doesNotMatch(reference, /MFA - all four planned in full/i);
23
+ }
24
+ });
@@ -6,47 +6,16 @@ import { fileURLToPath } from "node:url";
6
6
 
7
7
  const root = dirname(dirname(fileURLToPath(import.meta.url)));
8
8
 
9
- async function readUlwPlanCopies() {
9
+ test("#given ulw-plan skill copies #when component source and packaged copy are compared #then they are byte-identical and expose the loader-parsed name", async () => {
10
+ // given
10
11
  const componentPath = join(root, "components", "ultrawork", "skills", "ulw-plan", "SKILL.md");
11
12
  const packagedPath = join(root, "skills", "ulw-plan", "SKILL.md");
12
- return [
13
- { label: "component", path: componentPath, content: await readFile(componentPath, "utf8") },
14
- { label: "packaged", path: packagedPath, content: await readFile(packagedPath, "utf8") },
15
- ];
16
- }
17
13
 
18
- test("#given ulw-plan skill #when Codex delegation is inspected #then spawned planners block dependent work", async () => {
19
- for (const copy of await readUlwPlanCopies()) {
20
- assert.match(copy.content, /multi_agent_v1\.spawn_agent/, `${copy.label}: must document Codex spawning`);
21
- assert.match(copy.content, /multi_agent_v1\.wait_agent/, `${copy.label}: must document Codex waiting`);
22
- assert.match(
23
- copy.content,
24
- /Spawn every independent child for the current wave first/i,
25
- `${copy.label}: must preserve independent spawn waves`,
26
- );
27
- assert.match(
28
- copy.content,
29
- /After the wave\s+is launched[\s\S]{0,240}multi_agent_v1\.wait_agent[\s\S]{0,240}terminal status/i,
30
- `${copy.label}: must wait after the wave is launched`,
31
- );
32
- assert.doesNotMatch(
33
- copy.content,
34
- /Immediately after any `multi_agent_v1\.spawn_agent`/i,
35
- `${copy.label}: must not serialize independent spawns`,
36
- );
37
- assert.match(copy.content, /terminal status/i, `${copy.label}: must wait until terminal status`);
38
- assert.match(copy.content, /WORKING:/, `${copy.label}: must keep progress liveness guidance`);
39
- assert.match(copy.content, /BLOCKED:/, `${copy.label}: must keep blocked liveness guidance`);
40
- assert.match(
41
- copy.content,
42
- /timeout only means no new mailbox update arrived/i,
43
- `${copy.label}: must frame wait timeouts as mailbox silence`,
44
- );
45
- assert.match(copy.content, /Fallback only when/, `${copy.label}: must keep explicit fallback conditions`);
46
- assert.match(
47
- copy.content,
48
- /do not start dependent planning, drafting, approval-gate work, or final handoff/i,
49
- `${copy.label}: must block dependent planning work before child results are integrated`,
50
- );
51
- }
14
+ // when
15
+ const component = await readFile(componentPath, "utf8");
16
+ const packaged = await readFile(packagedPath, "utf8");
17
+
18
+ // then
19
+ assert.equal(packaged, component);
20
+ assert.match(component, /^name: ulw-plan$/m);
52
21
  });
@@ -1,10 +1,9 @@
1
- // allow: SIZE_OK - ULW research skill contract tests inspect one bundled prompt protocol; this release introduces the contract and future additions should split by protocol phase.
2
-
3
1
  import assert from "node:assert/strict";
4
2
  import { readFile } from "node:fs/promises";
5
3
  import { dirname, join } from "node:path";
6
4
  import test from "node:test";
7
5
  import { fileURLToPath } from "node:url";
6
+
8
7
  import { sharedSkillsRootPath } from "@oh-my-opencode/shared-skills";
9
8
 
10
9
  const root = dirname(dirname(fileURLToPath(import.meta.url)));
@@ -18,286 +17,14 @@ async function readUlwResearchCopies() {
18
17
  ];
19
18
  }
20
19
 
21
- function frontmatterDescription(content) {
22
- const match = content.match(/^---\r?\n[\s\S]*?\bdescription:\s*"([\s\S]*?)"\r?\n[\s\S]*?---/);
23
- assert.notEqual(match, null, "SKILL.md frontmatter description not found");
24
- return match[1];
25
- }
26
-
27
- function escapeRegExp(value) {
28
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29
- }
30
-
31
- function markdownSection(content, heading, nextHeading) {
32
- const headingPattern = new RegExp(`^${escapeRegExp(heading)}\\r?$`, "m");
33
- const headingMatch = content.match(headingPattern);
34
- assert.notEqual(headingMatch, null, `SKILL.md section not found: ${heading}`);
35
- assert.notEqual(headingMatch.index, undefined, `SKILL.md section index not found: ${heading}`);
36
- const bodyStart = headingMatch.index + headingMatch[0].length;
37
- if (nextHeading === undefined) {
38
- return content.slice(bodyStart);
39
- }
40
- const nextHeadingIndex = content.indexOf(`\n${nextHeading}`, bodyStart);
41
- assert.notEqual(nextHeadingIndex, -1, `SKILL.md next section not found: ${nextHeading}`);
42
- return content.slice(bodyStart, nextHeadingIndex);
43
- }
44
-
45
- test("#given renamed research skill #when frontmatter is inspected #then ulw-research is the canonical name", async () => {
20
+ test("#given ulw-research skill copies #when frontmatter is inspected #then the loader-parsed name is ulw-research", async () => {
46
21
  for (const copy of await readUlwResearchCopies()) {
47
22
  assert.match(copy.content, /^name: ulw-research$/m, `${copy.label}: frontmatter must expose ulw-research`);
48
23
  }
49
24
  });
50
25
 
51
- test("#given renamed research skill #when activation marker is inspected #then ulw-research is the canonical marker", async () => {
52
- for (const copy of await readUlwResearchCopies()) {
53
- assert.match(
54
- copy.content,
55
- /`ULW-RESEARCH MODE ENABLED!`/,
56
- `${copy.label}: body must expose the ulw-research activation marker`,
57
- );
58
- assert.doesNotMatch(
59
- copy.content,
60
- /`ULTRARESEARCH MODE ENABLED!`/,
61
- `${copy.label}: body must not expose the old ultraresearch activation marker`,
62
- );
63
- }
64
- });
65
-
66
- test("#given ulw-research skill #when scanned for non-English content #then it contains no Hangul", async () => {
67
- for (const copy of await readUlwResearchCopies()) {
68
- assert.doesNotMatch(
69
- copy.content,
70
- /[ᄀ-ᇿ㄰-㆏가-힣]/,
71
- `${copy.label} copy contains Hangul characters`,
72
- );
73
- }
74
- });
75
-
76
- test("#given ulw-research description #when activation policy is inspected #then it gates on explicit research demands only", async () => {
77
- for (const copy of await readUlwResearchCopies()) {
78
- const description = frontmatterDescription(copy.content);
79
- assert.match(description, /ulw-research/i, `${copy.label}: description must name the ulw-research trigger`);
80
- if (copy.label === "shared") {
81
- assert.match(description, /ultraresearch/i, `${copy.label}: description must preserve ultraresearch discoverability`);
82
- } else {
83
- assert.doesNotMatch(description, /ultraresearch/i, `${copy.label}: description must not expose ultraresearch`);
84
- }
85
- assert.match(description, /\bulw\b/i, `${copy.label}: description must preserve ulw discoverability`);
86
- assert.match(description, /explicit/i, `${copy.label}: description must gate activation on explicit demand`);
87
- assert.match(
88
- description,
89
- /ultra-precise investigation/i,
90
- `${copy.label}: description must name the ultra-precise investigation trigger`,
91
- );
92
- assert.match(description, /\bresearch\b/i, `${copy.label}: description must name the research trigger`);
93
- }
94
- });
95
-
96
- test("#given packaged ulw-research skill #when scanned for legacy aliases #then ultraresearch is not exposed", async () => {
97
- const packaged = (await readUlwResearchCopies()).find((copy) => copy.label === "packaged");
98
- assert.notEqual(packaged, undefined, "packaged copy not found");
99
- assert.doesNotMatch(packaged.content, /ultraresearch/i, "packaged ulw-research must not expose ultraresearch");
100
- });
101
-
102
- test("#given packaged ulw-research skill #when Codex guidance is inspected #then compatibility guidance is preserved", async () => {
103
- const packaged = (await readUlwResearchCopies()).find((copy) => copy.label === "packaged");
104
- assert.notEqual(packaged, undefined, "packaged copy not found");
105
- assert.match(packaged.content, /## Codex Harness Tool Compatibility/);
106
- assert.match(packaged.content, /multi_agent_v1\.spawn_agent/);
107
- assert.match(packaged.content, /multi_agent_v1\.wait_agent/);
108
- });
109
-
110
- test("#given ulw-research body #when authority is inspected #then it takes precedence over exploration-bounding instructions", async () => {
111
- for (const copy of await readUlwResearchCopies()) {
112
- assert.match(
113
- copy.content,
114
- /exploration-bounding|exploration (?:caps|budgets|limits)/i,
115
- `${copy.label}: body must name the exploration-bounding instructions it overrides`,
116
- );
117
- assert.match(
118
- copy.content,
119
- /supersede|override|do(?:es)? not (?:bind|apply)/i,
120
- `${copy.label}: body must state precedence while the mode is active`,
121
- );
122
- }
123
- });
124
-
125
- test("#given ulw-research worker protocol #when EXPAND flow is inspected #then markers travel as message text and workers never write files", async () => {
126
- for (const copy of await readUlwResearchCopies()) {
127
- assert.match(copy.content, /EXPAND/, `${copy.label}: body must keep the EXPAND marker protocol`);
128
- assert.match(
129
- copy.content,
130
- /(?:reply|message|response) text|end (?:its|the|your) (?:reply|response|final message)/i,
131
- `${copy.label}: EXPAND markers must be returned as message text`,
132
- );
133
- assert.match(
134
- copy.content,
135
- /read-only|cannot write files|never ask (?:a )?worker(?:s)? to write/i,
136
- `${copy.label}: body must state the read-only worker constraint`,
137
- );
138
- assert.doesNotMatch(
139
- copy.content,
140
- /APPEND (?:your )?findings to \$SESSION_DIR/i,
141
- `${copy.label}: workers must not be instructed to append session-dir files`,
142
- );
143
- }
144
- });
145
-
146
- test("#given ulw-research journaling #when ownership is inspected #then the orchestrator owns the session journal", async () => {
147
- for (const copy of await readUlwResearchCopies()) {
148
- assert.match(
149
- copy.content,
150
- /orchestrator[\s\S]{0,200}journal|journal[\s\S]{0,200}orchestrator/i,
151
- `${copy.label}: body must assign session-journal writes to the orchestrator`,
152
- );
153
- assert.match(copy.content, /SESSION_DIR/, `${copy.label}: body must keep the session directory protocol`);
154
- }
155
- });
156
-
157
- test("#given ulw-research expansion loop #when stop rules are inspected #then convergence rules and a depth cap are stated", async () => {
158
- for (const copy of await readUlwResearchCopies()) {
159
- assert.match(copy.content, /converg/i, `${copy.label}: body must define convergence`);
160
- assert.match(copy.content, /depth/i, `${copy.label}: body must define an expansion depth cap`);
161
- assert.match(
162
- copy.content,
163
- /minimum (?:of )?(?:2|two) expansion waves|at least (?:2|two) expansion waves/i,
164
- `${copy.label}: body must require a minimum of two expansion waves before convergence`,
165
- );
166
- }
167
- });
168
-
169
- test("#given ulw-research under ultrawork #when coexistence is inspected #then marker and done-definition conflicts are resolved", async () => {
170
- for (const copy of await readUlwResearchCopies()) {
171
- assert.match(copy.content, /ultrawork|\bulw\b/i, `${copy.label}: body must address ultrawork coexistence`);
172
- assert.match(
173
- copy.content,
174
- /first(?:-| )line/i,
175
- `${copy.label}: body must resolve the first-line activation marker conflict`,
176
- );
177
- }
178
- });
179
-
180
- test("#given ulw-research worker sizing #when spawn guidance is inspected #then capable-model and high-effort routing is stated", async () => {
181
- for (const copy of await readUlwResearchCopies()) {
182
- assert.match(
183
- copy.content,
184
- /capable model|high(?:est)? (?:reasoning )?effort/i,
185
- `${copy.label}: body must route research workers to a capable model or high effort`,
186
- );
187
- }
188
- });
189
-
190
- test("#given ulw-research execution substrate #when team usage is inspected #then it prefers a cooperating team with harness-native team tools", async () => {
191
- for (const copy of await readUlwResearchCopies()) {
192
- assert.match(
193
- copy.content,
194
- /cooperating team/i,
195
- `${copy.label}: body must encourage running the swarm as a cooperating team`,
196
- );
197
- assert.match(copy.content, /\bteammode\b/i, `${copy.label}: body must name the Codex teammode skill`);
198
- assert.match(copy.content, /team_mode/i, `${copy.label}: body must name the OpenCode team_mode path`);
199
- }
200
- });
201
-
202
- test("#given ulw-research team composition #when member slicing is inspected #then members map to part/ownership/perspective, never job titles", async () => {
203
- for (const copy of await readUlwResearchCopies()) {
204
- assert.match(
205
- copy.content,
206
- /by part, ownership, or perspective/i,
207
- `${copy.label}: body must compose members by part, ownership, or perspective`,
208
- );
209
- assert.match(
210
- copy.content,
211
- /never a job title|not (?:a |by )?job title/i,
212
- `${copy.label}: body must forbid vague job-title members`,
213
- );
214
- }
215
- });
216
-
217
- test("#given ulw-research team communication #when the raise law is inspected #then members broadcast every lead immediately rather than hoarding", async () => {
218
- for (const copy of await readUlwResearchCopies()) {
219
- assert.match(
220
- copy.content,
221
- /raise law|broadcast every lead/i,
222
- `${copy.label}: body must state the raise/broadcast law`,
223
- );
224
- assert.match(copy.content, /over-communicate/i, `${copy.label}: body must demand over-communication`);
225
- assert.match(
226
- copy.content,
227
- /the (?:moment|instant) it (?:surfaces|appears|lands)/i,
228
- `${copy.label}: body must require raising leads the moment they surface`,
229
- );
230
- assert.match(
231
- copy.content,
232
- /hoard/i,
233
- `${copy.label}: body must reject hoarding leads for a final dump`,
234
- );
235
- }
236
- });
237
-
238
- test("#given ulw-research default swarm #when team guidance is inspected #then teammode, many teammates, and hyperdebate are defaulted", async () => {
239
- for (const copy of await readUlwResearchCopies()) {
240
- const teamSection = markdownSection(copy.content, "## Run the swarm as a cooperating team", "## Worker ground rules");
241
- assert.match(teamSection, /default(?:s)? to teammode|teammode by default/i, `${copy.label}: teammode must be the default`);
242
- assert.match(teamSection, /many teammates|larger roster|5-8 teammates|5\+ teammates/i, `${copy.label}: body must prefer many teammates`);
243
- assert.match(teamSection, /hyperdebate|ultradebate/i, `${copy.label}: body must require adversarial debate`);
244
- assert.match(teamSection, /skeptic|red-team|cross-critique/i, `${copy.label}: body must include a critique perspective`);
245
- }
246
- });
247
-
248
- test("#given ulw-research non-code verification #when the gate is inspected #then a claim graph / verified-claims data-flow-lock exists", async () => {
249
- for (const copy of await readUlwResearchCopies()) {
250
- assert.match(
251
- copy.content,
252
- /claim graph|verified-claims/i,
253
- `${copy.label}: body must define the non-code claim-graph verification gate`,
254
- );
255
- }
256
- });
257
-
258
- test("#given ulw-research claim graph #when ownership is inspected #then workers never write the graph / verified-claims artifact", async () => {
259
- for (const copy of await readUlwResearchCopies()) {
260
- assert.doesNotMatch(
261
- copy.content,
262
- /worker[^.]*\b(?:write|append|create)s?\b[^.]*(?:claim[- ]graph|verified-claims)/i,
263
- `${copy.label}: workers must not be instructed to write/append/create the claim graph or verified-claims`,
264
- );
265
- }
266
- });
267
-
268
- test("#given ulw-research report output #when defaults are inspected #then HTML/PDF reports go through frontend, visual QA, and reviewer approval", async () => {
269
- for (const copy of await readUlwResearchCopies()) {
270
- const phase0 = markdownSection(copy.content, "## Phase 0 — Decompose and open the journal", "## Phase 1 — Saturation wave");
271
- const phase4 = markdownSection(copy.content, "## Phase 4 — Synthesize", "## Phase 5 — Final materials");
272
- const phase5 = markdownSection(copy.content, "## Phase 5 — Final materials", "## Search craft");
273
- assert.match(phase0, /Final material format:\s*<HTML\/PDF default \| explicit format \| markdown only>/, `${copy.label}: Phase 0 must track the default final-material contract`);
274
- assert.match(phase4, /citation source of truth/i, `${copy.label}: Phase 4 synthesis must be a source of truth, not the default final artifact`);
275
- assert.doesNotMatch(phase4, /When no report was requested, this is the deliverable/i, `${copy.label}: Phase 4 must not contradict default HTML/PDF final materials`);
276
- assert.match(phase5, /Default final materials to HTML\/PDF unless the user explicitly asks/i, `${copy.label}: Phase 5 must default final materials to HTML/PDF`);
277
- assert.match(phase5, /HTML first[\s\S]{0,120}PDF default/i, `${copy.label}: report output must default to HTML with PDF availability`);
278
- assert.match(phase5, /\bfrontend\b/i, `${copy.label}: report assembly must load the frontend skill`);
279
- assert.match(phase5, /visual-qa/i, `${copy.label}: report assembly must require visual-qa`);
280
- assert.match(phase5, /ulw-loop|ULW loop/i, `${copy.label}: report QA must run under the ULW loop`);
281
- assert.match(phase5, /reviewer[\s\S]{0,120}(?:approve|says no broken parts|no broken parts)/i, `${copy.label}: report completion must wait for reviewer approval`);
282
- }
283
- });
284
-
285
- test("#given ulw-research final materials #when visual artifact guidance is inspected #then charts Mermaid graphs and imagegen are strongly required", async () => {
286
- for (const copy of await readUlwResearchCopies()) {
287
- const phase5 = markdownSection(copy.content, "## Phase 5 — Final materials", "## Search craft");
288
- assert.match(phase5, /actively use charts/i, `${copy.label}: reports must strongly require charts`);
289
- assert.match(phase5, /Mermaid graphs/i, `${copy.label}: reports must require Mermaid graphs`);
290
- assert.match(phase5, /imagegen skill/i, `${copy.label}: reports must require imagegen visuals`);
291
- assert.match(phase5, /generated (?:diagrams|visuals)|generated diagrams or editorial visuals/i, `${copy.label}: report assets must include generated visual guidance`);
292
- }
293
- });
294
-
295
- test("#given ulw-research blocked sources #when escalation is inspected #then it routes through the ultimate-browsing skill", async () => {
26
+ test("#given ulw-research skill copies #when scanned for non-English content #then they contain no Hangul", async () => {
296
27
  for (const copy of await readUlwResearchCopies()) {
297
- assert.match(
298
- copy.content,
299
- /ultimate-browsing/,
300
- `${copy.label}: body must escalate blocked sources via the ultimate-browsing skill`,
301
- );
28
+ assert.doesNotMatch(copy.content, /[ᄀ-ᇿ㄰-㆏가-힣]/, `${copy.label} copy contains Hangul characters`);
302
29
  }
303
30
  });
@@ -5903,7 +5903,7 @@ var package_default;
5903
5903
  var init_package = __esm(() => {
5904
5904
  package_default = {
5905
5905
  name: "@oh-my-opencode/omo-codex",
5906
- version: "4.16.2",
5906
+ version: "4.17.1",
5907
5907
  type: "module",
5908
5908
  private: true,
5909
5909
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -7612,7 +7612,12 @@ function shouldCopyPluginPath(path, root) {
7612
7612
  if (relative4 === "")
7613
7613
  return true;
7614
7614
  const parts = relative4.split(sep5);
7615
- return !parts.some((part) => part === ".git" || part === "node_modules");
7615
+ if (parts.some((part) => part === ".git" || part === "node_modules"))
7616
+ return false;
7617
+ return !isNestedComponentMcpManifest(parts);
7618
+ }
7619
+ function isNestedComponentMcpManifest(parts) {
7620
+ return parts.length > 1 && parts.at(-1) === ".mcp.json";
7616
7621
  }
7617
7622
  var removedSparkshellReferencePattern = /\b(?:sparkshell|spark[-_\s]+shell)\b/i;
7618
7623
  var removedSparkshellPromptSurfaceDirs = new Set([".codex-plugin", "agents", "bundled-rules", "hooks", "skills"]);
@@ -8090,6 +8095,14 @@ function parseAgentHeaderName(header) {
8090
8095
  const path = parseTomlDottedKey(header);
8091
8096
  return path?.[0] === "agents" ? path[1] ?? null : null;
8092
8097
  }
8098
+ function parseJsonString(value) {
8099
+ try {
8100
+ const parsed = JSON.parse(value);
8101
+ return typeof parsed === "string" ? parsed : null;
8102
+ } catch {
8103
+ return null;
8104
+ }
8105
+ }
8093
8106
  function parseHookStateHeaderKey(header) {
8094
8107
  const path = parseTomlDottedKey(header);
8095
8108
  if (path?.[0] !== "hooks" || path[1] !== "state")
@@ -8139,6 +8152,9 @@ function stripTomlLineComment(line) {
8139
8152
  var LEGACY_MANAGED_CODEX_AGENT_NAMES_TO_PURGE = ["codex-ultrawork-reviewer"];
8140
8153
  var CURRENT_MANAGED_CODEX_AGENT_NAMES = [
8141
8154
  "explorer",
8155
+ "lazycodex-worker-high",
8156
+ "lazycodex-worker-low",
8157
+ "lazycodex-worker-medium",
8142
8158
  "librarian",
8143
8159
  "metis",
8144
8160
  "momus",
@@ -8556,12 +8572,18 @@ import { readFile as readFile10 } from "node:fs/promises";
8556
8572
  import { join as join17 } from "node:path";
8557
8573
  var FALLBACK_CODEX_MODEL_CATALOG = {
8558
8574
  current: {
8559
- model: "gpt-5.5",
8560
- modelContextWindow: 400000,
8575
+ model: "gpt-5.6-sol",
8576
+ modelContextWindow: 372000,
8561
8577
  modelReasoningEffort: "high",
8562
8578
  planModeReasoningEffort: "xhigh"
8563
8579
  },
8564
8580
  managedProfiles: [
8581
+ {
8582
+ model: "gpt-5.5",
8583
+ modelContextWindow: 400000,
8584
+ modelReasoningEffort: "high",
8585
+ planModeReasoningEffort: "xhigh"
8586
+ },
8565
8587
  {
8566
8588
  model: "gpt-5.5",
8567
8589
  modelContextWindow: 1e6,
@@ -9004,32 +9026,88 @@ import { join as join20 } from "node:path";
9004
9026
  var MANAGED_REASONING_DEFAULT_UPGRADES = new Map([
9005
9027
  [
9006
9028
  "explorer",
9007
- {
9008
- previous: { model: "gpt-5.4-mini", effort: "low" },
9009
- current: { model: "gpt-5.6-terra", effort: "medium" }
9010
- }
9029
+ [
9030
+ {
9031
+ previous: { model: "gpt-5.4-mini", effort: "low" },
9032
+ current: { model: "gpt-5.6-terra", effort: "medium" }
9033
+ },
9034
+ {
9035
+ previous: { model: "gpt-5.6-terra", effort: "medium" },
9036
+ current: { model: "gpt-5.6-luna", effort: "low" }
9037
+ }
9038
+ ]
9011
9039
  ],
9012
9040
  [
9013
9041
  "librarian",
9014
- {
9015
- previous: { model: "gpt-5.4-mini", effort: "low" },
9016
- current: { model: "gpt-5.6-terra", effort: "medium" }
9017
- }
9042
+ [
9043
+ {
9044
+ previous: { model: "gpt-5.4-mini", effort: "low" },
9045
+ current: { model: "gpt-5.6-terra", effort: "medium" }
9046
+ },
9047
+ {
9048
+ previous: { model: "gpt-5.6-terra", effort: "medium" },
9049
+ current: { model: "gpt-5.6-luna", effort: "low" }
9050
+ }
9051
+ ]
9018
9052
  ],
9019
9053
  [
9020
9054
  "momus",
9021
- {
9022
- previous: { model: "gpt-5.5", effort: "xhigh" },
9023
- current: { model: "gpt-5.6-sol", effort: "ultra" }
9024
- }
9055
+ [
9056
+ {
9057
+ previous: { model: "gpt-5.5", effort: "xhigh" },
9058
+ current: { model: "gpt-5.6-sol", effort: "ultra" }
9059
+ }
9060
+ ]
9061
+ ],
9062
+ [
9063
+ "plan",
9064
+ [
9065
+ {
9066
+ previous: { model: "gpt-5.6-sol", effort: "xhigh" },
9067
+ current: { model: "gpt-5.6-sol", effort: "max" }
9068
+ }
9069
+ ]
9070
+ ],
9071
+ [
9072
+ "lazycodex-worker-medium",
9073
+ [
9074
+ {
9075
+ previous: { model: "gpt-5.6-sol", effort: "high" },
9076
+ current: { model: "gpt-5.6-luna", effort: "max" }
9077
+ }
9078
+ ]
9079
+ ],
9080
+ [
9081
+ "lazycodex-qa-executor",
9082
+ [
9083
+ {
9084
+ previous: { model: "gpt-5.6-terra", effort: "medium" },
9085
+ current: { model: "gpt-5.6-luna", effort: "high" }
9086
+ }
9087
+ ]
9088
+ ],
9089
+ [
9090
+ "lazycodex-gate-reviewer",
9091
+ [
9092
+ {
9093
+ previous: { model: "gpt-5.6-sol", effort: "xhigh" },
9094
+ current: { model: "gpt-5.6-sol", effort: "high" }
9095
+ }
9096
+ ]
9025
9097
  ]
9026
9098
  ]);
9027
9099
  function resolveManagedAgentReasoning(input) {
9028
- const upgrade = MANAGED_REASONING_DEFAULT_UPGRADES.get(input.agentName);
9029
- if (upgrade !== undefined && input.preserved.model === upgrade.previous.model && input.preserved.effort === upgrade.previous.effort && input.bundledModel === upgrade.current.model && input.bundledEffort === upgrade.current.effort) {
9030
- return upgrade.current.effort;
9100
+ const steps = MANAGED_REASONING_DEFAULT_UPGRADES.get(input.agentName);
9101
+ if (steps === undefined)
9102
+ return input.preserved.effort;
9103
+ const latest = steps[steps.length - 1];
9104
+ if (latest === undefined)
9105
+ return input.preserved.effort;
9106
+ if (input.bundledModel !== latest.current.model || input.bundledEffort !== latest.current.effort) {
9107
+ return input.preserved.effort;
9031
9108
  }
9032
- return input.preserved.effort;
9109
+ const preservedMatchesAnyStep = steps.some((step) => input.preserved.model === step.previous.model && input.preserved.effort === step.previous.effort);
9110
+ return preservedMatchesAnyStep ? latest.current.effort : input.preserved.effort;
9033
9111
  }
9034
9112
 
9035
9113
  // packages/omo-codex/src/install/preserved-agent-settings.ts
@@ -9180,16 +9258,6 @@ function isSectionHeader3(line) {
9180
9258
  function agentNameFromToml(fileName) {
9181
9259
  return fileName.endsWith(".toml") ? fileName.slice(0, -".toml".length) : fileName;
9182
9260
  }
9183
- function parseJsonString(value) {
9184
- try {
9185
- const parsed = JSON.parse(value);
9186
- return typeof parsed === "string" ? parsed : null;
9187
- } catch (error) {
9188
- if (error instanceof Error)
9189
- return null;
9190
- return null;
9191
- }
9192
- }
9193
9261
  async function exists2(path) {
9194
9262
  try {
9195
9263
  await lstat7(path);
@@ -62,7 +62,7 @@ The agent looks for these nine categories. The first three are stylistic, the ne
62
62
  **Hard rule**: only apply when behavior equivalence is obvious. Do NOT change algorithms with subtle correctness implications. Do NOT micro-optimize hot paths without a benchmark. If in doubt, SKIP.
63
63
 
64
64
  ### Behavior coverage
65
- 9. **Missing tests** — behavior present in changed files that is not locked by any regression test. The fix is not to remove code but to ADD the narrowest test that pins the behavior.
65
+ 9. **Missing tests** — behavior present in changed files that is not locked by any regression test. The fix is not to remove code but to ADD the narrowest test that pins the behavior. EXCEPTION: a PROSE file (prompt, `SKILL.md`, rule, markdown) has no behavioral seam — do NOT add a text/word-count/phrase pin for it; that guards a diff, not behavior. Cover only a machine-consumed value (parsed field, sentinel a runtime greps, a doc JSON sample through its real validator) or leave it to review.
66
66
 
67
67
  ### Structural
68
68
  10. **Oversized modules** — any source file exceeding **250 pure LOC** (non-blank, non-comment lines). This is an architectural defect, not a style preference. Measure: `awk '!/^[[:space:]]*$/ && !/^[[:space:]]*(#|\/\/)/' <file> | wc -l`.
@@ -122,7 +122,7 @@ For each in-scope source file:
122
122
 
123
123
  1. Identify the public/observable behavior the file exposes (exported functions, HTTP handlers, CLI commands, classes used elsewhere).
124
124
  2. Check whether existing tests cover that behavior. Use `git grep` / project test conventions to find related test files.
125
- 3. **If behavior is uncovered or weakly covered, write the narrowest regression test that pins current behavior BEFORE editing the file.** Tests should pin observable outputs, not implementation details.
125
+ 3. **If behavior is uncovered or weakly covered, write the narrowest regression test that pins current behavior BEFORE editing the file.** Tests should pin observable outputs, not implementation details. A PROSE file (prompt/`SKILL.md`/rule/markdown) is exempt — its wording is not behavior; skip the test and rely on review, or assert only a machine-consumed value.
126
126
  4. Run the test suite (or at minimum the relevant tests). They must be **green** before any cleanup begins.
127
127
 
128
128
  If you cannot establish a green baseline (e.g., test runner is broken), STOP and report. Do not proceed with cleanup on unverified ground.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: review-work
3
- description: "Post-implementation review orchestrator. Launches 5 parallel background sub-agents: Oracle (goal/constraint verification), Oracle (code quality), Oracle (security), unspecified-high (hands-on QA execution), unspecified-high (context mining from GitHub/git/Slack/Notion). All must pass for review to pass. MUST USE after completing any significant implementation work. Triggers: 'review work', 'review my work', 'review changes', 'QA my work', 'verify implementation', 'check my work', 'validate changes', 'post-implementation review'."
3
+ description: "Post-implementation review orchestrator. Launches 5 parallel background sub-agents: Oracle (goal/constraint verification), Oracle (code quality), Oracle (security), unspecified-high (hands-on QA execution), unspecified-high (context mining from GitHub/git/Slack/Notion). All must pass for review to pass. MUST USE before a PR handoff or when the user explicitly asks to review completed work. Triggers: 'review work', 'review my work', 'review changes', 'QA my work', 'verify implementation', 'check my work', 'validate changes', 'post-implementation review'."
4
4
  ---
5
5
  ## Codex Harness Tool Compatibility
6
6
 
@@ -31,7 +31,13 @@ handoff. Role or specialty instructions belong inside `message`.
31
31
  Use `fork_context: false` unless full history is truly
32
32
  required; paste only the review context that worker needs.
33
33
 
34
- Plan and reviewer agents may run for a long time; spawn them in the background, keep doing independent root work, and poll with short `multi_agent_v1.wait_agent` cycles sized to the work. Never use a single long blocking wait for them, and never spin on tiny timeouts as a failure budget.
34
+ Review lanes are leaf agents: a lane does its own reading, running, and
35
+ judging inline and never spawns sub-reviewers of its own. Reviewers are
36
+ one-shot: a lane ends at its verdict; a re-review after fixes is a fresh
37
+ spawn scoped to the delta plus current evidence, never a `followup_task`
38
+ to a long-lived reviewer carrying stale context.
39
+
40
+ Plan and reviewer agents may run for a long time; spawn them in the background and keep doing independent root work. Between `multi_agent_v1.wait_agent` calls, back off — double the timeout up to ~5 minutes — instead of spinning short cycles.
35
41
 
36
42
  Treat child status as a progress signal, not a timeout counter. For
37
43
  work likely to exceed one wait cycle, require the child to send
@@ -225,6 +231,8 @@ task(
225
231
 
226
232
  You are a QA engineer. Your job is to RUN the application and verify it works through hands-on testing. You do not review code - you test behavior.
227
233
 
234
+ If the orchestrator already ran the `visual-qa` dual-oracle gate on this same build, consume that verdict instead of re-running it - your lane covers hands-on behavior the visual gate does not.
235
+
228
236
  MANDATORY PROCESS (follow in order):
229
237
 
230
238
  ### Step 1: Scenario Brainstorm